Files
dukang/docs/杜康好客-v3.5.1-开发文档.md
T
2026-08-19 16:20:33 +08:00

172 lines
9.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 杜康好客 · v3.5.1 版本更新
> **2026-08-19** · admin-web / h5-shop / mini-user / h5-partner / API
> 工单方案(探索与拆分):[`杜康好客-v3.5.1-工单迭代开发文档.md`](./杜康好客-v3.5.1-工单迭代开发文档.md)
> 目标:发布会大屏、C 端发票抬头与申请、门店信息变更审核、待支付自动取消、门店/合伙人运行时强退登录。
## 范围
| # | 项 | 交付 |
|---|----|------|
| 1 | 发布会订单大屏 | `GET /admin/orders/big-screen`;独立全屏页 `/orders/big-screen`;订单页「大屏」入口;超管「测试」连播假单 |
| 2 | 门店端核销即时刷新 | `shop:redeem-success` 事件总线;Mine / 提现页监听后立刻重拉 |
| 3 | C 端发票抬头 | 表 `user_invoice_title` + CRUD;我的 → 发票管理;图标操作(编辑 / 默认 / 删除) |
| 4 | C 端申请发票 | 仅已完成订单;列表/详情「申请发票」与「开票中」互斥 |
| 5 | 合伙人门店「提交变更」 | 表 `store_info_change_request`;审核通过才覆盖线上门店 |
| 6 | 审核通知 | 原「套餐审核」菜单改为「审核通知」;套餐变更 + 信息变更双 Tabbadge 合计 PENDING |
| 7 | 门店列表快捷入口 | `pendingInfoChangeId`;「审核信息 / 对比」;「提现」进结算页 |
| 8 | 待支付 30 分钟自动取消 | Cron 每分钟;`payExpireAt` 已过期且非测试单 → `CANCELLED` |
| 9 | 门店 / 合伙人运行时强退 | `JwtAuthGuard` 校验启停;`reason: ACCOUNT_DISABLED`;两端清登录并跳登录页 |
**Prisma 迁移(发版不可 `--skip-db`**`user_invoice_title``store_info_change_request``user_order``@@index([status, payExpireAt])`
---
## 1. 发布会订单大屏
- 路由:`/orders/big-screen`**不走** AdminLayout(无侧栏)。
- 数据:`GET /admin/orders/big-screen?limit=`(上限 2000)。过滤 `isTest=false``payAmount >= 100`;手机号 `maskContactPhone` 中间四位 `****`
- 展示:一屏锁死、订单上滚;新成交按金额档位动效(首次进入不撒花)。
- 入口:订单监控「大屏」;超管另有「测试」,经 `BroadcastChannel` / `localStorage` 连播三级假单。
| 位置 | 说明 |
|------|------|
| `GET /admin/orders/big-screen` | `admin-orders.controller.ts`(须写在 `:id` 之前) |
| `apps/admin-web/src/pages/BigScreenPage.tsx` | 大屏页 |
| `apps/admin-web/src/lib/admin-events.ts` | 测试成交 payload |
| `apps/admin-web/src/pages/OrdersPage.tsx` | 「大屏」「测试」按钮 |
---
## 2. 门店端核销即时刷新
核销成功页 `onMounted` 派发 `shop:redeem-success`;「我的」与「申请提现」监听后重拉接口,同 Tab 立即看到余额变化。
| 位置 | 说明 |
|------|------|
| `apps/h5-shop/src/lib/useRedeemSuccessBus.ts` | `notifyRedeemSuccess` / `useRedeemSuccessListener` |
| `RedeemSuccessPage` / `MinePage` / `WithdrawPage` | 广播与刷新 |
---
## 3 / 4. C 端发票抬头与申请发票
**仅 `COMPLETED` 且非售后补发单**可申请。已有 `PENDING` / `ISSUED` 发票则不可再申(驳回后可重申)。
### 抬头
- 我的 → **发票管理**`/pages/invoice-titles/index`
- 卡片操作:`编辑.png` / `默认.png` / `删除.png`(无文字按钮)
- 新增/编辑走底部弹层(无独立编辑页)
- 小程序标题只用原生 `navigationBarTitleText`,不再画二级 title(见 `.cursor/rules/mini-user-weapp-nav-title.mdc`
### 申请
- 入口:订单列表卡片、订单详情底栏
- **互斥**:无进行中/已开具发票 →「申请发票」;状态 `PENDING` →「开票中」(点进申请页看进度);`ISSUED` 两者都不显示
- 列表接口带 `invoiceStatus`(最新一条发票)
| 接口 | 说明 |
|------|------|
| `GET/POST /trade/invoice-titles` | 列表 / 新建 |
| `PUT/DELETE /trade/invoice-titles/:id` | 编辑 / 删除(已被发票引用则 409) |
| `GET /trade/orders/:orderId/invoice-titles` | 申请页可选抬头 |
| `GET /trade/orders/:orderId/invoice-status` | `{ exists, status }` |
| `POST /trade/orders/:id/invoices` | 提交申请(可传 `titleId` |
| `GET /trade/orders` | 列表项增加 `invoiceStatus` |
| 前端 | 说明 |
|------|------|
| `apps/mini-user/src/pages/invoice-titles/index.tsx` | 抬头列表 |
| `apps/mini-user/src/pages/invoice-apply/index.tsx` | 申请发票 |
| `apps/mini-user/src/pages/orders/index.tsx` | 申请 / 开票中互斥 |
| `apps/mini-user/src/pages/order-detail/index.tsx` | 同上 |
---
## 5 / 6 / 7. 门店信息变更与审核通知
合伙人改基本资料不再直接写 `store`,改为提交变更;审核通过后用 `proposedSnapshot` 覆盖线上。审核期间 C 端 / 合伙人端仍展示线上 live 数据。
可变字段白名单见 `STORE_INFO_CHANGEABLE_FIELDS``packages/shared-types/src/store-info-change.ts`)。
- 合伙人详情底栏文案:**提交变更**;有 PENDING 时黄条「基础信息变更审核中」
- 总部「套餐审核」改名 **审核通知**:Tab「套餐变更 | 门店信息变更」;菜单 badge = 两类 PENDING 之和
- 门店列表:`pendingInfoChangeId` →「审核信息 / 对比」;「提现」→ `/finance/store-bills?storeId=`
- 门店端提交接口已备(`POST /shop/store/info-change-request`),**本期无门店 H5 入口**
| 接口 | 角色 | 说明 |
|------|------|------|
| `POST /partner/stores/:storeId/info-change-request` | 合伙人 | 提交 |
| `GET /partner/stores/:storeId/info-change-requests` | 合伙人 | 历史(用于 PENDING banner |
| `POST /shop/store/info-change-request` | 门店 | 已实现,本期无 UI |
| `GET /admin/store-info-change-requests` | 总部 | 列表 |
| `GET /admin/store-info-change-requests/summary` | 总部 | `pendingCount` |
| `GET /admin/store-info-change-requests/:id` | 总部 | 详情 + 字段 diff |
| `PUT /admin/store-info-change-requests/:id/audit` | 总部 | `APPROVE` / `REJECT` |
| `GET /admin/stores` | 总部 | 增加 `pendingInfoChangeId` |
通过 / 驳回后派发既有 `admin:package-audit-changed` / `AUDIT_NOTICE_CHANGED_EVENT`,侧栏 badge 刷新。
---
## 8. 待支付 30 分钟自动取消
下单路径已写 `payExpireAt = now + 30min`。本次补定时翻状态(此前 monitor 只告警不取消)。
- Cron`*/1 * * * *` Asia/Shanghai`OrderExpiryScheduler`
- 条件:`PENDING_PAY` + `UNPAID` + `payExpireAt < now` + `isTest=false`
- 动作:条件更新 `CANCELLED` + `cancelledAt`;日志 `operator=SYSTEM_AUTO_EXPIRE`,备注「30 分钟未支付自动取消」
- **不回滚**权益券(与手动取消代下单一致;建单时未占用库存)
- 每批最多 200 条;`updateMany``status=PENDING_PAY` 防并发重复
| 位置 | 说明 |
|------|------|
| `server/dukang-api/src/jobs/order-expiry.scheduler.ts` | 定时任务 |
| `TradeService.cancelExpiredPendingOrders` | 业务取消 |
| `schema.prisma` Order | `@@index([status, payExpireAt])` |
---
## 9. 门店 / 合伙人接口强制退登录
登录后账号被停用 / 解绑时,后续任意鉴权接口拦截,前端清 token 并回登录页。
校验(仅 `STORE` / `PARTNER``USER` / `HQ` 跳过):
| 端 | 条件 |
|----|------|
| 门店 | `StoreAccount.status === ACTIVE`;已选店则 `Store.status === OPEN` |
| 合伙人 | `PartnerAccount.status === ACTIVE``bindingStatus === ACTIVE` |
`isTest=true` 的账号 / 门店**跳过**,避免测试环境自锁。
响应:HTTP 403`{ code, message, reason: 'ACCOUNT_DISABLED' }``HttpExceptionFilter` 透传 `reason`,避免走 401 refresh)。
| 位置 | 说明 |
|------|------|
| `jwt-auth.guard.ts` `assertAccountActive` | 运行时校验 |
| `http-exception.filter.ts` | 透传 `reason` |
| `apps/h5-shop/src/lib/api.ts` | `ACCOUNT_DISABLED``clearAuth` + `/login` |
| `apps/h5-partner/src/lib/api.ts` | 同上(`toAppPath('/login')` |
---
## 验收
- [ ] 大屏:非测试且实付 ≥100 的订单上屏,手机号中间四位 `****`;「测试」仅超管可见且能连播动效
- [ ] 门店端核销成功后,「我的 / 提现」无需下拉即可看到余额变化
- [ ] 发票管理可增删改、设默认;小程序无二级导航标题
- [ ] 仅已完成订单出现「申请发票」;提交后卡片改为「开票中」,不再出现申请按钮
- [ ] 合伙人提交门店资料后线上不立即变;总部审核通过后覆盖;驳回后可改再提
- [ ] 审核通知 badge = 套餐 PENDING + 信息变更 PENDING;门店列表有「审核信息 / 对比 / 提现」
- [ ] 构造已过期待支付正式单,约 1 分钟内变为已取消,且有 `SYSTEM_AUTO_EXPIRE` 日志;测试单不被取消
- [ ] 停用门店账号或关闭门店后,门店端接口 `reason=ACCOUNT_DISABLED` 并退登录;合伙人 `bindingStatus` 非 ACTIVE 同理;C 端不受影响
- [ ] `pnpm db:generate && npx prisma db push` 无报错;`pnpm lint` 无新增错误
## 发版注意
- 必须跑 Prisma(两张新表 + 订单索引),不可 `--skip-db`
- 发版时 mini-user `package.json` / `src/lib/client-version.ts`**`3.5.1`**(当前仓库仍为 `3.4.15`
- HQ 开发计划创建版本 `v3.5.1` 并关联本迭代任务