|
|
@@ -0,0 +1,180 @@
|
|
|
+#### 需求指令:
|
|
|
+hdApp 项目下 @hdApp/src/pagesPurchase/purDetails.vue 页面有个“申请售后”按钮,点击后跳转到 @hdApp/src/pagesPurchase/refund.vue 进行售后。
|
|
|
+
|
|
|
+需求:mallApp 项目下的 @mallApp/src/pages/order/detail.vue 页面也要实现同样的“申请售后”功能,后端要新增api请参照 hdApp 后端的实现来进行,附带考虑以下情形:
|
|
|
+1. 请查询 xhDistributionOrder 表,如果某订单与分销有关联,则要查询 xhDistributionRule 表的 settleDays字段,超过 settleDays 天后就不能发起退款
|
|
|
+2. 发起退款后,如果该订单使用了红包,且红包在退款期间没过期,要正常返回
|
|
|
+3. 页面颜色主调及按钮颜色以店铺首页为参照
|
|
|
+#### AI的输出
|
|
|
+---
|
|
|
+name: mallApp售后申请与审核
|
|
|
+overview: 在 mallApp 订单详情页新增"申请售后"入口与申请页,新增 app-mall 后端受理接口,售后申请以"待审核"状态入库,由商家在 hdApp 后台新增的审核页人工通过/驳回;通过时复用 hd 现有退款资金处理逻辑,并新增分销 settleDays 期限校验与红包按过期状态自动退回。
|
|
|
+todos:
|
|
|
+ - id: sql
|
|
|
+ content: 新增 xhMallRefundApply 表结构 SQL 脚本
|
|
|
+ status: completed
|
|
|
+ - id: biz-model
|
|
|
+ content: 新增 biz-hd/refund 下 MallRefundApply 的 Model/Class/Service
|
|
|
+ status: completed
|
|
|
+ - id: distribution-check
|
|
|
+ content: DistributionOrderClass 新增 assertRefundNotExpired 分销超期校验
|
|
|
+ status: completed
|
|
|
+ - id: hb-check
|
|
|
+ content: HbClass 新增 hbBackIfNotExpired 红包过期判断退回
|
|
|
+ status: completed
|
|
|
+ - id: app-mall-controller
|
|
|
+ content: 新增 app-mall RefundController(顾客提交/查看/撤销申请)
|
|
|
+ status: completed
|
|
|
+ - id: app-hd-controller
|
|
|
+ content: app-hd RefundController 新增商家审核通过/驳回 action
|
|
|
+ status: completed
|
|
|
+ - id: mallapp-frontend
|
|
|
+ content: mallApp:详情页按钮 + 新建 refund.vue 申请页 + api + pages.json 注册
|
|
|
+ status: completed
|
|
|
+ - id: hdapp-frontend
|
|
|
+ content: hdApp:新建审核列表/详情页 + 入口 + api + pages.json 注册
|
|
|
+ status: completed
|
|
|
+isProject: false
|
|
|
+---
|
|
|
+
|
|
|
+# mallApp 申请售后功能 + 后台人工审核
|
|
|
+
|
|
|
+## 背景与关键结论(已调研确认)
|
|
|
+- mallApp 订单与 hdApp 零售订单共用同一张 `xhOrder` 表(`bizMall\order\models\Order` 与 `bizHd\order\models\Order` 的 `tableName()` 都是 `xhOrder`),mall 下单/支付主流程已直接复用 `bizHd`([biz-hd/order/services/OrderService.php](../../huahuibao/biz-hd/order/services/OrderService.php)),红包、分销体系也都是 `bizHd` 的共享实现。
|
|
|
+- `app-mall` 目前**没有**任何退款/售后 Controller;完整的退款资金处理逻辑只存在于 [app-hd/controllers/RefundController.php](../../huahuibao/app-hd/controllers/RefundController.php)(`actionCreateOrder`,仅限门店超管调用)+ [biz-hd/refund/services/HdRefundService.php](../../huahuibao/biz-hd/refund/services/HdRefundService.php)(`addRefund`:校验退款金额、写 `xhHdRefund`/`xhHdRefundGoods`/`xhHdRefundItem`、按支付方式做 Lakala 线上原路退款 / 欠款冲减 / 现金支出 / 余额退回)。mall 的微信支付实际也是走 Lakala 聚合网关(`OrderController::actionWxPay` 里 `$laResource->driveWxPay(...)`),因此这套资金退款逻辑对 mall 订单同样适用,**直接复用,不重复实现**。
|
|
|
+- 用户已确认:mallApp 顾客提交"申请售后"**只生成待审核记录**,不立即执行资金退款;真正的退款仍由商家在 hdApp 后台人工审核通过后才执行(内部复用上面这套 `HdRefundService::addRefund`)。
|
|
|
+- 退款方式需同时支持"退货并退款"(勾选商品/花材及数量)和"仅退款",与 [hdApp/src/admin/order/refund.vue](../../front-end/hdApp/src/admin/order/refund.vue) 的商品选择结构一致(`goodsInfoList`/`itemList`,字段 `num`/`refundNum`/`unitPrice` 与 mall 订单详情数据结构完全一致)。
|
|
|
+- 分销:`xhDistributionOrder`([DistributionOrder.php](../../huahuibao/biz-hd/distribution/models/DistributionOrder.php))按 `orderId` 关联订单,`finishTime` 对齐 `xhOrder.successTime`;`xhDistributionRule`([DistributionRule.php](../../huahuibao/biz-hd/distribution/models/DistributionRule.php))按 `shopId` 存 `settleDays`(默认 5 天,[DistributionRuleClass::defaultRule](../../huahuibao/biz-hd/distribution/classes/DistributionRuleClass.php))。目前全仓库没有任何"退款超期校验",需要新增。
|
|
|
+- 红包:`HbClass::hbBack`([HbClass.php](../../huahuibao/biz-hd/hb/classes/HbClass.php))现状**不判断过期**,直接把红包置回可用。需求要求"退款期间未过期才正常退回",因此新增一个带过期判断的包装方法,不改动现有 `hbBack`(避免影响 hdApp 现有人工退款红包开关的既有行为)。
|
|
|
+
|
|
|
+## 数据模型:新增顾客售后申请表
|
|
|
+新增 `xhMallRefundApply`(放在新 SQL 文件 `huahuibao/sql/20260730_mall_refund_apply.sql`,风格参照 [sql/20260730_seckill.sql](../../huahuibao/sql/20260730_seckill.sql)):
|
|
|
+
|
|
|
+- `id`, `mainId`, `shopId`, `hdId`, `customId`, `userId`
|
|
|
+- `orderId`, `orderSn`
|
|
|
+- `refundType`(1退货并退款 2仅退款)
|
|
|
+- `product`(JSON,勾选的商品/花材及数量、单价快照)
|
|
|
+- `refundPrice`(系统按勾选数量自动计算,不可编辑)
|
|
|
+- `remark`(顾客备注,选填)
|
|
|
+- `hbId`(下单时红包 id 快照,仅展示用)
|
|
|
+- `status`(0待审核 1已通过 2已驳回 3已取消)
|
|
|
+- `rejectReason`、`auditAdminId`、`auditAdminName`、`auditTime`
|
|
|
+- `hdRefundId`(审核通过后关联生成的 `xhHdRefund.id`)
|
|
|
+- `addTime`
|
|
|
+
|
|
|
+对应新增 Model/Class/Service(放 `biz-hd/refund/` 下,与 `HdRefund` 同域,方便复用):
|
|
|
+- `biz-hd/refund/models/MallRefundApply.php`
|
|
|
+- `biz-hd/refund/classes/MallRefundApplyClass.php`(CRUD、`valid()`、列表查询,参照 [HdRefundClass.php](../../huahuibao/biz-hd/refund/classes/HdRefundClass.php)/[CgRefundClass.php](../../huahuibao/biz-hd/cg/classes/CgRefundClass.php) 风格)
|
|
|
+- `biz-hd/refund/services/MallRefundApplyService.php`:
|
|
|
+ - `createApply($post, $order)`:只做校验 + 插入待审核记录,不动订单/资金字段
|
|
|
+ - `approve($apply, $order, $shopAdmin)`:组装 `HdRefundService::addRefund` 所需 `$post`,调用它完成真正扣款/退款,随后处理红包(见下)、累计消费回退(照抄 `RefundController::actionCreateOrder` 里 `xhCustom.buyAmount`/`xhHd.expendAmount` 回退段落)、`DistributionCommissionClass::tryCalcDistributionAfterPay`,最后把 `apply.status=1`、`hdRefundId` 写回
|
|
|
+ - `reject($apply, $reason)` / `cancel($apply)`:改状态,不涉及资金
|
|
|
+
|
|
|
+## 分销 settleDays 校验(新增,顾客提交申请时校验)
|
|
|
+在 [DistributionOrderClass.php](../../huahuibao/biz-hd/distribution/classes/DistributionOrderClass.php) 新增方法 `assertRefundNotExpired($orderId, $shopId, $mainId)`:
|
|
|
+1. 按 `orderId` 查 `xhDistributionOrder`,无记录说明订单与分销无关,直接放行。
|
|
|
+2. 有记录则取 `finishTime`(对应订单完成时间),若为空说明订单还未计入完成,暂不限制。
|
|
|
+3. 调 `DistributionRuleClass::getRule($shopId, $mainId)` 取 `settleDays`。
|
|
|
+4. 若 `time() > strtotime(finishTime) + settleDays*86400`,`util::fail('该订单已超过售后期限(完成后 N 天内可申请),无法再发起退款')`。
|
|
|
+
|
|
|
+在 `app-mall` 新 `RefundController::actionCreateOrder` 校验链路里,紧跟订单状态校验之后调用该方法。
|
|
|
+
|
|
|
+## 红包按过期状态退回(新增,审核通过时执行)
|
|
|
+在 [HbClass.php](../../huahuibao/biz-hd/hb/classes/HbClass.php) 新增 `hbBackIfNotExpired($order)`:
|
|
|
+- 若 `hbId<=0` 直接返回
|
|
|
+- 查红包,若 `endTime >= time()`(未过期)→ 调用现有 `hbBack($order)` 正常退回(`status=0`,解除占用)
|
|
|
+- 若已过期 → 不恢复为可用状态,仅将 `order.hbId` 置为负数解除占用标记(避免重复判断),红包本身不返还
|
|
|
+
|
|
|
+`MallRefundApplyService::approve()` 里按 hd 现有规则触发:`hbId>0` 且退款后 `actPrice<=0`(全额退清)时才调用 `hbBackIfNotExpired`。
|
|
|
+
|
|
|
+## 后端 Controller
|
|
|
+
|
|
|
+### 新增 `app-mall/controllers/RefundController.php`(namespace `mall\controllers`)
|
|
|
+- `actionGetRefundData`:GET,按 `id`(订单id)返回订单详情(`goodsInfoList`/`itemList`/`orderPrice`/`tkPrice`/`hbId`/`hbAmount`)+ 可退金额 + 是否已有申请记录(有则一并返回申请状态,供前端展示进度)+ 售后截止提示文案;需校验 `order.customId == this->customId`。
|
|
|
+- `actionCreateOrder`:POST,顾客提交申请。校验:登录/归属、`payStatus==1`、`status` 不在 待付款(1)/已取消(5)/已退款(6)、`forward==0`、无已存在的待审核(0)记录、分销超期校验(上面新增方法)、退款金额 <= 可退金额;随后调 `MallRefundApplyService::createApply`。
|
|
|
+- `actionList` / `actionDetail`:顾客查看自己的售后申请列表/详情。
|
|
|
+- `actionCancel`:POST,顾客撤销 `status==0` 的申请。
|
|
|
+
|
|
|
+### 扩展 `app-hd/controllers/RefundController.php`(新增 action,不改动现有 `actionCreateOrder` 等)
|
|
|
+- `actionMallApplyList`:GET,商家端按门店 + `status` 筛选列表。
|
|
|
+- `actionMallApplyDetail`:GET,申请详情。
|
|
|
+- `actionMallApplyPass`:POST,超管审核通过 → `MallRefundApplyService::approve(...)`。
|
|
|
+- `actionMallApplyReject`:POST,超管驳回,需填 `rejectReason`。
|
|
|
+
|
|
|
+## 前端:mallApp
|
|
|
+
|
|
|
+### 1. 订单详情按钮 [mallApp/src/pages/order/detail.vue](../../front-end/mallApp/src/pages/order/detail.vue)
|
|
|
+在底部 `.page-btn.app-footer` 增加按钮,条件:`data.payStatus == 1 && ![1,5,6].includes(data.status)`,跳转 `/pages/order/refund?id=${data.id}`:
|
|
|
+```html
|
|
|
+<template v-else-if="showRefundBtn">
|
|
|
+ <button class="button-com default big" @click="goRefund">申请售后</button>
|
|
|
+</template>
|
|
|
+```
|
|
|
+按钮风格用现有 `.button-com.default`(浅色描边)或新增 `.button-com.pink`(用 `$mainColor` 描边,呼应首页主题色,与已有"立即支付"红色实心按钮区分主次)。
|
|
|
+
|
|
|
+### 2. 新增页面 `mallApp/src/pages/order/refund.vue`
|
|
|
+注册进 [pages.json](../../front-end/mallApp/src/pages.json) 的 `root: pages/order` 分包。
|
|
|
+- `init()` 调 `getRefundData({id})`:
|
|
|
+ - 若已有申请记录:展示状态卡片(待审核/已通过/已驳回+原因/已取消),`status==0` 时展示"撤销申请"按钮。
|
|
|
+ - 若无申请记录:展示表单——退款方式 Tab(退货并退款/仅退款,UI 结构参照 `admin/order/refund.vue` 的 `goodsInfoList`/`itemInfoList` 勾选数量),退款金额只读自动计算(不可编辑,防止顾客自报金额),备注 `textarea`,底部"提交申请"按钮 + 二次确认弹窗。
|
|
|
+ - 若接口返回超期错误(分销 settleDays 校验失败),toast 展示具体原因。
|
|
|
+- 提交调 `createRefund(...)` → 成功后原地刷新为"已提交,待审核"状态视图。
|
|
|
+
|
|
|
+### 3. 新增 API `mallApp/src/api/refund/index.js`
|
|
|
+```js
|
|
|
+import https from '@/plugins/luch-request_0.0.7/request'
|
|
|
+export const getRefundData = data => https.get('/refund/get-refund-data', data)
|
|
|
+export const createRefund = data => https.post('/refund/create-order', data)
|
|
|
+export const cancelRefund = data => https.post('/refund/cancel-order', data)
|
|
|
+```
|
|
|
+
|
|
|
+### 4. 配色(以店铺首页为准)
|
|
|
+参照 [mallApp/src/uni.scss](../../front-end/mallApp/src/uni.scss)(`$mainColor: #FF2842`)与首页渐变 CTA(`#FF8FA3 → #FF4D6D`):
|
|
|
+- 卡片沿用 admin/order/refund.vue 的白卡片+圆角+轻阴影结构,仅将强调色(可退金额、提交按钮、金额高亮)由绿色系换成 `$mainColor`/渐变粉红。
|
|
|
+- 提交按钮:`background: linear-gradient(135deg, #FF8FA3, #FF4D6D)`,白字,胶囊圆角(对齐首页 CTA 风格)。
|
|
|
+- 状态标签:待审核用中性灰/橙提示色,已通过用 `$mainColor`,已驳回用红色警示(区别于主色,用 `#ff4757` 之类的语义色)。
|
|
|
+
|
|
|
+## 前端:hdApp(商家审核)
|
|
|
+
|
|
|
+### 1. 新增页面
|
|
|
+- `hdApp/src/admin/order/mallRefundList.vue`:列表,UI 参照现有 [admin/order/refundList.vue](../../front-end/hdApp/src/admin/order/refundList.vue),增加状态筛选 Tab(待审核/已通过/已驳回)。
|
|
|
+- `hdApp/src/admin/order/mallRefundDetail.vue`:详情,UI 参照 [pagesPurchase/refundDetail.vue](../../front-end/hdApp/src/pagesPurchase/refundDetail.vue) 的状态展示风格;`status==0` 时底部展示"驳回"(弹窗填原因)/"通过"两个操作按钮。
|
|
|
+
|
|
|
+注册进 [pages.json](../../front-end/hdApp/src/pages.json) 的 `root: admin/order` 分包。
|
|
|
+
|
|
|
+### 2. 入口
|
|
|
+在 [hdApp/src/admin/order/detail.vue](../../front-end/hdApp/src/admin/order/detail.vue) 现有"售后记录"按钮旁新增"商城售后审核"入口(跳转 `mallRefundList`,可选按 `orderSn` 过滤)。
|
|
|
+
|
|
|
+### 3. 新增 API `hdApp/src/api/refund/index.js` 追加
|
|
|
+```js
|
|
|
+export const mallApplyList = data => https.get('/refund/mall-apply-list', data)
|
|
|
+export const mallApplyDetail = data => https.get('/refund/mall-apply-detail', data)
|
|
|
+export const mallApplyPass = data => https.post('/refund/mall-apply-pass', data)
|
|
|
+export const mallApplyReject = data => https.post('/refund/mall-apply-reject', data)
|
|
|
+```
|
|
|
+
|
|
|
+## 涉及文件清单
|
|
|
+**新增:**
|
|
|
+- `huahuibao/sql/20260730_mall_refund_apply.sql`
|
|
|
+- `huahuibao/biz-hd/refund/models/MallRefundApply.php`
|
|
|
+- `huahuibao/biz-hd/refund/classes/MallRefundApplyClass.php`
|
|
|
+- `huahuibao/biz-hd/refund/services/MallRefundApplyService.php`
|
|
|
+- `huahuibao/app-mall/controllers/RefundController.php`
|
|
|
+- `front-end/mallApp/src/pages/order/refund.vue`
|
|
|
+- `front-end/mallApp/src/api/refund/index.js`
|
|
|
+- `front-end/hdApp/src/admin/order/mallRefundList.vue`
|
|
|
+- `front-end/hdApp/src/admin/order/mallRefundDetail.vue`
|
|
|
+
|
|
|
+**修改:**
|
|
|
+- `huahuibao/biz-hd/distribution/classes/DistributionOrderClass.php`(新增 `assertRefundNotExpired`)
|
|
|
+- `huahuibao/biz-hd/hb/classes/HbClass.php`(新增 `hbBackIfNotExpired`)
|
|
|
+- `huahuibao/app-hd/controllers/RefundController.php`(新增 4 个审核 action)
|
|
|
+- `front-end/mallApp/src/pages/order/detail.vue`(新增按钮)
|
|
|
+- `front-end/mallApp/src/pages.json`(注册 refund 页面)
|
|
|
+- `front-end/hdApp/src/admin/order/detail.vue`(新增审核入口)
|
|
|
+- `front-end/hdApp/src/pages.json`(注册两个新页面)
|
|
|
+- `front-end/hdApp/src/api/refund/index.js`(追加 4 个函数)
|
|
|
+
|
|
|
+## 备注
|
|
|
+- 所有新增/改动代码将按仓库规范写简体中文注释(文件头 + 关键函数 + 复杂分支)。
|
|
|
+- 完成后不会自动执行 git 提交,等待人工复核。
|