合并本轮全部文档改动(原 5 个 docs 提交压成 1 个)。 口径与索引: - 新增 docs/README.md 文档总索引:三来源口径(91 + 快手 send-code = kuaishou-91)、 「一个订单 = 骨架 + 买家凭证 + 一个执行载体」、成本只改一处、文档状态机 - 过期阶段文档移入 docs/archive/2026-10-08/(保留内容,不删除) 分析报告: - docs/项目全量分析报告-2026-10-17.md:架构、五条业务链路、P0/P1/P2 风险与改进路线 - docs/载体判定与成本中心落地-复核与草案-2026-10-17.md:生产只读克隆量化、上一轮结论复核与 4 处修正 方案文档: - docs/成本中心与三块履约模型.md:三块执行载体、标准商品、成本版本与快照、人工支出登记 - docs/财务系统集成方案.md:复式记账模型、分录表、分期落地 - docs/影子总账说明.md:影子期与转正期的边界、对账与转正标准 SQL 草案(docs/drafts/,未接入迁移): - 载体判定与人工块量化.sql:量化查询、carrier_type 判定与回填、守恒校验 - 成本中心与销售事实-DDL草案.sql:product_catalog / channel_product_mappings / cost_items / cost_versions / cost_snapshots / cost_exceptions / sales_daily_facts - 人工支出登记-DDL草案.sql:manual_fulfillment_cases / manual_expense_records / manual_expense_events 业务口径确认(2026-10-17): - 收入 = 用户实付(orders.total_amount),与快手 paymentFen 数据核验 100% 一致 - 打手报酬 = 支出/成本(最终提现打款),按总额法 - 人工块以「支出可追溯」为先,SLA 监管延后 - 退款/仲裁暂未接入,先预留字段与反向冲正关系 三份草案已在一次性沙箱库按依赖顺序零错误应用(10 张新表、27 个 CHECK 约束)。
25 KiB
寄售仓库 / 寄卖子系统 深度技术分析
分析基线:
ef491660(含9298b31b白名单总开关)。全部结论取自仓库真实代码,行号可复核。
一、业务定位与术语表(本仓库口径)
| 术语 | 代码实体 | 含义与关键约束 |
|---|---|---|
| 寄卖 / 寄存 | consignment_* 全套 |
打手把自己在《和平精英》的苏尔南手枪挂到平台,由平台撮合卖给买家 |
| 现货 / 库存 | consignment_inventories |
审核通过后落库的一件真实货物,status ∈ in_stock/consumed/archived |
| 提报 / 上架 | consignment_submissions(打手端 publishWorkerConsignment) |
打手端唯一入口,发布即冻结发布押金;SUB… 单号是全流程唯一锚点(consignment-worker-service.ts:411) |
| 审核入库 | approveAdminConsignmentSubmission |
客服审核通过 → 生成 INV… 库存行(consignment-repo.ts:1170-1217);驳回退押金 |
| 匹配 | consignment-matching-service.ts |
按系统/区服/系列/钻级/璀璨做规格比对,exact/partial/conflict |
| 履约(两条) | internal_stock / worker_deposit |
内部现货:客服/内部仓代交付(无接单打手);押金履约:指派打手交货并冻结履约押金 |
| 待加好友 | parkWorkOrderWaitingFriendAddWithClient |
占库后工单停在 gift_phase=material_required,等人确认加好友 |
| 赠送冷却 | gift_phase=friend_countdown |
确认加好友后进入冷却,冷却结束才可上传赠送截图 |
| 赔付 / 没收 | forfeitConsignmentPublishDeposit*、settleWorkOrderDepositWithClient |
卖家发布押金 / 打手履约押金的没收与退还 |
| 押金履约押金 | worker_wallets.frozen_deposit_amount |
发布押金与工单履约押金共用同一冻结池,靠 payload_json.kind 区分口径 |
| 白名单 | worker_users.can_consign + 总开关 |
详见第八节 |
二、端到端流程
flowchart TD
A[打手端提报 苏尔南] -->|检查白名单+冻结发布押金 ¥20| B[consignment_submissions pending_review]
B -->|客服驳回| B2[rejected + 释放押金]
B -->|客服审核通过| C[consignment_inventories in_stock/待安排]
C -->|工单发布前候选提醒 / 手动匹配| D{匹配方式}
D -->|internal_stock| E1[原子占库 consumed/已安排 + 工单绑 material + 停待加好友]
D -->|worker_deposit| E2[条件占库 + 指派打手冻结履约押金 + in_progress]
E1 --> F[确认加好友 → 赠送冷却]
E2 --> F
F -->|冷却结束| G[卖家/打手上传赠送截图 → pending_acceptance]
G --> H[客服验收 accepted]
H --> I[释放发布押金 + 结算供货货款 cost_price_fen]
E1 -.撤销履约 reopen/回库/作废.-> C
E2 -.撤单/取消指派/超时.-> C
工单终态解绑出口唯一:releaseConsignmentInventoryBindingForWorkOrderWithClient(consignment-repo.ts:765),已接入 work-order-cancel-repo.ts:84,202,325,448,537、worker-cancel-request-repo.ts:572、work-order-issue-repo.ts:344。
三、数据模型
| 表 | 关键字段 | 状态枚举 | 索引/约束 |
|---|---|---|---|
consignment_inventories (077:3-39, 078:3-7, 079:49-58) |
inventory_no UNIQUE、item_name/system/server_zone/series/diamond_level/brilliance_count、cost_price_fen、credentials_json(账号密码)、screenshots_json、allow_matching、worker_id(卖家)、assigned_worker_id(履约打手)、deposit_amount_fen、bound_order_id/bound_work_order_id/bound_platform_order_id/shop_name |
status ∈ in_stock/consumed/archived(077:25-26);allocation_status ∈ 待安排/已安排(080:33-35);source_type ∈ manual/worker_portal/recycle(079:38-40) |
uniq_consignment_inventories_bound_work_order 部分唯一(bound_work_order_id WHERE status='consumed', 079:93-95);idx_..._status_matching、_game_category、_specs、_buyer、_shop、_batch、_worker_id、_assigned_worker_id |
consignment_submissions (077:64-91, 078:9-13) |
submission_no UNIQUE、result_inventory_id、content_json(characterName/Id/sellerNote/channel)、asking_price_fen、deposit_amount_fen、worker_id/name/phone |
status ∈ pending_review/approved/rejected(077:83-84) |
idx_..._status_created;link_id 已被 079:11-12 删除 |
consignment_collect_links |
— | — | 079:15 已整体 DROP |
worker_users (082:4-6) |
can_consign(默认 FALSE)、consignment_activated_at |
— | idx_worker_users_can_consign(082:12-13) |
worker_wallet_ledgers |
ledger_type、payload_json.kind=consignment_publish、consignmentSubmissionId |
deposit_freeze/deposit_release/deposit_deduction |
uniq_worker_wallet_ledgers_consignment_publish_freeze(079:177-180) |
079 为什么删除收集链接:H5 定向收集(/consignment-collect/:token + 公开 link/submit/upload)存在两个致命问题——上传响应层级取错导致截图恒为空(旧 ConsignmentCollectPage.tsx,优化方案 P0-1),以及按手机号自动绑定打手可让第三方被动冻结其押金(优化方案 P2-5)。业务改为「只能在接单平台提报」,于是删表删列,source_type 的 collection_link 归并为 worker_portal(079:1-8、17-40)。同一次迁移还补了两件资金/一致性收口:assigned_worker_id 拆分(079:47-54,防止占库覆盖卖家导致"我的寄卖"丢件)与冻结流水幂等唯一索引 + 历史重复冻结去重退款(079:97-180)。
四、核心服务清单
| 文件(仓库根相对) | 职责 | 关键导出 |
|---|---|---|
apps/backend/src/services/worker-platform/consignment-worker-service.ts |
打手端:提报(白名单+规格校验+冻结押金)、我的寄卖聚合、确认加好友、提交赠送截图、建议价 | publishWorkerConsignment(:146)、listWorkerConsignments(:351)、confirmWorkerConsignmentFriendAdded(:551)、submitWorkerConsignmentGiftEvidence(:566)、getWorkerConsignmentPriceSuggestion(:581) |
.../consignment-matching-service.ts |
规格解析/归一、三态比对、候选排序、手动匹配分类、建议价规则 | extractPeacekeeperSpecs(:245)、matchPeacekeeperOrderWithInventory(:309)、classifyConsignmentMatch(:518)、listConsignmentMatchOptions(:552)、findMatchingPeacekeeperInventories(:569)、suggestConsignmentPriceFromRules(:633) |
.../consignment-fulfillment-service.ts |
履约:内部现货履约、指派打手履约、补偿回滚、撤销、候选查询、服务端规格复检 | listWorkOrderInventoryMatchOptions(:179)、listInventoryMatchableOrders(:220)、checkWorkOrderInventoryMatches(:305)、fulfillWorkOrderWithConsignment(:345)、assignWorkOrderWithConsignmentWorker(:603)、resolveConsignmentAssignRewardFen(:590)、revokeWorkOrderConsignmentFulfillment(:910) |
.../consignment-admin-service.ts |
后台:库存 CRUD/开关/作废/回库、提报审核、映射 | mapConsignmentInventory(:158)、fetchAdminConsignmentInventories(:261)、createAdminConsignmentInventory(:319,已 409 停用)、updateAdminConsignmentInventory(:326)、archiveAdminConsignmentInventory(:414)、returnAdminConsignmentInventory(:471)、approve/reject(:564/:648) |
.../repositories/worker-platform/consignment-repo.ts |
库存/提报全部 SQL、占库/释放/解绑唯一出口 | claimConsignmentInventoryForWorkerWithClient(:500)、releaseConsignmentInventoryClaimWithClient(:563)、archiveConsignmentInventoryWithClient(:673)、returnConsignmentInventoryToStockWithClient(:706)、releaseConsignmentInventoryBindingForWorkOrderWithClient(:765)、approveConsignmentSubmissionWithInbound(:1126) |
.../repositories/worker-platform/consignment-deposit-repo.ts |
发布押金冻结/释放/没收、供货货款结算 | freezeConsignmentPublishDepositWithClient(:51)、release...WithClient(:118)、getConsignmentDepositLedgerSnapshot(:186)、forfeit...BySubmissionWithClient(:332)、forfeit...ByWorkOrderWithClient(:399)、settleConsignmentSupplierPayoutByWorkOrderWithClient(:441) |
.../repositories/worker-platform/consignment-supplier-repo.ts |
从工单反查供货卖家(货款与售后共用) | getConsignmentSupplierByWorkOrderWithClient(:20) |
手动匹配(f07e4087)如何工作
- 两个只读入口:订单侧
GET /matches/:workOrderId/options→listWorkOrderInventoryMatchOptions返回全部在库现货,按exact(0)/partial(1)/conflict(2)+ 成本价 + id 排序(consignment-fulfillment-service.ts:191-206);库存侧GET /inventories/:id/match-orders→listInventoryMatchableOrders反查unassigned/pending_material/open工单(:252-261)。 - 前端
ConsignmentManualMatchModal.tsx按matchType决定确认项:partial勾"允许非精确",conflict勾"确认规格不一致"且必填原因(utils/consignment-manual-match.ts:19-53)。 - 落地只走
fulfillWorkOrderWithConsignment(ConsignmentManualMatchModal.tsx:178-184),把allowPartial/allowSpecMismatch/matchNote传后端。 - 后端二次复检:
assertConsignmentSpecMatchedOrder(:73-110) 用宽松模式复检,真冲突默认 409(consignment_spec_mismatch),仅allowSpecMismatch=true且matchNote非空才放行(resolveManualMatchNote:155-167),冲突明细写入工单事件与material.consignment.specConflicts(:489-495)。
五、状态机
库存项展示阶段 deriveConsignmentItemStage(domain/consignment-item-stage.ts:146-248)把「提报单 + 库存 + 绑定工单」三套状态推导为唯一阶段:
pending_review → in_stock → (consumed 后按工单) matched_waiting_friend → gift_cooldown → gift_ready → gift_submitted → completed;标准验收走 fulfilling/pending_acceptance;异常终态 rejected/archived/cancelled(:20-34、46-78)。
| 迁移 | 触发者 | 代码位置 | 附加效果 |
|---|---|---|---|
in_stock → consumed(内部现货) |
客服 consignment.fulfill |
consignment-fulfillment-service.ts:424-453 |
锁单 FOR UPDATE + 写绑定 + 停在待加好友 |
in_stock → consumed(指派打手) |
客服 | consignment-repo.ts:511-540 |
写 assigned_worker_id='已安排',再调通用指派 |
consumed → in_stock(撤销回库) |
客服 | consignment-fulfillment-service.ts:986-1000 |
带 AND bound_work_order_id=$4 仲裁;发布押金 auto=保持冻结 |
consumed → archived |
客服/自动 | 同上 :971-984、consignment-admin-service.ts:414-440 |
已确认加好友强制作废不回池(:968-969) |
in_stock → archived |
客服 | consignment-repo.ts:673 |
释放发布押金 |
consumed → in_stock(人工回库) |
客服 | consignment-repo.ts:706-763 |
需 NO_LIVE_BOUND_WORK_ORDER_SQL;回库重新冻结押金(ensure...:262) |
in_stock → in_stock(终态解绑) |
系统 | consignment-repo.ts:765 |
撤单/超时/取消指派自动回池,押金不动 |
allocation_status 只由系统写:占库写 已安排(consignment-repo.ts:533、履约服务 :428),回库/撤销写 待安排(:990、release :569)。
六、匹配规则
- 品类隔离门禁:
detectItemCategory识别手枪/密钥/机甲/车皮等,双方都能识别且不一致直接null;现货为pistol_suernan时订单必须含系列或"苏尔南/手枪/枪皮"信号(consignment-matching-service.ts:319-340)。 - 规格三态:
compareSpec(:292-304) 返回match/mismatch/unknown;通配SYSTEM_WILDCARDS=['通用']、ZONE_WILDCARDS=['通用','互通'](:288-290)。 - 档位规则:钻级/璀璨不得低配充高配(:359-360);
unknown项禁止判精确(:363-374)。 - 严格/宽松:默认严格——系统/区服/系列任一非
match即排除,且无"高配"正信号也排除(:394-418),回退掉了"只写游戏名就命中全库"的旧行为;宽松模式allowUnspecifiedSpecs仅供人工选定后复检(:394、consignment-fulfillment-service.ts:88-90)。 - 排序:
score DESC → cost_price_fen ASC → inbound_at ASC → id ASC(:597-611)。 - 白名单/手动匹配:白名单只管"能否发布",不参与匹配(
domain/consignment-whitelist.ts:7-12);手动匹配可越过任何规格门禁,代价是必填原因并留痕。 - 建议价:按系统(含通用)+系列精确、钻级/璀璨向上兜底取后台已配最高档,多命中取最高(:633-710)。
七、资金 / 押金 / 赔付
| 事件 | 资金动作 | 代码 |
|---|---|---|
| 发布提报 | 按 consignmentPublishDepositFen(默认 2000 分 = ¥20,worker-finance-config-service.ts:73-78,108)从可用余额冻结,余额不足 409 |
consignment-worker-service.ts:255,297;consignment-deposit-repo.ts:51-113 |
| 审核驳回 | 全额释放(幂等:outstanding=0 即空操作) |
consignment-admin-service.ts:670-674 |
| 库存作废 | 释放发布押金 | consignment-admin-service.ts:420-426 |
| 人工回库 | 重新冻结(错失则 409 consignment_deposit_already_settled) |
:500-506、:262-314 |
| 验收通过 | 释放发布押金 + 补发供货货款 cost_price_fen || asking_price_fen 给卖家 |
work-order-settlement-repo.ts:99-104、:429、:679;consignment-deposit-repo.ts:441-... |
| 确认加好友后违约/取消/超时 | 没收发布押金(deposit_deduction) |
work-order-cancel-repo.ts:140,261,385、work-order-issue-repo.ts:68,254 |
| 撤销寄售履约 | 打手履约押金按 auto/refund/forfeit;卖家发布押金按 auto/archive→release/回库→keep_frozen/forfeit |
consignment-fulfillment-service.ts:1016-1058;domain/consignment-deposit-policy.ts:54-77 |
| 防双付 | 指派对象≠供货卖家时报酬保持原值,货款走供货货款渠道;=卖家则改报酬为结算价 | consignment-fulfillment-service.ts:590-601,689-695;consignment-deposit-repo.ts:459 |
八、权限与白名单(082 + cb8b249e / 9298b31b)
- 总开关:
worker_finance_config.consignmentWhitelistEnabled(非 DB 列),默认true(worker-finance-config-service.ts:16-19,79-80,108);后台在资金配置面板切换。 - 单人权限:
worker_users.can_consign,客服在打手管理列表 Switch 实时开关(082:4-6;admin-worker-user-service.ts:182-205;路由routes/admin/worker-platform/workers.ts:146-158,权限admin/operator)。空 body 不默认关闭(400can_consign_required)。 - 判定:
canWorkerPublishConsignment = !whitelistEnabled || workerCanConsign(domain/consignment-whitelist.ts:7-12),后端在提报入口强校验并 403consignment_permission_required(consignment-worker-service.ts:151-161);前端同口径(utils/consignment-whitelist.ts:5-12)+ 引导卡片(WorkerConsignmentPage.tsx:597-620)。 - 平滑过渡:082:16-24 把历史上出现在
consignment_submissions的worker_id批量置can_consign=TRUE。语义已从"永久白名单"演进为"总开关可整体放行"(9298b31b 新增),关闭总开关时保留标记以便再次开启。
九、API 端点清单
打手端(routes/worker/consignment.ts,前缀 /api/v1/worker)
| 方法/路径 | 门禁 | 服务 |
|---|---|---|
POST /consignment/publish (:19) |
requireActiveWorker |
publishWorkerConsignment |
GET /consignment/price-suggestion (:33) |
requireActiveWorker |
建议价 |
GET /consignment/my-items (:51) |
仅会话 | listWorkerConsignments |
POST /consignment/items/:submissionId/confirm-friend (:65) |
requireActiveWorker |
复用客服加好友链路 |
POST /consignment/items/:submissionId/gift-evidence (:87) |
requireActiveWorker |
复用 submitWorkerOrderAcceptance(asConsignmentSupplier) |
后台(routes/admin/worker-platform/consignment.ts,前缀 /api/v1/admin)
| 方法与路径 | 权限 | 行号 |
|---|---|---|
GET /consignment/inventories、/stats、/inventories/:id |
consignment.view |
:37,:47,:57 |
POST /consignment/inventories(已停用 409) |
consignment.manage |
:67 |
PUT /consignment/inventories/:id |
consignment.manage |
:80 |
PATCH /consignment/inventories/:id/matching |
consignment.manage |
:98 |
POST /consignment/inventories/:id/archive、/return |
consignment.manage |
:112,:122 |
GET /consignment/submissions、/submissions/:id |
consignment.view |
:142,:152 |
POST /consignment/submissions/:id/approve、/reject |
consignment.review |
:162,:180 |
GET /consignment/matches/:workOrderId、/.../options |
consignment.view |
:200,:211 |
GET /consignment/inventories/:id/match-orders |
consignment.view |
:225 |
POST /consignment/fulfill |
consignment.fulfill |
:242 |
POST /consignment/assign-worker |
consignment.fulfill |
:263(前端已无调用方) |
POST /consignment/revoke |
consignment.fulfill |
:285 |
POST /worker-platform/workers/:workerId/consignment-permission |
admin/operator |
workers.ts:146 |
十、风险与问题(按严重程度)
资金安全
- 审核改派打手会把货款付给非发货人 —
consignment-repo.ts:1227-1230审核可worker_id = COALESCE($4, worker_id)改派;consignment-supplier-repo.ts:67结算优先取inventory.worker_id。发布押金已按台账归还原发布人(consignment-deposit-repo.ts:186-241),但cost_price_fen货款会打给被改派的打手。若改派是刻意玩法可接受,否则是资金错付。待确认(需业务口径)。 assignWorkerWithConsignment仍是可达接口但已无前端入口 —routes/admin/worker-platform/consignment.ts:263-283+services/admin/consignment.ts:151仍在;直连可绕过ConsignmentManualMatchModal.tsx:178的"只走内部现货"收敛,回到追踪文档 §四描述的双重扣押金 + 打手被迫重填资料场景。建议下线或加开关。mapConsignmentInventory全量下发credentialsJson(游戏账号密码) —consignment-admin-service.ts:179-182,仅需consignment.view,列表接口即返回(优化方案 P2-3 仍成立)。
数据一致性 / 并发
- 指派链路跨事务"部分成功"窗口仍在 —
claimConsignmentInventoryForWorker(:663) 独立事务提交后,assignAdminWorkOrderToWorker(:680)、updateWorkOrder(:742)、createWorkOrderEvent(:748) 各自独立;失败靠compensateFailedConsignmentAssignment(:802-849) 收敛,且三步补偿全是catch {}吞错(:821-848)。补偿自身失败时会出现「工单 in_progress + 押金已冻 + 现货已回池」→ 同一件货被第二张单占用。文档寄卖系统优化方案.md:159-165仍标注"指派事务化未做"。 - 改派导致卖家端"我的寄卖"错位 —
consignment-worker-service.ts:352-368分别按submissions.worker_id与inventories.worker_id过滤(repo:137-140、:902-905)。审核改派后,原卖家有提报无库存 → 永远停在in_stock「正在入库」(consignment-item-stage.ts:158-161兜底);被改派者看到从未提报的货。 - 提报列表 LEFT JOIN 存在行放大 —
consignment-repo.ts:937-943用rinv.id = cs.result_inventory_id OR rinv.source_submission_id = cs.id,两个条件同时命中时同一提报单会出两行。 - 我的寄卖窗口被硬截断 —
consignment-worker-service.ts:353-354固定pageSize: 200,超过 200 条的历史寄卖静默不可见;:362-367同一提报单只保留第一件库存。 internal_stock履约的押金释放依赖验收事务,撤销/回库路径已覆盖,但"待加好友"无限期挂起时押金与货物同时冻结,无超时策略(文档寄卖库存优化现状与进度追踪.md:93,98仍标"待业务拍板")。
性能
- 候选匹配全表入内存 —
consignment-repo.ts:854-887listActiveConsignmentInventoriesForMatching无分页、无 LIMIT,checkWorkOrderInventoryMatches/listWorkOrderInventoryMatchOptions每次调用全量拉取后在 JS 内比对(consignment-fulfillment-service.ts:190,318)。 - 统计接口每次 5 条全表聚合 —
consignment-repo.ts:218-303(优化方案 P2-2 未处理)。
可维护性
- 仓库关键字搜索仍不覆盖承诺字段 —
consignment-repo.ts:178-182未含buyer_name/shop_name/seller_phone/worker_name,而前端占位符承诺(追踪文档:54仍标"待优化")。 - 编辑无法解除打手关联 —
ConsignmentInventoryPanel.tsx:255传workerId || undefined,后端按!== undefined判定(consignment-admin-service.ts:381-386),传空即"不修改"。 remark拼接式审计无长度上限(:980、:996、releaseconsignment-repo.ts:582)。listWorkerConsignments用Promise.all两查询 + N 次工单批量查,卖家量大时内存放大(非阻塞问题)。
十一、文档与代码一致性
| 文档承诺 | 实际 | 结论 |
|---|---|---|
| 优化方案 P0-1/2/3/4/5 五项 | 全部落地(079 迁移、assertConsignmentRevocableWorkOrderStatus:864、绑定唯一索引、release...BindingForWorkOrderWithClient:765) |
✅ 一致 |
| P1-2「指派事务化」 | 仅做了补偿回滚,未合并事务(见风险 4) | ⚠️ 半做 |
| P1-8 前端权限门控 | 已落地(consignment-permissions.test.ts 存在) |
✅ |
| 批次 E 未做项:报表(节省赏金/出库单数/批次回款)、搜索字段扩展、打手端菜单按账号状态隐藏 | 仍全部未做 | ❌ 未做 |
| §六/§七 统计看板 | getConsignmentInventoryStats 只有数量/成本 + 4 个 GROUP BY |
❌ 未做 |
追踪文档 :260 写"if (!worker.can_consign) throw" |
实际是 canWorkerPublishConsignment({whitelistEnabled, workerCanConsign})(consignment-worker-service.ts:151-155) |
⚠️ 文档滞后于 9298b31b |
| 追踪文档 §四「手动匹配弹窗收敛为内部现货履约」 | 前端已收敛(ConsignmentManualMatchModal.tsx:178),但后端 assign-worker 接口未下线 |
⚠️ 半做 |
| 批次策略"回库保留运营匹配开关" | releaseConsignmentInventoryClaim(:563) 与 returnConsignmentInventoryToStockWithClient(:706) 均保留 allow_matching |
✅ |
| 押金策略(待审超期自动驳回、打手自助撤回) | 均未实现,consignment_submissions.status 无 cancelled |
❌ 未做 |
历史演进(git log 摘要):1aa6dba9 初版(仓库+H5 收集+内部履约)→ 4a6215e8 接入打手押金履约 → fd1eb581 冷静期 + 押金闭环 → e828e677 权限/竞态/撤销守卫 → 632dddc4 下线 H5 + 状态机封闭 → 5d11bf20 补偿 + 规格复检 → 批次 F–U(押金不退、作废口径、统一状态机、货款结算、手动匹配)→ a5727554「彻底去除非平台内部现货履约」把匹配收敛为指派打手 → 追踪文档 §四发现该路线导致卖家被二次扣押金、被迫重填资料,随后提交把弹窗改回 fulfillWorkOrderWithConsignment;577e0eec 反向清理:从 WorkOrdersPanel.tsx/WorkerOrderDetailDrawer.tsx 移除已废弃的指派打手路径(a5727554 的方向被回退,指派线降级为遗留接口)→ cb8b249e/9298b31b 白名单与总开关。
十二、测试覆盖评估
| 测试文件 | 断言重点 |
|---|---|
domain/consignment-item-stage.test.ts(10 例) |
各阶段推导、内部现货 vs 打手线的"确认加好友"按钮差异、冷却到点转待赠送、终态 |
domain/consignment-deposit-policy.test.ts(6 例) |
auto/显式覆盖的押金处置矩阵、非法值归一 |
domain/consignment-whitelist.test.ts(2 例) |
总开关开/关 |
consignment-matching-service.test.ts(24 例) |
规格解析、精确/高配充低配、通配互通、空规格不命中、品类隔离、建议价档位兜底 |
consignment-manual-match.test.ts(7 例) |
冲突清单、宽松复检、必填原因、两链路留痕、读接口只读 |
consignment-worker-service.test.ts(9 例) |
单号聚合、状态机接线、卖家归属、白名单 403、璀璨≤钻级 |
consignment-payout.test.ts(10 例) |
单位(分)、双付防护、拼单钩子、079 去重迁移 |
consignment-fulfillment-price-trace.test.ts(4 例) |
发单金额改写与撤销恢复原值 |
consignment-revoke-policy.test.ts(3 例) |
撤销必结算打手押金、作废关匹配开关 |
consignment-evidence.test.ts(8 例) |
凭证取图去重、手工入库停用、链接归一化 |
consignment-repo.test.ts(3 例) |
SUB 号搜索、join 列前缀、allocation_status 落在 080 枚举内 |
admin-worker-consignment-permission.test.ts(3 例) |
权限回显、路由注册、空 body 不默认关闭 |
| 前端 8 个 consignment 测试 | 冷却倒计时、凭证、手动匹配挂载(断言走内部现货)、权限、规格选项、白名单、供货打手展示 |
缺口:(a) 无 approveAdminConsignmentSubmission 的端到端测试(改派+押金归属+货款归属这条链路无回归保护);(b) 无审核/驳回押金释放的金额断言;(c) 无 revokeWorkOrderConsignmentFulfillment 的并发/状态仲裁用例(assertConsignmentRevocableWorkOrderStatus 有纯函数测试但事务内 0 行 409 未覆盖);(d) 无 releaseConsignmentInventoryBindingForWorkOrderWithClient 的幂等/多工单绑定冲突用例;(e) 白名单仅有总开关与单人布尔两种纯函数用例,无"提报时总开关关闭但 can_consign=false 放行"的集成断言;(f) 无前端 ConsignmentManualMatchModal 对 allowSpecMismatch 必填原因的交互测试。