Commit Graph
100 Commits
Author SHA1 Message Date
yml2213 08318ef8d9 feat(deploy): 财务上线数据阶段编排与运维加固
- 新增 deploy/post-deploy.sh:回填 → 业务配置 → 同步 → 验收四阶段编排,支持 --only/--dry-run/窗口参数
- 新增 tools 镜像与 scripts/verify-finance-launch.sql(15 项上线验收)
- 验收口径:成本闸门二选一、要求已过账凭证、备用金支出关联、成本覆盖 WARN
- 加固:参数校验、工具镜像每次刷新、docker run 兜底超时、迁移前缀探测、验收失败退出码 2
- 工具镜像预建 /app/data,消除日志 EACCES
- 回填后与 restore-db 恢复后自动 VACUUM (ANALYZE),修复订单列表分页 COUNT 全表扫描(41 万单实测 27s → 0.17s)
- 文档:41 万单同步用 7 天窗 + 180s 超时;回填/恢复后刷新统计
2026-10-28 11:52:42 +08:00
yml2213 0d9fb29460 fix(admin): 移除总账与对账页重复的页面标题 2026-10-27 16:41:55 +08:00
yml2213 9d5af359fa feat(finance): 完成财务控制、L1 钱包硬化与迁移收敛
- P0/P1:影子总账追加调整、关账/退款/资金/积分幂等、成本版本追溯、对账订单项维度
- 迁移收敛:原 103–114 合并为 103_finance_foundation、104_finance_controls、105_work_order_consignment
- 数据:L1 钱包 BIGINT/CHECK/奖励幂等;重复奖励审计口径修正与人工核对清单
- 报表:销售毛利缺失成本收入提示,旧收支页明确现金流口径
- 文档:同步迁移基线、合并评估、代码复核与上线说明
2026-10-27 16:08:16 +08:00
yml2213 0de0fd7b58 chore(db): 将 108–115 补丁迁移收敛为 108–111
- 原 108/111/112/113/114 合并为 108_finance_cost_integrity:
  成本异常归档、人工成本完整性、影子总账、商品页/模板查询索引
- 原 115 注释迁移改为 111_work_order_share_cancel_reason_comment
- 新增 reconcile-migration-history.sql,用于已跑旧 112–115 的库
  重建 schema_migrations 顺序,不重复执行 DDL
- 已验证:001→111、101→111 两条升级路径;
  旧 115 与新 111 的 pg_dump schema 完全一致
- 测试/文档迁移编号同步到 103–111

验证:backend check 853(849 pass / 4 skip);frontend check 172 + build。
2026-10-27 12:37:21 +08:00
yml2213 c8b7e80979 perf(template): 补模板证据日期/覆盖索引,预览降到秒级 2026-10-26 16:43:56 +08:00
yml2213 2b967ddd4c feat(cost-center): 商品初始化/回填增加时间范围,默认最近 30 天
- 接单模板初始化预览/执行支持 dateFrom/dateTo,只使用范围内工单证据;
  范围外模板不再先建商品
- 按工单回填商品支持时间范围;人工商品归一 UI 传时间范围
- 模板初始化重置只清理范围内导入映射/订单项,避免误伤范围外数据
- 初始化/回填默认最近 30 天,自动发货仍固定 30 天
- 文档更新初始化口径与页面操作
2026-10-26 16:26:48 +08:00
yml2213 288a0526ad perf(cost-center): 建索引后立即刷新统计信息 2026-10-26 16:08:06 +08:00
yml2213 25012c30f4 perf(cost-center): 商品页跳过无关 affiliate 聚合并补部分索引 2026-10-26 16:04:52 +08:00
yml2213 f0dda3842b test(worker): 校验拼单验收统一收口函数的寄卖钩子 2026-10-26 15:51:38 +08:00
yml2213 6dc1e7e727 fix(scheduler): 成本财务同步默认回退最近 7 天,避免小库语句超时 2026-10-26 15:49:51 +08:00
yml2213 6b0078f680 fix(finance): 收口快手退款路由并修复销售事实变更后的总账同步
- 平台退款路由从通用订单路径改为
  POST /api/v1/admin/kuaishou-industry/orders/:orderId/refunds/approve-and-record,
  服务改名 approveAndRecordKuaishouRefund,明确仅快手 91
- 总账同步改为未关账期间按日整体重建销售凭证,解决收入回填/退款重算后
  旧凭证金额不更新的问题;删除与重建放在同一事务,已关账期间保持不动
- 文档明确 revenue:backfill 是存量订单退款的前置条件:
  revenue_amount_fen=0 会导致退款登记按钮置灰
- 本地生产副本已执行 revenue:backfill:375,447 行全部回填,
  order 375483 可退金额恢复为 237.00 元

验证:backend check 844(840 pass / 4 skip);frontend check 172 + build;
集成测试通过(代录、总账平衡、关账阻断、对账)。
2026-10-26 13:48:53 +08:00
yml2213 861524a91a docs(finance): 校准代录与本地迁移基线到 112 2026-10-26 13:33:25 +08:00
yml2213 62763ddf0c feat(finance): 支持代录指定客服账户,并上线影子总账/对账/关账/快手平台退款
- 人工确认履约:管理员/财务/运营可传 fundAccountId / creditOwnerAdminUserId
  指定客服备用金/积分账户;客服仍强制本人账户
- 新增迁移 112:finance_accounts / journal_entries / journal_lines /
  periods / reconciliations / reconciliation_items,种子 11 个科目
- 影子总账:销售事实按日生成收入/退款/成本凭证,支持手工凭证、试算平衡;
  不接管钱包余额;总账同步接入定时任务与退款重算
- 期间关账/反关账:关账先补凭证并校验试算平衡,closed 期间禁止新增凭证
- 平台对账:JSON 账单导入,按 provider + platform_order_id 匹配订单/退款,
  标记 matched/amount_mismatch/missing_order/missing_refund/duplicate
- 平台退款:快手行业(91)同意退款 API 接入,成功后落 source=platform;
  抖音/拼多多返回 501,保留手工退款
- 新增后台「财务 → 总账与对账」页面(总账/期间/对账三个 Tab)
- 集成测试扩展到代录、总账平衡、关账阻断、手工凭证、对账匹配

验证:backend check 844(840 pass / 4 skip);frontend check 172 + build;
迁移 112 在 scratch 库全量执行并重跑幂等;本地生产副本已升级到 112,
销售事实同步 56 条凭证,借贷合计 1,885,351,864 = 1,885,351,864。
2026-10-26 13:32:47 +08:00
yml2213 f0eb8a5e05 docs(finance): 补充责任主管前置与客服账户初始化步骤 2026-10-26 13:05:46 +08:00
yml2213 a3e2bdb7c4 feat(finance): 人工成本单事务/幂等 + 配置自动匹配 + 缺成本监控
- 确认履约改为单事务:锁订单项 → 复查快照 → 扣积分/备用金 → 写成本快照;
  快照失败整体回滚,不再出现「钱扣了、成本没记」
- manual_case 的 subject_id 统一为 order_item_id,新增订单项级唯一索引(迁移 111),
  消除 manual_expenses.id / platform_credit_entries.id 跨表撞车
- 人工 SKU 匹配增加 sku_code / sku_name 兜底;保存配置立即回填最近 30 天,
  定时任务按窗口 rematch,确认时再按 SKU 兜底匹配
- 新增 manual_cost_missing 异常队列:从首次人工配置起算,确认履约立即收口
- 补单元测试与真实 PostgreSQL 集成测试(并发、重复、强制快照失败回滚、双资金链路)
- 校准财务文档并新增上线初始化/验收手册(历史人工不补录,只保证配置后的新单)

验证:backend typecheck/lint/format/check:sql/test 843(839 pass / 4 skip);
frontend typecheck/lint/test 172;迁移 111 在 scratch 库全量执行 + 重跑幂等。
2026-10-26 13:04:51 +08:00
yml2213 73908119dc style(backend): 修复 4 个文件的 Prettier 格式告警
仅按仓库 Prettier 规则换行/去多余空行,无逻辑变更:
- routes/admin/cost-center-catalog.ts
- services/cost-center/affiliate-dash-prices-baseline.ts
- services/cost-center/affiliate-product-service.ts
- services/cost-center/product-catalog-service.ts

