| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324 |
- <?php
- namespace bizHd\homePageConfig\classes;
- use biz\shop\classes\ShopClass;
- use bizHd\goods\classes\GoodsClass;
- use bizHd\goods\classes\GoodsSettingClass;
- use common\components\business;
- use common\components\util;
- /**
- * 门店首页"展示数据"组装类
- * 把 HomePageConfigClass/HomePageModuleClass 存的原始配置,格式化为可直接渲染的结构
- * (拼好图片完整URL、过滤未开启/未上架内容、解析出真实商品列表、普通商品套上商城涨价等)。
- * 供 app-mall(顾客端商城首页)与 app-hd(商家端配置预览)共用同一套数据,
- * 保证"预览"看到的效果与顾客端真实首页完全一致。
- */
- class HomePageDisplayClass
- {
- /**
- * 一次性组装首页全部模块的展示数据
- *
- * @param int $mainId
- * @param int $shopId
- * @return array
- */
- public static function buildHome($mainId, $shopId)
- {
- // 三个普通商品模块共用一次涨价配置,避免重复查库
- $rise = GoodsSettingClass::getRise($mainId);
- return [
- 'modules' => HomePageConfigClass::getModules($mainId, $shopId),
- 'topNav' => self::formatTopNav($mainId, HomePageConfigClass::getTopNav($mainId, $shopId)),
- 'banner' => self::formatBanner(HomePageConfigClass::getBanner($mainId, $shopId)),
- 'navGrid' => self::formatNavGrid(HomePageModuleClass::getNavGrid($mainId, $shopId)),
- 'seckill' => self::formatActivity(HomePageModuleClass::getSeckill($mainId, $shopId, true)),
- 'groupBuy' => self::formatActivity(HomePageModuleClass::getGroupBuy($mainId, $shopId, true)),
- 'hot' => self::formatGoodsSection($mainId, $shopId, 'hot', $rise),
- 'new' => self::formatGoodsSection($mainId, $shopId, 'new', $rise),
- 'pullGoods' => self::formatGoodsSection($mainId, $shopId, 'pullGoods', $rise),
- ];
- }
- /**
- * 格式化顶部导航:门店名称不落 Redis,实时取 xhShop.merchantName
- *
- * @param int $mainId 门店 shopId
- * @param array $data HomePageConfigClass::getTopNav 返回值
- * @return array
- */
- public static function formatTopNav($mainId, $data)
- {
- $shop = ShopClass::getById($mainId, false, 'merchantName');
- $data['merchantName'] = is_array($shop) ? ($shop['merchantName'] ?? '') : '';
- return $data;
- }
- /**
- * 格式化轮播图:关闭时清空列表;开启时补上完整图片URL
- *
- * @param array $data HomePageConfigClass::getBanner 返回值
- * @return array
- */
- public static function formatBanner($data)
- {
- if (empty($data['enabled'])) {
- return ['enabled' => 0, 'interval' => intval($data['interval'] ?? 3), 'list' => []];
- }
- $list = [];
- foreach ($data['list'] as $item) {
- $img = $item['img'] ?? '';
- $formatted = $img !== '' ? business::formatUploadImg($img) : ['url' => ''];
- $list[] = [
- 'img' => $img,
- 'imgUrl' => $formatted['url'] ?? '',
- 'type' => intval($item['type'] ?? 1),
- 'value' => strval($item['value'] ?? ''),
- ];
- }
- return ['enabled' => 1, 'interval' => intval($data['interval'] ?? 3), 'list' => $list];
- }
- /**
- * 格式化金刚区:关闭时清空列表;开启时过滤未启用的单项,补上图标完整URL
- *
- * @param array $data HomePageModuleClass::getNavGrid 返回值
- * @return array
- */
- public static function formatNavGrid($data)
- {
- if (empty($data['enabled'])) {
- return ['enabled' => 0, 'cols' => intval($data['cols'] ?? 5), 'list' => []];
- }
- $list = [];
- foreach ($data['list'] as $item) {
- if (empty($item['enabled'])) {
- continue;
- }
- $icon = $item['icon'] ?? '';
- $iconUrl = $icon;
- $iconType = intval($item['iconType'] ?? 1);
- // 默认图标库 preset:N → OSS 静态图完整 URL(与前端默认图库一致)
- if (preg_match('/^preset:(\d+)$/', $icon, $m)) {
- $n = intval($m[1]);
- if ($n >= 1 && $n <= 12) {
- $path = 'hhb/images/navGrid-default/navGrid-default' . $n . '.png';
- $formatted = business::formatUploadImg($path);
- $iconUrl = $formatted['url'] ?? $path;
- }
- } elseif ($iconType === 2 && $icon !== '' && strpos($icon, 'http') !== 0) {
- // 商家上传图标转完整 URL
- $formatted = business::formatUploadImg($icon);
- $iconUrl = $formatted['url'] ?? $icon;
- }
- $list[] = [
- 'id' => $item['id'],
- 'name' => $item['name'],
- 'icon' => $icon,
- 'iconUrl' => $iconUrl,
- 'iconType' => $iconType,
- 'type' => intval($item['type'] ?? 3),
- 'value' => strval($item['value'] ?? ''),
- ];
- }
- return ['enabled' => 1, 'cols' => intval($data['cols'] ?? 5), 'list' => $list];
- }
- /**
- * 过滤上架中的活动商品并补上封面完整URL(不做条数截断)
- *
- * @param array $rawList
- * @return array
- */
- public static function filterActivityGoods($rawList)
- {
- $goods = [];
- foreach ($rawList as $item) {
- if (empty($item['status'])) {
- continue;
- }
- $cover = $item['cover'] ?? '';
- if ($cover !== '' && strpos($cover, 'http') !== 0) {
- $formatted = business::formatUploadImg($cover);
- $item['coverUrl'] = $formatted['url'] ?? $cover;
- } else {
- $item['coverUrl'] = $cover;
- }
- // 列表页统一用 id 字段,与普通商品列表对齐
- $item['id'] = intval($item['goodsId'] ?? ($item['id'] ?? 0));
- $goods[] = $item;
- }
- return $goods;
- }
- /**
- * 格式化秒杀/团购活动:只返回上架中的活动商品,并按 displayCount 截断;附带 goodsTotal
- *
- * @param array $data HomePageModuleClass::getSeckill/getGroupBuy 返回值
- * @return array
- */
- public static function formatActivity($data)
- {
- if (empty($data['enabled'])) {
- $data['goods'] = [];
- $data['goodsTotal'] = 0;
- return $data;
- }
- $goods = self::filterActivityGoods($data['goods'] ?? []);
- $data['goodsTotal'] = count($goods);
- $limit = !empty($data['expand']) ? 0 : HomePageModuleClass::resolveHomeDisplayLimit($data['displayCount'] ?? 0);
- if ($limit > 0 && count($goods) > $limit) {
- $goods = array_slice($goods, 0, $limit);
- }
- $data['goods'] = $goods;
- return $data;
- }
- /**
- * 格式化热门推荐/今日上新/下拉商品:关闭时清空商品;开启时按真实商品数量自动推导列数与展示条数
- * 输出价格为商城涨价后的售价(与详情页 obeyRiseRule 一致);秒杀/团购不走本方法
- *
- * @param int $mainId
- * @param int $shopId
- * @param string $moduleKey hot|new|pullGoods
- * @param array|null $rise 已查好的涨价配置;单模块接口未传时内部再查一次
- * @return array
- */
- public static function formatGoodsSection($mainId, $shopId, $moduleKey, $rise = null)
- {
- $data = HomePageModuleClass::getGoodsSection($mainId, $shopId, $moduleKey);
- if (empty($data['enabled'])) {
- $data['goods'] = [];
- $data['goodsTotal'] = 0;
- $data['layoutCols'] = 1;
- return $data;
- }
- $rows = HomePageModuleClass::matchGoodsRows($mainId, $data['type'], $data['value'], $data['sort']);
- $total = count($rows);
- $layout = HomePageModuleClass::resolveGoodsSectionLayout($total, $moduleKey);
- $data['layoutCols'] = $layout['layoutCols'];
- if ($layout['displayCount'] > 0 && $layout['displayCount'] < $total) {
- $rows = array_slice($rows, 0, $layout['displayCount']);
- }
- // 首页列表必须走与详情页相同的涨价公式,否则顾客看到原价、点进详情才变价
- $data['goods'] = self::applyMallRisePrice(HomePageModuleClass::formatGoodsRows($rows), $mainId, $rise);
- $data['goodsTotal'] = $total;
- return $data;
- }
- /**
- * 「更多」列表页分页入口:按模块返回全部可展示商品
- *
- * @param int $mainId
- * @param int $shopId
- * @param string $moduleKey seckill|groupBuy|hot|new|pullGoods
- * @param int $page
- * @param int $pageSize
- * @return array {list, total, totalPage, page, pageSize, moreData, title}
- */
- public static function getSectionGoodsPage($mainId, $shopId, $moduleKey, $page = 1, $pageSize = 10)
- {
- $mainId = intval($mainId);
- $shopId = intval($shopId);
- $moduleKey = strval($moduleKey);
- $page = max(1, intval($page));
- $pageSize = max(1, intval($pageSize));
- if ($mainId <= 0) {
- util::fail('无效门店');
- }
- // moduleKey / page / pageSize 形态校验由 GetSectionGoodsForm 完成
- $title = '';
- $list = [];
- $total = 0;
- // 秒杀/团购活动的起止时间,供列表页「更多」点击进详情时一并带上活动信息
- $activityEndTime = 0;
- $activityStartTime = 0;
- if ($moduleKey === 'seckill' || $moduleKey === 'groupBuy') {
- $data = $moduleKey === 'seckill'
- ? HomePageModuleClass::getSeckill($mainId, $shopId, true)
- : HomePageModuleClass::getGroupBuy($mainId, $shopId, true);
- $title = strval($data['title'] ?? '');
- if ($title === '') {
- $title = $moduleKey === 'groupBuy' ? '团购优惠' : '限时秒杀';
- }
- $activityStartTime = intval($data['startTime'] ?? 0);
- $activityEndTime = intval($data['endTime'] ?? 0);
- $all = empty($data['enabled']) ? [] : self::filterActivityGoods($data['goods'] ?? []);
- $total = count($all);
- $list = array_slice($all, ($page - 1) * $pageSize, $pageSize);
- } else {
- $data = HomePageModuleClass::getGoodsSection($mainId, $shopId, $moduleKey);
- $title = strval($data['name'] ?? '');
- if (empty($data['enabled'])) {
- $list = [];
- $total = 0;
- } else {
- $paged = HomePageModuleClass::resolveDisplayGoodsPaged(
- $mainId,
- $data['type'],
- $data['value'],
- $data['sort'],
- $page,
- $pageSize
- );
- // 「更多」列表与首页模块同源,同样补涨价;秒杀/团购走活动价,上面分支不套涨价
- $list = self::applyMallRisePrice($paged['list'], $mainId);
- $total = $paged['total'];
- }
- }
- $totalPage = $pageSize > 0 ? intval(ceil($total / $pageSize)) : 0;
- $moreData = $totalPage > $page ? 1 : 0;
- return [
- 'list' => $list,
- 'total' => $total,
- 'totalPage' => $totalPage,
- 'page' => $page,
- 'pageSize' => $pageSize,
- 'moreData' => $moreData,
- 'title' => $title,
- 'startTime' => $activityStartTime,
- 'endTime' => $activityEndTime,
- ];
- }
- /**
- * 给首页普通商品套上店铺涨价后的售价
- * 只走 obeyRiseRule 纯计算,不走 getFinalPrice(后者每条商品 Redis 查聊天报价,
- * 首页游客 userId=0 必 miss,下拉商品全量时会拖慢约 1 秒)。
- * 无价商品(priceType=0)不涨价;秒杀/团购走活动价,不要调用本方法。
- *
- * @param array $goods formatGoodsRows 产出的商品列表
- * @param int $mainId 商户 mainId,未传入 $rise 时用来查涨价配置
- * @param array|null $rise GoodsSettingClass::getRise 的返回值,传入则不再查库
- * @return array
- */
- public static function applyMallRisePrice($goods, $mainId, $rise = null)
- {
- if (empty($goods) || !is_array($goods)) {
- return $goods;
- }
- if (!is_array($rise)) {
- $rise = intval($mainId) > 0 ? GoodsSettingClass::getRise($mainId) : [];
- }
- $riseSwitch = intval($rise['riseSwitch'] ?? 0);
- $riseType = intval($rise['riseType'] ?? 0);
- $riseAmount = floatval($rise['riseAmount'] ?? 0);
- // 未开启涨价时直接返回原价,避免对全量下拉商品做无意义循环
- if ($riseSwitch != 1 || $riseAmount <= 0) {
- return $goods;
- }
- foreach ($goods as $key => $item) {
- // 无价商品不参与涨价,与详情页 modifyAndRisePrice 一致
- if (isset($item['priceType']) && intval($item['priceType']) === 0) {
- continue;
- }
- $goods[$key] = GoodsClass::obeyRiseRule($item, $riseSwitch, $riseType, $riseAmount, [], []);
- }
- return $goods;
- }
- }
|