- 订单列表页未登录时弹出登录引导弹窗,而非直接跳转 - 登录页登录成功添加订单列表为白名单,支持登录后回跳订单页 - 我的页面菜单和订单按钮未登录时增加登录弹窗拦截 - 需登录菜单项添加 requireAuth 标记并视觉降级为半透明 - 订单快捷入口增加登录拦截和登录后回跳逻辑 - 修改“联系电话”为新号码,更新联系信息
134 lines
9.6 KiB
Markdown
134 lines
9.6 KiB
Markdown
## 购物车功能修复(2026-07-14)
|
||
|
||
### 问题
|
||
购物车页面(pages/shop/cart)商品显示异常:
|
||
- 商品名称/图片/价格信息缺失
|
||
- 加入购物车后无法正确显示
|
||
|
||
### 根因
|
||
`CartContext.refresh()` 方法在将后端 API 返回的购物车项映射为前端 `CartItem` 时,**遗漏了 `product`(商品详情)和 `sku`(SKU 详情)嵌套对象的映射**。导致页面中 `item.product?.name/image/price` 和 `item.sku?.price/image` 均为 `undefined`,UI 只能显示硬编码的默认值。
|
||
|
||
### 修改
|
||
1. **`src/contexts/CartContext.tsx`**(核心修复)
|
||
- `refresh()` 的 `mappedItems` 映射中补充 `product` 和 `sku` 字段
|
||
- 使用 `(item as any).product` / `(item as any).sku` 获取后端返回的嵌套对象
|
||
|
||
2. **`src/utils/image.ts`**(增强健壮性)
|
||
- 新增 `ensureFullUrl()` 辅助函数:相对路径自动补全 OSS 域名 `https://oss.wsdns.cn`
|
||
- `getCompressedImageUrl()` 内部调用 `ensureFullUrl` 确保 URL 完整性
|
||
|
||
3. **`src/pages/shop/cart.tsx`**(补充图片回退源)
|
||
- 图片 `src` 回退链增加 `(item.sku as any)?.image`
|
||
- 完整回退链:`goodsImage -> product.image -> sku.image -> ''`
|
||
|
||
## 收藏列表图片/价格不显示修复(2026-07-14)
|
||
|
||
### 问题
|
||
`pages/user/favorite-list/index` 收藏列表:商品图片、价格、名称均空白。
|
||
|
||
### 根因
|
||
后端 `/api/shop/goods/favorite/list`(前端 `/shop/goods/favorite/list`)走 `ShopGoodsFavoriteServiceImpl.listRel` → `selectListRel`,SQL 只 `SELECT a.*` 未关联商品表,返回字段仅 `id/userId/goodsId/merchantId/tenantId/createTime`,不含商品信息。前端依赖 `goodsImage/goodsName/price/salePrice` 均为 undefined。
|
||
|
||
### 修改(方案1:后端返回商品信息)
|
||
1. **后端** `guilixu-java`:
|
||
- `ShopGoodsFavorite.java`:新增 4 个 `@TableField(exist=false)` 非持久化字段 `goodsName(String)`、`goodsImage(String)`、`price(BigDecimal)`、`salePrice(BigDecimal)`,并补 `BigDecimal`/`TableField` import。
|
||
- `ShopGoodsFavoriteMapper.xml` 的 `selectSql`:`SELECT a.*, g.name AS goods_name, g.image AS goods_image, g.price AS price, g.sale_price AS sale_price`,`LEFT JOIN shop_goods g ON a.goods_id = g.goods_id`(已确认 `map-underscore-to-camel-case: true`,别名可映射)。
|
||
- 注意:本机无 maven 无法编译,改动为常规 MyBatis/MP 写法,需用户自行编译部署。
|
||
|
||
2. **前端**:
|
||
- `src/api/shop/shopGoodsFavorite/model.ts`:`favoriteId` 改为 `id`(后端实际返回 `id`);新增 `price?: string|number`;`salePrice` 改为 `string|number`。
|
||
- `pages/user/favorite-list/index.tsx`:图片用 `item.goodsImage`;价格改为优先 `item.price`(到手价),`salePrice` 作为划线价(`salePrice > price` 时显示);`key` 改用 `item.id ?? item.goodsId`(原 `favoriteId` 始终 undefined 会导致 key 重复)。
|
||
- 注:`src/pages/favorite-list.tsx` 为未注册路由的重复文件,未改动。
|
||
|
||
### 遗留(非本次范围,供参考)
|
||
adapter `/list` 接口忽略分页,一次返回全部收藏;前端 `listShopGoodsFavorite({page,limit:20})` 的无限滚动在收藏>20条时会重复追加。如需彻底解决建议改前端走 `/page` 接口或后端 `/list` 支持分页。
|
||
|
||
## 购物车更新 API 请求方式修复(2026-07-14)
|
||
|
||
### 问题
|
||
`PUT /api/shop/shop-cart/{id}` 返回 `HttpRequestMethodNotSupportedException: Request method 'PUT' not supported`。
|
||
|
||
### 根因
|
||
`src/api/shop/shopCart/index.ts` 中 3 个函数用了非标准 URL 模式 `PUT /shop/shop-cart/{id}`,而项目所有其他 API(shopOrder、shopArticle 等)的更新操作统一走 `PUT /shop/shop-cart`(基础 URL,id 放 body)。
|
||
|
||
### 修改
|
||
1. `updateCartNum`:`PUT /shop/shop-cart/{id}` + `{quantity}` → `PUT /shop/shop-cart` + `{id, num}`
|
||
2. `updateCartChecked`:`PUT /shop/shop-cart/{id}` + `{selected}` → `PUT /shop/shop-cart` + `{id, checked}`(同时修正字段名 `selected`→`checked` 与 model 一致)
|
||
3. `updateCartAllChecked`:`PUT /shop/shop-cart/selected` + `{selected}` → `POST /shop/shop-cart/selected` + `{checked}`(改用 POST,自定义批量操作更可能支持 POST;CartContext 已有静默 catch 兜底)
|
||
|
||
## 购物车后端 SQL 关联查询修复(2026-07-14)
|
||
|
||
### 问题
|
||
`GET /api/shop/shop-cart` 返回的数据没有商品图片、价格等信息。前端 `CartContext.refresh()` 已映射 `goodsName/goodsImage/skuPrice/skuSpec/stock` 等字段,但后端根本没返回这些字段。
|
||
|
||
### 根因
|
||
后端 `ShopCartMapper.xml` 的 SQL 只做 `SELECT a.* FROM shop_cart a`,没有 JOIN 商品表和 SKU 表。
|
||
|
||
### 后端修改(`guilixu-java` 项目)
|
||
1. **`ShopCart.java`**:新增 7 个 `@TableField(exist = false)` 非持久化字段:`goodsName`、`goodsImage`、`skuPrice`、`skuSpec`、`stock`、`salePrice`、`dealerPrice`;补充 `TableField` import
|
||
2. **`ShopCartMapper.xml`**:SQL 改为 `LEFT JOIN shop_goods g ON a.goods_id = g.goods_id` + `LEFT JOIN shop_goods_sku s ON a.sku_id = s.id`,SELECT 别名映射到新字段(`COALESCE(s.price, g.price) AS sku_price`、`COALESCE(s.stock, g.stock) AS stock`);同时修复 `userId/goodsId/merchantId` 从 `LIKE` 改为 `=`(原 LIKE 会导致 userId=1 匹配到 10/11/21 等)
|
||
3. **`ShopCartController.java`**:`list()` 方法自动按当前登录用户过滤(`param.setUserId(loginUser.getUserId().longValue())`)
|
||
|
||
### 前端修改
|
||
4. **`src/api/shop/shopCart/model/index.ts`**:`ShopCart` 接口新增 `salePrice`、`dealerPrice` 字段
|
||
5. **`src/contexts/CartContext.tsx`**:`CartItem` 新增 `salePrice`、`dealerPrice`;`refresh()` 映射这两个字段;`calcPrice()` VIP 优先用扁平 `i.dealerPrice`(之前只看 `i.product?.dealerPrice`)
|
||
6. **`src/pages/shop/cart.tsx`** + **`src/pages/shop/checkout.tsx`**:价格显示逻辑同步更新,优先使用扁平 `item.dealerPrice` / `item.salePrice`
|
||
|
||
## 购物车前后端字段名对齐修复(2026-07-14)
|
||
|
||
### 问题
|
||
修改购物车数量时后端报 `UPDATE shop_cart WHERE id=?`(SET 子句为空),MyBatis-Plus 找不到要更新的字段。
|
||
|
||
### 根因
|
||
前后端字段名不匹配:
|
||
- 前端发送 `num`,后端实体字段是 `cartNum` → Jackson 反序列化时 `cartNum` 为 null → 空 UPDATE
|
||
- 前端发送 `checked`,后端实体字段是 `selected` → 同样不匹配
|
||
- 列表返回 `cartNum`,前端读 `item.num` → 数量永远为默认值 1
|
||
|
||
### 修改文件
|
||
1. **`src/api/shop/shopCart/model/index.ts`**:`ShopCart.num` → `cartNum`;新增 `selected` 字段;`AddToCartParam.num` → `cartNum`;`UpdateCartNumParam.num` → `cartNum`
|
||
2. **`src/api/shop/shopCart/index.ts`**:`updateCartNum` 发 `{id, cartNum}`;`updateCartChecked` 发 `{id, selected}`
|
||
3. **`src/contexts/CartContext.tsx`**:`refresh()` 读 `item.cartNum` 和 `item.selected`;`addItem()` 发 `cartNum`;`updateQuantity` 调用 `{id, cartNum}`
|
||
4. **`src/pages/shop/index.tsx`** + **`src/pages/shop/category.tsx`**:`addToCart` 参数 `num` → `cartNum`
|
||
|
||
## 禁用 loginByOpenId 静默登录(2026-07-14)
|
||
|
||
### 改动
|
||
- **`src/contexts/UserContext.tsx`**:移除"情况3"静默登录块(`Taro.login` + `loginByOpenId`),无 token 时直接保持未登录状态;清理 `loginByOpenId`、`TenantId` 无用导入
|
||
- **`src/hooks/useUser.ts`**:移除降级方案中的 `loginByOpenId` 调用,仅从 storage 读取;清理 `loginByOpenId`、`TenantId` 无用导入
|
||
- `src/api/layout/index.ts` 中 `loginByOpenId` 函数定义保留,仅不再被调用
|
||
|
||
## 商城分类页价格登录可见(2026-07-14)
|
||
|
||
### 改动
|
||
- **`src/pages/shop/index.tsx`**:价格显示从手写 `Text` 改为 `Price` 组件 + `loginMask` 属性(与首页一致),游客看到"登录后查看价格";VIP 划线价逻辑保留在 `original` prop 中;单位 `unitName` 仅登录后显示
|
||
|
||
## 订单列表页未登录可查看订单 Bug 修复(2026-07-14)
|
||
|
||
### 问题
|
||
`pages/order/list` 未登录用户也能看到订单数据。
|
||
|
||
### 根因
|
||
页面缺少登录校验——`useEffect` 直接调用 `loadOrders`,未登录时 `user?.userId` 为 `undefined`,后端未按用户过滤直接返回了订单。
|
||
|
||
### 修改
|
||
- **`src/pages/order/list.tsx`**:
|
||
1. 从 `useUser()` 获取 `isLoggedIn`
|
||
2. `useEffect` 中未登录时调用 `requireLogin({ action: 'viewOrder', redirect: '/pages/order/list', content: '登录后才能查看订单,是否前往登录?' })` 弹窗引导,而不是直接跳转
|
||
3. render 中 `if (!isLoggedIn) return null` 兜底,避免未登录时渲染订单内容
|
||
- **`src/passport/login.tsx`**:登录成功后的 `tabBarUrls` 白名单补全 `pages/order/list`,确保从订单入口登录后能 `switchTab` 回订单页
|
||
|
||
## 我的页面未登录可点击需登录功能 Bug 修复(2026-07-14)
|
||
|
||
### 问题
|
||
`pages/user/user` 未登录时,点击「我的订单」下的按钮(待付款/待发货/待收货/已完成)、「全部订单」、以及菜单中的「升级VIP会员」「我的钱包」「收货地址」「我的收藏」都能直接跳转页面。
|
||
|
||
### 修改
|
||
- **`src/pages/user/user.tsx`**:
|
||
1. 导入 `requireLogin` from `@/utils/login-guard`
|
||
2. 给需要登录的菜单项加 `requireAuth: true` 标记(升级VIP会员/门店中心/我的钱包/收货地址/我的收藏)
|
||
3. 新增 `handleMenuClick(item)`:`requireAuth` 项调用 `requireLogin` 弹窗拦截,已登录才 `navigateTo`
|
||
4. 新增 `handleOrderTabClick(status)` 和 `handleViewAllOrders()`:订单入口 `requireLogin` 拦截,并加 `redirect: '/pages/order/list'` 让登录后回跳订单页
|
||
5. 未登录时需登录的菜单项和订单按钮加 `opacity-50` 视觉降级
|
||
6. 「帮助中心」「设置」不需要登录,保持原样
|