Files
order_site/docs/寄卖库存优化现状与进度追踪.md
T
yml2213 cb8b249e57 feat(worker-platform): 实现打手寄卖白名单权限控制与存量发布打手平滑过渡
1. 新增数据库迁移 082_worker_consignment_whitelist.sql,worker_users 表增加 can_consign 与 consignment_activated_at 字段,存量在 consignment_submissions 提报过的打手默认自动开启;
2. 打手端提报接口 publishWorkerConsignment 增加白名单权限服务端强校验拦截(403 consignment_permission_required);
3. 管理后台打手管理表格增加「寄卖权限」实时 Switch 开关列与打手详情抽屉权限展示,支持客服即时开通或关闭打手寄卖权限;
4. 打手端我要寄卖页面在未开通权限时展示专属白名单引导卡片,一键呼起联系客服开通寄卖弹窗;
5. 补充寄卖权限拦截与路由单测,前端59项单测与后端507项单测全部通过。
2026-09-21 13:30:33 +08:00

26 KiB
Raw Blame History

寄卖库存功能 · 现状分析、进度与证据追踪报告

更新时间:2026-09-21 项目基线:040b3db8 (main 分支,工作区干净) 当前验证状态:后端 501 测试全绿 (498 pass / 0 fail / 3 skip);前端 54 测试全绿 (54 pass / 0 fail);两侧构建与类型检查通过。


一、 证据分类记录 (Evidence Classification)

1. 代码证据 (Code Implementation)

  • 打手提报与建议价闭环:
    • apps/frontend/src/pages/worker/WorkerConsignmentPage.tsx: 打手端唯一提报入口,支持系统(苹果/安卓)与区服(互通)规范输入;300ms防抖自动带出「接单模板」建议价;支持高档位溢出兜底与手改价保护;支持 URL/localStorage 记忆停留选项卡。
    • apps/backend/src/services/worker-platform/consignment-worker-service.ts: suggestConsignmentPriceFromRules 严格对齐璀璨数(0/1/2/3璀璨)与钻石等级;发布接口强制 requireActiveWorker。
  • 仓库与审核管理:
    • apps/frontend/src/pages/admin/panels/ConsignmentInventoryPanel.tsx: 寄售仓库管理,支持状态筛选、允许匹配开关、凭证链查看、工单双向匹配与退单回库。
    • apps/frontend/src/pages/admin/panels/ConsignmentSubmissionsPanel.tsx: 寄卖提报审核,支持通过入库与驳回退还押金。
  • 匹配与履约执行引擎:
    • apps/backend/src/services/worker-platform/consignment-matching-service.ts: compareSpec 三态判定(match / mismatch / unknown);支持区服「互通」对称通配;未知项降级为 partial 并列出缺失字段。
    • apps/backend/src/services/worker-platform/consignment-fulfillment-service.ts: 内部现货履约(原子占库 + 工单绑定 + 停在待加好友)与指派打手押金履约;服务端强制规格复检与冲突留痕。
  • 双向手动匹配与工单详情(最近落地):
    • apps/frontend/src/pages/admin/ConsignmentManualMatchModal.tsx: 双向手动匹配弹窗,支持 WO 工单号与 SUB 提报单号模糊检索,支持规格冲突时勾选强制匹配并必填原因。
    • apps/frontend/src/pages/admin/panels/WorkOrdersPanel.tsx: 工单详情抽屉完整回显卖家资料(角色名、数字ID、区服、系统、联系方式、单号等)与凭据截图,支持一键聚合复制与单项复制。

2. 数据与迁移证据 (Database & Migrations)

  • 077_consignment_inventory.sql: 寄售仓库表 consignment_inventories 与提报表 consignment_submissions 基线,建立 RBAC 四大权限。
  • 078_consignment_worker_deposit.sql: 打手端押金履约字段与台账支持。
  • 079_drop_consignment_collect_links.sql: 完全移除历史遗留 H5 定向收集渠道(下线 consignment_collect_links 表与 link_id 列);拆分 assigned_worker_id(履约打手)与 worker_id(供货卖家);建立绑定工单部分唯一索引与冻结流水去重幂等索引。
  • 080_consignment_allocation_status_and_copy.sql: 约束 allocation_status IN ('待安排', '已安排')。