验证:backend format:check / typecheck / lint / check:sql 通过,
tests 833 pass(3 skipped);frontend format:check 通过。
2026-10-26 12:13:08 +08:00
yml2213 31a8b6fc65 Merge branch 'dev1023' into dev
解决 9 个冲突文件,并修复合并后遗留问题:

- 大厅候选集:采用 FIFO 窗口 + 全部置顶单 UNION(列表与抢单/拼单复核同源)
- 拼单份额:采用多次参与模型(每次参与 INSERT 新份额、requestId 幂等),
  取消后可重新参与;移除 HEAD 已废弃的单行 rejoin 逻辑与对应测试
- 工单迁移与成本中心 103–108 编号撞车:合并重写为
  109_work_order_share_participation / 110_work_order_hall_and_shop_indexes;
  临时库全量执行与重跑幂等验证通过(10 列、唯一键已删、7 个索引)
- 实时补丁:保留个性化字段、置顶重排、分页总数同步;补回 orderTimelineVisible 类型
- 打手大厅:保留 memo 组件化,移植「再拼一次」多份额按钮逻辑
- 全项目表格统一 PercentTable:WorkerOrderShareTable 改造

验证:backend typecheck/lint/check:sql/test(833 pass)、
frontend typecheck/lint/test(172 pass)/build 全绿。
2026-10-26 12:10:53 +08:00
yml2213 dfc01db4ae feat(admin): 整合财务模块导航为侧边栏子菜单与顶部联动Tab
- 侧边栏收敛:将散落在运营分组下的销售毛利、商品与成本、钱包管理、收支明细整合入「财务」二级子菜单,并支持智能展开与角色权限隔离
- 顶部导航联动:新增 FinanceSubNav 通用组件,在销售毛利、商品与成本中心、钱包管理、收支明细 4 个页面顶部统一提供一键切换 Tab
- 语义规范化:将原“财务”流水页面标题明确为“收支明细”,消除模块与页面的命名歧义
- 验证方式:npm run check 全量检查通过(Prettier、ESLint、tsc、单测 100% 通过),构建产物已同步至运行容器并验证路由与交互
2026-10-25 20:39:11 +08:00
yml2213 eaffae4af0 fix(frontend): 支持请求级自定义超时并将接单模板初始化与批量回填超时延长至5分钟
- 在 http 客户端封装中增加可选 RequestOptions 参数透传,允许对耗时较长的数据初始化/大批量回填接口单独配置超时
- 将 applyAdminTemplateProductBootstrap、syncAdminAffiliateDashCostSnapshots、backfillAdminProductMappings 及 backfillAdminNormalizedQuantities 客户端超时由 50 秒延长至 300 秒(5分钟)
- 彻底解决生产全量订单数据规模下接单模板初始化触发 50 秒网络超时提示的问题
- 验证方式:npm --prefix apps/frontend run typecheck 通过,生产镜像构建运行正常
2026-10-25 17:29:58 +08:00
yml2213 12f370de15 feat(cost-center): 将统计与自动发货同步统一收敛至最近一个月并自愈历史非标SKU
- 范围收敛:将财务日期范围默认窗口、自动发货履约任务扫描、成本快照重算及定时任务默认窗口统一收敛为最近一个月(30 天),不再扫描混乱的历史遗留数据
- 脏数据清洗与自愈:在自动发货同步与基线导入时自动识别并清理历史把中文名当做 SKU 插入的 21 个非标脏商品,将关联的 116 个订单项平滑重定向至标准 38 款基线商品
- 标准提取:从履约任务 context_json 中按优先级提取标准上游 sku,通过正则仅允许合规英数标识符入库,避免中文名称污染商品目录
- 界面对齐:前端销售毛利概览默认查询最近 30 天,自动发货与目录改价追溯生效时间默认设置为近一个月(30 天前)
- 验证方式:全量单测 783 项通过、tsc 0 error、容器内执行同步后脏商品归零且销售事实精准重算
2026-10-25 16:24:50 +08:00
yml2213 e61d003342 fix(cost-center): 将自动发货价格基线转为内建常量并修复参数类型
- 提取并内建 38 条自动发货采购成本基线常量,消除生产镜像缺失 scripts 目录的 ENOENT 问题
- 在 jsonb_build_object 中增加 $5::text 类型显式强转,避免 Postgres 参数类型推断错误
- 增加同生效日期的版本就地更新逻辑,保障基线可重复无损导入
- 验证方式:npm run typecheck、npm test、生产镜像容器内真实触发导入接口返回 200
2026-10-25 16:03:16 +08:00
yml2213 b7ad69831a feat(cost-center): 统一商品成本中心为全系统唯一标准价格源并闭环改价与工单同步
- 核心架构:将商品与成本中心确立为全系统唯一标准价格源,接单模板价格在接单平台禁止编辑并提示收敛至成本中心,后端 saveAdminWorkProductRule 严格拦截价格篡改
- 改价与同步:标准商品目录与自动发货专属面板提供统一改价弹窗,支持追溯/立即生效/指定时间;改价后自动或手动将新价格同步至接单大厅待抢单工单,保持下游业务一致
- 缺陷修复:修复 cost_versions 追溯改价时因同生效时间违反 chk_cost_versions_period 检查约束及 uq_cost_versions_scope 唯一索引冲突的问题,采用 active 版本就地更新机制
- 分类树优化:工单二级分类树限定仅在工单来源展示,自动发货与人工客服彻底隐藏分类树并重置过滤条件
- 验证方式:通过后端 784 项全量测试、前后端 tsc 类型检查及前端生产构建打包
2026-10-25 15:21:34 +08:00
yml2213 55a3e0df9c refactor(admin-ui): 成本中心导航收敛为 4 个固定 Tab
原结构是「4 个来源 Tab(内容只有一句提示语)× 6 个内容 Tab」,
且来源 Tab 会增删内容 Tab:选「自动发货」后标准商品/渠道映射/发单价格直接消失,
切换来源还会强制跳转。用户反馈「逻辑不顺、很多 tab 没必要」。

- 来源改为工具栏 Segmented:只筛数据,不改变导航;Tab 永远 4 个
  标准商品 / 渠道映射 / 成本配置 / 成本异常;
- 自动发货 SKU、发单价格、人工 SKU 配置合并为「成本配置」,
  选「全部」时给三个入口卡片,选具体来源时直接渲染对应面板;
- 自动发货 SKU 原本是标准商品的同数据子集(同一个接口 + carrierType),
  合并后不再有重复入口;
- 渠道映射在自动发货/人工来源下改为说明性提示,不再展示空表;
- 异常徽标改用当前来源的计数,不再出现「徽标 10 万、列表几百条」;
- refreshAll 改为按 queryKey 前缀失效,修好漏刷
  (诊断、未归一队列、人工 SKU 等 5 个查询);
- 删除 Context 里 12 个从未被读取的字段(products/versions/exceptions 等
  空数组与 loading 常量),注释改为与实现一致;
- 「生效发单价格」改名「生效成本版本」——它统计的是全部 active 版本,
  按来源过滤后叫发单价格会误导。

验证:后端 786 测试、前端 lint/typecheck/test/build 通过。
2026-10-25 13:55:36 +08:00
yml2213 88ba87efff feat(cost-center): 总览统计支持按来源收敛
页面顶部的 6 张统计卡原本是全局口径:选了「自动发货」,商品数还是 2017、
异常数还是 108,314,和下面的列表对不上。

- overview 接口接受 scope(all / affiliate_dash / work_order / manual);
- 商品、映射、成本项、生效版本、待处理异常、未映射订单项全部按来源过滤:
  商品看 canonical_sku 前缀(aff: / tpl:+wo: / man:),
  成本项与版本看 cost_model,异常与未映射订单项看 order_items.fulfillment_mode;
