|
|
@@ -0,0 +1,68 @@
|
|
|
+# 订单售后与购买体验优化需求变更
|
|
|
+
|
|
|
+> 变更编号:SHOP-AFTERSALES-2026-11-13-V1 | 变更日期:2026-11-13 | 版本:v1.0
|
|
|
+> 需求来源:用户 2026-11-13 小程序端体验反馈
|
|
|
+> 状态:待实现(设计规范已定稿,见下文「设计文档」)
|
|
|
+
|
|
|
+## 一、需求原话
|
|
|
+
|
|
|
+> 1、用户在小程序误点退款后,后台还没处理退款时应该可以取消退款。
|
|
|
+> 2、另外,用户在订单里,应该是可以使用"再买一单",进行重新购买的。
|
|
|
+> 3、当商品可以使用优惠券时,应该有比较明显的提示,或者按最优规则,先帮用户选上。
|
|
|
+
|
|
|
+## 二、现状核查
|
|
|
+
|
|
|
+- **取消退款缺失**:`AfterSalesService.create()` 创建售后单后即把订单置为 `status="refunding"`、`refundStatus=1`;`AfterSalesRequest.status` 仅有 `pending → approved → completed / rejected`,**无 cancelled 通道**;`ProductOrder` 实体与 `product_orders` 表**未保存退款前状态**(无 `refund_before_status` / `refund_before_refund_status`),一旦申请退款即无法回滚订单原状态。管理端审核中(`pending`)期间用户无任何取消入口。
|
|
|
+- **再买一单体验断链**:`order-detail.vue onBuyAgain()` 仅 `uni.navigateTo` 跳商品详情页,用户需重新点「立即购买」再进结算,两步断链;结算页 `checkout.vue onLoad` 已原生支持从 storage `checkoutItems`(`[{productId, productName, coverImage, unitPrice, quantity}]`)读商品并 `calcAmount()`,具备直进结算的通道但未复用。
|
|
|
+- **优惠券选择不自动**:`checkout.vue autoSelectCoupon()` 仅处理 `from=coupon&couponId=` 深链透传场景;常规结算(购物车/商品直购)进入时即使用户有可用券,也不自动选、无「可用 N 张」的明显提示;`ownedCoupons` computed 已按 商品类型/满减门槛/金额 过滤,选择与折扣计算链路(`selectCoupon → applyCouponDiscount`,折扣由服务端 `/api/coupon/apply` 计算)完整可用。
|
|
|
+
|
|
|
+## 三、需求变更定义
|
|
|
+
|
|
|
+### S1 取消退款(用户误点可撤销)
|
|
|
+
|
|
|
+| 变更 | 文件 | 内容 |
|
|
|
+|---|---|---|
|
|
|
+| S1-1 | `cfc-backend/src/main/resources/db/migration/V254__add_refund_before_state_to_product_orders.sql`(**新增**) | `product_orders` 加 `refund_before_status varchar(32)`(退款前订单状态)与 `refund_before_refund_status tinyint(1) DEFAULT 0`(退款前退款状态) |
|
|
|
+| S1-2 | `ProductOrder.java` | 实体新增 `refundBeforeStatus` / `refundBeforeRefundStatus` 两字段(对应 S1-1 列) |
|
|
|
+| S1-3 | `AfterSalesService.create()` | 订单置 `refunding` **之前**,快照 `refundBeforeStatus=原status`、`refundBeforeRefundStatus=原refundStatus` |
|
|
|
+| S1-4 | `AfterSalesService` 新增 `cancel`(或 `cancelByOrderId`) | 校验:售后单存在、属于当前用户、`status="pending"`(后台未处理才可取消);订单处于 `refunding` 且 `refundStatus=1`。动作:售后单置 `cancelled`;订单回滚 `status=refundBeforeStatus`、`refundStatus=refundBeforeRefundStatus`(null 兜底 `paid`/`0`),清空 `refundReason/refundAmount/refundTime` |
|
|
|
+| S1-5 | `AfterSalesController` 新增 `POST /api/shop/after-sales/cancel` | 小程序的取消退款端点(userId 取登录态,与 create/list 一致) |
|
|
|
+| S1-6 | `order-detail.vue` | `refundStatus===1`(退款申请处理中)时显示「取消退款申请」按钮:`uni.showModal` 二次确认 → 调 cancel 接口 → 成功 toast「已取消」并刷新订单详情;失败(后台已处理)提示接口返回 |
|
|
|
+| S1-7 | `after-sales.vue` | `pending` 状态的申请卡片提供「取消退款」操作(复用同一接口,建议项) |
|
|
|
+
|
|
|
+### S2 再买一单(一键直进结算)
|
|
|
+
|
|
|
+| 变更 | 文件 | 内容 |
|
|
|
+|---|---|---|
|
|
|
+| S2-1 | `order-detail.vue onBuyAgain()` | 由「跳商品详情」改为:构造 `[{productId, productName, coverImage, unitPrice, quantity}]`(`this.order` 字段)写入 storage `checkoutItems`,`uni.navigateTo('/pages/shop/checkout/checkout')` 直进结算;商品已下架等异常保持跳详情兜底。按钮条件维持 `order.status === 'completed'`,不放开 paid/shipped/pending_receipt(避免与「申请售后」入口歧义) |
|
|
|
+
|
|
|
+### S3 优惠券最优选择与明显提示
|
|
|
+
|
|
|
+| 变更 | 文件 | 内容 |
|
|
|
+|---|---|---|
|
|
|
+| S3-1 | `checkout.vue autoSelectCoupon()` 扩展 | `loadCoupons()` 成功后:`_autoCouponId` 深链逻辑保留在前;否则若 `ownedCoupons` 非空且用户本次未手动取消过券(`data._couponDismissed !== true`),从 `ownedCoupons` 中选 `value` 最大(同 value 取 `minSpend` 最小)自动 `selectCoupon(best)`,触发服务端重算;置 `_autoSelected=true` 防重复 |
|
|
|
+| S3-2 | `checkout.vue` 优惠券区提示 | 未选券但 `ownedCoupons.length > 0` 时显示「有 N 张优惠券可抵,点击选择」醒目提示;自动选中后券区正常展示抵扣额,可加「已按最优自动选择」小字 |
|
|
|
+| S3-3 | `checkout.vue removeCoupon()` | 用户手动取消券后置 `_couponDismissed=true`(本次结算会话内不再自动选;页面销毁自然重置) |
|
|
|
+
|
|
|
+**设计文档**:`docs/design/2026-11-14-order-refund-coupon-improvements.md`(feature 分支 `feature/order-refund-coupon-improvements` commit `2bd41ec3f`)
|
|
|
+
|
|
|
+## 四、验收
|
|
|
+
|
|
|
+- 误点退款:`refundStatus===1` 时点「取消退款申请」→ 售后单变 `cancelled`、订单恢复原 `status`(paid/shipped/pending_receipt)且 `refundStatus=0`、`refundReason/refundAmount/refundTime` 清空。
|
|
|
+- 后台已 approve/reject 后:用户取消返回「后台已处理,无法取消」。
|
|
|
+- `refundStatus===2`(已退款)/3(拒绝)等状态不展示取消按钮。
|
|
|
+- 「再买一单」:completed 订单一键直达结算页,商品信息正确、金额可算、可提交下单。
|
|
|
+- 优惠券:商品有可用券时自动选面额最优券并显示抵扣;手动取消后本次不再自动选且显示「有 N 张优惠券可抵」;深链 `from=coupon` 场景不受影响。
|
|
|
+- 后端 `mvn clean compile` 通过;前端 lint/语法通过。
|
|
|
+
|
|
|
+## 五、风险
|
|
|
+
|
|
|
+- `V254` 迁移属加列(`ADD COLUMN`),对存量数据无破坏;Flyway 按命名规范执行,需在 `resources/db/migration/` 下按既有 `V2xx__描述.sql` 序号续接(并存服务需确认均已引入该目录)。
|
|
|
+- 取消退款仅允许 `pending` 状态,避免与管理端审核并发竞态;若管理端先审核通过(approved),用户侧取消被拒是预期行为。
|
|
|
+- 自动选券仅影响展示与「默认选中」,最终折扣仍由服务端 `/api/coupon/apply` 计算,与下单落库一致,无金额风险;用户可随时手动更换/取消。
|
|
|
+
|
|
|
+## 六、关联记录
|
|
|
+
|
|
|
+- 待实现:feature 分支 `feature/order-refund-coupon-improvements`(worktree `E:/tmp/family-cart`)
|
|
|
+- 设计文档:`docs/design/2026-11-14-order-refund-coupon-improvements.md`
|
|
|
+- 本变更合入 cfclub 后,实现合入时补 merge commit 记录于此。
|