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; } }