- 额外返回 productTotalCount(全局商品数),供「全部」徽标使用,
  避免切到单一来源后「全部」也被算成 49。

实测四种口径:
  all            商品 2017 / 映射 4897 / 成本项 3 / 版本 712 / 异常 108314 / 未映射 53901
  affiliate_dash 商品   49 / 映射    0 / 成本项 1 / 版本   0 / 异常  53204 / 未映射     0
  work_order     商品  773 / 映射 4897 / 成本项 1 / 版本 711 / 异常   1209 / 未映射     0
  manual         商品 1195 / 映射    0 / 成本项 1 / 版本   1 / 异常      0 / 未映射     0
2026-10-25 13:55:25 +08:00
yml2213 39fe448b48 feat(cost-exceptions): 支持 --days=0 一次性归档
一次性清理需要「不按时间过滤」的语义,但 CLI 把 days 下限钳在 1:
本地库的 15.2 万条 resolved 异常是 17 小时前重建生成的,
--days=1 一条都命中不了,只能手写 SQL。

- --days=0 表示不过滤时间,归档全部已处理行(open 仍不归档);
- 执行时打印一次性清理提示,避免日常误用;
- 记录 2026-10-25 的实际清理结果:151,939 行 / 152 批 / 3.9 秒,
  热表 260,253 → 108,314(全为 open),VACUUM FULL 后 155 MB → 51 MB,
  归档表 61 MB,主键重叠 0 条。

验证:--days=0 --dry-run 返回 retentionDays=0、archivableRows=0(已清空)。
2026-10-25 13:34:09 +08:00
yml2213 ccc71e0aab Merge branch 'main' into dev 2026-10-25 13:33:05 +08:00
yml2213 2fb7aae13f feat(auth): 登录态改为滑动续期(后台 24h/7d,打手 7d/30d) 2026-10-25 13:28:58 +08:00
yml2213 81edf530db fix(worker-platform): 拼单取消后可重入,大厅置顶始终优先 2026-10-25 13:08:19 +08:00
yml2213 601c10d2a5 refactor(cost-center-ui): 拆分渠道映射面板
ChannelMappingPanel 908 行 → 427 行外壳 + 3 个视图组件:

- ChannelMappingCatalog.tsx  322  映射目录 Tab(标准商品行 + 展开明细列)
- ChannelMappingQueue.tsx    218  未归一队列 Tab(含「按内部 SKU 归一」提示)
- MappingFormModal.tsx       135  新建/编辑弹窗表单

拆分边界:
- 查询、筛选/分页/展开状态、提交与回填动作仍由外壳持有,切 Tab 不丢条件;
- 视图组件只接收数据与回调,不直接访问 queryClient / message / modal;
- 履约方式文案与颜色、MappingPrefill 提到 shared.ts,避免「视图依赖视图」。

行为保持:
- JSX 与中文文案逐字保留,字面量集合比对只剩两类预期差异
  (4 个履约标签移到 shared、2 处模板字符串改用局部变量,输出一致);
- 队列空态判定、人工单提示、刷新 loading、展开本页/收起全部等逻辑语义不变。

验证:typecheck / lint / 前端测试 / build 通过。
2026-10-25 12:15:37 +08:00
yml2213 d90c066888 feat(cost-center): 成本异常 60 天归档
cost_exceptions 只增不减:本地快照 260,253 行(resolved 151,939 / open 108,314),
已处理的行只是审计痕迹,留在热表会拖慢「状态 + 时间」分页,并让唯一索引持续膨胀。

- 迁移 108:新增 cost_exceptions_archive(保留原 id 与时间字段,加 archived_at),
  热表补部分索引 idx_cost_exceptions_archivable
  (COALESCE(resolved_at, created_at)) WHERE status <> 'open',让每日任务不扫全表;
- cost-exception-archive-service:只归档 status <> 'open' 且超期的行,每批 1000 行,
  DELETE ... RETURNING + INSERT 在同一语句内完成,单批原子,不存在「删了没归档」;
- data-retention 每日任务接入;保留期走 COST_EXCEPTION_RETENTION_DAYS(默认 60);
- 新增 npm run cost-exceptions:archive(--dry-run / --days / --batch-size)。

为什么 open 行不归档:open 是待办队列,超期不等于已解决,归档等于把问题藏起来。

验证:
- 3 条 resolved 回拨到 90 天前 → 归档 3 条,热表 resolved 151,939 → 151,936;
- 1 条 open 回拨到 90 天前 → 仍在热表,未被归档;
- 归档表保留原 id 与时间,archived_at 记录归档时刻;
- 恢复测试数据后计数回到 151,939 / 108,314。
2026-10-25 12:09:20 +08:00
yml2213 fcd9b607d4 refactor(cost-center): 共享层按职责拆为四个模块
cost-center-shared.ts 804 行同时装枚举、行类型、映射、归一化,任何一处改动都会
让 8 个引用方重新编译。按职责拆开,本文件退化为统一出口(export *):

- cost-center-constants.ts    131  枚举、常量、SQL 片段
- cost-center-types.ts        220  行结构与 DTO 类型
- cost-center-mappers.ts      250  行映射与口径判断(含 CostPreview)
- cost-center-normalizers.ts  254  入参归一化与断言

同时消掉一个类型环:CostPreview 用 ReturnType<typeof mapProduct> 反推 mapper 的
返回类型,导致 types → mappers → types 互指;CostPreview 随 mapper 一起放进
mappers,依赖恢复单向。

出口保持向后兼容,8 个引用方无需改动;71 个导出逐一比对无缺失。
验证:typecheck / lint / 773 测试通过。
2026-10-25 12:02:36 +08:00
yml2213 ad1e1bc884 perf(db): 收入口径回填改为分批脚本
迁移 104 里对 order_items 的全表 UPDATE 实测 34.4 秒(375,447 行),
远超默认语句超时 15s,单事务迁移会拖住启动甚至直接失败。

- 104 只保留 DDL 与索引/约束,删除全表 UPDATE;
- 新增 scripts/backfill-revenue-basis.ts:按 id 分批、幂等、支持
  --dry-run / --batch-size / --max-batches(kebab 与 camel 两种写法);
- package.json 增加 revenue:backfill;
- migrate.ts 启动时做一次带索引计数,仍有 unknown 时打印告警并给出命令,
  不阻塞启动;
- 文档补充回填步骤与「不执行的后果」。

验证:
- 实测 37.5 万行全表更新 34.4s → 脚本按批执行,单批 5000 行;
- 功能验证:单条订单项置 unknown → 脚本回填 → 金额与 basis 恢复正确;
- 启动告警验证:保留 1 条 unknown 重启 → 日志出现告警;回填后计数归零;
- 全新库从 102 迁移到 107 仍成功(2s)。
2026-10-25 12:02:26 +08:00
yml2213 f10fefc303 refactor(cost-center): 拆分模板引导与成本解析服务
两个千行级服务按「变化原因」拆开,函数体逐字保留:

template-bootstrap-service.ts 1407 行 →
  - template-bootstrap-service.ts   745  preview/apply、映射计划、模板商品编码
  - affiliate-product-service.ts    199  自动发货商品同步与 SKU 回填
  - work-order-product-service.ts   467  接单平台商品回填与模板发单金额同步

cost-definition-service.ts 1382 行 →
  - cost-definition-service.ts      727  成本项/成本版本/成本异常 CRUD
  - cost-resolution-service.ts      680  预览、解析上下文、快照生成

依赖方向是单向的:CRUD 依赖解析层的 4 个校验/取值函数,解析层不反向依赖;
rebuildFactsForRange 因跨文件复用改为导出。

验证:9 个导出函数全部保留(无丢失),typecheck / lint / 773 测试通过。
2026-10-25 11:49:27 +08:00
yml2213 b033746172 refactor(admin): 成本中心路由按域拆分
cost-center.ts 从 898 行、48 个端点拆成 4 个子路由 + 54 行入口:

