diff --git a/.workbuddy/memory/2026-07-15.md b/.workbuddy/memory/2026-07-15.md index 1108c35..8ecb81a 100644 --- a/.workbuddy/memory/2026-07-15.md +++ b/.workbuddy/memory/2026-07-15.md @@ -137,3 +137,23 @@ - Button 样式重置:height:auto / lineHeight:normal / padding:16px / border:none / borderRadius:8px,保持原视觉(白底圆角卡片) - 引入:从 `@tarojs/components` 新增导入 `Button` - 注意:微信客服 Button 在开发者工具中无效,需真机预览测试 + +## 修复 VIP 价格首页不显示 + 后端不认 price 字段 +- **问题 1(首页)**:`src/pages/index/index.tsx`(tabBar 首页)没接入 `useVipStatus`,热销推荐价格一直显示 `product.price` 而非 `dealerPrice`。商品详情/商城列表/购物车/分类都修了,唯独漏了 tabBar 首页 +- **问题 2(后端 DTO 缺字段)**:前端 `OrderGoodsItem` 已传 `price` 字段,但后端 `OrderCreateRequest.OrderGoodsItem`(嵌套静态类)**根本没有 `price` 字段**,Jackson 反序列化直接丢弃。后端 `OrderBusinessService.validateAndCalculateTotal()` 和 `saveOrderGoods()` 都用 `goods.getPrice()` 兜底 —— 这就是「前端传的对、后端处理就错」的根本原因 +- **修复(3 个文件)**: + 1. `src/pages/index/index.tsx` + - 引入 `useVipStatus`,加 `const { isVip } = useVipStatus()` + - 加 `getHotDisplayPrice()`:VIP + 有 dealerPrice → `{price: dealerPrice, original: price}`,否则原逻辑 + - Price 组件传 `price + original` + 旁边加金色「VIP」角标 + 2. `/Users/gxwebsoft/JAVA/guilixu-java/src/main/java/com/gxwebsoft/shop/dto/OrderCreateRequest.java` + - `OrderGoodsItem` 内部类加 `private BigDecimal price;` 字段 + `@DecimalMin("0")` 校验 + 3. `/Users/gxwebsoft/JAVA/guilixu-java/src/main/java/com/gxwebsoft/shop/service/OrderBusinessService.java` + - `validateAndCalculateTotal()` 和 `saveOrderGoods()` 两处重构:先取 sku(无论价格来源都要校验 sku 合法性+取库存),再用「前端 price > sku.price > goods.price」优先级决定 actualPrice + - 注意不要把 sku 查询和 price 选择耦合在同一个 if-else 链里,否则 VIP+多规格商品会跳过 sku 库存校验 +- **编译验证**:Maven compile 成功无报错;后端需重启服务才能生效 +- **价格字段约定(再确认)**: + - `goods.price` - 到手价(主价格) + - `goods.salePrice` - 市场价(划掉的) + - `goods.dealerPrice` - VIP 专享价 + - 前端传 `dealerPrice` 到 `OrderGoodsItem.price`,后端通过该字段下单 diff --git a/src/pages/index/index.tsx b/src/pages/index/index.tsx index 5eadd3a..fd839e3 100644 --- a/src/pages/index/index.tsx +++ b/src/pages/index/index.tsx @@ -5,6 +5,7 @@ import { useUser } from '@/hooks/useUser' import { useShare } from '@/hooks/useShare' import { useScrollHeight } from '@/hooks/useScrollHeight' import { useNewOrderDetector } from '@/hooks/useNewOrderDetector' +import { useVipStatus } from '@/hooks/useVipStatus' import { getMyClerk } from '@/api/shop/shopStoreUser' import { pageShopOrder } from '@/api/shop/shopOrder' import { listCmsAd } from '@/api/cms/cmsAd' @@ -29,6 +30,8 @@ const IndexPage: React.FC = () => { const [hotProducts, setHotProducts] = useState([]) const [loading, setLoading] = useState(true) const scrollHeight = useScrollHeight(44) + // VIP 状态:异步校验并更新缓存,isVip 变化时触发重渲染 + const { isVip } = useVipStatus() // 首页分享:好友 + 朋友圈 + 复制链接(右上角三个按钮全亮) useShare({ @@ -165,6 +168,17 @@ const IndexPage: React.FC = () => { Taro.navigateTo({ url: '/pages/index/notification' }) } + /** + * VIP 会员显示 dealerPrice(同时把 price 作为划线原价),非 VIP 维持原行为 + */ + const getHotDisplayPrice = (item: ShopGoods): { price: string; original?: string } => { + if (isVip && item.dealerPrice) { + return { price: item.dealerPrice, original: item.price } + } + const original = item.salePrice && item.salePrice !== item.price ? item.salePrice : undefined + return { price: item.price || '0', original } + } + // tabBar 页面列表 const tabBarPages = ['/pages/index/index', '/pages/shop/index', '/pages/order/list', '/pages/user/user'] @@ -330,11 +344,14 @@ const IndexPage: React.FC = () => { {item.goodsName || item.name} + {isVip && item.dealerPrice ? ( + VIP + ) : null} {item.sales !== undefined && item.sales > 0 && ( 已售 {item.sales}