4-首页模块商品展示数量与更多页.md 14 KB


name: 首页模块商品展示数量与更多页 overview: 为 hdApp 门店首页配置的秒杀/团购/热门推荐/今日上新/下拉商品新增"商品展示数量"设置,mallApp 首页对应模块据此显示"更多"按钮并跳转到新建的模块商品列表页;同时移除秒杀/团购编辑页中冗余的"商品首页展开"开关(后端已确认该字段未参与任何展示逻辑,属于死代码)。 todos: []

isProject: false

计划需求指令:

  1. 项目 hdApp 下的首页配置-->门店首页配置下的秒杀专区 、团购专区 、热门推荐、今日上新和下拉商品的表单项要加个“商品展示数量”--默认是全部,另外可以设置1~10个(设置的数量超出总数时,即为全部)。增加“商品展示数量”后,在mallApp的 mallApp/src/pages/home/index.vue 的各模块要根据:“商品展示数量” 小于当前“商品总数”,则对应模块的右上角要显示“更多”按钮,“商品展示数量” 等于当前“商品总数”,则对应模块的右上角不显示“更多”按钮。
  2. 点击“更多”按钮跳转到一个商品列表页,标题为对应模块名称。这个页面要新建,样式参照 mallApp/src/pages/goods/list.vue ,此次实现的页面不需要筛选功能
  3. 项目 hdApp 下的首页配置-->门店首页配置下的秒杀专区编辑页(hdApp/src/admin/homePageConfig/seckill.vue)与团购专区编辑页(hdApp/src/admin/homePageConfig/groupBuy.vue)下的“商品首页展开”表单项是不是多余的,如果是请把它删除(对应后端的缓存数据也处理)

背景确认(已调研)

  • expandHome 字段:仅在 HomePageModuleClass.phpvalidateActivityBase/normalizeActivityBase 中写入/读出 Redis,全仓库无任何展示分支依赖它,确认为冗余字段,可删除。
  • 首页展示数据统一在 HomePageDisplayClass::buildHome 组装,秒杀/团购走 formatActivity(无条数截断),热门/上新/下拉走 formatGoodsSectionresolveDisplayGoods(硬编码 DISPLAY_GOODS_LIMIT=20 截断,且不返回总数)。
  • mallApp 首页当前:goodsSection.vue(热门/上新/下拉)已有无条件的"更多"(跳店铺分类页);activitySection.vue(秒杀/团购)没有"更多"入口。
  • 已与用户确认两个关键设计:
    1. "更多"列表页中秒杀/团购商品保留活动价/原价/团购人数展示,样式参照 goods/list.vue 卡片布局。
    2. "商品总数"与"更多"列表页范围采用真实总数(不受现有 20 条上限限制),后端新增接口支持分页浏览全部商品。

一、后端(huahuibao)

1. 新增 displayCount 字段,移除 expandHome

文件:biz-hd/homePageConfig/classes/HomePageModuleClass.php

  • validateActivityBase(行 641-686)、normalizeActivityBase(行 627-639):删除 expandHome 读写;新增 displayCount(0=全部,1-10=具体数量)。新增校验方法:

    public static function normalizeDisplayCount($value)
    {
    if ($value === '' || $value === null || intval($value) === 0) {
        return 0;
    }
    $count = intval($value);
    if ($count < 1 || $count > 10) {
        util::fail('商品展示数量范围为1-10,留空表示全部');
    }
    return $count;
    }
    
  • 秒杀/团购:validateActivityBase'displayCount' => self::normalizeDisplayCount($data['displayCount'] ?? 0) 替换 expandHome 那一行;normalizeActivityBase 同理用 intval($saved['displayCount'] ?? 0) 替换。

  • 热门/上新/下拉:getGoodsSection(行 438-456)、saveGoodsSection(行 458-494)同样新增 displayCount 的读取与保存(复用 normalizeDisplayCount)。

  • 旧 Redis 缓存中残留的 expandHome 字段无需专门迁移:整个模块配置以 JSON 整体 SET 覆盖存储,下次管理员保存后该字段自然被新结构替换;读取时不再解析它即不产生任何影响。

2. 商品总数与展示条数截断逻辑

