9.1 KiB
杜康好客 · v3.5.1 版本更新
2026-08-19 · admin-web / h5-shop / mini-user / h5-partner / API 工单方案(探索与拆分):
杜康好客-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 | 审核通知 | 原「套餐审核」菜单改为「审核通知」;套餐变更 + 信息变更双 Tab;badge 合计 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并关联本迭代任务