# 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`) - 编译通过