3. 资金与状态机闭环证据 (Financial & State Machine Audit)

  • 押金流转:
    • 卖家发布提报:冻结发布押金(deposit_freeze)。
    • 审核驳回:全额退还(deposit_unfreeze)。
    • 确认加好友后违约/撤单:没收卖家押金(deposit_deduction),只扣冻结额,不退可用余额。
    • 履约验收:释放卖家发布押金,同时自动补发「供货货款」(settleConsignmentSupplierPayoutByWorkOrderWithClient)。
  • 撤销与解绑:
    • 撤销白名单严格限制在 in_progress | pending_acceptance | problem,验收后绝对禁止撤销;
    • 解绑现货时自动识别是否已加好友(已加好友作废 archived 下架不回池,未加好友 in_stock 回池)。

二、 进度管理:已知、未知、目标与确信度登记

类型 事项描述 确信度 支撑证据 / 依据 状态 / 备注
已知 提报渠道单一化收敛完成 100% 迁移 079 已删 H5 相关表与路由,手工入库已设 409 守卫,唯一入口为打手端提报 ✅ 已闭环
已知 统一单号锚定与三态状态机 100% 提报单号(SUB...)作为统一主键暴露给前端与客服,隐藏 INV 编号;domain/consignment-item-stage.ts 纯函数推导状态 ✅ 已闭环
已知 资金流转(货款结算 + 押金没收/释放)闭环 100% 批次 Q 补发货款给供货卖家,修 100 倍单位错;批次 F/G 加好友后违约没收押金不可逆 ✅ 已闭环
已知 双向手动指定现货与强制匹配留痕 100% commit f07e4087 支持在工单调起匹配现货、在仓库调起匹配工单,支持工单号与提报单号搜索,冲突强制匹配带原因留痕 ✅ 已闭环
已知 资料展示与一键复制功能完成 100% commit f08a221e, 2c120bd3 工单详情抽屉完整展示卖家信息并提供聚合及单项复制按钮 ✅ 已闭环
已知 建议价精准对齐璀璨数与溢出兜底 100% 批次 X/Z:按系统+系列+钻级+璀璨数全匹配接单模板;超出档位按最高配报;手改不覆盖 ✅ 已闭环
已知 卖家上架主页截图在工单详情抽屉与打手端正常展示 100% 修复 normalizeUploadedFiles 字符串解析与 effectiveBoosterMaterial 截图兜底,504后端/54前端测试全绿,真实工单 #100140 成功解析出截图 ✅ 已闭环
已知 仓库搜索框占位符承诺字段与后端实现存在偏差 100% ConsignmentInventoryPanel.tsx:789 承诺按“收购人/店铺/卖家”,但 consignment-repo.ts:178 未覆盖 buyer_name, shop_name, seller_phone ⚠️ 待优化(低成本)

五、 专项优化:接单工单匹配后详情抽屉展示卖家上架主页截图(2026-09-21 已闭环)

1. 现象与线上真实证据

  • 问题现象:接单工单匹配寄售现货后,在管理后台工单详情抽屉的「寄售赠送进度」模块中,「卖家上架/主页截图」区域显示为“未提交”,无法查看卖家寄卖时上传的游戏主页与物资截图。
  • 数据库真实记录查证(工单 WOc5502148fd73,ID: 100140):
    • 关联寄售库存 ID: 23 (INV26091917439822);
    • material_json.consignment.screenshots 中确切存有截图:["/api/v1/files/object?key=consignment_screenshot%2F2026%2F09%2F19%2Fb8b974206a8a0cf6c89a6296.webp"](纯字符串 URL 数组);
    • 但后端接口返回的 gift.boosterMaterial.screenshots 却为空数组 []。

