Files
xinlong-shop-taro/.workbuddy/memory/2026-07-04.md
赵忠林 1729ef3ae4 feat(shop): 改造分类页为左右布局并新增商品排序功能
- 重写分类页,实现左侧一级分类列表和右侧商品列表布局
- 右侧增加商品排序栏,支持默认、销量、最新、价格排序(价格可升降序切换)
- 商品列表横向卡片布局,显示图片、标题、积分标签、VIP价格、销量及加购按钮
- 支持滚动触底自动分页加载更多商品
- 点击商品跳转详情页,点击加购按钮调用加入购物车接口
- 复用 VIP 价格逻辑,优化价格显示
- 修复门店中心页 loading 状态,确保数据加载完成后隐藏加载中提示
- 优化订阅消息模板 ID 填充和错误提示提示细节
2026-07-04 13:17:52 +08:00

170 lines
8.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 2026-07-04 工作日志
## VIP会员审核功能开发
### 功能概述
为 xinlong-shop-taro 小程序新增了 VIP 会员审核功能,包含以下三个核心模块:
### 1. VIP会员审核菜单入口user.tsx
- 在"门店中心"下方添加了"VIP会员审核"菜单项
- 仅门店店员身份显示(与门店中心相同的 `storeInfo` 判断条件)
- 点击跳转到 `/pages/user/vip-review/index`
- 同时在页面加载、useDidShow、下拉刷新时调用 `checkAndCacheVipStatus` 更新当前用户的 VIP 状态缓存
### 2. VIP会员审核页面vip-review/index.tsx
- 新建页面 `src/pages/user/vip-review/index.tsx`
- 页面进入时验证当前用户是否为店员(通过 `getMyClerk()`
- 三个 Tab待审核(applyStatus=10)、已通过(20)、已驳回(30)
- 展示申请人的门店名称、门店地址、申请时间
- 店员可"通过"(设 applyStatus=20或"驳回"(设 applyStatus=30附带驳回原因
- 使用 `updateShopDealerApply` API 进行审核操作
- 与 vip-upgrade/index.tsx 配套:用户提交申请 → 店员实地考察 → 审核通过/驳回
### 3. VIP会员价格特权dealerPrice
- 创建了 VIP 状态工具 `src/utils/vip.ts`
- `isVipMember()` - 同步从缓存读取 VIP 状态
- `checkAndCacheVipStatus(userId)` - 异步检查并缓存(查询 ShopDealerApply applyStatus=20
- `getDisplayPrice(product)` - 获取商品对当前用户的实际价格
- 创建了 `src/hooks/useVipStatus.ts` Hook
- 修改了以下页面/组件支持 VIP 显示 dealerPrice
- `ProductCard` - 商品列表卡片价格
- `product-detail.tsx` - 商品详情页价格 + 立即购买传参
- `SkuSelector` - SKU 选择弹窗价格 + 确认时 fakeSku 价格
- `cart.tsx` - 购物车商品价格 + 推荐商品价格
- `CartContext.tsx` - `calcPrice` 计算总价时使用 dealerPrice
- `checkout.tsx` - 结算页金额计算 + 单价显示
### 4. 路由注册
-`app.config.ts` 中注册了 `pages/user/vip-review/index`
### 5. VIP升级页字段来源修正
- 修改 `vip-upgrade/index.tsx`
- 门店名称和门店地址不再从 `user` 对象读取,统一从 `shop-dealer-apply` 表最新记录读取
- 待审核(10) 和 已通过(20) 时只读展示;已驳回(30) 时允许编辑并重新提交
- TypeScript 类型检查通过
### 6. 审核通过时添加 VIP 角色
-`vip-review/index.tsx` 中新增了 `assignVipRole` 辅助函数
- 审核通过applyStatus=20自动调用 `addUserRole` 给申请人添加 `VIP会员` 角色roleId=2032, roleCode=vip
- 先调用 `listUserRole({ userId })` 检查用户是否已有 VIP 角色,避免重复绑定
- TypeScript 类型检查通过
### 7. 门店中心改造为仪表盘
-`store/center/index.tsx` 从订单管理页改造为功能入口仪表盘
- 新建 `store/orders/index.tsx`,将原订单管理逻辑完整搬入
- VIP会员审核入口从 `user.tsx` 独立菜单移除,统一放入门店中心仪表盘
- 门店中心仪表盘功能卡片支持扩展FEATURE_CARDS 数组,新增只需加一项)
- VIP会员审核卡片显示待审核数量角标红底白字
- TypeScript 类型检查通过
### 8. 门店中心顶部显示店员头像和门店名称
- 修改 `store/center/index.tsx` 顶部信息区
- 左侧显示圆形店员头像(读取 `storeInfo.avatar`),无头像时显示默认 👤 图标
- 右侧显示门店名称(`storeInfo.storeName`)和店员姓名 + 手机号(`storeInfo.name``storeInfo.phone`
- TypeScript 类型检查通过
### 涉及文件(补充)
- 修改:`src/pages/store/center/index.tsx`
### 9. 商品详情页价格下方 0 值隐藏
- 修改 `product-detail.tsx` 价格区域
-`dealerPrice``salePrice``memberStorePrice` 增加 `Number(value) > 0` 判断
- 0 或无效值时不再渲染,避免价格下方出现单独的 "0"
- TypeScript 类型检查通过
### 涉及文件(补充)
- 修改:`src/pages/shop/product-detail.tsx`
---
### 10. 新订单提醒功能(前端轮询 + 订阅消息)
#### 10.1 创建 useNewOrderDetector Hook
- 新建 `src/hooks/useNewOrderDetector.ts`
- 封装新订单轮询检测逻辑:
- 首次加载自动建立订单 ID 基准线,不触发提醒
- 后续轮询对比发现新订单后触发 `onNewOrders` 回调
- 页面隐藏时自动暂停轮询,显示时恢复
- 提供 `clearUnread()` 方法清除未读计数
- 导出类型:`NewOrderItem``UseNewOrderDetectorOptions``UseNewOrderDetectorReturn`
- 注册到 `src/hooks/index.ts`
#### 10.2 改造订单管理页(前端轮询)
- 修改 `src/pages/store/orders/index.tsx`
- 集成 `useNewOrderDetector`30 秒轮询,静默检测新订单
- 发现新订单时:震动提醒(`Taro.vibrateShort`+ Toast 提示("您有 N 条新订单"
- "全部" Tab 增加红色角标显示未读新订单数(>99 显示 99+
- 切换 Tab 时自动清除未读计数
#### 10.3 改造门店中心页
- 修改 `src/pages/store/center/index.tsx`
- 订单管理卡片增加待处理订单角标(查询 statusFilter=1 的 total
- VIP 审核角标同步增强,统一使用 `getBadgeCount()` 方法
- 底部新增"接收新订单提醒"卡片:
- 调用 `Taro.requestSubscribeMessage` 请求微信订阅消息授权
- 模板 ID 通过 `SUBSCRIBE_TMPL_IDS` 常量配置(待微信公众平台申请后填入)
- 授权成功后 Toast 提示
#### 待后端配合
- 微信公众平台申请订阅消息模板("新订单通知"类目)
- 将模板 ID 填入 `store/center/index.tsx``SUBSCRIBE_TMPL_IDS` 数组
- 后端在订单创建成功后调用 `subscribeMessage.send` API 向店员推送
#### 涉及文件
- 新建:`src/hooks/useNewOrderDetector.ts`
- 修改:`src/hooks/index.ts`
- 修改:`src/pages/store/orders/index.tsx`
- 修改:`src/pages/store/center/index.tsx`
---
### 11. 后端订阅消息发送服务
#### 11.1 新建 WxSubscribeMessageService
- 接口:`/JAVA/shop-api/src/main/java/com/gxwebsoft/shop/service/WxSubscribeMessageService.java`
- 实现:`/JAVA/shop-api/src/main/java/com/gxwebsoft/shop/service/impl/WxSubscribeMessageServiceImpl.java`
- 功能:客户下单后自动推送微信小程序订阅消息给门店所有店员
- 流程:
1. 根据 `storeId` 查询 `shop_store_user` 表获取店员 userId 列表
2. 批量查询 `sys_user` 表获取店员小程序 openid
3. 调用 `WxMiniappAccessTokenService` 获取 access_token
4. 调用微信 `subscribeMessage.send` API 逐个发送
- 容错设计:
- 订单无 storeId 跳过
- 门店无店员/店员无 openid 跳过
- access_token 获取失败跳过
- errcode 43101用户未授权订阅正常跳过不报错
- 所有异常不向上抛出,不影响订单创建
#### 11.2 集成到 OrderBusinessService
- 修改 `OrderBusinessService.createOrder()` 方法
- 在保存订单和商品后、创建微信支付订单前,调用 `sendNewOrderNotification`
- 外层 try-catch 确保通知失败不影响主流程
#### 涉及文件
- 新建:`JAVA/shop-api/.../service/WxSubscribeMessageService.java`
- 新建:`JAVA/shop-api/.../service/impl/WxSubscribeMessageServiceImpl.java`
- 修改:`JAVA/shop-api/.../service/OrderBusinessService.java`
---
### 12. 订阅消息模板 ID 填入 + 错误提示优化
- 模板 ID`sh1K9iK7vZjebUNFu6OsMsnsJxm4whThWGrhN7I4zVg`(交易提醒)
- 字段:订单号(`character_string1`)、商品名称(`thing4`)、联系人(`thing10`)、联系电话(`phone_number7`)、送货地址(`thing8`)
- 优化 `requestSubscribeMessage` fail 回调errCode 20001 提示模板未配置20002/20004 提示已取消
### 13. 门店中心页 loading 状态修复
- `store/center/index.tsx``useEffect` 遗漏 `.finally(() => setLoading(false))`,导致页面卡在"加载中"
- 已修复
### 14. 分类页改造为左侧分类 + 右侧商品列表布局
- 重写 `src/pages/shop/category.tsx`
- 左侧:一级分类列表(绿色高亮选中态,保持不变)
- 右侧:
- 排序栏:默认/销量/最新/价格(可切换升降序)/筛选
- 商品卡片:横向布局(左图 + 右侧标题/积分标签/价格/销量 + 加购按钮)
- 滚动触底分页加载
- 点击商品跳转详情页,点击加购按钮调用 `addToCart` API
- 复用现有 VIP 价格逻辑(`isVipMember` + `dealerPrice`
- 编译通过