文件:biz-hd/homePageConfig/classes/HomePageModuleClass.php

  • resolveDisplayGoods(行 519-610)拆分为:
    • matchGoodsRows($mainId, $type, $value, $sort):保留现有匹配+排序逻辑,返回未截断的原始行数组。
    • formatGoodsRows($rows):现有"组装输出字段(含 coverUrl)"部分抽出为独立方法。
    • resolveDisplayGoodsPaged($mainId, $type, $value, $sort, $page, $pageSize):调用 matchGoodsRows 取总数,再按 page/pageSize 切片、formatGoodsRows 格式化,返回 ['list' => [...], 'total' => n]

文件:biz-hd/homePageConfig/classes/HomePageDisplayClass.php

  • formatActivity(行 119-141):抽出"状态过滤 + coverUrl 补全"为私有方法 filterActivityGoods($rawList)(不做截断),供 formatActivity 和后面的分页接口共用;formatActivity 内使用该方法取全量后计算 $total = count($goods),再按 $limit = 1<=displayCount<=10 ? displayCount : HomePageModuleClass::DISPLAY_GOODS_LIMIT 截断,返回时新增 goodsTotal 字段。
  • formatGoodsSection(行 150-164):改为调用 resolveDisplayGoodsPaged($mainId, type, value, sort, 1, $limit)$limit 同上取 displayCount 或默认 20),返回时新增 goodsTotal 字段(取分页结果里的 total)。
  • 新增 getSectionGoodsPage($mainId, $moduleKey, $page, $pageSize):统一入口,供"更多"列表页调用:
    • moduleKeyseckill/groupBuy:取 getSeckill/getGroupBuyfilterActivityGoods 取全量 → 按 page/pageSize 切片,标题取 title(与首页展示一致的兜底文案)。
    • moduleKeyhot/new/pullGoods:取 getGoodsSectionresolveDisplayGoodsPaged,标题取 name
    • 统一返回 { list, total, totalPage, page, pageSize, moreData, title }(与 GoodsCategoryClass::getGoodsList 分页返回约定一致,供前端 mixins/list.js 直接消费)。

3. Controller 新增接口

二、hdApp 管理端(front-end)

1. 秒杀/团购编辑页:移除"商品首页展开",新增"商品展示数量"

文件:hdApp/src/admin/homePageConfig/seckill.vuegroupBuy.vue(两文件结构一致,逐一同步修改)

  • 删除模板中"商品首页展开" tui-list-cell(seckill.vue 行 51-56)。
  • 原位置新增"商品展示数量"字段:

    <tui-list-cell class="line-cell" :hover="false">
    <view class="tui-title">商品展示数量</view>
    <input
    v-model="form.displayCount"
    class="tui-input"
    type="number"
    maxlength="2"
    placeholder="默认全部"
    />
    </tui-list-cell>
    <view class="field-hint">范围1-10,留空为全部;设置数量超出商品总数时按全部展示</view>
    
  • data().form:删除 expandHome: 0,新增 displayCount: ''

  • normalizeForm:删除 expandHome 映射,新增 displayCount: data.displayCount ? String(data.displayCount) : ''

  • 删除 onExpandHomeChange 方法。

  • saveFn 提交参数:删除 expandHome,新增 displayCount: this.form.displayCount === '' ? 0 : parseInt(this.form.displayCount, 10);提交前校验:非空时必须在 1-10 之间,否则 this.$msg('商品展示数量范围为1-10') 并中断。

2. 热门/上新/下拉共用编辑页:新增"商品展示数量"

文件:hdApp/src/admin/homePageConfig/goodsSection.vue

  • 在"排列规则"字段行(行 115-128)后新增同样的"商品展示数量"输入行。
  • data().form 新增 displayCount: ''init() 中回填 displayCount: d.displayCount ? String(d.displayCount) : ''saveFn 提交与校验逻辑同上。

3. API 封装

文件:hdApp/src/api/home-page-config/index.js — 无需新增(displayCount 随现有 saveSeckill/saveGroupBuy/saveHot/saveNew/savePullGoods 一起提交)。

三、mallApp 顾客端(front-end)

1. 首页模块组件:按 goodsTotal 显示"更多"

文件:mallApp/src/components/home/activitySection.vue

  • 新增 computed showMore()return Number(this.data.goodsTotal || 0) > (this.data.goods || []).length
  • 模板:在 activity-head 内新增"更多"按钮(放在标题行右侧,需要把当前 .activity-title-row 包一层并用 justify-content: space-between 让"更多"贴右,倒计时与标题保持左侧一组),v-if="showMore",点击调用 goMore()
  • 新增方法:

    goMore() {
    const title = this.data.title || (this.isGroupBuy ? '团购优惠' : '限时秒杀')
    this.pageTo({
    url: `/pages/goods/section-list?moduleKey=${this.type}&title=${encodeURIComponent(title)}&account=${this.account}&hdId=${this.hdId}`
    })
    }
    