- cost-center-catalog  商品主数据、渠道映射、模板/自动发货/接单平台回填
- cost-center-cost     成本项、成本版本、快照、异常
- cost-center-manual   人工履约 SKU 配置
- cost-center-credits  客服平台积分钱包

入口只保留角色校验、overview/options 与挂载顺序;子路由路径仍是完整路径,
不需要再加前缀。

验证:
- 静态核对:拆分前后 (method, path) 集合完全一致,48 → 48;
- 运行时核对:遍历 Express router stack,仍注册 48 条 /cost-center 路由;
- 端点正文逐字保留,只有 import 与文件边界变化。
2026-10-25 11:49:21 +08:00
yml2213 26c70143db refactor(admin): 路由请求助手去重
finance / fund / cost-center 三个路由文件各自复制了 sessionOf / idOf / bodyOf,
语义相同写法不同。统一到 routes/admin/request-helpers.ts,路由文件只保留业务
差异(fund.ts 的 accountIdOf / expenseIdOf)。

无行为变更:typecheck、lint、773 个测试全部通过。
2026-10-25 11:38:19 +08:00
yml2213 0099597b0d docs: 迁移编号同步为 103–107 并校准分支状态
- 全量替换文档里的旧迁移编号:106→107、107→105、108/109/111→104、112→106、110→107;
- 删除 113/114 的残留引用(这两个编号从未落地);
- 分支状态校准为 `dev @ 465a9f65 + 迁移收敛`,本地库按「清 103–112 记录后重跑」对齐;
- 成本中心与履约模型 §一 重写迁移基线表,§八 改为迁移基线与本地库同步;
- 归档原地改造脚本的索引补登记。
2026-10-25 11:38:18 +08:00
yml2213 472769a977 refactor(db): 财务迁移收敛为 103–107
把 103–112 十个迁移收敛为五个,删除在「生产 102 → 当前」路径上的空操作与补丁:

- 108(下线人工支出登记)与 109(隔离历史快照主体)在生产库和重建库上都是空操作,
  口径注释并入 104;
- 111 是给 104 自身种子打的补丁,合并后 104 直接写入 active 0 元占位;
- 112 的 cost_exceptions.resolution_note 并入 104,退款表独立为 106;
- 106(备用金编号可读化)与 110(积分钱包)合并为 107(人工履约资金层);
- 107(履约方式列)并入 105,履约方式本就是销售事实的维度键。

配套调整:
- check-sql-guard 改为以 main 为基线校验迁移字节,删除 103–114 的永久豁免;
  未合并分支上的新迁移仍可重写,已发布迁移不可修改。
- 本地库原地改造脚本移入 docs/archive,禁止对新环境执行。

验证:清掉 schema_migrations 里 103–112 的记录后重跑,升级结果与全新构建的
schema 完全一致(pg_dump --schema-only 仅随机 token 不同),种子数据一致;
升级前后业务数据量不变(成本版本 713 → 712,差异来自删除占位草稿)。
2026-10-25 11:38:12 +08:00
yml2213 465a9f65dc Merge remote-tracking branch 'gitea-aliyun/main' into dev 2026-10-25 11:14:12 +08:00
yml2213 7824170d3c fix(finance): 支持生产快照升级并修复成本回填
修复生产 101 到 112 的迁移兼容问题;接单商品回填改为分批执行;修正未验收工单成本快照的 order_id/order_item_id 映射;更新本地生产快照数据基线。
2026-10-25 11:10:33 +08:00
yml2213 7fdef88ba6 perf(worker-hall): 优化百单大厅加载与渲染性能 2026-10-24 20:41:58 +08:00
yml2213 790de676c6 feat(admin): 收口人工履约入口并修复履约筛选 2026-10-24 17:42:07 +08:00
yml2213 faf56e567e feat(finance): P2 手动退款登记与成本异常闭环
- 迁移 112:order_refunds(订单项级退款,整单拆多条共享 batch_no,source/external_ref 预留平台 API)+ cost_exceptions.resolution_note
- 新服务 order-refund-service:整单/指定商品退款、可退金额校验、撤销、全额退完同步 pay_status
- 销售事实改为按有效退款记录冲减;无记录时仍兼容 pay_status=refunded 的历史全额退款
- 订单详情新增退款登记与退款记录表,商品明细显示收入/已退/可退
- 全额退款自动关闭该订单项成本异常并写处理备注;成本异常处理改为带备注弹窗
- 财务事件 UNION 接入退款记录,文档同步 P2 状态与 API
2026-10-24 17:18:51 +08:00
yml2213 a78cc1f984 feat(finance): P1 人工商品归一,按内部 SKU 生成 man 商品并回填
- 新服务 manual-product-normalization-service:skuNick → outSkuSn → sku_code 兜底,按内部 SKU 生成 man:<sku> 商品
- 订单项按 id 分批(2 万/批)回填,避免 15s 语句超时;同步补齐人工成本快照的商品维度
- 新增 POST /cost-center/manual-products/normalize(支持 dryRun/日期窗口),成本中心「标准商品」加「归一人工商品」按钮
- 每日 cost_finance_sync 接入最近 N 天的增量归一
- 渠道映射未归一队列增加人工单提示:人工单不能用平台 sku_code 建映射
- 文档同步:P1 标记完成,补充归一接口契约与销售事实重算结果
2026-10-24 16:54:55 +08:00
yml2213 e5122d116a feat(cost-center): 渠道映射改为诊断优先,新增未归一队列
- 顶部统计卡:标准商品 / 映射 / 未归一订单项 / 未归一 SKU 组
- 新增「未归一」队列:按来源+店铺+平台SKU+履约方式聚合,行内建映射并预填
- 目录表从 7 列精简到 4 列,匹配方式移入展开明细
- 回填订单项后自动把已归一的 product_mapping_missing 异常收口
- 新增 /cost-center/mappings/diagnostics 与 /mappings/unmapped,按履约方式拆分聚合避免全表扫描
2026-10-24 16:36:16 +08:00
yml2213 956ef5d695 refactor(cost-center): 精简成本中心,人工成本以 SKU 配置为唯一真源
- 删除「成本项目」「成本版本」「成本预览」三个 Tab:成本项只有 3 条系统内置,版本金额只是快照挂载点
- 新增只读「发单价格」面板,仅在接单平台来源显示,改价仍走接单模板后同步
- 成本预览改为弹窗,从成本异常行和订单详情「查成本」进入;人工单显示 SKU 配置成本并禁止生成快照
- 成本异常新增按原因聚合摘要接口,列表支持 reason/since 筛选,默认只看近 24 小时
- 迁移 111:把 sys_manual_service 的历史 ¥88 全局版本清零;预估同步与成本缺失判定排除 manual_actual
2026-10-24 16:07:25 +08:00
yml2213 9f2206430f style(frontend): 表格首列左对齐其余列居中 2026-10-24 15:49:51 +08:00
yml2213 8991263d25 fix(frontend): 修复百分比表格列宽与单元格居中 2026-10-24 15:13:05 +08:00
yml2213 ce8efa6bad style(frontend): 全项目表格统一百分比布局并居中 2026-10-24 14:49:23 +08:00
yml2213 a96229a106 feat(finance): 完善客服钱包与人工履约成本流水 2026-10-24 14:34:28 +08:00
yml2213 f0f8c92e67 fix(finance): 客服可读取自己的积分钱包 2026-10-24 13:47:53 +08:00
yml2213andClaude Opus 4.5 0a743f00b1 feat(finance): 客服端「我的备用金」改为「我的钱包」,四平台并列
客服原来只能看到备用金现金,平台积分藏在 Tab 里且是空的。
现在四个钱包并列展示:南航积分 / 乐玩积分 / ROCK 积分 / 备用金现金。

后端:
- 客服查询积分账户时自动补建三个空账户,保证四个钱包始终并列展示,
  不会出现「点了没反应」的空白卡片。

前端:
- 标题「我的备用金」→「我的钱包」,菜单同步改名。
- 顶部四张卡:三个积分平台各一张(显示积分余额 + 折合金额 + 换算率标签),
  备用金现金一张。余额为 0 时置灰。
