Commit Graph
219 Commits
Author SHA1 Message Date
yml2213 33b220ae10 fix(dcauth): order_site 白名单补充生产域名 ks.khhao.com 2026-10-22 10:04:05 +08:00
yml2213 ef36453694 feat(dcauth): 移除机器码,改用纯设备码认证
- DCAuth 协议升级到 v2,签名原文只含设备码;客户端 2.0.0,旧版本返回 426
- 删除客户端机器码采集、后端 machine_code_* 字段与日志、后台机器码展示
- 102 迁移在生产执行前直接改为无机器码结构;SQL 守卫仅放行该文件
- Mock 短信不启用每日限额;修复慢电脑首次启动的协议转发竞态
- 新增 macOS DCAuth.app 打包脚本,注册 dcauth:// 协议,浏览器可直接唤起
2026-10-21 20:46:25 +08:00
yml2213 040100f290 feat(dcauth): 新增后台手机号与设备认证登录
登录链路改为账号密码 + 短信验证码 + DCAuth 设备签名,并新增后台手机号绑定、
登录日志、设备绑定与重置接口。
2026-10-21 20:46:24 +08:00
yml2213 7542d547bf feat: 新增客服备用金台账与后台用户中文显示名
- 新增备用金账户、流水、支出、对账与权限
- 后台用户支持中文显示名并同步备用金姓名
- 审计、登录记录、任务及工单操作人优先展示中文名
- 补充备用金与人工支出方案文档
2026-10-18 13:55:24 +08:00
yml2213 7bacb7d5eb docs: 重构项目文档并补充三块载体、成本中心与人工支出方案
合并本轮全部文档改动(原 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 约束)。
2026-10-17 22:03:03 +08:00
yml2213 6850bc64ff feat(work-order): 发布并核销支持抖音券(按来源分流,抖音走 DYC 券核销) 2026-10-15 13:22:18 +08:00
yml2213 10464fea89 refactor(product-match): 抽离接单模板匹配引擎(来源适配器/引擎/价格收口 + 后台按订单项试匹配)
新增 services/product-match:来源适配器(kuaishou-91 合成 91+快手 / pdd / douyin-mashida)+ 平台无关匹配上下文 + 条件打分引擎(并列最高=ambiguous 不猜、逐维诊断)+ 价格数量拼单唯一实现。

- 商店键命名空间化(kuaishou:/pdd:/douyin:),店铺为可选作用域:留空即可按订单信息匹配
- 抖音匹配文本只取内部 SKU,引流标题只进 promoTitle,itemTitle 恒空(修复 0.85 元误命中碎梦浮光珍宝礼盒、拼单未开)
- work-product-match-mappers 改为门面(签名不变),work-order-pricing 改为转发
- 新增后台「按订单项试匹配」接口与面板:走发单同一套链路,返回模板/数量/单价/总额/拼单
- 生产样本回放:91/PDD 6000 条决策 0 差异;抖音 5 条全为修正

设计见 docs/接单模板匹配引擎重构设计.md
2026-10-14 15:58:21 +08:00
yml2213 2d02630eea docs(mashida): 更新 ngrok 亚太区域与固定静态域名说明 2026-10-10 20:22:48 +08:00
yml2213 10d1449b8d docs(douyin-mashida): 09 重写为「一条链接闭环 + 复用 affiliate_dash」
按纠偏后的实现改写:目标流程(一条链接 → 输 UID → 二维码 → 扫码绑定 → 比对 UID → 完成)、
为什么复用 affiliate_dash 而不另建执行器、为什么未命中必须显式回落人工(漏单风险)、
为什么链接必须是路径式且只有一个(老订单的 /redeem 链接保留可用)、商品图来源与降级、
配置项表(含「保存接口必须带全量配置」的注意点)、以及下一步(真正的发货与冲正)。
2026-10-09 16:13:53 +08:00
yml2213 f32e76f843 docs(douyin-mashida): 新增皮肤领取流程设计文档 + 联调清单补充
- `09-皮肤领取流程.md`:为什么改(固定链接/输订单号的问题)、新流程图、
  为什么链接必须是路径式(# 是打手页)、商品图怎么来(内部 SKU → 英文 sku → 图片,
  复用权威映射表 + 漏图守卫测试)、配置项表、兼容性(旧链接保留)、下一步(真正发货)
- `08-公网联调.md`:联调 checklist 补「皮肤领取页两项配置」(含 `#` 告警)、
  把「手机打开链接」改为买家领取链接并补任务/token 与四表对账
2026-10-09 15:07:03 +08:00
yml2213 f72eeb7648 docs(douyin-mashida): 记录「平台会改写券码」这个坑与核销实测结论
- 07 §4.11:新增「平台会改写我们提交的券码」——实测 3 笔里 2 笔被平台改名,
  连带 10017 核销码不匹配(且要 ~10.5s 才返回,会伪装成网关超时);
  写明处理方式(回查落库 + 核销用平台券码 + 失败自愈 + 超时 20s)
- 00 总览:实测结论表补上「核销成功」「平台改写券码」「order.message 已调用」
2026-10-09 14:09:05 +08:00
yml2213 d12dce7575 docs(douyin-mashida): 记录商品展示口径(内部 SKU 为主)
新增 §4.10:说明 code=内部 SKU / product_name=引流标题的区别,
以及三个界面(后台列表、后台详情、兑换中心)统一以内部 SKU 为主的展示规则,
并注明实现只对 douyin_mashida 生效、不影响其它平台。
2026-10-09 13:31:51 +08:00
yml2213 3505ca4e05 docs(douyin-mashida): 补平台真实推送的实测形态
订阅生效后一笔真实付款的推送原文(来源 IP、耗时、字段值):
- p_id/s_ids 是 19 位裸数字,pay_time 是秒级 —— 与 §4.1 精度修复、§4.8 双形态解析相互印证
- 记录文档未覆盖的 pay_type=8,代码不依赖该字段
- 端到端:付款 12:55:05 → 推送 12:55:11 → 建单+发券+syncV2 完成 12:55:12
2026-10-09 12:57:09 +08:00
yml2213 5c13d9221f docs(douyin-mashida): 回填真实联调实测结论与推送订阅步骤
- 08-公网联调:新增「必须做:订阅推送」一节 —— 只填 uid/secret 平台不会推消息,
  必须调 message.config 配置 message_url/topics/status;含脚本用法、实测返回、
  域名变更后需重订阅、平台不补推历史订单等注意事项;排错表补两行
