Просмотр исходного кода

docs(requirements): 需求变更登记 2026-11-13(家庭运营工作台重构 + 订单售后与购买体验优化)

Agnes Agent 1 день назад
Родитель
Сommit
538bc1de20

+ 58 - 0
docs/需求分析/2026-11-13-家庭运营工作台重构需求变更.md

@@ -0,0 +1,58 @@
+# 家庭运营工作台重构需求变更
+
+> 变更编号:FAMILY-WB-2026-11-13-V1 | 变更日期:2026-11-13 | 版本:v1.0
+> 需求来源:用户 2026-11-13 管理端体验反馈
+> 状态:已实现待合入(f9b880b59 推 feature 分支,待评审合 cfclub)
+
+## 一、需求原话
+
+> 重新设计家庭运营工作台,上半部分内容应该有一些只能放到家庭工作台里的,你做好分类处理。家庭列表上保留进入工作台和编辑即可,其他更多功能都应该在家庭工作台中处理。家庭工作台显示家庭的统计数字和指标曲线,点击统计数字进入相应列表进行操作,比如代传报告、方案审核、创建任务、查看CF值、奖励、心愿、消息等等与单一家庭有关的信息。家庭运营工作台放所有家庭相关的信息,家庭工作台里只放与当前家庭有关的信息。
+
+## 二、现状核查
+
+- `cfc-web/src/views/Families.vue`(家庭运营工作台)行操作含「更多」下拉(详情/优惠券管理/代传报告/计划生成)+ 行内报告数/方案数/任务数/优惠券数可点击链接 + 「家庭总收益 —」占位卡片——**单家庭功能与跨家庭运营功能混杂在同一列表页**。
+- 无「单家庭工作台」页面:家庭维度的报告/计划/任务/优惠券/CF值/奖励/心愿/消息 全部依赖列表页行内入口或散落各管理页,无法集中操作单一家庭。
+- 后端已有 `FamilyAdminOverviewService.buildOverview(familyId)`(家庭+统计+报告+计划)、`pageTasks(id,page,size)`(`/api/admin/families/{id}/tasks`);**缺 CF 值家庭维度汇总**(现有接口仅按 memberId/userId)与**缺消息家庭维度查询**(`TeacherMessageController` 仅 teacher/家长 userId 维度)。
+
+## 三、需求变更定义
+
+### S1 家庭运营工作台(列表页)精简为纯跨家庭运营视角
+
+| 变更 | 文件 | 内容 |
+|---|---|---|
+| S1-1 | `Families.vue` | 副标题改「运营总览(跨家庭)」;行操作只保留【进入工作台】【编辑】,**删除「更多」下拉**;报告/方案/任务/优惠券数改为纯文本(不可点击);移除「家庭总收益 —」占位卡片;quickEntries 补入 CF 值管理(`/cf-value`);删除 `handleMoreCmd / goCouponManage / goProxyReportUpload / openPlanGen / openDetailDialog / loadDetail / loadTasks` 等方法与详情弹窗模板;「进入工作台」→ `push('/family-workbench?familyId=<id>')` |
+
+### S2 单家庭工作台页面(FamilyWorkbench.vue)
+
+| 变更 | 文件 | 内容 |
+|---|---|---|
+| S2-1 | `cfc-web/src/views/FamilyWorkbench.vue`(**新增**) | ① 页头:返回列表 + 家庭名/邀请码/创建时间/成员数;② 统计卡片带(8 张可点击,含 pending_review/进行中角标)切换对应 tab;③ ECharts 指标曲线区(报告趋势 + CF 值累计趋势,无数据空态);④ 9 个 tab:报告(代传报告按钮)/方案(审核入口+待审角标)/任务(创建任务入口+分页)/CF值(成员余额表+合计+流水)/奖励(分页+跳转)/心愿(分页+跳转)/咨询消息(分页+跳转)/成员(设为管理员/撤销)。点击统计数字进入对应列表操作——**全部限定当前家庭** |
+| S2-2 | `router/index.js` | 注册 `/family-workbench`,`meta.perm='family:list'`,懒加载 `FamilyWorkbench.vue` |
+| S2-3 | `api/admin.js` | 新增 `getFamilyCfSummary(id, params)`、`getFamilyMessages(id, params)` |
+
+### S3 后端家庭维度接口补齐
+
+| 变更 | 文件 | 内容 |
+|---|---|---|
+| S3-1 | `AdminFamilyOverviewController.java` | 新增 `POST /api/admin/families/{id}/cf-summary`(调 CfBalanceService.getCfSummary,校验 role=admin)、`POST /api/admin/families/{id}/messages`(调 TeacherMessageService.getFamilyMessages,校验 role=admin) |
+| S3-2 | `CfBalanceService` / `CfBalanceServiceImpl` | 新增 `getCfSummary(familyId, page, size)`:查 `family_members`(排回收箱)→ 逐人 `getBalance` 累加 totalAvailable/totalFrozen → 各成员 `getLogs` 合并按 createdAt 倒序内存分页返回。**注意**:`getBalance/getLogs` 本就按 memberId 语义,用 `fm.getId()` 正确 |
+| S3-3 | `TeacherMessageService` | 新增 `getFamilyMessages(familyId, page, size)`:按 familyId 分页 + 回填 parentId/teacherId 昵称。**昵称通过回显字段 `parentName`(`@TableField(exist=false)`)返回,不得拼接进 `content` 污染消息原文**(核验修复 a00b4ba6b) |
+
+## 四、验收
+
+- `/families` 列表操作列只有【进入工作台】【编辑】;无更多下拉、无行内明细链接;统计条与快捷入口保留(含 CF 值入口);无「家庭总收益 —」占位。
+- `/family-workbench?familyId=N` 可访问;统计卡片带 8 项数字与 tab 一致;报告/CF 趋势曲线渲染(有数据)或空态(无数据)。
+- 报告 tab 可代传报告、方案 tab 可见待审角标并可审核、任务 tab 可创建任务、CF 值 tab 显示成员余额+合计+流水、消息 tab 显示该家庭咨询列表(昵称回显不污染 content)、成员 tab 可设管理员/撤销。
+- 后端 2 端点 `mvn clean compile` 通过;管理端可正常操作单一家庭全流程。
+
+## 五、风险
+
+- `getFamilyMessages` 回填昵称使用「回显字段+@TableField(exist=false)」模式(参照 `teacherName` 先例),不新增表列、不影响 `teacher_messages` 表结构。
+- `getCfSummary` 内存切片分页仅适用家庭规模较小的场景(<100 成员),量级可接受;远期可改 SQL 分页。
+- 统计卡角标依赖请求频度,须在页面 `mounted` 一次性拉全量(报告/方案/任务各频度接口已有),避免高频轮询。
+
+## 六、关联记录
+
+- 已实现:feature 分支 `feature/family-workbench-redesign`,feature commit `f9b880b59`、核验修复 `a00b4ba6b`、设计文档 `4e2974449`(worktree `E:/tmp/family-workbench`)
+- 设计文档:`docs/design/2026-11-13-family-workbench-redesign.md`
+- 本变更合入 cfclub 后,实现合入时补 merge commit 记录于此。

+ 68 - 0
docs/需求分析/2026-11-13-订单售后与购买体验优化需求变更.md

@@ -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 记录于此。