- 四个钱包卡片与备用金账户解耦:没开通备用金账户的客服也能看到积分钱包,
  只是现金卡显示「尚未开通备用金账户」。
- Tab 调整为「积分流水 / 备用金流水 / 我的支出」,积分流水独立展示
  (平台、类型、变动、余额、折合金额、备注、时间)。
- 备用金账户详情卡(账户编号、责任主管、状态、登记支出、缴回备用金)
  仍然只在有账户时显示。

校验:后端 765 项 / 0 失败,前端 143 项全通过(含 lint、tsc -b、build)。

Co-Authored-By: Claude Opus 4.5 (1M context) <noreply@anthropic.com>
2026-10-24 13:36:38 +08:00
yml2213andClaude Opus 4.5 d07d88e25c feat(finance): 积分钱包操作 + 客服「确认履约」闭环
把「配置 → 待办 → 确认履约 → 扣额度 → 写成本快照」整条链路打通,
客服点一下就完成履约,不需要填复杂的东西。

积分钱包(P1.3):
- platform-credit-service.ts:充值 / 调整 / 消耗 / 流水查询。
- 三平台积分互不通用,每客服每平台一个账户;余额只能由流水产生,
  消耗不足直接拒绝(409),不允许负余额,与备用金口径一致。
- 换算率按平台:南航、乐玩 1 积分 = 1 分,ROCK 1 积分 = 1 元。
- 充值 / 调整只对 admin/operator/finance 开放;客服只能看自己的钱包。
- 备用金现金不在这里,走现有 fund_* 链路。

确认履约(P1.4):
- manual-fulfillment-service.ts:待办列表 + 确认履约。
- 待办口径:order_items.fulfillment_mode='manual' 且已配 fulfillment_config_id。
  人工单**不建 fulfillment_tasks**——那是自动发货通道的体系,人工单历来不走它
  (本地 102,955 个人工单的任务行数为 0)。
- 「已履约」判定:该订单项存在有效 manual_case 成本快照。
- 固定成本(消耗积分 > 0)→ 零输入;成本不固定(= 0)→ 只填实际成本金额。
- 确认时:积分平台扣积分钱包、备用金现金走 writeFundExpense,
  随后写 actual 成本快照(主体 = 积分流水 id 或备用金支出单 id)。
- 渠道与消耗积分永远提前配好,客服不选;重复履约直接拒绝。

前端:
- 新增「人工履约」页(客服菜单):待确认 / 已履约 / 全部,确认履约弹窗。
- 备用金页新增「平台积分」Tab(客服端与管理端各一份):
  余额卡片、积分流水、管理员充值与调整。

E2E 实测:配置 ROCK 100 积分 → 成本 ¥100.00(1 积分 = 1 元);充值 5000 积分
= ¥5000;确认履约后积分 5000 → 4900,成本快照 actual ¥100.00 写入;
重复履约被拒绝。测试数据已清理,登记表保留 357 条扫描结果供运营使用。

校验:后端 765 项 / 0 失败,前端 143 项全通过(含 tsc -b 与 build)。

Co-Authored-By: Claude Opus 4.5 (1M context) <noreply@anthropic.com>
2026-10-24 13:21:34 +08:00
yml2213andClaude Opus 4.5 4bcb4e6b57 feat(finance): 人工履约 SKU 配置清单 + 四钱包(南航/乐玩/ROCK积分 + 备用金现金)
客服人工履约有四个钱包,成本与渠道在后台配置好,客服确认履约时零输入。

口径(2026-10-24 确认):
- 四个钱包:南航积分 / 乐玩积分 / ROCK 积分 / 备用金现金。三平台积分互不通用,
  每客服每平台一个积分账户;现金复用现有 fund_accounts / fund_entries。
- 积分换算率按平台不同:南航 1 积分 = 1 分,乐玩 1 积分 = 1 分,
  ROCK 1 积分 = 1 元(100 分)。真源是履约档案 config_json.rechargeUnitPriceFen。
- 积分是货币,幸运币是商品;消耗积分与成本金额按换算率一一对应。
- 配置主键是**内部 SKU**(快手 spec_json.skuNick / 拼多多 spec_json.outSkuSn),
  不是商品标题(标题是引流)。同名 SKU 算同一商品,跨渠道共用一份配置。
- 配置链路没有匹配引擎、没有打分:扫描 → 配置 → 重新匹配。
  10 月口径下人工单 17,469 单 / 357 个内部 SKU,Top 50 覆盖 88% 单量。
  更早的老单没配置意义,不纳入统计口径。
- 消耗积分填 0 = 成本不固定,客服在确认履约时手填实际成本;
  渠道始终提前配好,客服不选。

迁移 110:
- manual_sku_registry:扫描到的内部 SKU 登记表(统计 + 配置状态)。
- manual_fulfillment_configs:内部 SKU → 渠道 + 消耗积分 + 成本模式。
- platform_credit_accounts / platform_credit_entries:三平台积分钱包与流水。
- order_items.fulfillment_config_id:订单项挂配置,重新匹配时回填。
- 4 条 manual_* 履约档案(manual_dispatch 执行器 + config_json 区分平台)。
  不复用 kuaishou_ct_assisted / kuaishou_feifei——那是已下线的历史自动发货通道。

性能:spec_json->>'skuNick' 无索引时扫描 2.4s / 回填 5.4s;
新增 idx_order_items_manual_internal_sku 表达式索引后回填降到 1.7s。

后端:manual-fulfillment-config-service.ts(扫描/清单/配置CRUD/重新匹配),
成本中心挂 7 个接口。
前端:成本中心新增「人工 SKU 配置」Tab(扫描、清单、配置弹窗、重新匹配)。

校验:后端 765 项 / 0 失败(含 check:sql 迁移护栏),前端 143 项全通过;
E2E 实测扫描 357 个 SKU、配置四平台换算正确、重新匹配回填 7,604 个订单项;
本地库迁移 110 执行后数据量与改造前一致。

Co-Authored-By: Claude Opus 4.5 (1M context) <noreply@anthropic.com>
2026-10-24 13:12:46 +08:00
yml2213andClaude Opus 4.5 fb679d76f6 refactor(finance): 人工成本收敛为「人工录单 → 扣备用金 → 写快照」
公司人工支出登记单与审批报销状态机整链下线,人工成本只留一条链路。

口径调整(2026-10-23 确认):
- 历史人工支出找不回来,直接放弃:不补录、不做样本校准、不做均价估算,
  只保证上线后的新单不丢。
- 人工成本逐单按实际金额,从客服备用金扣款,客服只能用本人账户;
  没有登记单、没有审批、没有报销,录入即计入毛利。

后端:
- 新增 services/finance/manual-order-cost-service.ts:扣备用金 + 写 actual
  成本快照,同一事务,余额不足直接拒绝不允许负余额。
- 成本快照主体从「人工支出登记单 id」改为「客服备用金支出单 id」
  (subject_type='manual_case',subject_id=manual_expenses.id)。
- 删除 services/finance/manual-expense-service.ts(1263 行)与
  routes/admin/finance.ts 下 /finance/manual-expenses* 全套接口。

前端:
- 删除 AdminManualExpensePage.tsx(778 行)与 /admin/manual-expenses 菜单页。
- ManualOrderCostModal 去掉「提交审核 / 立即计入成本」开关,录入即生效。
- 新增 services/admin/manual-order-cost.ts。

迁移:
- 106_manual_expense_records.sql → 106_fund_account_no_readable.sql,
  只保留备用金账户编号可读化。
- 108_drop_manual_expense_records.sql:删除 manual_expense_records 与
  manual_expense_events 两张表。
- 109_isolate_legacy_manual_snapshots.sql:把来源为旧登记链的历史孤儿快照
  subject_id 改为负数,与 manual_expenses.id 彻底隔离。

踩坑修复(E2E 实测发现):主体 id 换空间后与历史孤儿快照撞唯一索引
uq_cost_snapshots_active_subject_item,INSERT ... ON CONFLICT DO NOTHING
静默跳过,导致「钱从备用金扣了、成本快照却没写成」。修法是迁移 109 隔离
legacy 主体 + 后端快照写失败必须抛错回滚(409),杜绝账实不符。