- 07-最小接入实现说明:新增三条实测结论
  §4.8 pay_time 有 Integer 与 "YYYY-MM-DD HH:mm:ss" 两种形态(及 epoch 0 表示"无")
  §4.9 文档示例值不能照抄(真实 shop_id / 子单号可能是字符串且等于父单号)
  §4.10 平台推送是订阅制、不补推历史订单
- 00-总览:补「真实平台实测结论」表,并把 subscribe 脚本纳入清单
2026-10-09 12:43:58 +08:00
yml2213 d9848aaef3 docs(douyin-mashida): 接入分析、实现说明与公网联调文档
- 00-总览:进度索引(闭环落点 / 代码清单 / 配置项 / 上线步骤 / 缺口 / 待实测点)
- 04-结合本项目的深度分析:深读平台文档后与仓库既有实现的对应关系
- 05-最小接入方案分析:实施方案与取舍(本期只做抖音、不做打手、不做多平台)
- 06-待确认问题清单:已答复项与"边做边测"项
- 07-最小接入实现说明:实现要点、上线三步、两个必须记住的坑
  (19 位订单号 JSON.parse 丢精度 / 验签必须用 body 原文)
- 08-公网联调:ngrok 隧道 + 一键切地址 + 前置自检 + 联调 checklist + 排错表
2026-10-09 12:01:49 +08:00
yml2213 5978e92370 docs(抖音-码速达): 收录开放平台全量对接文档(抓取快照)
新增 docs/抖音-码速达:把新平台(dy-openplatform-api.wanmahui.com)联调文档页的
全部数据落到仓库,供离线查阅与后续对接。

数据来源:文档页把全部数据内嵌在隐藏 input#raw_data 的 JSON 里(api / message /
fee / menu 四块),一次请求即取全,无需逐页爬取。

内容:
- README.md:平台速览(网关、鉴权要素、计费)、14 条消息与 16 个接口总表、对接六步;
- 01-计费规则.md:免费/基础(1 金豆)/高级(2 金豆)/增值(4 金豆)四档与各接口分级;
- 02-接口调用规范与签名.md:网关 POST /api/openplatform/gateway、公共参数
  uid/method/timestamp/sign、MD5 签名算法与可复算示例、返回结构;
- 03-消息推送规范与签名.md:topic/pub_time/sign 走 URL、data 走 POST body、
  验签要点、message.config 消息设置、messagetest 测试入口;
- 接口API/ 16 篇:请求参数、返回字段(层级缩进)、可解析的返回示例 JSON、
  签名原串 + MD5 结果;
- 消息推送/ 14 篇:topic、data 字段、示例 JSON、签名原串 + MD5 结果;
- data/raw_data.json(与页面快照逐字段校验一致)、data/page.html、data/代码示例/
  (页面内置 JAVA/.NET/PHP 示例 6 份)、data/crawl-meta.json(抓取元信息与文件 MD5)。

校验:接口 16/16、消息 14/14 无缺漏,33 段示例 JSON 全部可解析,内部链接全部可达。
文档页访问令牌已隐去(凭据不入库)。04~06 的分析类文档暂不入库,仅保留本地。
2026-10-08 14:57:30 +08:00
yml2213 0b48313617 feat(deploy): 部署改成按需重建,无 schema 变更自动跳过备份
每次部署都无条件重建 backend + web 两个镜像(实测后端 3m35s、前端 2m54s),
并且每次都在迁移前 pg_dump + 传 OSS(生产 492MB dump 那一步约 12 分钟);
只改了后端也要把前端整条链重跑一遍。