2. 代码级根因定位

  1. 文件归一化函数 normalizeUploadedFiles 丢失字符串 URL 支持(核心根因):
    • apps/backend/src/services/worker-platform/worker-input-normalizers.ts:36-40: 原逻辑仅接受 { objectKey, url } 对象格式;当传入纯字符串 URL 数组(寄售提报老格式与历史库数据)时,typeof item === 'object' 判定为 false,提取出的 objectKey 和 url 均为空串,最终被 filter(Boolean) 全数过滤为 []!
  2. 工单展示映射器 resolveWorkOrderEffectiveBoosterMaterial 缺少截图 fallback:
    • apps/backend/src/services/worker-platform/work-order-display-mappers.ts:104: 当工单的 booster_material_json 中已存在 fields(如之前同步过卖家昵称/ID)但 screenshots 为空时,直接提前返回了空截图列表,没有回退到寄售数据的 consignment.screenshots。
  3. 前端工单详情渲染缺乏兜底:
    • apps/frontend/src/pages/admin/panels/WorkOrdersPanel.tsx:2412 与 WorkerOrderDetailDrawer.tsx:244: 原逻辑只读取 detailOrder.gift.boosterMaterial?.screenshots,未将 consignmentInfo?.screenshots 字符串数组作为第二层降级展示。

3. 解决对策与落地成果

  1. 文件/URL 解析能力全方位增强:
    • apps/backend/src/services/file-storage/file-storage-service.ts:导出 extractObjectKeyFromFileUrl,支持从 /api/v1/files/object?key=... 中稳定提取 objectKey。
    • apps/backend/src/services/worker-platform/worker-input-normalizers.ts:normalizeUploadedFiles 增加分支支持 typeof item === 'string',自动提取 objectKey 并标准化为带有 url、thumbnailUrl、mediumUrl 的完整 UploadedFilePayload。
  2. 展示层截图自动回退:
    • apps/backend/src/services/worker-platform/work-order-display-mappers.ts:在 resolveWorkOrderEffectiveBoosterMaterial 中,当打手/工单未传截图且关联寄售时,自动取寄售卖家的主页截图兜底填充,并保留 isConsignmentSellerMaterial 标识。
  3. 前后端双保险与打手端对齐:
    • apps/frontend/src/pages/admin/panels/WorkOrdersPanel.tsx:详情抽屉在 detailOrder.gift.boosterMaterial.screenshots 之后追加 consignmentInfo.screenshots 字符串列表降级渲染。
    • apps/frontend/src/pages/worker/WorkerOrderDetailDrawer.tsx:打手端详情抽屉同步增加对寄售截图的降级渲染。
  4. 自动化测试与实际验证:
    • 新增后端单元测试 apps/backend/src/services/worker-platform/consignment-booster-material.test.ts;
    • 真实工单数据(WOc5502148fd73)映射执行验证,成功输出标准卖家主页截图对象;
    • 后端 504 单测全绿、前端 54 单测全绿,构建与样式检查全部通过。