文档:现行 5 篇 + README 基线校准为 dev @ 43f402cf + 迁移 103–109,
修正已删除的旧迁移号,删除「人工支出登记 + 审批 + 报销」口径,
已作废 DDL 草案移入 docs/archive/2026-10-23/。

校验:后端 765 项 / 0 失败(含 check:sql 迁移护栏),前端 143 项全通过;
E2E 实测两笔同订单项各自独立主体、余额扣减与快照金额一一对应;
本地库迁移 108/109 执行后数据量与改造前完全一致。

Co-Authored-By: Claude Opus 4.5 (1M context) <noreply@anthropic.com>
2026-10-24 11:31:29 +08:00
yml2213 43f402cf72 docs(finance): 现行财务文档收敛为 5 篇,履约口径只定义一次
原 9 篇 3,647 行,履约分类口径在总纲、模型文档、交接总结里重复三遍,
且仍留着"三块履约""按小时人工成本"等已作废表述。本次收敛为 5 篇
1,778 行:

- 财务与履约口径总纲-2026-10-23.md(300 行):唯一口径来源
  七条硬口径、三个正交维度、真实履约构成、成本模型规则、人工全覆盖、
  实施顺序、进度、验收 SQL、防回归清单
- 成本中心与履约模型.md(471 行):数据模型、迁移 103–107、履约回填、
  销售事实、本地库原地改造、索引与性能
- 成本中心API契约.md(270 行):字段替换总表、枚举、前后端模块边界
- 人工支出与备用金.md(218 行):人工支出登记字段/状态机/权限 +
  客服备用金台账
- 财务系统集成方案.md:复式总账层(未实施)

旧的 4 篇(成本中心与三块履约模型、人工支出登记落地方案、
客服备用金台账实施方案、财务履约改造交接总结)移入
docs/archive/2026-10-23/ 并加归档提示。

履约分类判定 SQL 只在总纲保留一份,其它文档改为链接。
2026-10-23 16:06:40 +08:00
yml2213 63ae32d18c refactor(finance): 成本模型与履约方式正交,拆分成本中心巨型文件
后端:
- 删除 services/admin/admin-cost-center-service.ts(4,248 行),拆为
  services/cost-center/ 下 5 个模块:
  cost-center-shared(类型/枚举/归一化/映射/costModelScopeSql)、
  cost-center-overview(总览与选项)、
  product-catalog(商品与渠道映射)、
  template-bootstrap(模板引导、自动发货同步、工单证据回填)、
  cost-definition(成本项/版本/异常/预览/快照)
- cost_items.carrier_type / cost_type 改为单一 cost_model;专属模型只对
  对应履约方式生效,通用模型对所有履约方式生效
- cost_snapshots / cost_exceptions 删除载体列;按履约方式筛异常改用
  IN 半连接(248k 异常下 EXISTS 逐行回表 2.7s -> 170ms)
- sales_daily_facts.carrier_type -> fulfillment_mode
- 人工支出按 cost_model 归类;履约方式只读 order_items.fulfillment_mode
- 移除 syncOpenCostExceptionCarrierTypes:异常表已无载体列可同步

前端:
- AdminCostCenterPage.tsx(2,887 行 -> 18 行转发),拆为
  pages/admin/cost-center/ 下 8 个 Panel + shared + CostCenterContext
- CostCarrierType 删除;新增 FulfillmentMode / ProductSource / CostModel
- 销售毛利页 carrierType -> fulfillmentMode

同步补两个索引:idx_order_items_fulfillment_id(异常半连接)、
idx_work_categories_name(商品目录分类 lateral join)。
2026-10-23 16:06:25 +08:00
yml2213 5c549a2dc5 refactor(db): 12 个财务迁移合并重写为 5 个
原 103–114 十二个迁移(1,087 行)分批落地,字段反复摇摆,且同一语义
(履约载体)在四张表各存一份,口径互相打架。本次整体重写为五个:

- 103_product_catalog:product_catalog 不再存载体,来源改由 canonical_sku
  前缀表达(aff: / tpl: / wo: / man:);channel_product_mappings 直接
  包含 match_type 与 platform_sku_name_key
- 104_cost_center:cost_items 用 cost_model 取代 cost_type + carrier_type;
  cost_snapshots / cost_exceptions 删除载体列;pricing_mode 精简为
  per_item / per_order / percent_of_revenue(删除按小时与按天固定)
- 105_sales_daily_facts:carrier_type 改名 fulfillment_mode
- 106_manual_expense_records:合并原 111 与 113
- 107_order_item_fulfillment_mode:履约事实三列

核心口径:order_items.fulfillment_mode 是履约方式唯一真源;成本模型
与履约方式正交;核销码不参与履约判定。

本地库已按新 schema 原地改造(scripts/rewrite-local-db-2026-10-23.sql),
316,585 项四项计数与总纲一致,NULL = 0。
2026-10-23 16:06:11 +08:00
yml2213 7557de6d60 docs: 校正分支提交数表述 2026-10-23 13:36:47 +08:00
yml2213 b629cd27d8 docs: 记录 P0 履约事实落地结果 2026-10-23 13:36:25 +08:00
yml2213 5d1ba11523 feat(finance): 统一履约事实并改造人工账单分类 2026-10-23 13:35:48 +08:00
yml2213 fb80cad695 docs: 统一财务与履约口径并新增总纲 2026-10-23 13:17:30 +08:00
yml2213 fac34c8420 feat(fund): 备用金账户编号改为带用户名的可读编号 2026-10-23 11:57:39 +08:00
yml2213 a7f60414a4 fix(finance): 客服只能使用自己的备用金账户 2026-10-23 11:44:04 +08:00
yml2213 2aeb789e20 feat(finance): 人工支出改为从客服备用金扣款 2026-10-23 11:31:47 +08:00
yml2213 cd9bb1419c fix(admin): 人工录单订单项只显示真实内部 SKU 2026-10-22 20:08:43 +08:00
yml2213 c38cd8ca2d feat(admin): 订单列表只展示平台判断 SKU 2026-10-22 19:55:13 +08:00
yml2213 74b62f3494 feat(finance): 订单页人工录单按单实际金额计入成本 2026-10-22 19:48:56 +08:00
yml2213 7c8832078f feat(finance): 接单模板发单金额落规则级成本版本
此前接单平台成本版本只有 sys_work_order_reward 的全局 0 元占位,662 个模板的发单金额从未进入 cost_versions。\n\n现在为 662 个模板各生成一条规则级版本:634 条固定发单金额 + 28 条按件单价;全局 0 元版本仅作“按工单实际结算”占位。成本版本页新增“用户实付均价”和“平均实发/项”,支持按模板名称/规则键搜索,按商品筛选也能命中规则版本。\n\n历史工单快照关联到对应模板版本;模板保存时自动同步单条成本版本;删除模板会先把历史版本脱钩停用,保留快照可追溯。\n\n新增迁移 112 覆盖索引,用户实付聚合从约 1.1s 降到约 150ms。
2026-10-22 19:29:53 +08:00
yml2213 72e1141c8a feat(finance): 补齐自动发货与接单平台成本和对账
自动发货:价格导入支持 --effective-from,把首次基线版本回填到历史起点;41,676 个订单项全部归一并生成采购成本快照,缺失 0。\n\n接单平台:新增按工单 product_rule_id 回填商品的接口与按钮,长尾项按 provider+shop_id+sku_code+normalized_sku_name 补建 wo: 商品和 sku_code_name 渠道映射;118,053 个订单项全部归一。\n\n成本:已验收工单按 reward_amount 写 actual;未验收但已确定报酬的工单写 estimated,验收后升级。全量 95,870 actual + 21,217 estimated,actual 与 reward 0 差异。\n\n剩余 966 条取消/零报酬工单保留在成本异常队列,不自动记 0;人工块未改动。\n\n实测自动发货与接单平台未归一收入均为 0;整体未归一 79.67% 降至 57.54%,全部来自人工块。
2026-10-22 18:59:53 +08:00
yml2213 54d2eb2f59 feat(finance): 自动发货订单项按上游 SKU 直接归一
自动发货只有 affiliate-dash 单一上游渠道,订单项直接按 fulfillment_tasks.context_json.skuCode 归一为 aff:<skuCode>,不写 channel_product_mappings。\n\n新增 /cost-center/affiliate-products/backfill:按 order_item_id 取最新任务 SKU 回填 canonical_product_id,只更新有变化的订单项,并自动重算受影响日期的销售事实;返回 updatedCount/skippedCount/remainingCount。\n\n自动发货 SKU 列表改为实时统计履约任务数与最近履约时间,不读会被价格导入覆盖的 attributes_json。\n\n本地实测 41,676 个订单项全部归一,自动发货未归一收入 5,089,712.26 元降至 0;整体未归一占比 79.67% 降至 60.47%。
2026-10-22 18:41:31 +08:00
yml2213 0889235870 feat(finance): 完成成本快照运行层、销售事实与人工支出登记
迁移 108-111:快照业务时间与预估转实际、销售事实表、系统成本项、公司人工支出登记。接单平台按工单实际 reward 入账;人工支出支持登记/审批/驳回/报销并写 actual 快照。新增销售毛利页、人工支出页与订单入口。
2026-10-22 16:41:03 +08:00
yml2213 15989af87c merge: 同步 main 最新到 dev(游戏ID查询修复) 2026-10-22 15:33:30 +08:00
yml2213 39cf14ed7a merge: 同步 main 最新到 dev(接单平台店铺筛选) 2026-10-22 15:30:38 +08:00
yml2213 f0c6960da7 merge: 合并 feat/cost-center-wip 到 dev(商品载体、成本中心、自动发货价格、分页与删除) 2026-10-22 15:19:59 +08:00
yml2213 aee0e4d1d2 docs: 同步财务进度、成本中心迁移号与 feat 分支状态 2026-10-22 15:19:53 +08:00
yml2213 78580c6165 feat(cost-center): 成本项编码改系统自动生成,补自动发货价格导入脚本
- 新建成本项目不再手填编码:后端按成本类型生成基础编码(auto_purchase /
  work_order_reward / manual_service / platform_fee / payment_fee /
  after_sales_loss / shipping_other / other_cost),重复时追加 _2、_3;
  接口显式传 code 时仍优先使用,兼容脚本导入