文件:mallApp/src/components/home/goodsSection.vue

  • 新增 prop moduleKey(hot/new/pullGoods)。
  • .section-more 增加 v-if="showMore"(computed 同上)。
  • goMore() 改为跳转新页面:/pages/goods/section-list?moduleKey=${this.moduleKey}&title=${encodeURIComponent(this.data.name)}&account=...&hdId=...(替换现有跳店铺分类页的逻辑)。

文件:mallApp/src/pages/home/index.vue

  • 给三个 home-goods-section 实例分别加上 module-key="hot" / "new" / "pullGoods"(行 54-71 附近)。

2. 新增 API 封装

文件:mallApp/src/api/home-page-config/index.js

export const getSectionGoods = data => https.get('/home-page-config/get-section-goods', data)

3. 新建"模块商品列表"页面

新文件:mallApp/src/pages/goods/section-list.vue

  • 参照 goods/list.vue 的整体风格(卡片列表、mixins/list、下拉刷新/触底加载、空态),但不含搜索栏与筛选弹窗(整段移除)。
  • 通过 query 取 moduleKeytitleaccounthdIdonLoad/inituni.setNavigationBarTitle({ title })
  • 请求:buildQuery() 返回 { moduleKey, page, pageSize: 10 }loadGoods()getSectionGoods(...).then(res => this.completes(res))
  • 卡片渲染需兼容两类返回数据形状:
    • 热门/上新/下拉:{id,name,price,stock,cover,coverUrl,sold} — 展示价格 + 已售数量。
    • 秒杀/团购:{id,name,price,originPrice,cover,coverUrl,groupSize?} — 展示活动价 + 原价划线,团购额外显示"XX人团"角标。
    • moduleKey 判断展示分支(isActivity = moduleKey === 'seckill' || moduleKey === 'groupBuy')。
  • 点击卡片跳转 /pages/goods/detail?id=${item.id}&account=...&hdId=...

mallApp/src/pages.jsonpages/goods 分包(行 74-80)追加:

{ "path": "section-list", "style": { "navigationBarTitleText": "商品列表", "enablePullDownRefresh": true } }

四、不涉及的范围(明确说明)

  • hdApp/src/admin/homePageConfig/preview.vue 及其 previewParts/* 组件为只读预览(不支持下单/跳转交互),不新增"更多"按钮,维持现状。
  • seckillGoodsEdit.vue / groupBuyGoodsEdit.vue 中的"单人限购"字段与本次"商品展示数量"无关,不改动。

验证

  • 前端改动完成后不自动执行 npm run build:mp-weixin(按项目规则,由用户自行运行)。
  • 结构性改动后运行 npm run index(understand-project)刷新索引,npm run validate 校验。
  • [{"id":"backend-displaycount","content":"HomePageModuleClass.php: 移除 expandHome,新增 displayCount 校验/读写(活动+goodsSection)"},{"id":"backend-total-refactor","content":"重构 resolveDisplayGoods 为 matchGoodsRows/formatGoodsRows/resolveDisplayGoodsPaged,支持真实总数与分页"},{"id":"backend-display-class","content":"HomePageDisplayClass.php: formatActivity/formatGoodsSection 返回 goodsTotal 并按 displayCount 截断;新增 getSectionGoodsPage"},{"id":"backend-controller","content":"app-mall HomePageConfigController 新增 actionGetSectionGoods 并加入 guestAccess"},{"id":"hd-seckill-groupbuy-form","content":"hdApp seckill.vue/groupBuy.vue: 删除商品首页展开,新增商品展示数量输入与校验"},{"id":"hd-goodssection-form","content":"hdApp goodsSection.vue: 新增商品展示数量输入与校验"},{"id":"mall-api","content":"mallApp api/home-page-config: 新增 getSectionGoods"},{"id":"mall-activity-section","content":"mallApp activitySection.vue: 按 goodsTotal 显示更多按钮并跳转"},{"id":"mall-goods-section","content":"mallApp goodsSection.vue: 新增 moduleKey prop,按 goodsTotal 显示更多并跳转新页面"},{"id":"mall-home-index","content":"mallApp home/index.vue: 为三个 goods-section 实例传入 module-key"},{"id":"mall-section-list-page","content":"新建 mallApp pages/goods/section-list.vue 并注册 pages.json,参照 list.vue 去掉筛选"}]