改动:
- 新增 deploy/lib/classify-changes.sh:把改动文件映射成"要重建哪一端",
  规则保守——apps/backend/** → backend、apps/frontend/**|deploy/caddy/**|前端 Dockerfile → web、
  文档/部署脚本/测试文件 → 不重建,compose 文件与未知路径 → 两端都重建。
- ubuntu-deploy.sh 用 .deploy-state(上次成功部署的 commit + .env 指纹)算 git diff,
  未变化的一端不 build、也不 --force-recreate,容器保持运行;若它没在跑则用现有镜像拉起。
  两端都要建时合并为一次 compose build(bake 并行)。
- 备份:改动不含 apps/backend/src/db/migrations/** 时自动跳过(--backup 强制、
  --skip-backup 无条件跳过);算不出改动范围(首次使用、force push)时不自动跳过。
- compose pull 改 --policy missing:不再每次重新校验 postgres tag,避免顺手静默升级数据库镜像。
- 新增 --dry-run(打印计划后退出,含基础镜像 digest)、--all、--backend-only/--web-only;
  部署结束打印各阶段耗时,回答"这次怎么比上次慢"不用靠推算。
- .deploy-state 进 .gitignore;README 与 docs/部署启动与数据库重建.md 同步。

验证:新增 7 个用例直接执行分类脚本断言"改动→重建范围",并守住"状态只在健康检查后才落盘"
等关键顺序;全量 595 个单测、typecheck、lint、check:sql 全通过。
2026-10-03 16:29:05 +08:00
yml2213 adaf4ed240 feat(worker-risk): 新增大厅阶梯式风控中间件与鉴权短缓存,惩罚外挂死循环狂刷并支持恶意封号
1. 新增 worker-risk-control 阶梯式风控:单打手/IP 限流 3次/秒(超限返 429);1 分钟累计违规 10 次升级为二级惩罚(锁定 5 分钟秒拒并带 Retry-After);惩罚期内持续暴力刷接口累计 30 次自动判定恶意不改,直接封禁打手账号(status='frozen')并作废所有 session;
2. 风控限流前置挂载在 requireWorkerSession 之前:命中限流或处于风控期时,微秒级在内存中基于 JWT payload 与 IP 拦截,彻底杜绝外挂流量穿透到 PostgreSQL 数据库;
3. verifyWorkerSessionToken 增加 3 秒内存校验缓存:并发请求直接复用内存鉴权对象,同一页面并发发出的多个接口请求仅查 1 次数据库,极大减轻连接池争抢压力;
4. 全套新增风控阶梯机制与自动封号自动化测试,后端 549 项测试全绿通过。
2026-10-02 16:30:53 +08:00
yml2213 610c65bb34 docs: 新增发单系统与寄售仓库技术分析报告
1. docs/项目分析报告-发单系统与寄售仓库.md:项目全景(实测文件/行数、测试结果、迁移规模)、后台发单链路与工单状态机、寄售仓库数据模型与匹配规则、按优先级排序的风险总表与改进路线;
2. docs/寄卖子系统技术分析报告.md:寄卖子系统逐项分析,含端到端流程、077-082 数据模型、核心服务清单、库存与分配状态机、API 清单、风险与测试缺口;
3. 两份报告中的资金与安全类结论均已对照源码复核,标注「待确认」的属需要业务口径拍板、而非代码缺陷的项。
2026-10-01 11:07:36 +08:00
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
yml2213 0df5c9f34e feat(worker-platform): 抢单大厅首页新增联系客服胶囊入口并抽象通用客服弹窗组件
1. 抽离打手端通用联系客服弹窗组件 WorkerContactModal,统一维护微信二维码、打手账号/状态/余额回显、一键复制及沟通提示;
2. 抢单大厅移动端顶部状态栏(余额上限右侧首屏黄金位)新增精致微动效【联系客服】胶囊按钮,大幅缩短找客服沟通链路;
3. 抢单大厅桌面端头部操作栏同步补齐【联系客服】按钮,并在个人中心账号弹窗中统一复用 WorkerContactModal;
4. 适配移动端与超窄屏自适应响应式样式,完成前端59项测试与全量打包构建验证。
2026-09-21 12:37:38 +08:00
yml2213 a4f6f5ed9b style(worker-portal): 优化打手端我要寄卖页面顶部卡片布局,轻量化重构首屏体验
1. 移除第 4 个占位无意义的「发布寄卖 苏尔南」卡片,核心指标精准收敛为待审核、履约中、已完成 3 大状态;
2. 新增 worker-consignment-kpi-grid 紧凑统计栏,移动端改为横向 3 列等宽平铺,高度由 320px+ 骤降至 52px,竖向空间节省超 80%;
3. 剔除卡片内无实际价值的长句副说明文案,改为上行轻量状态标签 + 下行醒目数字的微排版,支持点击秒切记录过滤;
4. 彻底解决移动端首屏被巨幅卡片占满导致表单下沉的问题,首屏直接呈现履约押金提示与规格选择,提升打手发布效率;
5. 前端 59 个自动化测试全绿,全套 check 与 build 100% 通过。
2026-09-21 12:31:03 +08:00
yml2213andCursor 577e0eec02 fix(consignment): 内部现货履约文案对齐待加好友,并移除已废弃的指派打手路径
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-21 12:04:30 +08:00
yml2213 29589bb9af feat(worker-platform): 接单工单表格「打手」列支持展示寄售供货打手与现货资料
1. 新增 resolveConsignmentWorkerDisplay 工具函数,自动解析工单寄售现货与资料字段(供货打手、游戏角色昵称、游戏ID及联系方式);
2. 优化 renderWorkOrderWorkers 渲染逻辑:当工单为内部寄售现货履约时,打手列带「供货打手」或「内部现货」专属角标,主标题展示打手名/角色名,副标题拼接游戏ID与联系方式,解决原先显示为破折号 - 的问题;
3. 新增 consignment-worker-display 单元测试,更新寄卖库存优化现状与进度追踪文档,前端 57 个测试全绿并通过类型检查。
2026-09-21 11:40:25 +08:00
yml2213 c80bd0e337 fix(worker-platform): 修复寄售匹配工单详情中卖家上架截图丢失问题,并收敛手动匹配为内部现货直接履约
1. 修复文件归一化器 normalizeUploadedFiles 遇到纯字符串 URL 数组被误过滤为空的问题,自动提取 objectKey 并构造规范 UploadedFile 结构;
2. 优化工单展示映射器 resolveWorkOrderEffectiveBoosterMaterial:当工单资料中截图为空时,自动回退并加载寄售卖家上架/主页截图;
3. 前端管理后台详情抽屉与打手端详情抽屉支持读取 detailOrder.gift.boosterMaterial.screenshots 与 consignmentInfo.screenshots 降级兜底渲染;
4. 手动匹配弹窗与发布拦截弹窗全面收敛为单一标准的【内部现货直接履约】,废除旧版指派打手带来的重复扣押金与二次填资料问题;
5. 新增 consignment-booster-material 单元测试,更新寄卖库存优化现状与进度追踪文档,前后端全套测试通过。
2026-09-21 11:35:38 +08:00
yml2213 c115f5e944 fix(claim): 修复后台手动关闭任务后领取链接未失效的缺陷
1. 鉴权层激活 CLAIM_TERMINAL_STATUSES:在 getClaimContext 中增加 task 状态校验,对 closed 与 expired 终态任务实施 410 拦截并自愈更新关联 Token;
2. 仓储层新增 closeClaimTokensByTaskId():支持按 taskId 批量更新所有非 closed 状态的 Token 为 closed,彻底杜绝多 Token 或重发链接导致的历史活跃残留;
3. 后台关闭任务流程闭环:closeAdminTask 显式触发 closeClaimTokensByTaskId,确保任务关闭时关联领取链接立即失效;
4. 补充 CLAIM_TERMINAL_STATUSES 单元测试与完整排查分析方案文档。
2026-09-20 14:06:48 +08:00
yml2213 9180b5f61c feat(consignment): 高规格(超配钻级/璀璨)寄卖建议价自动按当前最高档位报价 2026-09-17 19:23:01 +08:00
yml2213 1526907005 feat(consignment): 建议价精准匹配璀璨数 + 限制璀璨不超过钻石数量
- 修复价格匹配:parseSpecsFromText 支持「璀」字缩写(1璀/2璀/3璀)与「无璀/0璀」,
  避免生产规则被误判为 0 璀;suggestConsignmentPriceFromRules 增加 brillianceCount
  精准对齐匹配,未配对应模板则返回空,解决同钻级多条规则全中并取最高价的问题
- 透传参数:路由与打手端服务均增加 brillianceCount 传递
- 限制璀璨不超过钻级:
  - 前端选项动态禁用:大于当前钻级的璀璨芯片置灰
  - 钻级调小自动收敛:若原选璀璨大于新钻级,自动 clamp 至新钻级
  - 默认值与联动:璀璨数默认 initialValue=0,queryKey 纳入璀璨,切换即刻带出对应建议价
  - 前后端双重校验:前端表单 Validator 校验 + 后端提报硬拦截(brilliance_exceeds_diamond)
- 后端 487 / 前端 54 测试全绿,docs/寄卖系统优化方案.md 记录批次 Z
2026-09-17 19:14:04 +08:00
yml2213 ccb5b6f4d6 docs: 清理过时文档(以代码为准)
删除(整篇已被代码淘汰 / 重复副本 / 与仓库无关):
- cloudflared_tunnel.txt:全仓无 cloudflared 配置,个人终端记录,无任何引用
- 履约配置/工程债-lewan拆分与短链.md:文中 services/kuaishou-cloud 与 kuaishou-cloud-executor 已删除
- 履约配置/快手Cloud领取mock.md:mock:claim / mock:feifei 与 dev-mock 卡片已移除(只剩 mock:open91)
- 行业电子凭证/解决方案/技术方案/1.基础技术.md(+ 其孤立 image.png):0.基础技术.md 的 75 行截断副本
- 寄卖库存功能设计与实施方案.md:手工入库已 409 停用、收集链接表已随 079 删除、统计看板未实现
- 服务器图片迁移到阿里云OSS.md:MinIO→OSS 迁移已完成(生产 STORAGE_MODE=oss)
- pgBackRest备份方案分析.md:全仓无 pgBackRest 落地痕迹,文档自述暂缓实施
- finance-implementation-plan.md:财务模块已落地(072 迁移 / RBAC / 页面接口),已实现部分与代码重复
  (未落地的二期三期路线图可从本提交的历史版本取回)

改写为与代码一致(已下线通道不再当作现行能力):
- 履约配置/多发货平台与电子凭证整体链路.md:kuaishou-cloud / kuaishou-feifei 标注为已下线 legacy stub,
  现行自动通道 affiliate-dash、人工 manual_dispatch;核销时机与券表按实现校正
- 履约配置/{UID领取与旧单兼容, open91请求, TypeScript类型收紧}.md:lewan/feifei/cloudtentacles 表述改为
  现行 affiliate-dash 链路;normalize 具名类型 KuaishouCloudFlow/FeifeiFlow → AffiliateDashFlow
-  affiliate_dash_发货平台/affiliate-dash对接.md:§13/§14/§19/§21/§24/§25 的已删文件与已下线通道引用校正,
  §21/§22 加「当时快照 / 落地后现状」横幅,回调去重表按 013_affiliate_dash_webhook_events.sql 改写
- 91卡券/{3.异步卡密下单, 5.当前项目对接配置, 6.开发设计}.md:删掉不存在的后台入口、
  cloudtentacles/kuaishou_ct_assisted 依赖、cardsEncoding 与 .js 代码落点校正
- 行业电子凭证/技术方案.md:checklist 指向不存在的 测试用例.md → gen-test-cases.ts + 5.测试指南.md
- 履约配置/cloudtentacles发货平台.md:补「本仓库未接入该通道」说明(保持外部参考)
- 部署启动与数据库重建.md:补齐生产必需变量 APP_DOMAIN / CORS_ALLOWED_ORIGINS / STORAGE_MODE / STORAGE_OSS_*

其它:
- README.md:迁移序号范围 002~009 → 002~080
- 寄卖系统迁移079上库前检查.sql:第 2 段注释按批次 Y 的自动去重更新;新增 2.1「重复退款风险」只读排查
  (已在一次性 PostgreSQL 16 上跑通 001→080 迁移:整份脚本 exit=0,脏数据下 2/2.1 均按预期报警)
- 寄卖系统优化方案.md:删掉链路图里已下线的「客服手工录入」,去掉指向已删设计稿的引用
2026-09-17 16:57:27 +08:00
yml2213 617794f2cf docs: 寄卖系统优化方案记录批次 Y(079 迁移去重修复) 2026-09-17 13:35:41 +08:00
yml2213 103299a7c9 feat(consignment): 发布寄卖自动从接单模板带出建议价
- 新纯函数 suggestConsignmentPriceFromRules:模板商品名(安卓暗潮1钻)用与
  订单同一套规格解析器拆解,系统+系列+钻级全对上才命中;系统按通配口径
  (模板写通用/双端两端都算,模板没写系统不命中——宁可不建议不给错价);
  多条命中取最高价
- 新端点 GET /worker/consignment/price-suggestion(requireActiveWorker)
- 发布表单规格选齐后 300ms 防抖请求:同规格去重、过期响应丢弃;命中自动
  填入寄售价并提示来源与条数;卖家手改过价只提示不覆盖,换规格重新带出;
  提交成功状态复位;接口失败静默(本地没配模板保持手填,行为不变)
- 建议:本地模板没配不影响任何现有行为,生产库模板越多建议越准

后端 483(+建议价命中/不符排除/取最高/通用模板用例)/ 前端 54 测试全绿
docs/寄卖系统优化方案.md 记录批次 X
2026-09-17 13:14:10 +08:00
yml2213 f8101c1730 feat(consignment): 规格口径定案——互通通配 + 后台全量/发布端按物品展示
业务定案:
- 操作后台全量:系统 苹果/安卓/通用,区服 微信区/QQ区/互通;提报审核与
  库存编辑的系统/区服从自由文本改为受控下拉(单一来源 utils/consignment-spec.ts)
- 打手端发布按物品类型展示:苏尔南系统二选一(必须区分端),区服唯一
  「互通」选项且默认选中;后续其他品类在共享常量按品类加条目
- 匹配引擎通配符对称化:区服通配=互通(通用/全区/不限归一化为别名),
  系统通配=通用(双端/全端同理);订单侧写通配同样放行,只增不减匹配面;
  差异描述不把通配对当冲突
- 提报白名单校验(API 层):系统只收 苹果/安卓,区服只收 微信/QQ/互通,
  旧页面缓存或直调接口绕不过
- 物品名拼接:区服为互通时不拼入(对买家无信息量),前后端同口径

后端 481(+互通双向匹配/通配不算差异/真冲突仍排除/白名单校验)、
前端 54(+选项口径/表单引用/默认值)测试全绿;typecheck/lint/format/check:sql 通过
docs/寄卖系统优化方案.md 记录批次 W
2026-09-17 13:01:59 +08:00
yml2213 b666a9c951 fix(consignment): 拼单份额验收收官补寄卖结算钩子 + 手动匹配弹窗三处复核遗留
- acceptWorkOrderShareAndSettle 最后一个份额把母单转 accepted 的分支,
  此前不释放发布押金也不结算供货货款(两钩子只在统一验收里):
  现在同口径补上;供货货款传 assignedWorkerId=0(拼单母单无单一接单人,
  份额打手已各自按 share_reward 结算,不会重复付款)
- 手动匹配弹窗:race_condition/unavailable/spec_mismatch/partial_requires_confirm
  四个错误码清空已选并自动重拉列表,数据过期不再死循环撞错
- 手动匹配弹窗库存侧:keyword+pageSize100 透传后端(原来 keyword 是死参数、
  只拉 50 条),300ms 防抖后端搜索;无供货打手时禁用指派选项并在提交前
  再拦一道(原来必 400 死路);选中订单回显 workerId/workerName
- 凭证核销反馈抽共享 utils/voucher-consume,WorkOrdersPanel 与弹窗共用,
  口径不再漂移(弹窗顺带获得"已提前核销 N 张"提示)
- docs/寄卖系统优化方案.md 记录批次 V

后端 477(+4)/ 前端 50(+1)测试全绿,typecheck / lint / format / check:sql 通过
2026-09-17 12:45:51 +08:00
yml2213 63837e473b fix(consignment): 复核修复——占库撞 080 CHECK 必 500、指派非卖家双付货款、手动匹配权限门控
- 占库默认 allocation_status 从自由文本改为「已安排」,不再撞 080 的
  CHECK ('待安排','已安排');加静态守卫测试(剥注释断言枚举内默认值)
- resolveConsignmentAssignRewardFen 加 assigneeIsSupplier:指派供货卖家本人
  → 报酬=结算价(货款走报酬渠道);指派别的打手 → 报酬保持原值(货款走
  供货货款渠道),两条渠道互斥,封住平台双付;补行为级测试 + 调用点钉住
- 手动匹配两处入口(库存面板行内按钮、拦截弹窗 footer)统一按
  consignment.fulfill 门控,编辑/作废仍为 manage,与后端权限一一对应
- docs/寄卖系统优化方案.md 记录批次 U

后端 473(+3)/ 前端 49(+1)测试全绿,typecheck / lint / format / check:sql / build 通过
2026-09-17 12:36:12 +08:00
yml2213 0476339ec4 fix(consignment): 手动匹配订单按钮点了不弹窗(弹窗挂错了位置)
用户反馈:在库待匹配列表点「手动匹配订单」没有反应。

根因:上一批把手动匹配弹窗挂到了「编辑寄售物品」弹窗**内部**,外层弹窗未打开时
该组件根本没被挂载,点击只改状态、界面无变化。

- 弹窗移到面板顶层(与其它弹窗同级),点击即弹
- 新增静态守卫测试:断言手动匹配弹窗前面不能有未闭合的 Modal(即不能嵌在别的弹窗里)、
  按钮必须真的 setState、open 由该状态驱动;已验证该守卫能拦下错误写法
- 顺带补入口缺口:订单侧原先只在"检测到系统候选"的提醒弹窗里给入口,订单没有任何候选时
  反而进不去手动匹配 —— 工单行内新增常驻「手动匹配现货」(仅待指派/待补资料,
  与后端前置校验同口径)
- 已暂停匹配的现货点按钮会直接 409,改为按钮禁用并提示先打开「允许匹配」开关
- destroyOnClose → antd 6 的 destroyOnHidden(前者已废弃)

验证:前端 typecheck/lint/format/48 例测试/build 全过。
2026-09-17 12:27:58 +08:00
yml2213 a7a55d6c16 feat(consignment): 客服手动指定现货匹配的界面入口
后端批次已提供判定/差异/强制留痕与双向读取接口,这里补界面,让客服真的能用上。

- 新增共享弹窗 ConsignmentManualMatchModal:订单侧(匹配弹窗「手动指定现货匹配」)与
  库存侧(寄售仓库行内「手动匹配订单」)共用同一套交互与落地逻辑,避免两套 UI 漂移
- 交互:搜索 → 选中(精确/非精确/规格冲突三档标签 + 字段级差异说明)→ 选交付方式
  (内部现货履约 / 指派供货打手)→ 非精确需勾选确认、冲突需勾选「确认规格不一致」并必填原因
  → 落地;并在落地前提示"现货立刻被占用、点错需撤销寄售履约"
- 判定规则收敛成纯函数 consignment-manual-match.ts(需不需要确认/填原因、能否提交、
  关键词过滤、标签文案)并加 4 例单测
- 服务与类型补齐:fetchWorkOrderConsignmentMatchOptions / fetchInventoryMatchableOrders,
  fulfill/assign 入参增加 allowSpecMismatch 与 matchNote
- 凭证核销失败的提示沿用既有规则(核销失败不能报成功)

验证:前端 typecheck/lint/format/44 例测试/build 全过;两个新接口未登录访问均 401
(路由已挂载、权限位生效)。
2026-09-17 12:23:30 +08:00
yml2213 f62f9b6645 fix(consignment): 售后立案回落到供货卖家,修内部现货单立不了案
补货款时排查"只认接单人"的地方,发现同类第三处:售后立案的责任人取
work_orders.assigned_worker_id,取不到就报 worker_missing(界面 409「请指定已验收的责任
打手或拼单份额」)。内部现货履约的寄卖单没有接单人,于是这类单子连售后都立不了案;
而货款修好后钱已结算给供货卖家,担责人本来就该是他。

- 抽出共享查询 getConsignmentSupplierByWorkOrderWithClient()
  (consignment-supplier-repo.ts):工单 material_json.consignment.inventoryId 或库存
  bound_work_order_id → 库存 → 提报单,货款结算与售后立案共用同一份口径
- 售后在找不到接单人时回落到供货卖家,并在验收快照里标记 consignmentSupplier
  与提报单号留痕
- 加测试钉住:售后必须先认寄卖关系再判定 worker_missing;取卖家的 SQL 只有一处实现

真实库验证(内部现货履约,接单人为空):反查供货卖家 workerId=3 正确;
售后立案成功且责任人 worker_id=3。临时数据残留 0。
2026-09-17 12:08:39 +08:00
yml2213 896194aa2b fix(consignment): 验收结算补上寄卖货款,并修指派打手线报酬 100 倍单位错
问题:工单 #100171 验收完成时卖家钱包只有押金 -20/+20,货卖掉了但货款收益没进卖家钱包。

查证:工单报酬 reward_amount=14500 分(发单方付 ¥145),货的结算价 cost_price_fen=12400 分
(卖家应得 ¥124),而 assigned_worker_id 为空(内部现货履约)。通用结算的规则是"把工单报酬
付给接单人",内部现货单没有接单人 → 这笔钱谁也没拿到,卖家只拿回自己的押金。

- 新增 settleConsignmentSupplierPayoutByWorkOrderWithClient():验收完成时把货的结算价
  (cost_price_fen,缺省退回 asking_price_fen)补给供货卖家,单位与通用报酬一致(分),
  同样做售后欠款抵扣、按售后策略决定是否延迟解冻、写 reward_settlement/reward_pending_unfreeze
  流水(说明「寄卖货款结算 #单号」)
- 不重复付款:接单人就是供货卖家本人时跳过(指派打手线里货物已随工单报酬付过)
- 修 100 倍单位错:指派打手线把工单报酬改写成货的结算价时写了 (cost_price_fen/100).toFixed(2),
  ¥124 被写成 ¥1.24;reward_amount 的单位是分(已用真实数据核对)。抽成纯函数
  resolveConsignmentAssignRewardFen() 并加测试钉住单位

真实库端到端验证:卖家钱包 ¥205.50 → ¥329.50(+¥124.00 寄卖货款结算),累计结算同步 +¥124.00;
验证脚本改动的开发库数据已还原,临时数据残留 0。
2026-09-17 12:04:39 +08:00
yml2213 40882aeebb fix(consignment): 确认加好友与上传赠送截图恢复为卖家操作,客服兜底
问题:卖家「我的寄卖」里"已匹配-待加好友"的货点不了确认加好友,提示还写着"等待客服确认加好友"。

原因:批次 I 把能力位绑在"订单接单人 = 当前卖家"(selfFulfilling)上,而内部现货履约的订单
根本没有接单打手(assigned_worker_id 为空),于是状态机关掉按钮、后端归属校验还会 403。

业务定调:卖家可以确认加好友,冷却到期后也能自己上传赠送成功截图,客服只是兜底。

- 能力位改成按阶段给:material_submitted 可确认;内部现货履约在 material_required 也可确认
  (与客服侧一致);冷却结束可提交赠送截图;提示改成卖家视角
- 后端归属只认"这张提报单就是当前卖家的"(别人的单仍 404),删除"订单接单人必须是卖家"的 403
- 卖家提交凭证走 asConsignmentSupplier 选项:跳过接单人校验(归属由寄卖单保证),
  冷却是否结束、必须带图等校验全部保留
- 客服侧按钮不变,谁先点谁生效,后点者拿到明确 409

真实库端到端验证:卖家列表按钮=true → 确认加好友 gift_phase=friend_countdown(+72h) →
冷却中被拒 work_order_gift_cooldown_active → 冷却到期后卖家上传赠送截图成功(工单转 pending_acceptance)。
2026-09-17 11:57:33 +08:00
yml2213 0fd09976a5 fix(files): 去掉文件链接的签名与有效期,修客服端凭证裂图
问题:寄卖凭证的图片地址是带签名的临时链接(15 分钟有效),而入库时会把当时的链接
原样存进 screenshots_json;工单验收那条线出参时会用 refreshStoredFileUrl() 重签,
寄卖这条线(提报凭证/赠送凭证/卖家列表)漏了这一步,于是入库 15 分钟后链接必然失效,
客服看到裂图。图片本身没丢,是取的时候没重签。

业务定调:签名这套意义不大,直接去掉。

- buildFileUrl() 只产出不带签名、不带有效期的普通链接(对象 key 带随机段,不可枚举),
  删除签名生成/校验与 15 分钟 TTL 常量,文件读取路由不再校验签名
- refreshStoredFileUrl() 语义改为"归一化":把历史存的签名链接洗成普通链接,老数据不用改也能看
- 寄卖出参统一归一化:提报凭证、赠送凭证(imageUrls + files[])、库存截图、卖家列表截图

真实库验证:库里早在 2026-09-15 就过期的老链接现在返回 HTTP 200(image/webp,52632 字节),
改造前是 403;客服接口下发地址已无签名;不存在的 key 仍 404。

取舍:文件路由原本靠签名把关,去掉后知道链接即可看图(key 含 24 位随机段,实际不可枚举)。
如需收紧可给该路由加后台登录校验。
2026-09-17 11:52:40 +08:00
yml2213 e731348bb0 refactor(consignment): 删掉按库存号操作寄卖的卖家入口
手动入库停用后,"没有提报单的现货"已不可能再产生,批次 I 为兜这类货加的两个
按库存号入口(/worker/consignment/inventories/:inventoryId/...)成了纯负担。

- 删除两个按库存号的路由/服务函数、前端两个请求函数与页面里的锚点分派逻辑,
  卖家动作只按提报单号(寄卖单号)定位
- 卖家列表里"没有提报单"的兜底行不再暴露内部仓库号(标题改「客服手工入库」),
  且一律不给操作能力位,不给用户一个点下去必然失败的按钮
- 加静态守卫测试钉住以上两点,防止以后又长出按库存号的入口

真实库验证:卖家列表三件货都带寄卖单号与 submissionId,没有提报单的现货 0 件。
2026-09-17 11:45:50 +08:00
yml2213 0c10f0e135 feat(consignment): 停用客服手动入库,寄卖货源只走平台提报
背景:手动入库是唯一会造出「没有提报单的现货」的入口,这类货没有寄卖单号,
统一状态机/凭证链/搜索/卖家端单号锚定都串不起来,只能在界面回退显示内部仓库号 INV,
正是"一件货两个号"的残留。业务定调:寄卖货源只走「打手平台提报 → 客服审核入库」。

- 前端寄售仓库的「手动入库」入口整块删除(按钮 + 入库弹窗 + 提交逻辑 + 服务函数)
- 后端同时挡住,防旧页面缓存或直接调接口绕过:
  POST /worker-platform/consignment/inventories 返回 409 consignment_manual_inbound_disabled;
  死代码一并清掉(服务层原实现、仓库层 createConsignmentInventory)
- 提报审核入库路径不受影响,照旧生成内部仓库号 INV 并写 source_submission_id,
  即每件货都必然挂着寄卖单号,INV 只作为内部编号存在、界面不展示

真实库验证:接口被拒(409),且「没有提报单的现货行数」前后均为 0。
2026-09-17 11:41:46 +08:00
yml2213 47e09d72ce fix(consignment): 内部寄售匹配弹窗防点错
问题:弹窗里「走接单平台指派打手(冻结押金交付)」与「内部现货履约」两个按钮上下紧挨、
样式相近,而且只有"部分匹配"才弹确认——精确匹配时两个按钮点下去都立刻执行,
点错就得走「撤销寄售履约」才能退回来。

- 两个动作一律二次确认(不再只有部分匹配才确认),确认框写明:寄卖单号(可复制)、
  动作(给谁接单/是否冻结押金)、结果(立刻占用现货、其它订单不能再匹配、
  内部履约还会跳过「待打手提交资料」直接进冷却)、以及退回要走撤销寄售履约;
  部分匹配额外红字提示"不是精确匹配、无法自动回退"并把确认按钮降为 danger
- 按钮区改成独立的「选择履约方式」分区小卡片:两个按钮各占一行 block 铺满
  (点击目标更大、不再小按钮挨着)、间距 14px、各加图标(打手 TeamOutlined /
  库存 PushpinOutlined),每个按钮下方一句后果说明
2026-09-17 11:33:23 +08:00
yml2213 54f8a27e97 fix(consignment): 匹配弹窗改用寄卖单号,客服界面不再展示内部仓库号
问题:内部寄售库存匹配弹窗显示的是「寄卖单号 INV26091711253394」——候选现货走的
是另一个查询 listActiveConsignmentInventoriesForMatching,它没 join 提报单,
sourceSubmissionNo 取不到,前端就回退显示内部仓库号;客服拿这个号去寄卖仓库又搜不到。

- 匹配候选查询补 LEFT JOIN consignment_submissions 带出 source_submission_no;
  该查询原本是 SELECT * 且列名无前缀,而 consignment_submissions 同样有
  status/game_name/category_id,加 join 会让条件变成 ambiguous column 直接 500,
  故列名统一加 ci. 前缀并显式列字段(加静态守卫测试钉住)
- 客服界面只展示寄卖单号:匹配弹窗候选卡片、工单寄售标识、工单详情、寄卖仓库列表与详情
  全部去掉内部仓库号;手工入库现货写「客服手工入库(无提报单号)」,
  历史老单写「老单无提报单号」,不再抛内部编号
- 内部仓库号保留:数据/接口/按它搜索都还在,撤销解绑等链路未动

真实库验证:仓库层候选查询与 checkWorkOrderInventoryMatches 都带出了寄卖单号。临时数据已清理。
2026-09-17 11:31:01 +08:00
yml2213 ca04e09deb feat(consignment): 客服端凭证链可视化(提报凭证 + 赠送凭证)
问题:一件寄卖有两类凭证,客服界面只看得见第一类,还是 48x48 一张缩略图,
看不出是主页还是物品;第二类(证明"这件货真送出去了"的赠送完成截图)只在工单验收界面,
客服要证明赠送是否完成得自己跨模块翻,没有任何地方把两类凭证并排呈现。

- 两类凭证分别在哪里:
  提报凭证 = 提报表 screenshots_json(卖家提报时的游戏主页截图,含物品/仓库详情)
  赠送凭证 = 绑定工单的验收资料 work_orders.acceptance_json(冷却结束后上传、客服凭此验收)
- 后端把凭证链从客服两个列表/详情接口一起下发:提报表/库存 → 结果库存 → 绑定工单,
  新增 submissionScreenshots / giftEvidenceImages / giftEvidenceNote / giftEvidenceSubmittedAt /
  giftWorkOrderNo / giftWorkOrderStatus / giftEvidenceReviewStatus(none|pending|accepted|submitted);
  赠送凭证图从 imageUrls 与 files[].url|mediumUrl|thumbnailUrl 两处取并去重
- 提报凭证口径统一:有来源提报单用提报单主页截图,客服手工入库现货回退库存自身截图,
  前端只看 submissionScreenshots 一个字段,不会拿错
- 前端新增共享组件 ConsignmentEvidenceGallery(缩略图 + 大图预览 + 共 N 张,
  预览用 Image.PreviewGroup items,被折叠的图在大图里仍能翻看);审核面板把「凭据截图」
  拆成「提报凭证(游戏主页截图)」与「赠送凭证」(带待验收/已验收 Tag + 关联工单 Tooltip),
  仓库面板新增「凭证」列并分组展示,两个详情弹窗同口径(含备注/提交时间/工单号/一句话说明)

真实库验证:赠送凭证解析在构造的工单验收资料上取到 3 张图(imageUrls 1 + files 2)并识别
pending_acceptance → 待客服验收;提报凭证在真实数据上取到 1 张。临时数据已清理。
2026-09-17 11:22:59 +08:00
yml2213 44de11a3a7 feat(consignment): 一个寄卖单号锚定全流程 + 统一状态机 + 卖家侧确认加好友/提交赠送截图
问题:一件货身上挂着三套互不相通的状态(提报单审核态、仓库库存态、工单赠送态),
my-items 同时返回两个数组、卖家端分两个列表渲染,同一件货显示两行两个号;
且卖家端只映射了前两套状态,"已出库"之后流程就断了,卖家不知道该干什么。

- 提报单号 SUB… 作为唯一「寄卖单号」从发布锚定到结算(零迁移);
  listWorkerConsignments 改成一件货一条记录,库存/工单信息挂上去,
  客服手工入库的现货(无提报单)才回退用库存号当锚点
- 新增 domain/consignment-item-stage.ts:把三套底层状态推导成卖家看得懂的一个阶段
  (待审核/已通过待匹配/已匹配-待加好友/冷却中/待赠送/已赠送待审核/已完成/驳回/作废/取消)
  + 一句"下一步做什么" + 能力位(谁能确认加好友、谁该传截图),列表筛选与 KPI 也改由它驱动
- 卖家侧新增动作(以前只有 publish + my-items,卖家只能干看):
  POST /worker/consignment/items/:submissionId/{confirm-friend,gift-evidence}
  POST /worker/consignment/inventories/:inventoryId/{confirm-friend,gift-evidence}(手工入库现货)
  复用既有工单链路 confirmWorkOrderFriendAdded / submitWorkerOrderAcceptance,
  只加归属校验(不是本人履约的订单 403),顺带白拿"冷却没结束不许提交凭证""必须带图"
- 客服端用同一个号:库存列表/详情补 sourceSubmissionNo(LEFT JOIN 提报单),
  履约/指派写进工单的寄售信息也带上;关键字搜索支持按寄卖单号搜(计数 SQL 同步补 join)

真实库端到端验证:确认加好友 → gift_phase=friend_countdown / friend_added_at 落库 /
gift_available_at 正好 +72h;冷却期内提交截图被拒(work_order_gift_cooldown_active);
越权操作被拒(consignment_item_not_found);按寄卖单号搜索命中正确。临时数据已清理。
2026-09-17 10:57:57 +08:00
yml2213 99752dce9e fix(consignment): 修掉发布时乱弹内部库存提醒,并把弹窗赏金换算成元
乱弹窗根因:matchPeacekeeperOrderWithInventory 精确匹配判定失败后无条件 fall through 到
部分匹配;而系统/区服/系列/钻级缺失时 compareSpec 返回 unknown(不是 mismatch)会被放行,
于是任何只写了游戏名的订单都命中仓库里全部在库货,表现为"随便发布点什么都会弹一下"。

严格模式(自动提醒)现在要求:① 系统/区服/系列都能确认一致;② 存在正信号(库存配置更高,
或订单压根没提钻级)。"订单没写规格"不再算命中。

同时给 matchPeacekeeperOrderWithInventory / findMatchingPeacekeeperInventories 增加
allowUnspecifiedSpecs 选项:人工履约的服务端复检(运营已人工选定现货)走宽松模式,
标题没写全规格不硬拦、真冲突仍拦,避免收紧自动提醒时把人工履约一起挡掉。

赏金显示:弹窗用 rewardAmount(单位分)直接 toFixed,把 ¥40 显示成 ¥4000;
同文件其他 30 余处均为 /100,仅此处漏了。弹窗内收购成本/履约押金本来就已 /100,核对无误。

验证:用截图里的现货(苹果QQ区怒嚎3钻2璀璨)对照 6 种订单——
"怒嚎"、"苏尔南" 从命中变为不命中;"苹果QQ区怒嚎1钻" 仍按高配充低配提醒;
"5钻"(低配充高配)、"安卓微信区怒嚎1钻"(系统/区服不符)不命中。
后端 435 例(新增 3 例、改写 3 例)全绿。
2026-09-17 10:30:17 +08:00
yml2213 d158cc91bc feat(consignment): 确认加好友后现货作废不回池,撤销履约押金可选并结算打手押金
现货口径(严):已确认加好友 = 买家好友已加上、货随时可能送出去,回池会被下一个工单
再次占用(等于二次出货)。收口在 releaseConsignmentInventoryBindingForWorkOrderWithClient:
解绑前读工单 acceptance_mode/friend_added_at,命中则 archived + allow_matching=FALSE + 留痕,
否则仍回池。所有解绑路径自动继承,发单系统接口未动。

撤销寄售履约(寄卖专属入口)支持两笔押金各自可选,默认按规则自动:
- 打手履约押金:auto / refund / forfeit
- 卖家发布押金:auto / keep_frozen / forfeit
策略抽成 domain/consignment-deposit-policy.ts 纯函数;覆盖时原因照旧必填,选项与金额写进
工单事件便于对账。

顺带修掉两个 bug:
1. 撤销寄售履约从不结算打手履约押金——只清 assigned_worker_id、只处理卖家押金,
   worker_deposit 单撤销后打手押金永久冻结。现按选项结算(退还/没收)。
2. detachConsignmentMaterialFromWorkOrderWithClient 里 $1 既作 $1::text(detachedAt)
   又赋值给 updated_at,Postgres 整体推断成 text → 42804。凡解绑现货摘寄售标记的路径
   (取消指派/撤单/退单/售后/撤销履约/人工回库)在真实库上必然 500,假 client 单测抓不到。
   已显式 ::timestamptz,并补类级静态护栏扫同类写法。

验证:真实库(全回滚)——已确认加好友解绑 → archived/allow_matching=false;
未确认 → 仍 in_stock;打手押金冻结 3000 → 退还 3000(重复结算 0)→ 再冻 2500 → 没收 2500
(可用余额不变、冻结归零、流水 deposit_deduction)。后端 432 例(新增 5 例)全绿。
2026-09-17 10:21:38 +08:00
yml2213 a47c243421 feat(consignment): 确认加好友后卖家发布押金不退,并封住二次冻结的 500
需求:确认加好友之后押金不退回,卖家的押金也不退回。

- 新增 forfeitConsignmentPublishDepositBySubmissionWithClient /
  ...ByWorkOrderWithClient:release 的镜像——可用余额不动、只扣冻结额,写一条负数
  deposit_deduction 流水并带上工单号与 giftDepositForfeited 标记。
  台账 outstanding 会把 deposit_deduction 计入已核销,因此之后同一提报单的
  release 与重新冻结都拿不到钱,天然幂等、退不回去。
- 挂载点:取消指派/撤单/退单/售后回退等 6 处「押金不退」判定点,以及「撤销寄售履约」的
  作废与回库分支(后者原来会把押金留着或直接退还卖家)。
- 修掉一个会 500 的边角:押金已退还/已没收时 ensureConsignmentPublishDepositFrozenBySubmissionWithClient
  会去插第二条 deposit_freeze 流水,撞上"每个提报单只允许一条冻结流水"的唯一索引
  (没收后现货回库、再被匹配后撤销/退回复库即可触发)。现显式抛
  consignment_deposit_already_settled,两个服务层都映射成 409 文案。

验证:真实库(回滚)验证没收全链路——冻结 2000 → 工单侧没收 2000 → 可用余额不变、
冻结额归零、流水为 deposit_deduction(-2000, 关联工单);没收后 release 恒为 0。
后端 420 例(417 通过,新增 5 例)全绿。
2026-09-16 21:27:47 +08:00
yml2213 563e548b2e feat(consignment): 补齐寄卖前端权限门控,收口调拨状态与运营体验
权限门控(P1-8 剩余):
- 新增 resolveAdminPermission(sessionPermissions, code):会话接口的最新权限列表优先,
  接口异常才回退登录时的本地快照;空数组也判无权限,避免"刚被收回权限仍能点"。
- 寄售仓库面板:consignment.manage 控制手动入库/编辑/作废/退单回库/匹配开关(无权限时开关禁用)。
- 寄卖提报面板:consignment.review 控制审核入库/驳回。
- 接单平台页:无 consignment.view 不渲染两个寄卖 tab,并把 URL/localStorage 的旧选择拉回工单页。

数据约束(P2-19 剩余):
- 迁移 080:allocation_status 历史非法值归位「待安排」(备注留痕)后加 CHECK(待安排/已安排),
  并顺手修正 077 遗留的"收集链接/玩家提交"权限描述文案。
- 编辑接口拒绝直接改 allocationStatus(400 consignment_allocation_status_update_forbidden)。

运营体验:
- 两个面板补 isError 错误态与重试;审核通过/驳回加 confirmLoading 与提交中守卫(防双提交)。
- 待审徽标改用后端真实总数(原来只统计当前页);编辑弹窗押金不再兜底 ¥100(会误写押金)。
- 履约拦截弹窗冷静期文案不再硬编码"3 天",改为按商品规则设定。
- 核实并撤回"倒计时时区偏移"误报:deadlineAt 为带 Z 的 ISO,前端无偏移问题。

验证:后端 412 例(409 通过)、前端 21 例(新增 5 例权限解析)全绿,
typecheck / lint / format / check:sql / build 通过;迁移 001→080 在全新空库跑通并在 dev 库应用。
2026-09-16 20:39:52 +08:00