- 前端移除编码输入框,改为说明提示,创建成功提示展示生成的编码
- 新增 scripts/sync-affiliate-dash-prices.ts + scripts/data/affiliate-dash-prices.json:
  按上游 38 条自动发货价格补建 aff:<sku> 商品,并按 cost_amount(分)生成
  scope=product 的按件成本版本;价格变化时停用旧版本再插新版本
- 自动发货商品同步与价格导入的 attributes_json 改为合并,避免互相覆盖
2026-10-22 15:07:29 +08:00
yml2213 0f7d9d4fad feat(cost-center): 记住载体/Tab 选择,补配置引导并优化表格列宽
- 新增 usePersistedState:载体工作区与 Tab 存 localStorage(admin-cost-center:carrier / :tab),
  刷新后保持;存储值非法或 Tab 不适用于该载体时自动回退
- 成本项目增加配置说明与常用成本项模板(采购成本/打手报酬/人工成本/平台费/通道费/售后损失),
  成本项行新增「加版本」并按成本类型预选范围;成本项/版本弹窗补字段说明
- 商品与成本中心 8 张表统一 tableLayout=fixed,名称类列定宽 + 省略 + tooltip,
  表格最小宽度按列宽之和设置,避免名称列独占剩余宽度
2026-10-22 14:36:56 +08:00
yml2213 b520a078b0 feat(cost-center): 商品与成本按履约载体分区,补充分页与删除能力
- 新增迁移 107_product_catalog_carrier:product_catalog 增加 carrier_type,
  自动发货只认 fulfillment_tasks.executor_key='affiliate_dash' 的履约证据
  (28 个上游 SKU),接单模板商品统一归为 work_order(662 个)
- 页面按「全部 / 自动发货 / 接单平台 / 人工客服 / 共用成本」分区;
  自动发货只展示自动发货 SKU 列表与采购成本,不展示商品目录/渠道映射
- 新增「同步自动发货商品」接口与按钮,按 aff:<skuCode> 幂等补建
- 列表统一接入公共分页 buildAdminTablePagination,支持 10/20/50/100 每页条数
- 标准商品、自动发货 SKU、渠道映射、成本项目、成本版本支持删除,
  带引用保护(映射/版本/快照/订单/接单规则)与生效版本先停用约束
2026-10-22 14:05:34 +08:00
yml2213 8f3babdabe chore(db): 成本中心迁移重编号到 main 之后(103–106),check:sql 允许纯重编号 2026-10-22 12:42:59 +08:00
yml2213 3e73289e31 merge: 合并 main 到 feat/cost-center-wip(同步抖音券、设备认证与图标等最新改动) 2026-10-22 12:40:18 +08:00
yml2213 33b220ae10 fix(dcauth): order_site 白名单补充生产域名 ks.khhao.com 2026-10-22 10:04:05 +08:00
yml2213 d94a648c80 style(admin): 格式化后台用户管理页 2026-10-22 09:21:06 +08:00
yml2213 7a03abf8a1 feat(ui): 新增运营后台站点图标并统一登录页品牌标记
- 新增橙色渐变仪表盘图标(SVG / ICO / apple-touch-icon / 192 / 512)
- 登录页侧栏与移动端品牌标记改用同一 BrandMark
- index.html 补齐图标、theme-color 与页面描述,标题改为「运营后台管理中心」
2026-10-21 22:10:33 +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 cb916d7750 feat(dcauth): 新增常驻托盘客户端与版本显示
Windows 改为单实例托盘常驻,协议唤起只弹一个确认窗口;补充 macOS 后台守护进程
与客户端版本显示。
2026-10-21 20:46:25 +08:00
yml2213 040100f290 feat(dcauth): 新增后台手机号与设备认证登录
登录链路改为账号密码 + 短信验证码 + DCAuth 设备签名,并新增后台手机号绑定、
登录日志、设备绑定与重置接口。
2026-10-21 20:46:24 +08:00
yml2213 111bc76357 feat(cost-center): 成本中心与商品映射开发草案 (含文档与订单页调整 WIP) 2026-10-20 10:01:52 +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 584b6f52aa fix(work-order): 问题单处置存在活跃拼单份额时禁止取消/退回大厅/重开
生产实锤 WK26101503335487:客服对份额已提交的拼单母单走问题单处置-取消,
母单整单 cancelled 后份额验收/单人撤单全部被母单状态挡死,后台无补救入口。

- 抽出 getActiveWorkOrderShareCountWithClient 统一活跃份额统计口径
- resolveProblemWorkOrder 的 cancel/cancel_deduct/reopen 先过活跃份额防线
  (return_to_worker 不拦),返回结构改为 {order, failureReason}
- settleOverdueWorkOrder 复用同一统计函数,消除两份 COUNT 口径
- 服务层映射 409 work_order_problem_resolution_has_active_shares,
  文案引导客服先单独验收/单人撤单
2026-10-15 10:34:43 +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 4b081d88c5 feat(douyin-mashida): 抖音按 SKU 三层分类接入(对齐 91/快手)
- sku_code 恒为内部 SKU(不再被英文 sku 覆写);英文 sku / 引流标题分别落 snapshot
- 命中映射 → affiliate_dash;未命中不再兜底 manual_dispatch(无执行载体 = 待人工,不建任务)
- 抖音映射支持「常量表 + 后台 skuMapping 增量」,新增商品不必发版
- 载体唯一守卫:命中自动发货的订单项不再建工单
- 券 cert_link 与命中解耦(/h5 一律按订单号拼);券写入工单 material_json.douyinMashidaVoucher
- 新增/修正 16 例单测;后端全量 717 例 / 0 失败
2026-10-14 13:00:49 +08:00
yml2213 e8fbb28cf4 feat(claim): 人工履约单领取页只显示「人工处理中,请等待客服」
未命中 AFFILIATE_DASH_SKU_MAPPING 的抖音单显式回落 manual_dispatch(人工),这类单没有
自动发货通道(无 claim token、无绑定二维码),但卡券 cert_link 仍指向 /h5/<订单号> 领取页;
原页面会让买家「输 UID」,提交后没有任何自动发货动作,属于误导买家。