| 未知 | 待审核状态(pending_review)下打手是否需要自主撤回能力 | 80% | 业务目前仅提供客服审核通过/驳回,打手填错价格或想自用无法自主撤回,需业务确认 | ⏳ 待业务拍板 | | 未知 | 待加好友停滞是否有超时策略 | 75% | 现货履约停在待加好友,若客服/卖家长时间不操作,工单永久挂起,是否需超时自动预警/工单回退 | ⏳ 待业务拍板 | | 未知 | 批次 Q 之前已验收的历史寄卖单是否需要补发货款 | 70% | 历史单(如 #100171)在批次 Q 之前结算未获货款,需与运营对账确认是否需要补账脚本 | ⏳ 待对账确认 | | 目标 | 完善寄卖仓库检索与展示体验 | 95% | 将后端搜索扩展至 buyer_name、shop_name、seller_phone、打手昵称等,兑现前端占位符承诺 | 🎯 近期可推进 | | 目标 | 打手端支持“撤回提报”并即时解冻押金 | 90% | 在打手端“我的寄卖-待审核”卡片增加撤回功能,避免误提报占用押金和客服审核工时 | 🎯 近期可推进 | | 目标 | 增加寄卖模块统计与节省赏金看板 | 80% | 补齐设计方案中的“累计节省赏金”、“出库单数”、“货款结算对账”统计图表 | 🎯 中期规划 | | 目标 | 待加好友超时预警与催促机制 | 85% | 工单列表中对停留在待加好友超过 24/48 小时的寄售工单显示催促角标 | 🎯 近期可推进 |


三、 思考、灵感与演进分析 (Insights & Inspirations)

1. 思考:从“被动等待匹配”到“主动撮合建议”

  • 现状:目前系统主要依靠进单发布时自动检查现货候选,或者客服在管理后台手动调起匹配弹窗。
  • 灵感:当打手发布的高价值现货(例如安卓微信暗潮5钻)审核入库时,后台可自动检索当前排队池(抢单大厅、未分配工单)中是否有完全匹配的订单,并在审核通过成功提示或管理后台右上角通知栏弹窗提醒:“该现货已自动匹配待发工单 #WO26...,是否立即一键履约?”。这将将货找单的时延缩短至秒级。

2. 思考:打手端自闭环与客服减负

  • 现状:打手一旦提交寄卖,如果填错账号或写错价格,只能联系客服在后台驳回。
  • 灵感:在 pending_review(待审核)阶段,打手拥有随时撤回的权利(打手自主取消 -> 事务内释放押金 -> 状态转 cancelled)。这既能防止客服审核了无效的错单,也能大幅降低双方沟通成本。

3. 思考:待加好友阶段的履约节奏管控

  • 现状:为了防止错发和押金纠纷,内部现货履约被设计为停在“待加好友”,待加好友后才启动 72 小时赠送冷却。
  • 灵感:游戏内加好友存在单向通过的时滞。可以在工单面板上为“待加好友”超过 12 小时的工单打上“⚠️ 待加好友超时”标签,让客服能集中优先跟进买家/号主,保障履约时效。

四、 专项排查:打手 A 重复扣押金与二次填写资料的根因分析

1. 现象复现路径

  • 打手 A 在接单平台提报寄卖一个物品,系统冻结发布押金(deposit_freeze,如 ¥20 或 ¥100);
  • 后续外部进单匹配到此物品时,实际走入了【指派打手履约(worker_deposit)】而非【内部现货直接履约(internal_stock)】;
  • 导致打手 A 账户被额外扣除一笔【接单履约押金】(双倍资金占用);
  • 工单在打手端显示为“待提交资料”,打手 A 被迫重新手动上传游戏昵称、ID 及截图。

2. 代码级根因定位

  1. 手动匹配弹窗硬编码为指派打手(关键漏项):
    • apps/frontend/src/components/admin/ConsignmentManualMatchModal.tsx:184: 不论从寄售仓库还是工单操作列调起手动匹配弹窗,提交按钮直接硬编码调用了 assignWorkOrderWithConsignmentWorker(指派打手履约接口); 弹窗内完全没有提供【内部现货直接履约】(fulfillWorkOrderWithConsignment)的选项。
  2. 发布拦截弹窗排版引导偏差:
    • apps/frontend/src/pages/admin/panels/WorkOrdersPanel.tsx:3434-3475: 候选卡片中,【走接单平台指派打手(冻结押金交付)】被置于顶部且为高亮紫色主按钮(Primary),而真正推荐的【内部现货直接履约(免外派佣金)】为次要按钮(Default),客服极易默认点击主按钮。
  3. 指派打手履约复用普通工单逻辑导致双冻结与资料丢失:
    • consignment-fulfillment-service.ts:680 调用了通用的 assignAdminWorkOrderToWorker;
    • 通用指派将打手 A 视作外部抢单打手,再次执行 freezeWorkerOrderDepositWithClient 冻结履约押金;
    • 通用指派将工单置为 acceptance_mode = 'friend_gift', gift_phase = 'material_required',但未自动将现货中的 seller_game_id、credentials_json、screenshots_json 自动写入工单 booster_material_json 并推进阶段,导致打手端仍停留在“待提交资料”。

3. 解决对策与落地成果(2026-09-21 已闭环)

  1. 手动匹配弹窗收敛为单一【内部现货直接履约】:
    • 在 ConsignmentManualMatchModal.tsx 中彻底废除 assignWorkOrderWithConsignmentWorker,切换为调用 fulfillWorkOrderWithConsignment;
    • 彻底解除 selected.workerId 强依赖与无法指派错误提示,详情卡片调整为展示供货来源(“供货打手”或“内部现货”);
    • 文案统一调整为“确认内部现货履约”,明确告知“免外派佣金、不冻结重复押金、自动跳过打手资料”。
  2. 工单发布拦截弹窗候选操作收敛为【内部现货直接履约】:
    • 在 WorkOrdersPanel.tsx 中将卡片操作按钮替换为【内部现货直接履约】高亮主按钮(绿色),副标题标注“免外派佣金 · 不扣打手押金 · 进入待加好友”;
    • 杜绝客服误点走旧指派流程。
  3. 测试套件与类型风格全面达标:
    • consignment-manual-match-mount.test.ts 更新为断言手动匹配走内部现货直接履约;
    • 前端 54 测试全绿、后端 501 测试全绿;两侧 typecheck、format:check、build 均 100% 通过。

六、 专项优化:接单工单表格「打手」列回显寄售供货打手与现货资料(2026-09-21 已闭环)

1. 现象与用户反馈

  • 问题现象:接单工单在走内部现货直接履约后,工单列表表格的【打手】列以及工单详情基本信息中的【打手】字段显示为冰冷的一横杠 -,客服/运营在列表视图下无法直观查看是谁供的货或对应哪个游戏角色。

2. 代码级根因定位

  • apps/frontend/src/pages/admin/panels/work-order-panel-utils.tsx:31: 原 renderWorkOrderWorkers(order) 仅针对 order.worker(传统指派/抢单打手)与 order.sharingWorkers(拼单打手)进行了渲染,而内部现货履约单没有 order.worker,直接走到底部返回了 '-'。

3. 解决对策与落地成果

  1. 提炼寄售供货展示纯函数:
    • 在 apps/frontend/src/utils/consignment-display.ts 中建立 resolveConsignmentWorkerDisplay(order: WorkOrder);
    • 自动解析 material.consignment 与 gift.boosterMaterial.fields:
      • 当存在 workerName 时,主标题展示供货打手名称,打上 <Tag color="cyan">供货打手</Tag>,副标题自动拼接游戏角色昵称与游戏 ID;
      • 当无 workerName(纯仓库现货)时,主标题展示卖家角色昵称/游戏 ID,打上 <Tag color="cyan">内部现货</Tag>。
  2. 列表与详情无缝集成:
    • renderWorkOrderWorkers 统一接入 resolveConsignmentWorkerDisplay,使工单列表表格中的【打手】列和工单详情抽屉基本信息中的【打手】栏均能清晰、美观地回显供货人。
  3. 自动化测试与样式达标:
    • 新增前端单元测试 apps/frontend/tests/consignment-worker-display.test.ts,验证普通工单、有供货打手寄售单、无打手纯现货单的解析分支;
    • 前端 57 个测试全绿,format:check、lint:check、typecheck 全部通过。

七、 专项优化:打手端「我要寄卖」顶部臃肿卡片轻量化重构(2026-09-21 已闭环)

1. 现象与用户反馈

  • 问题现象:打手在手机端打开“我要寄卖”页面,顶部纵向堆叠了 4 个巨型卡片(待审核、履约中、已完成、发布寄卖 苏尔南),占用高达 400px+ 竖向空间,几乎占满整块手机屏幕。打手进页面完全看不到下方的发布表单,必须下滑整屏才能开始填表,操作链路极长且视觉严重失调。

2. 代码级根因定位

  1. 通用样式在移动端粗暴单列堆叠:
    • apps/frontend/src/pages/worker/WorkerConsignmentPage.tsx:510 原先套用了通用 .worker-orders-kpi-grid;
    • 其在 @media (max-width: 640px) 下被定义为 grid-template-columns: 1fr,4 个卡片被强制纵向拉成长条大块;
  2. 信息噪音多、占位无意义:
    • 每个卡片塞入了诸如“客服审核中,通过后自动入库待匹配”、“待加好友 / 冷却 / 待赠送 / 待验收”、“含已完成、已驳回、已下架作废”等多余的长文本;
    • 第 4 个卡片“发布寄卖 苏尔南”纯属凑数占位,点击只是切到下方的发布 Tab,自身毫无数据与功能意义。

3. 解决对策与落地成果

  1. 彻底移除无意义的第 4 个卡片:
    • 移除“发布寄卖 苏尔南”假 KPI 卡片,将核心关注点精准收敛为【待审核】、【履约中】、【已完成】3 大关键数据。
  2. 重构为专属轻量级横向数据栏:
    • 提取并新增 .worker-consignment-kpi-grid 与 .worker-consignment-kpi-card:
      • 移动端采用 repeat(3, 1fr) 紧凑横向三等分网格,高度由原来的 320px+ 骤降至约 52px(竖向空间释放超 80%);
      • 剔除无意义的长句副文案,采用居中微标签布局:上行小字展示状态(11px),下行加粗展示数值(16px);
      • 待审核(紫/橙光)、履约中(科技蓝光)、已完成(清新绿光),选中态带优雅的主题高亮指示;
      • 桌面端保留图文两列的优雅排布,兼顾大屏美观。
  3. 首屏即见核心发布表单:
    • 优化后,打手打开手机首屏顶端即可在不滑动的情况下直接看到“履约押金提示”、“操作系统(苹果/安卓)”与“游戏区服”选择,提报效率大幅提升!
  4. 自动化测试与全量构建:
    • 前端 59 个自动化测试全绿(59 pass / 0 fail);
    • format:check、lint:check、typecheck、build 全部通过。

八、 专项优化:打手抢单大厅首页新增「联系客服」入口与通用客服弹窗组件(2026-09-21 已闭环)

1. 现状与用户诉求(User Feedback & Target)

  • 用户反馈:“首页 增加联系客服 现在联系客服藏的太深了”,并附带手机端首页截图,用红圈标注了移动端顶部状态栏(余额 / 上限 胶囊右侧、操作按钮区左侧的空白区域)。
  • 目标:
    1. 在抢单大厅首页移动端顶部状态栏(红圈标注的核心首屏黄金位置)增加醒目高质感的【联系客服】胶囊按钮;
    2. 在桌面端抢单大厅头部操作栏同步补齐【联系客服】入口,打通双端闭环;
    3. 将原本深藏在个人中心底层的“联系客服/管理员”弹窗抽象为全站通用的 WorkerContactModal 组件,统一维护二维码、账号、余额等信息,提供一键复制与标准沟通提示。

2. 证据分类与代码级根因(Evidence & Root Cause)

  • 已知信息 [确信度: 100%]:
    1. 官方公告栏循环播放:“☆接单请先个人中心联系客服☆方便客服处理”,证明新打手或接单打手频繁需要找客服沟通充值、提现或报备;
    2. 原联系管理员弹窗代码内联在 apps/frontend/src/pages/worker/WorkerProfileAccountModals.tsx:187-240,打手必须切换至“个人中心”页面并向下滑动到底部才能找到入口,链路过长、深度太深;
    3. WorkerHallPage.tsx 中的 profileQuery.data?.data 原生就包含了 worker 实体与 financeConfig(含管理员微信二维码配置 adminContact.wechatQrCodeImage),数据已就绪,仅缺前端呈现入口。
  • 未知/风险预判 [确信度: 100%]:
    • 移动端 375px 或超窄屏(如 320px)下顶部栏元素横向空间是否会挤压拥挤;
    • 应对对策:采用弹性缩放与媒体查询控制,超小屏下保持单行不折叠。

3. 解决对策与落地成果(Solution & Milestones)

  1. 抽离通用联系客服弹窗组件:
    • 新建 apps/frontend/src/components/worker/WorkerContactModal.tsx,集中管理微信二维码大图、当前打手账号、昵称、手机号、账号状态、可用余额,以及一键复制和温馨沟通提示;
    • 在 WorkerProfileAccountModals.tsx 与 WorkerHallPage.tsx 中全面复用该组件,消灭重复代码。
  2. 移动端黄金位置新增【联系客服】胶囊按钮:
    • 在 WorkerHallPage.tsx 移动端顶部状态条(用户红圈位置)插入专属胶囊:
      <button class="worker-hall-mobile-contact-pill" onClick={() => setContactOpen(true)}>
        <CustomerServiceOutlined />
        <span>联系客服</span>
      </button>
      
    • 采用浅暖橙背景(#fff7ed)+ 优雅橙边框(#fed7aa)+ 微动效,与打手端整体暖橙调性浑然一体,点击即弹出客服微信与账号卡片。
  3. 桌面端同步补齐入口:
    • 在桌面端头部操作按钮栏(刷新与排行榜旁)新增 <Button icon={<CustomerServiceOutlined />} onClick={() => setContactOpen(true)}>联系客服</Button>。
  4. 验证门禁全绿通过 [确信度: 100%]:
    • 前端 59 个自动化测试全绿(59 pass / 0 fail);
    • 前端 format:check、lint:check、typecheck、build 均零错误零警告通过;
    • 后端 504 个自动化测试全绿(501 pass / 3 skipped / 0 fail)。

九、 专项优化:打手寄卖白名单开关控制与存量平滑过渡(2026-09-21 已闭环)

1. 现状与用户诉求(User Feedback & Target)

  • 用户反馈:“寄卖系统 我想增加一个类似白名单 激活模式, 如果有新的注册的人员, 默认无法开启寄卖; 必须联系客服... 方案 A 就够了, 能实现控制 一个开关也行, 然后 存量老打手平滑过渡 发布过的默认开启”。
  • 目标:
    1. 实行寄卖白名单准入机制:新注册打手默认不开启寄卖,防止虚假提报与黑产刷单;
    2. 存量老打手平滑过渡:历史上在 consignment_submissions 中发布过寄卖的打手,在迁移中自动批量赋权开启;
    3. 后台提供开关:客服/运营在打手管理表格与详情抽屉中可一键开通/关闭打手寄卖权限;
    4. 打手端友好提示与拦截:未开通寄卖权限的打手在「我要寄卖」页面展示专属引导卡片,一键唤起客服弹窗;后端接口进行服务端强拦截(403 consignment_permission_required)。

2. 证据分类与实现细节(Evidence & Implementation)

  • 已知信息 [确信度: 100%]:
    1. worker_users 表增加了 can_consign(布尔值,默认 FALSE)与 consignment_activated_at(开通时间戳);
    2. 迁移文件 082_worker_consignment_whitelist.sql 通过 IN (SELECT DISTINCT worker_id FROM consignment_submissions WHERE worker_id IS NOT NULL) 实现存量打手秒级平滑过渡;
    3. 打手端提报接口 publishWorkerConsignment 增加了 if (!worker.can_consign) throw ... 强校验;
    4. 前端管理后台 WorkersPanel.tsx 增加了「寄卖权限」列,直接嵌入 Switch 开关实时切换;打手详情抽屉 WorkerDetailDrawer.tsx 补充了权限和开通时间回显。

3. 验证与门禁报告(Quality Gate Status)

  • 后端单测与类型检查 [确信度: 100%]:
    • 新增 admin-worker-consignment-permission.test.ts 及 consignment-worker-service.test.ts 权限拦截测试;
    • 后端 507 项单测全绿(504 pass / 3 skipped / 0 fail);
    • 后端 typecheck、check:sql 全部通过;
  • 前端门禁与生产构建 [确信度: 100%]:
    • 前端 59 项单元测试全绿(59 pass / 0 fail);
    • 前端 format:check、lint:check、typecheck、build 零错误全绿通过。