- 后端 kuaishou-cloud-claim-context.ts:新增 MANUAL_FULFILLMENT_MESSAGE 与
  resolveManualFulfillmentMessage(executorKey)(manual_dispatch → 等待话术,其它执行器空串);
  三个 payload builder 统一输出 manualFulfillment / manualFulfillmentMessage
- 前端 claim-snapshot.ts:输出 isManualFulfillment / manualFulfillmentMessage,
  progressText 同步显示等待话术
- 前端 ClaimPage.tsx:在「渠道已下线」之后、「输 UID」之前插入人工单卡片(只读 + 刷新状态),
  人工单不会自动轮询(无 expectedUid → 不安排下一次轮询)
- types/claim.ts:补齐两个可选字段;话术只在后端维护一份,前端只做兜底

验证:后端 npm run check(701 单测)与前端 npm run check(格式/lint/类型/143 单测/构建)全绿
2026-10-13 13:53:00 +08:00
yml2213 319e082254 fix(douyin-mashida): 领取消息只发给有自动发货领取单元的单,人工单不再假发货
根因:notifyBuyerClaimLink 对 `/h5` 形态的 claimLinkBase 走了一条捷径——只拼订单号
(`${base}/${orderNo}`)就发消息,跳过了「该订单项是否有自动发货领取单元」的校验。
领取 token 只由 affiliate_dash 执行器在建单时创建,未命中 AFFILIATE_DASH_SKU_MAPPING
回落 manual_dispatch 的人工单、以及自动准备失败的订单都没有 token,却照样收到
「您的订单已发货,请点击链接领取」(线上实测:非映射商品「套装-牛仔情诗」)。

- claim-link.ts:新增 buildDouyinMashidaBuyerClaimUrl(无自动领取单元一律返回空串 = 不发消息)
  与 isDouyinMashidaH5ClaimBase(/h5 形态判定收敛到一处)
- notify-service.ts:两种基址形态统一先 resolveOrderItemClaimLink 拿 taskId 作为「会自动发货」
  的证据,缺失则跳过并留痕「该订单项没有自动发货领取单元,跳过领取链接消息」
- claim-link.test.ts:补齐人工单不发消息、/h5 与 token 形态拼接、基址/订单号缺失等用例

验证:npm run check 全绿(prettier + SQL guard + eslint + tsc + 703 单测 + build)
2026-10-13 13:48:58 +08:00
yml2213 7e197c9413 fix(frontend): H5 领取前缀整段接管,/h5 裸链接不再跳后台登录
根因:公开路径判定原先只认「带参数」形态(isH5ClaimPath 只认 /h5/<orderNo>),
裸前缀 https://<域名>/h5(后台 claimLinkBase / certLink 的基址)判定不命中,
于是落回主站 HashRouter 被后台路由接管成
https://<域名>/h5/#/admin/dashboard 后台登录页。

- utils/claim-path.ts:isClaimPath / isH5ClaimPath 改为命名空间级判定(含裸前缀与多段路径),
  参数解析仍严格;新增 resolveH5ClaimOrderNoFromInput(纯订单号 / 整条链接 / 缺协议 /
  带后台残留 hash 都能取出订单号,只有前缀时返回空串)
- pages/claim/H5ClaimEntryPage.tsx:新增 /h5 领取入口页,买家输订单号或粘贴完整链接后
  跳 /h5/<订单号>,走与分享链接同一套领取流程
- App.tsx:H5ClaimApplication 接管 /h5 整段前缀(/h5 入口页、/h5/:orderNo 领取页、
  其它子路径回入口页);useClearStrayHash 抹掉历史残留的 #/admin/dashboard
- tests/claim-path.test.ts:补齐裸前缀、相邻前缀 /h5x、粘贴链接解析等回归用例

验证:npm run check 全绿(prettier + eslint + tsc + 143 单测 + vite build)
2026-10-13 13:42:06 +08:00
yml2213 5a73fb74a9 feat(douyin-mashida): 新增抖音券核销后台界面(列表/核销/冲正/同步/对账/作废)
抖音订单并非纯自动发货:内部 SKU 命中 AFFILIATE_DASH_SKU_MAPPING 才走自动通道,
未命中显式回落人工,且核销依赖买家自己到 /redeem 输订单号。此前核销侧在后台完全
不可见:自动核销是 void .catch(warn) 只落日志,cancelVerify 出网方法已就绪但没有入口。

照快手电子凭证的骨架做一套抖音版(两张表两套状态机,不复用):
- 券码状态、平台侧状态、同步错误全部可视化,支持只看同步失败
- 核销/冲正/重新同步/平台对账/重发券码/作废,每个写操作都带审计
- 券码列显示「核销实际会用的券码」(platform_cert_no 优先),平台改过名时额外标注
- 冲正先打平台 cancelVerify 再回退本地,避免本地与平台状态漂移
2026-10-12 19:45:06 +08:00
yml2213 0dd26da4ee merge: 合并 dev 到 main (工单号前缀 WK + 检索侧 O/0 容错) 2026-10-12 16:51:21 +08:00
yml2213 cb064d7cd5 fix(worker-platform): 工单号前缀改 WK 并在检索侧容错 O/0,彻底解决「按工单号搜不到」
## 线上定位到的真正根因

客服搜 `WO26101213031939` 搜不到,但用同单的平台号 `2628501763808879` 搜得到。
到生产库核对后确认:

- 库里真实值 `work_order_no = WO26101213031939`(hex 574f… = 字母 O),状态 pending_acceptance;
- 用字母 O 的 SQL 分支 → 1 行;用数字 0(`W026101213031939`)→ 0 行;
- 全库 127,906 单**全部**以 `WO` 开头、`W0` 开头 0 单、字母 `o` 只出现在第 2 位。

即:前缀里的字母 O 被输成数字 0(`WO` / `W0` 在界面字体里几乎无法区分),
落进通配符分支后必然为空 —— 与前面几轮的「筛选把单藏起来」是两个独立成因,
这也解释了为什么改筛选逻辑一直没解决。

## 修法

1. 生成端换前缀:generateWorkOrderNo 产出 `WK…`(K 与 0 不会看混),从源头消掉歧义;
2. 检索端同时兼容三种写法(历史 WO 号无需迁移):
   - isWorkOrderNoLookupKeyword 放宽为 `^W[oOkK0]…`;
   - 新增 buildWorkOrderNoKeywordVariants:W0→[W0, WO, WK]、WO→[WO, W0]、WK→[WK],
     SQL 分支对每个候选下发「等值 + 前缀」条件(仍是索引条件,不会退化成全表扫);
   - 前端 isExplicitOrderNoSearch 同步(否则面板不清理筛选、实时补丁护栏也不生效);
3. 顺手加一层归一化:NFKC(全角→半角)+ 去零宽字符,前后端同一口径
   (normalizeLookupKeyword / normalizeSearchText),覆盖「粘贴带不可见字符」这类同族问题;
4. 寄卖匹配弹窗的占位提示更新为 WK... / WO...。

## 验证

- 后端 npm run check 全绿:692 tests(689 pass / 3 skip),新增
  work-order-keyword-lookup.test.ts 直接断言 SQL 参数与「不得出现前置通配符」;
- 前端 npm run check 全绿:139 tests;
- 既有用例 worker-platform-repo.test.ts 的期望值同步为新形态(两条候选条件)。
2026-10-12 16:51:08 +08:00
yml2213 26780c9a4b merge: 合并 dev 到 main (基础镜像源可配置 BASE_REGISTRY) 2026-10-12 16:33:54 +08:00