Compare commits

..

2841 Commits

Author SHA1 Message Date
居居
2ea3f22349 feat(freight): 支持连续对话修正与部分报价计算 2026-10-29 14:48:55 +08:00
WuYongJie
60c933a14e fix(intake): reuse empty SKU placeholders and normalize imported dimensions
Preserve factory specification names; match equivalent size separators.

Task: sku-import-empty-placeholder-20261029-01a18026
Source-commit: afcede79a052c0d478866f71c59fd15f4c64d3ef
2026-10-29 14:43:43 +08:00
WuYongJie
f18a0f3f80 fix(store-account): support JD profiles in account editor 2026-10-29 14:36:55 +08:00
WuYongJie
ee410934ec fix(intake): update children furniture execution standard to GB 28007-2024 2026-10-29 13:52:20 +08:00
WuYongJie
b936295a7d feat(intake): preserve factory specification names in SKU imports 2026-10-29 11:40:50 +08:00
WuYongJie
9af1d9efda fix(limit-management): bind large style sets as a PostgreSQL array 2026-10-29 10:56:34 +08:00
WuYongJie
2be511f346 perf(freight): index batch barcode calculations with shared calculator
calculateByBarcodes previously called calculateByBarcode per item, re-reading rates, shipment share and courier rules and re-scanning the full rate catalogue for every barcode. Switch it to the shared createFreightCalculator snapshot: batch archive read via findProductArchiveSnapshots, courier rules fetched once per warehouse, rates and province shipment share fetched once, and the calculation loop yields to the event loop every 8ms like the archive page path. Per-item validation messages and result/error shapes are unchanged.
2026-10-29 10:46:16 +08:00
WuYongJie
2830836b92 test(freight): align release fixture with published region formula 2026-10-29 10:22:51 +08:00
WuYongJie
c169f9392c fix(limit-management): reuse locale comparator for archive sorting 2026-10-29 10:20:35 +08:00
居居
09128489fb feat(freight-maintenance): 完善批量测算与对话式比价 2026-10-29 10:13:38 +08:00
WuYongJie
4fd17c6677 fix(intake): convert WebP installation drawings and verify image delivery
Isolated release of 423d8bc7e663788d4bd2f3c7a41d6f3a1b1089d1.
2026-10-29 10:08:56 +08:00
WuYongJie
66db2a26f6 fix(freight): use framework-compatible event loop scheduling 2026-10-29 09:49:12 +08:00
WuYongJie
ec8cf4a819 feat(material-library): export all boards and normalize surface types 2026-10-29 09:19:36 +08:00
WuYongJie
416bcd5939 test(freight): preserve production formulas in scoped release 2026-10-28 20:18:20 +08:00
WuYongJie
e889d53cb6 fix(freight): index batch rates and yield the web event loop 2026-10-28 20:10:56 +08:00
WuYongJie
83a3138fe9 fix(intake): use configured vision model for reference cost estimates 2026-10-28 17:06:19 +08:00
居居
45387c9003 fix(limit-management): include freight in limit exports 2026-10-28 16:36:28 +08:00
WuYongJie
a9f2917c5b style(intake): align SKU toolbar actions by task 2026-10-28 16:16:29 +08:00
WuYongJie
77665c85b5 feat(intake): add product notification delivery history 2026-10-28 16:03:41 +08:00
居居
3f7710ef84 feat(limit-management): add regional and national freight averages 2026-10-28 15:56:14 +08:00
居居
281e52bb95 feat(supply-chain): 完善快递维护与AI运费比价 2026-10-28 15:56:14 +08:00
WuYongJie
2775b4ff83 feat(intake): import SKU templates with automatic coding 2026-10-28 14:36:34 +08:00
WuYongJie
e58f8ba96d fix(limit-management): restore mysql2 query call compatible with locked 3.15.3 typings
75adc3f7 imported QueryValues from mysql2/promise, which only exists in newer mysql2 typings than the package-lock version (3.15.3), breaking tsc on a clean install. Restore the previous equivalent call form (options object + values argument), preserving runtime behavior exactly.
2026-10-28 14:04:01 +08:00
居居
062666f530 feat(limit-management): consolidate limit and freight maintenance 2026-10-28 13:59:30 +08:00
居居
ce0aa8f387 fix(supply-chain): 修复运费配置权限并过滤过期费率 2026-10-28 13:59:30 +08:00
居居
5c5fef8b8e feat(supply-chain): 新增运费配置查询页面 2026-10-28 13:59:30 +08:00
WuYongJie
8f1cb2ac02 refactor(users): align product permissions with four navigation levels 2026-10-28 10:28:26 +08:00
WuYongJie
500da7be24 fix(market-analysis): add account and role access control 2026-10-28 09:42:24 +08:00
WuYongJie
1ddf0a34ce fix(intake): honor photo upload grants across products 2026-10-28 09:04:00 +08:00
居居
d3468b3756 feat(clearance): 排除福利品和空白分类 2026-10-27 17:25:40 +08:00
居居
11c91796e3 fix(clearance): 扣减虚拟云仓库存 2026-10-27 17:25:40 +08:00
WuYongJie
dcb61cc13f feat(intake): improve installation pushes and admin replacement 2026-10-27 17:13:37 +08:00
居居
6eb3ac0d53 feat(clearance): 简尚无库存时标记入库时间 2026-10-27 15:39:03 +08:00
居居
47fde040ee fix(clearance): 日销保留两位小数 2026-10-27 15:39:03 +08:00
居居
14b6157411 feat(clearance): 调整加权日销计算逻辑 2026-10-27 15:39:03 +08:00
居居
51e9ac3642 fix(clearance): 修正两清协议库存统计标记 2026-10-27 15:39:03 +08:00
居居
c7d1965df1 fix(clearance): 页面库存明细负数显示为零 2026-10-27 15:39:03 +08:00
居居
74613ce107 fix(clearance): 负库存参与最终库存汇总 2026-10-27 15:39:03 +08:00
居居
003b0e780c fix(clearance): 库存负数生成时归零 2026-10-27 15:39:03 +08:00
居居
638d8f591f fix(clearance): 生成时使用实时商品状态 2026-10-27 15:39:03 +08:00
WuYongJie
40debae10c fix(store-account): prevent accidental dismissal of create dialog 2026-10-27 15:24:13 +08:00
WuYongJie
cc208a400a fix(store-account): sync personnel profit centers and show save errors 2026-10-27 14:39:13 +08:00
WuYongJie
b026c8c840 fix(intake): 更新新增产品必填项 2026-10-27 14:05:21 +08:00
居居
6b85379ebb fix(clearance): 注册清货菜单权限节点
(cherry picked from commit 136350a02efa09bb4684da8cf6a6e442c198ed93)
2026-10-27 09:40:30 +08:00
居居
6d341c4196 fix(discontinuation): 将每日任务调整为十点三十分 2026-10-27 09:23:54 +08:00
WuYongJie
7fe6939daa Merge remote-tracking branch 'origin/main' of D:\ChanPing\furniture-3d-system-Wu into HEAD 2026-10-26 18:03:03 +08:00
WuYongJie
afb2d2b153 fix(clearance): restore applied migration content to keep checksum stable
5ea75eac added IF NOT EXISTS to migration 20261020090000 so dev databases can replay it. That migration is already applied on production with a recorded checksum, so main must keep the original file content or prisma migrate deploy fails with a checksum mismatch. The IF NOT EXISTS tweak is only needed in dev environments; production already has the table.
2026-10-26 17:55:47 +08:00
居居
af9381c2df feat(clearance): 接入采购入库与分利润中心发货统计
- 最近入库时间按采购单完结时间或预计完结时间取最新值
- 入库天数按清货池生成日展示整数
- 发货数量按任务利润中心匹配发货店铺后汇总
- 发货数据限定当前清货月份和有效确认出库单
2026-10-26 17:55:47 +08:00
居居
5375e21d92 feat(supply-chain): 上线清货管理与月度评分
- 新增清货池、任务审核确认、任务推送与复盘分数体系
- 新增优先级/固定任务/折扣限制/分数档位配置
- 新增清货数据迁移、同步脚本、权限和钉钉组合异常通知
- 补充清货页面、接口、服务、仓储及自动化测试
2026-10-26 17:55:47 +08:00
apple
64ab4a9065 fix(modular-processing): remove retired status rule column 2026-10-26 17:55:35 +08:00
WuYongJie
769e3d519c fix(intake): standardize category display and validate create prefill 2026-10-26 17:50:21 +08:00
WuYongJie
3ac409dd24 Merge remote-tracking branch 'origin/main' into release-discontinuation 2026-10-26 16:46:05 +08:00
WuYongJie
75ad922a5f fix(supply-chain): trigger ERP export dropdown on hover 2026-10-26 16:45:32 +08:00
apple
454ea9f564 feat(modular-processing): add modular processing order management 2026-10-26 16:41:43 +08:00
WuYongJie
3e7f2c4dd1 fix(supply-chain): click ERP goods controls inside their frame 2026-10-26 16:32:49 +08:00
WuYongJie
e0b99c7331 fix(supply-chain): recognize authenticated ERP with hidden goods menu 2026-10-26 16:24:26 +08:00
WuYongJie
5abc141b03 test(supply-chain): complete typed ERP page mocks 2026-10-26 16:24:26 +08:00
WuYongJie
17c10b0863 fix(intake): follow current product purchase owner permissions 2026-10-26 16:17:59 +08:00
WuYongJie
3e487baa0f fix(supply-chain): handle actual ERP agreement and QR login state 2026-10-26 16:07:07 +08:00
居居
5905923527 fix(deploy): 发布时安全写入聚水潭登录凭据 2026-10-26 16:06:28 +08:00
居居
c9cd224684 feat(supply-chain): 支持聚水潭登录态失效后自动登录 2026-10-26 16:06:28 +08:00
居居
5874d57f00 test(supply-chain): 锁定首次导出成功即停止重试 2026-10-26 16:06:28 +08:00
居居
b7cf1e25ae feat(supply-chain): 单次导出重试三次后再分批 2026-10-26 16:06:28 +08:00
WuYongJie
b65051cf8a fix(supply-chain): load Next env through native ESM default import 2026-10-26 14:32:32 +08:00
WuYongJie
f08ac565cd fix(supply-chain): continue historical monitoring on empty notice dates
(cherry picked from commit c137661049b733449be4b21983ed511d1e0773e5)
2026-10-26 14:19:43 +08:00
居居
bd44175734 fix(supply-chain): 加强每日同步异常与并发保护
(cherry picked from commit 2b985b657f1faa4d26fabbe746a47c0ad8d50923)
2026-10-26 14:19:43 +08:00
居居
4350394e81 fix(supply-chain): 恢复完整链接导出并阻止快照覆盖
(cherry picked from commit e4b15fa61527c5dbef753676274265f2b9e57d80)
2026-10-26 14:19:42 +08:00
居居
05df5da4e0 feat(supply-chain): 提供服务器每日调度与重跑保护
(cherry picked from commit 1eb6ebd387a84e2a57b51f9ed798fc67238e24bb)
2026-10-26 14:19:42 +08:00
WuYongJie
121e213fc1 fix(market-analysis): use unified workbench layout 2026-10-26 11:56:19 +08:00
WuYongJie
b152c821af fix(supply-chain): 恢复前置仓列设置拖拽排序 2026-10-26 11:34:51 +08:00
apple
bba34df1ab feat(supply-chain): 过滤下单表中的双零明细 2026-10-26 11:14:13 +08:00
apple
20b09c6b12 fix(supply-chain): 同步更新下单重量汇总 2026-10-26 11:14:13 +08:00
apple
35c226a783 feat(supply-chain): 新增前置仓明细列设置 2026-10-26 11:14:12 +08:00
apple
f232e1adab feat(supply-chain): 精简前置仓页面并新增下单重量 2026-10-26 11:14:12 +08:00
apple
733b98792e fix(supply-chain): 导入后立即覆盖并展示反馈数据 2026-10-26 11:14:12 +08:00
apple
572888f688 feat(supply-chain): 新增批量清空字段弹窗 2026-10-26 11:14:11 +08:00
apple
b6937fc9cf fix(supply-chain): 刷新数据时恢复最终下单量计算值 2026-10-26 11:14:11 +08:00
apple
461e6866d4 fix(supply-chain): 限制采购账号并锁定下单表最终下单量 2026-10-26 11:14:11 +08:00
apple
57c366b2a0 feat(supply-chain): 支持最终下单量人工编辑 2026-10-26 11:14:10 +08:00
apple
58d217cbc9 fix(supply-chain): 将前置仓下单表调整为进销存子页面 2026-10-26 11:14:10 +08:00
apple
ea76449f3c feat(supply-chain): 新增前置仓下单表快照推送 2026-10-26 11:14:10 +08:00
apple
d9f3b5ae1e feat(supply-chain): 支持前置仓批量筛选与反馈默认值 2026-10-26 11:14:09 +08:00
apple
5aa915f477 feat(supply-chain): 限制采购视角与导出字段 2026-10-26 11:14:09 +08:00
WuYongJie
6c874a67db feat(market-analysis): integrate and modularize selection dashboard 2026-10-26 10:59:31 +08:00
居居
3d5c23ace9 feat(supply-chain): 使用聚水潭最新替换规则快照 2026-10-26 09:50:02 +08:00
居居
2702a501f4 fix(supply-chain): 重复商品按最新PLM记录取剩余库存 2026-10-26 09:50:02 +08:00
居居
b57346a5ae feat(supply-chain): 接入聚水潭替换规则并展开条码 2026-10-26 09:50:02 +08:00
居居
ffabb6af88 fix(supply-chain): 替换规则支持同货号并展开条码 2026-10-26 09:50:02 +08:00
居居
5d541e92dc fix(supply-chain): 默认一次性查询聚水潭链接 2026-10-26 09:50:01 +08:00
居居
38d6642833 fix(supply-chain): 分批同步聚水潭链接并增强重试 2026-10-26 09:50:01 +08:00
居居
3b5560adb6 feat(supply-chain): 调整停产下架查看与负责人数据范围 2026-10-26 09:50:01 +08:00
居居
8781c40461 feat(supply-chain): 配置停产下架页签权限与运营数据范围 2026-10-26 09:50:01 +08:00
居居
00227f524d feat(supply-chain): 完成停产下架管理与监控 2026-10-26 09:50:01 +08:00
WuYongJie
c6310a9912 fix(product-archive): retire historical owner refresh and prioritize intake 2026-10-26 09:43:37 +08:00
apple
1b66b87d19 feat(production-stop-demands): 增加分页页大小并放宽原因分类权限 2026-10-24 15:03:08 +08:00
WuYongJie
ab408b90a0 feat(intake): 产品定厂仓库必填改为样包测量门禁
产品定厂确认不再强制仓库必填,允许空仓库确认并进入条码打印;样包测量确认前校验定厂仓库已填,未填提示「定厂仓库未填写」。产品开发待办规则口径同步调整。
2026-10-24 14:22:43 +08:00
WuYongJie
1646e6c4ee feat(supply-chain): 导出字段弹窗分组级全选/全不选切换 2026-10-24 14:03:13 +08:00
WuYongJie
5fc195d9fe feat(supply-chain): 产品全量档案导出字段勾选与图片URL导出修复 2026-10-24 13:40:30 +08:00
WuYongJie
c0e7a8d606 feat(supply-chain): add authenticated SPU return address push API 2026-10-24 13:30:41 +08:00
apple
5feb69feff feat(production-stop-demands): 完善流程校验、删除权限与分析视图 2026-10-24 13:14:38 +08:00
WuYongJie
83fb538d8c fix(product-archive): preserve existing images when sync source is empty 2026-10-24 11:31:23 +08:00
WuYongJie
26a6a28aa0 fix(supply-chain): include no-sales SPUs in all dropship issues
(cherry picked from commit 9d32b57e970905fdee7b3194ceb9df4894eb517e)
(cherry picked from commit ac885932d082a371ddb16d982a8acdea6dc28588)
2026-10-24 11:21:19 +08:00
WuYongJie
3d7c519b3c fix(intake): 产品开发待办节点确认回退批次级确认记录
待办规则此前只读产品级 documentWorkspaceConfirmations/documentWorkspaceApprovedAt,与产品开发明细页面读取批次级 skuBatchWorkflow* 的兜底口径不一致,历史数据两份记录不同步时(如 GBSFY-LRSF0091 样包测量批次级已确认、产品级为 false)会每天误报节点未完成。规则层 nodeApproved/approvedAt 增加批次级记录回退(任一批次已确认且带可解析确认时间即视为节点已确认,激活锚点同取批次级时间),取数组装传入批次级确认映射。生产真实数据对照:消除 14 条误报候选(样包测量 6、基础信息相关 8),恢复 8 条此前漏推的提醒。
2026-10-24 11:18:39 +08:00
WuYongJie
e5d4db5127 feat(ai-render): manage independent SPU SKU models and deletion 2026-10-24 10:25:24 +08:00
WuYongJie
005b8cf535 feat(navigation): rename AI tools and add Yiyidian link 2026-10-24 10:25:23 +08:00
WuYongJie
4f076c3b67 fix(distribution): separate daily job lock from archive writers 2026-10-24 10:05:48 +08:00
WuYongJie
6b221e0db4 perf(distribution): use indexed scope checks for dependency groups 2026-10-24 09:49:25 +08:00
WuYongJie
87cf63745d perf(distribution): publish incremental snapshots with durable checkpoints 2026-10-24 09:18:01 +08:00
WuYongJie
4b16861dd1 fix(diy): place dimension annotations outside the cabinet 2026-10-23 17:29:27 +08:00
WuYongJie
69599e1d60 feat(diy): allow barcode overrides with admin audit history 2026-10-23 16:03:32 +08:00
WuYongJie
3730b8cbd8 feat(mobile): simplify product and supply workspaces and unify navigation 2026-10-23 14:44:14 +08:00
WuYongJie
3c4706019c feat(diy): add brand barcode summaries and product dimensions 2026-10-23 14:08:55 +08:00
apple
fbcc5bf26a fix(supply-chain): 前置仓默认展示满足选品数据 2026-10-23 14:00:11 +08:00
WuYongJie
3b715e79b9 feat(production-stop-demands): 新增停产需求明细导出(全字段/自选字段)
- 导出使用停产需求管理的「下载」权限,未授权时不显示导出入口

- 支持全字段导出和点选字段导出当前筛选结果

- 新增导出接口与共享筛选参数解析,单次最多 20000 条
2026-10-23 11:51:24 +08:00
WuYongJie
530b9631fa fix(intake): keep date filter hints and values consistent across browser locales 2026-10-23 11:32:30 +08:00
WuYongJie
e1fba9a533 fix(intake): compact filters and unify workspace typography 2026-10-23 10:19:56 +08:00
WuYongJie
b04b196155 fix(print): stabilize Sofia carton label size and preview 2026-10-23 10:07:46 +08:00
WuYongJie
6c494c72e0 fix(supply-chain): complete front warehouse import reports and local layout 2026-10-23 09:31:42 +08:00
apple
a68d80e59e fix(supply-chain): 修复前置仓移仓与导入反馈 2026-10-23 09:31:42 +08:00
apple
902cb3613f feat(supply-chain): 新增前置仓进销存管理 2026-10-23 09:31:42 +08:00
WuYongJie
3321f0fcdd fix(supply-chain): refine distribution count display 2026-10-23 09:13:30 +08:00
WuYongJie
11c9ea93ba fix(workbench): unify account operation logs and show scoped records 2026-10-22 16:17:12 +08:00
WuYongJie
840ef0c319 feat(supply-chain): export all unselected supplier products
Isolated integration of c9370e6c53f64e0078d839d75f5a5ae7a0efb33a; approved task supplier-recommended-unselected-export-20261022.
2026-10-22 15:36:50 +08:00
WuYongJie
304514ee13 fix(supply-chain): remove excess inventory table bottom spacing 2026-10-22 14:10:32 +08:00
WuYongJie
2a94cebb14 perf(supply-chain): publish paged distribution summaries and online snapshot exports 2026-10-22 12:44:45 +08:00
WuYongJie
08e1a4764f test(workbench): align account tools with accepted product layout
(cherry picked from commit e665ed6c53543ca3447162ce1082f119dd680f46)
(cherry picked from commit b8792bd18857b0391c1fb6659f61cab59f2f2cc2)
2026-10-22 11:10:10 +08:00
WuYongJie
f5f27f44b4 feat(workbench): unify workspace navigation, surfaces and tab scrolling
(cherry picked from commit 8beecc67ea3df76bbb97cca01400bc67c5dbd08c)
(cherry picked from commit 65428ffa0df6a04d7997af46acd6600698e2dd28)
2026-10-22 11:03:33 +08:00
WuYongJie
dc6c3a74ee fix(product-archive): classify DF products as dropship without warehouse fallback 2026-10-22 10:42:47 +08:00
WuYongJie
142bafaa34 feat(intake): allow editing quality notification content 2026-10-22 09:09:21 +08:00
WuYongJie
bf6cdf8ef3 perf(product-archive): batch source reads and writes with resumable sync 2026-10-22 08:57:56 +08:00
WuYongJie
bc17baba42 fix(supply-chain): protect the 81 limit-file manual prices
Preserve manual prices only for the exact 586cf718 batch and the limit-file provenance marker. Keep other styles and sources on the existing upstream sync rules. Retain timestamp precision and explain manual precedence in sync exports. Add focused scope and preservation regression checks.
2026-10-21 18:22:16 +08:00
居居
975efc6dfb feat(supply-chain): 按限价文件更新大货和品牌商品限价
命中 81 个货号并统一人工指定为 49,组合关系与组合逻辑不变。
2026-10-21 18:18:43 +08:00
WuYongJie
a6f097da3d fix(supply-chain): restore original SJ0380 limit prices
Compensate the authorized 48186a9f / 925f5b2e price-49 release using its pre-release production snapshot. Restore 74 prices and approval sources, remove the added manual sync protection, retain original migration history and all later distribution features. No limit upload interface or API.
2026-10-21 18:01:53 +08:00
WuYongJie
7f190d3e77 feat(supply-chain): publish distribution snapshots, combo coverage and archive links 2026-10-21 17:21:59 +08:00
WuYongJie
925f5b2e6b fix(supply-chain): pin SJ0380 limit prices to 49
Apply the final authorized net change from 17a56eca and 48186a9f21fda9c0ddeb6baed2be3846ca0297ac. Includes the 74-code data migration and manual price sync protection. The temporary upload UI, API, schema and migration are excluded.
2026-10-21 17:07:05 +08:00
WuYongJie
772ee85cb4 fix(intake): include business roles in owner candidates
(cherry picked from commit 3c7d69250efe05da878cfbe7ae92c85b44fd8b50)
(cherry picked from commit eb560236a941f7a1426b638ccf17b149c1199716)
2026-10-21 16:10:19 +08:00
WuYongJie
7b142eb04a fix(supply-chain): normalize marketing sales barcode matching
Normalize case and surrounding spaces during source aggregation and archive matching, while preserving stored barcode values and existing daily sales calculations.
2026-10-21 15:19:01 +08:00
WuYongJie
599273a46e feat(home): default to centered brand and workspace capsules 2026-10-21 15:07:18 +08:00
WuYongJie
170ca52dac fix(supply-chain): retry transient product archive enrichment reads
Reconnect and retry failed source reads after 30 seconds, 2 minutes and 5 minutes. Keep the current batch cursor, avoid repeated archive and audit writes, wait for concurrent reads before cleanup, and preserve permanent errors and the existing failure notification.
2026-10-21 14:14:07 +08:00
WuYongJie
50c2d44571 fix(production-stop-demands): 恢复盘停建议配置主窗口操作反馈
- 查询、新增、删除、导出、导入的错误/成功提示恢复到配置主窗口

- 新增/删除/导出的成功提示改为刷新后写入,避免被查询清空

- 保留独立批量导入弹窗

(cherry picked from commit 6226a4076d6352323f6342754d539970e7282e24)
2026-10-21 11:50:22 +08:00
WuYongJie
244a9f8b85 fix(production-stop-demands): 修复盘停建议大批量导入并完善配置权限
- 盘停建议导入上限提升到 5MB / 20000 行,修复数千行被拒与静默截断

- 修复条码解析把「保留:」并入条码的问题,前后端口径一致

- 批量 upsert 改为单条 SQL,5867 行导入约 0.1 秒

- 批量导入界面改为独立弹窗

- 原因分类配置仅系统管理员可维护

(cherry picked from commit f314d7802090c18ccc2b94d2e23529a4ffb89bfa)
2026-10-21 11:50:21 +08:00
居居
1c1efebf27 fix(supply-chain): 清空停产退市商品限价
(cherry picked from commit 42b374801df5926aba8f302af518a538e2baede1)
2026-10-20 17:24:25 +08:00
WuYongJie
0509df6408 fix(installation-demo): synchronize clockwise screw and tool playback 2026-10-20 15:08:37 +08:00
居居
89eb66c6f6 feat(supply-chain): 限价筛选条件支持自定义 2026-10-20 14:51:20 +08:00
居居
7ce4b93706 feat(supply-chain): 限价顶部新增编码筛选 2026-10-20 14:51:20 +08:00
WuYongJie
75ba586ac8 feat(production-stop-demands): 完善档案字段、筛选、视图与通知中心联动
- 明细新增图片、产品标签、含大单近30日日销(条码/SKU 数值快照)

- 表头漏斗筛选(模糊/多选/数值比较/日期区间)、批量搜索、筛选设置

- 列设置拖动排序、快捷查询保存与套用

- 视图统计:日/周/月趋势、部门/需求人/原因/状态分布、饼图与明细下钻

- 通知中心:停产确认/待走流程/需求驳回通知、待办快照同步、钉钉全屏链接

- 新增迁移与历史数据回填脚本
2026-10-20 14:32:41 +08:00
居居
c34b72304d feat(supply-chain): 新增组合限价导出 2026-10-20 13:10:28 +08:00
居居
3cc85ed5d2 feat(supply-chain): 精简破价订单筛选条件 2026-10-20 13:10:28 +08:00
居居
8153f284e5 feat(supply-chain): 品牌页纳入三类国标前缀 2026-10-20 13:10:28 +08:00
WuYongJie
1614bd5e95 feat(diy): add text replacement and template URL import
Add image text detection/replacement with original preservation, compact result actions, and stored template imports. Keep image editor and template layout dialogs at consistent viewport sizes with internal scrolling.
2026-10-20 12:12:53 +08:00
WuYongJie
cadb917d90 feat(diy): add image adjustment, resizing and template layout tools 2026-10-20 09:43:40 +08:00
WuYongJie
09f36608de Use furniture Z-up axes in installation demo editing
Map X to width, Y to depth, and Z to height in numeric movement, drag and rotation controls, and feedback. Preserve existing Y-up model poses and saved data, and extract transform-anchor helpers.
2026-10-19 17:55:11 +08:00
WuYongJie
cba68a8cc7 fix(print): allow C-Lodop embedded preview frames 2026-10-19 17:07:48 +08:00
WuYongJie
414b86fd56 fix(home): open saved websites in a new tab 2026-10-19 16:46:53 +08:00
WuYongJie
df253a470d Optimize installation model preview and repair exploded layouts
Parse and cache OBJ geometry off the main thread, reuse the viewport, and adapt interaction rendering. Pull drawers out as complete groups, enforce panel and hardware clearance, and frame the applied layout. Add relative X/Y/Z movement in millimeters with existing persistence.
2026-10-19 16:44:30 +08:00
居居
4e949067d3 fix(supply-chain): 仅在品牌页按GBSFY归类 2026-10-19 16:22:34 +08:00
居居
8aa17b7a34 fix(supply-chain): 按GBSFY前缀纠正索菲亚品牌 2026-10-19 16:22:34 +08:00
居居
d5b5a60141 feat(supply-chain): 限价列表按负责人限价降序 2026-10-19 16:22:33 +08:00
WuYongJie
ef4e4e36ed feat(supply-chain): 商品库存快照落库并改读快照
- 新增 ProductInventorySnapshot / ProductInventorySnapshotRun 模型与正式迁移(条码×实际仓库)
- 同步任务复用现有库存/云仓/档案读取,临时表+事务原子替换,advisory lock 防重叠,失败保留上一份快照
- 新增 15 分钟 systemd timer 安装脚本与同步脚本(身份校验、凭据走环境变量)
- 列表/导出接口改读快照并展示 syncedAt,保留全零行过滤与导出字段选择
2026-10-19 15:40:57 +08:00
WuYongJie
5cf84a19c8 Merge latest main into accepted homepage release 2026-10-19 15:17:01 +08:00
WuYongJie
7210dd2111 fix(home): render homepage without the product sidebar 2026-10-19 15:12:29 +08:00
WuYongJie
071cd23ac9 feat(home): add fan carousel and double-click overview 2026-10-19 15:12:29 +08:00
居居
211aff2578 feat(supply-chain): 查询框直接支持批量筛选 2026-10-19 15:07:49 +08:00
居居
c691669101 feat(supply-chain): 限价筛选支持批量查询 2026-10-19 15:07:49 +08:00
居居
2b4eb17ec7 fix(supply-chain): 排除停产退市组合限价 2026-10-19 15:07:49 +08:00
居居
c62d951228 fix(supply-chain): 限价筛选候选值联动 2026-10-19 15:07:49 +08:00
居居
da4b77e6d6 style(supply-chain): 对齐表头列宽拖拽热区 2026-10-19 15:07:49 +08:00
居居
9360c553a2 fix(supply-chain): 修复组合单行表头遮挡明细 2026-10-19 15:07:49 +08:00
居居
a843b643ed fix(supply-chain): 放行组合运营负责人筛选 2026-10-19 15:07:49 +08:00
居居
05e1f94e46 fix(supply-chain): 修复组合限价筛选交互 2026-10-19 15:07:49 +08:00
居居
de26559e3e fix(supply-chain): 完善组合限价筛选与运营负责人 2026-10-19 15:07:49 +08:00
居居
c2f005712b feat(supply-chain): 新增组合限价页 2026-10-19 15:07:49 +08:00
居居
177d11dd47 style(supply-chain): 列名「非负责人限价(新)」改为「非负责人限价」
- 限价明细页与产品全量档案页的限价分组同步改名(导出列头随列定义一起生效)
2026-10-19 15:07:49 +08:00
居居
c104a029c9 fix(supply-chain): 限价明细「负责人限价」筛选补上候选值与筛选逻辑
- 负责人限价是 SupplyChainStyleLimitPrice.ownerLimitPrice 的派生列(按货号),此前 option 接口没有对应分支,
  下拉框显示「没有可选值」、选了也不生效
- 候选值:无其他筛选时取限价表的全部去重价格(两位小数,与界面一致);有筛选时只取当前结果集里货号的限价;
  无流程限价的商品提供「空值」选项
- 筛选:选中的价格先经 ROUND(price,2) 换回货号再按 sku 过滤;选中的价格无对应货号返回空结果;
  「空值」= 货号不在限价表里
- 补 3 条单测(价格→货号、无匹配、空值)
2026-10-19 15:07:49 +08:00
WuYongJie
ee983673d5 feat(supply-chain): 产品全量档案新增安装方式列(定厂优先+商品标签推导) 2026-10-19 12:06:41 +08:00
居居
132331733e feat(supply-chain): 限价流程同步改为服务器端可运行 + systemd 每日定时器
- sync-limit-workflows.mjs 路径参数化:新增 --out-dir/--initial-dir/--env-file/--skip-excel,
  环境变量 LIMIT_SYNC_OUT_DIR / LIMIT_SYNC_INITIAL_DIR / LIMIT_SYNC_ENV_FILE / LIMIT_SYNC_SKIP_EXCEL / LIMIT_SYNC_HISTORY_KEEP;
  默认目录改为应用根目录,不再写死 Mac 桌面
- 期初数据:优先显式目录,其次仓库自带 scripts/data/limit-sync/期初数据(首次部署可直接使用),
  服务器上业务更新只需把新的「限价期初数据*.xlsx」放进 shared 目录
- 写库安全:校验 DATABASE_URL、打印目标库(不含密码)、DELETE+INSERT 包在单事务里,
  失败自动回滚保留上一版限价/授权;Excel 导出失败不影响已提交的库数据
- 输出治理:输出目录自动创建;历史版本默认保留最近 20 份,避免服务器磁盘每天累积 30MB
- 新增 run-limit-workflow-sync-production.cjs:预检 shared/.env 变量(DATABASE_URL / JST_REPORT_DB_*)、
  打印库目标、透传参数、30 分钟硬超时、失败写 job 日志
- 新增 install-limit-workflow-sync-timer.sh:照 marketing-sales 样板安装 systemd service+timer,
  EnvironmentFile=$BASE/shared/.env,默认每天北京时间 07:30,输出/期初数据放 $BASE/shared/limit-workflow-sync
- 文档补充「正式站同步」章节;顺带修正 supply-chain-page-permissions 测试的菜单页数(新增限价管理后 27 页)
- 未改动 20261014/20261015 三个迁移目录(正式库已按现名建表)
2026-10-19 10:13:34 +08:00
WuYongJie
1b849b0209 feat(supply-chain): 新增商品库存管理(库存/云仓/筛选/导出/快捷查询)
- 页面:成品库存 × 实际仓库,按条码匹配产品档案与仓库配置
- 服务:聚水潭成品库存全量读取与缓存、筛选/排序/分页、小计、Excel 导出
- 云仓:链接服务器 OPENQUERY 汇总 order_able_qty,支持云仓明细下钻
- 接入:菜单、标签页、权限节点 productInventory
2026-10-19 09:54:57 +08:00
WuYongJie
d8b5006e44 feat(diy): add permanent deletion for saved schemes
(cherry picked from commit 2d1486b64c5f7dcd3a3a1e247ebe0c6d12e41d21)
2026-10-19 09:50:58 +08:00
居居
7fc43502fd fix(supply-chain): 修复限价管理合并入 mainline 后的 18 处类型错误(type-check 0 错误)
提交自身的错误:
- breach-orders/route.ts:filtersSchema 去掉重复的 platform / shopName 键(保留带长度上限的一份)
- supply-chain-breach-order.service.ts:BreachOrderListFilters 去掉重复声明的 platform / shopName
- BreachOrderTab.tsx:MultiFilterChip 的 field 联合类型补齐店铺款式编码/店铺商品编码/申诉原因/平台/店铺(与 filter-options 接口支持的字段一致)
- breach-orders/[id]/route.ts 与 breach-orders/route.ts:多结果分支的处理器统一声明为 handleRequest<unknown>(…): Promise<NextResponse<unknown>>,
  与既有 reference-image-estimate 路由同一写法,解决 ctx.user 可选态与返回形状不匹配

补齐缺失的配套改动:
- errors.ts:新增 ErrorCode.RESOURCE_NOT_FOUND(含 ERROR_MESSAGES 与 HTTP 404 映射)
- ProductArchiveFilters:补 materialLevel / inspectionReport 两个筛选项类型(查询逻辑此前已随功能提交)
- bom-costing-multimodal-gateway.ts:BomCostingMultimodalOperation 增加 IMAGE_EXTRACTION(破价申诉凭证识别用),
  breach-evidence.service 对可空的 providerConfig 加空值保护
- supply-chain-product-archive-select.ts:去掉重复的 sabcRating 选择项
- supply-chain-product-archive.repository.ts:storageType 候选值已在专用分支处理,去掉恒为 false 的重复判断

验证:git 干净检出后 npm run type-check(next typegen + tsc --noEmit)0 错误;
breach/supply-chain/permission 相关 230 个测试套件 1650 用例通过,失败 7 个套件均为 mainline 原有问题。
2026-10-19 09:23:04 +08:00
居居
62452b6343 fix(supply-chain): 检测报告按 SPU 文本里的编码匹配(平台 SPU 是自由文本)
- 平台 spu 形如「SJ0380书架 / 顾家穿衣镜DS5154 / BJ0056」,与档案 SPU 编码不一致;
  解析时从 spu 与报告标题里提取编码(SJ0380、GBGJ-SJZ0021、DS5154…)再匹配,纯编码仍原样收下
- 通用报告(「茶几通用」等)不产出 SPU;无文件记录继续忽略
- 单测补自由文本/标题提取用例
2026-10-19 09:23:04 +08:00
居居
2fde21f5da feat(supply-chain): 限价明细「是否有检测报告」接入素材平台检测报告接口
- 新增检测报告索引服务:GET {素材平台}/api/external/certificate-reports(X-API-Key),只认有报告文件的记录,按 SPU 汇总,进程内缓存 10 分钟
- 列取自 external 接口:限价页数据接口与「导出明细(含图片)」都带上 inspectionReport(有 / 无 / 空)
- 表头筛选接入:候选值「有 / 无」,筛选按报告 SPU 清单(接口未配置时不加条件、候选值为空)
- 配置:MATERIAL_LIBRARY_CERTIFICATE_REPORT_API_BASE_URL/API_KEY,不填复用 MATERIAL_LIBRARY_WHITE_BACKGROUND_API_*;未配置时该列显示为空
- 增补单测(解析/缓存/未配置/接口报错)与文档说明
2026-10-19 09:23:04 +08:00
居居
eca1d63842 feat(supply-chain): 限价管理的查看/导出/申诉权限统一由管理员配置
- 查看:页面与数据仍走「限价管理 · 可见」;导出改按「限价管理 · 下载」,申诉/审核/生成/导入改按「限价管理 · 操作」(原来是经营管理 edit)
- 服务端:下载中心 limit-export 任务与产品档案导出接口的 columnSet=limit 都按「限价管理 · 下载」鉴权
- 前端:无下载权限不展示导出入口(限价明细两个导出、破价订单导出当前筛选/乐捐明细);规则配置仍单独走 breachRuleConfig 节点
- 申诉保留兜底:破价单负责人本人即使无「操作」权限也可申诉本人订单,审核必须「操作」
- 测试:CustomTableView 补导出入口权限用例并修正过期的表头断言;文档补充权限章节
2026-10-19 09:23:04 +08:00
居居
f276164532 feat(supply-chain): 限价管理(限价明细 + 破价订单审核 + 规则配置 + 流程同步)
- 限价明细:抬头列/筛选/列宽/排序可配置,批量查询(商品编码/订单号/负责人等),筛选条件回显与一键清空
- 列取数口径:入库/代发按仓库名推导(含仓库配置覆盖)、产品标签取商品SABC打标、材质等级从「材质」识别 E0/E1/ENF
- 导出:导出明细 / 导出明细(含图片)改为全局下载中心后台生成,进度/取消/保存都在下载中心;页签名与文件名一致
- 破价订单审核:按天增量生成、链接级与订单级申诉、审核通过/驳回/二次申诉冲销乐捐、豁免(同价/活动)与证据凭证要求
- 规则配置页与权限:管理员开通后可编辑(权限节点 breachRuleConfig),无权限不可见
- 限价流程同步脚本:4 类钉钉限价流程 + 产品限价页面已确认限价 + 限价期初数据;流程/页面/期初优先级与「期初更新日期更新则以期初为准」
- 非负责人限价统一按最新口径派生(×1.05 且不低于 +10 元)
- 迁移:breach order review / breach rule config / limit flow sync
- 与 mainline 合并:保留字段权限(blockedFields)、负责人在职接管、限价目标 limitManagement 等新特性;
  规则配置权限并入新的权限节点结构,档案列去掉重复的 opsPriceLimit 列,相关测试断言按当前口径更新
2026-10-19 09:23:03 +08:00
WuYongJie
399fd8182d refactor(diy): simplify canvas controls and unify capsule styling
(cherry picked from commit 1429b870f08b34e37b02c3077053f17385e9738a)
2026-10-16 18:04:54 +08:00
WuYongJie
5c899b4705 revert: 限价管理两个提交(类型检查不通过,待功能线程修复后重新提交) 2026-10-16 17:55:56 +08:00
居居
fbe276d4f6 feat(supply-chain): 限价管理的查看/导出/申诉权限统一由管理员配置
- 查看:页面与数据仍走「限价管理 · 可见」;导出改按「限价管理 · 下载」,申诉/审核/生成/导入改按「限价管理 · 操作」(原来是经营管理 edit)
- 服务端:下载中心 limit-export 任务与产品档案导出接口的 columnSet=limit 都按「限价管理 · 下载」鉴权
- 前端:无下载权限不展示导出入口(限价明细两个导出、破价订单导出当前筛选/乐捐明细);规则配置仍单独走 breachRuleConfig 节点
- 申诉保留兜底:破价单负责人本人即使无「操作」权限也可申诉本人订单,审核必须「操作」
- 测试:CustomTableView 补导出入口权限用例并修正过期的表头断言;文档补充权限章节
2026-10-16 17:46:01 +08:00
居居
4be4bd1e09 feat(supply-chain): 限价管理(限价明细 + 破价订单审核 + 规则配置 + 流程同步)
- 限价明细:抬头列/筛选/列宽/排序可配置,批量查询(商品编码/订单号/负责人等),筛选条件回显与一键清空
- 列取数口径:入库/代发按仓库名推导(含仓库配置覆盖)、产品标签取商品SABC打标、材质等级从「材质」识别 E0/E1/ENF
- 导出:导出明细 / 导出明细(含图片)改为全局下载中心后台生成,进度/取消/保存都在下载中心;页签名与文件名一致
- 破价订单审核:按天增量生成、链接级与订单级申诉、审核通过/驳回/二次申诉冲销乐捐、豁免(同价/活动)与证据凭证要求
- 规则配置页与权限:管理员开通后可编辑(权限节点 breachRuleConfig),无权限不可见
- 限价流程同步脚本:4 类钉钉限价流程 + 产品限价页面已确认限价 + 限价期初数据;流程/页面/期初优先级与「期初更新日期更新则以期初为准」
- 非负责人限价统一按最新口径派生(×1.05 且不低于 +10 元)
- 迁移:breach order review / breach rule config / limit flow sync
- 与 mainline 合并:保留字段权限(blockedFields)、负责人在职接管、限价目标 limitManagement 等新特性;
  规则配置权限并入新的权限节点结构,档案列去掉重复的 opsPriceLimit 列,相关测试断言按当前口径更新
2026-10-16 17:46:01 +08:00
WuYongJie
bc8a4a15e9 feat(intake): notify quality inspectors and keep product photo uploads available 2026-10-16 17:28:45 +08:00
WuYongJie
77c91bd689 fix(supply-chain): 产品全量档案 DF 条码成本价改为统一取 jst_sku.cost_price
- enrichment 价格补丁不再区分 DF/非 DF:purchasePrice 与 costPrice 均取 rpt.jst_sku(purchase_price / cost_price)
- 删除 dws_sn_sales_full_info_di.goods_cost 取价链路(dws-sales-goods-cost.repository.ts 整删,DWS_SALES_GOODS_COST 来源常量移除)
- 单测与《供应链产品全量档案字段来源对照表》同步更新

预期效果(部署后下一轮同步):约 1874 条 DF 成本价由空变有值、约 230 条由 dws 金额口径变为 jst 单价口径、约 4516 条数值不变、0 条丢值。
2026-10-16 16:27:31 +08:00
WuYongJie
4bd48d8bc0 fix(diy): keep wood grain continuous and compact inspector
(cherry picked from commit 9af20a14b07f6da46691a7356c5fd1d08aa48887)
2026-10-16 14:47:27 +08:00
WuYongJie
d8e43e89ba fix(supply-chain): 仓库管理列表只取聚水潭仓库档案,档案历史名称不再补充展示 2026-10-16 14:00:51 +08:00
WuYongJie
12f04a2f96 feat(supply-chain): 产品全量档案移除「数据字典」占位入口
数据字典属内部开发口径,不对外暴露;「更多」菜单仅保留使用说明,清理占位提示状态;使用说明对应条目同步。
2026-10-16 13:56:48 +08:00
Codex
47eed75bca feat(supply-chain): 仓库管理模块全量源码(筛选排序/导入导出/属性覆盖/负责人对齐)
- 表头:除操作列外全列筛选下拉 + 升/降序排序(服务端排序,空值恒排末尾)
- 导入导出:模板含仓库名称/仓库属性/仓库归属/负责人/入库代发;导出支持字段勾选、跟随筛选与排序;导入弹窗(下载模板+选择文件)与进度面板,导入后可一键「仅查看导入的仓库」
- 仓库属性人工覆盖表(新增迁移 20261016103000)与单元格内联编辑
- 仓库负责人:工厂仓取产品档案采购,档案读取走只读库(回退主库)
- 菜单/页签/页面标题统一为「仓库管理」
2026-10-16 13:32:52 +08:00
WuYongJie
0ca4e4f8f1 fix(supply-chain): 产品全量档案导入入口补挂「操作」权限门控 2026-10-16 13:14:36 +08:00
WuYongJie
a54d32941f fix(diy): fit transparent basket patterns with five millimeter clearance 2026-10-16 12:31:53 +08:00
WuYongJie
559d025e6d feat(users): 字段权限集中配置——产品全量档案与店铺账号管理 2026-10-16 11:29:50 +08:00
居居
141ac4654c fix(supply-chain): 创建天数正好 90 天归入「创建60-90天」
- 新品区间分布边界修正:90 天整算 60-90 天,91 天起才是「创建90天以上」
- 读取已生成月份快照时按快照里的创建天数重算该字段,旧月份无需重新核算即可按新口径显示
2026-10-16 11:20:24 +08:00
WuYongJie
9465c98702 feat(product-archive): add batch code filters and compact sales controls 2026-10-15 17:51:10 +08:00
居居
11fd22f356 feat(supply-chain): 产品中心/采购中心不再依赖运营负责人
- 有设计师即计入产品中心、有采购即计入采购中心,即使该行没有运营负责人
- 运营中心仍只统计有运营负责人的行;「山东项目组」设计师/采购继续排除
- 快照增加口径版本号:读到旧口径快照时先按实时口径出数,并在后台自动重建该月快照(无需手动点保存配置)
2026-10-15 17:20:10 +08:00
居居
fc862c80fc feat(supply-chain): 各部门数据分类支持按事业部导出,事业部按一/二/三/四部排序
- 运营中心卡片「导出」改为先勾选事业部(默认全选;页面已筛事业部时默认只选它),只导出勾选范围
- 导出接口本已支持 department 过滤,前端补上多选入口(后端无需改动)
- 事业部/品类部名称排序改为按序号解析:事业一部→二部→三部→四部,品类九部→十部→十一部,不再按拼音乱序
- 新增部门名称排序工具与单测
2026-10-15 17:20:10 +08:00
WuYongJie
bcfd191657 fix(diy): add generated image deletion 2026-10-15 16:26:10 +08:00
WuYongJie
a9635163bc Merge shared mainline for Relay native image generation
Preserve the five existing production owner fixes and apply the reviewed AI task migration. Resolve DIY add/add conflicts only after checking that the feature baseline and production versions were identical. Merged AI tests and type-check passed; the retained production write guards were also checked in production mode.
2026-10-15 15:10:10 +08:00
WuYongJie
928a7b37a9 feat(ai): use durable Relay native image tasks
Persist image submissions with fixed idempotency keys, leased execution, provider
identity, reference snapshots and staged results. Integrate DIY, assisted assembly
and non-integrated white-background sessions without holding generation in a
browser request. Recover ambiguous submissions through owner-scoped reads and
stop a new eight-view batch when restoring an earlier request.

Add the NativeImageGenerationJob migration and a dedicated worker to both release
entry points. Protect job inputs/results from storage GC. Existing production
configuration and business data are not changed by this commit.

Validation: 256 focused Jest tests, isolated PostgreSQL migration/lease/transaction
checks (8), deployment guard tests (9), type-check, production build and desktop/
mobile browser component scenarios. Live native 2K reference-image request worked;
reusing its idempotency key returned the same task. Build uses local placeholders
for otherwise absent Drawing System configuration. Three unrelated material tests
also fail with the original mainline test file; they remain outside this change.

Architecture/visual/root-cause review: passed with warnings. Independent review
completed for the integration and shared input/storage paths; worker additionally
reviewed by the primary agent. Production merge/deployment requires authorization.
2026-10-15 14:55:46 +08:00
WuYongJie
8e14aa5fb1 feat(diy): add shared assets, uploaded styles and AI rendering 2026-10-15 11:36:32 +08:00
WuYongJie
dc2c86275e feat(diy): add shared assets, uploaded styles and AI rendering 2026-10-15 11:35:34 +08:00
WuYongJie
e0c324ce06 feat(supply-chain): 全量档案清除筛选移入筛选行并优化筛选交互(设置抽屉/回车确认)
- 「清除 N」从工具栏移到筛选行尾部(设置图标旁),收起细条保留清除入口
2026-10-15 11:11:47 +08:00
WuYongJie
67541f9208 feat(supply-chain): 全量档案清除筛选移入筛选行并优化筛选交互(设置抽屉/回车确认)
- 「清除 N」从工具栏移到筛选行尾部(设置图标旁),收起细条保留清除入口
2026-10-15 11:10:50 +08:00
WuYongJie
e2a237f43b fix(product-archive): 结算价公式修正为成本价÷0.9(模块化)
- 模块化分支由 ×0.9 改为 ÷0.9:聚水潭里模块化成本价按 9 折记,
  结算价需除以 0.9 还原(如成本 34.00 → 结算 37.78)
- 非模块化仍为成本价原样展示;先取整到分再除、四舍五入保留两位
- 同步更新测试期望值(76.20→84.67、123.45→137.17、85→94.44、34.00→37.78)
2026-10-15 09:18:26 +08:00
WuYongJie
d1496b0c11 fix(product-archive): 结算价公式修正为成本价÷0.9(模块化)
- 模块化分支由 ×0.9 改为 ÷0.9:聚水潭里模块化成本价按 9 折记,
  结算价需除以 0.9 还原(如成本 34.00 → 结算 37.78)
- 非模块化仍为成本价原样展示;先取整到分再除、四舍五入保留两位
- 同步更新测试期望值(76.20→84.67、123.45→137.17、85→94.44、34.00→37.78)
2026-10-15 09:17:57 +08:00
WuYongJie
46ca3bf786 feat(product-archive): 全量档案第二个成本价列改为结算价(模块化 ×0.9)
- 列与变更记录标签:成本价(新品)→ 结算价 / 结算价(新品),表头与导出同步生效
- 结算价在查询映射层实时计算:非模块化沿用成本价原样,模块化按 0.9 折
  (先取整到分再打折、四舍五入保留两位);模块化以商品标签含「模块化」判断,不落库
- 修复列设置合并时 localStorage 旧 label 覆盖默认列名的问题:内置列名
  一律以当前默认定义为准,改名对已保存列设置的用户才能生效
2026-10-15 08:48:16 +08:00
WuYongJie
67834358d2 fix(product-archive): allow trusted HTTPS image host on port 3333 2026-10-14 18:18:50 +08:00
WuYongJie
b6a326d996 fix(product-archive): allow trusted HTTPS image host on port 3333 2026-10-14 18:14:47 +08:00
WuYongJie
ec6067facc feat(supply-chain): 产品全量档案新增独立图文使用说明页(更多菜单新标签页打开)
- 新增 /product-archive-guide 独立路由:模块树目录(产品全量档案 → 1.1~1.10),无系统壳,登录+productArchive 查看权限
2026-10-14 17:45:18 +08:00
WuYongJie
e57f95c489 feat(supply-chain): 产品全量档案新增独立图文使用说明页(更多菜单新标签页打开)
- 新增 /product-archive-guide 独立路由:模块树目录(产品全量档案 → 1.1~1.10),无系统壳,登录+productArchive 查看权限
2026-10-14 17:43:53 +08:00
WuYongJie
9ef800001f feat(product-archive): 全量档案第二个成本价列改为结算价(模块化 ×0.9)
- 列与变更记录标签:成本价(新品)→ 结算价 / 结算价(新品),表头与导出同步生效
- 结算价在查询映射层实时计算:非模块化沿用成本价原样,模块化按 0.9 折
  (先取整到分再打折、四舍五入保留两位);模块化以商品标签含「模块化」判断,不落库
- 修复列设置合并时 localStorage 旧 label 覆盖默认列名的问题:内置列名
  一律以当前默认定义为准,改名对已保存列设置的用户才能生效
2026-10-14 17:09:30 +08:00
WuYongJie
89fbe9231b feat(supply-chain): 全量档案运营负责人切换 js_sku_info_manage.sku_manager 数据源 2026-10-14 14:28:05 +08:00
WuYongJie
289926294d Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/local-3001-integration 2026-10-14 14:27:19 +08:00
WuYongJie
9492eba22d feat(supply-chain): 全量档案运营负责人切换 js_sku_info_manage.sku_manager 数据源 2026-10-14 14:27:02 +08:00
居居
bfe3073aa1 feat(supply-chain): 人员信息总负责人支持多中心总监并列显示(如 子龙/妙玉) 2026-10-14 13:03:08 +08:00
WuYongJie
49ec0be34f feat(supply-chain): 日销任务改为每日 08:00 单次执行,未到数即告警并支持手动补跑 2026-10-14 12:28:45 +08:00
WuYongJie
1e0a8decc1 feat(supply-chain): 日销任务改为每日 08:00 单次执行,未到数即告警并支持手动补跑 2026-10-14 12:28:40 +08:00
WuYongJie
2c4128e065 feat(supply-chain): 日销任务改为每日 08:00 单次执行,未到数即告警并支持手动补跑 2026-10-14 12:28:24 +08:00
WuYongJie
d5443e9f77 fix(product-archive): display complete column headers and preserve readable widths 2026-10-14 11:56:12 +08:00
WuYongJie
bcb0636625 fix(product-archive): display complete column headers and preserve readable widths 2026-10-14 11:55:26 +08:00
WuYongJie
822df76e19 fix(product-archive): display complete column headers and preserve readable widths 2026-10-14 11:55:00 +08:00
WuYongJie
fc50035d65 feat(owners): include growth center employees in business owner options 2026-10-14 11:35:12 +08:00
WuYongJie
b0d531e1af feat(owners): include growth center employees in business owner options 2026-10-14 11:33:58 +08:00
WuYongJie
bf2f114762 feat(owners): include growth center employees in business owner options 2026-10-14 11:33:22 +08:00
WuYongJie
a917949a5e fix(supply-chain): 基础同步回退视图不存在的 item_type 列引用并修复失败告警原因为空 2026-10-14 10:39:04 +08:00
WuYongJie
cf11c4251e fix(supply-chain): 基础同步回退视图不存在的 item_type 列引用并修复失败告警原因为空 2026-10-14 10:38:37 +08:00
WuYongJie
7f1358aa68 fix(supply-chain): 基础同步回退视图不存在的 item_type 列引用并修复失败告警原因为空 2026-10-14 10:38:22 +08:00
WuYongJie
83f0fbee86 feat(supply-chain): 产品全量档案负责人治理与聚水潭式表头改造 2026-10-14 10:08:08 +08:00
WuYongJie
f84abed356 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/local-3001-integration
# Conflicts:
#	furniture-3d-system/src/server/repositories/__tests__/product-archive-owner-workflow.repository.test.ts
#	furniture-3d-system/src/server/repositories/product-archive-owner-workflow.repository.ts
2026-10-14 10:04:53 +08:00
WuYongJie
42d2447481 feat(supply-chain): 产品全量档案负责人治理与聚水潭式表头改造 2026-10-14 10:04:06 +08:00
WuYongJie
fb1c74ae67 fix(diy): retry transient storage failures during catalog import 2026-10-14 09:20:36 +08:00
WuYongJie
20eaf3589c fix(diy): retry transient storage failures during catalog import 2026-10-14 09:20:00 +08:00
WuYongJie
ce66215764 fix(storage): handle Qiniu CommonJS SDK default export for DIY import 2026-10-14 08:59:22 +08:00
WuYongJie
d76d024d62 fix(storage): handle Qiniu CommonJS SDK default export for DIY import 2026-10-14 08:58:44 +08:00
WuYongJie
56548a731e Merge production main into shared baseline for SABC release
Preserve SABC storage-type and batch-search changes, logistics column resizing, and production-main employee-hours and route export compatibility. Verified 54 focused tests and type-check; no pending production migrations.
2026-10-13 16:24:15 +08:00
居居
252624708d Merge branch 'codex/xuxiake-sabc-sync-20260929' into codex/xuxiake-mainline 2026-10-13 10:15:47 +08:00
居居
7ae628f9f1 feat(supply-chain): SABC 明细新增「入库/代发」列,货号/商品编码/款式编码支持空格批量查询
- 明细与导出新增「入库/代发」,取值来源产品全量档案 storageType(入仓/代发)
- 已生成月份仍读快照;旧快照缺该字段时按 barcode 从档案补齐,无需重新核算
- 货号/商品编码/款式编码额外支持空格/制表符分隔(可直接粘贴 Excel 多行或多列),服务端最多取 200 个
- 入库/代发取值兼容字典值(INBOUND/DROPSHIP)与中文直填(入仓/入库/代发),产品全量档案列表同步显示
2026-10-13 10:15:34 +08:00
WuYongJie
f8b8959347 feat(diy): persist shared catalog and assets in database and object storage 2026-10-13 09:56:39 +08:00
WuYongJie
409e35e232 feat(diy): persist shared catalog and assets in database and object storage 2026-10-13 09:55:55 +08:00
WuYongJie
462fee6a46 feat(diy): persist shared catalog and assets in database and object storage 2026-10-13 09:48:09 +08:00
WuYongJie
ee033a1e08 feat(diy): add cabinet workbench with saved versions and BOM exports 2026-10-12 18:16:14 +08:00
WuYongJie
12de551328 feat(diy): add cabinet workbench with saved versions and BOM exports 2026-10-12 18:14:15 +08:00
WuYongJie
96f0373e79 feat(diy): add cabinet workbench with saved versions and BOM exports 2026-10-12 18:12:57 +08:00
WuYongJie
ecd11db3af docs: 删除已废弃的苹果风格视觉标准(验收只按白曜石工坊口径) 2026-10-12 14:05:53 +08:00
WuYongJie
b45b584871 chore(installation-demo): 移除安装演示V2试验链并保留成对迁移历史 2026-10-12 14:05:53 +08:00
WuYongJie
b237bbed7c feat(supply-chain): 产品全量档案定时任务通知——业绩快照每日简报与四任务失败兜底 2026-10-12 14:05:53 +08:00
WuYongJie
b8093f899e feat(supply-chain): 产品全量档案定时任务通知——业绩快照每日简报与四任务失败兜底 2026-10-12 14:05:18 +08:00
WuYongJie
f7811468f7 feat(supply-chain): 产品全量档案定时任务通知——业绩快照每日简报与四任务失败兜底 2026-10-12 14:05:06 +08:00
WuYongJie
92cd5f2903 docs: 删除已废弃的苹果风格视觉标准(验收只按白曜石工坊口径) 2026-10-12 11:08:32 +08:00
WuYongJie
e612936125 chore(installation-demo): 移除安装演示V2试验链并保留成对迁移历史 2026-10-12 11:08:32 +08:00
WuYongJie
c9c62f4b22 docs: 删除已废弃的苹果风格视觉标准(验收只按白曜石工坊口径) 2026-10-12 11:08:10 +08:00
WuYongJie
1dbcc0d84c chore(installation-demo): 移除安装演示V2试验链并保留成对迁移历史 2026-10-12 11:08:10 +08:00
WuYongJie
1de64d05f6 fix(supply-chain): keep daily sales notification fields in separate paragraphs 2026-10-12 10:47:05 +08:00
WuYongJie
553c237268 fix(supply-chain): keep daily sales notification fields in separate paragraphs 2026-10-12 10:47:05 +08:00
WuYongJie
5ca82d1033 fix(supply-chain): keep daily sales notification fields in separate paragraphs 2026-10-12 10:46:24 +08:00
WuYongJie
00dd1b2f89 fix(supply-chain): 日销通知改为纯文字
去掉新通知的卡片按钮字段,正文采用普通换行。
保留旧投递的幂等重试载荷,公共通知链路不变。
验证:相关25项测试、ESLint及diff检查通过。
2026-10-12 10:26:40 +08:00
WuYongJie
75dd248046 fix(supply-chain): 日销通知改为纯文字
去掉新通知的卡片按钮字段,正文采用普通换行。
保留旧投递的幂等重试载荷,公共通知链路不变。
验证:相关25项测试、ESLint及diff检查通过。
2026-10-12 10:26:40 +08:00
WuYongJie
81cffc020a fix(supply-chain): 日销通知改为纯文字
去掉新通知的卡片按钮字段,正文采用普通换行。
保留旧投递的幂等重试载荷,公共通知链路不变。
验证:相关25项测试、ESLint及diff检查通过。
2026-10-12 10:25:34 +08:00
WuYongJie
34e8426bb6 feat(store-account): display exact source platforms and filter before pagination 2026-10-12 10:24:17 +08:00
WuYongJie
a7554bebad feat(store-account): display exact source platforms and filter before pagination 2026-10-12 10:23:48 +08:00
WuYongJie
520706df0d feat(store-account): display exact source platforms and filter before pagination 2026-10-12 10:22:51 +08:00
WuYongJie
6a94f1b215 fix(supply-chain): 日销08点同步、失败补跑及管理员结果通知
北京时间08:00开始,未到数或失败按固定10分钟刻度补跑,成功当天停止源查询。
保留重启/PG失败记录和到数时间,正式任务定向徐霞客发送去重结果通知。
验证:31项定向测试、ESLint、全仓TypeScript、脚本语法与本地真实运行通过。
2026-10-12 10:05:44 +08:00
WuYongJie
9ca2f2d382 fix(supply-chain): 日销08点同步、失败补跑及管理员结果通知
北京时间08:00开始,未到数或失败按固定10分钟刻度补跑,成功当天停止源查询。
保留重启/PG失败记录和到数时间,正式任务定向徐霞客发送去重结果通知。
验证:31项定向测试、ESLint、全仓TypeScript、脚本语法与本地真实运行通过。
2026-10-12 10:04:42 +08:00
WuYongJie
c4f3063e88 fix(supply-chain): 日销08点同步、失败补跑及管理员结果通知
北京时间08:00开始,未到数或失败按固定10分钟刻度补跑,成功当天停止源查询。
保留重启/PG失败记录和到数时间,正式任务定向徐霞客发送去重结果通知。
验证:31项定向测试、ESLint、全仓TypeScript、脚本语法与本地真实运行通过。
2026-10-12 10:03:13 +08:00
WuYongJie
cb91d7a42f fix(intake): calibrate Gujia 2026 certificate print positions 2026-10-12 09:22:56 +08:00
WuYongJie
6edf13e974 fix(intake): calibrate Gujia 2026 certificate print positions 2026-10-12 09:22:20 +08:00
WuYongJie
4885e8fc75 fix(intake): calibrate Gujia 2026 certificate print positions 2026-10-12 09:21:26 +08:00
WuYongJie
ffa4290c4a feat(product-archive): 全量档案图片自动增量索引、换图失效与失败重试 2026-10-12 08:51:02 +08:00
WuYongJie
7b9fd60f6e feat(product-archive): 全量档案图片自动增量索引、换图失效与失败重试 2026-10-12 08:50:39 +08:00
WuYongJie
0ca07f8c5e feat(product-archive): 全量档案图片自动增量索引、换图失效与失败重试 2026-10-12 08:49:10 +08:00
WuYongJie
393f149c05 feat(product-archive): sync approved owner workflows daily 2026-10-10 16:14:24 +08:00
WuYongJie
50062a4c3d feat(product-archive): sync approved owner workflows daily 2026-10-10 16:13:53 +08:00
WuYongJie
9c2f5f6085 feat(product-archive): sync approved owner workflows daily 2026-10-10 16:13:25 +08:00
WuYongJie
abcffc424a fix(supply-chain): isolate permissions for every menu page 2026-10-10 14:31:38 +08:00
WuYongJie
9b7ab9e532 fix(supply-chain): isolate permissions for every menu page 2026-10-10 14:31:21 +08:00
apple
729eaf492d fix(logistics-arrival): 换货单不再把已换货的 0 数量行算成条码
内部单号 9627695(赔偿换货单)看板显示 X00005、SJ0061100N430V01 两个条码,
但聚水潭里 SJ0061100N430V01 是 qty=0 / item_status=Replaced 的"已换货"原始行,
实际发出的是手工换货替换品 X00005,看板应只显示 X00005。

- 条码匹配时跳过 qty<=0 的明细行(已换货/取消的原始行不产生条码);
- 明细查询补上 oi.qty 字段;
- 补单测:换货单只保留实际发出条码、0/负数行不计入,并把原有两条条码用例补上 qty。

实测(10-01~10-09 窗口):jst_OrderItem 2436 行、jst_qmcust_orderlist_item 3007 行
数量为 0 且全部是 Replaced;过滤后没有任何订单会变成无条码。

注:快照里的条码是生成时固化的,快照区间需重跑当天批次后才会更新。
任务名:物流到货签收时长-deepseek
2026-10-10 14:18:40 +08:00
apple
253c803be6 fix(logistics-arrival): 换货单不再把已换货的 0 数量行算成条码
内部单号 9627695(赔偿换货单)看板显示 X00005、SJ0061100N430V01 两个条码,
但聚水潭里 SJ0061100N430V01 是 qty=0 / item_status=Replaced 的"已换货"原始行,
实际发出的是手工换货替换品 X00005,看板应只显示 X00005。

- 条码匹配时跳过 qty<=0 的明细行(已换货/取消的原始行不产生条码);
- 明细查询补上 oi.qty 字段;
- 补单测:换货单只保留实际发出条码、0/负数行不计入,并把原有两条条码用例补上 qty。

实测(10-01~10-09 窗口):jst_OrderItem 2436 行、jst_qmcust_orderlist_item 3007 行
数量为 0 且全部是 Replaced;过滤后没有任何订单会变成无条码。

注:快照里的条码是生成时固化的,快照区间需重跑当天批次后才会更新。
任务名:物流到货签收时长-deepseek
2026-10-10 13:48:03 +08:00
apple
91eeb6402a fix(docs): 恢复生产部署说明中被覆盖的 SABC 章节并重放停产收口章节
上一次提交把 deploy 文档替换成旧版本,误删了「商品 SABC 月度核算」等主线内容;本次恢复主线版本并仅追加「停产需求确认超时收口」章节。
2026-10-10 13:21:18 +08:00
apple
f2480700ee chore(production-stop-demands): 补齐超时自动收口定时器与部署说明
- 新增 scripts/install-production-stop-confirmation-finalize-timer.sh:systemd service+timer,每 10 分钟检查一次(Asia/Shanghai),失败 5 分钟后自动重试,日志进 journald
- 生产部署入口说明新增「停产需求确认超时收口」章节(脚本、systemd 名称、调度、日志、启用步骤与授权边界)
2026-10-10 13:21:18 +08:00
apple
158995b71b fix(docs): 恢复生产部署说明中被覆盖的 SABC 章节并重放停产收口章节
上一次提交把 deploy 文档替换成旧版本,误删了「商品 SABC 月度核算」等主线内容;本次恢复主线版本并仅追加「停产需求确认超时收口」章节。
2026-10-10 12:14:38 +08:00
apple
26ebec4c40 chore(production-stop-demands): 补齐超时自动收口定时器与部署说明
- 新增 scripts/install-production-stop-confirmation-finalize-timer.sh:systemd service+timer,每 10 分钟检查一次(Asia/Shanghai),失败 5 分钟后自动重试,日志进 journald
- 生产部署入口说明新增「停产需求确认超时收口」章节(脚本、systemd 名称、调度、日志、启用步骤与授权边界)
2026-10-10 12:13:28 +08:00
apple
8270ae9b38 Merge branch 'codex/wuyongjie-production-stop-demands' into codex/xuxiake-mainline
feat(production-stop-demands): 停产需求管理全流程(提单→需求确认→走停产流程→流程结果同步)
- 按条码拆单提交;批量同意/不同意、批量走流程、批量修改停产原因
- 需求确认人与流程负责人分开配置(批量新增/删除/查询)
- 确认截止时间(15:00/16:00 规则)与超时默认同意;任一人不同意即整单驳回
- PLM 流程结果同步(拒绝→需求驳回;商品停产/退市→流程审批通过)与盘停建议配置

(cherry picked from commit 33555c7f6bc0881452a074b06c89b6caf911ca1d)
2026-10-10 11:41:51 +08:00
apple
33555c7f6b Merge branch 'codex/wuyongjie-production-stop-demands' into codex/xuxiake-mainline
feat(production-stop-demands): 停产需求管理全流程(提单→需求确认→走停产流程→流程结果同步)
- 按条码拆单提交;批量同意/不同意、批量走流程、批量修改停产原因
- 需求确认人与流程负责人分开配置(批量新增/删除/查询)
- 确认截止时间(15:00/16:00 规则)与超时默认同意;任一人不同意即整单驳回
- PLM 流程结果同步(拒绝→需求驳回;商品停产/退市→流程审批通过)与盘停建议配置
2026-10-10 11:28:48 +08:00
apple
737926de7e feat(production-stop-demands): 停产需求管理全流程(提单/确认/走流程/结果同步)
- 按条码拆单提交,支持批量同意/不同意、批量走流程、批量修改停产原因
- 需求确认人与流程负责人分别配置,支持批量新增/删除/查询
- 确认截止时间规则(当天15:00前当天16:00截止,否则次日16:00)与超时默认同意;任一人不同意即整单驳回
- PLM 流程结果同步:流程拒绝→需求驳回;商品状态变为停产/退市→流程审批通过
- 盘停建议配置:批量导入(模板/文件/三种模式)、表格式维护、提单按条码自动带出
- 列表支持列宽拖拽、表头排序、日期区间/需求人/采购筛选、需求状态流程步骤条与批量操作
2026-10-10 11:17:18 +08:00
WuYongJie
de7518bb16 feat(product-archive): use marketing daily sales with daily sync and arrival monitor
Aggregate rpt.op_marketingDailySales by complete SKU and calculate weighted purchase sales.
Persist daily source fingerprints, skip unchanged archive writes and prevent old enrichment from overwriting sales.
Run daily at 09:30 Beijing time and observe source arrival every 10 minutes on 2026-10-11 08:00-09:30.
2026-10-10 11:09:51 +08:00
WuYongJie
cd8d5f2799 feat(product-archive): use marketing daily sales with daily sync and arrival monitor
Aggregate rpt.op_marketingDailySales by complete SKU and calculate weighted purchase sales.
Persist daily source fingerprints, skip unchanged archive writes and prevent old enrichment from overwriting sales.
Run daily at 09:30 Beijing time and observe source arrival every 10 minutes on 2026-10-11 08:00-09:30.
2026-10-10 11:08:29 +08:00
WuYongJie
a944d5eecd feat(product-archive): use marketing daily sales with daily sync and arrival monitor
Aggregate rpt.op_marketingDailySales by complete SKU and calculate weighted purchase sales.
Persist daily source fingerprints, skip unchanged archive writes and prevent old enrichment from overwriting sales.
Run daily at 09:30 Beijing time and observe source arrival every 10 minutes on 2026-10-11 08:00-09:30.
2026-10-10 11:07:23 +08:00
apple
ce3658a33d fix(logistics-arrival): 条码不再并集同一物流单号上的其它订单
内部单号 9627695(线上单 351207604012)实际只有 X00005 和 SJ0061100N430V01
两项,看板却显示 4 个条码——多出来的 SJ0061100N430V01-5/-7 属于同一物流单号
75627908174893 上的另一张订单 9593499(合并发货)。

根因:buildBarcodeMap 把"物流单号"键的条码无条件并入,而一个物流单号可能合并
发货多张订单,于是一张单会串上别单的条码;同一张单还会因为分页里恰好有没有
那张邻单而显示不同条码。

- 条码匹配规则抽成纯函数 matchLogisticsArrivalSigningDurationBarcodes:
  先用内部单号/线上订单号/物流单号+付款时间匹配本单自己的明细,
  物流单号只在精确键一个都匹配不到时兜底;
- 补单测覆盖"合并发货不串单"和"精确键为空才兜底且去重"。

注:快照里的条码是生成时固化的,快照区间需重跑当天批次后才会更新。
任务名:物流到货签收时长-deepseek
2026-10-10 10:52:42 +08:00
apple
3679c247bf feat(logistics-arrival): 订单明细支持拖动调整各字段列宽
20 个字段原来只有统一的 max-width: 260px + 省略号,长文本(备注/留言/地址)
看不全也没法放大。现在每列表头右侧都有拖拽把手:

- 拖动调整列宽(72~640px),键盘 ←/→ 微调,双击把手恢复该列默认宽度;
- 列宽写进 localStorage,刷新/切页后保留;改过列宽后表头出现"恢复默认列宽"按钮;
- colgroup + table-layout: fixed,列宽所见即所得,表格总宽随列宽变化并横向滚动。

任务名:物流到货签收时长-deepseek
2026-10-10 10:12:36 +08:00
apple
7e1ca79dc0 fix(logistics-arrival): 变体条码回退基准条码,商品维度不再是未填写
聚水潭同款不同规格会给基准条码加 `-数字`(如 SJ0061100N430V01-5),
产品档案只登记基准条码,于是变体条码查不到档案、供应商/采购为空;
而订单明细行是按整单所有明细聚合的,只要单里有基准条码就有值——
同一张订单因此出现"商品维度未填写、订单明细有值"。

- 档案查询两步走:先精确匹配,未命中再用基准条码(去掉结尾 `-数字`)兜底;
- 基准条码可能与本批一起查询,两轮结果都参与回退;
- 新增 logisticsArrivalSigningDurationArchiveFallbackBarcodes 纯函数 + 单测。

注:快照里的 productItems 是生成时固化的,需重跑当天批次后分析看板才会带上兜底结果。
任务名:物流到货签收时长-deepseek
2026-10-10 10:06:10 +08:00
apple
f665a6d271 fix(logistics-arrival): 快照覆盖判定改用实际数据覆盖,修当天少算/导出缺单
看板/导出的快照覆盖判定此前只比对批次"声明窗口"(windowTo = 跑批当天),
但每天 03:00/05:30 跑批时当天还没签收完,数据只到跑批那一刻,于是把
"还没签收完的当天"误判成已覆盖:10-08 生成的批次只会算到 10-07(约 3.8 万),
当天签收的单(用户清单里那 5,820 条)整批缺失。

- 快照批次新增 dataThrough(该批真实最大签收时间),覆盖上限改为
  min(windowTo - 1, dataThrough 当天):跑批当天永远不完整,只信任到前一天;
  数据源本身滞后时再由 dataThrough 收窄。
- 生成任务逐片记录 dataThrough 并写回批次;旧批次缺值时按 windowTo - 1 兜底。
- 定时器默认 05:30 → 03:00;文档同步更新覆盖规则。
- migration: LogisticsArrivalSigningDurationSnapshotRun.dataThrough。

任务名:物流到货签收时长-deepseek

(cherry picked from commit eca96b3067d73bc01e54f72dd11dd7253b324b97)
2026-10-09 18:01:32 +08:00
居居
1a53aa31a3 feat(supply-chain): 各部门数据分类去掉「数据权限例外」,权限统一以用户管理后台为准
- 配置弹窗移除「数据权限例外」输入项,保存时不再写入该字段(旧配置下次保存即清空)
- 数据范围不再按人收窄:部门负责人/总负责人/普通账号一律看全部利润中心
- 设置结构、settings 接口返回与权限节点描述同步移除 dataScopeGrants
2026-10-09 17:47:34 +08:00
apple
eca96b3067 fix(logistics-arrival): 快照覆盖判定改用实际数据覆盖,修当天少算/导出缺单
看板/导出的快照覆盖判定此前只比对批次"声明窗口"(windowTo = 跑批当天),
但每天 03:00/05:30 跑批时当天还没签收完,数据只到跑批那一刻,于是把
"还没签收完的当天"误判成已覆盖:10-08 生成的批次只会算到 10-07(约 3.8 万),
当天签收的单(用户清单里那 5,820 条)整批缺失。

- 快照批次新增 dataThrough(该批真实最大签收时间),覆盖上限改为
  min(windowTo - 1, dataThrough 当天):跑批当天永远不完整,只信任到前一天;
  数据源本身滞后时再由 dataThrough 收窄。
- 生成任务逐片记录 dataThrough 并写回批次;旧批次缺值时按 windowTo - 1 兜底。
- 定时器默认 05:30 → 03:00;文档同步更新覆盖规则。
- migration: LogisticsArrivalSigningDurationSnapshotRun.dataThrough。

任务名:物流到货签收时长-deepseek
2026-10-09 17:16:12 +08:00
居居
1779d8a697 style(supply-chain): 各部门数据分类配置弹窗标题去掉「(仅管理员)」 2026-10-09 16:42:01 +08:00
居居
e95748dee9 Merge branch 'codex/xuxiake-sabc-sync-20260929' into codex/xuxiake-mainline 2026-10-09 16:30:54 +08:00
居居
530a35711f style(supply-chain): 各部门数据分类配置弹窗标题去掉「(仅管理员)」 2026-10-09 16:30:45 +08:00
居居
810f3a8a07 Merge branch 'codex/xuxiake-sabc-sync-20260929' into codex/xuxiake-mainline 2026-10-09 16:19:12 +08:00
居居
c4c370df2c feat(supply-chain): 各部门数据分类去掉「数据权限例外」,权限统一以用户管理后台为准
- 配置弹窗移除「数据权限例外」输入项,保存时不再写入该字段(旧配置下次保存即清空)
- 数据范围不再按人收窄:部门负责人/总负责人/普通账号一律看全部利润中心
- 设置结构、settings 接口返回与权限节点描述同步移除 dataScopeGrants
2026-10-09 16:18:56 +08:00
codex
1187a7ec56 fix(logistics-arrival): 经营维度点选不再自动滚到 09 订单明细
之前任何下钻(经营对象维度点选、经营总览异常卡片)都会把 09 订单明细 scrollIntoView 到视口顶部,
点平台/店铺等维度时会直接把页面翻到底,用户没法接着看其他维度、还得手动往上拉。

- 自动滚动只保留给经营总览的异常卡片(卡片写着"点击看明细")
- 经营对象维度(平台/店铺/发货仓/物流/采购/供应商/商品/签收日期)点选不再抢滚动条,
  下钻筛选照常生效,09 明细在原位置更新
- 测试拆成两条:维度点选不滚动(且仍触发 /drilldown)、异常卡片仍滚动到明细锚点
2026-10-09 15:48:00 +08:00
codex
e4fa4a2880 fix(logistics-arrival): 下钻/导出接口接受按字段分组的排除关键词
下钻和导出两个接口的 zod schema 还停留在 string | array,
而前端下发的是新的分组对象 { 字段: [词] },
于是点商品/店铺等对象下钻时 09 明细直接报"下钻条件格式不正确"(导出报"导出筛选条件格式不正确")。

- 两个接口的 excludeKeywords 都接受 对象 / `字段:词,词` 字符串 / 旧平铺数组
- 字符串形态改用 parseExcludeKeywords 解析(老链接按配置归位),不会把字段名当成关键词
- 新增两条路由单测:分组对象下钻/导出、字符串与平铺兼容、非法形态返回 400
2026-10-09 15:47:59 +08:00
居居
9b7d691ca9 feat(supply-chain): 商品SABC打标查看/导出默认全员开放,限制只在用户管理后台收紧
- 新增「商品SABC打标 · 商品明细」权限节点:默认全员可见+可导出,后台可单独关闭
- 侧边栏「商品SABC打标」入口与明细/经营总览/趋势/筛选候选/导出接口统一改用该节点
- 「各部门数据分类」同样默认全员可见+导出(移除商品企划的默认下载限制)
- 默认开放节点支持「显式关闭优先」:后台关掉某业务类型或个人例外,立即生效
- 「执行核算」仍由「商品SABC打标 · 执行核算」节点控制,未授权账号返回 403
- 补充权限映射与默认开放语义单测
2026-10-09 15:00:37 +08:00
居居
8d08176ab2 feat(supply-chain): 数据权限支持「全部」授权写法 2026-10-09 15:00:37 +08:00
居居
18eaaa4c5f feat(supply-chain): 部门数据配置改为独立权限节点,默认商品企划与管理员可用 2026-10-09 15:00:37 +08:00
居居
fb1d25b373 feat(supply-chain): 各部门数据分类改为独立权限模块(可见/下载分开配置) 2026-10-09 15:00:37 +08:00
居居
b2ca7bf7f1 Merge branch 'codex/xuxiake-sabc-sync-20260929' into codex/xuxiake-mainline 2026-10-09 14:42:53 +08:00
居居
e2254c50f5 feat(supply-chain): 各部门数据分类默认全员可见全部利润中心,只有「数据权限例外」才收窄
- 未配置数据权限例外时不再默认只看本人:所有人可见全部利润中心数据(查看/导出仍由用户管理后台节点控制,默认开放)
- 移除按人员信息表(部门负责人/总负责人)自动收窄到本事业部的旧规则
- 显式配置了范围的人仍按配置收窄,写「全部/所有/*/全公司」表示不受限
- 配置弹窗提示语同步说明「默认不需要配置」
2026-10-09 14:42:38 +08:00
居居
93293258d1 Merge branch 'codex/xuxiake-sabc-sync-20260929' into codex/xuxiake-mainline 2026-10-09 14:24:53 +08:00
居居
f86d27cae1 feat(supply-chain): 商品SABC打标查看/导出默认全员开放,限制只在用户管理后台收紧
- 新增「商品SABC打标 · 商品明细」权限节点:默认全员可见+可导出,后台可单独关闭
- 侧边栏「商品SABC打标」入口与明细/经营总览/趋势/筛选候选/导出接口统一改用该节点
- 「各部门数据分类」同样默认全员可见+导出(移除商品企划的默认下载限制)
- 默认开放节点支持「显式关闭优先」:后台关掉某业务类型或个人例外,立即生效
- 「执行核算」仍由「商品SABC打标 · 执行核算」节点控制,未授权账号返回 403
- 补充权限映射与默认开放语义单测
2026-10-09 14:24:45 +08:00
codex
d727421dca fix(logistics-arrival): 经营维度点选不再自动滚到 09 订单明细
之前任何下钻(经营对象维度点选、经营总览异常卡片)都会把 09 订单明细 scrollIntoView 到视口顶部,
点平台/店铺等维度时会直接把页面翻到底,用户没法接着看其他维度、还得手动往上拉。

- 自动滚动只保留给经营总览的异常卡片(卡片写着"点击看明细")
- 经营对象维度(平台/店铺/发货仓/物流/采购/供应商/商品/签收日期)点选不再抢滚动条,
  下钻筛选照常生效,09 明细在原位置更新
- 测试拆成两条:维度点选不滚动(且仍触发 /drilldown)、异常卡片仍滚动到明细锚点
2026-10-09 14:21:08 +08:00
居居
f94c86bcc8 Merge branch 'codex/xuxiake-sabc-sync-20260929' into codex/xuxiake-mainline
部门数据分类数据权限支持「全部」授权写法。
2026-10-09 13:08:24 +08:00
居居
5fdeea9a51 feat(supply-chain): 数据权限支持「全部」授权写法 2026-10-09 13:07:36 +08:00
居居
5a00ad317d Merge branch 'codex/xuxiake-sabc-sync-20260929' into codex/xuxiake-mainline
部门数据配置改为独立权限节点(默认商品企划 + 管理员)。
2026-10-09 11:27:32 +08:00
居居
cf5f3b2d49 feat(supply-chain): 部门数据配置改为独立权限节点,默认商品企划与管理员可用 2026-10-09 11:27:01 +08:00
居居
28e972f663 Merge branch 'codex/xuxiake-sabc-sync-20260929' into codex/xuxiake-mainline
各部门数据分类改为独立权限模块(可见/下载分开配置),无权限自动隐藏页签。
2026-10-09 10:26:28 +08:00
居居
ca08d89946 feat(supply-chain): 各部门数据分类改为独立权限模块(可见/下载分开配置) 2026-10-09 10:25:36 +08:00
WuYongJie
bffa3ec1a6 fix(intake): enable Gujia 2026 certificate template 2026-10-09 10:09:37 +08:00
WuYongJie
3fd4c0fac0 Merge Gujia 2026 certificate enablement into shared mainline 2026-10-09 10:09:06 +08:00
WuYongJie
ee95abd0b0 fix(intake): enable Gujia 2026 certificate template 2026-10-09 10:03:34 +08:00
WuYongJie
6989354a42 feat(supply-chain): 档案设计师绑定新品流程结构设计师(只填空值,以新品流程表为准) 2026-10-09 10:02:26 +08:00
WuYongJie
8a4e0ac797 feat(supply-chain): 档案设计师绑定新品流程结构设计师(只填空值,以新品流程表为准) 2026-10-09 10:02:18 +08:00
WuYongJie
afe9b806d5 feat(supply-chain): 档案设计师绑定新品流程结构设计师(只填空值,以新品流程表为准) 2026-10-09 10:01:58 +08:00
WuYongJie
6d3891fc44 style(layout): 产品开发侧栏对齐供应链 224px,修复系统切换器「产品开发」截断
侧栏变量 --layout-app-sidebar-width 11rem→14rem(浅色/深色两处),切换器簇/按钮随之与供应链逐项一致(224/192/144);切换器簇改 min-width、触发器 flex-1→flex-auto 作为防截断兜底。已实测四主页面无挤压无横向溢出。
2026-10-09 09:39:26 +08:00
WuYongJie
4cd07bdda5 Merge origin/codex/xuxiake-mainline into codex/local-3001-integration (sync before sidebar alignment push) 2026-10-09 09:39:06 +08:00
WuYongJie
8617493f8a style(layout): 产品开发侧栏对齐供应链 224px,修复系统切换器「产品开发」截断
侧栏变量 --layout-app-sidebar-width 11rem→14rem(浅色/深色两处),切换器簇/按钮随之与供应链逐项一致(224/192/144);切换器簇改 min-width、触发器 flex-1→flex-auto 作为防截断兜底。已实测四主页面无挤压无横向溢出。
2026-10-09 09:38:44 +08:00
WuYongJie
c3b20aace6 fix(supply-chain): 运营负责人改为一次性定标冻结(摘除跟随最新销售的每日翻转) 2026-10-09 09:00:53 +08:00
WuYongJie
5e842eeeb8 fix(supply-chain): 运营负责人改为一次性定标冻结(摘除跟随最新销售的每日翻转) 2026-10-09 09:00:46 +08:00
WuYongJie
b5dc4a1b1b fix(supply-chain): 运营负责人改为一次性定标冻结(摘除跟随最新销售的每日翻转) 2026-10-09 09:00:12 +08:00
WuYongJie
139aec0e70 feat(oa-board): 出图进度页改为美术设计申请源数据视图
一行=一条流程实例,列=流程实例ID/编号/标题/状态/时间+128 个表单原字段(按全量填写率排序,与源库导出 xlsx 同口径)。新快照表 oa_art_flow_raw_snapshot(关键筛选列+fields_json 全字段清洗值)+ oa_art_flow_raw_meta 字段顺序;同步脚本入 timer 链;API /api/intake/oa-board/art-flow-raw。旧 SKU 维度视图从页面移除,后端服务与导出消费方保留。
2026-10-08 17:24:06 +08:00
WuYongJie
1ba16cbc6b Merge origin/codex/xuxiake-mainline into codex/local-3001-integration (sync before art-flow raw view push) 2026-10-08 17:23:44 +08:00
WuYongJie
eaf11faea1 feat(oa-board): 出图进度页改为美术设计申请源数据视图
一行=一条流程实例,列=流程实例ID/编号/标题/状态/时间+128 个表单原字段(按全量填写率排序,与源库导出 xlsx 同口径)。新快照表 oa_art_flow_raw_snapshot(关键筛选列+fields_json 全字段清洗值)+ oa_art_flow_raw_meta 字段顺序;同步脚本入 timer 链;API /api/intake/oa-board/art-flow-raw。旧 SKU 维度视图从页面移除,后端服务与导出消费方保留。
2026-10-08 17:23:18 +08:00
WuYongJie
13b81e5822 feat(supply-chain): 新增替换款规则每日同步定时器安装脚本
SupplyChainProductArchiveReplacementRule 的上游是 rpt.pm_replacementManage,
此前只有 local-sync-archive.mjs 会调用 sync-product-replacement-rules.ts,
正式机没有任何定时任务,表建好后仍然是空的,SABC 的「同款商品编码」也就一直是空。

新增 install-product-replacement-rule-sync-timer.sh,按仓库既有 install-*-timer.sh
同款写法安装 furniture-product-replacement-rule-sync.{service,timer},
默认每天 07:40(Asia/Shanghai)同步一次,早于 09:00 的 SABC 打标日结。
脚本仅安装定时任务,改动生产数据由 sync-product-replacement-rules.ts 自己完成。
2026-10-08 16:43:58 +08:00
WuYongJie
bb777d4880 feat(supply-chain): 新增替换款规则每日同步定时器安装脚本
SupplyChainProductArchiveReplacementRule 的上游是 rpt.pm_replacementManage,
此前只有 local-sync-archive.mjs 会调用 sync-product-replacement-rules.ts,
正式机没有任何定时任务,表建好后仍然是空的,SABC 的「同款商品编码」也就一直是空。

新增 install-product-replacement-rule-sync-timer.sh,按仓库既有 install-*-timer.sh
同款写法安装 furniture-product-replacement-rule-sync.{service,timer},
默认每天 07:40(Asia/Shanghai)同步一次,早于 09:00 的 SABC 打标日结。
脚本仅安装定时任务,改动生产数据由 sync-product-replacement-rules.ts 自己完成。
2026-10-08 16:43:37 +08:00
居居
1bea953315 fix(supply-chain): 补齐替换规则表迁移(正式环境缺表导致同款商品编码全为空) 2026-10-08 16:30:35 +08:00
WuYongJie
03741083fa feat(supply-chain): 产品全量档案产品标签每日跟随SABC打标结果(有变化才更新) 2026-10-08 16:28:31 +08:00
WuYongJie
c23f616003 feat(supply-chain): 产品全量档案产品标签每日跟随SABC打标结果(有变化才更新) 2026-10-08 16:28:14 +08:00
WuYongJie
a3e236e986 feat(supply-chain): 产品全量档案产品标签每日跟随SABC打标结果(有变化才更新) 2026-10-08 16:26:54 +08:00
居居
9baee61769 Merge branch 'codex/xuxiake-sabc-sync-20260929' into codex/xuxiake-mainline
补齐 SupplyChainProductArchiveReplacementRule 迁移(正式环境缺表 → 同款商品编码全为空)。
2026-10-08 16:20:35 +08:00
居居
64a820a998 fix(supply-chain): 补齐替换规则表迁移(正式环境缺表导致同款商品编码全为空) 2026-10-08 16:20:27 +08:00
WuYongJie
c81b696a62 fix(supply-chain): 店铺账号列筛选支持全选后排除个别项(exclude 换算正面清单+筛选值截断上限提升) 2026-10-08 14:23:57 +08:00
WuYongJie
f13ed3d3fb fix(supply-chain): 店铺账号列筛选支持全选后排除个别项(exclude 换算正面清单+筛选值截断上限提升) 2026-10-08 14:23:53 +08:00
WuYongJie
ad0b094af1 fix(supply-chain): 店铺账号列筛选支持全选后排除个别项(exclude 换算正面清单+筛选值截断上限提升) 2026-10-08 14:23:02 +08:00
WuYongJie
2925818a75 feat(supply-chain): 店铺账号三级负责人离职改为文字后缀(已离职)并支持任一列命中筛选 2026-10-08 14:02:06 +08:00
WuYongJie
b7dd8ac490 feat(supply-chain): 店铺账号三级负责人离职改为文字后缀(已离职)并支持任一列命中筛选 2026-10-08 14:02:03 +08:00
WuYongJie
b295e128eb feat(supply-chain): 店铺账号三级负责人离职改为文字后缀(已离职)并支持任一列命中筛选 2026-10-08 14:01:43 +08:00
居居
8a3f32c5a2 fix(supply-chain): 修正月末创建时间边界,避免最后一天16点后创建的商品整月漏收录 2026-10-08 13:42:53 +08:00
WuYongJie
da1872c59d feat(supply-chain): 店铺账号离职负责人红色标注与负责人状态筛选(自定义下拉) 2026-10-08 12:59:32 +08:00
WuYongJie
4e594a4eee feat(supply-chain): 店铺账号离职负责人红色标注与负责人状态筛选(自定义下拉) 2026-10-08 12:59:23 +08:00
WuYongJie
ba1209deb3 feat(supply-chain): 店铺账号离职负责人红色标注与负责人状态筛选(自定义下拉) 2026-10-08 12:59:04 +08:00
WuYongJie
8e38894a2b fix(supply-chain): 全量档案运营层级匹配加固(不可见字符清洗+档案已有运营负责人兜底) 2026-10-08 12:01:59 +08:00
WuYongJie
605fb1347b fix(supply-chain): 全量档案运营层级匹配加固(不可见字符清洗+档案已有运营负责人兜底) 2026-10-08 12:01:38 +08:00
WuYongJie
bcfadc1e3f fix(supply-chain): 全量档案运营层级匹配加固(不可见字符清洗+档案已有运营负责人兜底) 2026-10-08 12:01:11 +08:00
WuYongJie
867b5bf897 feat(supply-chain): 店铺授权提醒每日定时推送(11:00)+ 负责人不在内部整店跳过 2026-10-08 11:36:30 +08:00
WuYongJie
cde4d59afb feat(supply-chain): 店铺授权提醒每日定时推送(11:00)+ 负责人不在内部整店跳过 2026-10-08 11:36:17 +08:00
WuYongJie
7979671a3d feat(supply-chain): 店铺授权提醒每日定时推送(11:00)+ 负责人不在内部整店跳过 2026-10-08 11:36:02 +08:00
WuYongJie
3a10aa3d9f feat(oa-board): 新品-视频进度(内容部)看板,钉钉内容视频流程独立接入
独立快照表 oa_video_flow_board_snapshot + 双驱动同步脚本 + 分页筛选接口 + 新 Tab;不进新品主链项目聚合/总状态/时效。阶段推进按表单字段推断(编导→摄像→剪辑→封面→验收/评分),节点名清单到位后可升级 activityId 映射。附数据字典 docs/数据字典/13-内容视频流程看板.md 供下游只读接入。
2026-10-08 11:22:46 +08:00
WuYongJie
9996ee83b2 Merge origin/codex/xuxiake-mainline into codex/local-3001-integration (sync before video-flow board push) 2026-10-08 11:22:14 +08:00
WuYongJie
af378a9d00 feat(oa-board): 新品-视频进度(内容部)看板,钉钉内容视频流程独立接入
独立快照表 oa_video_flow_board_snapshot + 双驱动同步脚本 + 分页筛选接口 + 新 Tab;不进新品主链项目聚合/总状态/时效。阶段推进按表单字段推断(编导→摄像→剪辑→封面→验收/评分),节点名清单到位后可升级 activityId 映射。附数据字典 docs/数据字典/13-内容视频流程看板.md 供下游只读接入。
2026-10-08 11:20:48 +08:00
codex
e6241481aa fix(logistics-arrival): 下钻/导出接口接受按字段分组的排除关键词
下钻和导出两个接口的 zod schema 还停留在 string | array,
而前端下发的是新的分组对象 { 字段: [词] },
于是点商品/店铺等对象下钻时 09 明细直接报"下钻条件格式不正确"(导出报"导出筛选条件格式不正确")。

- 两个接口的 excludeKeywords 都接受 对象 / `字段:词,词` 字符串 / 旧平铺数组
- 字符串形态改用 parseExcludeKeywords 解析(老链接按配置归位),不会把字段名当成关键词
- 新增两条路由单测:分组对象下钻/导出、字符串与平铺兼容、非法形态返回 400
2026-10-08 11:16:57 +08:00
WuYongJie
12feabd17f feat(supply-chain): 店铺账号授权提醒推送(正常+未授权店铺推送给运营负责人,离职顺延) 2026-10-08 11:05:56 +08:00
WuYongJie
24e403b183 feat(supply-chain): 店铺账号授权提醒推送(正常+未授权店铺推送给运营负责人,离职顺延) 2026-10-08 11:05:35 +08:00
WuYongJie
2342c53704 feat(supply-chain): 店铺账号授权提醒推送(正常+未授权店铺推送给运营负责人,离职顺延) 2026-10-08 10:59:54 +08:00
居居
246313c45a Merge branch 'codex/xuxiake-sabc-sync-20260929' into codex/xuxiake-mainline
修正商品SABC打标月末创建时间边界:最后一天 16:00 之后创建的商品不再被整月漏收录。
2026-10-08 09:27:37 +08:00
居居
838dcce410 fix(supply-chain): 修正月末创建时间边界,避免最后一天16点后创建的商品整月漏收录 2026-10-08 09:27:27 +08:00
WuYongJie
2528229c08 fix(supply-chain): 全量档案表宽固定为列宽之和,修复滚动时横向滚动条跳动 2026-10-08 09:27:05 +08:00
WuYongJie
91af9c5284 fix(supply-chain): 全量档案表宽固定为列宽之和,修复滚动时横向滚动条跳动 2026-10-08 09:26:56 +08:00
WuYongJie
f3f3bfa08b fix(supply-chain): 全量档案表宽固定为列宽之和,修复滚动时横向滚动条跳动 2026-10-08 09:26:38 +08:00
WuYongJie
685f3cc756 perf(supply-chain): 产品全量档案表体行虚拟化(视口窗口渲染+占位行) 2026-10-08 08:50:19 +08:00
WuYongJie
17474f0d85 perf(supply-chain): 产品全量档案表体行虚拟化(视口窗口渲染+占位行) 2026-10-08 08:50:10 +08:00
WuYongJie
174b1eec25 perf(supply-chain): 产品全量档案表体行虚拟化(视口窗口渲染+占位行) 2026-10-08 08:49:52 +08:00
WuYongJie
6363ed87b7 style(layout): 系统切换器灰底与下拉面板右边缘对齐左侧栏 2026-10-07 17:58:59 +08:00
WuYongJie
173c594c24 style(supply-chain): 物流到货签收时长看板移除顶部表头区块 2026-10-07 17:58:59 +08:00
WuYongJie
62f693223f style(supply-chain): 移除多处页面标题/说明块与冗余计数文本(工具条保持右对齐) 2026-10-07 17:58:59 +08:00
WuYongJie
bc79cd6321 style(layout): 系统切换器灰底与下拉面板右边缘对齐左侧栏 2026-10-07 17:58:56 +08:00
WuYongJie
48a8de5d77 style(supply-chain): 物流到货签收时长看板移除顶部表头区块 2026-10-07 17:58:56 +08:00
WuYongJie
bd0a5c81f3 style(supply-chain): 移除多处页面标题/说明块与冗余计数文本(工具条保持右对齐) 2026-10-07 17:58:56 +08:00
WuYongJie
5394319205 style(layout): 系统切换器灰底与下拉面板右边缘对齐左侧栏 2026-10-07 17:58:43 +08:00
WuYongJie
5779dcf5be style(supply-chain): 物流到货签收时长看板移除顶部表头区块 2026-10-07 17:58:42 +08:00
WuYongJie
97fffc4f3d style(supply-chain): 移除多处页面标题/说明块与冗余计数文本(工具条保持右对齐) 2026-10-07 17:58:42 +08:00
WuYongJie
5b8e1945af perf(supply-chain): 列设置关闭面板改为非阻塞过渡,修复整表同步重渲染卡顿 2026-10-07 17:33:36 +08:00
WuYongJie
45ba5c1005 perf(supply-chain): 列设置关闭面板改为非阻塞过渡,修复整表同步重渲染卡顿 2026-10-07 17:33:29 +08:00
WuYongJie
70fb47f529 perf(supply-chain): 列设置关闭面板改为非阻塞过渡,修复整表同步重渲染卡顿 2026-10-07 17:33:15 +08:00
WuYongJie
d5762b3e12 style(supply-chain): 产品全量档案工具栏移除标题与字段统计文案 2026-10-07 17:19:28 +08:00
WuYongJie
e54976df03 perf(supply-chain): 产品全量档案按页聚合+缓存+候选项SQL化(含SWR后台刷新与全选提速) 2026-10-07 17:19:27 +08:00
WuYongJie
f14d796056 style(supply-chain): 产品全量档案工具栏移除标题与字段统计文案 2026-10-07 17:19:03 +08:00
WuYongJie
0a0b925d99 perf(supply-chain): 产品全量档案按页聚合+缓存+候选项SQL化(含SWR后台刷新与全选提速) 2026-10-07 17:18:44 +08:00
WuYongJie
1f8e8bab74 style(supply-chain): 产品全量档案工具栏移除标题与字段统计文案 2026-10-07 17:18:26 +08:00
WuYongJie
1b3498e785 perf(supply-chain): 产品全量档案按页聚合+缓存+候选项SQL化(含SWR后台刷新与全选提速) 2026-10-07 17:18:25 +08:00
codex
ed865a3c2d fix(logistics-arrival): 修复订单明细"每页条数"选了没反应
BoardPagination 的下拉框在 onChange 里同时调了 onPageSizeChange(新值) 和 onPageChange(1)。
服务端分页(09 订单明细未下钻)这两次都会 router.push,而后一次是拿调用方当前的 filters
(pageSize 还是旧值)拼的 URL,把前一次覆盖掉——所以选 100/200 后又被拉回 50 条/页。

- BoardPagination 只通知"每页条数变了",回到第 1 页由调用方负责
- 本地分页(经营对象各维度表、发货仓/物流公司排名)在 setState 里带 page: 1
- 服务端分页继续用 href(1, { ...filters, pageSize })
- OrderDetailsBoard 测试补回归断言:切换每页条数只触发一次跳转
2026-10-07 15:26:12 +08:00
WuYongJie
1aef696ae6 chore(deploy): 生产 heap 上限 768MB 提升到 2048MB(缓解看板等重查询导致的 OOM 重启) 2026-10-07 15:26:11 +08:00
WuYongJie
b9a9d4b426 chore(deploy): 生产 heap 上限 768MB 提升到 2048MB(缓解看板等重查询导致的 OOM 重启) 2026-10-07 15:26:09 +08:00
WuYongJie
4fc857f1bd Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/local-3001-integration 2026-10-07 15:25:56 +08:00
WuYongJie
c1dbfaa145 chore(deploy): 生产 heap 上限 768MB 提升到 2048MB(缓解看板等重查询导致的 OOM 重启) 2026-10-07 15:25:55 +08:00
codex
debdfb454b fix(logistics-arrival): 修复订单明细"每页条数"选了没反应
BoardPagination 的下拉框在 onChange 里同时调了 onPageSizeChange(新值) 和 onPageChange(1)。
服务端分页(09 订单明细未下钻)这两次都会 router.push,而后一次是拿调用方当前的 filters
(pageSize 还是旧值)拼的 URL,把前一次覆盖掉——所以选 100/200 后又被拉回 50 条/页。

- BoardPagination 只通知"每页条数变了",回到第 1 页由调用方负责
- 本地分页(经营对象各维度表、发货仓/物流公司排名)在 setState 里带 page: 1
- 服务端分页继续用 href(1, { ...filters, pageSize })
- OrderDetailsBoard 测试补回归断言:切换每页条数只触发一次跳转
2026-10-07 14:35:46 +08:00
居居
255130b31f fix(supply-chain): 修正导出 dense 选项的类型声明(xlsx 0.18 类型未含 dense) 2026-10-07 14:28:52 +08:00
居居
5367bc4d27 perf(supply-chain): SABC 导出改 dense 表格+结果缓存+串行生成,降低内存峰值并支持秒级重试 2026-10-07 14:28:52 +08:00
WuYongJie
dfdfe019f2 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/local-3001-integration 2026-10-07 14:27:58 +08:00
WuYongJie
5f31eca7ac fix(build): 外置 mssql,修复正式构建下 mssql 参数类型校验失败(物流看板等 mssql 功能) 2026-10-07 14:10:08 +08:00
WuYongJie
cb3e973bf6 fix(build): 外置 mssql,修复正式构建下 mssql 参数类型校验失败(物流看板等 mssql 功能) 2026-10-07 14:09:58 +08:00
WuYongJie
855cce7034 fix(build): 外置 mssql,修复正式构建下 mssql 参数类型校验失败(物流看板等 mssql 功能) 2026-10-07 14:09:47 +08:00
居居
ed893bd598 Merge branch 'codex/xuxiake-sabc-sync-20260929' into codex/xuxiake-mainline
修正 SABC 导出 dense 选项类型声明。
2026-10-07 14:08:24 +08:00
居居
3d64e3e332 fix(supply-chain): 修正导出 dense 选项的类型声明(xlsx 0.18 类型未含 dense) 2026-10-07 14:08:23 +08:00
居居
60ea2f923b Merge branch 'codex/xuxiake-sabc-sync-20260929' into codex/xuxiake-mainline
商品SABC打标导出:dense 表格 + 压缩输出 + 结果缓存 + 串行生成,降低 502/超时概率。
2026-10-07 14:00:21 +08:00
居居
faa60655f7 perf(supply-chain): SABC 导出改 dense 表格+结果缓存+串行生成,降低内存峰值并支持秒级重试 2026-10-07 14:00:13 +08:00
WuYongJie
0498a8f2e6 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/local-3001-integration 2026-10-07 13:33:45 +08:00
居居
47f446bf62 perf(supply-chain): 导出压缩输出(8月明细 64MB→17MB)并补充导出耗时日志与错误详情 2026-10-07 13:04:59 +08:00
居居
14cb9939ad Merge branch 'codex/xuxiake-sabc-sync-20260929' into codex/xuxiake-mainline
商品SABC打标导出改为压缩输出(8 月明细 64MB → 17MB),并补充导出耗时日志与失败原因提示。
2026-10-07 12:00:26 +08:00
居居
9d8b75ca4d perf(supply-chain): 导出压缩输出(8月明细 64MB→17MB)并补充导出耗时日志与错误详情 2026-10-07 12:00:19 +08:00
codex
1b49125ffa feat(logistics-arrival): 重置 / 恢复默认 / 清空排除 三个按钮语义拆开
过去三个按钮都只是"改输入、等用户点查询",而且重置只清日期+关键词、另两个只改排除词,
最终看起来结果一样。现在各自一件事,点下去立即查询:

- 重置:签收日期、关键词、排除关键词全部清空 → 没有任何筛选条件
  (空日期仍由服务端兜底成本月 1 号~昨日;新增 dateRangeCleared 标记,
   让输入框保持空白而不是被兜底值回填)
- 恢复默认:签收日期回到本月 1 号~昨日(显式填回输入框)+ 排除关键词恢复系统默认配置
- 清空排除:签收日期回到本月 1 号~昨日 + 排除关键词置空

配套:`logisticsArrivalSigningDurationDefaultRange()` 从过滤器规范化里抽出来共用(单一来源)、
按钮 hover 说明 + 筛选栏底部图例、去掉旧的"填好后点查询"提示、补视图层测试。
2026-10-07 11:46:00 +08:00
codex
787fcb67bb perf(logistics-arrival): 看板冷启动从 7 秒降到 2 秒出头
整区间总览/环节目标原来 SELECT 全列,PG 只能对 900MB 堆表做 Seq Scan
(28 天区间 read=106409 页、6.3s);percentile_cont 又把 14 列宽的输入行
整行送进排序(两个分位数 4.3s,环节分位数叠加到分钟级);CTE 里的
CASE+EXTRACT 还会在每处引用被重复内联。

- 按用途收窄列集合:时间戳 / 时间戳+维度列,并新增覆盖索引
  (snapshotDate, signTime) INCLUDE (payTime, sendTime, fetchTime,
  warehouseName, platformName, shopName, logisticCompanyName) → Index Only Scan
- 分位数按列拆成独立语句、只投影一个浮点列,与计数语句并行下发
- measured / durations 改 AS MATERIALIZED,时长表达式只算一次
- 环节目标(上月平均 × 98%)接入 10 分钟内存缓存

实测(本机快照 648,689 行、冷启动):
28 天 7.3s→2.3s、10 天 4.4s→0.4s、2 天 1.7s→0.3s;
浏览器首屏出数 ~7-10s→2.7s。2 天区间与 JS 现算逐项对账一致。
2026-10-07 11:46:00 +08:00
codex
83d10ec9e7 fix(logistics-arrival): 修复排除关键词弹窗透明与保存报格式错误
- globals.css:在 :root 与 [data-theme='dark'] 补齐 --sc-* 主题别名。
  弹窗通过 createPortal 挂在 document.body 上,位于 .sc-layout 之外,
  之前取不到 --sc-surface/--sc-border 等变量,正式环境里表现为面板透明、
  边框与分隔线丢失(本地开发因为另一分支已临时补过这段而看不出来)。
- settings 接口:接受按字段分组的排除关键词对象(同时兼容历史平铺数组与字符串),
  修复管理员在选择器里新增关键词时报"排除关键词格式不正确"。
- 补充 settings 路由单测:分组对象落库、平铺数组兼容、非法格式返回 400。
2026-10-07 11:46:00 +08:00
WuYongJie
9a2bff07ab Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/local-3001-integration 2026-10-07 11:39:58 +08:00
WuYongJie
ff722ab12e chore(installation-demo-v2): 合并主线前落盘本地在途 V2 模型(仅 schema.prisma) 2026-10-07 11:39:55 +08:00
codex
7620e4bcb6 feat(logistics-arrival): 重置 / 恢复默认 / 清空排除 三个按钮语义拆开
过去三个按钮都只是"改输入、等用户点查询",而且重置只清日期+关键词、另两个只改排除词,
最终看起来结果一样。现在各自一件事,点下去立即查询:

- 重置:签收日期、关键词、排除关键词全部清空 → 没有任何筛选条件
  (空日期仍由服务端兜底成本月 1 号~昨日;新增 dateRangeCleared 标记,
   让输入框保持空白而不是被兜底值回填)
- 恢复默认:签收日期回到本月 1 号~昨日(显式填回输入框)+ 排除关键词恢复系统默认配置
- 清空排除:签收日期回到本月 1 号~昨日 + 排除关键词置空

配套:`logisticsArrivalSigningDurationDefaultRange()` 从过滤器规范化里抽出来共用(单一来源)、
按钮 hover 说明 + 筛选栏底部图例、去掉旧的"填好后点查询"提示、补视图层测试。
2026-10-07 11:05:35 +08:00
居居
bc10af7b62 feat(supply-chain): 商品SABC打标执行核算改由权限配置节点控制 2026-10-07 10:58:34 +08:00
居居
9f63e51702 Merge branch 'codex/xuxiake-sabc-sync-20260929' into codex/xuxiake-mainline
商品SABC打标「执行核算」改由权限配置节点(商品SABC打标 · 执行核算)控制,前端按钮与接口同步;清理未随提交带上的 WorkflowMonitorView 引用。
2026-10-07 10:01:28 +08:00
居居
e57604ac81 feat(supply-chain): 商品SABC打标执行核算改由权限配置节点控制 2026-10-07 10:01:19 +08:00
WuYongJie
c981ff3bb0 以图搜图粘贴与放大体验修复;部署脚本补齐 onnxruntime 原生库
- ProductArchiveImageSearchDialog:弹窗打开期间监听 document 级 paste,页面任意位置 Ctrl+V 直接粘贴图片(点击上传区仍是文件选择);搜索结果小图可点击,复用 ProductArchiveImagePreview 放大核对
- yydd-prod-release-guards.sh:prepare_standalone_runtime 补齐 Turbopack standalone 产物遗漏的 onnxruntime-node 原生二进制(libonnxruntime.so.*),根治部署后本地图索层加载失败;符号链接场景自动跳过
2026-10-07 09:57:43 +08:00
WuYongJie
8370ef2ddc 以图搜图粘贴与放大体验修复;部署脚本补齐 onnxruntime 原生库
- ProductArchiveImageSearchDialog:弹窗打开期间监听 document 级 paste,页面任意位置 Ctrl+V 直接粘贴图片(点击上传区仍是文件选择);搜索结果小图可点击,复用 ProductArchiveImagePreview 放大核对
- yydd-prod-release-guards.sh:prepare_standalone_runtime 补齐 Turbopack standalone 产物遗漏的 onnxruntime-node 原生二进制(libonnxruntime.so.*),根治部署后本地图索层加载失败;符号链接场景自动跳过
2026-10-07 09:57:23 +08:00
WuYongJie
a308eb6c81 以图搜图粘贴与放大体验修复;部署脚本补齐 onnxruntime 原生库
- ProductArchiveImageSearchDialog:弹窗打开期间监听 document 级 paste,页面任意位置 Ctrl+V 直接粘贴图片(点击上传区仍是文件选择);搜索结果小图可点击,复用 ProductArchiveImagePreview 放大核对
- yydd-prod-release-guards.sh:prepare_standalone_runtime 补齐 Turbopack standalone 产物遗漏的 onnxruntime-node 原生二进制(libonnxruntime.so.*),根治部署后本地图索层加载失败;符号链接场景自动跳过
2026-10-07 09:57:08 +08:00
WuYongJie
dbb2d4965a fix(layout): 浏览器标签页标题统一为工作区名,不再随子页面跳变
供应链中心 layout 新增统一标题「由壹点「供应链中心」」并删除其下 25 个页面的页级 metadata title;产品开发侧产品开发日志、BOM核算、AI出图工作台、安装演示工作台(V1)、通知记录、更新日志、回收站 8 处删除旧标题覆盖,统一显示「由壹点「产品开发」」。纯 metadata 变更,无 UI 与逻辑改动。3001 逐页 SSR title 实测通过。
2026-10-07 09:51:18 +08:00
codex
eac3344e2d perf(logistics-arrival): 看板冷启动从 7 秒降到 2 秒出头
整区间总览/环节目标原来 SELECT 全列,PG 只能对 900MB 堆表做 Seq Scan
(28 天区间 read=106409 页、6.3s);percentile_cont 又把 14 列宽的输入行
整行送进排序(两个分位数 4.3s,环节分位数叠加到分钟级);CTE 里的
CASE+EXTRACT 还会在每处引用被重复内联。

- 按用途收窄列集合:时间戳 / 时间戳+维度列,并新增覆盖索引
  (snapshotDate, signTime) INCLUDE (payTime, sendTime, fetchTime,
  warehouseName, platformName, shopName, logisticCompanyName) → Index Only Scan
- 分位数按列拆成独立语句、只投影一个浮点列,与计数语句并行下发
- measured / durations 改 AS MATERIALIZED,时长表达式只算一次
- 环节目标(上月平均 × 98%)接入 10 分钟内存缓存

实测(本机快照 648,689 行、冷启动):
28 天 7.3s→2.3s、10 天 4.4s→0.4s、2 天 1.7s→0.3s;
浏览器首屏出数 ~7-10s→2.7s。2 天区间与 JS 现算逐项对账一致。
2026-10-07 09:45:35 +08:00
WuYongJie
1da917bb01 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/local-3001-integration 2026-10-07 09:40:10 +08:00
WuYongJie
08bb5a96a4 fix(layout): 浏览器标签页标题统一为工作区名,不再随子页面跳变
供应链中心 layout 新增统一标题「由壹点「供应链中心」」并删除其下 25 个页面的页级 metadata title;产品开发侧产品开发日志、BOM核算、AI出图工作台、安装演示工作台(V1)、通知记录、更新日志、回收站 8 处删除旧标题覆盖,统一显示「由壹点「产品开发」」。纯 metadata 变更,无 UI 与逻辑改动。3001 逐页 SSR title 实测通过。
2026-10-07 09:37:21 +08:00
WuYongJie
b0a6cdd1e7 feat(installation-demo): 工作台顶栏改为目录/制作/分享并新增工具抽屉与制作流程卡
- 标签行:模型→目录、详情→制作;工具从跳转链接改为面板内抽屉,勾选即保存,完整工具箱保留次级入口
2026-10-07 08:50:28 +08:00
WuYongJie
69618965c7 feat(installation-demo): 工作台顶栏改为目录/制作/分享并新增工具抽屉与制作流程卡
- 标签行:模型→目录、详情→制作;工具从跳转链接改为面板内抽屉,勾选即保存,完整工具箱保留次级入口
2026-10-06 18:21:35 +08:00
WuYongJie
f6e4d7f2e1 feat(installation-demo): 工作台顶栏改为目录/制作/分享并新增工具抽屉与制作流程卡
- 标签行:模型→目录、详情→制作;工具从跳转链接改为面板内抽屉,勾选即保存,完整工具箱保留次级入口
2026-10-06 18:20:36 +08:00
WuYongJie
614e3dabe2 feat(supply-chain): 产品全量档案「产品标签」接入 SABC 打标与未打标兜底 2026-10-06 18:19:40 +08:00
WuYongJie
ce2a6ebbaf feat(supply-chain): 产品全量档案「产品标签」接入 SABC 打标与未打标兜底 2026-10-06 18:19:34 +08:00
WuYongJie
b1f55faebb feat(supply-chain): 产品全量档案「产品标签」接入 SABC 打标与未打标兜底 2026-10-06 18:19:10 +08:00
codex
c5cae01ecd fix(logistics-arrival): 修复排除关键词弹窗透明与保存报格式错误
- globals.css:在 :root 与 [data-theme='dark'] 补齐 --sc-* 主题别名。
  弹窗通过 createPortal 挂在 document.body 上,位于 .sc-layout 之外,
  之前取不到 --sc-surface/--sc-border 等变量,正式环境里表现为面板透明、
  边框与分隔线丢失(本地开发因为另一分支已临时补过这段而看不出来)。
- settings 接口:接受按字段分组的排除关键词对象(同时兼容历史平铺数组与字符串),
  修复管理员在选择器里新增关键词时报"排除关键词格式不正确"。
- 补充 settings 路由单测:分组对象落库、平铺数组兼容、非法格式返回 400。
2026-10-06 18:15:57 +08:00
WuYongJie
7e6cc35199 fix(intake): 搜索下拉支持清空已选值 2026-10-06 17:56:20 +08:00
WuYongJie
57b2b405cf fix(intake): 商品企划候选人排除供应商账号 2026-10-06 17:56:20 +08:00
WuYongJie
e1b8989621 fix(intake): 搜索下拉支持清空已选值 2026-10-06 17:56:07 +08:00
WuYongJie
f5f20a8b18 fix(intake): 商品企划候选人排除供应商账号 2026-10-06 17:56:06 +08:00
WuYongJie
a110714305 fix(intake): 搜索下拉支持清空已选值 2026-10-06 17:55:36 +08:00
WuYongJie
f430b3e18d fix(intake): 商品企划候选人排除供应商账号 2026-10-06 17:55:24 +08:00
居居
5cd69fb9db Merge branch 'codex/xuxiake-sabc-sync-20260929' into codex/xuxiake-mainline 2026-10-06 17:24:22 +08:00
WuYongJie
a4e61b44a1 Merge origin/codex/xuxiake-mainline (SABC 模块等 74 个提交) into codex/local-3001-integration 2026-10-06 17:21:50 +08:00
居居
2be45f7a74 Merge branch 'codex/xuxiake-sabc-sync-20260929' into codex/xuxiake-mainline 2026-10-06 17:02:56 +08:00
居居
14a5e1c5f7 feat(supply-chain): 人员信息同步支持自动标记离职(方案B:抓取比对+钉钉确认) 2026-10-06 16:53:13 +08:00
WuYongJie
6d5a8a65d3 fix(intake): 商品企划候选人改为全部内部人员(商品企划部解散后搜不到人) 2026-10-06 16:29:59 +08:00
WuYongJie
e95a2365f5 fix(intake): 商品企划候选人改为全部内部人员(商品企划部解散后搜不到人) 2026-10-06 16:29:36 +08:00
WuYongJie
294d6d3dfa fix(intake): 商品企划候选人改为全部内部人员(商品企划部解散后搜不到人) 2026-10-06 16:29:20 +08:00
居居
cda264dd30 Merge branch 'codex/xuxiake-sabc-sync-20260929' into codex/xuxiake-mainline
商品SABC打标:月度核算生成后冻结、各部门数据分类子页面(按利润中心分组 + 部门数据权限 +
可配置品牌范围/兜底/目标 + 月度快照)、导出明细与经营总览、同款商品编码匹配修复;
并移除未随提交带上的 WorkflowMonitorView 引用、修正行快照类型。
2026-10-06 16:12:42 +08:00
居居
cfe8cf950c Merge branch 'codex/xuxiake-sabc-sync-20260929' into codex/xuxiake-mainline
商品SABC打标:月度核算生成后冻结、各部门数据分类子页面(按利润中心分组 + 部门数据权限 +
可配置品牌范围/兜底/目标 + 月度快照)、导出明细与经营总览、同款商品编码匹配修复;
并移除未随提交带上的 WorkflowMonitorView 引用、修正行快照类型。
2026-10-06 16:07:22 +08:00
居居
3ef36c7648 fix(supply-chain): 移除未随提交带上的 WorkflowMonitorView 引用并修正 SABC 行快照类型 2026-10-06 16:05:54 +08:00
codex
83c10719ca feat(logistics-arrival): 物流到货签收时长看板
- 看板:经营总览(平均到货时长 + 本月目标 + 目标达成率、异常单点击下钻)、
  履约环节拆解(平均/中位/P90/目标/目标达成率,分栏可拖动)、发货→签收时效分布
- 经营对象问题排名:签收日期→平台→店铺→发货仓→物流→采购→供应商→商品→订单明细
  逐级联动 + 独立翻页;经营对象带「目标 = 该对象上月平均 × 98%」与目标达成率
- 09 订单明细:看板内翻页、高度可拖动、下钻后自动滚动定位
- 排除关键词按字段分组(发货仓/物流公司/订单标签/买家留言/卖家备注),
  选择器支持搜索、全部/已选项、全选/反选/清空、紧凑模式与按字段新增
- 每日订单明细快照:Prisma 模型与迁移、同步脚本、定时器安装脚本;
  命中快照时整区间精确统计,超过规模上限回落均匀样本并如实标注
- 接入侧边菜单、标签页标题与权限映射(businessManagement),补充架构文档
2026-10-06 15:37:48 +08:00
居居
ac572e2c4d Merge branch 'codex/xuxiake-sabc-sync-20260929' into codex/xuxiake-mainline
商品SABC打标:月度核算生成后冻结(每月3日自动生成上月)、各部门数据分类子页面
(按利润中心分组 + 部门数据权限 + 可配置品牌范围/兜底/目标)、导出明细与经营总览、
同款商品编码匹配修复等。
2026-10-06 15:37:48 +08:00
codex
77eff1744a feat(employee-hours): 工时记录列表支持按列排序
- 查询接口与管理端筛选条件新增 sortBy / sortDirection,服务端校验取值合法性
- 仓储层按列名映射排序字段,approvedScore / attachment 使用 nulls last,并保持 id 升序兜底
- 列表列头改为可点击排序(显示升序/降序箭头与 aria-sort),保留原有列宽拖拽
- 补齐仓储、服务、视图层单测(排序参数校验与列头交互)
2026-10-06 15:37:47 +08:00
codex
05007d3ae2 feat(logistics-arrival): 物流到货签收时长看板
- 看板:经营总览(平均到货时长 + 本月目标 + 目标达成率、异常单点击下钻)、
  履约环节拆解(平均/中位/P90/目标/目标达成率,分栏可拖动)、发货→签收时效分布
- 经营对象问题排名:签收日期→平台→店铺→发货仓→物流→采购→供应商→商品→订单明细
  逐级联动 + 独立翻页;经营对象带「目标 = 该对象上月平均 × 98%」与目标达成率
- 09 订单明细:看板内翻页、高度可拖动、下钻后自动滚动定位
- 排除关键词按字段分组(发货仓/物流公司/订单标签/买家留言/卖家备注),
  选择器支持搜索、全部/已选项、全选/反选/清空、紧凑模式与按字段新增
- 每日订单明细快照:Prisma 模型与迁移、同步脚本、定时器安装脚本;
  命中快照时整区间精确统计,超过规模上限回落均匀样本并如实标注
- 接入侧边菜单、标签页标题与权限映射(businessManagement),补充架构文档
2026-09-30 18:18:51 +08:00
居居
a771a9a5dc Merge branch 'codex/xuxiake-sabc-sync-20260929' into codex/xuxiake-mainline
商品SABC打标:月度核算生成后冻结(每月3日自动生成上月)、各部门数据分类子页面
(按利润中心分组 + 部门数据权限 + 可配置品牌范围/兜底/目标)、导出明细与经营总览、
同款商品编码匹配修复等。
2026-09-30 18:15:07 +08:00
居居
3f1de4e431 style(supply-chain): 导出下拉框与查询/重置按钮对齐 2026-09-30 18:14:09 +08:00
居居
155c93a0c5 feat(supply-chain): 产品中心/采购中心卡片新增导出按钮 2026-09-30 18:11:09 +08:00
居居
471b5b373e perf(supply-chain): 各部门数据分类改为核算时落库月度快照,页面直接读结果 2026-09-30 18:08:01 +08:00
codex
df206dbfe3 feat(employee-hours): 工时记录列表支持按列排序
- 查询接口与管理端筛选条件新增 sortBy / sortDirection,服务端校验取值合法性
- 仓储层按列名映射排序字段,approvedScore / attachment 使用 nulls last,并保持 id 升序兜底
- 列表列头改为可点击排序(显示升序/降序箭头与 aria-sort),保留原有列宽拖拽
- 补齐仓储、服务、视图层单测(排序参数校验与列头交互)
2026-09-30 18:04:41 +08:00
居居
dc0a9e740a style(supply-chain): 各部门数据分类按 A/B/C/G 优先排序 2026-09-30 17:56:43 +08:00
居居
398bc73450 feat(supply-chain): 产品中心/采购中心剔除山东项目组,导出补合计行 2026-09-30 17:51:18 +08:00
居居
4369e2f050 perf(supply-chain): 各部门数据分类增加结果/快照/花名册缓存,加载从秒级降到毫秒级 2026-09-30 17:11:52 +08:00
居居
e61772c2ce feat(supply-chain): 导出菜单去掉列表项,明细=仅商品表,明细(含经营总览)=商品表+汇总 2026-09-30 15:51:36 +08:00
居居
5bc45f4e93 fix(supply-chain): 品牌兜底行的部门负责人/总负责人改按人员信息逻辑取 2026-09-30 15:41:07 +08:00
居居
4c4807c72e feat(supply-chain): SABC 导出改为导出列表/导出明细/导出经营总览三档菜单 2026-09-30 15:39:14 +08:00
居居
baa2017106 feat(supply-chain): 山东专用/分销专用品牌运营负责人兜底(刘景刚/宋兵乙) 2026-09-30 15:34:17 +08:00
居居
38120d3f73 feat(supply-chain): 其他(未分配)分组核实花名册离职状态并置底展示 2026-09-30 14:37:55 +08:00
居居
9d2633420d style(supply-chain): 产品中心/采购中心改为与运营中心一致的卡片与合计行 2026-09-30 14:25:33 +08:00
居居
de6d9014b3 feat(supply-chain): 各部门数据分类产品中心/采购中心改为完整指标列,去掉重复的未匹配清单 2026-09-30 14:22:09 +08:00
居居
0a2a9c2f89 feat(supply-chain): 各部门数据分类筛选占位/单中心导出/部门回落利润中心/离职人员分组/运营中心E并入G 2026-09-30 14:10:38 +08:00
居居
6a36cae707 style(supply-chain): 各部门数据分类业绩按万元展示 2026-09-30 13:54:03 +08:00
居居
d47d550409 fix(supply-chain): 各部门数据分类配置改为弹窗,点击配置立即可见 2026-09-30 13:53:28 +08:00
居居
303694784c feat(supply-chain): SABC 导出新增「明细」/「明细(含经营总览)」两种模式 2026-09-30 13:49:38 +08:00
居居
da46e84526 feat(supply-chain): 新增「各部门数据分类」子页面(按利润中心分组 + 部门数据权限 + 可配置品牌范围) 2026-09-30 13:02:00 +08:00
居居
6eebb56ba0 feat(supply-chain): SABC 每月3日生成上月并冻结,执行核算仅管理员 2026-09-30 09:51:41 +08:00
居居
ad08dccf1c Merge branch 'codex/xuxiake-sabc-sync-20260929' into codex/xuxiake-mainline
商品SABC打标全部源码:页面/筛选/经营总览、服务端核算规则、同款商品编码匹配、
每日同步(聚水潭档案/销售日表/替换规则/类目档位/产品类型回填)、API 与导出、测试用例。
2026-09-29 18:04:53 +08:00
居居
6da6b0df76 Merge branch 'codex/xuxiake-sabc-sync-20260929' into codex/xuxiake-mainline
商品SABC打标全部源码:页面/筛选/经营总览、服务端核算规则、同款商品编码匹配、
每日同步(聚水潭档案/销售日表/替换规则/类目档位/产品类型回填)、API 与导出、测试用例。
2026-09-29 17:59:16 +08:00
WuYongJie
b9dc0bddb1 产品全量档案以图搜图改用壹点图搜接口并增加本地向量双层检索
- A 层:调壹点图搜上游(ownProductMatches 我司 SKU 命中),上游调用收口为共享 client,供应商推荐搜索市场同款同步复用
- B 层:本地 DINOv2 向量索引覆盖全量档案图(宽松排序、同图哈希置顶、模型未就绪自动降级)
- 上游编码与档案条码/SKU 大小写不敏感匹配,两路结果按条码去重
- 弹窗分「我司 SKU 命中」「全量档案相似」两区展示,本地索引通过 scripts/index-product-archive-images.ts 增量维护
2026-09-29 17:55:30 +08:00
WuYongJie
4008bcf061 产品全量档案以图搜图改用壹点图搜接口并增加本地向量双层检索
- A 层:调壹点图搜上游(ownProductMatches 我司 SKU 命中),上游调用收口为共享 client,供应商推荐搜索市场同款同步复用
- B 层:本地 DINOv2 向量索引覆盖全量档案图(宽松排序、同图哈希置顶、模型未就绪自动降级)
- 上游编码与档案条码/SKU 大小写不敏感匹配,两路结果按条码去重
- 弹窗分「我司 SKU 命中」「全量档案相似」两区展示,本地索引通过 scripts/index-product-archive-images.ts 增量维护
2026-09-29 17:54:54 +08:00
居居
39f603c091 fix(supply-chain): 同款编码改为直接正反向匹配,不再顺延替换链到末端 2026-09-29 17:21:24 +08:00
居居
34abc63edc feat(supply-chain): 同款编码正反向匹配并顺延替换链到最终编码 2026-09-29 17:05:49 +08:00
居居
0a8231d93c feat(supply-chain): 总览刷新与趋势支持强制取最新数据(绕过缓存) 2026-09-29 16:49:52 +08:00
居居
7838b82655 feat(supply-chain): 同款编码重复映射取创建时间最新的一条 2026-09-29 16:47:06 +08:00
居居
9f89ccbb7e feat(supply-chain): 不考核原因只保留 ODM,其余为空并同步是否考核 2026-09-29 16:35:12 +08:00
WuYongJie
1dcaa48baf fix(intake): 产品核价工作区接入受控列宽并修复长规格名称挤成多排 2026-09-29 16:19:38 +08:00
WuYongJie
51ff817dde fix(intake): 产品核价工作区接入受控列宽并修复长规格名称挤成多排 2026-09-29 16:18:19 +08:00
居居
791fcf083b style(supply-chain): 总览标签顺序恢复 S/A/B/C/D 2026-09-29 16:16:22 +08:00
居居
4cb5f9192a feat(supply-chain): 筛选栏新增运营部门负责人(含下拉候选) 2026-09-29 16:13:58 +08:00
居居
0f9bade034 feat(supply-chain): 总览维度改为运营部门负责人并支持联动筛选 2026-09-29 16:12:30 +08:00
居居
eedda35a29 fix(supply-chain): 补回被误删的 percent 格式化函数 2026-09-29 16:06:51 +08:00
居居
55d77fd989 style(supply-chain): 总览真实业绩统一按万元展示 2026-09-29 16:05:29 +08:00
居居
c45ec60635 style(supply-chain): 总览标签卡片与对比条按真实业绩降序 2026-09-29 16:04:55 +08:00
居居
efc437f0de feat(supply-chain): 维度汇总表展示全部分组,不再合并其他行 2026-09-29 16:04:23 +08:00
居居
3b1a629854 style(supply-chain): 维度汇总表去掉标签配色,与其他列保持一致 2026-09-29 16:03:08 +08:00
居居
a38aaef5d2 feat(supply-chain): 总览维度模块改为 S/A/B/C/D 数据汇总表 2026-09-29 16:01:06 +08:00
居居
7caa307042 style(supply-chain): 总览卡片保留数量与占比,对比条改为真实业绩(万)+业绩占比 2026-09-29 15:53:44 +08:00
居居
e0bad60b31 fix(supply-chain): 页面支持整体滚动,明细区不再被压扁 2026-09-29 15:48:53 +08:00
居居
8e0fc1d347 perf(supply-chain): 经营总览一次计算+短时缓存,首页刷新提速 2026-09-29 15:47:34 +08:00
居居
574f42c4ed fix(supply-chain): 修复筛选区与总览重叠,总览可点击联动明细 2026-09-29 15:42:45 +08:00
居居
5102516b10 feat(supply-chain): 经营总览新增维度对比与近6个月趋势 2026-09-29 15:37:14 +08:00
居居
189344626e feat(supply-chain): 经营总览改为 SABC 页内可折叠区块,移除独立页面与菜单 2026-09-29 15:35:24 +08:00
居居
fe6389a2a0 feat(supply-chain): 新增 SABC 经营总览(商品数 vs 业绩对比) 2026-09-29 15:31:48 +08:00
居居
9d53362466 style(supply-chain): SABC 筛选框固定单行排列,标签归位到行尾 2026-09-29 15:28:29 +08:00
居居
005cc37a65 style(supply-chain): SABC 筛选框按内容宽度排成一行 2026-09-29 15:26:57 +08:00
居居
2f081dd1f5 style(supply-chain): SABC 筛选改为圆角输入框样式 2026-09-29 15:25:10 +08:00
居居
b0701d8ae4 feat(supply-chain): 筛选候选取消服务端上限 2026-09-29 15:22:11 +08:00
居居
f0af29c62b fix(supply-chain): 筛选候选上限提高到 200,运营负责人等人员全部可选 2026-09-29 15:21:14 +08:00
居居
2a61ed2b34 style(supply-chain): 核算按钮移至核算月份后,查询/重置/导出统一按钮样式 2026-09-29 15:17:06 +08:00
WuYongJie
143dfe019d fix(layout): raise sidebar peek z-index above page content layers 2026-09-29 15:14:27 +08:00
WuYongJie
f5f4e2ec90 fix(layout): raise sidebar peek z-index above page content layers 2026-09-29 15:13:52 +08:00
居居
fefb1319c0 style(supply-chain): SABC 筛选头部与字段网格分离,消除空格 2026-09-29 15:05:35 +08:00
居居
cde8d617ad style(supply-chain): SABC 筛选区统一网格排版 2026-09-29 15:03:55 +08:00
居居
85c69041fe feat(supply-chain): SABC 新增运营负责人/采购/设计师筛选 2026-09-29 15:01:55 +08:00
居居
1762ba8387 feat(supply-chain): SABC 筛选字段支持下拉候选选择 2026-09-29 15:01:04 +08:00
居居
84515e895c feat(supply-chain): SABC 筛选改为人员信息页同款样式(字段网格 + 搜索/重置) 2026-09-29 14:57:58 +08:00
居居
852d42bf3a feat(supply-chain): SABC 筛选改为按字段独立输入框(支持批量、多字段取交集) 2026-09-29 14:53:59 +08:00
居居
8cd0f71ff7 feat(supply-chain): SABC 筛选支持批量查询,筛选区拆分为两行 2026-09-29 14:50:27 +08:00
WuYongJie
8c1c4bd938 feat(barcode-print): PLM 产品开发视图每日同步正式站条码打印脚本 2026-09-29 14:44:04 +08:00
居居
b1c3ba3bda feat(supply-chain): 新老编码两侧均按自身+同款编码合并计算 2026-09-29 14:43:26 +08:00
居居
ea7c5a953c fix(supply-chain): 老编码按自身数据照常打标(与人工表一致) 2026-09-29 14:40:41 +08:00
居居
117a5b2947 feat(supply-chain): 人员字段以正式库档案为准同步 2026-09-29 14:02:09 +08:00
居居
2dbc455b86 feat(supply-chain): 每日任务新增运营总负责人映射步骤 2026-09-29 14:00:19 +08:00
居居
c59647ac9f feat(supply-chain): SABC 页面新增运营/供应商/采购/设计师字段(置于创建时间前) 2026-09-29 13:44:40 +08:00
居居
7b3a7acb12 feat(supply-chain): 是否考核动销按产品类型判定(OEM 考核,其余不考核) 2026-09-29 13:40:36 +08:00
居居
95f5915c6a fix(supply-chain): 同款编码只展示单个编码,自映射规则不重复计算 2026-09-29 13:34:47 +08:00
居居
ff1ea6ce24 feat(supply-chain): 同款商品编码按替换款管理合并业绩与费比 2026-09-29 13:21:45 +08:00
WuYongJie
5eb7d4b1aa fix(layout): cast keydown target to HTMLElement for isContentEditable check 2026-09-29 13:18:15 +08:00
WuYongJie
d40cad8eed fix(layout): cast keydown target to HTMLElement for isContentEditable check 2026-09-29 13:18:06 +08:00
WuYongJie
110de56e7f feat(layout): add collapsible workbench sidebar with hover peek and space shortcut 2026-09-29 13:03:51 +08:00
WuYongJie
d7e348b236 merge origin/codex/xuxiake-mainline (employee-hours sync) 2026-09-29 13:03:09 +08:00
WuYongJie
b2f4242526 feat(layout): add collapsible workbench sidebar with hover peek and space shortcut 2026-09-29 13:03:04 +08:00
apple
4c771e0a82 feat(employee-hours): sync row copy and time entry improvements 2026-09-29 11:49:49 +08:00
apple
f6b8065580 feat(employee-hours): sync row copy and time entry improvements 2026-09-29 11:37:15 +08:00
WuYongJie
db01d9e445 fix(intake): 样包测量/产品限价/首批质检列宽整列联动(受控列宽) 2026-09-29 11:27:18 +08:00
WuYongJie
eb6fa9d672 fix(intake): 样包测量/产品限价/首批质检列宽整列联动(受控列宽) 2026-09-29 11:25:55 +08:00
居居
4c518b054e feat(supply-chain): SABC 不考核原因改用档案产品类型,并纳入每日回填 2026-09-29 11:19:17 +08:00
居居
9ae9423742 feat(supply-chain): 每日同步新增正式库类目档位配置步骤 2026-09-29 10:20:18 +08:00
居居
b976f075ff Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/xuxiake-sabc-sync-20260929
# Conflicts:
#	furniture-3d-system/prisma/schema.prisma
#	furniture-3d-system/src/server/repositories/supply-chain-product-archive-category-scale-row.repository.ts
#	furniture-3d-system/src/server/repositories/supply-chain-product-archive-sales-period.repository.ts
2026-09-29 10:14:29 +08:00
居居
648b1eee8d feat(supply-chain): 商品SABC打标(同步开发线前的本地快照) 2026-09-29 10:10:16 +08:00
WuYongJie
749c28452c Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/local-3001-integration 2026-09-29 09:44:02 +08:00
WuYongJie
f2dfcf1419 feat(supply-chain): 产品全量档案新增「售后金额」列(after_sale_amount 按日/月/年周期聚合) 2026-09-28 18:13:15 +08:00
WuYongJie
0e85656279 feat(supply-chain): 产品全量档案新增「售后金额」列(after_sale_amount 按日/月/年周期聚合) 2026-09-28 18:12:31 +08:00
WuYongJie
fe99b46eef feat(supply-chain): 产品全量档案新增「售后金额」列(after_sale_amount 按日/月/年周期聚合) 2026-09-28 18:11:43 +08:00
WuYongJie
afbb7b3aad feat(supply-chain): refresh product type in daily archive sync
在每日产品档案同步链路中追加「产品类型」刷新步骤(定厂优先、JST vc_name 兜底),复用既有 timer 与库身份校验,无需单独回填或新增定时任务。
2026-09-28 17:00:23 +08:00
WuYongJie
7384163a2c feat(supply-chain): refresh product type in daily archive sync
在每日产品档案同步链路中追加「产品类型」刷新步骤(定厂优先、JST vc_name 兜底),复用既有 timer 与库身份校验,无需单独回填或新增定时任务。
2026-09-28 17:00:17 +08:00
WuYongJie
c473825b3d feat(supply-chain): refresh product type in daily archive sync
在每日产品档案同步链路中追加「产品类型」刷新步骤(定厂优先、JST vc_name 兜底),复用既有 timer 与库身份校验,无需单独回填或新增定时任务。
2026-09-28 17:00:08 +08:00
WuYongJie
5664958dfb feat(supply-chain): add product type column to product archive
产品全量档案在「商品状态」后新增「产品类型」:定厂「产品生产类型」(IntakeNonIntegratedProduct.payload.factoryRows[].productionType) 优先,rpt.jst_sku.vc_name 兜底,按条码对应,都没有留空;值原样写入。附迁移、筛选与回填脚本。
2026-09-28 16:31:09 +08:00
WuYongJie
199be5d7cb feat(supply-chain): add product type column to product archive
产品全量档案在「商品状态」后新增「产品类型」:定厂「产品生产类型」(IntakeNonIntegratedProduct.payload.factoryRows[].productionType) 优先,rpt.jst_sku.vc_name 兜底,按条码对应,都没有留空;值原样写入。附迁移、筛选与回填脚本。
2026-09-28 16:30:55 +08:00
WuYongJie
51c6c9f20b feat(supply-chain): add product type column to product archive
产品全量档案在「商品状态」后新增「产品类型」:定厂「产品生产类型」(IntakeNonIntegratedProduct.payload.factoryRows[].productionType) 优先,rpt.jst_sku.vc_name 兜底,按条码对应,都没有留空;值原样写入。附迁移、筛选与回填脚本。
2026-09-28 16:30:14 +08:00
WuYongJie
8b76cd57db feat(product-archive): 新增「销售金额」表头字段(取每日快照 sales_amount)
- 列表「数据信息」分组新增「销售金额」,位置固定在「真实业绩」前一列
- 取值来自每日快照表 SupplyChainProductArchiveSalesPerformanceDaily.sales_amount,
  与发货金额/退货金额/真实业绩走同一链路,随页面 日/月/年 周期聚合
- 表头漏斗支持按销售金额筛选(可搜索多选标准弹层),列设置/详情弹窗/资料导出随列配置自动生效,
  字段总数 89 → 90
- 新增一次性 localStorage 列序迁移,把上线前保存过的列设置里的新列挪回「真实业绩」前
- 不改数据库结构、不改每日同步脚本;旧的全周期汇总表不加列、不回填
2026-09-28 16:02:45 +08:00
WuYongJie
3f36d2b51e feat(product-archive): 新增「销售金额」表头字段(取每日快照 sales_amount)
- 列表「数据信息」分组新增「销售金额」,位置固定在「真实业绩」前一列
- 取值来自每日快照表 SupplyChainProductArchiveSalesPerformanceDaily.sales_amount,
  与发货金额/退货金额/真实业绩走同一链路,随页面 日/月/年 周期聚合
- 表头漏斗支持按销售金额筛选(可搜索多选标准弹层),列设置/详情弹窗/资料导出随列配置自动生效,
  字段总数 89 → 90
- 新增一次性 localStorage 列序迁移,把上线前保存过的列设置里的新列挪回「真实业绩」前
- 不改数据库结构、不改每日同步脚本;旧的全周期汇总表不加列、不回填
2026-09-28 16:02:22 +08:00
apple
0fde0bfe4b feat(employee-hours): add resizable columns and category import 2026-09-28 15:39:40 +08:00
codex
61a4d81658 feat(store-account): 新增账号按人员信息带出负责人层级,修复自动填充残留并明文显示密码 2026-09-28 14:58:24 +08:00
codex
2c4949f1cc feat(store-account): 新增账号按人员信息带出负责人层级,修复自动填充残留并明文显示密码 2026-09-28 14:58:13 +08:00
codex
c89e4248f0 feat(store-account): 新增账号按人员信息带出负责人层级,修复自动填充残留并明文显示密码 2026-09-28 14:57:53 +08:00
WuYongJie
2b14e8863e feat(supply-chain): sync product archive designer from js_sku_info_manage
按 barcode=sku_id 从 rpt.js_sku_info_manage 回填产品全量档案 designer:空值补来源值,冲突行按用户口径取辛环;写入 fieldSourceMap=JST_SKU_INFO_MANAGE 并保留来源记录。附正式站 systemd timer 安装脚本(每天 09:00 Asia/Shanghai)。
2026-09-28 14:45:30 +08:00
WuYongJie
97d618a25d feat(supply-chain): sync product archive designer from js_sku_info_manage
按 barcode=sku_id 从 rpt.js_sku_info_manage 回填产品全量档案 designer:空值补来源值,冲突行按用户口径取辛环;写入 fieldSourceMap=JST_SKU_INFO_MANAGE 并保留来源记录。附正式站 systemd timer 安装脚本(每天 09:00 Asia/Shanghai)。
2026-09-28 14:45:11 +08:00
WuYongJie
5f4170919d feat(supply-chain): sync product archive designer from js_sku_info_manage
按 barcode=sku_id 从 rpt.js_sku_info_manage 回填产品全量档案 designer:空值补来源值,冲突行按用户口径取辛环;写入 fieldSourceMap=JST_SKU_INFO_MANAGE 并保留来源记录。附正式站 systemd timer 安装脚本(每天 09:00 Asia/Shanghai)。
2026-09-28 14:44:54 +08:00
WuYongJie
b01a5bb574 fix(supplier-recommended): use upstream image search defaults 2026-09-28 14:22:40 +08:00
WuYongJie
da3a49f03f fix(supplier-recommended): use upstream image search defaults 2026-09-28 14:19:21 +08:00
apple
a2dab2cd49 feat(employee-hours): add resizable columns and category import 2026-09-28 14:15:33 +08:00
WuYongJie
a4e577e376 fix(supplier-recommended): use upstream image search defaults 2026-09-28 14:09:50 +08:00
WuYongJie
4f12fdfcac fix(intake): 分销部纳入运营负责人候选名单并默认归运营
1. intake-owner-options.service.ts: operation 口径在路径含运营中心之外,增加 江苏简尚品牌管理有限公司>分销部,SPU负责人与运营负责人共用该名单,运营中心原口径不变。

2. business-role-inference.ts: 分销部从 EXCLUDED_ROOTS 移出,改为默认归 OPERATIONS,避免每日花名册同步把分销部在职员工打回普通用户。
2026-09-28 12:35:36 +08:00
WuYongJie
4fb7802eb4 fix(intake): 分销部纳入运营负责人候选名单并默认归运营
1. intake-owner-options.service.ts: operation 口径在路径含运营中心之外,增加 江苏简尚品牌管理有限公司>分销部,SPU负责人与运营负责人共用该名单,运营中心原口径不变。

2. business-role-inference.ts: 分销部从 EXCLUDED_ROOTS 移出,改为默认归 OPERATIONS,避免每日花名册同步把分销部在职员工打回普通用户。
2026-09-28 12:35:21 +08:00
WuYongJie
d1aa93e17f fix(intake): 分销部纳入运营负责人候选名单并默认归运营
1. intake-owner-options.service.ts: operation 口径在路径含运营中心之外,增加 江苏简尚品牌管理有限公司>分销部,SPU负责人与运营负责人共用该名单,运营中心原口径不变。

2. business-role-inference.ts: 分销部从 EXCLUDED_ROOTS 移出,改为默认归 OPERATIONS,避免每日花名册同步把分销部在职员工打回普通用户。
2026-09-28 12:35:10 +08:00
apple
6a52c0aa4b feat(employee-hours): make business selector resizable 2026-09-28 09:27:59 +08:00
apple
daa0abbf03 feat(employee-hours): make business selector resizable 2026-09-28 09:00:22 +08:00
WuYongJie
48fcd34608 Revert "fix(deploy): support interactive password authentication"
This reverts commit d2f965611c15838a5b3e3e1f32cf1a5dbe7091bb.
2026-09-27 17:18:29 +08:00
WuYongJie
80f82d8ff0 fix(employee-hours): normalize attachment URLs before save 2026-09-27 17:14:02 +08:00
WuYongJie
9d7023df4a fix(employee-hours): normalize attachment URLs before save 2026-09-27 17:11:37 +08:00
WuYongJie
d2f965611c fix(deploy): support interactive password authentication 2026-09-27 17:10:21 +08:00
WuYongJie
a87a8b50b3 fix(employee-hours): normalize attachment URLs before save 2026-09-27 17:09:52 +08:00
WuYongJie
13e1dcb7b2 feat(barcode-print): 顾家模板改名「顾家(6x4)」并修复默认选中乱码匹配
- 下拉选项「顾家」改为「顾家(6x4)」(模板本身为 60mm×40mm 纸张)
2026-09-27 16:12:52 +08:00
WuYongJie
68b310f646 feat(store-account): add authorization status and header filters 2026-09-27 16:12:35 +08:00
WuYongJie
f9c32930da feat(barcode-print): 顾家模板改名「顾家(6x4)」并修复默认选中乱码匹配
- 下拉选项「顾家」改为「顾家(6x4)」(模板本身为 60mm×40mm 纸张)
2026-09-27 16:09:42 +08:00
WuYongJie
2ba2a37232 feat(store-account): add authorization status and header filters 2026-09-27 16:08:43 +08:00
apple
5a59e727c0 feat(employee-hours): complete statistics and ranking workflow 2026-09-27 15:40:53 +08:00
WuYongJie
52ab8578e5 feat(barcode-print): 顾家模板改名「顾家(6x4)」并修复默认选中乱码匹配
- 下拉选项「顾家」改为「顾家(6x4)」(模板本身为 60mm×40mm 纸张)
2026-09-27 15:32:06 +08:00
WuYongJie
4e52997d64 feat(layout): 侧栏分组归类与首页、操作日志体验统一
1) 首页快捷网址子项去图标改4px圆点(产品开发/供应链双侧栏共用生效)
2) 工作台选择卡片只留图标与名称,去掉描述小字
3) 产品开发侧栏按 新品流程/AI生图/模块化/仓库管理 分组(默认展开可折叠,一级带图标统一14px,二级圆点13px,BOM核算归新品流程),手机端下拉同步
4) /intake/operation-logs 去左侧栏,固定返回链接改为返回上一步按钮(无历史兜底/intake)
2026-09-27 15:20:20 +08:00
WuYongJie
ccf8b6480f feat(layout): 侧栏分组归类与首页、操作日志体验统一
1) 首页快捷网址子项去图标改4px圆点(产品开发/供应链双侧栏共用生效)
2) 工作台选择卡片只留图标与名称,去掉描述小字
3) 产品开发侧栏按 新品流程/AI生图/模块化/仓库管理 分组(默认展开可折叠,一级带图标统一14px,二级圆点13px,BOM核算归新品流程),手机端下拉同步
4) /intake/operation-logs 去左侧栏,固定返回链接改为返回上一步按钮(无历史兜底/intake)
2026-09-27 15:20:03 +08:00
apple
b96dfe9780 feat(employee-hours): complete statistics and ranking workflow 2026-09-27 14:30:00 +08:00
WuYongJie
aee6dc6c8f feat(store-account): add batch delete 2026-09-27 13:44:31 +08:00
WuYongJie
010cd87601 feat(store-account): add batch delete 2026-09-27 13:42:59 +08:00
WuYongJie
5013d709e4 feat(store-account): add batch delete 2026-09-27 13:41:04 +08:00
WuYongJie
ca0e2d884c fix(intake): persist AB package grouping and set counts 2026-09-27 13:14:50 +08:00
WuYongJie
02843032d2 fix(intake): persist AB package grouping and set counts 2026-09-27 13:13:28 +08:00
WuYongJie
90eebbc74d fix(intake): persist AB package grouping and set counts 2026-09-27 13:10:02 +08:00
WuYongJie
f988334005 style(warehouse-config): 表头靠左,筛选图标后置对齐产品全量档案 2026-09-27 12:33:04 +08:00
WuYongJie
e6545b6eae style(warehouse-config): 表头靠左,筛选图标后置对齐产品全量档案 2026-09-27 12:32:48 +08:00
WuYongJie
0cb88569d8 style(warehouse-config): 表头靠左,筛选图标后置对齐产品全量档案 2026-09-27 12:32:45 +08:00
WuYongJie
f9ff4af8c5 refactor(employee-hours): 工时独立业务配置表,与工作记录解耦
- 新增 EmployeeHoursBusinessOption/EmployeeHoursScoreRule 独立配置表与迁移
2026-09-27 11:37:39 +08:00
WuYongJie
3bd5384699 refactor(employee-hours): 工时独立业务配置表,与工作记录解耦
- 新增 EmployeeHoursBusinessOption/EmployeeHoursScoreRule 独立配置表与迁移
2026-09-27 11:36:16 +08:00
WuYongJie
5af8c6c539 refactor(employee-hours): 工时独立业务配置表,与工作记录解耦
- 新增 EmployeeHoursBusinessOption/EmployeeHoursScoreRule 独立配置表与迁移
2026-09-27 11:36:01 +08:00
WuYongJie
6f63f3936e Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/local-3001-integration 2026-09-27 10:59:34 +08:00
WuYongJie
7fa65e3309 feat(warehouse-config): 导入导出+聚水潭字典候选+采购负责人回填+表头筛选改造
- 导入导出:模板下载/NDJSON流式导入(名称upsert+逐行报错)/ExcelJS导出,均跟随筛选
2026-09-27 10:40:24 +08:00
WuYongJie
997efc1084 feat(warehouse-config): 导入导出+聚水潭字典候选+采购负责人回填+表头筛选改造
- 导入导出:模板下载/NDJSON流式导入(名称upsert+逐行报错)/ExcelJS导出,均跟随筛选
2026-09-27 10:40:01 +08:00
WuYongJie
36493b75f8 feat(warehouse-config): 导入导出+聚水潭字典候选+采购负责人回填+表头筛选改造
- 导入导出:模板下载/NDJSON流式导入(名称upsert+逐行报错)/ExcelJS导出,均跟随筛选
2026-09-27 10:39:45 +08:00
WuYongJie
001a1e919e fix(intake): skip unconfigured jushuitan virtual inventory 2026-09-27 10:22:31 +08:00
WuYongJie
1422c2f5fa fix(intake): skip unconfigured jushuitan virtual inventory 2026-09-27 10:21:02 +08:00
WuYongJie
427448f48e fix(intake): skip unconfigured jushuitan virtual inventory 2026-09-27 10:19:53 +08:00
WuYongJie
218517d5af fix(build): keep upload route constants private 2026-09-27 10:01:21 +08:00
apple
3e31bcf29e feat(supply-chain): add employee hours statistics 2026-09-27 09:22:12 +08:00
apple
2e3a36b25d feat(supply-chain): add employee hours statistics 2026-09-24 19:49:35 +08:00
WuYongJie
842bdd3967 style(category-config): 重置按钮去图标纯文字 2026-09-24 18:04:58 +08:00
WuYongJie
0b7cb58418 style(category-config): 重置按钮去图标纯文字 2026-09-24 18:04:45 +08:00
WuYongJie
e3e572657a feat(category-config): 筛选栏增加重置按钮(清空搜索/分类/规模标签并回第一页) 2026-09-24 18:03:12 +08:00
WuYongJie
ab817eddfa feat(category-config): 筛选栏增加重置按钮(清空搜索/分类/规模标签并回第一页) 2026-09-24 18:02:59 +08:00
WuYongJie
3dcdeb5cf1 docs(数据字典): 类目配置更新为单表合并结构(两表口径+取数方式+消费方) 2026-09-24 17:34:49 +08:00
WuYongJie
0a2e0484b3 fix(category-config): buildRowInput 分类入参改可选(生产构建类型对齐) 2026-09-24 17:27:12 +08:00
WuYongJie
01cf89cd01 fix(category-config): buildRowInput 分类入参改可选(生产构建类型对齐) 2026-09-24 17:26:59 +08:00
WuYongJie
5984179dc9 fix(category-config): 规模行服务入参分类改为可选以匹配路由校验 2026-09-24 17:21:21 +08:00
WuYongJie
f75b05bda1 fix(category-config): 规模行服务入参分类改为可选以匹配路由校验 2026-09-24 17:20:59 +08:00
WuYongJie
9e7f8914f0 fix(category-config): 移除对已删除规模行生成方法的残留调用 2026-09-24 17:13:21 +08:00
WuYongJie
a45c691428 fix(category-config): 移除对已删除规模行生成方法的残留调用 2026-09-24 17:12:27 +08:00
WuYongJie
fff6675c7a refactor(category-config): 类目规模合并为单表展示结构(一级类目/分类并入规模行,移除分类档位模板表) 2026-09-24 17:07:00 +08:00
WuYongJie
9e91f18dfd refactor(category-config): 类目规模合并为单表展示结构(一级类目/分类并入规模行,移除分类档位模板表) 2026-09-24 17:06:41 +08:00
WuYongJie
2af84fd9ce feat(intake): allow manual installation asset ordering 2026-09-24 16:36:24 +08:00
WuYongJie
9808224718 fix(category-config): 规模行导入同步一级类目与分类到类目配置;档位导入表头兼容带单位列名 2026-09-24 16:32:53 +08:00
WuYongJie
cb3efaa50c fix(category-config): 规模行导入同步一级类目与分类到类目配置;档位导入表头兼容带单位列名 2026-09-24 16:31:44 +08:00
WuYongJie
d52fd19c49 fix(category-config): 规模行导入同步一级类目与分类到类目配置(留空保留原值) 2026-09-24 15:47:04 +08:00
WuYongJie
eb6a2e6571 fix(category-config): 规模行导入同步一级类目与分类到类目配置(留空保留原值) 2026-09-24 15:46:30 +08:00
WuYongJie
ebf9e6a6c4 fix(category-config): 规模行导入表头对齐导出格式(含一级类目/分类/带单位列名)
导入、导出、下载模板三处表头统一为导出格式;导入兼容带单位列名(业绩起点(元)/日销起点(件/天)),一级类目与分类列接受但忽略
2026-09-24 15:02:12 +08:00
WuYongJie
d42d500071 fix(category-config): 规模行导入表头对齐导出格式(含一级类目/分类/带单位列名)
导入、导出、下载模板三处表头统一为导出格式;导入兼容带单位列名(业绩起点(元)/日销起点(件/天)),一级类目与分类列接受但忽略
2026-09-24 15:00:27 +08:00
WuYongJie
e8a374e93c feat(category-config): 类目配置增加分类、规模标签与业绩/日销阈值(含导入导出与删除)
- 类目配置单表新增:分类、规模标签、业绩起点/终点、日销起点/终点,操作列含编辑/删除
2026-09-24 14:36:43 +08:00
WuYongJie
fddf877d9e feat(category-config): 类目配置增加分类、规模标签与业绩/日销阈值(含导入导出与删除)
- 类目配置单表新增:分类、规模标签、业绩起点/终点、日销起点/终点,操作列含编辑/删除
2026-09-24 14:35:46 +08:00
WuYongJie
cc7219a24e feat(intake): sync installation assets to drawing system by ID
(cherry picked from commit c066c60494a9103e3d33655cbe09a0b7e03ffb18)
2026-09-24 13:37:30 +08:00
WuYongJie
c066c60494 feat(intake): sync installation assets to drawing system by ID 2026-09-24 13:35:04 +08:00
WuYongJie
9875a28716 feat(product-archive): include intake products in base sync and add 08:20 timer 2026-09-24 11:50:09 +08:00
WuYongJie
97a173eb9c Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/local-3001-integration 2026-09-24 11:48:37 +08:00
WuYongJie
a8b6d31c5e feat(product-archive): include intake products in base sync and add 08:20 timer 2026-09-24 10:56:21 +08:00
WuYongJie
46d0521105 merge: release DingTalk login resilience 2026-09-24 09:56:24 +08:00
WuYongJie
44be8f58b8 fix(auth): harden DingTalk login network failures 2026-09-24 09:50:38 +08:00
WuYongJie
02a25b1e75 修复:补齐创建人解析服务缺失的 ResolutionCache 类型声明(服务器构建失败根因) 2026-09-23 17:29:38 +08:00
WuYongJie
2d4965dfc7 修复:补齐创建人解析服务缺失的 ResolutionCache 类型声明(服务器构建失败根因) 2026-09-23 17:29:09 +08:00
WuYongJie
272219a4eb 1688代发异常事项:创建人列(纳廷创建人+人员信息在职校验+离职/兜底解析链)与业绩范围切换 2026-09-23 17:20:32 +08:00
WuYongJie
da4be64bfe 1688代发异常事项:创建人列(纳廷创建人+人员信息在职校验+离职/兜底解析链)与业绩范围切换 2026-09-23 17:20:05 +08:00
WuYongJie
c9431b7e26 feat(supply-chain): 店铺状态落库(StoreAccount.shopState 列 + 每日同步任务) 2026-09-23 14:05:25 +08:00
WuYongJie
a93159dddc feat(supply-chain): 店铺状态落库(StoreAccount.shopState 列 + 每日同步任务) 2026-09-23 14:03:13 +08:00
WuYongJie
1b293985d6 1688代发异常事项:上传图纸改为页内直传图纸系统(条码分组绑定V01/V02)并接入每日图纸对账 2026-09-23 13:16:56 +08:00
WuYongJie
291485dbda 1688代发异常事项:上传图纸改为页内直传图纸系统(条码分组绑定V01/V02)并接入每日图纸对账 2026-09-23 13:16:08 +08:00
WuYongJie
aff07c4375 feat(intake): support batch lead time with row overrides 2026-09-23 13:15:43 +08:00
WuYongJie
84ac3ed6a4 feat(intake): support batch lead time with row overrides 2026-09-23 13:14:21 +08:00
WuYongJie
791f6bfa40 feat(supply-chain): 店铺账号管理新增店铺状态列与筛选(实时取公司报表库 rpt.fys_shopInfo) 2026-09-23 12:45:04 +08:00
WuYongJie
eabc26a044 feat(supply-chain): 店铺账号管理新增店铺状态列与筛选(实时取公司报表库 rpt.fys_shopInfo) 2026-09-23 12:40:33 +08:00
WuYongJie
4b800d0b3b Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/wuyongjie-main-merge
# Conflicts:
#	furniture-3d-system/docs/workflow/生产部署入口说明.md
#	furniture-3d-system/scripts/install-dingtalk-directory-sync-timer.sh
#	furniture-3d-system/src/server/services/download-center/download-center.service.ts
2026-09-23 10:48:04 +08:00
WuYongJie
3d22d627fb fix(auth): separate DingTalk login credentials from API credentials 2026-09-23 10:43:16 +08:00
WuYongJie
fa17ffa9a8 fix(download-center): 生成中删除任务时丢弃产物,并忽略本地运行目录 2026-09-23 09:48:21 +08:00
WuYongJie
159035f98a fix(download-center): correct error code enum and failAllActive return shape 2026-09-22 17:40:30 +08:00
WuYongJie
8a95dbcbf0 fix(download-center): correct error code enum and failAllActive return shape 2026-09-22 17:40:21 +08:00
WuYongJie
71a7f0a09a feat(supply-chain): global download center with background export tasks 2026-09-22 17:32:53 +08:00
WuYongJie
9bfc3e826f feat(product-archive): factory stock column and ops-owner hierarchy rework 2026-09-22 17:32:53 +08:00
WuYongJie
89ed5ee355 chore(sync): schedule product archive source sync daily at 08:10 2026-09-22 17:32:53 +08:00
WuYongJie
24c668e1c8 feat(supply-chain): global download center with background export tasks 2026-09-22 17:32:32 +08:00
WuYongJie
870632bd5e feat(product-archive): factory stock column and ops-owner hierarchy rework 2026-09-22 17:32:23 +08:00
WuYongJie
152df22a1a chore(sync): schedule product archive source sync daily at 08:10 2026-09-22 17:32:10 +08:00
WuYongJie
6e35bb42ee chore(product-archive): 补提交发货方式历史数据回填脚本 2026-09-22 15:53:29 +08:00
WuYongJie
6f55f490f6 fix(supply-chain): complete personnel information source sync
(content-sync from origin/codex/xuxiake-mainline 0f52aca9)
2026-09-22 12:48:12 +08:00
居居
0f52aca923 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/xuxiake-mainline 2026-09-22 12:01:43 +08:00
居居
c0cc39a565 fix(supply-chain): complete personnel information source sync 2026-09-22 11:59:28 +08:00
WuYongJie
41030ec7f2 feat(oa-board): 流程状态筛选新增「全部」口径
流程状态下拉新增「全部」:overallStatus=__all__ 时服务端与客户端过滤均跳过状态限制,包含已驳回、已终止、已取消及无状态标记数据;默认口径(进行中+已完成)不变,导出明细同口径生效。
2026-09-22 11:29:19 +08:00
WuYongJie
687e80b6cd feat(oa-board): 流程状态筛选新增「全部」口径
流程状态下拉新增「全部」:overallStatus=__all__ 时服务端与客户端过滤均跳过状态限制,包含已驳回、已终止、已取消及无状态标记数据;默认口径(进行中+已完成)不变,导出明细同口径生效。
2026-09-22 11:24:16 +08:00
居居
5512be5371 fix(supply-chain): 固化人员信息界面配置 2026-09-22 11:08:10 +08:00
居居
7b5f66dfcf fix(supply-chain): 固化人员信息界面配置 2026-09-22 10:33:18 +08:00
Codex
271c7b24b4 feat(supplier-recommended): add image similarity search 2026-09-22 10:20:05 +08:00
Codex
f94286464b feat(supplier-recommended): add image similarity search 2026-09-22 10:17:35 +08:00
WuYongJie
e3dcc2463a Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into HEAD 2026-09-21 21:27:48 +08:00
WuYongJie
4b54f3e531 fix(sync): guard against null skuoid rows in dws ops owners listing 2026-09-21 21:27:19 +08:00
WuYongJie
669fbd63fd Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into HEAD 2026-09-21 20:58:35 +08:00
WuYongJie
191e050374 fix(sync): drop server-only marker imports from the archive sync dependency chain 2026-09-21 20:58:07 +08:00
WuYongJie
9e0081724e Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into HEAD 2026-09-21 20:35:51 +08:00
WuYongJie
fd3b451af9 chore(sync): log full stack on enrichment failures 2026-09-21 20:34:25 +08:00
WuYongJie
616f985dee Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into HEAD 2026-09-21 19:28:31 +08:00
WuYongJie
16587f62af fix(sync): alias server-only to an empty stub for plain-node tooling runs 2026-09-21 19:28:06 +08:00
WuYongJie
f57fd6d354 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into HEAD 2026-09-21 19:15:48 +08:00
WuYongJie
407946d5d2 chore(sync): record server-only and uuid in the deploy lock file 2026-09-21 19:15:24 +08:00
WuYongJie
37d09f0ca1 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into HEAD 2026-09-21 19:11:37 +08:00
WuYongJie
3269f4409f fix(sync): declare server-only and uuid deps and drop the marker import so node-side scripts can run 2026-09-21 19:11:12 +08:00
WuYongJie
65b32ce405 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into HEAD 2026-09-21 17:36:54 +08:00
WuYongJie
c4943e6b04 fix(product-archive): include stat_date in ops owners group by to unblock daily sync 2026-09-21 17:35:36 +08:00
居居
475478b273 feat(supply-chain): 新增人员信息与钉钉组织同步 2026-09-21 16:38:13 +08:00
WuYongJie
ec807b3217 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/local-3001-integration
# Conflicts:
#	furniture-3d-system/prisma/schema.prisma
#	furniture-3d-system/src/app/api/supply-chain/new-products/dropship-issues/route.test.ts
#	furniture-3d-system/src/app/api/supply-chain/new-products/dropship-issues/route.ts
#	furniture-3d-system/src/app/api/supply-chain/new-products/dropship-issues/update/route.test.ts
#	furniture-3d-system/src/app/api/supply-chain/new-products/dropship-issues/update/route.ts
#	furniture-3d-system/src/app/supply-chain/config/supply-chain-menu.test.ts
#	furniture-3d-system/src/app/supply-chain/new-products/dropship-issues/DropshipIssueEditDialog.tsx
#	furniture-3d-system/src/app/supply-chain/new-products/dropship-issues/DropshipIssuesPagination.tsx
#	furniture-3d-system/src/app/supply-chain/new-products/dropship-issues/DropshipIssuesTable.tsx
#	furniture-3d-system/src/app/supply-chain/new-products/dropship-issues/DropshipOpsFilter.tsx
#	furniture-3d-system/src/app/supply-chain/new-products/dropship-issues/DropshipSkuPanel.tsx
#	furniture-3d-system/src/app/supply-chain/new-products/dropship-issues/dropship-issues.module.css
#	furniture-3d-system/src/app/supply-chain/new-products/dropship-issues/page.tsx
#	furniture-3d-system/src/app/supply-chain/new-products/dropship-issues/types.ts
#	furniture-3d-system/src/lib/supply-chain-permission-settings.test.ts
#	furniture-3d-system/src/lib/supply-chain-permission-settings.ts
#	furniture-3d-system/src/server/repositories/supply-chain-dropship-issue.repository.ts
#	furniture-3d-system/src/server/services/__tests__/supply-chain-dropship-issue.service.test.ts
#	furniture-3d-system/src/server/services/supply-chain-dropship-issue.service.ts
2026-09-21 15:58:02 +08:00
居居
e9cb61e18c Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/xuxiake-mainline 2026-09-21 14:25:22 +08:00
居居
1cf72e3c81 feat(supply-chain): 新增人员信息与钉钉组织同步 2026-09-21 14:25:05 +08:00
WuYongJie
4df5e800fe fix(1688): show zero for missing cost values
(cherry picked from commit ce48ab7944bed1a81c29eb36145bcd9d76bf01f8)
2026-09-21 11:50:13 +08:00
WuYongJie
ce48ab7944 fix(1688): show zero for missing cost values 2026-09-21 11:42:05 +08:00
WuYongJie
bb730dd533 安装演示工作台 5 项 bug 根因修复接手
(cherry picked from commit 073437c8bfe809f3992bb1a5288aa2c57f3c3567)
2026-09-21 11:33:53 +08:00
WuYongJie
073437c8bf 安装演示工作台 5 项 bug 根因修复接手 2026-09-21 11:02:32 +08:00
WuYongJie
b92d56c090 feat(intake): extend barcode import permissions
(cherry picked from commit d4778d29e9f618745f0777335336dd8986614d9f)
2026-09-21 11:01:48 +08:00
WuYongJie
d4778d29e9 feat(intake): extend barcode import permissions 2026-09-21 10:54:14 +08:00
WuYongJie
ba5eeaea33 feat(supply-chain): add estimated freight to 1688 dropship data
Task: supply-chain-1688-freight-inclusive-unit-cost-20260918
(cherry picked from commit 4450ac5ce610a45c5c06f7cced6bfa7a2f4af82a)
2026-09-21 10:00:40 +08:00
WuYongJie
4450ac5ce6 feat(supply-chain): add estimated freight to 1688 dropship data
Task: supply-chain-1688-freight-inclusive-unit-cost-20260918
2026-09-21 09:43:43 +08:00
WuYongJie
87a28cc5f7 fix(supply-chain): restore 1688 data menu order 2026-09-18 15:53:51 +08:00
WuYongJie
7d8f6d3848 fix(supply-chain): restore 1688 data menu order 2026-09-18 15:53:36 +08:00
WuYongJie
76420b8ecd fix(supply-chain): merge rapid 1688 field filters 2026-09-18 15:19:10 +08:00
伯阳
5a6f09b0df feat(supply-chain): complete 1688 dropship sourcing workflow 2026-09-18 15:18:56 +08:00
WuYongJie
009685cdd7 fix(supply-chain): merge rapid 1688 field filters 2026-09-18 15:16:55 +08:00
伯阳
9244b9d570 merge: sync xuxiake mainline for 1688 sourcing 2026-09-18 13:25:12 +08:00
伯阳
a22657e28e feat(supply-chain): complete 1688 dropship sourcing workflow 2026-09-18 11:17:47 +08:00
WuYongJie
446c550320 feat(operation-logs): 失败操作日志实时推送徐霞客
- 失败日志(FAILED/RETRY)写入后经壹点通知中心个人推送徐霞客
- 聚水潭固定虚拟库存错误码按 1 小时折叠成一条,其余按 动作+错误码+SPU+SKU 10 分钟合并
- 正文空行分段(钉钉 Markdown 会吞单个换行),纯文字无按钮
- record 挂载异步通知不阻塞业务,NODE_ENV=test 静默
- 新增带 worker 密钥的手动测试入口 /api/internal/operation-logs/failure-notification/run
2026-09-18 10:10:36 +08:00
WuYongJie
8ea81f886a feat(product-archive): 定厂「发货方式」同步进全量档案的入库/代发列
全量档案的「入库/代发」列(storageType)此前 73,278 行 100% 为空:产品定厂时
采购填的「发货方式」(入仓/代发)从来没有回流到档案表,列上没有任何来源映射。

规则(按用户口径):全量的入库/代发只有 代发/入仓 两个值——
- 新品(产品开发)定厂带了发货方式的,直接带进档案
- 没填的,等仓库配置同步兜底填空
- 无法识别的值(如 海运)不写,保持空

实现要点:
- sync.repository:产品开发来源的 SELECT/类型加 shipping_method;
  buildArchiveUpdate 白名单补 storageType(此前该列不在白名单里,值写不进档案表)
- sync.service:宽表 shipping_method 经 storageTypeFromShippingMethodLabel
  映射(入仓/入库→INBOUND、代发→DROPSHIP、无法识别→空串不动),
  仅非空时写入;fieldSourceMap 记 storageType ← shipping_method
- enrichment mapper:仓库配置来源拆成两条——warehouseHead 照常无条件更新;
  storageType 改 fillEmptyOnly(只填空),定厂带回的值不被仓库配置覆盖
- lib/values:新增 storageTypeFromShippingMethodLabel(入仓/入库→INBOUND、
  代发→DROPSHIP,兼容「入库」写法)
- 页面显示「入库」→「入仓」(与定厂填值一致)
- 测试:sync.service 加 3 用例;新增 warehouse-config-fill 套件 3 用例
  (已有值不覆盖 / 为空才填 / 初始化过不再重复应用);
  enrichment.service 计数断言 8→9 并补仓库配置两条的断言

验证:type-check EXIT=0;相关套件 sync 11 / enrichment 9 / warehouse-config-fill 3
全过;真库端到端——跑一次 XG0012 的产品开发同步,档案 storageType 从空变 INBOUND、
来源记 PRODUCT_DEVELOPMENT/shipping_method,再跑仓库配置 enrichment 后仍为 INBOUND
(不被覆盖);3001 真机按「入仓」筛选出 1 行、页面列显示「入仓」。
2026-09-18 10:10:36 +08:00
WuYongJie
f3f59adcbc 供应商新品推荐:页面默认视图改为明细数据 2026-09-18 10:10:36 +08:00
WuYongJie
b0bfd3d65a feat(operation-logs): 失败操作日志实时推送徐霞客
- 失败日志(FAILED/RETRY)写入后经壹点通知中心个人推送徐霞客
- 聚水潭固定虚拟库存错误码按 1 小时折叠成一条,其余按 动作+错误码+SPU+SKU 10 分钟合并
- 正文空行分段(钉钉 Markdown 会吞单个换行),纯文字无按钮
- record 挂载异步通知不阻塞业务,NODE_ENV=test 静默
- 新增带 worker 密钥的手动测试入口 /api/internal/operation-logs/failure-notification/run
2026-09-18 09:46:16 +08:00
WuYongJie
fc12269838 fix(jushuitan): batch fixed virtual inventory pushes 2026-09-18 09:39:26 +08:00
WuYongJie
9647a1f49f feat(operation-logs): 失败操作日志实时推送徐霞客
- 失败日志(FAILED/RETRY)写入后经壹点通知中心个人推送徐霞客
- 聚水潭固定虚拟库存错误码按 1 小时折叠成一条,其余按 动作+错误码+SPU+SKU 10 分钟合并
- 正文空行分段(钉钉 Markdown 会吞单个换行),纯文字无按钮
- record 挂载异步通知不阻塞业务,NODE_ENV=test 静默
- 新增带 worker 密钥的手动测试入口 /api/internal/operation-logs/failure-notification/run
2026-09-18 09:21:41 +08:00
WuYongJie
dc07310cda fix(jushuitan): batch fixed virtual inventory pushes 2026-09-18 09:20:17 +08:00
WuYongJie
e8f8087f78 fix(intake): 保存实时供应商目录映射 2026-09-17 17:28:08 +08:00
WuYongJie
be9f844c5a fix(intake): 保存实时供应商目录映射 2026-09-17 17:25:52 +08:00
WuYongJie
ca6e22ac66 feat(product-archive): 定厂「发货方式」同步进全量档案的入库/代发列
全量档案的「入库/代发」列(storageType)此前 73,278 行 100% 为空:产品定厂时
采购填的「发货方式」(入仓/代发)从来没有回流到档案表,列上没有任何来源映射。

规则(按用户口径):全量的入库/代发只有 代发/入仓 两个值——
- 新品(产品开发)定厂带了发货方式的,直接带进档案
- 没填的,等仓库配置同步兜底填空
- 无法识别的值(如 海运)不写,保持空

实现要点:
- sync.repository:产品开发来源的 SELECT/类型加 shipping_method;
  buildArchiveUpdate 白名单补 storageType(此前该列不在白名单里,值写不进档案表)
- sync.service:宽表 shipping_method 经 storageTypeFromShippingMethodLabel
  映射(入仓/入库→INBOUND、代发→DROPSHIP、无法识别→空串不动),
  仅非空时写入;fieldSourceMap 记 storageType ← shipping_method
- enrichment mapper:仓库配置来源拆成两条——warehouseHead 照常无条件更新;
  storageType 改 fillEmptyOnly(只填空),定厂带回的值不被仓库配置覆盖
- lib/values:新增 storageTypeFromShippingMethodLabel(入仓/入库→INBOUND、
  代发→DROPSHIP,兼容「入库」写法)
- 页面显示「入库」→「入仓」(与定厂填值一致)
- 测试:sync.service 加 3 用例;新增 warehouse-config-fill 套件 3 用例
  (已有值不覆盖 / 为空才填 / 初始化过不再重复应用);
  enrichment.service 计数断言 8→9 并补仓库配置两条的断言

验证:type-check EXIT=0;相关套件 sync 11 / enrichment 9 / warehouse-config-fill 3
全过;真库端到端——跑一次 XG0012 的产品开发同步,档案 storageType 从空变 INBOUND、
来源记 PRODUCT_DEVELOPMENT/shipping_method,再跑仓库配置 enrichment 后仍为 INBOUND
(不被覆盖);3001 真机按「入仓」筛选出 1 行、页面列显示「入仓」。
2026-09-17 16:58:54 +08:00
WuYongJie
8d38f07626 fix(intake): 修复大产品保存事务超时与聚水潭分批推送
- 非集成产品保存事务(formal SPU 主事务 / saveActiveWithLock / createRecord /
  updateRecord)统一加 { maxWait: 10s, timeout: 60s }:修复 224 SKU 大产品保存时
  Prisma 交互式事务超过默认 5s 触发 P2028 整笔回滚、页面提示保存成功但数据未落库
  的问题(正式站 LRSF0095 实际案例,单日 11 次保存失败,供应商数据全部丢失)
- 聚水潭商品资料推送分批:itemsku/upload 与 combinesku/upload 按每批 100 个 items
  推送(单次上限 200,LRSF0095 一次推 224 个被 code=130 拒绝),逐批成功落锁,
  中间批次失败抛 PartialFailureError 保护已成功 SKU
- 新增回归用例:250 SKU 断言 itemsku/upload 分 3 批(100/100/50)且总数无遗漏

验证:type-check 通过;intake-non-integrated-product.service.test.ts 108/108;
jushuitan-product-pricing-push.service.test.ts 33/34(唯一失败为既有环境问题)
2026-09-17 15:42:40 +08:00
WuYongJie
a310362839 fix(intake): 修复大产品保存事务超时与聚水潭分批推送
- 非集成产品保存事务(formal SPU 主事务 / saveActiveWithLock / createRecord /
  updateRecord)统一加 { maxWait: 10s, timeout: 60s }:修复 224 SKU 大产品保存时
  Prisma 交互式事务超过默认 5s 触发 P2028 整笔回滚、页面提示保存成功但数据未落库
  的问题(正式站 LRSF0095 实际案例,单日 11 次保存失败,供应商数据全部丢失)
- 聚水潭商品资料推送分批:itemsku/upload 与 combinesku/upload 按每批 100 个 items
  推送(单次上限 200,LRSF0095 一次推 224 个被 code=130 拒绝),逐批成功落锁,
  中间批次失败抛 PartialFailureError 保护已成功 SKU
- 新增回归用例:250 SKU 断言 itemsku/upload 分 3 批(100/100/50)且总数无遗漏

验证:type-check 通过;intake-non-integrated-product.service.test.ts 108/108;
jushuitan-product-pricing-push.service.test.ts 33/34(唯一失败为既有环境问题)
2026-09-17 15:37:45 +08:00
WuYongJie
14974d20ef fix(intake): 修复大产品保存事务超时与聚水潭分批推送
- 非集成产品保存事务(formal SPU 主事务 / saveActiveWithLock / createRecord /
  updateRecord)统一加 { maxWait: 10s, timeout: 60s }:修复 224 SKU 大产品保存时
  Prisma 交互式事务超过默认 5s 触发 P2028 整笔回滚、页面提示保存成功但数据未落库
  的问题(正式站 LRSF0095 实际案例,单日 11 次保存失败,供应商数据全部丢失)
- 聚水潭商品资料推送分批:itemsku/upload 与 combinesku/upload 按每批 100 个 items
  推送(单次上限 200,LRSF0095 一次推 224 个被 code=130 拒绝),逐批成功落锁,
  中间批次失败抛 PartialFailureError 保护已成功 SKU
- 新增回归用例:250 SKU 断言 itemsku/upload 分 3 批(100/100/50)且总数无遗漏

验证:type-check 通过;intake-non-integrated-product.service.test.ts 108/108;
jushuitan-product-pricing-push.service.test.ts 33/34(唯一失败为既有环境问题)
2026-09-17 15:36:22 +08:00
WuYongJie
26754ae266 供应商新品推荐:页面默认视图改为明细数据 2026-09-17 14:56:22 +08:00
WuYongJie
98482bccec feat(product-archive): 定厂「发货方式」同步进全量档案的入库/代发列
全量档案的「入库/代发」列(storageType)此前 73,278 行 100% 为空:产品定厂时
采购填的「发货方式」(入仓/代发)从来没有回流到档案表,列上没有任何来源映射。

规则(按用户口径):全量的入库/代发只有 代发/入仓 两个值——
- 新品(产品开发)定厂带了发货方式的,直接带进档案
- 没填的,等仓库配置同步兜底填空
- 无法识别的值(如 海运)不写,保持空

实现要点:
- sync.repository:产品开发来源的 SELECT/类型加 shipping_method;
  buildArchiveUpdate 白名单补 storageType(此前该列不在白名单里,值写不进档案表)
- sync.service:宽表 shipping_method 经 storageTypeFromShippingMethodLabel
  映射(入仓/入库→INBOUND、代发→DROPSHIP、无法识别→空串不动),
  仅非空时写入;fieldSourceMap 记 storageType ← shipping_method
- enrichment mapper:仓库配置来源拆成两条——warehouseHead 照常无条件更新;
  storageType 改 fillEmptyOnly(只填空),定厂带回的值不被仓库配置覆盖
- lib/values:新增 storageTypeFromShippingMethodLabel(入仓/入库→INBOUND、
  代发→DROPSHIP,兼容「入库」写法)
- 页面显示「入库」→「入仓」(与定厂填值一致)
- 测试:sync.service 加 3 用例;新增 warehouse-config-fill 套件 3 用例
  (已有值不覆盖 / 为空才填 / 初始化过不再重复应用);
  enrichment.service 计数断言 8→9 并补仓库配置两条的断言

验证:type-check EXIT=0;相关套件 sync 11 / enrichment 9 / warehouse-config-fill 3
全过;真库端到端——跑一次 XG0012 的产品开发同步,档案 storageType 从空变 INBOUND、
来源记 PRODUCT_DEVELOPMENT/shipping_method,再跑仓库配置 enrichment 后仍为 INBOUND
(不被覆盖);3001 真机按「入仓」筛选出 1 行、页面列显示「入仓」。
2026-09-17 14:55:11 +08:00
WuYongJie
ba930d1df2 feat(product-archive): SPU 列支持「只看正常编码」与可累加排除规则
产品全量档案的 SPU 列筛选原来只有「勾选具体值 = 包含」一种语义,没法表达
「不要 DF- 开头的 / 不要纯数字的」这类排除需求,只能靠不断放宽正选来绕。

新增两类能力(原有「勾选值包含」语义一字未改):
- 「只看正常编码」:字母前缀(2~6位) + 可选「-字母段」 + 数字编号(3~8位),
  一次收掉纯数字 / 1643A 型 / 含中文的商品名 / 32 位哈希等非正常形态
- 「排除以…开头」:可累加的前缀黑名单(如 WM- 外贸、DF- 代发、MKH),
  对应「还有不想看就再填一条」

实现要点:
- lib:新增 ProductArchiveTextFilterKey / ProductArchiveExcludeRule 与
  PRODUCT_ARCHIVE_NORMAL_CODE_PATTERN;ProductArchiveFilters 只追加
  normalCodeOnly、excludeStartsWith 两个可选字段,老字段类型与语义不动
- 校验:zod schema 是 .strict(),同步放行两个新字段(否则整包筛选会被 400 拒掉)
- 服务端:buildProductArchiveWhere 保持同步,只追加 NOT startsWith;
  需要查库的「正常编码」放在新增的异步 buildProductArchiveWhereWithTextRules
  (Prisma 7.3 的字符串过滤不支持 regex,改为原生 SQL 取符合形态的取值清单拼 IN,
  带 5 分钟缓存)。preparePeriodArchiveQuery 是全站唯一取数入口,
  列表、候选项、导出、图片导出自动生效
- 文本规则故意不参与 omitFilter:若参与,候选值列表会冒出已被排除的取值,
  用户勾了却得到 0 行
- UI:文本列弹层改左右双排(左=形态与排除规则,右=搜索与候选值),
  弹层高度与横向偏移按触发按钮所在位置动态计算,保证清除/应用在任何视口都可见
- 偏好:两个新字段进入 sanitizeFilters 白名单,规则可持久化,点清除即清空

验证:本地真实库 66033 行——只勾正常编码 27645 行、再接 WM- 26852 行、
再接 DF- 26788 行,与 SQL 基准逐一致;3001 HTTP 对账五个口径全对、
非法列返回 400、候选项接口在勾了正常编码后返回的 SPU 全部符合形态;
真机 UI 12/12(应用 26788、刷新记住、回显、清除回 66033);
布局专项 36/36(1600x900 / 1440x720 / 1366x640 / 1280x600 下弹层均在视口内、
按钮可见、不超左右边界);新增单测 15/15;type-check EXIT=0。
2026-09-17 11:46:18 +08:00
WuYongJie
3cd14c4f0d feat(product-archive): SPU 列支持「只看正常编码」与可累加排除规则
产品全量档案的 SPU 列筛选原来只有「勾选具体值 = 包含」一种语义,没法表达
「不要 DF- 开头的 / 不要纯数字的」这类排除需求,只能靠不断放宽正选来绕。

新增两类能力(原有「勾选值包含」语义一字未改):
- 「只看正常编码」:字母前缀(2~6位) + 可选「-字母段」 + 数字编号(3~8位),
  一次收掉纯数字 / 1643A 型 / 含中文的商品名 / 32 位哈希等非正常形态
- 「排除以…开头」:可累加的前缀黑名单(如 WM- 外贸、DF- 代发、MKH),
  对应「还有不想看就再填一条」

实现要点:
- lib:新增 ProductArchiveTextFilterKey / ProductArchiveExcludeRule 与
  PRODUCT_ARCHIVE_NORMAL_CODE_PATTERN;ProductArchiveFilters 只追加
  normalCodeOnly、excludeStartsWith 两个可选字段,老字段类型与语义不动
- 校验:zod schema 是 .strict(),同步放行两个新字段(否则整包筛选会被 400 拒掉)
- 服务端:buildProductArchiveWhere 保持同步,只追加 NOT startsWith;
  需要查库的「正常编码」放在新增的异步 buildProductArchiveWhereWithTextRules
  (Prisma 7.3 的字符串过滤不支持 regex,改为原生 SQL 取符合形态的取值清单拼 IN,
  带 5 分钟缓存)。preparePeriodArchiveQuery 是全站唯一取数入口,
  列表、候选项、导出、图片导出自动生效
- 文本规则故意不参与 omitFilter:若参与,候选值列表会冒出已被排除的取值,
  用户勾了却得到 0 行
- UI:文本列弹层改左右双排(左=形态与排除规则,右=搜索与候选值),
  弹层高度与横向偏移按触发按钮所在位置动态计算,保证清除/应用在任何视口都可见
- 偏好:两个新字段进入 sanitizeFilters 白名单,规则可持久化,点清除即清空

验证:本地真实库 66033 行——只勾正常编码 27645 行、再接 WM- 26852 行、
再接 DF- 26788 行,与 SQL 基准逐一致;3001 HTTP 对账五个口径全对、
非法列返回 400、候选项接口在勾了正常编码后返回的 SPU 全部符合形态;
真机 UI 12/12(应用 26788、刷新记住、回显、清除回 66033);
布局专项 36/36(1600x900 / 1440x720 / 1366x640 / 1280x600 下弹层均在视口内、
按钮可见、不超左右边界);新增单测 15/15;type-check EXIT=0。
2026-09-17 11:36:12 +08:00
WuYongJie
57e422308b feat(product-archive): SPU 列支持「只看正常编码」与可累加排除规则
产品全量档案的 SPU 列筛选原来只有「勾选具体值 = 包含」一种语义,没法表达
「不要 DF- 开头的 / 不要纯数字的」这类排除需求,只能靠不断放宽正选来绕。

新增两类能力(原有「勾选值包含」语义一字未改):
- 「只看正常编码」:字母前缀(2~6位) + 可选「-字母段」 + 数字编号(3~8位),
  一次收掉纯数字 / 1643A 型 / 含中文的商品名 / 32 位哈希等非正常形态
- 「排除以…开头」:可累加的前缀黑名单(如 WM- 外贸、DF- 代发、MKH),
  对应「还有不想看就再填一条」

实现要点:
- lib:新增 ProductArchiveTextFilterKey / ProductArchiveExcludeRule 与
  PRODUCT_ARCHIVE_NORMAL_CODE_PATTERN;ProductArchiveFilters 只追加
  normalCodeOnly、excludeStartsWith 两个可选字段,老字段类型与语义不动
- 校验:zod schema 是 .strict(),同步放行两个新字段(否则整包筛选会被 400 拒掉)
- 服务端:buildProductArchiveWhere 保持同步,只追加 NOT startsWith;
  需要查库的「正常编码」放在新增的异步 buildProductArchiveWhereWithTextRules
  (Prisma 7.3 的字符串过滤不支持 regex,改为原生 SQL 取符合形态的取值清单拼 IN,
  带 5 分钟缓存)。preparePeriodArchiveQuery 是全站唯一取数入口,
  列表、候选项、导出、图片导出自动生效
- 文本规则故意不参与 omitFilter:若参与,候选值列表会冒出已被排除的取值,
  用户勾了却得到 0 行
- UI:文本列弹层改左右双排(左=形态与排除规则,右=搜索与候选值),
  弹层高度与横向偏移按触发按钮所在位置动态计算,保证清除/应用在任何视口都可见
- 偏好:两个新字段进入 sanitizeFilters 白名单,规则可持久化,点清除即清空

验证:本地真实库 66033 行——只勾正常编码 27645 行、再接 WM- 26852 行、
再接 DF- 26788 行,与 SQL 基准逐一致;3001 HTTP 对账五个口径全对、
非法列返回 400、候选项接口在勾了正常编码后返回的 SPU 全部符合形态;
真机 UI 12/12(应用 26788、刷新记住、回显、清除回 66033);
布局专项 36/36(1600x900 / 1440x720 / 1366x640 / 1280x600 下弹层均在视口内、
按钮可见、不超左右边界);新增单测 15/15;type-check EXIT=0。
2026-09-17 11:32:53 +08:00
WuYongJie
cffa8b64f8 merge: release BOM 预估 v2(价格回退工具/case 级预估卡/预览页/缓存表) 2026-09-16 17:37:42 +08:00
WuYongJie
b0036bcc48 merge: BOM 预估 v2 落地——价格回退工具、case 级预估卡编排、预估卡预览页、结果缓存表 2026-09-16 17:37:26 +08:00
WuYongJie
f30866530a Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/wuyongjie-bom-estimate-agent-phase0 2026-09-16 17:37:23 +08:00
WuYongJie
48871454e9 feat(bom-costing): BOM 预估 v2 —— 价格回退工具、case 级预估卡编排与预览页
- agent 工具:尺寸感知镜像检索 + 分类画像三级级联(包装 v1 回退链,导出纯函数复用)
- case 级编排:首批代表 SKU 自动精算,其余按需点算;结果持久缓存(新表 BomCostingAgentSkuEstimate,幂等迁移)
- EstimateCard 契约:代码侧聚合五行构成/区间包络/最小置信度/不确定点并集
- API:/api/bom-costing/cases/[id]/agent-estimate(GET 缓存卡 + POST 运行,复用模块鉴权)
- 预览页:/bom-costing/estimate(预估卡 + SKU 列表按需点算 + 竞品图片浏览,旁路不过闸门不设默认入口)
- Select 组件:透传 id/aria 到触发按钮;修复 skill 知识未注入循环的缺陷
- 基线工具:report:bom-agent-baseline(定价覆盖率 + shadow 聚合,含隧道重试)
- 设计文档:docs/架构设计/BOM成本预估v2-agent方案设计-20260916.md
2026-09-16 17:37:06 +08:00
WuYongJie
a3b9fa0fbb merge: release 产品全量档案流式导出 2026-09-16 16:21:14 +08:00
WuYongJie
6f023e3f0d fix(product-archive): 导出改为流式写出,修复全量导出 OOM 崩溃
正式站导出「产品全量档案资料」必然崩溃:整包写法在 89 列下约 60MB/千行,
生产 Node 堆被 PM2 限到 768MB,实际只能撑约 5000 行,而档案表已有 7 万余行。
PM2 记录 exited with code [0] via signal [SIGABRT],error log 19 次
FATAL ERROR: Reached heap limit,最后一次 GC dump 763.5MB(= 堆上限)。

改成「先冻结行 id 快照 → 每 2000 行分批取数 → ExcelJS 流式写出 → 边生成边下发」,
服务端堆占用与导出总行数解耦;并加同机并发上限 3(超限 429)兜底。

- repository:listRows 全量取数改为 openRowSource。先冻结本次要导的有序 id 快照,
  再按 id 分批取完整行并按冻结顺序重排,避免导出期间上游同步导致行集合错位。
- service:createWorkbook 整包 writeBuffer 改为 openWorkbook 流式写出。
  useSharedStrings:false(共享字符串表会累积全部唯一文本且无法回收);
  冻结首行走 addWorksheet 的 views 选项(流式 worksheet 的 views 只有 getter,
  直接赋值会被静默忽略);并发额度在「正常写完」与「客户端断开」两条路径都归还。
- route:改为流式响应,不再发 Content-Length(改 chunked);监听 request.signal,
  客户端断开时销毁生成流;响应头发出后生成失败只能掐断流,故在路由层记日志。
- 前端:下载态文案改为「正在生成并下载文件...」;无 Content-Length 时显示「已接收 X」;
  收流中断统一提示为可读文案,不再只报网络错误。
- 测试:5 个用例,含冻结首行回归守护与「客户端中途断开不泄漏并发额度」守护。

验证:本地真实库 66033 行 × 89 列,NODE_OPTIONS=--max-old-space-size=768 下
首字节 0.5s / 总耗时 26.7s / 产物 25.8MB / 峰值 heapUsed 152.5MB(对照:整包写法
同规模在 4GB 堆直接 OOM)。3001 真实路由 13951 行:status 200、无 Content-Length、
chunked、首字节 0.2s、5.5s / 5.6MB。产物特性 10/10(表名、冻结首行、autoFilter
A1:CK1、89 列宽度、表头加粗与文本、行数),并用 openpyxl 独立交叉复核一致。
jest 5/5 通过、type-check EXIT=0。

已知边界:只在本机 next dev 验证,未跑 next build / next start。
2026-09-16 16:07:31 +08:00
WuYongJie
c5e1c50418 fix(product-archive): 导出改为流式写出,修复全量导出 OOM 崩溃
正式站导出「产品全量档案资料」必然崩溃:整包写法在 89 列下约 60MB/千行,
生产 Node 堆被 PM2 限到 768MB,实际只能撑约 5000 行,而档案表已有 7 万余行。
PM2 记录 exited with code [0] via signal [SIGABRT],error log 19 次
FATAL ERROR: Reached heap limit,最后一次 GC dump 763.5MB(= 堆上限)。

改成「先冻结行 id 快照 → 每 2000 行分批取数 → ExcelJS 流式写出 → 边生成边下发」,
服务端堆占用与导出总行数解耦;并加同机并发上限 3(超限 429)兜底。

- repository:listRows 全量取数改为 openRowSource。先冻结本次要导的有序 id 快照,
  再按 id 分批取完整行并按冻结顺序重排,避免导出期间上游同步导致行集合错位。
- service:createWorkbook 整包 writeBuffer 改为 openWorkbook 流式写出。
  useSharedStrings:false(共享字符串表会累积全部唯一文本且无法回收);
  冻结首行走 addWorksheet 的 views 选项(流式 worksheet 的 views 只有 getter,
  直接赋值会被静默忽略);并发额度在「正常写完」与「客户端断开」两条路径都归还。
- route:改为流式响应,不再发 Content-Length(改 chunked);监听 request.signal,
  客户端断开时销毁生成流;响应头发出后生成失败只能掐断流,故在路由层记日志。
- 前端:下载态文案改为「正在生成并下载文件...」;无 Content-Length 时显示「已接收 X」;
  收流中断统一提示为可读文案,不再只报网络错误。
- 测试:5 个用例,含冻结首行回归守护与「客户端中途断开不泄漏并发额度」守护。

验证:本地真实库 66033 行 × 89 列,NODE_OPTIONS=--max-old-space-size=768 下
首字节 0.5s / 总耗时 26.7s / 产物 25.8MB / 峰值 heapUsed 152.5MB(对照:整包写法
同规模在 4GB 堆直接 OOM)。3001 真实路由 13951 行:status 200、无 Content-Length、
chunked、首字节 0.2s、5.5s / 5.6MB。产物特性 10/10(表名、冻结首行、autoFilter
A1:CK1、89 列宽度、表头加粗与文本、行数),并用 openpyxl 独立交叉复核一致。
jest 5/5 通过、type-check EXIT=0。

已知边界:只在本机 next dev 验证,未跑 next build / next start。
2026-09-16 16:02:44 +08:00
WuYongJie
990a4bfeb1 merge: release 商品抠图模型目录合并与选择器升级 + BOM agent 旁路引擎
# Conflicts:
#	furniture-3d-system/src/app/supply-chain/config/supply-chain-menu.test.ts
#	furniture-3d-system/src/app/supply-chain/config/supply-chain-menu.ts
2026-09-16 15:19:50 +08:00
WuYongJie
9533c2e4ec merge: 商品抠图配置合并上游专用抠图模型目录 + BOM 核算 agent 旁路引擎与文本脱敏契约
- ai-config: 任一协议模式合并网关与异步两份模型目录,抠图模型置顶标记,选中自动对齐协议
- bom-costing/agent: 估算引擎(契约/工具/循环/网关适配/组装器,27 测试)旁路试验版
- lib: 预估文本对外脱敏契约共享模块(public-estimate-text)
- scripts: shadow 偏差报表与 agent 试跑工具(工程域专用)
2026-09-16 15:17:03 +08:00
WuYongJie
6492c2e400 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/wuyongjie-bom-estimate-agent-phase0 2026-09-16 15:14:00 +08:00
WuYongJie
20755dfdd1 feat(ai-config): 商品抠图配置合并上游专用抠图模型目录并升级选择器
- 目录服务:商品抠图任一协议模式都合并通用网关与异步媒体任务两份目录,
  模型带 source 来源标记,抠图模型置顶;提取器按端点路径选择
- 配置页:原生 select 换平台 Select(可搜索、暗色协调),抠图模型带
  【抠图】标记,选中后运行协议自动对齐异步媒体任务
- Select 组件:rest props 透传到触发按钮,支持 aria-label/id
2026-09-16 15:13:52 +08:00
WuYongJie
f8d74a5543 fix(intake): 补齐按SKU锁定与导入保护 2026-09-16 14:21:57 +08:00
WuYongJie
d73508bae6 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/wuyongjie-bom-estimate-agent-phase0 2026-09-16 14:18:51 +08:00
WuYongJie
2d93a22721 feat(bom-costing): agent 估算引擎(旁路试验版)
- agent/ 契约+工具+接线+循环+skill知识+网关适配+端到端组装器(27 测试)
- agent 只读仓储(归档素材/镜像价格/材质目录/案例与SKU简报)
- shadow 偏差报表与 trial 试跑脚本(工程域专用)
- 纪律:单价只来自工具结果、总额代码汇总、硬预算+trace、1688 仅中性摘要
2026-09-16 14:18:39 +08:00
WuYongJie
9983ab3a1a fix(product-archive): 固定列不再透字,操作列改图标按钮
问题:产品全量档案的「序号」「操作」是两个 position: sticky 固定列。
主题样式把半透明的 --sc-hover(rgba(17,19,21,0.035))用 !important 打到了
这两个固定列上,覆盖了组件自带的不透明底色;横向滚动时压在固定列下方的
单元格文字就会透出来,污染序号列与操作列。

修复:
- .archive-td-index / .archive-td-actions 从半透明 hover 规则中摘出,
  改为「不透明底色 var(--sc-surface) + linear-gradient(var(--sc-hover)) 叠加色层」,
  视觉与原来一致,但底色恒不透明(浅色与深色主题均适用)
- 操作列「查看 / 更多」文字按钮改为图标按钮(Eye / MoreHorizontal),
  补 title 与 aria-label,菜单项加图标并改用 --sc-* 主题变量配色
- 操作列宽度由 138px 收窄到 96px(colgroup / th / td 同步)

验证:3001 真机 puppeteer 复验 9/9 通过——hover 与横向滚动后两个固定列
背景均为不透明 rgb;操作列仅 2 个图标、无文字、宽度 96px;「更多」菜单与
「商品修改日志」入口正常,图标「查看」仍能打开条码档案详情。
type-check EXIT=0。jest 的 3 个失败用例均与本改动无关(主体文件属其他线程
未提交改动,或与 HEAD 逐字节一致属既有失败)。
2026-09-16 14:08:17 +08:00
WuYongJie
9c9a6a9a08 fix(product-archive): 固定列不再透字,操作列改图标按钮
问题:产品全量档案的「序号」「操作」是两个 position: sticky 固定列。
主题样式把半透明的 --sc-hover(rgba(17,19,21,0.035))用 !important 打到了
这两个固定列上,覆盖了组件自带的不透明底色;横向滚动时压在固定列下方的
单元格文字就会透出来,污染序号列与操作列。

修复:
- .archive-td-index / .archive-td-actions 从半透明 hover 规则中摘出,
  改为「不透明底色 var(--sc-surface) + linear-gradient(var(--sc-hover)) 叠加色层」,
  视觉与原来一致,但底色恒不透明(浅色与深色主题均适用)
- 操作列「查看 / 更多」文字按钮改为图标按钮(Eye / MoreHorizontal),
  补 title 与 aria-label,菜单项加图标并改用 --sc-* 主题变量配色
- 操作列宽度由 138px 收窄到 96px(colgroup / th / td 同步)

验证:3001 真机 puppeteer 复验 9/9 通过——hover 与横向滚动后两个固定列
背景均为不透明 rgb;操作列仅 2 个图标、无文字、宽度 96px;「更多」菜单与
「商品修改日志」入口正常,图标「查看」仍能打开条码档案详情。
type-check EXIT=0。jest 的 3 个失败用例均与本改动无关(主体文件属其他线程
未提交改动,或与 HEAD 逐字节一致属既有失败)。
2026-09-16 13:54:43 +08:00
WuYongJie
570dcacdc9 fix(product-archive): 固定列不再透字,操作列改图标按钮
问题:产品全量档案的「序号」「操作」是两个 position: sticky 固定列。
主题样式把半透明的 --sc-hover(rgba(17,19,21,0.035))用 !important 打到了
这两个固定列上,覆盖了组件自带的不透明底色;横向滚动时压在固定列下方的
单元格文字就会透出来,污染序号列与操作列。

修复:
- .archive-td-index / .archive-td-actions 从半透明 hover 规则中摘出,
  改为「不透明底色 var(--sc-surface) + linear-gradient(var(--sc-hover)) 叠加色层」,
  视觉与原来一致,但底色恒不透明(浅色与深色主题均适用)
- 操作列「查看 / 更多」文字按钮改为图标按钮(Eye / MoreHorizontal),
  补 title 与 aria-label,菜单项加图标并改用 --sc-* 主题变量配色
- 操作列宽度由 138px 收窄到 96px(colgroup / th / td 同步)

验证:3001 真机 puppeteer 复验 9/9 通过——hover 与横向滚动后两个固定列
背景均为不透明 rgb;操作列仅 2 个图标、无文字、宽度 96px;「更多」菜单与
「商品修改日志」入口正常,图标「查看」仍能打开条码档案详情。
type-check EXIT=0。jest 的 3 个失败用例均与本改动无关(主体文件属其他线程
未提交改动,或与 HEAD 逐字节一致属既有失败)。
2026-09-16 13:52:12 +08:00
WuYongJie
adac0dfc3a fix(intake): 补齐按SKU锁定与导入保护 2026-09-16 13:47:39 +08:00
WuYongJie
374a39b6dc feat(intake): 成品寄样支持一键填是/填否批量设置是否寄出
在产品开发明细-成品寄样工作区,「请寄样」旁新增「一键填否」「一键填是」,
一键把当前批次显示的 SKU 行的「是否寄出」填好,之后仍可单独改个别行
(例:30 个 SKU 先全填否,再把第 1 个改成是)。

实现要点:
- 只填空行,不覆盖已选过的行;目标为当前批次显示行的 skuId 集合。
- 单行默认值计算抽成 buildFinishedSampleShipmentRowWithShipped 复用,
  批量走 applyFinishedSampleShipmentDecisionToRows(无变化时返回原引用)。
- 权限沿用 canEditFinishedSampleShipmentDecision;无权限或无待填写行时按钮置灰。
- HeaderActions 经 DocumentWorkspaceHeaderActionsSlot 透传动作、权限与待填写行数。

验证:
- type-check EXIT=0
- 新增单测 8 例 + 组件测试 5 例 + 集成测试 3 例 全通过
- 既有回归 buildNonIntegratedDetailChrome / buildNonIntegratedDocumentWorkspaceHeaderActions 通过
- 3001 真机(puppeteer)确认按钮组与交互元素就位,用户目视验收通过
2026-09-16 13:12:28 +08:00
WuYongJie
60034dfff0 test(intake): 样包测量只读断言随锁定口径对齐
非集成权限工作流用例中原断言期望样包测量「已确认」行仍可编辑,
与本次落地的口径(已确认即不可改、取消确认后方可改)冲突,
随主提交一并校正为期望 readonly,并加注释说明规则来源。

补 d3dc8821 遗漏的这一个测试文件(主提交已含对应实现)。
2026-09-16 13:12:28 +08:00
WuYongJie
44c69bef3e feat(intake): 产品定厂与样包测量按SKU取消确认
为采购、跟单、管理员增加按当前批次取消样包测量 / 产品定厂确认的能力,
取消只退回未推送聚水潭的 SKU,已推送 SKU 保持锁定,且不清空任何业务字段。

主要改动:
- 取消确认:新增 workflow-confirmation/cancel 接口与服务端按结构化
  systemEnteredAt 逐 SKU 重算逻辑;严格要求先取消样包测量再取消产品定厂;
  「全部」页签不开放取消入口,仅具体批次页签可取消
- 编辑锁逐 SKU 化:基础信息、产品定厂、样包测量、产品核价改为逐 SKU 判定,
  旧页面保存、整件删除、并发聚水潭推送均增加已推送 SKU 保护
- 样包测量锁定口径对齐:已确认即不可改,取消确认后可改;
  界面只读、写入拦截与 Excel 导入共用同一判定
- 基础信息修订签名纳入产品公共字段,公共字段变更自动退回当前批次基础信息确认
- 修复产品定厂回写误退回基础信息确认:手动同步侧与派生侧统一使用
  buildBasicInfoRevisionSignature,避免两侧签名形态错位导致比对恒不等
- 修复 advisory lock 被 Prisma 按 void 结果反序列化导致的保存报错
  (无返回值加锁改用 executeRaw,产品行 FOR UPDATE 仍走 queryRaw)
- 并发保护:普通保存、正式 SPU 分配、资产中心系列部件写入、AI白底图乐观保存
  统一接入产品级锁与锁内最新数据重读,避免旧快照覆盖取消结果
2026-09-16 13:12:28 +08:00
WuYongJie
2a7d2b04a2 feat(intake): 成品寄样支持一键填是/填否批量设置是否寄出
在产品开发明细-成品寄样工作区,「请寄样」旁新增「一键填否」「一键填是」,
一键把当前批次显示的 SKU 行的「是否寄出」填好,之后仍可单独改个别行
(例:30 个 SKU 先全填否,再把第 1 个改成是)。

实现要点:
- 只填空行,不覆盖已选过的行;目标为当前批次显示行的 skuId 集合。
- 单行默认值计算抽成 buildFinishedSampleShipmentRowWithShipped 复用,
  批量走 applyFinishedSampleShipmentDecisionToRows(无变化时返回原引用)。
- 权限沿用 canEditFinishedSampleShipmentDecision;无权限或无待填写行时按钮置灰。
- HeaderActions 经 DocumentWorkspaceHeaderActionsSlot 透传动作、权限与待填写行数。

验证:
- type-check EXIT=0
- 新增单测 8 例 + 组件测试 5 例 + 集成测试 3 例 全通过
- 既有回归 buildNonIntegratedDetailChrome / buildNonIntegratedDocumentWorkspaceHeaderActions 通过
- 3001 真机(puppeteer)确认按钮组与交互元素就位,用户目视验收通过
2026-09-16 12:10:53 +08:00
WuYongJie
f9d29ba92f feat(intake): 成品寄样支持一键填是/填否批量设置是否寄出
在产品开发明细-成品寄样工作区,「请寄样」旁新增「一键填否」「一键填是」,
一键把当前批次显示的 SKU 行的「是否寄出」填好,之后仍可单独改个别行
(例:30 个 SKU 先全填否,再把第 1 个改成是)。

实现要点:
- 只填空行,不覆盖已选过的行;目标为当前批次显示行的 skuId 集合。
- 单行默认值计算抽成 buildFinishedSampleShipmentRowWithShipped 复用,
  批量走 applyFinishedSampleShipmentDecisionToRows(无变化时返回原引用)。
- 权限沿用 canEditFinishedSampleShipmentDecision;无权限或无待填写行时按钮置灰。
- HeaderActions 经 DocumentWorkspaceHeaderActionsSlot 透传动作、权限与待填写行数。

验证:
- type-check EXIT=0
- 新增单测 8 例 + 组件测试 5 例 + 集成测试 3 例 全通过
- 既有回归 buildNonIntegratedDetailChrome / buildNonIntegratedDocumentWorkspaceHeaderActions 通过
- 3001 真机(puppeteer)确认按钮组与交互元素就位,用户目视验收通过
2026-09-16 12:06:09 +08:00
WuYongJie
495ff9f30b test(intake): 样包测量只读断言随锁定口径对齐
非集成权限工作流用例中原断言期望样包测量「已确认」行仍可编辑,
与本次落地的口径(已确认即不可改、取消确认后方可改)冲突,
随主提交一并校正为期望 readonly,并加注释说明规则来源。

补 d3dc8821 遗漏的这一个测试文件(主提交已含对应实现)。
2026-09-16 12:01:21 +08:00
WuYongJie
3ae72e800f feat(intake): 产品定厂与样包测量按SKU取消确认
为采购、跟单、管理员增加按当前批次取消样包测量 / 产品定厂确认的能力,
取消只退回未推送聚水潭的 SKU,已推送 SKU 保持锁定,且不清空任何业务字段。

主要改动:
- 取消确认:新增 workflow-confirmation/cancel 接口与服务端按结构化
  systemEnteredAt 逐 SKU 重算逻辑;严格要求先取消样包测量再取消产品定厂;
  「全部」页签不开放取消入口,仅具体批次页签可取消
- 编辑锁逐 SKU 化:基础信息、产品定厂、样包测量、产品核价改为逐 SKU 判定,
  旧页面保存、整件删除、并发聚水潭推送均增加已推送 SKU 保护
- 样包测量锁定口径对齐:已确认即不可改,取消确认后可改;
  界面只读、写入拦截与 Excel 导入共用同一判定
- 基础信息修订签名纳入产品公共字段,公共字段变更自动退回当前批次基础信息确认
- 修复产品定厂回写误退回基础信息确认:手动同步侧与派生侧统一使用
  buildBasicInfoRevisionSignature,避免两侧签名形态错位导致比对恒不等
- 修复 advisory lock 被 Prisma 按 void 结果反序列化导致的保存报错
  (无返回值加锁改用 executeRaw,产品行 FOR UPDATE 仍走 queryRaw)
- 并发保护:普通保存、正式 SPU 分配、资产中心系列部件写入、AI白底图乐观保存
  统一接入产品级锁与锁内最新数据重读,避免旧快照覆盖取消结果
2026-09-16 12:01:21 +08:00
WuYongJie
a4bff5dd59 test(intake): 样包测量只读断言随锁定口径对齐
非集成权限工作流用例中原断言期望样包测量「已确认」行仍可编辑,
与本次落地的口径(已确认即不可改、取消确认后方可改)冲突,
随主提交一并校正为期望 readonly,并加注释说明规则来源。

补 d3dc8821 遗漏的这一个测试文件(主提交已含对应实现)。
2026-09-16 11:52:18 +08:00
WuYongJie
d3dc8821c2 feat(intake): 产品定厂与样包测量按SKU取消确认
为采购、跟单、管理员增加按当前批次取消样包测量 / 产品定厂确认的能力,
取消只退回未推送聚水潭的 SKU,已推送 SKU 保持锁定,且不清空任何业务字段。

主要改动:
- 取消确认:新增 workflow-confirmation/cancel 接口与服务端按结构化
  systemEnteredAt 逐 SKU 重算逻辑;严格要求先取消样包测量再取消产品定厂;
  「全部」页签不开放取消入口,仅具体批次页签可取消
- 编辑锁逐 SKU 化:基础信息、产品定厂、样包测量、产品核价改为逐 SKU 判定,
  旧页面保存、整件删除、并发聚水潭推送均增加已推送 SKU 保护
- 样包测量锁定口径对齐:已确认即不可改,取消确认后可改;
  界面只读、写入拦截与 Excel 导入共用同一判定
- 基础信息修订签名纳入产品公共字段,公共字段变更自动退回当前批次基础信息确认
- 修复产品定厂回写误退回基础信息确认:手动同步侧与派生侧统一使用
  buildBasicInfoRevisionSignature,避免两侧签名形态错位导致比对恒不等
- 修复 advisory lock 被 Prisma 按 void 结果反序列化导致的保存报错
  (无返回值加锁改用 executeRaw,产品行 FOR UPDATE 仍走 queryRaw)
- 并发保护:普通保存、正式 SPU 分配、资产中心系列部件写入、AI白底图乐观保存
  统一接入产品级锁与锁内最新数据重读,避免旧快照覆盖取消结果
2026-09-16 11:41:32 +08:00
WuYongJie
31dfacab23 1688代发异常事项:当月业绩列/供应商列/整装拆装维护 + Excel式列头筛选
- 列表新增当月真实业绩列(SPU 汇总条码当月值,条码展开行显示自身),当月无业绩整行过滤
- 新增供应商列(取 SPU 内非空 supplierName),列顺序调整为 SPU|业绩|供应商|运营
- 维护抽屉新增整装/拆装二选一,标记整装的 SPU 在"是否有图纸"列显示"整装不需要图纸"
- 顶部有无筛选与 Excel 式列头筛选(含 filter-options 接口)
- 新增迁移 20260915180000_add_dropship_issue_assembly_type(SupplyChainDropshipIssue.assemblyType)
2026-09-16 08:50:57 +08:00
WuYongJie
9e50804b2e 1688代发异常事项:当月业绩列/供应商列/整装拆装维护 + Excel式列头筛选
- 列表新增当月真实业绩列(SPU 汇总条码当月值,条码展开行显示自身),当月无业绩整行过滤
- 新增供应商列(取 SPU 内非空 supplierName),列顺序调整为 SPU|业绩|供应商|运营
- 维护抽屉新增整装/拆装二选一,标记整装的 SPU 在"是否有图纸"列显示"整装不需要图纸"
- 顶部有无筛选与 Excel 式列头筛选(含 filter-options 接口)
- 新增迁移 20260915180000_add_dropship_issue_assembly_type(SupplyChainDropshipIssue.assemblyType)
2026-09-16 08:43:27 +08:00
WuYongJie
b0fd9a8800 1688代发异常事项:SPU级维护表+运营筛选+图纸/视频筛选+条码搜索 2026-09-16 08:43:06 +08:00
WuYongJie
55ee1b421b fix(barcode-print): restore legacy split-code text layout
Full-Page scaling mis-measured the 3096x416 single-line PNG by its intrinsic size and shrank the whole layout. Templates two and three now share the restored legacy ADD_PRINT_TEXT segments.
2026-09-15 18:16:15 +08:00
WuYongJie
8a7d6cae5a fix(barcode-print): restore legacy split-code text layout
Full-Page scaling mis-measured the 3096x416 single-line PNG by its intrinsic size and shrank the whole layout. Templates two and three now share the restored legacy ADD_PRINT_TEXT segments.
2026-09-15 18:08:49 +08:00
WuYongJie
260fbc8428 feat(progress): add column header filters 2026-09-15 17:02:03 +08:00
WuYongJie
36616821cf feat(progress): add column header filters 2026-09-15 16:57:42 +08:00
WuYongJie
53febe8eb7 feat(supplier-recommendations): add guided editor options 2026-09-15 14:45:25 +08:00
WuYongJie
170d776aa6 feat(supplier-recommendations): add guided editor options 2026-09-15 14:44:48 +08:00
WuYongJie
64e3378125 fix(finished-progress): backfill sample merchandiser owner 2026-09-15 13:49:26 +08:00
WuYongJie
f6dd04eeee fix(finished-progress): backfill sample merchandiser owner 2026-09-15 13:45:40 +08:00
WuYongJie
1b301af15e feat(finished-progress): link automatic rows to sample details 2026-09-15 11:38:40 +08:00
WuYongJie
499cbf66d1 feat(finished-progress): link automatic rows to sample details 2026-09-15 11:26:52 +08:00
WuYongJie
78dcdae880 fix(finished-progress): exclude historical JST entries 2026-09-15 11:01:33 +08:00
WuYongJie
79f34971d6 fix(finished-progress): exclude historical JST entries 2026-09-15 10:58:04 +08:00
WuYongJie
dac31e736a fix(1688): accept opaque CDN image responses 2026-09-15 10:16:12 +08:00
WuYongJie
b63b2fe974 fix(1688): accept opaque CDN image responses 2026-09-15 10:05:15 +08:00
WuYongJie
200790b6fc feat(finished-progress): require completed samples and improve automatic purchase intake
Require a real completed sample before finished-product intake. Carry factory, brand, merchandiser, delivery date and minimum order quantity into editable records; leave order date blank and support bulk maintenance.

Generate one factory contract per source group, place new automatic orders first and enlarge the horizontal scrollbar. Include source identity migration and regressions.

Validation: TypeScript noEmit; 18 Jest suites / 164 tests; local 3001 browser drag, wheel, and bottom-row checks.
2026-09-14 18:13:13 +08:00
WuYongJie
ed15789a81 feat(finished-progress): require completed samples and improve automatic purchase intake
Require a real completed sample before finished-product intake. Carry factory, brand, merchandiser, delivery date and minimum order quantity into editable records; leave order date blank and support bulk maintenance.

Generate one factory contract per source group, place new automatic orders first and enlarge the horizontal scrollbar. Include source identity migration and regressions.

Validation: TypeScript noEmit; 18 Jest suites / 164 tests; local 3001 browser drag, wheel, and bottom-row checks.
2026-09-14 18:07:47 +08:00
WuYongJie
73be6c9019 1688代发异常事项:SPU级维护表+运营筛选+图纸/视频筛选+条码搜索
- 新表 SupplyChainDropshipIssue:SPU 级普票/专票、退货地址运营维护,带操作日志
- 页面重构:删除 header,SPU 汇总行+展开条码明细(一码一行),操作列图标化
- 运营独立筛选项:可搜索/单选/多选(DropshipOpsFilter),默认按近7天销量合计降序
- 新增 是否有图纸/是否有安装视频 三态筛选(下拉一行排布),搜索支持条码维度
- 菜单排序:新品经营总览→新品终止任务反馈→1688代发数据明细→1688代发异常事项
- 平台标签标题注册 dropship-issues,修复顶部标签空白
2026-09-14 17:03:29 +08:00
WuYongJie
027d17dd4a 1688代发异常事项:SPU级维护表+运营筛选+图纸/视频筛选+条码搜索
- 新表 SupplyChainDropshipIssue:SPU 级普票/专票、退货地址运营维护,带操作日志
- 页面重构:删除 header,SPU 汇总行+展开条码明细(一码一行),操作列图标化
- 运营独立筛选项:可搜索/单选/多选(DropshipOpsFilter),默认按近7天销量合计降序
- 新增 是否有图纸/是否有安装视频 三态筛选(下拉一行排布),搜索支持条码维度
- 菜单排序:新品经营总览→新品终止任务反馈→1688代发数据明细→1688代发异常事项
- 平台标签标题注册 dropship-issues,修复顶部标签空白
2026-09-14 16:00:55 +08:00
WuYongJie
01fd83d28b feat(supply-chain): 并入1688代发数据明细与代发异常事项占位
内容来源: codex/xuxiake-mainline 2aa85619(伯阳 1688 dropship analytics + 晓晓占位与图片预览),按文件集从 origin/main 干净并入。

- 新增 /supply-chain/new-products/1688-dropship-data 全链路(页面/筛选/趋势/API/repository/service)
- 新增 /supply-chain/new-products/dropship-issues 占位入口
- 权限 targetKey: newProduct1688DropshipData / newProductDropshipIssues
- 迁移 20260912120000_add_daily_sales_dropship_fields(salesAmount/skuOperator/unitCost)
- 产品图片点击弹窗预览
2026-09-14 10:23:47 +08:00
WuYongJie
2aa856197b feat(supply-chain): 1688代发数据明细产品图片点击弹窗预览
- 新增 DropshipImageCell:缩略图可点击,平台 Modal 弹窗放大(等比铺满,最高680px)
- 缩略图样式收口到 .imageButton,避免与就地渲染的 Modal 大图互相污染
- 大图复用 source-image 认证代理 URL,浏览器缓存零额外请求
2026-09-14 10:02:55 +08:00
伯阳
bc2104b169 test(supply-chain): verify merged 1688 entries and record integration checks 2026-09-12 18:32:24 +08:00
伯阳
e271d1b941 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/wuyongjie-1688-xuxiake-integration 2026-09-12 18:29:30 +08:00
伯阳
dfdc3c3626 feat(supply-chain): integrate 1688 dropship analytics with shared daily sales
Preserve shared barcode/day facts and atomic synchronization; add DF sales, cost and operator enrichment, filters, trends, and module-scoped image access. Include additive migration and deployment/backfill handoff. Independent review: passed with warnings; existing master-data audit failures match baseline.
2026-09-12 18:29:16 +08:00
WuYongJie
5156ead4c1 供应链新品管理新增「1688代发异常事项」占位入口
- 新增 /supply-chain/new-products/dropship-issues 占位页(功能建设中)
- supply-chain-menu 新品管理分组加菜单项,targetKey=newProductDropshipIssues
- 权限体系 targetKey 类型/列表/路由映射同步
- 侧栏清理未使用的 Home 图标导入
2026-09-12 18:05:22 +08:00
WuYongJie
090c6b39c5 运营负责人SPU级兜底:同SPU最新销售条码的负责人下放给未匹配条码 2026-09-12 17:10:50 +08:00
WuYongJie
38259cc40c 运营负责人SPU级兜底:同SPU最新销售条码的负责人下放给未匹配条码 2026-09-12 17:10:28 +08:00
WuYongJie
d20d7e4dd6 运营负责人SPU级兜底:同SPU最新销售条码的负责人下放给未匹配条码
- dws listLatestOpsOwners 带回 lastSaleDate;新增 listBarcodeSpuPairs(全档案条码→spu)
- service 构建按 spu 聚合的运营负责人映射(逐字段取最新销售日期的非空值)
- mapper 兜底:条码无 dws 直配时按 spu 继承(精确匹配优先,来源追溯 spu: 前缀)
- 用户口径:能匹配到的都放上去,不留空
2026-09-12 17:07:29 +08:00
WuYongJie
687ef50bb5 fix(home): workbench entry inside quick-links fold with unified styles
- expand list now starts with a fixed workbench entry (router.push to
  the workspace picker) followed by configured links
- replace next/link with button + router.push inside the nav item so
  styled-jsx scoped styles apply; fixes icon/label wrapping and keeps
  font size and spacing consistent across entries
- tests updated for the new push-based navigation and roles
2026-09-12 17:03:28 +08:00
WuYongJie
f6dc344b71 fix(home): workbench entry inside quick-links fold with unified styles
- expand list now starts with a fixed workbench entry (router.push to
  the workspace picker) followed by configured links
- replace next/link with button + router.push inside the nav item so
  styled-jsx scoped styles apply; fixes icon/label wrapping and keeps
  font size and spacing consistent across entries
- tests updated for the new push-based navigation and roles
2026-09-12 17:02:38 +08:00
WuYongJie
2b192afd86 fix(installation-demo): allow customer service model upload with progress toast
- /api/upload/model 去掉 requireDesignWorkspaceWrite 硬性门槛:改为安装演示
  canEdit 或设计工作区权限二者其一即可上传(客服等已配置安装演示编辑权限
  的角色可上传模型,其他模块设计权限语义不变)
- 上传进度右下角浮层按系统既有导入进度样式实现(文件名+百分比+进度条,
  完成绿色停留 3 秒自动收起,失败红色保留可关闭)
- installationModelUpload 改用 XHR 以获得真实上传字节进度,工具箱共用不受影响
2026-09-12 15:51:36 +08:00
WuYongJie
6aba6e077c fix(installation-demo): allow customer service model upload with progress toast
- /api/upload/model 去掉 requireDesignWorkspaceWrite 硬性门槛:改为安装演示
  canEdit 或设计工作区权限二者其一即可上传(客服等已配置安装演示编辑权限
  的角色可上传模型,其他模块设计权限语义不变)
- 上传进度右下角浮层按系统既有导入进度样式实现(文件名+百分比+进度条,
  完成绿色停留 3 秒自动收起,失败红色保留可关闭)
- installationModelUpload 改用 XHR 以获得真实上传字节进度,工具箱共用不受影响
2026-09-12 15:51:11 +08:00
WuYongJie
9892fead34 fix(installation-demo): allow customer service model upload with progress toast
- /api/upload/model 去掉 requireDesignWorkspaceWrite 硬性门槛:改为安装演示
  canEdit 或设计工作区权限二者其一即可上传(客服等已配置安装演示编辑权限
  的角色可上传模型,其他模块设计权限语义不变)
- 上传进度右下角浮层按系统既有导入进度样式实现(文件名+百分比+进度条,
  完成绿色停留 3 秒自动收起,失败红色保留可关闭)
- installationModelUpload 改用 XHR 以获得真实上传字节进度,工具箱共用不受影响
2026-09-12 15:50:47 +08:00
WuYongJie
9e9d92306e feat(home): admin-configured quick links with sidebar home fold
- HomeQuickLink table + migration; CRUD API with admin-only writes and
  internal-only visibility (suppliers/external intake excluded)
- sidebar home item folds open configured links in both product and
  supply-chain sidebars, entries open in a new tab
- home portal top-right manage entry with sort/enable/delete sheet
- permission matrix default: home overview open to all internal subjects
  so switching to supply chain no longer lands on an empty page
2026-09-12 15:04:54 +08:00
WuYongJie
0ea1c3ecdd feat(home): admin-configured quick links with sidebar home fold
- HomeQuickLink table + migration; CRUD API with admin-only writes and
  internal-only visibility (suppliers/external intake excluded)
- sidebar home item folds open configured links in both product and
  supply-chain sidebars, entries open in a new tab
- home portal top-right manage entry with sort/enable/delete sheet
- permission matrix default: home overview open to all internal subjects
  so switching to supply chain no longer lands on an empty page
2026-09-12 15:04:08 +08:00
WuYongJie
43f8540c9a 是否有图纸/是否有视频接入图纸系统API+非DF铺货图兜底+筛选修复 2026-09-12 14:27:10 +08:00
WuYongJie
002aa9dc34 fix(installation-demo): route customer service through node permissions
删除安装演示权限里硬编码的客服强制只读分享口径:原 isCustomerServiceUser
(CUSTOMER_SERVICE 角色或部门路径含客服中心)直接返回 canEdit=false 且排在
节点权限 overrides 之前,导致正式站给客服配置的编辑权限永远无效,客服只能
查看和分享、无法新建编辑截取。

删除后客服与普通员工一致走节点权限配置:客服主体 customerService
(部门路径含客服中心),正式站已配置的编辑权限即刻生效,可新建图纸、
维护编号、截取、分享与下载。
2026-09-12 14:25:40 +08:00
WuYongJie
d9d1b39d1c fix(installation-demo): route customer service through node permissions
删除安装演示权限里硬编码的客服强制只读分享口径:原 isCustomerServiceUser
(CUSTOMER_SERVICE 角色或部门路径含客服中心)直接返回 canEdit=false 且排在
节点权限 overrides 之前,导致正式站给客服配置的编辑权限永远无效,客服只能
查看和分享、无法新建编辑截取。

删除后客服与普通员工一致走节点权限配置:客服主体 customerService
(部门路径含客服中心),正式站已配置的编辑权限即刻生效,可新建图纸、
维护编号、截取、分享与下载。
2026-09-12 14:24:58 +08:00
WuYongJie
4f2ea0bdf0 fix(installation-demo): route customer service through node permissions
删除安装演示权限里硬编码的客服强制只读分享口径:原 isCustomerServiceUser
(CUSTOMER_SERVICE 角色或部门路径含客服中心)直接返回 canEdit=false 且排在
节点权限 overrides 之前,导致正式站给客服配置的编辑权限永远无效,客服只能
查看和分享、无法新建编辑截取。

删除后客服与普通员工一致走节点权限配置:客服主体 customerService
(部门路径含客服中心),正式站已配置的编辑权限即刻生效,可新建图纸、
维护编号、截取、分享与下载。
2026-09-12 14:24:11 +08:00
WuYongJie
904b80d4c9 运营部门负责人/运营负责人接入聚水潭销售宽表cater/ider
- dws repository 新增 listLatestOpsOwners:rpt.dws_sn_sales_full_info_di 按 skuoid 取 stat_date 最新一条的 cater/ider,全条码范围
- enrichment 链路新增 ops owners patch:来源码 DWS_SALES_OPS 可追溯;字段级有值才覆盖(dws 无值保留档案原值)
- opsDirector(运营总负责人)不接
- 本地全量验证:抽样 10 条与上游 100% 一致;3001 API 验收通过
2026-09-12 11:14:04 +08:00
WuYongJie
aaa9c74eec Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/local-3001-integration 2026-09-12 11:13:15 +08:00
WuYongJie
dd693dfbd5 运营部门负责人/运营负责人接入聚水潭销售宽表cater/ider
- dws repository 新增 listLatestOpsOwners:rpt.dws_sn_sales_full_info_di 按 skuoid 取 stat_date 最新一条的 cater/ider,全条码范围
- enrichment 链路新增 ops owners patch:来源码 DWS_SALES_OPS 可追溯;字段级有值才覆盖(dws 无值保留档案原值)
- opsDirector(运营总负责人)不接
- 本地全量验证:抽样 10 条与上游 100% 一致;3001 API 验收通过
2026-09-12 11:12:50 +08:00
WuYongJie
1b3f210e0f feat(barcode-print): add size template and keep package codes on one line 2026-09-11 17:13:52 +08:00
WuYongJie
04b24f7972 feat(barcode-print): add size template and keep package codes on one line 2026-09-11 17:12:52 +08:00
WuYongJie
222f3e6a97 feat(barcode-print): add size template and keep package codes on one line 2026-09-11 17:08:02 +08:00
WuYongJie
02ad38908e fix(installation-demo): recapture by current viewpoint, align material counts, add finished-frame ending
- 编号重截取按当前视角取景(engine 截图支持 viewpoint:current,默认行为不变),成功/失败给可见消息
- 动作分解物料数量改为该动作实际命中节点数(fixed/action 帧同口径),徽标与编号标注共用管理编号覆盖值
- 动作分解末尾固定追加成品展示收尾帧:复用成品展示截图,不参与截取与计数,支持调整画面与文字标注
- 编号标注对账按编号兜底认领并清理超量残留,修复部件重绑后改数量导致标注叠加翻倍
- 成品线稿统一 detail 风格,与动作图线宽一致
2026-09-11 14:37:05 +08:00
WuYongJie
6f49206964 fix(installation-demo): recapture by current viewpoint, align material counts, add finished-frame ending
- 编号重截取按当前视角取景(engine 截图支持 viewpoint:current,默认行为不变),成功/失败给可见消息
- 动作分解物料数量改为该动作实际命中节点数(fixed/action 帧同口径),徽标与编号标注共用管理编号覆盖值
- 动作分解末尾固定追加成品展示收尾帧:复用成品展示截图,不参与截取与计数,支持调整画面与文字标注
- 编号标注对账按编号兜底认领并清理超量残留,修复部件重绑后改数量导致标注叠加翻倍
- 成品线稿统一 detail 风格,与动作图线宽一致
2026-09-11 14:34:04 +08:00
WuYongJie
0c045ff906 chore(product-archive): default daily sales schedule to Beijing 08:00
- local scheduled task installer: compute next 08:00 Asia/Shanghai start boundary
- production systemd timer installer: default OnCalendar 08:00 Asia/Shanghai
- aligns installers with already-active 08:00 runtimes on both ends
2026-09-11 09:46:58 +08:00
WuYongJie
0c7d147129 chore(product-archive): default daily sales schedule to Beijing 08:00
- local scheduled task installer: compute next 08:00 Asia/Shanghai start boundary
- production systemd timer installer: default OnCalendar 08:00 Asia/Shanghai
- aligns installers with already-active 08:00 runtimes on both ends
2026-09-11 09:44:56 +08:00
WuYongJie
e075a81eb7 DF开头SKU档案图片接入聚水潭skumap三表平台图
- 新增 jst-skumap-pic.repository:rpt.jst_skumap/_pdd/_qmcust_add 三表 UNION,按 sku_id 取 modified 最新非空 pic,仅 DF 开头
- enrichment 同步链路:DF 条码 image 字段改用 skumap 平台图(无图清空),来源记录 JST_SKUMAP_PIC 可追溯;其他 SKU 图片逻辑不变
- 变更日志字段清单加入 image(图片)
- source-image 图片代理白名单放行 JST_SKUMAP_PIC,修复 DF 档案平台图 404 灰框
- 本地全量回填验证:331 批扫描 66033 failed=0;DF 有图 2281→24700;非 DF 14974 不变
2026-09-11 09:14:48 +08:00
WuYongJie
9e5a0d20b5 DF开头SKU档案图片接入聚水潭skumap三表平台图
- 新增 jst-skumap-pic.repository:rpt.jst_skumap/_pdd/_qmcust_add 三表 UNION,按 sku_id 取 modified 最新非空 pic,仅 DF 开头
- enrichment 同步链路:DF 条码 image 字段改用 skumap 平台图(无图清空),来源记录 JST_SKUMAP_PIC 可追溯;其他 SKU 图片逻辑不变
- 变更日志字段清单加入 image(图片)
- source-image 图片代理白名单放行 JST_SKUMAP_PIC,修复 DF 档案平台图 404 灰框
- 本地全量回填验证:331 批扫描 66033 failed=0;DF 有图 2281→24700;非 DF 14974 不变
2026-09-11 09:12:05 +08:00
WuYongJie
56560cd6d2 fix(deploy): verify complete releases before switching production 2026-09-10 18:29:17 +08:00
WuYongJie
e2f211c7ac fix(deploy): verify complete releases before switching production 2026-09-10 18:29:13 +08:00
WuYongJie
7f9adebf88 feat(installation-demo): add manual catalog, permanent shares and hinge binding 2026-09-10 18:12:46 +08:00
WuYongJie
46a732d892 feat(installation-demo): add manual catalog, permanent shares and hinge binding 2026-09-10 17:59:58 +08:00
WuYongJie
2cfd57d678 feat(product-archive): add daily monthly yearly sales and daily sync 2026-09-10 13:16:26 +08:00
WuYongJie
aa1ca0afcf feat(product-archive): add daily monthly yearly sales and daily sync 2026-09-10 13:15:23 +08:00
WuYongJie
b66e6b1f11 Merge remote-tracking branch 'origin/main' into HEAD 2026-09-10 12:59:21 +08:00
WuYongJie
0875c87058 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into HEAD 2026-09-10 12:59:20 +08:00
WuYongJie
a20b6cb79f fix(product-archive): add missing POST handlers for large filter payloads 2026-09-10 12:59:03 +08:00
WuYongJie
b9c85357e6 fix(intake): abandon permission checks creator and real designer keys
废弃权限白名单原读取 payload 中不存在的 appearanceDesigner 等键,导致外观/结构设计师无法废弃产品。改为按 创建人 + 外观设计师(designer 列/payload.designer) + 结构设计师(openingReference.structureDesigner,兼容顶层旧键) 判定,不再放行 SPU 负责人与采购负责人;管理员口径不变。
2026-09-10 12:32:19 +08:00
WuYongJie
5c7ebbe914 fix(intake): abandon permission checks creator and real designer keys
废弃权限白名单原读取 payload 中不存在的 appearanceDesigner 等键,导致外观/结构设计师无法废弃产品。改为按 创建人 + 外观设计师(designer 列/payload.designer) + 结构设计师(openingReference.structureDesigner,兼容顶层旧键) 判定,不再放行 SPU 负责人与采购负责人;管理员口径不变。
2026-09-10 12:32:06 +08:00
WuYongJie
2947ddebcf Merge remote-tracking branch 'origin/main' into HEAD 2026-09-10 11:53:26 +08:00
WuYongJie
69d19076bd Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into HEAD 2026-09-10 11:53:07 +08:00
WuYongJie
17d2e1d7bb Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/local-3001-integration 2026-09-10 11:52:31 +08:00
WuYongJie
351b7d7d2a feat(product-archive): take dropship df sku cost from sales goods_cost 2026-09-10 11:52:14 +08:00
WuYongJie
b8e80204a0 fix(barcode-print): raise Gujia certificate fields 2026-09-10 08:44:31 +08:00
WuYongJie
1042f35090 fix(barcode-print): raise Gujia certificate fields 2026-09-10 08:44:28 +08:00
WuYongJie
eedea9f791 fix(barcode-print): raise Gujia certificate fields 2026-09-10 08:43:13 +08:00
WuYongJie
0271da1b69 fix(barcode-print): recalibrate Gujia card and disable 2026 template 2026-09-09 17:56:14 +08:00
WuYongJie
b647cc2943 fix(barcode-print): recalibrate Gujia card and disable 2026 template 2026-09-09 17:55:27 +08:00
WuYongJie
3360ccb801 fix(barcode-print): recalibrate Gujia card and disable 2026 template 2026-09-09 17:54:04 +08:00
WuYongJie
1c0beffcb6 feat(barcode-print): add calibrated Gujia certificate template 2026-09-09 15:47:45 +08:00
WuYongJie
254cd92c5b fix(product-archive): stream material library images through a same-origin endpoint
the material library api hands out signed preview urls whose objects 404 on its cdn, so archive rows kept rendering empty placeholders; the batch endpoint now returns same-origin streaming urls (material-image?file=1) that resolve server-side, try the reachable s3 direct link first with the original signed url as fallback, and stream the bytes to the browser; the resolved image object is copied before url mapping so the service in-memory cache is no longer poisoned across requests.
2026-09-09 15:45:58 +08:00
WuYongJie
3976f96fcb fix(product-archive): stream material library images through a same-origin endpoint
the material library api hands out signed preview urls whose objects 404 on its cdn, so archive rows kept rendering empty placeholders; the batch endpoint now returns same-origin streaming urls (material-image?file=1) that resolve server-side, try the reachable s3 direct link first with the original signed url as fallback, and stream the bytes to the browser; the resolved image object is copied before url mapping so the service in-memory cache is no longer poisoned across requests.
2026-09-09 15:45:18 +08:00
WuYongJie
6161bb3e59 feat(barcode-print): add calibrated Gujia certificate template 2026-09-09 15:43:08 +08:00
WuYongJie
3cd064a467 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into HEAD 2026-09-09 14:57:09 +08:00
WuYongJie
db05c1ca0a Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/local-3001-integration 2026-09-09 14:42:30 +08:00
WuYongJie
1bb87a454d feat(product-archive): persist jianshang stock on main table and harden filter select-all 2026-09-09 14:42:17 +08:00
WuYongJie
cc1e15582e fix(product-archive): fall back signed qnycdn material image urls to reachable s3 links
the material library api now returns signed preview urls on qnycdn.jiansun.vip/prod whose objects 404 on the cdn, so every resolved archive material image failed to render; rewrite those urls to the same path on s3.jiansun.vip/gongxiangpan (verified reachable) and drop the signature at every exit of the material image service (barcode lookup, sku zip index, white background fallback, resolved cache reads) so matched sku/barcode images display again.
2026-09-09 13:35:55 +08:00
WuYongJie
560579b7f9 fix(product-archive): fall back signed qnycdn material image urls to reachable s3 links
the material library api now returns signed preview urls on qnycdn.jiansun.vip/prod whose objects 404 on the cdn, so every resolved archive material image failed to render; rewrite those urls to the same path on s3.jiansun.vip/gongxiangpan (verified reachable) and drop the signature at every exit of the material image service (barcode lookup, sku zip index, white background fallback, resolved cache reads) so matched sku/barcode images display again.
2026-09-09 13:35:35 +08:00
WuYongJie
f0cc716dd0 fix(intake): map reorganized planning department to PLANNING role
钉钉组织调整后商品企划部更名为企划部并挂到公司根节点。部门到业务角色推断、非集成产品权限、节点权限主体与商品企划候选人筛选统一识别 企划部 及其下级在职人员;保留旧 品牌中心>商品企划部 口径兼容存量数据;在职/外部过滤逻辑不变。
2026-09-09 12:12:01 +08:00
WuYongJie
66746bdc7e fix(intake): map reorganized planning department to PLANNING role
钉钉组织调整后商品企划部更名为企划部并挂到公司根节点。部门到业务角色推断、非集成产品权限、节点权限主体与商品企划候选人筛选统一识别 企划部 及其下级在职人员;保留旧 品牌中心>商品企划部 口径兼容存量数据;在职/外部过滤逻辑不变。
2026-09-09 12:11:32 +08:00
WuYongJie
d563513875 feat(product-development-todos): drop early-stage reminders and read structured factory rows 2026-09-09 11:45:40 +08:00
WuYongJie
1a0d3a7429 feat(product-development-todos): drop early-stage reminders and read structured factory rows 2026-09-09 11:45:01 +08:00
WuYongJie
c20bf5314a feat(product-development-todos): drop early-stage reminders and read structured factory rows 2026-09-09 11:43:21 +08:00
f615161d8c Merge pull request 'fix(store-accounts): 按明文存储规则修正密码状态' (#21) from codex/xuxiake-mainline into main 2026-09-09 11:05:13 +08:00
WuYongJie
ed339ceb3f merge: sync latest xuxiake before password status release
# Conflicts:
#	furniture-3d-system/docs/integrations/finance-store-account-password-reveal.md
2026-09-09 11:02:18 +08:00
WuYongJie
149cf46b63 fix(store-accounts): align password status with plaintext storage 2026-09-09 11:01:42 +08:00
17daaee224 保持当前页分块读取限流额度 (#20) 2026-09-08 18:13:20 +08:00
2224112c29 保持当前页分块读取限流额度 (#19) 2026-09-08 18:11:34 +08:00
4fd134f636 发布财务当前页批量读取店铺密码 (#16)
Co-authored-by: xuxiake <2644600472@qq.com>
Co-committed-by: xuxiake <2644600472@qq.com>
2026-09-08 17:21:32 +08:00
caa960d70a 支持财务当前页批量读取店铺密码 (#18) 2026-09-08 17:19:01 +08:00
WuYongJie
9965c93c8d feat(store-accounts): store password and bank account as plaintext 2026-09-08 15:07:35 +08:00
WuYongJie
811926e67b feat(store-accounts): store password and bank account as plaintext 2026-09-08 15:06:43 +08:00
WuYongJie
c9d2f37ead feat(product-archive): add select-all to header filter option lists 2026-09-08 14:44:26 +08:00
WuYongJie
4deea6518a feat(product-archive): add select-all to header filter option lists 2026-09-08 14:43:37 +08:00
WuYongJie
0b4311a882 feat(store-accounts): show password and bank account in plaintext in list 2026-09-08 14:07:06 +08:00
WuYongJie
ecfd596ad0 feat(store-accounts): show password and bank account in plaintext in list 2026-09-08 14:05:44 +08:00
WuYongJie
df9c0ad67f feat(intake): add product abandon action to the product list
the product list rows gain an abandon action next to edit/copy/delete for admins and product owners (operations brand / spu / appearance / structure / purchase / merchandiser / planner / space owners matched by name); abandoning sets projectStatus to rejected which makes every workspace read-only and the existing daily todo push already skips rejected products, so abandoned products drop out of daily pushes automatically; the server enforces the same permission via a new POST abandon endpoint. Abandoned rows keep the restore action to come back.
2026-09-08 12:27:26 +08:00
WuYongJie
d2f71b3723 feat(intake): add product abandon action to the product list
the product list rows gain an abandon action next to edit/copy/delete for admins and product owners (operations brand / spu / appearance / structure / purchase / merchandiser / planner / space owners matched by name); abandoning sets projectStatus to rejected which makes every workspace read-only and the existing daily todo push already skips rejected products, so abandoned products drop out of daily pushes automatically; the server enforces the same permission via a new POST abandon endpoint. Abandoned rows keep the restore action to come back.
2026-09-08 12:26:44 +08:00
WuYongJie
5754172787 fix(product-development-todo): route missing purchaser reminders and use plain text 2026-09-08 10:31:22 +08:00
WuYongJie
ee8172c724 fix(product-development-todo): route missing purchaser reminders and use plain text 2026-09-08 10:21:19 +08:00
WuYongJie
7139f40c8d feat(oa-board): make workflow link cells clickable to open product detail
workflow link cells on the oa board detail table now render as anchors when the value is an http(s) url, opening the linked product detail in a new tab with platform link styling and hover underline; empty or non-url text still renders the dash placeholder.
2026-09-08 09:02:51 +08:00
WuYongJie
54bf9107fb Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/local-3001-integration 2026-09-08 09:01:57 +08:00
WuYongJie
41e962da37 feat(oa-board): make workflow link cells clickable to open product detail
workflow link cells on the oa board detail table now render as anchors when the value is an http(s) url, opening the linked product detail in a new tab with platform link styling and hover underline; empty or non-url text still renders the dash placeholder.
2026-09-08 09:01:37 +08:00
WuYongJie
22cede9ed0 merge(main): publish finance store password reveal 2026-09-08 06:22:23 +08:00
c1dd4e666e Merge pull request 'feat(store-accounts): 财务专用按需密码读取、审计与安全状态' (#17) from codex/wuyongjie-store-accounts-finance-reveal into codex/xuxiake-mainline 2026-09-08 06:21:56 +08:00
WuYongJie
494a1cf60f feat(store-accounts): add audited finance password reveal 2026-09-08 05:59:19 +08:00
WuYongJie
f5a8ec1c05 feat(intake): add product factory workbook export and import by sku code
the product factory workspace gains export/import template buttons (purchase/merchandiser already hold node download grants): the export brings out the sku code, set count and every factory fillable field, splitting set count 2 rows into their A/B package codes; the import matches rows by sku code, enforces a header layout identical to the exported template, validates supplier names against the supplier directory, warehouses against the warehouse directory, enum fields against system options and number/date formats, collapses or splits A/B packages when the imported set count changes, and rejects confirmed rows - any row error aborts the whole import with per-row line numbers and reasons. Size, color and material columns are reference only.
2026-09-07 17:14:07 +08:00
WuYongJie
e9f83b16ee feat(intake): add product factory workbook export and import by sku code
the product factory workspace gains export/import template buttons (purchase/merchandiser already hold node download grants): the export brings out the sku code, set count and every factory fillable field, splitting set count 2 rows into their A/B package codes; the import matches rows by sku code, enforces a header layout identical to the exported template, validates supplier names against the supplier directory, warehouses against the warehouse directory, enum fields against system options and number/date formats, collapses or splits A/B packages when the imported set count changes, and rejects confirmed rows - any row error aborts the whole import with per-row line numbers and reasons. Size, color and material columns are reference only.
2026-09-07 17:12:59 +08:00
WuYongJie
416e22754a 供应商新品推荐:新增采购数据看板与PK榜
看板双视图(明细数据/采购看板,仅采购与管理可见看板);按月聚合采购推荐SKU/涉及工厂/被选款/被选率;路径行明细支持工厂勾选后跳转明细数据;被选款数量卡片跳转已选明细;PK榜爬山形态铺满全屏,管理员可配置主题/总金额/层级门槛与金额/规则说明(存 SystemConfig,无迁移)。
2026-09-07 16:40:49 +08:00
WuYongJie
d4d26c43bf 供应商新品推荐:新增采购数据看板与PK榜
看板双视图(明细数据/采购看板,仅采购与管理可见看板);按月聚合采购推荐SKU/涉及工厂/被选款/被选率;路径行明细支持工厂勾选后跳转明细数据;被选款数量卡片跳转已选明细;PK榜爬山形态铺满全屏,管理员可配置主题/总金额/层级门槛与金额/规则说明(存 SystemConfig,无迁移)。
2026-09-07 16:39:38 +08:00
WuYongJie
8fb872a3f9 feat(intake): open sample measurement and pricing template access with spec name column
measurement and pricing nodes now default downloads for pricing/purchase/merchandiser subjects so non-admin owners see the export/import template buttons; both workbook exports add a spec name reference column after the barcode (imports stay barcode-keyed and ignore it); the pricing node also grants merchandiser download parity with purchase owners.
2026-09-07 11:48:18 +08:00
WuYongJie
f8ba4f1e25 feat(intake): open sample measurement and pricing template access with spec name column
measurement and pricing nodes now default downloads for pricing/purchase/merchandiser subjects so non-admin owners see the export/import template buttons; both workbook exports add a spec name reference column after the barcode (imports stay barcode-keyed and ignore it); the pricing node also grants merchandiser download parity with purchase owners.
2026-09-07 11:47:40 +08:00
WuYongJie
39d7fc02f6 feat(finished-product-progress): auto-import factory-confirmed SKUs on sample completion 2026-09-07 11:17:21 +08:00
WuYongJie
8ea6a54eaa feat(finished-product-progress): auto-import factory-confirmed SKUs on sample completion 2026-09-07 11:15:01 +08:00
WuYongJie
667438447a fix(intake): move import rowNumber off the shared sku export row type
the optional numeric rowNumber on NonIntegratedSkuExportRow broke the dynamic template column writes (string vs never) in the production build type check; import rows now use a dedicated NonIntegratedSkuImportRow type that extends the export row with a required rowNumber.
2026-09-05 12:26:25 +08:00
WuYongJie
092036786c fix(barcode-print): restore Sofia certificate row pitch 2026-09-05 11:55:52 +08:00
WuYongJie
4a574041a9 fix(barcode-print): restore Sofia certificate row pitch 2026-09-05 11:53:55 +08:00
WuYongJie
2dbb214006 fix(intake): move import rowNumber off the shared sku export row type
the optional numeric rowNumber on NonIntegratedSkuExportRow broke the dynamic template column writes (string vs never) in the production build type check; import rows now use a dedicated NonIntegratedSkuImportRow type that extends the export row with a required rowNumber.
2026-09-04 17:59:40 +08:00
WuYongJie
e926a5a990 fix(intake): replace unsafe cast in sku export empty row builder
adding the optional rowNumber field to NonIntegratedSkuExportRow made the Object.fromEntries cast insufficient for the production build type check; build the empty import row explicitly instead.
2026-09-04 17:49:57 +08:00
WuYongJie
4f6510271f fix(intake): replace unsafe cast in sku export empty row builder
adding the optional rowNumber field to NonIntegratedSkuExportRow made the Object.fromEntries cast insufficient for the production build type check; build the empty import row explicitly instead.
2026-09-04 17:49:31 +08:00
WuYongJie
fccf9485b7 feat(intake): validate sku import skuCode spu prefix
standard sku workbook import now rejects rows whose skuCode does not start with the product spu in uppercase (lowercase codes are reported as needing uppercase); rows with an empty skuCode still pass and get auto-generated on save; the whole import is rejected with per-row line numbers and reasons. barcodes are skipped since they derive from the sku code.
2026-09-04 17:40:11 +08:00
WuYongJie
f4712cd1a2 feat(intake): validate sku import skuCode spu prefix
standard sku workbook import now rejects rows whose skuCode does not start with the product spu in uppercase (lowercase codes are reported as needing uppercase); rows with an empty skuCode still pass and get auto-generated on save; the whole import is rejected with per-row line numbers and reasons. barcodes are skipped since they derive from the sku code.
2026-09-04 17:39:35 +08:00
WuYongJie
e27e4fe67e feat(sample-progress): add daily due-date reminder notifications 2026-09-04 16:15:44 +08:00
WuYongJie
4843e16124 feat(sample-progress): add daily due-date reminder notifications 2026-09-04 16:14:51 +08:00
WuYongJie
f41e87373b fix(barcode-print): normalize Sofia certificate row spacing 2026-09-04 15:27:09 +08:00
WuYongJie
d32988dde6 fix(barcode-print): normalize Sofia certificate row spacing 2026-09-04 15:26:23 +08:00
WuYongJie
b30e5e5850 fix(barcode-print): tune Sofia certificate field positions 2026-09-04 12:27:39 +08:00
WuYongJie
bbb35a44f3 fix(barcode-print): tune Sofia certificate field positions 2026-09-04 12:25:32 +08:00
WuYongJie
56f3a7fe3f fix(supply-chain): show feedback as timed toast 2026-09-04 11:27:55 +08:00
WuYongJie
d3dee58b2b fix(supply-chain): default batch selection operator 2026-09-04 11:27:55 +08:00
WuYongJie
3df9bf08b1 fix(supply-chain): show feedback as timed toast 2026-09-04 11:25:31 +08:00
WuYongJie
d08a244fcb fix(supply-chain): default batch selection operator 2026-09-04 11:23:54 +08:00
WuYongJie
b488e6084c fix(finished-product-progress): enforce first-due-date protection on import updates
Import rows must not bypass the confirmed-first-due-date protection. Drop the allowDueDateChanges flag from the import update path so first-due-date changes are rejected and weekly due-date changes still require a reason, matching manual edits. Legacy rows without an order-placed date keep their free-correction path.
2026-09-04 10:59:29 +08:00
WuYongJie
99f004a593 fix(finished-product-progress): enforce first-due-date protection on import updates
Import rows must not bypass the confirmed-first-due-date protection. Drop the allowDueDateChanges flag from the import update path so first-due-date changes are rejected and weekly due-date changes still require a reason, matching manual edits. Legacy rows without an order-placed date keep their free-correction path.
2026-09-04 10:55:55 +08:00
WuYongJie
a252c00ac2 fix: align sofia certificate print fields 2026-09-04 10:32:41 +08:00
WuYongJie
13dd73069e fix: align sofia certificate print fields 2026-09-04 10:28:58 +08:00
WuYongJie
592b53f0ac merge(main): 发布可切换抠图配置与异步智能抠图 2026-09-03 18:48:20 +08:00
WuYongJie
16d6069123 merge: 发布可切换抠图配置与异步智能抠图 2026-09-03 18:48:04 +08:00
WuYongJie
a5cca36d69 fix(bom-costing): 接入供应商异步智能抠图模型 2026-09-03 18:44:51 +08:00
WuYongJie
966a8340e4 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/wuyongjie-bom-estimate-agent-phase0 2026-09-03 18:27:47 +08:00
WuYongJie
6b3760c6e7 feat(bom-costing): 支持可切换的抠图接口配置 2026-09-03 18:27:22 +08:00
WuYongJie
92bd812a17 feat(supply-chain): add supplier recommendation notice discard pool 2026-09-03 17:55:00 +08:00
WuYongJie
3456d1f465 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/local-3001-integration 2026-09-03 17:53:56 +08:00
WuYongJie
ffcf242738 feat(supply-chain): add supplier recommendation notice discard pool 2026-09-03 17:51:56 +08:00
WuYongJie
24b5d5872f merge(main): 发布 BOM 商品详情图排列修正 2026-09-03 17:46:23 +08:00
WuYongJie
b335ef7719 merge: 修正 BOM 商品详情图排列 2026-09-03 17:46:11 +08:00
WuYongJie
394927d843 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/wuyongjie-bom-estimate-agent-phase0 2026-09-03 17:45:59 +08:00
WuYongJie
f4adeb3808 fix(bom-costing): 纵向完整展示商品详情图 2026-09-03 17:45:38 +08:00
WuYongJie
452c41bc4d merge(main): 发布 BOM 商品图片布局修正 2026-09-03 17:24:23 +08:00
WuYongJie
cac0452672 merge: 修正 BOM 商品图片布局 2026-09-03 17:24:09 +08:00
WuYongJie
0c65f7af2b Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/wuyongjie-bom-estimate-agent-phase0 2026-09-03 17:23:54 +08:00
WuYongJie
4a9e5d99be fix(bom-costing): 按指定位置重排商品图片 2026-09-03 17:23:03 +08:00
WuYongJie
04d6219417 merge(main): 发布 BOM 商品抠图与图片分类 2026-09-03 17:06:12 +08:00
WuYongJie
30ab1b4b35 merge: 发布 BOM 商品抠图与图片分类 2026-09-03 17:05:49 +08:00
WuYongJie
b5d05f2779 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/wuyongjie-bom-estimate-agent-phase0 2026-09-03 17:04:34 +08:00
WuYongJie
4ce03262c0 feat(bom-costing): 接入商品抠图并完善图片浏览 2026-09-03 17:04:05 +08:00
WuYongJie
4014f53b9e Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into HEAD 2026-09-03 15:52:13 +08:00
WuYongJie
3e92e7242a Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/local-3001-integration 2026-09-03 15:51:17 +08:00
WuYongJie
c10e787fcf fix(users): fall back permission subjects to business roles when department misses dedicated lines
Department dedicated lines stay authoritative; when no department path matches any line, resolve subjects from account business roles (OPERATIONS->operation, PURCHASING->purchase, STRATEGY->brandCenter, etc). Personal overrides still apply last. Fixes operations and four purchasing accounts being downgraded to plain viewers.
2026-09-03 15:51:09 +08:00
WuYongJie
17a0491a4a merge(main): 发布 BOM 九折预估与极简工作台
# Conflicts:
#	furniture-3d-system/prisma/schema.prisma
#	furniture-3d-system/src/app/intake/sample-progress/components/SampleProgressTableRow.tsx
#	furniture-3d-system/src/app/supply-chain/database/store-account-management/StoreAccountManagementView.tsx
#	furniture-3d-system/src/lib/store-account-management.ts
#	furniture-3d-system/src/server/integrations/notification-center/client.test.ts
#	furniture-3d-system/src/server/integrations/notification-center/client.ts
#	furniture-3d-system/src/server/integrations/notification-center/types.ts
#	furniture-3d-system/src/server/repositories/__tests__/store-account-management.repository.test.ts
#	furniture-3d-system/src/server/repositories/store-account-management.repository.ts
#	furniture-3d-system/src/server/services/__tests__/notification-delivery.service.test.ts
#	furniture-3d-system/src/server/services/__tests__/store-account-notification.service.test.ts
#	furniture-3d-system/src/server/services/notification-delivery.service.ts
#	furniture-3d-system/src/server/services/sample-progress.service.test.ts
#	furniture-3d-system/src/server/services/store-account-notification.service.ts
2026-09-03 15:44:35 +08:00
WuYongJie
1e1f667530 merge: 发布 BOM 九折预估与极简工作台 2026-09-03 15:41:55 +08:00
WuYongJie
33a13a8abb Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/wuyongjie-bom-estimate-agent-phase0 2026-09-03 15:38:14 +08:00
WuYongJie
4ceedf50ee feat(bom-costing): 固定九折预估并精简工作台 2026-09-03 15:37:34 +08:00
WuYongJie
41a6bbff48 chore: enforce operation log retention policy 2026-09-03 15:36:36 +08:00
WuYongJie
856522552f chore: enforce operation log retention policy 2026-09-03 15:33:22 +08:00
WuYongJie
c30aed3987 feat(supply-chain): enforce import required fields and move sample request column for supplier recommended products
- import rejects rows missing required fields and reports the row number with
  missing labels; drop-shipping fee is required only when shipping mode includes
  代发; date is system-filled on import and not required
- move 申请寄样 after 代发运费 across export, import template, table columns
  and the editor drawer
- gate the download-template button behind edit permission (the template belongs
  to the purchaser import workflow)
- add selection endpoint tests
2026-09-03 15:08:51 +08:00
WuYongJie
205db8234c feat(supply-chain): enforce import required fields and move sample request column for supplier recommended products
- import rejects rows missing required fields and reports the row number with
  missing labels; drop-shipping fee is required only when shipping mode includes
  代发; date is system-filled on import and not required
- move 申请寄样 after 代发运费 across export, import template, table columns
  and the editor drawer
- gate the download-template button behind edit permission (the template belongs
  to the purchaser import workflow)
- add selection endpoint tests
2026-09-03 15:07:09 +08:00
WuYongJie
1edbc110d4 feat(users): show last login status in account management list
账号管理表格在账号状态与操作之间新增最后登录列:从未登录灰色、今天 HH:mm、昨天、N 天前、日期,超 30 天橙色标记闲置账号;组织树接口对管理员已返回 lastLoginAt,本次仅前端改动。
2026-09-03 14:21:23 +08:00
WuYongJie
455025f546 feat(users): show last login status in account management list
账号管理表格在账号状态与操作之间新增最后登录列:从未登录灰色、今天 HH:mm、昨天、N 天前、日期,超 30 天橙色标记闲置账号;组织树接口对管理员已返回 lastLoginAt,本次仅前端改动。
2026-09-03 14:21:06 +08:00
WuYongJie
58d5e0ffdd feat: add operation log scrolling and pagination 2026-09-03 13:53:21 +08:00
WuYongJie
583e3240ce feat: add operation log scrolling and pagination 2026-09-03 13:44:06 +08:00
WuYongJie
88ddd67736 style(finished-product-progress): soften contract group separator to 1px light gray 2026-09-03 13:32:09 +08:00
WuYongJie
259f4b8e7e style(finished-product-progress): soften contract group separator to 1px light gray 2026-09-03 13:29:48 +08:00
WuYongJie
bb561d2482 feat(mobile): streamline mobile navigation and compact intake workspace UI 2026-09-03 13:20:42 +08:00
WuYongJie
8f5fde8d4e feat(mobile): streamline mobile navigation and compact intake workspace UI 2026-09-03 13:18:39 +08:00
WuYongJie
925868fb65 feat(intake): allow designers to delete their own product records
product intake list delete button now also resolves for designers (DESIGN business role or design department paths), restricted to records they created; admins keep full delete scope; server DELETE route and client row button share the same record-level predicate; delete stays soft with operation logs.
2026-09-03 13:06:01 +08:00
WuYongJie
3556b48c4a feat(intake): allow designers to delete their own product records
product intake list delete button now also resolves for designers (DESIGN business role or design department paths), restricted to records they created; admins keep full delete scope; server DELETE route and client row button share the same record-level predicate; delete stays soft with operation logs.
2026-09-03 13:03:49 +08:00
WuYongJie
74ac36f34d feat(finished-product-progress): add filtered export with embedded images
Add an export action that collects all rows matching the current filters (or everything when unfiltered), fetches each row's image from object storage, and builds an ExcelJS workbook with the images embedded in the image column. The workbook headers match the import template so the file round-trips through the existing import flow. Export progress, image fetch failures and completion counts are surfaced in a status panel.
2026-09-03 12:07:58 +08:00
WuYongJie
b129acdc48 feat(finished-product-progress): add filtered export with embedded images
Add an export action that collects all rows matching the current filters (or everything when unfiltered), fetches each row's image from object storage, and builds an ExcelJS workbook with the images embedded in the image column. The workbook headers match the import template so the file round-trips through the existing import flow. Export progress, image fetch failures and completion counts are surfaced in a status panel.
2026-09-03 12:06:29 +08:00
WuYongJie
ee9a7cb88e feat(supply-chain): add operations selection pools and selected-pool export to supplier recommended products
- selection pools: all/unselected/selected switch on the same page, batch select with
  operator search-confirm (status, operator and time recorded with change logs), batch return
- selected rows stamped with a red 已选款 seal on card/thumbnail/detail images and locked
  in the master pool to avoid accidental re-selection
- operations-role users (or admins) can select/return; service re-validates the operator
- selected-pool export: export endpoint follows all active filters, embeds product images
  into the image column (webp converted via sharp to 320px png, fallback to url text),
  includes selection status/operator/time columns, gated by download permission
2026-09-03 11:46:34 +08:00
WuYongJie
970cd3f234 feat(supply-chain): add operations selection pools and selected-pool export to supplier recommended products
- selection pools: all/unselected/selected switch on the same page, batch select with
  operator search-confirm (status, operator and time recorded with change logs), batch return
- selected rows stamped with a red 已选款 seal on card/thumbnail/detail images and locked
  in the master pool to avoid accidental re-selection
- operations-role users (or admins) can select/return; service re-validates the operator
- selected-pool export: export endpoint follows all active filters, embeds product images
  into the image column (webp converted via sharp to 320px png, fallback to url text),
  includes selection status/operator/time columns, gated by download permission
2026-09-03 11:44:41 +08:00
WuYongJie
7f15c5b756 fix finished product progress order dates 2026-09-03 10:01:26 +08:00
WuYongJie
25f5796dd0 fix finished product progress order dates 2026-09-03 09:54:33 +08:00
WuYongJie
ce34f56c39 feat(users): merchandiser inherits purchase permission subject
采购-跟单(merchandiser,含跟单组与雁兰/槐米特例)解析权限主体时追加采购负责人主体:给采购负责人开通的节点权限与供应链权限对跟单自动生效,无需重复开通;核价与质检主体保持独立。
2026-09-02 16:21:01 +08:00
WuYongJie
7ed6c061c4 feat(users): merchandiser inherits purchase permission subject
采购-跟单(merchandiser,含跟单组与雁兰/槐米特例)解析权限主体时追加采购负责人主体:给采购负责人开通的节点权限与供应链权限对跟单自动生效,无需重复开通;核价与质检主体保持独立。
2026-09-02 16:19:57 +08:00
WuYongJie
15f3331d58 feat(supply-chain): support clipboard paste image upload in supplier recommended product editor
- paste a screenshot anywhere in the drawer to upload and fill the storage url
- add file picker button, uploading state, error message and preview thumbnail
2026-09-02 15:51:02 +08:00
WuYongJie
cc0f5e65f4 feat(supply-chain): add category, card view and unified controls to supplier recommended products
- add category field with migration, import template column and multi-select filter (IN query)
- card view aligned with product selection dashboard style; table/card toggle persisted per browser
- purchaser/shipping-mode filters upgraded to searchable multi-select
- table actions as icon-only buttons with a view entry; date filter opens the picker on click
- column settings: reset to defaults and name search; page styles moved to a plain css file
2026-09-02 15:51:02 +08:00
WuYongJie
607b030034 feat(supply-chain): support clipboard paste image upload in supplier recommended product editor
- paste a screenshot anywhere in the drawer to upload and fill the storage url
- add file picker button, uploading state, error message and preview thumbnail
2026-09-02 15:44:14 +08:00
WuYongJie
021d7eab2b feat(supply-chain): add category, card view and unified controls to supplier recommended products
- add category field with migration, import template column and multi-select filter (IN query)
- card view aligned with product selection dashboard style; table/card toggle persisted per browser
- purchaser/shipping-mode filters upgraded to searchable multi-select
- table actions as icon-only buttons with a view entry; date filter opens the picker on click
- column settings: reset to defaults and name search; page styles moved to a plain css file
2026-09-02 15:44:13 +08:00
WuYongJie
adfecb4c67 feat(intake): add sample measurement and product pricing workbook import/export
sample measurement: export template with image/barcode/L-W-H-weight columns (all batches) and import backfill by barcode into draft rows with per-row skip reasons; product pricing: export template with image/barcode/cost-price and import backfill cost price only; both reuse the product limit workbook pattern, keep edits in draft until the existing confirm/push flow, no API or schema changes.
2026-09-02 15:19:48 +08:00
WuYongJie
5aedfea85c feat(intake): add sample measurement and product pricing workbook import/export
sample measurement: export template with image/barcode/L-W-H-weight columns (all batches) and import backfill by barcode into draft rows with per-row skip reasons; product pricing: export template with image/barcode/cost-price and import backfill cost price only; both reuse the product limit workbook pattern, keep edits in draft until the existing confirm/push flow, no API or schema changes.
2026-09-02 15:19:04 +08:00
WuYongJie
58966bba20 feat(finished-product-progress): align column settings drawer with unified standard
Replace the two-column popover with a right-docked drawer: single-column list with drag handles, checkboxes and lock markers; add column-name search, hide-all and reset-default buttons, and persist unlocked column order locally. Locked columns keep their default positions (trailing sticky actions column).
2026-09-02 14:43:01 +08:00
WuYongJie
7740433ae7 feat(finished-product-progress): align column settings drawer with unified standard
Replace the two-column popover with a right-docked drawer: single-column list with drag handles, checkboxes and lock markers; add column-name search, hide-all and reset-default buttons, and persist unlocked column order locally. Locked columns keep their default positions (trailing sticky actions column).
2026-09-02 14:41:19 +08:00
WuYongJie
5c43428a47 feat: route store account notices to DingTalk group 2026-09-02 13:57:51 +08:00
WuYongJie
7f078abb7b feat: route store account notices to DingTalk group 2026-09-02 13:55:00 +08:00
WuYongJie
940e94882e fix(finished-product-progress): allow negative in-transit quantity for over-delivery
Remove the Math.max(0,...) clamps in the in-transit calculation and delivery-record recompute, and switch the input schema inTransitQuantity validator to a dedicated negative-tolerant one. Ordered and delivered quantities stay non-negative.
2026-09-02 12:22:17 +08:00
WuYongJie
7126984caa feat(finished-product-progress): support clipboard paste image upload in editor drawer 2026-09-02 12:22:17 +08:00
WuYongJie
43b867ef55 feat(finished-product-progress): add contract group separators and alternating band backgrounds 2026-09-02 12:22:17 +08:00
WuYongJie
9c459e7195 fix(finished-product-progress): allow negative in-transit quantity for over-delivery
Remove the Math.max(0,...) clamps in the in-transit calculation and delivery-record recompute, and switch the input schema inTransitQuantity validator to a dedicated negative-tolerant one. Ordered and delivered quantities stay non-negative.
2026-09-02 12:19:07 +08:00
WuYongJie
e4df1b2576 feat(finished-product-progress): support clipboard paste image upload in editor drawer 2026-09-02 12:18:26 +08:00
WuYongJie
b2fc4dde6d feat(finished-product-progress): add contract group separators and alternating band backgrounds 2026-09-02 12:18:11 +08:00
WuYongJie
138dc0d644 feat(supply-chain): add finished product select all 2026-09-02 09:23:04 +08:00
WuYongJie
f91554c7dc feat(supply-chain): add finished product select all 2026-09-02 09:17:39 +08:00
WuYongJie
6ec0258001 Merge branch 'release-finished-product-progress' 2026-09-01 18:32:15 +08:00
WuYongJie
9c66706b67 release finished product progress import and management 2026-09-01 18:32:06 +08:00
WuYongJie
f89bc61af4 fix finished product progress import and management 2026-09-01 18:27:04 +08:00
WuYongJie
3c69088433 fix: map store account subject company header 2026-09-01 17:53:56 +08:00
WuYongJie
e60b3b1e60 fix: map store account subject company header 2026-09-01 17:47:45 +08:00
WuYongJie
d06e45b0c8 fix(supply-chain): support supplier recommendation import images 2026-09-01 17:44:32 +08:00
WuYongJie
03eca07f9f fix(supply-chain): support supplier recommendation import images 2026-09-01 17:38:57 +08:00
WuYongJie
242ed201ba feat(store-accounts): add profit center options 2026-09-01 16:04:51 +08:00
WuYongJie
6b8661dcfd feat(store-accounts): add profit center options 2026-09-01 16:02:49 +08:00
WuYongJie
b3f85d5f5a fix(work-record): persist monthly archive rows with stable ids 2026-09-01 14:33:15 +08:00
WuYongJie
dc6c45848a fix(work-record): persist monthly archive rows with stable ids 2026-09-01 14:31:58 +08:00
WuYongJie
eead468d4d fix(users): use standalone permission navigation 2026-09-01 13:37:19 +08:00
WuYongJie
fb51614a86 fix(users): use standalone permission navigation 2026-09-01 13:35:49 +08:00
WuYongJie
e7996abc6a feat(supply-chain): improve supplier recommended product management 2026-09-01 13:08:04 +08:00
WuYongJie
474f245ba7 feat(supply-chain): add supplier recommended products 2026-09-01 13:07:55 +08:00
WuYongJie
03f308261e feat(supply-chain): improve supplier recommended product management 2026-09-01 13:01:55 +08:00
WuYongJie
934b073eea fix(supply-chain): unify list pagination spacing 2026-09-01 12:37:41 +08:00
WuYongJie
9a3c5f9157 fix(supply-chain): unify list pagination spacing 2026-09-01 12:35:29 +08:00
WuYongJie
6e140e1445 fix(work-record): complete monthly archive release 2026-09-01 12:24:38 +08:00
WuYongJie
0b12ec28b9 feat(work-record): add monthly archive editing permissions 2026-09-01 12:08:25 +08:00
WuYongJie
2b5f49fc51 feat(work-record): add monthly archive editing permissions 2026-09-01 11:59:22 +08:00
WuYongJie
7b7e7d7e28 fix(oa-board): prevent production unified table redirect 2026-09-01 11:12:35 +08:00
WuYongJie
b01579ca99 fix(oa-board): prevent production unified table redirect 2026-09-01 11:10:59 +08:00
WuYongJie
d5f2b68d88 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/local-3001-integration
# Conflicts:
#	furniture-3d-system/agents/script-monitor/README.md
#	furniture-3d-system/agents/script-monitor/agent.mjs
#	furniture-3d-system/agents/script-monitor/config.example.json
#	furniture-3d-system/src/app/api/supply-chain/store-account-management/[id]/bank-account/route.ts
#	furniture-3d-system/src/app/api/supply-chain/store-account-management/profiles/import/route.ts
#	furniture-3d-system/src/app/api/supply-chain/store-account-management/profiles/route.ts
#	furniture-3d-system/src/app/api/supply-chain/store-account-management/profiles/template/route.ts
#	furniture-3d-system/src/app/intake/sample-progress/components/SampleProgressTableRow.tsx
#	furniture-3d-system/src/app/supply-chain/database/store-account-management/StoreAccountManagementView.tsx
#	furniture-3d-system/src/app/supply-chain/script-monitor/ScriptMonitorView.test.tsx
#	furniture-3d-system/src/app/supply-chain/script-monitor/ScriptMonitorView.tsx
#	furniture-3d-system/src/app/supply-chain/script-monitor/page.tsx
#	furniture-3d-system/src/lib/store-account-management.ts
#	furniture-3d-system/src/lib/supply-chain-script-monitor.ts
#	furniture-3d-system/src/server/dto/script-monitor.dto.ts
#	furniture-3d-system/src/server/integrations/notification-center/client.test.ts
#	furniture-3d-system/src/server/integrations/notification-center/client.ts
#	furniture-3d-system/src/server/integrations/notification-center/types.ts
#	furniture-3d-system/src/server/repositories/__tests__/store-account-management.repository.test.ts
#	furniture-3d-system/src/server/repositories/script-monitor.repository.ts
#	furniture-3d-system/src/server/repositories/store-account-management.repository.ts
#	furniture-3d-system/src/server/services/__tests__/notification-delivery.service.test.ts
#	furniture-3d-system/src/server/services/__tests__/store-account-management-export.service.test.ts
#	furniture-3d-system/src/server/services/__tests__/store-account-notification.service.test.ts
#	furniture-3d-system/src/server/services/notification-delivery.service.ts
#	furniture-3d-system/src/server/services/sample-progress.service.test.ts
#	furniture-3d-system/src/server/services/script-monitor.service.test.ts
#	furniture-3d-system/src/server/services/script-monitor.service.ts
#	furniture-3d-system/src/server/services/store-account-management-export.service.ts
#	furniture-3d-system/src/server/services/store-account-notification.service.ts
2026-09-01 11:09:26 +08:00
WuYongJie
a2afbc40bb chore: reconcile worktree snapshot before origin merge (local branch only) 2026-09-01 11:07:53 +08:00
WuYongJie
facc1f0955 feat(supply-chain): restrict store account password visibility 2026-09-01 10:36:27 +08:00
WuYongJie
e38f8e813b feat(supply-chain): restrict store account password visibility 2026-09-01 10:33:49 +08:00
WuYongJie
70e268034e fix(intake): keep default workspace tab available
Cherry-picked as an isolated mainline release from 22227e7cadf00b45056c429f96de489af7c6767c.
2026-09-01 10:11:07 +08:00
WuYongJie
508e0a40d5 fix(intake): keep default workspace tab available 2026-09-01 10:08:05 +08:00
WuYongJie
c0562fdddc fix(intake): keep default workspace tab available 2026-09-01 10:02:57 +08:00
WuYongJie
22227e7cad fix(auth): preserve custom permission role in API context 2026-08-31 18:07:46 +08:00
WuYongJie
7089ada0a0 fix(auth): preserve custom permission role in API context 2026-08-31 18:05:56 +08:00
WuYongJie
9bb36756d1 fix(auth): preserve custom permission role in session 2026-08-31 17:43:30 +08:00
jingchuan
f2a554a330 fix(oa-board): mark XP2026081900000414 terminated 2026-08-31 17:39:04 +08:00
WuYongJie
0aaacb4bff fix(auth): preserve custom permission role in session 2026-08-31 17:38:38 +08:00
WuYongJie
bf7b71ab00 fix(auth): preserve custom permission role in session 2026-08-31 17:36:25 +08:00
WuYongJie
4ecad009b9 cherry-pick: publish approved supply chain updates 2026-08-31 17:17:23 +08:00
WuYongJie
e43bf78c73 feat: publish approved supply chain updates 2026-08-31 17:15:56 +08:00
WuYongJie
fecfd9053e fix: 完善店铺账号通知与筛选体验 2026-08-31 16:34:36 +08:00
WuYongJie
7c6be91a91 fix: 完善店铺账号通知与筛选体验 2026-08-31 16:30:58 +08:00
WuYongJie
7d246e1d5b fix(product-archive): include full export client hook
Add the client hook omitted from the isolated main integration.
2026-08-31 16:02:37 +08:00
WuYongJie
b974d83986 feat(product-archive): add full export and column filters
Applied only the product archive feature patch from 232eaa87 onto origin/main.
2026-08-31 15:52:20 +08:00
WuYongJie
232eaa8768 feat(product-archive): add full export and column filters
Cherry-picked feature patch from c2289ca0 onto latest codex/xuxiake-mainline without including unrelated working-tree changes.
2026-08-31 15:49:13 +08:00
WuYongJie
c2289ca074 feat(product-archive): add full export and column filters 2026-08-31 15:42:07 +08:00
WuYongJie
68916e2791 feat: store account management updates 2026-08-31 13:53:44 +08:00
WuYongJie
72262acfa0 feat: complete store account management updates 2026-08-31 13:52:18 +08:00
WuYongJie
4950135cfc fix: normalize notification line breaks 2026-08-31 12:19:26 +08:00
WuYongJie
d40b6ad197 fix: normalize notification line breaks 2026-08-31 12:15:44 +08:00
WuYongJie
315ede4f3f fix: normalize notification line breaks 2026-08-31 12:13:36 +08:00
WuYongJie
f3b0124d4c feat(intake): add supplier filter and fixed development toolbar 2026-08-31 11:19:57 +08:00
WuYongJie
fb53234811 feat(intake): add supplier filter and fixed development toolbar 2026-08-31 11:17:30 +08:00
WuYongJie
9e51faa192 feat: notify on store account creation 2026-08-31 10:39:08 +08:00
WuYongJie
916930a714 feat: notify on store account creation 2026-08-31 10:38:33 +08:00
WuYongJie
7c17626339 feat: notify on store account creation 2026-08-31 10:27:20 +08:00
WuYongJie
368107c17b release: publish approved sample and finished progress updates 2026-08-31 10:24:00 +08:00
WuYongJie
865be95b6e feat: submit approved sample and finished progress updates 2026-08-31 10:21:29 +08:00
WuYongJie
3efe408a27 merge: release product development base SPU grouping 2026-08-29 16:52:10 +08:00
WuYongJie
b1505b4d63 feat(intake): group product development list by base SPU 2026-08-29 16:14:03 +08:00
WuYongJie
e1b7683bfd fix(supply-chain): include finished product delivery service 2026-08-29 15:35:59 +08:00
WuYongJie
a69bf1997b feat(supply-chain): add multi-delivery tracking to finished product progress 2026-08-29 15:25:36 +08:00
WuYongJie
622fc9d527 feat(supply-chain): refine finished product progress import 2026-08-29 15:17:19 +08:00
WuYongJie
3409a9db50 feat(supply-chain): add multi-delivery tracking to finished product progress 2026-08-29 15:07:12 +08:00
WuYongJie
0f55175d9b fix: respect configured HR SQL Server schema
Use HR_SQLSERVER_SCHEMA for default employee directory queries so production can read the rpt source tables.
2026-08-29 14:07:33 +08:00
WuYongJie
0811bea57c fix: respect configured HR SQL Server schema
Use HR_SQLSERVER_SCHEMA for default employee directory queries so production can read the rpt source tables.
2026-08-29 14:06:54 +08:00
WuYongJie
0ff6f87757 feat(supply-chain): add supplier recommended products 2026-08-29 13:31:45 +08:00
WuYongJie
089845e7ee merge: integrate employee directory account protection 2026-08-29 13:25:24 +08:00
WuYongJie
ab5ea15e80 fix: protect external accounts during employee directory sync 2026-08-29 13:23:26 +08:00
WuYongJie
1347a34d14 feat(supply-chain): refine finished product progress import 2026-08-29 13:08:12 +08:00
WuYongJie
6a32957bf5 fix: protect external accounts during employee directory sync 2026-08-29 12:04:57 +08:00
WuYongJie
9bf54d95d3 fix: protect external accounts during employee directory sync 2026-08-29 12:01:18 +08:00
WuYongJie
dc16d2b75c merge: release script monitor machine deletion 2026-08-28 20:48:38 +08:00
WuYongJie
cd73be673d feat(script-monitor): allow deleting monitored machines 2026-08-28 20:47:47 +08:00
WuYongJie
85c31677c5 merge: release script monitor operations and store account completion
# Conflicts:
#	furniture-3d-system/prisma/schema.prisma
#	furniture-3d-system/src/app/api/supply-chain/store-account-management/[id]/bank-account/route.ts
#	furniture-3d-system/src/app/api/supply-chain/store-account-management/profiles/import/route.ts
#	furniture-3d-system/src/app/api/supply-chain/store-account-management/profiles/route.ts
#	furniture-3d-system/src/app/api/supply-chain/store-account-management/profiles/template/route.ts
2026-08-28 18:28:11 +08:00
WuYongJie
59634f8516 merge: integrate latest shared mainline 2026-08-28 18:23:01 +08:00
WuYongJie
d8495e98ef fix(store-account): complete unified profile workflow 2026-08-28 18:17:01 +08:00
WuYongJie
ea363984a7 merge: release approved store account updates 2026-08-28 17:49:53 +08:00
WuYongJie
47df269785 release: approve store account updates and users build fix 2026-08-28 17:49:53 +08:00
WuYongJie
19e39e0b8c fix: remove invalid users page export 2026-08-28 17:46:29 +08:00
WuYongJie
68c48086df feat: extend store account profiles and bank account 2026-08-28 17:46:14 +08:00
WuYongJie
e34c80cdd2 feat(supply-chain): add script monitor operations 2026-08-28 17:38:51 +08:00
WuYongJie
73b3049e01 fix(store-account): export bank account crypto helpers 2026-08-28 16:31:43 +08:00
WuYongJie
978b609325 merge: release accepted five features and latest long-lived changes 2026-08-28 16:12:43 +08:00
WuYongJie
6e9d0e474f merge: release five accepted features 2026-08-28 16:09:04 +08:00
WuYongJie
240ea4b01a feat(supply-chain): unify store profile entry 2026-08-28 16:07:35 +08:00
WuYongJie
422c23d3e5 release: merge latest development with script monitoring 2026-08-28 15:51:55 +08:00
WuYongJie
f974e7d4b4 feat(intake): bulk maintain barcode print imports 2026-08-28 15:43:15 +08:00
WuYongJie
b27399d908 feat(supply-chain): maintain supplier information by barcode 2026-08-28 15:43:15 +08:00
WuYongJie
cc7e45a225 feat(intake): add fuzzy SKU material import 2026-08-28 15:43:14 +08:00
WuYongJie
0a466dcb2b feat(installation): add hinge articulation motion 2026-08-28 15:43:14 +08:00
WuYongJie
4492c0eb8f feat(supply-chain): add finished product progress detail 2026-08-28 15:43:13 +08:00
WuYongJie
0f336e9d1e feat(supply-chain): add script monitoring center 2026-08-28 15:41:35 +08:00
WuYongJie
4d34a387a9 feat(supply-chain): add store account exports and permissions 2026-08-28 09:41:13 +08:00
WuYongJie
571b840911 feat(supply-chain): add store account exports and permissions 2026-08-28 09:39:08 +08:00
WuYongJie
78cfa85232 release: integrate approved product and notification updates
Includes 13268ee5, 01a9d1e2, 48e496b0, bf85258d.
Store account fix e48229ab is already integrated by parent d8141a63.
2026-08-27 16:39:54 +08:00
WuYongJie
d8141a63a9 fix(supply-chain): allow incomplete store account imports
Isolated main integration of e48229ab.
2026-08-27 16:34:50 +08:00
WuYongJie
bf85258d3c feat(notifications): add product development reminders 2026-08-27 15:13:22 +08:00
WuYongJie
e48229ab22 fix(supply-chain): allow incomplete store account imports 2026-08-27 15:13:21 +08:00
WuYongJie
48e496b01b fix(intake): preserve confirmation after factory edits 2026-08-27 15:13:20 +08:00
WuYongJie
01a9d1e2c8 fix(intake): default product type to all 2026-08-27 15:13:20 +08:00
WuYongJie
13268ee5b5 feat(intake): default sku material compliance 2026-08-27 15:13:19 +08:00
WuYongJie
55c99cbc4d feat(sample-progress): enhance detail collaboration 2026-08-27 13:53:01 +08:00
WuYongJie
023c4c07d2 feat(sample-progress): enhance detail collaboration 2026-08-27 13:52:56 +08:00
WuYongJie
37074cf25b feat(supply-chain): stream store account import progress 2026-08-27 13:14:23 +08:00
WuYongJie
1619213039 feat(supply-chain): stream store account import progress 2026-08-27 13:11:11 +08:00
WuYongJie
5da6c34758 feat(installation): auto-explode unnamed assemblies 2026-08-26 18:29:15 +08:00
WuYongJie
879a73e480 feat(supply-chain): add product, supplier, and store management 2026-08-26 18:28:55 +08:00
WuYongJie
629ad42104 feat(installation): auto-explode unnamed assemblies 2026-08-26 18:19:24 +08:00
WuYongJie
a34dee6825 feat(supply-chain): add product, supplier, and store management 2026-08-26 18:18:41 +08:00
WuYongJie
8b8a41f2d7 fix(intake): preserve sku identities on delete 2026-08-26 16:49:42 +08:00
WuYongJie
3f5cf79cc2 fix(intake): preserve sku identities on delete 2026-08-26 16:48:22 +08:00
WuYongJie
c093c32e1d fix(intake): preserve sku identities on delete 2026-08-26 16:46:57 +08:00
WuYongJie
07d6d0d03f fix(intake): isolate basic info confirmation by batch 2026-08-26 16:25:41 +08:00
WuYongJie
71e746b5f5 fix(intake): isolate basic info confirmation by batch 2026-08-26 16:23:46 +08:00
WuYongJie
9761465d45 fix(intake): isolate basic info confirmation by batch 2026-08-26 16:20:04 +08:00
WuYongJie
aa5d983b7d merge: release SKU batch workbook isolation 2026-08-26 13:19:46 +08:00
WuYongJie
d0ddbb6ccf fix(intake): isolate SKU batch workbook imports 2026-08-26 13:17:16 +08:00
WuYongJie
77b3b3c800 merge: release daily Jushuitan fixed virtual inventory 2026-08-25 14:27:28 +08:00
WuYongJie
2cd254fee5 fix(jushuitan): schedule fixed virtual inventory daily 2026-08-25 14:26:02 +08:00
WuYongJie
ffc9c1a727 fix(jushuitan): schedule fixed virtual inventory daily 2026-08-25 14:07:36 +08:00
jingchuan
b23e4122f2 feat(supply-chain): organize sample timing by plan tabs 2026-08-25 13:04:30 +08:00
WuYongJie
42e4503ce6 test(auth): cover sample editor permission scope 2026-08-25 11:12:55 +08:00
jingchuan
336b47a5fc fix: classify sample timing by review product type 2026-08-25 10:35:32 +08:00
jingchuan
ecf4d4f743 fix: pass supply chain scope through sample editor 2026-08-24 18:00:47 +08:00
jingchuan
5984f82c75 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/jingchuan-sample-dimensions-preview-20260824 2026-08-24 17:57:37 +08:00
jingchuan
2e33b9b1c0 feat: refine sample timing and procurement analysis 2026-08-24 17:56:55 +08:00
WuYongJie
73ffcb17bb feat(users): create suppliers from warehouse directory 2026-08-24 17:43:52 +08:00
WuYongJie
8365286651 feat(auth): enforce permission contract 2026-08-24 17:43:52 +08:00
WuYongJie
b497c2d061 fix(intake): preserve basic info confirmation after factory sync 2026-08-24 16:42:03 +08:00
WuYongJie
10c32b2c97 fix(intake): preserve basic info confirmation after factory sync 2026-08-24 16:40:58 +08:00
WuYongJie
bfbe044005 feat(sample-progress): move editing into drawer 2026-08-24 10:20:59 +08:00
WuYongJie
0fa4481719 fix(intake): project factory model for barcode printing 2026-08-24 09:21:11 +08:00
WuYongJie
b0a9aa0c4b feat(intake): sync factory-confirmed SKUs to barcode printing 2026-08-21 18:32:51 +08:00
jingchuan
fcdf25ed38 fix(supply-chain): align flow detail dates with status 2026-08-21 17:34:26 +08:00
jingchuan
e8531fde1d feat(supply-chain): focus sample owner load on inflight tasks 2026-08-21 17:16:39 +08:00
jingchuan
64f1b2732b merge: synchronize latest production mainline before termination fix 2026-08-21 16:44:51 +08:00
jingchuan
9a68b886ac merge: synchronize latest shared mainline before termination fix 2026-08-21 16:44:43 +08:00
jingchuan
9bb14e391d fix(oa-board): preserve terminated opening status 2026-08-21 16:44:20 +08:00
jingchuan
d252924a21 feat(supply-chain): add sample performance analysis 2026-08-21 16:27:39 +08:00
WuYongJie
19f9affe5c 供应链:打样进度明细移入采购管理 2026-08-21 15:20:29 +08:00
jingchuan
b15c292f12 merge: synchronize shared mainline before OA binding release 2026-08-21 13:36:48 +08:00
jingchuan
03c97d234b merge: persist OA historical order binding 2026-08-21 13:33:18 +08:00
WuYongJie
b1cebf0707 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/local-3001-integration
# Conflicts:
#	furniture-3d-system/src/app/supply-chain/database/product-archive/ProductArchiveView.tsx
#	furniture-3d-system/src/lib/permissions.ts
#	furniture-3d-system/src/lib/workspace-route-permissions.ts
#	furniture-3d-system/src/server/core/types.ts
#	furniture-3d-system/src/server/repositories/user.repository.ts
#	furniture-3d-system/src/server/services/auth.service.ts
2026-08-21 13:11:21 +08:00
WuYongJie
58fa0c7133 test(users): cover permission role activation 2026-08-21 11:47:16 +08:00
WuYongJie
2631849409 test(users): cover permission role activation 2026-08-21 11:46:33 +08:00
WuYongJie
e5985cf4cd feat(users): add administrator account filter 2026-08-21 11:33:32 +08:00
WuYongJie
bd651338dc feat(users): add administrator account filter 2026-08-21 11:30:21 +08:00
WuYongJie
022298db92 refactor(supply-chain): clarify sync and UI ownership
Integrate the reviewed supply-chain structure governance scope without unpublished image-search changes.
2026-08-21 11:12:34 +08:00
WuYongJie
d0c11dd979 refactor(supply-chain): clarify sync and UI ownership
Integrate the reviewed supply-chain structure governance scope without unpublished image-search changes.
2026-08-21 11:12:34 +08:00
WuYongJie
a26f53aaba refactor(supply-chain): clarify sync and UI ownership 2026-08-21 10:54:30 +08:00
jingchuan
1075eea0aa fix(oa-board): bind historical order approval 2026-08-21 10:45:26 +08:00
WuYongJie
b15329bec8 feat(users): sync permissions with real navigation 2026-08-21 10:34:45 +08:00
WuYongJie
9faa52d91d feat(users): sync permissions with real navigation 2026-08-21 10:34:45 +08:00
WuYongJie
c8c06c88e9 Merge origin/main into shared development mainline 2026-08-21 10:14:29 +08:00
WuYongJie
4fe426ce56 fix(intake): prevent modular barcode prefix clipping 2026-08-21 09:38:44 +08:00
WuYongJie
e8990d7e63 fix(intake): prevent modular barcode prefix clipping 2026-08-21 09:36:44 +08:00
WuYongJie
075f37f31f feat(users): redesign account and role permissions 2026-08-20 17:47:21 +08:00
WuYongJie
095bae1be8 feat(users): redesign account and role permissions 2026-08-20 17:40:21 +08:00
WuYongJie
1e035f10a4 feat(supply-chain): sync clearance stock 2026-08-20 16:34:46 +08:00
WuYongJie
f5d7cfb2df feat(supply-chain): sync clearance stock 2026-08-20 16:32:55 +08:00
jingchuan
26ce017921 feat(supply-chain): streamline terminated task details 2026-08-20 15:20:22 +08:00
WuYongJie
10ae34fc4a fix(intake): split modular barcode suffix 2026-08-20 15:12:22 +08:00
WuYongJie
482858405c feat(supply-chain): read JST public available stock 2026-08-20 15:12:22 +08:00
WuYongJie
aae05326ab fix(intake): split modular barcode suffix 2026-08-20 15:09:12 +08:00
WuYongJie
b20ffaa30f feat(supply-chain): read JST public available stock 2026-08-20 15:09:12 +08:00
WuYongJie
07516303d4 fix(intake): fit long certificate product names 2026-08-20 13:55:35 +08:00
WuYongJie
61c66362bb fix(intake): fit long certificate product names 2026-08-20 13:51:46 +08:00
jingchuan
633b7a37dd feat(supply-chain): filter termination feedback by creator 2026-08-20 11:00:41 +08:00
jingchuan
fa32c6bec4 fix(supply-chain): archive missing termination instances 2026-08-20 10:37:22 +08:00
jingchuan
22744b28c8 feat(supply-chain): archive termination reasons 2026-08-20 10:28:25 +08:00
jingchuan
2897f3b0c6 fix(supply-chain): refine terminated task drilldowns 2026-08-19 17:58:54 +08:00
jingchuan
718c6a8886 merge: add terminated task feedback 2026-08-19 16:59:54 +08:00
jingchuan
32fedbe898 feat(supply-chain): add terminated task feedback 2026-08-19 16:58:13 +08:00
WuYongJie
0bf579a6f0 merge: add admin barcode data export 2026-08-19 15:03:41 +08:00
WuYongJie
1dc2c04b20 feat(intake): add admin barcode data export 2026-08-19 15:02:48 +08:00
WuYongJie
e645a71283 merge: align permission nodes and add pricing role 2026-08-19 14:50:38 +08:00
WuYongJie
9a8c25fe24 fix(users): align permission nodes and add pricing role 2026-08-19 14:48:09 +08:00
WuYongJie
8ee0dd21fe feat(users): refine permission management 2026-08-19 13:50:13 +08:00
WuYongJie
c0aab147bf feat(users): refine permission management 2026-08-19 13:44:38 +08:00
jingchuan
52ac60cf29 merge: fix near-overtime display precision 2026-08-19 13:26:14 +08:00
jingchuan
6178d09e31 fix(supply-chain): round near-overtime remaining days 2026-08-19 13:25:45 +08:00
jingchuan
7e772dcfa8 merge: publish timing hover summaries 2026-08-19 13:06:33 +08:00
jingchuan
1f9293cc42 feat(supply-chain): refine timing hover summaries 2026-08-19 13:04:46 +08:00
jingchuan
e2b711c0df merge: include material in procurement timing 2026-08-19 12:01:08 +08:00
jingchuan
94f754c80b fix(supply-chain): include material in procurement timing 2026-08-19 11:11:02 +08:00
WuYongJie
2d1516e621 merge: add product archive scrollbar wheel 2026-08-19 11:06:41 +08:00
WuYongJie
68051dd0bf feat(supply-chain): add product archive scrollbar wheel 2026-08-19 11:05:41 +08:00
WuYongJie
a8184ae024 merge: fix installation demo snapshot resave 2026-08-19 10:40:36 +08:00
WuYongJie
efbf1c1a41 fix(installation-demo): preserve existing snapshots on resave 2026-08-19 10:39:33 +08:00
WuYongJie
66dced1c3f merge: add fee ratio and operating profit to product archive 2026-08-19 10:03:04 +08:00
WuYongJie
6024abe7aa feat(supply-chain): add fee ratio and operating profit 2026-08-19 10:01:21 +08:00
jingchuan
b16320c352 merge: publish supply-chain new product timing drilldown 2026-08-19 09:39:26 +08:00
jingchuan
8cfd3f8292 fix(supply-chain): preserve new product overview entry 2026-08-19 09:37:15 +08:00
jingchuan
053a603308 feat(supply-chain): add running timing department drilldown 2026-08-19 09:34:18 +08:00
WuYongJie
90eeba280d Merge sample progress detail rebuild into main
Includes only f8555a49: the approved sample progress detail table and its API, persistence, navigation, history, and migration changes.
2026-08-19 09:00:52 +08:00
WuYongJie
f8555a4946 feat: rebuild sample progress detail
Implement the complete sample progress detail table from the approved production baseline, including source-derived timing fields, editable sampling fields, review links, change history, pagination and supply-chain navigation updates.
2026-08-19 09:00:13 +08:00
jingchuan
b840de8d55 merge: supply-chain timing departments into main 2026-08-18 19:12:05 +08:00
jingchuan
641a162675 merge: completed timing department analysis 2026-08-18 19:06:19 +08:00
jingchuan
d507aa08f7 feat(supply-chain): drill into department overtime flows 2026-08-18 19:02:08 +08:00
jingchuan
90e58ecaf7 feat(supply-chain): add completed timing department metrics 2026-08-18 18:49:20 +08:00
WuYongJie
f0730ec03d fix: stabilize installation shares and restore supply-chain home navigation 2026-08-18 18:17:02 +08:00
WuYongJie
a51936ed98 Merge remote-tracking branch 'origin/main' into codex/wuyongjie-bom-source-retry-release 2026-08-18 17:01:56 +08:00
WuYongJie
91026fccd7 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/wuyongjie-bom-source-retry-release 2026-08-18 16:55:27 +08:00
jingchuan
45f8aaf449 Merge shared timing image fix into main 2026-08-18 16:52:17 +08:00
jingchuan
6b6564e59a Merge timing detail image preview fix 2026-08-18 16:52:01 +08:00
jingchuan
58aa36720b fix(supply-chain): enlarge timing detail images 2026-08-18 16:50:26 +08:00
WuYongJie
5e20f8178f Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/wuyongjie-bom-source-retry-release 2026-08-18 16:48:10 +08:00
WuYongJie
239cae7b5a Merge branch 'codex/wuyongjie-bom-source-retry' into codex/wuyongjie-bom-source-retry-integration 2026-08-18 16:43:22 +08:00
WuYongJie
f2599a5a37 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/wuyongjie-bom-source-retry 2026-08-18 16:41:22 +08:00
WuYongJie
2db8e39666 fix(oa): keep page module exports Next-compatible 2026-08-18 16:39:30 +08:00
WuYongJie
e267426f5e Merge BOM-only session redirect fix 2026-08-18 16:33:51 +08:00
WuYongJie
cfe9ce4e7b fix(auth): preserve BOM-only session source 2026-08-18 16:32:58 +08:00
WuYongJie
e9cd4e312a fix(auth): preserve BOM-only session source 2026-08-18 16:32:30 +08:00
WuYongJie
8d09d19206 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/wuyongjie-bom-source-retry 2026-08-18 16:16:48 +08:00
WuYongJie
d3b4d56934 fix(bom): clarify source read failures and allow retry 2026-08-18 16:16:42 +08:00
WuYongJie
f5cc1764cc merge: release workspace switcher 2026-08-18 16:09:25 +08:00
WuYongJie
6f10780bc5 feat(auth): add BOM-costing-only account access 2026-08-18 15:59:08 +08:00
WuYongJie
d264efc2e7 feat(auth): add BOM-costing-only account access 2026-08-18 15:57:39 +08:00
WuYongJie
63b37b564a feat(auth): add BOM-costing-only account access 2026-08-18 15:57:05 +08:00
WuYongJie
3ba90b83e0 feat(navigation): add workspace switcher 2026-08-18 15:56:01 +08:00
WuYongJie
1ffee0d6cc merge: release installation demo part material workflow 2026-08-18 15:19:19 +08:00
WuYongJie
ec5875367a feat(installation-demo): add part material editing workflow 2026-08-18 15:16:20 +08:00
jingchuan
d6e78edaf2 Merge shared supply-chain timing overview into main 2026-08-18 15:02:00 +08:00
jingchuan
75f7b3ac7f Merge supply-chain new product timing overview 2026-08-18 15:01:20 +08:00
jingchuan
df3a8a7894 Merge latest shared mainline before supply-chain timing release 2026-08-18 14:59:34 +08:00
jingchuan
d8d254598b feat(supply-chain): refine timing metrics and detail imagery 2026-08-18 14:57:41 +08:00
jingchuan
b83a95df06 feat(supply-chain): split completed and running timing 2026-08-18 12:52:54 +08:00
jingchuan
20c6433273 fix(supply-chain): use single-select opening brand metric 2026-08-18 09:13:48 +08:00
WuYongJie
033c1058e9 merge: release BOM completion feedback 2026-08-18 00:33:11 +08:00
WuYongJie
86b60103c1 merge: align BOM completion feedback 2026-08-18 00:32:56 +08:00
WuYongJie
51f4c97489 fix(bom-costing): align completed history status 2026-08-18 00:27:14 +08:00
WuYongJie
4a8cbcdcb3 fix(bom-costing): refresh completed run feedback 2026-08-18 00:18:20 +08:00
WuYongJie
c30b094194 merge: synchronize BOM estimate result-first flow 2026-08-17 23:39:56 +08:00
WuYongJie
2be5f59220 merge: preserve BOM estimates after structure review 2026-08-17 23:39:17 +08:00
WuYongJie
c80c06d2f7 fix(bom-costing): preserve estimates after structure review 2026-08-17 23:22:50 +08:00
WuYongJie
4c03c35e8d Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/wuyongjie-bom-estimate-release-20260817 2026-08-17 21:21:18 +08:00
WuYongJie
c7da99562d Merge remote-tracking branch 'origin/codex/wuyongjie-bom-1688-realtime-cost' into codex/wuyongjie-bom-estimate-integration-20260817 2026-08-17 21:21:12 +08:00
WuYongJie
f08d4ff5c4 fix(bom-costing): read stored images through object storage 2026-08-17 21:20:56 +08:00
WuYongJie
fece43291b Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/wuyongjie-bom-estimate-release-20260817 2026-08-17 21:14:11 +08:00
WuYongJie
e674843455 Merge remote-tracking branch 'origin/codex/wuyongjie-bom-1688-realtime-cost' into codex/wuyongjie-bom-estimate-integration-20260817 2026-08-17 21:13:50 +08:00
WuYongJie
c038bcedbe fix(bom-costing): fetch stored images for realtime estimates 2026-08-17 21:13:23 +08:00
WuYongJie
f64fac7a68 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/wuyongjie-bom-estimate-release-20260817 2026-08-17 20:59:43 +08:00
WuYongJie
6f0fdf3c71 Merge remote-tracking branch 'origin/codex/wuyongjie-bom-1688-realtime-cost' into codex/wuyongjie-bom-estimate-integration-20260817 2026-08-17 20:58:59 +08:00
WuYongJie
7f67bd858c Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/wuyongjie-bom-1688-realtime-cost 2026-08-17 20:54:52 +08:00
WuYongJie
d3a1049b55 feat(bom-costing): complete unified cost estimates 2026-08-17 20:54:45 +08:00
jingchuan
62e7ea28e4 fix(supply-chain): recognize configured node stage sla 2026-08-17 19:33:38 +08:00
jingchuan
e5e7c3bd07 fix(supply-chain): map review-stage sla 2026-08-17 19:26:58 +08:00
jingchuan
9a17715a21 fix(supply-chain): correct new product overview metrics 2026-08-17 19:19:14 +08:00
jingchuan
41b33c731c fix(oa-board): restore original workflow dashboard entry 2026-08-17 19:00:16 +08:00
jingchuan
156b431dda fix(intake): preserve existing new product dashboard 2026-08-17 18:53:46 +08:00
WuYongJie
fa48bcc48d Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/wuyongjie-bom-1688-realtime-cost 2026-08-17 18:48:08 +08:00
WuYongJie
4e892573df fix(bom-costing): sign 1688 image search requests 2026-08-17 18:48:02 +08:00
jingchuan
5ac98a6b82 fix(supply-chain): show product overview in sidebar 2026-08-17 18:46:47 +08:00
jingchuan
5441d1786d feat: add executive overview to supply chain new products 2026-08-17 18:36:57 +08:00
WuYongJie
5cfbcaa5fe feat(installation-demo): refine printable drawing workflow 2026-08-17 14:55:22 +08:00
jingchuan
330cf30ac9 feat: expose new product management dashboard 2026-08-17 13:44:30 +08:00
jingchuan
5af369ef3d feat: add new product management executive dashboard 2026-08-17 13:36:46 +08:00
WuYongJie
0c782238af Merge product archive sales performance into main 2026-08-17 12:09:00 +08:00
WuYongJie
5d60abd57b feat(supply-chain): sync product archive sales performance 2026-08-17 12:07:57 +08:00
jingchuan
ab66b20893 Merge OA latest child flow selection into main 2026-08-17 11:40:00 +08:00
jingchuan
dded0237d0 Merge OA latest child flow selection 2026-08-17 11:39:18 +08:00
jingchuan
fb4fa3efca fix(oa-board): prefer latest restarted child flow 2026-08-17 11:38:37 +08:00
WuYongJie
6a3bd0fa22 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/wuyongjie-bom-1688-realtime-cost 2026-08-17 10:29:00 +08:00
jingchuan
9929f6a3c6 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' 2026-08-17 09:14:56 +08:00
jingchuan
04379751f6 Merge remote-tracking branch 'origin/codex/jingchuan-unified-table-stage-fix' into codex/xuxiake-mainline 2026-08-17 09:14:41 +08:00
jingchuan
8c2776ec1d Rename sample progress detail view 2026-08-17 09:14:25 +08:00
jingchuan
54548071ad Merge remote-tracking branch 'origin/codex/xuxiake-mainline' 2026-08-16 20:33:41 +08:00
jingchuan
e24adfa492 Merge remote-tracking branch 'origin/codex/jingchuan-unified-table-stage-fix' into codex/xuxiake-mainline 2026-08-16 20:33:28 +08:00
jingchuan
54af0add08 Rename unified table to new product progress summary 2026-08-16 20:33:08 +08:00
jingchuan
d8dd85d380 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' 2026-08-16 20:21:21 +08:00
jingchuan
867de78fe7 Merge remote-tracking branch 'origin/codex/jingchuan-unified-table-stage-fix' into codex/xuxiake-mainline 2026-08-16 20:21:06 +08:00
jingchuan
cd4b6f7023 fix(supply-chain): move timing view toggle to table header 2026-08-16 20:19:52 +08:00
jingchuan
ec687f4788 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' 2026-08-16 19:57:21 +08:00
jingchuan
e0fb0f22a4 Merge remote-tracking branch 'origin/codex/jingchuan-unified-table-stage-fix' into codex/xuxiake-mainline 2026-08-16 19:57:10 +08:00
jingchuan
816d2ff544 fix(supply-chain): correct unified table stage groups 2026-08-16 19:56:54 +08:00
jingchuan
59a1449d73 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' 2026-08-16 17:26:06 +08:00
jingchuan
7b5fea54c5 fix(supply-chain): refine unified table layout 2026-08-16 17:25:54 +08:00
jingchuan
bd33cfc936 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' 2026-08-16 16:35:05 +08:00
jingchuan
b69f1c8eb6 Merge branch 'codex/jingchuan-unified-table-groups' into codex/xuxiake-mainline 2026-08-16 16:34:48 +08:00
jingchuan
016280c1a3 feat(supply-chain): group unified table columns 2026-08-15 18:28:54 +08:00
jingchuan
f78f8c1cf4 Merge supply chain new product views 2026-08-15 17:41:08 +08:00
jingchuan
7a1d05b7db Merge sample progress and supply chain new product views
# Conflicts:
#	furniture-3d-system/src/app/supply-chain/config/supply-chain-menu.test.ts
2026-08-15 17:40:03 +08:00
jingchuan
ceda595797 feat(supply-chain): add new product data views 2026-08-15 17:27:50 +08:00
WuYongJie
5082213a11 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/wuyongjie-bom-1688-realtime-cost 2026-08-15 17:07:11 +08:00
WuYongJie
5b7435f218 Merge supply chain business permissions 2026-08-15 17:06:57 +08:00
WuYongJie
57b502e1c3 feat(bom-costing): prioritize realtime 1688 procurement estimates 2026-08-15 17:06:46 +08:00
WuYongJie
65c1cd6d93 Merge supply chain business permissions 2026-08-15 17:05:53 +08:00
WuYongJie
465a92612f feat(supply-chain): add business permission controls 2026-08-15 17:05:19 +08:00
WuYongJie
8ffbea63ce Merge installation demo drawing generator 2026-08-15 16:56:38 +08:00
WuYongJie
8b1cb357ea Merge installation demo drawing generator 2026-08-15 16:55:43 +08:00
WuYongJie
d711742300 feat(installation-demo): add printable installation drawings 2026-08-15 16:55:19 +08:00
WuYongJie
9142d24612 Merge development mainline for BOM GPT reasoning fix 2026-08-15 16:11:05 +08:00
WuYongJie
72f2519e3a Merge BOM GPT reasoning fix 2026-08-15 16:10:34 +08:00
WuYongJie
d0eb2d4bd4 fix(bom-costing): use supported GPT-5 reasoning effort 2026-08-15 16:09:56 +08:00
WuYongJie
2972a8fb7a Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/wuyongjie-bom-ai-release-20260815 2026-08-15 15:50:51 +08:00
WuYongJie
d2c6f0749a Merge remote-tracking branch 'origin/codex/wuyongjie-bom-ai-estimation' into codex/wuyongjie-bom-ai-integration-20260815 2026-08-15 15:46:40 +08:00
WuYongJie
a0029c7dec feat(bom-costing): estimate unresolved lines with multimodal model 2026-08-15 15:42:33 +08:00
WuYongJie
07008eeeb7 fix(intake): keep patent workspace on full product source 2026-08-14 15:05:27 +08:00
WuYongJie
16b43cba11 feat(intake): paginate product patent ledger 2026-08-14 14:09:23 +08:00
WuYongJie
c3566c4b83 Merge remote-tracking branch 'origin/main' into codex/local-3001-integration 2026-08-14 13:08:16 +08:00
WuYongJie
026ea66c62 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/local-3001-integration 2026-08-14 13:06:32 +08:00
WuYongJie
4511c0ad51 fix: include selected patent applications in detail 2026-08-14 12:10:33 +08:00
WuYongJie
c0f9c147fa merge: release flip shoe cabinet costing fix 2026-08-14 11:49:25 +08:00
WuYongJie
ecce8a1a28 merge: fix flip shoe cabinet costing 2026-08-14 11:41:34 +08:00
WuYongJie
7c53b42199 fix(bom-costing): classify flip shoe cabinets correctly 2026-08-14 11:37:57 +08:00
WuYongJie
8016482127 merge(main): release product progress completion filters 2026-08-14 10:09:36 +08:00
WuYongJie
413debe66b merge(intake): add product progress completion filters 2026-08-14 10:08:29 +08:00
WuYongJie
f8d877c88c feat(intake): filter product progress by completion time 2026-08-14 10:07:34 +08:00
WuYongJie
c6c2790354 merge(main): retire sku operator archive source 2026-08-14 09:42:25 +08:00
WuYongJie
b2e672139e refactor(supply-chain): retire sku operator source 2026-08-14 09:40:23 +08:00
WuYongJie
0d6d080687 refactor(supply-chain): retire sku operator source 2026-08-14 09:39:20 +08:00
WuYongJie
ec38c6e64a merge(main): release on-demand product archive images 2026-08-14 08:55:33 +08:00
WuYongJie
d786515831 fix(supply-chain): cache material images on SPU lookup 2026-08-14 08:54:21 +08:00
WuYongJie
032b609f1b fix(supply-chain): cache material images on SPU lookup 2026-08-14 08:53:05 +08:00
WuYongJie
502d85decb merge(main): release archive group header alignment 2026-08-13 14:53:46 +08:00
jingchuan
88fbdbacd2 fix(sample-progress): match flow detail typography and filter defaults 2026-08-13 14:51:25 +08:00
WuYongJie
42ad3299a3 fix(supply-chain): center archive group headers 2026-08-13 14:45:24 +08:00
WuYongJie
bdb21cd824 fix(supply-chain): center archive group headers 2026-08-13 14:39:27 +08:00
jingchuan
a5c0a4f83d fix(sample-progress): preserve selected calendar dates 2026-08-13 14:37:36 +08:00
jingchuan
7371676f6f fix(sample-progress): restrict deletion and optional sample fields 2026-08-13 14:11:01 +08:00
WuYongJie
6acbc75a09 merge(main): release BOM responsive inspector and sample progress 2026-08-13 14:03:11 +08:00
WuYongJie
7b46654cb7 merge(sample-progress): preserve latest production flow 2026-08-13 14:01:36 +08:00
jingchuan
2ab42d68e1 fix(sample-progress): compact header and filter overdue items 2026-08-13 13:55:46 +08:00
WuYongJie
2199376f11 Merge branch 'codex/jingchuan-sample-progress-main' into main 2026-08-13 13:42:14 +08:00
WuYongJie
4192f27b17 Merge branch 'codex/xuxiake-mainline' into main 2026-08-13 13:40:10 +08:00
WuYongJie
ea834d8dea Merge branch 'codex/wuyongjie-bom-responsive-inspector' into codex/xuxiake-mainline 2026-08-13 13:39:34 +08:00
jingchuan
f34d938e2e fix(sample-progress): use fixed scrollable table workspace 2026-08-13 13:38:02 +08:00
WuYongJie
f6b28ecd63 fix(bom-costing): keep recalculation controls in view 2026-08-13 13:30:06 +08:00
jingchuan
ade0751701 fix(sample-progress): calculate dwell time and anomalies 2026-08-13 13:25:38 +08:00
WuYongJie
2ba8ab0f05 Merge commit '62017377' into codex/wuyongjie-promote-bom-optional-20260813 2026-08-13 12:38:47 +08:00
WuYongJie
62017377ad fix(bom): preserve resolved primary material 2026-08-13 12:36:47 +08:00
WuYongJie
2905c42455 Merge remote-tracking branch 'origin/codex/jingchuan-sample-progress-main' into codex/wuyongjie-promote-bom-optional-20260813 2026-08-13 12:15:27 +08:00
jingchuan
ce808f8c07 feat(sample-progress): allow no-sample status 2026-08-13 12:14:43 +08:00
WuYongJie
915450a748 Merge remote-tracking branch 'origin/codex/jingchuan-sample-progress-main' into codex/wuyongjie-promote-bom-optional-20260813 2026-08-13 12:11:31 +08:00
WuYongJie
adae1ac0f1 Merge remote-tracking branch 'origin/codex/wuyongjie-bom-category-skills-v7' into codex/wuyongjie-promote-bom-optional-20260813 2026-08-13 12:11:10 +08:00
jingchuan
db844e6126 fix(sample-progress): derive sample status from OA stage 2026-08-13 12:09:44 +08:00
WuYongJie
cdb807dcd5 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/wuyongjie-bom-category-skills-v7 2026-08-13 12:08:42 +08:00
WuYongJie
97ade48cf8 fix(bom): preserve trusted slot geometry 2026-08-13 12:08:13 +08:00
WuYongJie
af97ea7074 merge: sync product archive operators 2026-08-13 12:02:14 +08:00
WuYongJie
138155b04a feat(supply-chain): sync product archive operators 2026-08-13 12:01:02 +08:00
WuYongJie
609e675659 merge: preserve latest sample progress stage alignment 2026-08-13 11:02:08 +08:00
WuYongJie
218a7d91a6 merge: preserve deployed sample progress updates 2026-08-13 11:00:32 +08:00
jingchuan
5318a30346 fix(sample-progress): align board with current OA stage 2026-08-13 10:57:13 +08:00
WuYongJie
c21b384050 merge: add storage rack and table v2 skills 2026-08-13 10:55:04 +08:00
WuYongJie
acd22bbffa feat(bom): add storage rack and table v2 skills 2026-08-13 10:54:26 +08:00
jingchuan
1433428cf7 fix(sample-progress): show current OA sample stage count 2026-08-13 10:38:22 +08:00
WuYongJie
5c05df5855 fix(bom): preserve sku material and module geometry 2026-08-13 09:56:21 +08:00
WuYongJie
35384031c6 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/wuyongjie-bom-category-skills-v7 2026-08-13 09:28:12 +08:00
WuYongJie
fee8bdb0a8 fix(bom): harden category skill costing contracts 2026-08-13 09:27:59 +08:00
jingchuan
e2d739d1d4 fix(sample-progress): count only active managed samples 2026-08-13 09:08:33 +08:00
WuYongJie
f12b68ff56 Merge remote-tracking branch 'origin/codex/wuyongjie-bom-category-skills-v7' into codex/wuyongjie-promote-bom-optional-20260813 2026-08-13 06:32:43 +08:00
WuYongJie
869f0e6922 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/wuyongjie-bom-category-skills-v7 2026-08-13 06:30:22 +08:00
WuYongJie
76421163c7 fix(bom-costing): enforce exclusive sku structure 2026-08-13 06:30:01 +08:00
WuYongJie
439b427259 Merge remote-tracking branch 'origin/codex/wuyongjie-bom-category-skills-v7' into codex/wuyongjie-promote-bom-optional-20260813 2026-08-13 04:49:02 +08:00
WuYongJie
6f8fc02b2f Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/wuyongjie-bom-category-skills-v7 2026-08-13 04:46:13 +08:00
WuYongJie
b12d1eeeb3 fix(bom-costing): preserve sku evidence and size scaling 2026-08-13 04:45:31 +08:00
WuYongJie
0c9491a370 merge: promote BOM optional SKU structure fix 2026-08-13 02:52:34 +08:00
WuYongJie
37430946d8 fix(bom-costing): isolate optional SKU structures 2026-08-13 02:51:12 +08:00
WuYongJie
eb0a6ad499 fix(bom-costing): restore layered category estimates 2026-08-13 01:18:19 +08:00
WuYongJie
de048075ef Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/wuyongjie-bom-category-skills-v7
# Conflicts:
#	furniture-3d-system/src/server/services/__tests__/intake-non-integrated-product.service.test.ts
#	furniture-3d-system/src/server/services/intake-non-integrated-product.service.ts
2026-08-12 21:06:18 +08:00
WuYongJie
c87266c2c7 fix(intake): bound virtual inventory processing 2026-08-12 20:51:03 +08:00
WuYongJie
a51ec8a162 fix(bom-costing): guard fact snapshot fingerprints 2026-08-12 20:49:07 +08:00
WuYongJie
14915ef1f2 fix(supply-chain): resolve new-product images by barcode 2026-08-12 18:10:08 +08:00
jingchuan
7a25001d6b fix(sample-progress): retain reached cancelled sample nodes 2026-08-12 17:48:52 +08:00
jingchuan
fd0354f1d0 fix(sample-progress): sync all OA flow statuses 2026-08-12 17:34:26 +08:00
WuYongJie
ae9ae0fcae Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/wu-product-development-barcode-print-20260812 2026-08-12 17:32:37 +08:00
WuYongJie
a36b5ede46 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/wu-product-development-barcode-print-20260812 2026-08-12 17:29:44 +08:00
WuYongJie
e2a725ed58 feat(barcode-print): add barcode QR to Sofia carton label 2026-08-12 17:29:12 +08:00
WuYongJie
0b4f903325 fix(intake): require directory selections for suppliers and warehouses 2026-08-12 17:22:41 +08:00
jingchuan
8d7ab94cac fix(sample-progress): sync cancelled and terminated flows 2026-08-12 16:54:33 +08:00
jingchuan
27b16a9ce6 fix(sample-progress): refine board fields and unique codes 2026-08-12 16:20:53 +08:00
jingchuan
09dd4a1730 fix(sample-progress): normalize compact delivery dates 2026-08-12 16:04:59 +08:00
jingchuan
fc4763a8c9 fix(sample-progress): use configured prisma client for import 2026-08-12 16:03:17 +08:00
jingchuan
0b2bc3ce5a Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/jingchuan-sample-progress-main 2026-08-12 15:46:52 +08:00
jingchuan
73005fdd9b feat(sample-progress): import sampling data and completion time 2026-08-12 15:43:53 +08:00
jingchuan
c2e75dda3e fix(sample-progress): sort by OA arrival time 2026-08-12 14:54:15 +08:00
jingchuan
ac146f8879 Merge remote-tracking branch 'origin/main' into codex/jingchuan-sample-progress-main 2026-08-12 14:43:59 +08:00
jingchuan
4f1372668f fix(sample-progress): simplify summary and expand designer 2026-08-12 14:43:29 +08:00
WuYongJie
344e1b108a Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/xuxiake-installation-demo-integration-20260812 2026-08-12 14:25:56 +08:00
WuYongJie
a17844604c Merge commit '082d5cfc' into codex/xuxiake-installation-demo-integration-20260812 2026-08-12 14:24:23 +08:00
WuYongJie
082d5cfcee feat(installation-demo): complete sharing catalog and tool motion 2026-08-12 14:17:40 +08:00
WuYongJie
bdc8f393a8 fix(bom-costing): extend structure progress transaction 2026-08-12 14:16:31 +08:00
WuYongJie
76230f9f34 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/wuyongjie-bom-category-skills-v7 2026-08-12 13:09:36 +08:00
WuYongJie
17dd830976 fix(bom-costing): harden category skill costing closure 2026-08-12 13:09:26 +08:00
WuYongJie
70d0e4e5d9 fix(supply-chain): move price type to data group 2026-08-12 11:24:06 +08:00
jingchuan
432cd9fc4f feat(sample-progress): enrich OA tracking board 2026-08-12 11:07:49 +08:00
WuYongJie
944b5b0a58 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/wuyongjie-bom-category-skills-v7 2026-08-11 18:33:33 +08:00
WuYongJie
7040fd2d03 feat(bom-costing): add category skill engine v7 2026-08-11 18:33:04 +08:00
jingchuan
a040b015b5 fix(oa-board): align export default statuses 2026-08-11 18:08:32 +08:00
jingchuan
ad9afabc49 fix(sample-progress): exclude OA drafts from overdue metrics 2026-08-11 17:45:23 +08:00
jingchuan
2c201674a4 Merge remote-tracking branch 'origin/main' into codex/jingchuan-sample-progress-main 2026-08-11 17:36:57 +08:00
jingchuan
ba9adb0db4 fix(sample-progress): sync OA data and embed board tab 2026-08-11 17:36:57 +08:00
WuYongJie
7558939482 feat(supply-chain): sync supplier regions 2026-08-11 17:19:29 +08:00
WuYongJie
31ef235c80 fix(intake): keep opening name out of SKU specs 2026-08-11 17:02:31 +08:00
jingchuan
37851f0f04 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/jingchuan-sample-progress-main 2026-08-11 16:32:03 +08:00
jingchuan
20a450c4bd feat(intake): reorder OA tabs and add sample flow links 2026-08-11 16:30:00 +08:00
WuYongJie
0ece1c38dc fix(supply-chain): populate warehouse config and pin archive actions 2026-08-11 16:14:36 +08:00
WuYongJie
179040b1ab Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/xuxiake-package-set-count-fix-20260811-1548 2026-08-11 16:12:21 +08:00
WuYongJie
6388b8f37a fix(intake): keep package set counts consistent 2026-08-11 16:05:00 +08:00
jingchuan
ac9deefe85 merge: release sample progress board 2026-08-11 16:02:00 +08:00
jingchuan
1fa15cef79 merge: add sample progress board 2026-08-11 16:00:59 +08:00
jingchuan
23c20714dd feat(sample-progress): integrate board into OA workspace 2026-08-11 16:00:17 +08:00
jingchuan
c031c36f8f feat(sample-progress): add sampling progress board module 2026-08-11 15:49:58 +08:00
WuYongJie
aa646a795a fix(supply-chain): isolate product archive column settings 2026-08-11 14:59:06 +08:00
jingchuan
6a19e30527 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/jingchuan-brand-shipment-main-merge 2026-08-11 14:56:35 +08:00
jingchuan
43d8d43e16 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/jingchuan-brand-shipment-main-merge 2026-08-11 14:56:23 +08:00
jingchuan
b2fb4165b5 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/jingchuan-brand-shipment-todo 2026-08-11 14:54:22 +08:00
jingchuan
bdf20c2064 feat(oa-board): remind brand planning before shipment 2026-08-11 14:49:28 +08:00
WuYongJie
c86367c6b0 fix(intake): keep product type filters readable 2026-08-11 14:33:00 +08:00
jingchuan
4dcbed4c10 feat(oa-board): track unconfirmed completion followups 2026-08-11 13:46:32 +08:00
WuYongJie
199228241a fix(intake): save product tags and support all product types 2026-08-11 13:42:33 +08:00
WuYongJie
63ca46c030 fix(intake): save product tags and support all product types 2026-08-11 13:38:28 +08:00
WuYongJie
10ce1696dc fix(supply-chain): sync product development tags 2026-08-11 13:01:54 +08:00
WuYongJie
728495143e fix(supply-chain): sync product development tags 2026-08-11 12:52:30 +08:00
WuYongJie
20fee3b7ba merge: fix barcode certificate QR codes 2026-08-11 12:31:55 +08:00
WuYongJie
5c547dd25f fix(barcode-print): sync certificate QR codes 2026-08-11 12:31:52 +08:00
jingchuan
981df46e3f feat(oa-board): add monthly flow analysis 2026-08-11 12:06:51 +08:00
jingchuan
b24328f4f8 feat(oa-board): add daily stage report snapshots 2026-08-11 11:46:58 +08:00
WuYongJie
83a4d456b5 merge: release supply chain archive persistence 2026-08-11 10:46:55 +08:00
WuYongJie
be247f5a4b Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/tmp-supply-chain-mainline-20260811 2026-08-11 10:40:13 +08:00
WuYongJie
b47f745b83 feat(supply-chain): persist archive enrichment and image cache 2026-08-11 10:31:12 +08:00
jingchuan
35b9c5e080 feat(oa-board): read DingTalk source from JSReport replica 2026-08-11 10:17:18 +08:00
WuYongJie
759cba00d7 Merge remote-tracking branch 'origin/codex/wu-product-pricing-inventory-status' into codex/tmp-main-merge-product-pricing-20260811 2026-08-11 09:06:39 +08:00
WuYongJie
6858161f3f fix: show fixed virtual inventory task status 2026-08-11 08:58:37 +08:00
WuYongJie
7bfb69405d release: honor unitless internal dimensions 2026-08-11 05:59:32 +08:00
WuYongJie
814a7ed4be merge: honor unitless internal dimensions 2026-08-11 05:59:14 +08:00
WuYongJie
9383233130 fix(bom): honor unitless internal dimensions 2026-08-11 05:58:26 +08:00
WuYongJie
27ed15f55a release: isolate oversized board packing 2026-08-11 05:42:04 +08:00
WuYongJie
7b95e5af33 merge: isolate oversized board packing 2026-08-11 05:41:14 +08:00
WuYongJie
5bd554f762 fix(bom): isolate oversized board packing 2026-08-11 05:40:24 +08:00
WuYongJie
c1985a2396 release: area-scaled BOM fallback v6 2026-08-11 05:10:27 +08:00
WuYongJie
c538e175bc merge: area-scaled BOM fallback v6 2026-08-11 05:10:21 +08:00
WuYongJie
24a5043d15 fix(bom): scale fallback costs by board area 2026-08-11 05:10:02 +08:00
WuYongJie
0ba596a7c7 release: deterministic BOM blueprint v6 2026-08-11 04:39:10 +08:00
WuYongJie
bcf04b7438 merge: deterministic BOM blueprint v6 2026-08-11 04:38:52 +08:00
WuYongJie
d5e1f2af99 fix(bom): stabilize structure blueprint costing 2026-08-11 04:38:14 +08:00
WuYongJie
42095c6dab release: BOM tuple synthesis v6 2026-08-11 03:28:38 +08:00
WuYongJie
67ce313c9a merge: BOM tuple synthesis v6 2026-08-11 03:28:32 +08:00
WuYongJie
4f1571d508 fix(bom): compact sku synthesis into tuples 2026-08-11 03:27:15 +08:00
WuYongJie
871fd38bb5 release: BOM non-stream synthesis v6 2026-08-11 02:50:38 +08:00
WuYongJie
3c8d7f0801 merge: BOM non-stream synthesis v6 2026-08-11 02:50:17 +08:00
WuYongJie
7518041829 fix(bom-costing): avoid stalled synthesis streams 2026-08-11 02:49:47 +08:00
WuYongJie
164192bae7 release: BOM compact structure synthesis v6 2026-08-11 02:21:31 +08:00
WuYongJie
b9fd690e5d merge: BOM compact structure synthesis v6 2026-08-11 02:21:08 +08:00
WuYongJie
efbb08b7a5 fix(bom-costing): compact structure synthesis 2026-08-11 02:20:39 +08:00
WuYongJie
ebf0eca3b7 merge: publish complete BOM JSON stream handling 2026-08-11 01:25:16 +08:00
WuYongJie
5416bed96e merge: accept complete BOM JSON streams 2026-08-11 01:24:53 +08:00
WuYongJie
e945eff091 fix(bom-costing): accept completed json streams 2026-08-11 01:24:10 +08:00
WuYongJie
aefff98cad merge: publish BOM finish-reason stream fix 2026-08-11 00:38:32 +08:00
WuYongJie
be26f6d795 merge: finish completed BOM response streams 2026-08-11 00:38:25 +08:00
WuYongJie
f1a7b9c941 fix(bom-costing): finish completed response streams 2026-08-11 00:37:57 +08:00
WuYongJie
67a68067a0 merge: publish scoped BOM structure synthesis 2026-08-11 00:07:57 +08:00
WuYongJie
707feb213a merge: scope BOM structure synthesis requests 2026-08-11 00:06:57 +08:00
WuYongJie
2afdbb9ca7 fix(bom-costing): scope structure synthesis requests 2026-08-11 00:06:32 +08:00
WuYongJie
f2df3e53dc merge: publish BOM stream completion fix 2026-08-10 23:32:51 +08:00
WuYongJie
075fb38096 merge: fix completed BOM model streams 2026-08-10 23:32:14 +08:00
WuYongJie
dbf48330bd fix(bom-costing): stop completed model streams promptly 2026-08-10 23:27:39 +08:00
WuYongJie
7b220f824e merge: publish BOM structure blueprint v6 2026-08-10 22:16:31 +08:00
WuYongJie
e4554d86cf merge: BOM structure blueprint v6 2026-08-10 22:15:08 +08:00
WuYongJie
7a84b8fde0 feat(bom-costing): add v6 structure blueprint and batch cutting 2026-08-10 22:12:59 +08:00
jingchuan
fe48bbb181 feat(oa-board): add private daily report 2026-08-10 18:23:51 +08:00
WuYongJie
50317a3c0f merge: supply chain mainline into main 2026-08-10 17:28:10 +08:00
jingchuan
127730c5cf fix(oa-board): add manual termination overrides 2026-08-10 17:26:47 +08:00
WuYongJie
cbbf2fbb21 feat(supply-chain): map archive prices by barcode 2026-08-10 17:21:51 +08:00
WuYongJie
b9ec3511ac feat(supply-chain): add interactive archive dashboard 2026-08-10 16:25:16 +08:00
jingchuan
f55bddb017 fix(oa-board): honor manual termination overrides 2026-08-10 16:18:35 +08:00
jingchuan
9a1e588af3 fix(oa-board): terminate withdrawn XP2026070100000242 2026-08-10 16:17:11 +08:00
WuYongJie
c1ba901f7a feat(supply-chain): map warehouse attributes from JST 2026-08-10 16:05:13 +08:00
WuYongJie
cf74985e56 merge: publish BOM thickness evidence priority 2026-08-10 15:49:20 +08:00
WuYongJie
80c4dcc91b merge: release BOM thickness evidence priority 2026-08-10 15:48:48 +08:00
WuYongJie
c632402f2d Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/wuyongjie-bom-v5-runtime-fix 2026-08-10 15:44:46 +08:00
WuYongJie
2e3168bb99 fix(bom-costing): prefer product-wide explicit thickness facts 2026-08-10 15:42:16 +08:00
WuYongJie
d630a73433 fix(bom-costing): classify observed and estimated board thickness 2026-08-10 15:26:41 +08:00
WuYongJie
d90e6754b5 fix(bom-costing): bound history memory and price material substitutions 2026-08-10 14:54:09 +08:00
WuYongJie
cdf95640ae Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/wu-product-development-type-filter-main-release-20260810 2026-08-10 14:38:59 +08:00
WuYongJie
e7799331e0 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/wu-product-development-type-filter 2026-08-10 14:37:50 +08:00
WuYongJie
dab6002b5c feat(intake): add product type filter 2026-08-10 14:37:34 +08:00
WuYongJie
b3d947fc16 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/wuyongjie-release-main-bom-v5-20260810 2026-08-10 14:00:30 +08:00
WuYongJie
b0a9cd029f Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/wuyongjie-release-bom-v5-20260810 2026-08-10 13:57:52 +08:00
WuYongJie
a783e4c94b feat(supply-chain): map stock monitor daily sales 2026-08-10 13:55:58 +08:00
WuYongJie
2ca9d51339 Merge remote-tracking branch 'origin/codex/wuyongjie-bom-cost-v5-acceptance-fix' into codex/wuyongjie-release-bom-v5-20260810 2026-08-10 13:50:45 +08:00
WuYongJie
218941d97b fix(bom-costing): constrain history to product structure 2026-08-10 13:50:20 +08:00
WuYongJie
ff771b7bba feat(supply-chain): configure warehouse archive fields 2026-08-10 13:16:22 +08:00
WuYongJie
b010bd1355 merge: keep BOM estimates when synthesis is unavailable 2026-08-10 13:12:49 +08:00
WuYongJie
2dbe903c64 fix(bom-costing): price from saved facts on synthesis outage 2026-08-10 13:12:26 +08:00
WuYongJie
2f0c9a37e6 merge: improve BOM v5 production estimates 2026-08-10 12:59:54 +08:00
WuYongJie
22403f5a45 fix(bom-costing): select comparable whole BOM profiles 2026-08-10 12:59:27 +08:00
WuYongJie
d8a9be3d00 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/wuyongjie-release-main-bom-v5-20260810
# Conflicts:
#	furniture-3d-system/src/server/services/__tests__/oa-board-sync.service.test.ts
#	furniture-3d-system/src/server/services/oa-board-sync.service.ts
2026-08-10 12:24:37 +08:00
WuYongJie
80179df9fc Merge remote-tracking branch 'origin/codex/wuyongjie-bom-cost-dynamic-20260807' into codex/wuyongjie-release-bom-v5-20260810 2026-08-10 12:18:10 +08:00
WuYongJie
c353757d6b Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/wuyongjie-bom-cost-dynamic-20260807 2026-08-10 12:14:30 +08:00
WuYongJie
9f368104b5 fix(oa-board): pass pending pricing stage to metrics 2026-08-10 12:14:11 +08:00
WuYongJie
d0b9b22879 feat(jushuitan): add fixed virtual inventory queue 2026-08-10 12:08:51 +08:00
WuYongJie
81b1453db5 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/wuyongjie-bom-cost-dynamic-20260807 2026-08-10 12:08:06 +08:00
WuYongJie
d511fd9b9e feat(jushuitan): add fixed virtual inventory queue 2026-08-10 12:08:03 +08:00
WuYongJie
3ea61a2f07 feat(bom-costing): add layered v5 estimates 2026-08-10 12:08:01 +08:00
jingchuan
e869d32594 fix(oa-board): track pending pricing SLA 2026-08-10 11:45:10 +08:00
jingchuan
3c5c38e72b fix(oa-board): track pending pricing SLA 2026-08-10 11:34:35 +08:00
WuYongJie
8dda70ecdd Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/wuyongjie-bom-cost-dynamic-20260807 2026-08-10 11:04:17 +08:00
WuYongJie
b9a398830f perf(supply-chain): batch product archive image loading 2026-08-10 11:02:52 +08:00
WuYongJie
772c6813ed fix(bom-costing): restore detail slices and correct cost semantics 2026-08-10 10:43:00 +08:00
WuYongJie
ead86d523e feat(bom-costing): add auditable dynamic company cost engine 2026-08-09 14:23:45 +08:00
WuYongJie
a77c7a3296 merge: supply chain archive updates 2026-08-07 18:10:20 +08:00
WuYongJie
b87bb1ccb4 feat(supply-chain): add stock monitor fields 2026-08-07 18:09:56 +08:00
WuYongJie
c3f9ecbafd fix(supply-chain): backfill archive source images 2026-08-07 17:44:28 +08:00
WuYongJie
8b53afa468 fix(supply-chain): backfill archive source images 2026-08-07 17:43:34 +08:00
WuYongJie
28901d34b4 feat(supply-chain): enrich archive supplier profiles 2026-08-07 17:42:56 +08:00
WuYongJie
3c1983352a merge: release drawing and video archive media 2026-08-07 16:17:19 +08:00
WuYongJie
a69da95217 feat(supply-chain): import archive drawing and video media 2026-08-07 16:14:51 +08:00
WuYongJie
eaf7b9ecca feat(supply-chain): resolve archive images from material library 2026-08-07 15:56:36 +08:00
WuYongJie
e3047c8e6e feat(supply-chain): persist archive views and add multiselect filters 2026-08-07 14:38:18 +08:00
WuYongJie
e7f07a451c feat(supply-chain): add full JST archive sync 2026-08-07 13:02:22 +08:00
WuYongJie
b1566874e1 feat(supply-chain): add full JST archive sync 2026-08-07 13:01:47 +08:00
WuYongJie
2e87027672 fix(db): make JST archive source migration idempotent 2026-08-07 12:38:21 +08:00
WuYongJie
2a483ea415 fix(db): make JST archive source migration idempotent 2026-08-07 12:38:02 +08:00
WuYongJie
a1972a0103 merge: release supply chain product archive
# Conflicts:
#	furniture-3d-system/src/app/intake/oa-board/OaBoardClient.tsx
#	furniture-3d-system/src/server/services/__tests__/oa-board.service.test.ts
#	furniture-3d-system/src/server/services/oa-board.service.ts
2026-08-07 12:22:11 +08:00
WuYongJie
4b5affacd0 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/tmp-supply-chain-archive-snapshot-20260804 2026-08-07 12:18:20 +08:00
WuYongJie
2bd31cc06b feat(supply-chain): complete product archive data pipeline 2026-08-07 12:17:47 +08:00
WuYongJie
1910c2581e fix(intake): expose CJ0267 installation demo 2026-08-07 11:55:13 +08:00
WuYongJie
501f561eae fix(intake): expose CJ0267 installation demo 2026-08-07 11:53:32 +08:00
jingchuan
16a70d2920 feat(oa-board): track production stage overtime 2026-08-06 18:44:01 +08:00
jingchuan
ddb153f0d7 fix(oa-board): track pending first-order SLA 2026-08-06 17:39:54 +08:00
jingchuan
41251e2223 fix(oa-board): separate overall and stage overtime 2026-08-06 17:02:04 +08:00
WuYongJie
f7885fa6ec fix(work-record): prepend newly added records
(cherry picked from commit 8a999c29dcc9d07202c6b685f58c8fb386ed04a7)
2026-08-06 16:31:18 +08:00
WuYongJie
8a999c29dc fix(work-record): prepend newly added records 2026-08-06 16:29:28 +08:00
jingchuan
f047d6b418 fix(oa-board): allow partial timing metrics 2026-08-06 15:55:04 +08:00
jingchuan
7914b07996 fix(oa-board): unify stage overtime followups 2026-08-06 15:45:23 +08:00
WuYongJie
5b0f98264c fix(deploy): align intake sku schema before release 2026-08-06 15:17:20 +08:00
WuYongJie
929b0eacd3 merge: 索菲亚合格证/箱贴模板修复 2026-08-06 14:33:43 +08:00
WuYongJie
4d24976ab9 fix(barcode-print): 索菲亚合格证/箱贴模板修复 + 顾家布局微调
索菲亚相关:
- barcodePrintSofiaCartonLayout 新增索菲亚箱贴布局
- barcodePrintCertificate 证书渲染逻辑调整
- BarcodePrintCertificateEditDialog 编辑弹窗重构

顾家相关:
- barcodePrintGujiaCertificateLayout 布局微调

纯前端/打印逻辑,不涉及数据库结构,可安全部署。
2026-08-06 14:33:24 +08:00
WuYongJie
a62ed2b6b7 merge: sync latest xuxiake mainline 2026-08-06 14:16:52 +08:00
WuYongJie
2ccb52e75b fix(intake): restore structured sku sales status normalization 2026-08-06 13:54:37 +08:00
WuYongJie
dc236236be docs: document product archive wide view contract 2026-08-06 13:21:41 +08:00
WuYongJie
3ba508e8bb docs: document product archive wide view contract 2026-08-06 13:20:47 +08:00
jingchuan
100d2d05fa fix(oa-board): keep total overtime separate from stage sla 2026-08-06 13:06:09 +08:00
WuYongJie
21572d3377 fix: calibrate Sofia carton certificate print layout 2026-08-06 12:58:37 +08:00
WuYongJie
09d0e169bc feat(supply-chain): unify archive source with product catalog wide table 2026-08-06 12:40:00 +08:00
WuYongJie
373aa0a753 feat(supply-chain): unify archive source with product catalog wide table 2026-08-06 12:29:36 +08:00
WuYongJie
ef1ad7999c feat(supply-chain): update product archive column headers 2026-08-06 12:11:17 +08:00
jingchuan
f60dbfa159 fix(oa-board): correct duration and sku flow matching 2026-08-06 10:53:56 +08:00
jingchuan
4efb7f4083 fix(oa-board): prefer active reassigned tasks 2026-08-06 09:59:50 +08:00
jingchuan
d3280f8fc5 fix(oa-board): refresh brand planning snapshot with timer 2026-08-06 09:39:36 +08:00
WuYongJie
c8b8fccc5b Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/release-bom-mincost-main-20260805 2026-08-05 21:07:34 +08:00
WuYongJie
1f001701a6 Merge branch 'codex/wuyongjie-bom-min-cost-20260805' into codex/release-bom-mincost-xuxiake-20260805 2026-08-05 21:06:58 +08:00
WuYongJie
db262e18db feat(bom): cross-check sibling sku facts 2026-08-05 21:04:13 +08:00
WuYongJie
2239d35564 fix(bom): estimate costs from saved sku facts 2026-08-05 20:56:48 +08:00
WuYongJie
5ea48578ec Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/wuyongjie-bom-main-release-20260805 2026-08-05 20:05:50 +08:00
WuYongJie
5a2438595e Merge branch 'codex/wuyongjie-bom-recalc-rootfix-20260805' into codex/xuxiake-mainline 2026-08-05 20:04:55 +08:00
WuYongJie
87a7e75d21 fix(bom): assemble exact sku structures from image facts 2026-08-05 19:56:34 +08:00
WuYongJie
d41ee6a61a fix(bom): bound gpt synthesis by real sku 2026-08-05 19:26:10 +08:00
jingchuan
25f4354823 fix(oa-board): use stage SLA for overtime 2026-08-05 17:53:15 +08:00
jingchuan
317eaa8655 fix(oa-board): allow historical overtime followup editing 2026-08-05 17:53:15 +08:00
jingchuan
d531a62361 fix(oa-board): retain historical overtime followups 2026-08-05 17:53:15 +08:00
WuYongJie
2a01b4929b Merge remote-tracking branch 'origin/main' into codex/wuyongjie-bom-recalc-rootfix-20260805 2026-08-05 16:31:02 +08:00
WuYongJie
cc01261d96 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/wuyongjie-bom-recalc-rootfix-20260805 2026-08-05 16:28:53 +08:00
WuYongJie
6fbc44f0d1 fix(bom): tolerate partial image analysis failures 2026-08-05 16:27:07 +08:00
jingchuan
495a639c8d fix(oa-board): expose historical overtime followups 2026-08-05 16:23:44 +08:00
jingchuan
8e5c6f91ba fix(oa-board): expose historical overtime followups 2026-08-05 16:22:58 +08:00
WuYongJie
c08f5661b4 merge: sync management workspace access 2026-08-05 16:19:49 +08:00
WuYongJie
656a1d1d9e merge: add management workspace access 2026-08-05 16:19:01 +08:00
WuYongJie
8f14eebe15 feat: add management workspace access 2026-08-05 16:16:33 +08:00
WuYongJie
82b478a1fe fix(bom): clarify actual sku recalculation scope 2026-08-05 15:42:13 +08:00
WuYongJie
d6214a2c40 fix(bom): recover malformed image facts and clarify recalc 2026-08-05 15:39:12 +08:00
WuYongJie
2c13dd0312 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/release-bom-live-stream-main-20260805 2026-08-05 14:25:35 +08:00
WuYongJie
06665326b2 Merge branch 'codex/wuyongjie-bom-live-stream-workbench-clean-20260805' into codex/release-bom-live-stream-xuxiake-20260805 2026-08-05 14:23:59 +08:00
WuYongJie
bc7be2e2ad feat(bom): surface live image analysis results 2026-08-05 14:19:38 +08:00
WuYongJie
52e8d8baef merge: release OpenSSH deploy key support to production main 2026-08-05 13:31:36 +08:00
WuYongJie
d12ecc74f2 merge: bound identity-key deployment connections 2026-08-05 13:31:14 +08:00
WuYongJie
5e0f34ecb7 fix(deploy): bound OpenSSH identity connections 2026-08-05 13:31:13 +08:00
WuYongJie
e2c22b260f merge: promote OpenSSH deploy key support to shared mainline 2026-08-05 13:27:13 +08:00
WuYongJie
fc74d265cd fix(deploy): support OpenSSH identity files 2026-08-05 13:26:49 +08:00
WuYongJie
8350e9f5fc merge: release product progress completion fix 2026-08-05 12:53:51 +08:00
WuYongJie
024be4307a merge: complete product progress after SKU entry 2026-08-05 12:52:55 +08:00
WuYongJie
a863754ae6 fix(product-progress): complete historical entered SPUs 2026-08-05 12:51:57 +08:00
WuYongJie
cd4ec9a23a feat(supply-chain): add product archive dashboard 2026-08-05 12:45:28 +08:00
WuYongJie
e5b97d7750 feat(supply-chain): add product archive dashboard 2026-08-05 12:43:51 +08:00
WuYongJie
f6460b1eda feat(supply-chain): add product archive dashboard 2026-08-05 12:43:13 +08:00
WuYongJie
c5ddcb428c merge: release BOM quality safeguards to production main 2026-08-05 11:45:39 +08:00
WuYongJie
68914fceec merge: promote BOM quality safeguards to shared mainline 2026-08-05 11:45:11 +08:00
WuYongJie
3d18a89e55 fix(bom): guard historical and invalid costing results 2026-08-05 11:42:28 +08:00
WuYongJie
f1dc44376a merge: retain current production BOM safeguards 2026-08-05 11:19:42 +08:00
WuYongJie
02c869cf70 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/wu-product-development-main-merge-20260805 2026-08-05 11:04:43 +08:00
WuYongJie
8b9474262c Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/wu-product-development-release-20260805
# Conflicts:
#	furniture-3d-system/src/app/operation-logs/OperationLogClient.tsx
2026-08-05 11:02:16 +08:00
WuYongJie
f456c56d57 feat(intake): consolidate product development progress 2026-08-05 11:00:42 +08:00
WuYongJie
9a713e9a98 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/xuxiake-supply-chain-archive-release-20260804 2026-08-05 10:50:57 +08:00
WuYongJie
1a90b2e7b3 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/xuxiake-supply-chain-archive-release-20260804 2026-08-05 10:50:29 +08:00
WuYongJie
bc573566eb feat(operation-logs): separate workspace administrator views 2026-08-05 10:50:09 +08:00
WuYongJie
3cbbe8eb3d merge: release bounded BOM worker execution 2026-08-05 10:49:46 +08:00
WuYongJie
3136604a53 merge: bound BOM worker execution time 2026-08-05 10:49:17 +08:00
WuYongJie
d17d308be1 merge: sync shared mainline before BOM timeout fix 2026-08-05 10:47:55 +08:00
WuYongJie
115a8b8042 fix(bom): bound worker and model execution time 2026-08-05 10:47:49 +08:00
jingchuan
8cd5764428 fix(oa-board): allow historical overtime followup editing 2026-08-05 10:45:36 +08:00
WuYongJie
5b537b8f9c feat(intake): consolidate product development progress 2026-08-05 10:42:54 +08:00
WuYongJie
af596560b6 merge: skip unused onnx cuda runtime 2026-08-05 09:59:18 +08:00
WuYongJie
adaa1ed8ac fix(deploy): skip unused onnx cuda runtime 2026-08-05 09:58:43 +08:00
WuYongJie
9636cc9733 merge: release real BOM SKU verification 2026-08-05 09:51:45 +08:00
WuYongJie
86290edf6a merge: preserve real BOM SKU rows 2026-08-05 09:51:20 +08:00
WuYongJie
26063e1d16 fix(bom): verify real sku rows before costing 2026-08-05 09:50:42 +08:00
WuYongJie
461e10a3ab merge: release supply chain product archive 2026-08-05 09:06:03 +08:00
WuYongJie
2cb7a35c26 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/xuxiake-supply-chain-archive-release-20260804
# Conflicts:
#	scripts/deploy-yydd-prod-from-git.ps1
2026-08-05 09:02:28 +08:00
WuYongJie
368fc1953a feat(supply-chain): integrate product archive pipeline 2026-08-05 09:00:49 +08:00
WuYongJie
3d382146f4 merge: release batched BOM result persistence 2026-08-05 03:07:44 +08:00
WuYongJie
03cc085514 merge: batch BOM result persistence 2026-08-05 03:07:33 +08:00
WuYongJie
1e41401ec3 fix(bom): batch large costing result persistence 2026-08-05 03:07:18 +08:00
WuYongJie
78fe9d6ded merge: release BOM tabletop area costing 2026-08-05 02:57:04 +08:00
WuYongJie
0d82963ffa merge: fix BOM tabletop area costing 2026-08-05 02:56:50 +08:00
WuYongJie
8c56a3a164 fix(bom): use sku dimensions for tabletop area costing 2026-08-05 02:56:32 +08:00
WuYongJie
5972bf4db4 merge: recover transient BOM upstream bad requests 2026-08-05 02:13:42 +08:00
WuYongJie
eaef521816 merge: recover transient BOM upstream bad requests 2026-08-05 02:13:31 +08:00
WuYongJie
faf313b940 fix(bom-costing): recover transient upstream bad requests 2026-08-05 02:13:18 +08:00
WuYongJie
dccc745d51 merge: auto-recover empty BOM model responses 2026-08-05 01:50:32 +08:00
WuYongJie
97b9359235 merge: auto-recover empty BOM model responses 2026-08-05 01:50:21 +08:00
WuYongJie
00b8070699 fix(bom-costing): auto-recover empty model responses 2026-08-05 01:49:55 +08:00
WuYongJie
76e60f2465 merge: reset BOM recovery budget after progress 2026-08-05 01:01:41 +08:00
WuYongJie
d5da0a0390 merge: reset BOM recovery budget after progress 2026-08-05 01:01:20 +08:00
WuYongJie
131e83ce77 fix(bom-costing): reset recovery budget after progress 2026-08-05 01:00:07 +08:00
WuYongJie
71a8d06c97 merge: default omitted BOM model confidence 2026-08-05 00:28:47 +08:00
WuYongJie
c6feb67947 merge: default omitted BOM model confidence 2026-08-05 00:28:41 +08:00
WuYongJie
96a3abda1d fix(bom-costing): default omitted model confidence conservatively 2026-08-05 00:28:24 +08:00
WuYongJie
300753f56c merge: auto-resume malformed BOM model responses 2026-08-05 00:21:51 +08:00
WuYongJie
09743ffc3f merge: auto-resume malformed BOM model responses 2026-08-05 00:21:46 +08:00
WuYongJie
0e20ab41c5 fix(bom-costing): auto-resume malformed model responses 2026-08-05 00:21:26 +08:00
WuYongJie
4ea787faf1 merge: auto-resume transient BOM model failures 2026-08-05 00:07:44 +08:00
WuYongJie
74ec257d96 merge: auto-resume transient BOM model failures 2026-08-05 00:07:31 +08:00
WuYongJie
e5e5f62504 fix(bom-costing): auto-resume transient model failures 2026-08-05 00:05:35 +08:00
WuYongJie
29b6992314 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/release-bom-rearchive-main-20260804 2026-08-04 23:45:44 +08:00
WuYongJie
0a3bd1969c Merge branch 'codex/wuyongjie-bom-rearchive-batch-20260804' into codex/release-bom-rearchive-xuxiake-20260804 2026-08-04 23:45:26 +08:00
WuYongJie
ad43342687 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/wuyongjie-bom-rearchive-batch-20260804 2026-08-04 23:45:12 +08:00
WuYongJie
22b02adda9 fix(bom-costing): split network timeouts immediately 2026-08-04 23:44:58 +08:00
WuYongJie
68d59842c5 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/release-bom-rearchive-main-20260804 2026-08-04 22:47:35 +08:00
WuYongJie
c1e14b23a8 Merge branch 'codex/wuyongjie-bom-rearchive-batch-20260804' into codex/release-bom-rearchive-xuxiake-20260804 2026-08-04 22:47:22 +08:00
WuYongJie
86f0e56739 fix(bom-costing): checkpoint completed synthesis batches 2026-08-04 22:46:49 +08:00
WuYongJie
4dae247b96 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/release-bom-rearchive-main-20260804 2026-08-04 22:04:25 +08:00
WuYongJie
f881fdda30 Merge branch 'codex/wuyongjie-bom-rearchive-batch-20260804' into codex/release-bom-rearchive-xuxiake-20260804 2026-08-04 22:04:07 +08:00
WuYongJie
86702e95ff Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/wuyongjie-bom-rearchive-batch-20260804 2026-08-04 22:03:54 +08:00
WuYongJie
6e296c6c61 fix(bom-costing): time out stalled response streams 2026-08-04 22:03:28 +08:00
WuYongJie
9c9c57ba5c merge: release immediate BOM timeout splitting 2026-08-04 21:37:52 +08:00
WuYongJie
2420cec963 merge: split timed out BOM synthesis immediately 2026-08-04 21:37:34 +08:00
WuYongJie
0f9caa09ca merge: synchronize compact BOM synthesis release 2026-08-04 21:37:13 +08:00
WuYongJie
56988d753d fix(bom-costing): split timed out synthesis immediately 2026-08-04 21:36:55 +08:00
WuYongJie
146b3992ab merge: release compact BOM synthesis facts 2026-08-04 21:23:12 +08:00
WuYongJie
6ac92f6274 merge: compact BOM synthesis facts 2026-08-04 21:22:55 +08:00
WuYongJie
e0ca7775a4 merge: synchronize stalled BOM recovery release 2026-08-04 21:22:39 +08:00
WuYongJie
634a2dad9d perf(bom-costing): compact product synthesis facts 2026-08-04 21:22:19 +08:00
WuYongJie
3b16f69efe merge: release stalled BOM synthesis batch recovery 2026-08-04 21:00:07 +08:00
WuYongJie
a61a10ffb9 merge: split stalled BOM synthesis batches 2026-08-04 20:59:49 +08:00
WuYongJie
b32fc52427 merge: synchronize BOM retry safeguards 2026-08-04 20:59:31 +08:00
WuYongJie
acf3dc8fc2 fix(bom-costing): split stalled synthesis batches 2026-08-04 20:59:00 +08:00
WuYongJie
89db71a377 merge: release BOM synthesis retry safeguards 2026-08-04 20:30:56 +08:00
WuYongJie
71558003a7 merge: retry incomplete BOM synthesis batches 2026-08-04 20:30:35 +08:00
WuYongJie
7211a2fc78 fix(bom-costing): retry incomplete synthesis batches 2026-08-04 20:30:07 +08:00
WuYongJie
eccbc1bc68 merge: release scoped BOM synthesis facts 2026-08-04 20:14:34 +08:00
WuYongJie
f6a54980df merge: scope BOM synthesis facts by SKU batch 2026-08-04 20:14:17 +08:00
WuYongJie
b23d0b44f6 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/wuyongjie-bom-rearchive-batch-20260804 2026-08-04 20:14:02 +08:00
WuYongJie
99c6833b0c fix(bom-costing): scope synthesis facts to SKU batch 2026-08-04 20:13:48 +08:00
WuYongJie
c12194f333 merge: release bounded BOM synthesis reasoning 2026-08-04 20:05:02 +08:00
WuYongJie
179ec64a8c merge: bound BOM synthesis reasoning 2026-08-04 20:04:46 +08:00
WuYongJie
07cdfbb20c Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/wuyongjie-bom-rearchive-batch-20260804 2026-08-04 20:04:25 +08:00
WuYongJie
b6b4edeaf5 fix(bom-costing): bound GPT synthesis reasoning 2026-08-04 20:04:04 +08:00
WuYongJie
0b0e014d5e merge: release hardened BOM SKU batch processing 2026-08-04 19:49:29 +08:00
WuYongJie
10a23cb5b8 merge: harden BOM SKU batch processing 2026-08-04 19:49:12 +08:00
WuYongJie
d5b73444e5 fix(bom-costing): tolerate unknown measures in sku batches 2026-08-04 19:48:22 +08:00
WuYongJie
2e51bad245 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/release-bom-rearchive-main-20260804 2026-08-04 19:16:17 +08:00
WuYongJie
041b60a563 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/wuyongjie-bom-rearchive-batch-20260804 2026-08-04 19:15:15 +08:00
WuYongJie
143aa7fa3f fix(bom-costing): bound concurrent sku synthesis 2026-08-04 19:14:41 +08:00
WuYongJie
1b6e743dd0 merge: release 600 SKU BOM catalog support 2026-08-04 18:44:25 +08:00
WuYongJie
4841ca549b merge: support complete 600 SKU BOM catalogs 2026-08-04 18:43:59 +08:00
WuYongJie
f0687f2d5d fix(bom-costing): support complete 600 sku catalogs 2026-08-04 18:43:33 +08:00
WuYongJie
6ba383076a merge: release BOM synthesis progress serialization 2026-08-04 18:34:01 +08:00
WuYongJie
d2b123066b merge: serialize BOM synthesis progress events 2026-08-04 18:33:35 +08:00
WuYongJie
47f19da2e2 fix(bom-costing): serialize synthesis progress events 2026-08-04 18:32:48 +08:00
WuYongJie
b192e0359a merge: release BOM source recovery and batch synthesis 2026-08-04 18:23:45 +08:00
WuYongJie
a11aa15017 merge: recover BOM changed sources and batch synthesis 2026-08-04 18:22:35 +08:00
WuYongJie
45a501406b fix(bom-costing): recover changed sources and batch sku synthesis 2026-08-04 18:21:44 +08:00
WuYongJie
26906c0585 feat(supply-chain): snapshot product archive workspace 2026-08-04 18:20:12 +08:00
WuYongJie
899ec8b9f4 feat(supply-chain): snapshot product archive workspace 2026-08-04 18:19:44 +08:00
WuYongJie
ab2b64c0d4 merge: release BOM SKU intake repair 2026-08-04 17:49:56 +08:00
WuYongJie
6371d9f248 merge: harden BOM SKU intake and hints 2026-08-04 17:49:20 +08:00
WuYongJie
a78900ce64 fix(bom-costing): harden SKU intake and simplify hints 2026-08-04 17:48:48 +08:00
WuYongJie
71cd22a12a Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/release-bom-costing-promote-main-20260804 2026-08-04 17:14:40 +08:00
WuYongJie
c4628fb8c4 Merge remote-tracking branch 'origin/codex/release-bom-costing-main-20260804' into codex/release-bom-costing-xuxiake-20260804 2026-08-04 17:13:45 +08:00
WuYongJie
a7c371073b Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/release-bom-costing-xuxiake-20260804 2026-08-04 17:13:44 +08:00
WuYongJie
2899a1bcd4 fix(bom-costing): bound synthesis workload 2026-08-04 17:13:03 +08:00
WuYongJie
37cb0fd876 Merge remote-tracking branch 'origin/main' into codex/release-bom-costing-main-20260804 2026-08-04 16:53:10 +08:00
WuYongJie
a115a4a73c fix(bom-costing): retry transient synthesis failures 2026-08-04 16:52:40 +08:00
WuYongJie
8f8e03734c merge: guard intake basic info before factory confirmation 2026-08-04 16:45:07 +08:00
WuYongJie
747a201196 fix(intake): guard basic info confirmation before factory 2026-08-04 16:44:30 +08:00
WuYongJie
b3fd61dadb fix(bom-costing): bound GPT-5 reasoning time 2026-08-04 16:43:59 +08:00
WuYongJie
608da97538 Merge remote-tracking branch 'origin/main' into codex/release-bom-costing-main-20260804 2026-08-04 16:24:36 +08:00
WuYongJie
a36d7ab1a8 fix(bom-costing): recover interrupted worker jobs 2026-08-04 16:24:31 +08:00
jingchuan
6187aecab2 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/main-oa-history-followup-release 2026-08-04 15:40:51 +08:00
jingchuan
02d3345763 fix(oa-board): retain historical overtime followups 2026-08-04 15:40:12 +08:00
WuYongJie
532e4724da merge: synchronize BOM synthesis resilience 2026-08-04 15:35:15 +08:00
WuYongJie
81f3c10ca3 merge: extend BOM synthesis resilience 2026-08-04 15:34:54 +08:00
WuYongJie
e5a5662303 fix(bom-costing): extend synthesis resilience 2026-08-04 15:34:30 +08:00
WuYongJie
16b22dcd40 merge: release BOM costing recovery 2026-08-04 15:13:48 +08:00
WuYongJie
e6580c9b26 merge: release BOM costing recovery 2026-08-04 15:13:08 +08:00
WuYongJie
425e5e444d fix(bom-costing): preserve viable cost estimates 2026-08-04 14:43:29 +08:00
jingchuan
3553211fc5 merge: block duplicate todo recovery 2026-08-03 17:52:08 +08:00
jingchuan
5848dcd71f merge: block duplicate todo recovery 2026-08-03 17:51:29 +08:00
jingchuan
5c370b3f57 fix(oa-board): block duplicate todo recovery 2026-08-03 17:51:05 +08:00
jingchuan
699fb65e10 merge: retain DingTalk todo ID on update 2026-08-03 17:40:48 +08:00
jingchuan
b80792d753 merge: retain DingTalk todo ID on update 2026-08-03 17:40:34 +08:00
jingchuan
6d92aa52ae fix(oa-board): retain todo id after dingtalk update 2026-08-03 17:40:17 +08:00
jingchuan
59e44086b1 merge: schedule OA overtime todo dispatch 2026-08-03 17:29:35 +08:00
jingchuan
a2040410e8 merge: enable scheduled OA overtime todo dispatch 2026-08-03 17:28:45 +08:00
jingchuan
5d01a3b2fd fix(oa-board): run overdue todo scan after snapshot sync 2026-08-03 17:26:56 +08:00
WuYongJie
9882dede2c merge: keep one intake workspace tab per page 2026-08-03 17:03:09 +08:00
WuYongJie
59dfb2a1b1 fix: keep one tab per intake workspace page 2026-08-03 17:01:47 +08:00
WuYongJie
e5f603ca8e merge: portal permissions and external barcode scope 2026-08-03 16:35:54 +08:00
WuYongJie
29c70537fb Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/xuxiake-supply-chain-permissions-20260803 2026-08-03 16:30:19 +08:00
WuYongJie
c58f642574 fix: scope external barcode print records 2026-08-03 16:28:40 +08:00
WuYongJie
076075a3a8 fix: stabilize intake and supply-chain tab navigation 2026-08-03 16:28:39 +08:00
WuYongJie
7acd668918 feat: move product permission controls to user management 2026-08-03 16:28:26 +08:00
WuYongJie
a50f81eaed feat: add portal and workspace access guards 2026-08-03 16:28:16 +08:00
WuYongJie
19c3409b09 Merge remote-tracking branch 'origin/main' into codex/wuyongjie-bom-unified-progress-20260803 2026-08-03 16:21:56 +08:00
WuYongJie
5a40b422f9 fix(bom-costing): 自动形成预估成本并精简工作台 2026-08-03 16:21:14 +08:00
WuYongJie
546cea38d9 fix: 对齐顾家合格证2026模板 2026-08-03 13:53:37 +08:00
WuYongJie
e3da1628ce fix: 删除首页门户return后的死代码(UTF8安全), 修复TS构建错误 2026-08-03 13:06:56 +08:00
WuYongJie
fee09e5116 fix: 删除首页门户 return 后的死代码,修复 TS 构建错误 2026-08-03 12:59:08 +08:00
WuYongJie
0bf9003485 fix: HomeClient editingProduct 可能为 null 的 TS 构建错误 2026-08-03 12:50:52 +08:00
WuYongJie
97c73a4e0c merge: 首页门户化 + 供应链中心框架 2026-08-03 12:43:57 +08:00
WuYongJie
51e44d1eaf feat: 首页门户化 + 供应链中心框架
首页改门户选择页:
- HomeClient.workspace 加门户短路,渲染 HomePortal(两个工作台入口)
- HomePortal:产品开发(→/intake) + 供应链中心(→/supply-chain) 两大入口卡
- 顶部导航:首页时只显示「首页」,进入产品开发后恢复全部功能导航
- 入口图标:产品开发用 Package,供应链用 Truck
- 时间问候语(早午晚好+用户名)

供应链中心(src/app/supply-chain/):
- 独立布局:窄边栏(76px) + hover二级菜单浮层 + 多标签页 + 顶栏搜索
- 复用主项目顶栏(保留首页导航),供应链路由时品牌切换为「由壹点「供应链中心」」
- 全局菜单搜索:模糊匹配 + 拼音全拼/首字母 + 键盘导航(↑↓Enter Esc)
- 4个页面:工作台(问候语)、产品全量档案、日常事项(空壳)、产品变价(空壳)
- 产品全量档案:多级表头(5分组81字段) + 列设置抽屉(勾选显隐+拖拽排序+重置) + localStorage持久化 + 浮动分页

视觉:白曜石规范(浅色精密、克制通透、石墨灰强调色)
基于 origin/main,不含其他线程改动
2026-08-03 12:39:02 +08:00
WuYongJie
5904e96494 merge: 发布 BOM 并发分析与进度可视化修复 2026-08-03 12:15:40 +08:00
WuYongJie
62d9578e1b merge: 合入 BOM 并发分析与进度可视化修复 2026-08-03 12:13:07 +08:00
WuYongJie
4f7acbdafa fix(bom-costing): 修复多模态结果解析并展示并发进度 2026-08-03 12:11:43 +08:00
WuYongJie
668fa3c219 merge: 发布 BOM 多模态事实传输契约修复 2026-08-03 09:25:04 +08:00
WuYongJie
a0f701f24d merge: 合入 BOM 多模态事实传输契约修复 2026-08-03 09:22:34 +08:00
WuYongJie
ecb6549341 fix(bom-costing): 拆分多模态事实传输契约 2026-08-02 01:03:10 +08:00
WuYongJie
dc46e09888 merge: 发布 BOM 多模态事实类型契约修复 2026-08-02 00:17:46 +08:00
WuYongJie
2261b3f663 merge: 合入 BOM 多模态事实类型契约修复 2026-08-02 00:16:55 +08:00
WuYongJie
45b5cb05ba fix(bom-costing): 统一多模态事实类型契约 2026-08-02 00:15:27 +08:00
WuYongJie
229a65b8aa merge: 发布 BOM 多模态输出契约根因修复 2026-08-01 23:24:34 +08:00
WuYongJie
9faa24fe9c merge: 合入 BOM 多模态输出契约根因修复 2026-08-01 23:23:38 +08:00
WuYongJie
62c89a81c8 fix(bom-costing): 重构多模态输出契约边界 2026-08-01 23:11:14 +08:00
WuYongJie
2e891c9a95 feat(bom-costing): 使用 GSAP 重构核算动效 2026-08-01 21:57:03 +08:00
WuYongJie
70a2d8eb55 fix(bom-costing): 修正多模态事实结果契约 2026-08-01 19:59:57 +08:00
WuYongJie
d9ebf7d9cb Merge remote-tracking branch 'origin/main' into codex/wuyongjie-bom-failure-root-20260801 2026-08-01 18:38:11 +08:00
WuYongJie
665151aa22 fix(bom-costing): 修复多模态核算失败链路 2026-08-01 18:32:49 +08:00
jingchuan
3289809a95 feat(oa-board): split current and historical timeout analysis 2026-08-01 09:22:22 +08:00
jingchuan
d9672a9231 Merge branch 'codex/xuxiake-mainline' of http://git.1080p.hk/WuYongJie/furniture-3d-system-Wu into codex/xuxiake-mainline-todo-unionid-20260729 2026-07-31 18:08:29 +08:00
jingchuan
c88e63978c fix(oa-board): retain historical timeout followups 2026-07-31 18:07:35 +08:00
WuYongJie
939810a702 fix(barcode-print): restore Gujia certificate field alignment 2026-07-31 17:36:18 +08:00
WuYongJie
d9052de583 fix(barcode-print): restore Gujia certificate field alignment 2026-07-31 17:34:57 +08:00
jingchuan
19ce18fa0b fix(oa-board): align stage overtime followups 2026-07-31 15:44:02 +08:00
jingchuan
adc97204ff fix(oa-board): fall back to current stage SLA alerts 2026-07-31 13:11:08 +08:00
WuYongJie
d3915c4cd3 merge: 同步徐霞客主线最新 OA 修复 2026-07-31 12:04:31 +08:00
jingchuan
781d92ea71 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/xuxiake-mainline-todo-unionid-20260729 2026-07-31 12:00:13 +08:00
jingchuan
f4150e8e2c fix(oa-board): disable unconfirmed sample courier SLA 2026-07-31 11:59:47 +08:00
WuYongJie
9233a9013d merge: 同步最新生产主线后发布 BOM 改动 2026-07-31 11:40:21 +08:00
WuYongJie
4cc6a63267 merge: barcode print database pagination 2026-07-31 11:37:25 +08:00
WuYongJie
c598da5ef8 fix(barcode-print): page records at database 2026-07-31 11:36:37 +08:00
WuYongJie
e7de41ce8d merge: 同步最新徐霞客主线 2026-07-31 11:34:28 +08:00
WuYongJie
2d3d5f2ef0 feat(bom-costing): 按业务类型开放并留档人工核算 2026-07-31 11:33:31 +08:00
jingchuan
46a7f25619 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/xuxiake-mainline-todo-unionid-20260729 2026-07-31 11:24:49 +08:00
jingchuan
64738ea4d6 fix(oa-board): unify current-node overtime alerts 2026-07-31 11:23:15 +08:00
WuYongJie
1d4f176337 merge: align Gujia certificate fields 2026-07-31 10:32:37 +08:00
WuYongJie
8d04698637 fix(intake): align Gujia certificate fields 2026-07-31 10:29:10 +08:00
WuYongJie
59b960d5ce merge: release barcode pagination and supplier brand SKU visibility 2026-07-30 23:37:06 +08:00
WuYongJie
783e7038b0 fix(barcode-print): page imports and expose supplier brand SKUs 2026-07-30 23:36:14 +08:00
WuYongJie
0264b4c63c merge: 发布 BOM 全量图片事实分析 2026-07-30 19:08:20 +08:00
WuYongJie
d9a7ac208a merge: BOM 全量图片事实分析 2026-07-30 19:05:35 +08:00
WuYongJie
ed424431a7 feat(bom-costing): 持久化全量图片事实分析 2026-07-30 19:01:56 +08:00
WuYongJie
e0cad57074 merge: barcode print append import and supplier scope 2026-07-30 17:28:09 +08:00
WuYongJie
d68f49620d fix(barcode-print): append imports and scope suppliers by name 2026-07-30 17:14:49 +08:00
WuYongJie
6af723ac40 feat(barcode-print): 条码打印后端真分页 + 供应商隐藏空字段
后端分页:
- BarcodePrintService 新增 listRowsPaged,take/skip 只查当前页 + count 取总数
- 筛选条件下沉到后端 where(货号/供应商查独立列,条码/型号等查 updates JSONB)
- GET /api/intake/barcode-print 接收 page/pageSize/筛选参数

前端真分页:
- 从全量拉取+内存切片 改为 带参数请求后端+只存当前页
- 翻页/搜索/重置/导入/删除 均触发后端重新请求
- 本地实测:打开 18.5s -> 0.4s

供应商隐藏空字段:
- tableConfig 新增供应商可见列集合 + getVisibleBarcodePrintColumns
- BarcodePrintTable 加 isSupplier prop,供应商隐藏 24 个始终为空的内部字段
- 验证:管理员仍看全部 46 列,供应商看 20 列

注意:本提交的 listRowsPaged 依赖 normalizedSupplierName 列
(schema.prisma + 迁移 20260730150000,由另一线程改动,未含在本提交)。
单独部署会因缺列报 500,需与另一线程的 schema/迁移一并合并。
2026-07-30 17:04:53 +08:00
WuYongJie
400bdaf1ef merge: release AI render catalog scope 2026-07-30 10:32:27 +08:00
WuYongJie
3a0f7079fc merge: scope AI render catalog to product development 2026-07-30 10:30:54 +08:00
WuYongJie
0a2f6b971b fix(ai-render): scope catalog to product development 2026-07-30 10:28:45 +08:00
WuYongJie
fc61e25d73 merge: release BOM costing cost truth 2026-07-29 20:02:49 +08:00
WuYongJie
10409ae69d Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/wuyongjie-bom-cost-truth-20260729 2026-07-29 19:56:50 +08:00
WuYongJie
91a5ce30ce fix(bom-costing): align material and packaging cost truth 2026-07-29 19:56:27 +08:00
jingchuan
a0bf3a21c7 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/xuxiake-mainline-todo-unionid-20260729 2026-07-29 18:32:09 +08:00
jingchuan
2c178b5b49 fix(oa-board): use union ids for dingtalk todos 2026-07-29 18:31:29 +08:00
WuYongJie
03585c7872 merge: release intake AI render asset linking 2026-07-29 17:54:30 +08:00
WuYongJie
f8fe78e2cb merge: link intake products with AI render assets 2026-07-29 17:42:56 +08:00
WuYongJie
449eef2a19 feat(ai-render): link intake models and generated assets 2026-07-29 17:41:04 +08:00
jingchuan
e9d60543b0 fix(oa-board): dedupe dingtalk owner identities 2026-07-29 17:18:26 +08:00
jingchuan
e53d5555f6 fix(oa-board): dedupe dingtalk owner identities 2026-07-29 17:04:12 +08:00
WuYongJie
c3036152f2 merge: restrict barcode import permissions 2026-07-29 16:59:13 +08:00
WuYongJie
2697fb9f1d merge: restrict barcode import permissions 2026-07-29 16:57:56 +08:00
WuYongJie
d435d1f535 fix: restrict barcode import management permissions 2026-07-29 16:56:34 +08:00
WuYongJie
49fde0f5c0 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/xuxiake-main-work-record-score-deploy-20260729 2026-07-29 16:01:48 +08:00
WuYongJie
c1151b6af5 Merge remote-tracking branch 'origin/codex/xuxiake-work-record-score-management-20260729' into codex/xuxiake-mainline-work-record-score-submit-20260729 2026-07-29 16:00:48 +08:00
WuYongJie
0259d685d2 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/xuxiake-work-record-score-management-20260729 2026-07-29 15:59:53 +08:00
WuYongJie
679e726a14 feat(work-record): manage score rules 2026-07-29 15:59:41 +08:00
WuYongJie
03430313b5 merge: 同步 BOM 核算商品决策布局 2026-07-29 15:07:36 +08:00
WuYongJie
ec98f2b33c merge: 发布 BOM 核算商品决策布局 2026-07-29 15:07:08 +08:00
WuYongJie
0c9c2fccc8 feat(bom-costing): 重构竞品核算结果工作台 2026-07-29 15:06:16 +08:00
jingchuan
60f252571a Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/xuxiake-mainline-submit-20260704 2026-07-29 13:49:38 +08:00
WuYongJie
eafa63f962 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/wuyongjie-restore-prod-ssh-main-20260729 2026-07-29 13:47:29 +08:00
jingchuan
c1f1c319c6 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/xuxiake-mainline-submit-20260704 2026-07-29 13:47:14 +08:00
WuYongJie
f496d8aac9 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/wuyongjie-restore-prod-ssh-20260729 2026-07-29 13:45:57 +08:00
WuYongJie
27789d37e8 revert(deploy): 恢复生产 SSH 直连入口 2026-07-29 13:45:50 +08:00
jingchuan
9ed6399c32 feat(oa-board): scaffold dingtalk todo dispatch 2026-07-29 13:45:41 +08:00
WuYongJie
a85c41383d merge: release square mobile nine-view previews 2026-07-29 13:39:15 +08:00
WuYongJie
654df39b1e fix(intake): square mobile nine-view previews 2026-07-29 13:38:30 +08:00
WuYongJie
8f1cfa68ce merge: release BOM streaming and workspace layout 2026-07-29 13:02:34 +08:00
WuYongJie
b7227f3ddc Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/wuyongjie-bom-524-layout-20260729 2026-07-29 13:00:37 +08:00
WuYongJie
2d866aa5e4 fix(bom-costing): 修复长请求并压缩图片工作区 2026-07-29 13:00:20 +08:00
WuYongJie
04aa9b3004 merge: release mobile intake detail adaptation 2026-07-29 12:26:55 +08:00
WuYongJie
97f7018c03 fix(intake): adapt product detail links for mobile 2026-07-29 12:26:18 +08:00
WuYongJie
b18418ff40 merge: sync production management jump path 2026-07-29 11:44:36 +08:00
WuYongJie
bdc8cdab8c merge: 生产管理跳板通道 2026-07-29 11:44:12 +08:00
WuYongJie
8d92e137cb ops(deploy): 切换生产管理跳板通道 2026-07-29 11:43:47 +08:00
WuYongJie
c437177609 merge: sync OA category normalization 2026-07-29 11:16:27 +08:00
WuYongJie
e6a4fdf21a fix(intake): normalize OA residential categories 2026-07-29 11:14:27 +08:00
WuYongJie
5dedc6ed72 merge: 同步 BOM SKU 尺寸契约修复 2026-07-29 11:10:53 +08:00
WuYongJie
e41966d1fa merge: BOM SKU 尺寸契约修复 2026-07-29 11:10:08 +08:00
WuYongJie
bfdefd20d3 fix(bom-costing): 统一 SKU 尺寸输出契约 2026-07-29 11:07:10 +08:00
WuYongJie
7aa0e67063 merge: sync top navigation layout 2026-07-29 10:56:48 +08:00
WuYongJie
a8dff278e0 fix: keep workbench navigation on one line 2026-07-29 10:48:15 +08:00
WuYongJie
11ad175bae merge: 同步 BOM 核算过程可视化 2026-07-29 10:36:12 +08:00
WuYongJie
30989452a9 merge: BOM 核算过程可视化 2026-07-29 10:35:20 +08:00
WuYongJie
b541acca8e feat(bom-costing): 增强核算过程可视化 2026-07-29 10:34:07 +08:00
WuYongJie
5f5a8f2036 merge: 同步 BOM 核算历史续跑 2026-07-28 21:13:17 +08:00
WuYongJie
7c632aba6f merge: BOM 核算历史续跑 2026-07-28 21:12:42 +08:00
WuYongJie
80b65bc7f3 fix(bom-costing): 收敛模型输入并支持历史续跑 2026-07-28 21:11:57 +08:00
WuYongJie
2093f809c7 merge: installation demo share preview parity 2026-07-28 19:03:25 +08:00
WuYongJie
155a6579aa fix: align installation demo share preview runtime 2026-07-28 18:59:14 +08:00
WuYongJie
3a7fbe81fb merge: 同步 BOM 核算异步工作台 2026-07-28 18:52:48 +08:00
WuYongJie
cab376d91c merge: BOM 核算异步工作台 2026-07-28 18:52:11 +08:00
WuYongJie
999969a78d Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/wuyongjie-bom-async-workbench 2026-07-28 18:50:59 +08:00
WuYongJie
156bff395d feat(bom-costing): 增加异步核算与资源缓存 2026-07-28 18:50:47 +08:00
WuYongJie
7f201fe08e merge: supplier barcode-only access 2026-07-28 17:39:50 +08:00
WuYongJie
7f0561df35 merge: supplier barcode-only access 2026-07-28 17:39:17 +08:00
WuYongJie
10be42a9c8 fix(auth): restrict supplier accounts to barcode printing 2026-07-28 17:38:23 +08:00
WuYongJie
63562013af Merge branch 'codex/xuxiake-mainline' into main 2026-07-28 17:01:33 +08:00
WuYongJie
6e6e0f5e4b Merge branch 'codex/wuyongjie-bom-real-provider' into codex/xuxiake-mainline 2026-07-28 17:01:01 +08:00
WuYongJie
5311fc2d51 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/wuyongjie-bom-real-provider 2026-07-28 16:56:04 +08:00
WuYongJie
61a0c9e301 feat(bom-costing): 接入竞品详情与多模态核算 2026-07-28 16:55:59 +08:00
WuYongJie
175b5b7bb5 fix(intake): add barcode print page jump 2026-07-28 16:26:09 +08:00
jingchuan
c5000a5950 Merge branch 'codex/xuxiake-oa-flow-status-20260728' into HEAD 2026-07-28 16:21:33 +08:00
jingchuan
1b6ea9dcbe fix(oa-board): finalize component development flows 2026-07-28 16:20:36 +08:00
WuYongJie
78f5e8c570 fix(intake): wrap long Gujia barcode suffixes 2026-07-28 15:56:39 +08:00
WuYongJie
a423bddc63 merge: sync main before release notes deployment 2026-07-28 11:32:16 +08:00
WuYongJie
c927c831c5 feat: add release notes and sku warehouse batch initialization 2026-07-28 11:29:32 +08:00
WuYongJie
b2cf27ef68 merge: apply shared display refinements 2026-07-28 11:22:05 +08:00
WuYongJie
be9cdb8ed8 fix(installation-demo): refine shared display stages 2026-07-28 11:20:13 +08:00
WuYongJie
a36521f07c merge: apply carried-group screw playback fix 2026-07-28 10:52:47 +08:00
WuYongJie
7695bacfe2 fix(installation-demo): skip screw drive for carried groups 2026-07-28 10:49:08 +08:00
WuYongJie
84510b2f57 merge: 同步 AI 配置模型列表与共享主线 2026-07-28 10:17:56 +08:00
WuYongJie
e3d37c4391 merge: AI 配置读取可用模型列表 2026-07-28 10:17:34 +08:00
WuYongJie
edab790d0d Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/wuyongjie-ai-model-selector 2026-07-28 10:13:50 +08:00
WuYongJie
fd76a06942 fix(ai-config): 从服务端读取可用模型列表 2026-07-28 10:13:37 +08:00
WuYongJie
89acc2cd4b merge: publish installation demo playback refinements 2026-07-28 09:59:43 +08:00
WuYongJie
494bd0b04b merge: installation demo playback refinements 2026-07-28 09:56:36 +08:00
WuYongJie
b4e6bb865c feat(installation-demo): refine authored playback guidance 2026-07-28 09:55:52 +08:00
WuYongJie
22d54be408 merge: improve work record editing workflow 2026-07-27 14:37:57 +08:00
WuYongJie
117abf7df0 fix(work-record): improve table editing workflow 2026-07-27 14:37:20 +08:00
WuYongJie
0c73cdddc2 merge: save installation snapshots under production CSP 2026-07-27 14:20:13 +08:00
WuYongJie
2773368df1 merge: save installation snapshots under production CSP 2026-07-27 14:19:45 +08:00
WuYongJie
f30c1aa17f fix(installation-demo): save snapshots under production CSP 2026-07-27 14:19:14 +08:00
WuYongJie
fa9c4738e0 merge: release installation demo snapshot persistence 2026-07-27 12:00:25 +08:00
WuYongJie
4a9e8460c0 merge: persist installation demo snapshots 2026-07-27 11:59:48 +08:00
WuYongJie
cea36979d9 fix(installation-demo): persist numbering snapshots 2026-07-27 11:59:26 +08:00
WuYongJie
eb69c3473e merge: release installation demo tool loading fix 2026-07-27 10:53:20 +08:00
WuYongJie
d6e3be000b fix(installation-demo): stabilize tool model loading 2026-07-27 10:51:50 +08:00
WuYongJie
951f62832a merge: 同步徐霞客主线协作规则 2026-07-27 10:32:12 +08:00
WuYongJie
7e2f20bba9 merge: 回流主逻辑优先协作规则 2026-07-27 10:32:05 +08:00
WuYongJie
675237e16d docs(agents): 强化主逻辑优先规则 2026-07-27 10:31:43 +08:00
WuYongJie
f6f6ea4493 Merge remote-tracking branch 'origin/main' into codex/wuyongjie-bom-costing-ui-polish-20260723 2026-07-27 10:23:31 +08:00
WuYongJie
d48a905077 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/wuyongjie-bom-costing-ui-polish-20260723 2026-07-27 10:23:26 +08:00
WuYongJie
e909cbdc94 refactor(bom-costing): 收紧空态工作台布局 2026-07-27 10:22:59 +08:00
WuYongJie
4e59043761 fix(installation-demo): recover screw-drive tool attachments 2026-07-27 09:00:45 +08:00
WuYongJie
8752d7c5ef merge: 同步主线后发布安装演示工作台
# Conflicts:
#	furniture-3d-system/prisma/schema.prisma
#	furniture-3d-system/src/app/installation-demo-workbench/InstallationDemoWorkbenchClient.tsx
#	furniture-3d-system/src/app/installation-demo-workbench/components/InstallationDetailsPanel.tsx
#	furniture-3d-system/src/app/installation-demo-workbench/components/InstallationInspector.tsx
#	furniture-3d-system/src/app/installation-demo-workbench/components/InstallationPartsInventoryBoard.tsx
#	furniture-3d-system/src/app/installation-demo-workbench/components/InstallationPreviewStage.tsx
#	furniture-3d-system/src/app/installation-demo-workbench/components/InstallationToolsInventoryBoard.tsx
#	furniture-3d-system/src/app/installation-demo-workbench/components/PartCatalogSection.tsx
#	furniture-3d-system/src/app/installation-demo-workbench/hooks/useInstallationLocalTransformPreview.ts
#	furniture-3d-system/src/app/installation-demo-workbench/hooks/useInstallationPreviewController.ts
#	furniture-3d-system/src/app/installation-demo-workbench/lib/installationNodeMaterialStorage.ts
#	furniture-3d-system/src/app/installation-demo-workbench/lib/installationNumberingSnapshotStorage.ts
2026-07-24 18:05:06 +08:00
WuYongJie
43ed761fae test: 补充安装步骤选择回归覆盖 2026-07-24 17:58:39 +08:00
WuYongJie
fc22c24fa0 feat: 完善安装演示工作台工具链 2026-07-24 17:58:02 +08:00
WuYongJie
ddd0556030 merge: release work record column resize 2026-07-24 17:36:17 +08:00
WuYongJie
de2c1e1011 fix(work-record): add resizable table columns 2026-07-24 17:35:49 +08:00
WuYongJie
2e43240f51 merge: release installation demo workbench 2026-07-24 15:45:51 +08:00
WuYongJie
bc6b5249c4 chore(installation-demo): fix source whitespace 2026-07-24 15:39:21 +08:00
WuYongJie
1973664e0a chore(installation-demo): normalize source line endings 2026-07-24 15:38:26 +08:00
WuYongJie
4025cf6538 merge: retain installation demo playback refinements 2026-07-24 15:32:33 +08:00
WuYongJie
a33b249e28 feat(installation-demo): refine playback and shared preview 2026-07-24 15:32:22 +08:00
WuYongJie
a8e48929ea feat(installation-demo): add toolbox authoring support 2026-07-24 15:30:39 +08:00
jingchuan
adc7fbd7b8 Merge branch 'codex/xuxiake-mainline-submit-20260704' into HEAD 2026-07-24 14:51:03 +08:00
jingchuan
2869c9a27c fix(oa-board): enforce brand planning field sources 2026-07-24 14:48:52 +08:00
WuYongJie
9ed61a8a14 fix(work-record): normalize underscore import labels 2026-07-24 14:03:59 +08:00
WuYongJie
67a0efc0a5 fix(work-record): normalize imported labels and dates 2026-07-24 13:17:16 +08:00
WuYongJie
63e3ab1504 fix(intake): 直连报表库获取供应商目录 2026-07-24 10:54:23 +08:00
WuYongJie
cb0f69d6c0 fix(work-record): preserve workspace tab labels 2026-07-24 09:30:01 +08:00
WuYongJie
32df0f8c84 feat(work-record): add designer work record workspace 2026-07-23 20:36:09 +08:00
WuYongJie
baea745394 merge: release BOM costing workbench 2026-07-23 14:38:42 +08:00
WuYongJie
026fab35c9 merge: add BOM costing workbench 2026-07-23 14:38:05 +08:00
WuYongJie
fabc7ebdb4 feat(bom-costing): add competitor costing workbench 2026-07-23 14:37:12 +08:00
WuYongJie
b24fcf26ca feat(operation-logs): record intake detail events 2026-07-23 10:20:35 +08:00
jingchuan
018feadda3 merge: scope OA brand planning board to new workflows 2026-07-22 18:48:54 +08:00
jingchuan
b1c8ef2e48 fix(oa-board): scope brand planning rows to new workflows 2026-07-22 18:48:21 +08:00
jingchuan
b5506df5d1 merge: add OA brand planning board 2026-07-22 18:32:10 +08:00
jingchuan
3150fea488 feat(oa-board): add brand planning board snapshot 2026-07-22 18:18:57 +08:00
WuYongJie
735a0edd1c merge: add operation-log admin navigation 2026-07-22 16:33:40 +08:00
WuYongJie
615b0013f4 fix(operation-logs): add admin navigation entry 2026-07-22 16:32:34 +08:00
WuYongJie
0a85348fbd fix(jushuitan): map package count to package type 2026-07-22 15:38:24 +08:00
WuYongJie
79618eb594 merge: release external intake visibility restriction 2026-07-22 13:43:07 +08:00
WuYongJie
36f3f6e910 merge: restrict external intake record visibility 2026-07-22 13:41:01 +08:00
WuYongJie
058272ecbf fix(intake): hide external entry records from internal users 2026-07-22 13:39:14 +08:00
WuYongJie
2c15734c11 merge: admin operation monitoring into main 2026-07-22 12:31:31 +08:00
WuYongJie
b870272eb5 merge: admin operation monitoring into mainline 2026-07-22 12:30:33 +08:00
WuYongJie
e18773d3aa feat(operation-logs): add admin operation monitoring 2026-07-22 12:29:58 +08:00
WuYongJie
ab954f3505 feat(external): 结构化产品定厂字段并扩展宽表 2026-07-22 11:58:54 +08:00
WuYongJie
53ded89075 feat(jushuitan): retry virtual inventory push 2026-07-22 10:44:47 +08:00
WuYongJie
28ea27f119 fix(intake): unify purchase owner authority 2026-07-21 20:42:54 +08:00
WuYongJie
5e722abde4 fix: OA预填改为系统已有值优先,OA只在系统没值时才填 2026-07-21 15:06:05 +08:00
WuYongJie
f4edd3e780 fix: 仓库模糊匹配——输入不完整仓库名自动纠正 2026-07-21 09:24:28 +08:00
WuYongJie
c18b54a92c fix: 非保留类目一级分类统一改为住宅家具 2026-07-20 14:56:51 +08:00
WuYongJie
7bd796b04a fix: 更新favicon.ico为新logo 2026-07-20 13:16:35 +08:00
WuYongJie
fe2c7f8249 Merge branch 'main' of http://git.1080p.hk/WuYongJie/furniture-3d-system-Wu 2026-07-20 13:07:28 +08:00
WuYongJie
edb1f30451 fix: 更新logo为最新版本 2026-07-20 13:06:44 +08:00
jingchuan
7a9ec16300 merge: measure first order from material completion 2026-07-18 14:36:50 +08:00
jingchuan
1c38d05b1d fix(oa-board): measure first order from material completion 2026-07-18 14:36:09 +08:00
jingchuan
df55db0bc7 merge: include OA board or-sign timing fix 2026-07-18 13:26:27 +08:00
jingchuan
e1781983aa fix(oa-board): exclude canceled or-sign tasks from timing 2026-07-18 12:06:04 +08:00
WuYongJie
a1228df9ea Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/wuyongjie-main-merge-oa-board-20260718 2026-07-18 11:45:19 +08:00
WuYongJie
3b18d3beab Merge remote-tracking branch 'origin/codex/xuxiake-mainline-submit-20260704' into codex/wuyongjie-release-oa-board-20260718 2026-07-18 11:28:45 +08:00
jingchuan
e8d2eb7509 fix(oa-board): parse source timestamps as china time 2026-07-18 10:35:33 +08:00
jingchuan
a35ad4776a fix(oa-board): sum repeated node durations 2026-07-18 10:10:22 +08:00
jingchuan
b0a7ec9591 fix(oa-board): wrap timeout followup exports 2026-07-17 18:28:02 +08:00
jingchuan
bb3445fdd1 fix(oa-board): honor canceled returned tasks 2026-07-17 17:14:54 +08:00
jingchuan
83b12fc11f fix(oa-board): backfill export creators 2026-07-17 15:48:13 +08:00
jingchuan
2cfa2eede0 fix(oa-board): resolve current task owners 2026-07-17 15:41:47 +08:00
jingchuan
1edfaec702 chore(oa-board): add scheduled snapshot sync 2026-07-17 14:32:55 +08:00
jingchuan
03f87e2dcb fix(oa-board): save all edited timeout stages 2026-07-17 13:57:41 +08:00
jingchuan
12b454505e fix(oa-board): preserve detail tab when filtering 2026-07-17 13:34:47 +08:00
WuYongJie
1c9bd11d20 Merge remote-tracking branch 'origin/codex/xuxiake-mainline-submit-20260704' 2026-07-17 13:04:45 +08:00
jingchuan
ebc261a730 feat(oa-board): restrict timeout followup editing 2026-07-17 12:30:19 +08:00
jingchuan
ea82b2c66f fix(oa-board): exclude exact threshold from overtime 2026-07-17 12:14:24 +08:00
jingchuan
a0e9913311 fix(oa-board): allow empty followup due date 2026-07-17 11:36:52 +08:00
WuYongJie
1cfe54ca17 Merge remote-tracking branch 'origin/codex/xuxiake-mainline-submit-20260704' into codex/non-integrated-detail-split 2026-07-17 10:58:59 +08:00
jingchuan
9115c519e1 fix(oa-board): make timeout action plan optional 2026-07-17 10:40:18 +08:00
WuYongJie
fdcfbae436 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/non-integrated-detail-split 2026-07-17 10:37:14 +08:00
WuYongJie
c673fa18e3 refactor: 拆分产品资料详情组件 2026-07-17 10:36:29 +08:00
WuYongJie
f6b045d5ae Merge remote-tracking branch 'origin/codex/xuxiake-mainline-submit-20260704' 2026-07-17 10:10:39 +08:00
jingchuan
081e1f6cc4 feat(oa-board): filter detail by current approver 2026-07-17 09:55:05 +08:00
WuYongJie
cf0fc7c6ec feat: 权限判定增加成功日志(write allowed),方便排查 2026-07-17 09:08:35 +08:00
WuYongJie
8c9c662aeb fix: 更新浏览器页签logo 2026-07-16 15:18:37 +08:00
jingchuan
204ad40e76 perf(oa-board): make sidebar tab switches instant 2026-07-16 09:08:48 +08:00
WuYongJie
34077ca512 Merge branch 'main' of http://git.1080p.hk/WuYongJie/furniture-3d-system-Wu 2026-07-15 18:51:05 +08:00
WuYongJie
329d793705 fix: 厨房储物架/置物架一级类目改为住宅家具 2026-07-15 18:48:29 +08:00
WuYongJie
ad80419fae fix: send jst combine sku childList payload 2026-07-15 18:20:14 +08:00
WuYongJie
393893c295 Merge remote-tracking branch 'origin/codex/xuxiake-mainline-submit-20260704' 2026-07-15 18:11:45 +08:00
jingchuan
0eece49dc0 fix(oa-board): map pricing timeout owners correctly 2026-07-15 18:00:13 +08:00
jingchuan
cb2466c243 feat(oa-board): add timeout analysis and followup workflow 2026-07-15 17:56:48 +08:00
WuYongJie
e0fbc8c988 fix: use dedicated jst combine sku credentials 2026-07-15 17:48:47 +08:00
WuYongJie
f8e9d6855e fix: 权限拦截彻底修复——通用分支去硬拦截+权限判定日志+管理员豁免存量商品 2026-07-15 16:37:45 +08:00
WuYongJie
5e6fc49bb7 fix: 去掉保存时非当前节点的硬拦截,改为静默忽略 2026-07-15 15:46:16 +08:00
WuYongJie
f3e7d93aa3 fix: scope non-integrated product factory saves 2026-07-15 15:05:16 +08:00
WuYongJie
1b4ea170aa fix: scope product factory autosaves 2026-07-15 14:06:29 +08:00
WuYongJie
ff4950b69e fix: scope product factory download saves 2026-07-15 13:37:27 +08:00
WuYongJie
c1215a4617 chore(storage): use current qiniu resumable options 2026-07-14 17:00:02 +08:00
WuYongJie
9ae3dad2d0 fix(storage): use resumable upload for large documents 2026-07-14 16:51:06 +08:00
WuYongJie
299d737da8 fix(intake): harden large document uploads 2026-07-14 16:36:35 +08:00
WuYongJie
694230e30c fix(intake): stream large attachment uploads 2026-07-14 14:44:06 +08:00
WuYongJie
5825c52ad3 fix(intake): raise attachment upload limit to 1.5GB 2026-07-14 14:33:48 +08:00
WuYongJie
bb7f4260cf fix(intake): restore legacy barcode preview scaling 2026-07-14 10:38:22 +08:00
WuYongJie
5d13d2550b feat: add customer service business permissions 2026-07-13 16:02:59 +08:00
WuYongJie
ccfe925b5d feat: improve installation demo mobile share 2026-07-13 15:19:09 +08:00
WuYongJie
e1c4d5dc33 fix(users): classify strategy and general business roles 2026-07-13 15:07:36 +08:00
WuYongJie
5426a3782c fix(intake): add missing node permission targets 2026-07-13 13:53:49 +08:00
WuYongJie
386efdbeb2 feat: align sample review sheet template export 2026-07-13 13:36:12 +08:00
WuYongJie
5bf8f64d15 fix(users): append missing operations roles 2026-07-13 13:28:18 +08:00
WuYongJie
0c72819a12 feat(users): add operations business type 2026-07-13 13:08:18 +08:00
WuYongJie
23cf041ee7 merge: promote external intake confirm fix to main 2026-07-13 11:59:59 +08:00
WuYongJie
36763ca629 fix(intake): scope external confirm saves 2026-07-13 11:59:14 +08:00
WuYongJie
f2af9582af merge: promote intake updates to main 2026-07-13 11:11:20 +08:00
WuYongJie
5ab182a61e Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/tmp-intake-date-filter-20260713-105421 2026-07-13 10:57:37 +08:00
WuYongJie
f3eadddcb3 fix(intake): add product development created date filter 2026-07-13 10:57:01 +08:00
WuYongJie
89da950c07 fix(intake): save pricing workspace explicitly 2026-07-13 10:56:58 +08:00
WuYongJie
bae1563a98 fix(intake): enable suofeiya brand filing package download 2026-07-13 10:51:47 +08:00
WuYongJie
6172ead37c Merge remote-tracking branch 'origin/codex/xuxiake-mainline' 2026-07-13 10:10:57 +08:00
WuYongJie
c1bbdee0b9 refactor: 删除废弃的 buildApprovalNumber/padApprovalNumberPart 2026-07-13 10:09:59 +08:00
WuYongJie
df257bde69 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' 2026-07-12 18:31:55 +08:00
WuYongJie
975ecee94a fix(intake): 确认节点先保存再打勾,SKU未入库提示修正 2026-07-12 09:35:48 +08:00
WuYongJie
35e08a6151 merge: promote brand filing updates to main 2026-07-10 18:24:25 +08:00
WuYongJie
bfcc1bdc39 feat(intake): 完善品牌报备模板流程 2026-07-10 18:10:43 +08:00
WuYongJie
5d8e136f12 merge: promote long-running branch to main 2026-07-10 18:07:56 +08:00
WuYongJie
11ea3e168b fix: restrict external intake owner selections 2026-07-10 18:01:48 +08:00
WuYongJie
a789124f10 feat: refine installation demo numbering preview 2026-07-10 16:49:30 +08:00
WuYongJie
c29e25b880 merge: 合并长期分支到 main 2026-07-10 14:42:28 +08:00
WuYongJie
6c407f208b Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into local/xuxiake-mainline-continue 2026-07-10 14:29:14 +08:00
WuYongJie
9c755282ce merge: 同步长期分支并保留品牌报备更新 2026-07-10 14:27:43 +08:00
WuYongJie
a866e0dffe fix: use public origin for installation demo shares 2026-07-10 14:24:07 +08:00
WuYongJie
d0af5d85dc fix: use public origin for installation demo shares 2026-07-10 14:23:20 +08:00
WuYongJie
be49070962 feat(intake): 完善品牌报备模板与已报备流程 2026-07-10 14:22:30 +08:00
WuYongJie
3346804952 fix(intake): scope factory saves to active sku batch 2026-07-10 13:57:36 +08:00
WuYongJie
58471baaf6 Merge remote-tracking branch 'origin/codex/wuyongjie-intake-factory-save-scope-20260710' into codex/tmp-promote-intake-factory-save-scope-20260710 2026-07-10 13:48:57 +08:00
WuYongJie
72b4581f77 fix(intake): scope product factory saves by target sku 2026-07-10 13:47:39 +08:00
WuYongJie
11be446db2 merge: retain latest main before installation demo build fix 2026-07-10 11:58:52 +08:00
WuYongJie
f035863350 fix(installation-demo): resolve playback focus type checks 2026-07-10 11:56:51 +08:00
WuYongJie
3e67badaf9 fix(installation-demo): resolve playback focus type checks 2026-07-10 11:55:14 +08:00
WuYongJie
c9405db975 merge: promote sku-scoped product factory permissions 2026-07-10 11:51:48 +08:00
WuYongJie
3c97d2b774 fix(intake): scope product factory writes by sku owner 2026-07-10 11:42:24 +08:00
WuYongJie
f178e9cceb fix(intake): scope product factory writes by sku owner 2026-07-10 11:41:24 +08:00
WuYongJie
5734fca012 merge: promote installation demo workbench to main 2026-07-10 11:25:10 +08:00
WuYongJie
d37bfcdde1 feat: add installation demo workbench 2026-07-10 11:16:26 +08:00
WuYongJie
8cb9252115 feat: add installation demo workbench 2026-07-10 11:02:00 +08:00
WuYongJie
fcc94ee37e fix(intake): tighten brand filing entry rules 2026-07-09 18:36:55 +08:00
WuYongJie
a98caca397 fix(intake): tighten brand filing entry rules 2026-07-09 18:35:59 +08:00
WuYongJie
3c78dbf994 feat(intake): add gujia brand filing templates 2026-07-09 17:43:46 +08:00
WuYongJie
05fe0cc783 feat(intake): add gujia brand filing templates 2026-07-09 17:40:54 +08:00
WuYongJie
149870943d feat(intake): add brand filing workspace and planning export 2026-07-09 13:56:23 +08:00
WuYongJie
cf44f1c371 feat(intake): add brand filing workspace and planning export 2026-07-09 13:55:52 +08:00
WuYongJie
29fe5aaeb2 fix: allow purchasing downloads for product data 2026-07-08 16:45:11 +08:00
WuYongJie
5f5dc2ead7 fix: allow purchasing downloads for product data 2026-07-08 16:38:36 +08:00
WuYongJie
071021fe54 fix: default intake sku sales status to 销售 2026-07-08 15:55:45 +08:00
WuYongJie
4982b37864 fix: default intake sku sales status to 销售 2026-07-08 15:45:49 +08:00
WuYongJie
30b1c5740d fix(intake): classify owner dropdown options 2026-07-07 14:08:01 +08:00
WuYongJie
37b2e89b49 fix(intake): classify owner dropdown options 2026-07-07 14:07:04 +08:00
WuYongJie
cec4b449ad fix(auth): 放行主管用户管理入口 2026-07-06 21:51:59 +08:00
WuYongJie
50b8f61a69 fix(auth): 补齐主管权限范围字段 2026-07-06 19:14:13 +08:00
jingchuan
cf54f94ba5 feat(oa-board): add summary tabs and stage graph updates 2026-07-04 16:46:38 +08:00
WuYongJie
5332202f9f fix(external): stream jsreport sync from stable cursor 2026-07-03 16:35:08 +08:00
WuYongJie
883d896406 chore(external): prefix jsreport sync tables 2026-07-03 16:08:00 +08:00
WuYongJie
122df58236 chore(external): sync jsreport every 45 minutes 2026-07-03 15:36:06 +08:00
WuYongJie
6c5ee5e512 chore: keep shell scripts lf 2026-07-03 15:00:15 +08:00
WuYongJie
0300858fdf feat(external): sync readonly views to jsreport 2026-07-03 14:46:59 +08:00
WuYongJie
611b7842c0 feat(external): expose development owners in catalog wide view 2026-07-03 13:26:59 +08:00
WuYongJie
1cbfeba4a6 merge: sync product category filter into main 2026-07-02 14:03:49 +08:00
WuYongJie
d598f30a0c feat(intake): add product category filter to development list 2026-07-02 14:03:07 +08:00
WuYongJie
8a28af209d merge: promote planning analysis upload copy to main 2026-07-02 10:40:20 +08:00
WuYongJie
f455dc47de fix(intake): update planning analysis upload copy 2026-07-02 10:39:56 +08:00
WuYongJie
f4dec4e1a9 merge: promote intake existing spu brand carryover to main
# Conflicts:
#	furniture-3d-system/src/server/services/__tests__/assisted-assembly-ai-render.service.test.ts
2026-07-02 10:15:46 +08:00
WuYongJie
b1f10cd37c feat(intake): align existing spu brand carryover 2026-07-02 10:09:49 +08:00
WuYongJie
553329ac80 test(ai-render): align delete storage mock 2026-07-01 15:50:56 +08:00
WuYongJie
921e0a1503 refactor(ai-render-workbench): split ai render backend flow 2026-07-01 15:44:06 +08:00
WuYongJie
a6fb2d8380 refactor(ai-render-workbench): split gallery and material panel 2026-07-01 15:44:06 +08:00
WuYongJie
0af59ed31b fix(ai-render): protect records when storage cleanup fails 2026-07-01 15:44:06 +08:00
WuYongJie
d02f27b28f refactor(ai-render-workbench): split ai render backend flow 2026-07-01 15:37:39 +08:00
WuYongJie
b59e6a241f fix(jst): push sales status and modular label 2026-07-01 15:05:40 +08:00
WuYongJie
135cab0990 fix(jst): push sales status and modular label 2026-07-01 15:03:36 +08:00
WuYongJie
f6f717eae8 refactor(ai-render-workbench): split gallery and material panel 2026-07-01 14:34:50 +08:00
WuYongJie
708e0679c2 fix(ai-render): protect records when storage cleanup fails 2026-07-01 13:13:40 +08:00
WuYongJie
397767604d fix(ai-render): make render deletion idempotent 2026-07-01 11:03:31 +08:00
WuYongJie
0df9f12c2c fix(intake): refine second-template barcode layout 2026-07-01 10:32:02 +08:00
WuYongJie
26b1d33eca merge: promote ai-white-background regenerate UI fix to main 2026-07-01 10:30:40 +08:00
WuYongJie
ad344c27eb Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/submit-barcode-second-template-followup-20260701 2026-07-01 10:30:06 +08:00
WuYongJie
8510049293 fix(intake): refine second-template barcode layout 2026-07-01 10:28:44 +08:00
WuYongJie
9b0bf2f31a fix(ai-white-background): hide duplicate regenerate entry and title in refinement popover
- 精修气泡展开时隐藏卡片底部「重新生成」按钮,避免功能入口重复占地方
- 去掉气泡内「重新生成 · 正视图」重复标题(上下文已在视图卡片内)
- 保留「生成」态与右侧精修面板,单张首生成能力不受影响
2026-07-01 10:25:27 +08:00
WuYongJie
354a154fee merge: promote second-template barcode print fix to main 2026-07-01 08:44:08 +08:00
WuYongJie
dd4dc279e1 fix(intake): stabilize second-template barcode printing 2026-07-01 08:43:45 +08:00
WuYongJie
91a9585b68 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' 2026-06-30 17:50:37 +08:00
WuYongJie
9b799dd838 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/wuyongjie-ai-white-background-color-fix 2026-06-30 17:41:13 +08:00
WuYongJie
c26113a6ec refactor(ai-white-background): 合并生成设置为单一材质方案区块
将「目标与源图」「单张修正」「材质方案」三个并列折叠区块合并为一个
「材质方案」区块,简化用户心智模型:

- 目标花色(本次生图主色) + 源条码 + 禁用原因 上移到材质方案区顶部
- 部位材质定义 保留为材质方案核心
- 各视图精修指令(原单张修正) 收纳为材质方案底部子区
- 「重新生成」按钮改为弹内联编辑气泡: 预填该视图精修提示词,
  可改可不改后确认重做, 不再跳转到独立单张修正区
- 简化 AiWhiteBackgroundSettingsSectionId 类型为单一 materials

纯前端 UI 重组, 不动后端 API/服务/数据模型。
type-check 通过, 19 个相关测试全部通过。
2026-06-30 17:39:51 +08:00
WuYongJie
960f867744 merge: promote opening-code oa prefill to main 2026-06-30 16:26:19 +08:00
WuYongJie
6d89e1c2c3 feat(intake): prefill create form from oa opening code 2026-06-30 16:25:09 +08:00
WuYongJie
70594a287d fix(intake): polish development toolbar controls 2026-06-30 14:31:39 +08:00
WuYongJie
4629eea670 fix(intake): keep development table header sticky 2026-06-30 14:13:51 +08:00
WuYongJie
2b0f3758bb feat(intake): add processed quick scope 2026-06-30 09:49:40 +08:00
WuYongJie
614e568763 fix(intake): align non-integrated quick scopes 2026-06-29 21:33:03 +08:00
WuYongJie
e0bc1db6bf feat(external): 宽表强制一条码一行保护(DISTINCT ON barcode_business_key)
根因:external.product_catalog_wide_v1 的 FROM sku_source 行粒度是 SKU,
barcode 只是字段。当前 43261 行 barcode 全唯一是数据巧合(formal 0 行 +
intake ready 每条码唯一),视图定义没强制一条码一行。一旦出现一条码多 SKU
(正式 ProductSKU 落库 + intake ready 同条码,或 intake 内部同条码多行),
宽表就会重复,污染外部系统 barcode 主同步键。

修复:复用项目已有 DISTINCT ON(barcode_business_key) 模式(latest_quality /
limit_by_barcode CTE),把原主查询整体包成 catalog_by_sku CTE,外层加
DISTINCT ON (barcode_business_key)。优先级:FORMAL > INTAKE_READY,
updated_at 最新 > created_at 最新。

末尾追加 catalog_source 字段输出(数据来源标记,对外部系统有用)。
用 CREATE OR REPLACE VIEW 保留 external_reader 已有 GRANT 权限。

生产验证:行数 43261 不变,0 重复 barcode 组,字段完整。
2026-06-29 19:40:23 +08:00
WuYongJie
9c04e39aaf Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/wuyongjie-ai-white-background-color-fix 2026-06-29 16:05:05 +08:00
WuYongJie
a9ec724127 fix(intake): rename modular tag to modular component 2026-06-29 15:59:57 +08:00
WuYongJie
2f59b46444 revert(storage): 恢复CDN直连307跳转,撤回流式转发
之前的流式转发改动(66928576)是误诊。真实根因是七牛AK/SK失效:
- 密钥有效时,307重定向到签名URL → 七牛返回200 + CORS头(Access-Control-Allow-Origin:*)
- 密钥失效时,签名URL无效 → 七牛返回401 → 浏览器误判为ORB拦截

七牛CDN本身已正确配置CORS,不存在跨域问题。流式转发反而违背'图片走CDN减轻
香港带宽压力'的架构目标(图片又挤回香港管道)。现撤回流式转发,恢复307直连CDN。
2026-06-29 15:44:05 +08:00
WuYongJie
906fd5b8e6 Merge remote-tracking branch 'origin/main' into codex/wuyongjie-ai-white-background-color-fix
# Conflicts:
#	furniture-3d-system/src/app/intake/oa-board/OaBoardClient.tsx
2026-06-29 15:01:22 +08:00
WuYongJie
98e89f1573 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/wuyongjie-ai-white-background-color-fix 2026-06-29 13:59:38 +08:00
WuYongJie
66928576ac fix(storage): 图片代理改回流式转发修复跨域ORB拦截
根因:buildObjectReadResponse 默认对 https URL 返回 307 重定向到七牛 CDN,
浏览器对 cp.jiansun.vip → qnycdn.jiansun.vip 的跨域图片响应触发
ERR_BLOCKED_BY_ORB,导致所有 <img> 加载失败(图片全炸)。

修复:将 redirectHttps 默认值从 true 改为 false,强制走流式代理。
storage/object、intake assets 两处显式传 false 保持一致。
其余 6 处调用点自动继承新默认值,无需逐个改。

代价:Node 重新承担图片流式转发压力(后续签名URL下发优化解决)。
2026-06-29 13:58:51 +08:00
WuYongJie
5492ba316b fix(intake): prevent barcode print stretching 2026-06-29 13:30:03 +08:00
WuYongJie
772079750d fix(auth): allow redirect back to core workspaces 2026-06-29 13:30:03 +08:00
WuYongJie
cec5e2fcb2 fix(intake): prevent barcode print stretching 2026-06-29 13:11:13 +08:00
WuYongJie
b3d4a6f2ed fix(auth): allow redirect back to core workspaces 2026-06-29 13:11:12 +08:00
WuYongJie
391a085c2c fix(intake): derive product categories from secondary category 2026-06-29 11:54:38 +08:00
WuYongJie
b234134334 fix(intake): derive product categories from secondary category 2026-06-29 09:40:21 +08:00
WuYongJie
a0d597e14e refactor(ai-render-workbench): split workbench client modules 2026-06-26 21:25:20 +08:00
WuYongJie
3926fa4f26 refactor(ai-render-workbench): split workbench client modules 2026-06-26 21:18:28 +08:00
WuYongJie
443f56b099 fix(oa-board): compact filters and enable image preview 2026-06-26 17:56:56 +08:00
jingchuan
9c696e1947 fix(oa-board): stabilize filter and stage sync 2026-06-25 18:00:09 +08:00
WuYongJie
8cc0dc5218 fix(ai-white-background): 无花色借源颜色污染修复 + 工作区重排
根因:无花色 SKU 借源生图时,"未配置花色"占位符被当真实色传入,
后端 normalize 后 prompt 退化为"保持源图原色",AI 跟随源条码原图色调
生成错误颜色(SZ024203V01 案例:借胡桃色源图生成出胡桃色结果)。

A 方案(解开死结):
- Workspace 新增 inlineTargetColor 状态,用户可手动指定本次生图颜色
- isEffectiveAiWhiteBackgroundTargetColor 识别"未配置花色"等占位符为无效色
- targetColor 改为 effectiveTargetColor,占位符不再绕过空值校验
- Panel 目标花色区改为条件可输入:SKU 无色时显示输入框

B 方案(借源必填):
- 借源模式 + 无色时给出明确警示"必须指定目标颜色,否则跟随源条码色调"
- 输入框用警示色高亮

工作区重排(解决"操作小小一块"):
- 设置区加宽 310px→380px,字号放大 10/12px→11/13px
- 视图卡片放大 164/190px→180/210px,间距 gap-2→gap-3
- "目标与源图"小节默认展开(最常用不该藏)

验证:type-check 通过,白底图 61 个测试全过(含新增 3 个 A/B 方案验证)
2026-06-25 15:56:02 +08:00
WuYongJie
c172ce87bc docs(agents): 对齐当前项目真相并固化主线部署流程
- 全局规则引用改为 agent 中性(ZCode/Codex 各取所需)
- 技术栈口径改为以 package.json 为准,补 Tailwind v4 等漏列项
- 模型名 SKU 统一修正为 ProductSKU(业务概念与 Prisma 模型名对齐)
- 主链目录补充 approval-workflows/materials/mobile
- 对象存储路径修正为 src/lib/storage.ts(文件而非目录)
- 第 3 节新增主线部署标准流程(支线→xuxiake→main→部署)
- 合并验证与规范审查两节,修正不存在的 storage:gc 参数
2026-06-25 15:55:33 +08:00
WuYongJie
35ad68bf5e fix(storage): expose client runtime storage config 2026-06-24 18:28:32 +08:00
WuYongJie
caa5ca3c34 feat(draft-groups): add direct modular sku workflow 2026-06-24 17:58:54 +08:00
WuYongJie
e699dbb4b6 refactor(storage): remove legacy s3 aliases 2026-06-24 17:00:22 +08:00
WuYongJie
d42f4311e6 fix(storage): make gc provider aware 2026-06-24 16:54:23 +08:00
WuYongJie
d7d9317977 fix(storage): require explicit object provider 2026-06-24 16:44:01 +08:00
WuYongJie
13f8d94224 fix(intake): allow read-only adaptable brand viewing 2026-06-24 15:39:17 +08:00
WuYongJie
720644869c fix(ai-white-background): inherit related refinement context 2026-06-24 13:36:12 +08:00
WuYongJie
47a83a9f16 fix(ai-white-background): use generated views for refinement consistency 2026-06-24 11:25:08 +08:00
WuYongJie
350936d3c3 feat(asset-center): add asset family name code 2026-06-24 10:57:56 +08:00
WuYongJie
864b07c061 Align draft group deletion with modular detail references 2026-06-24 10:57:50 +08:00
WuYongJie
14ded3cab8 fix(ai-white-background): lock refinement camera prompts 2026-06-24 09:42:38 +08:00
WuYongJie
0eaa0ee023 Merge remote-tracking branch 'origin/main' 2026-06-24 09:38:56 +08:00
WuYongJie
708d28cd94 fix(intake): narrow brand center department permissions 2026-06-23 17:31:23 +08:00
WuYongJie
1188165fa1 fix(intake): narrow brand center department permissions 2026-06-23 17:25:03 +08:00
WuYongJie
2ba5062846 fix(intake): use basic info permission for sku download 2026-06-23 16:46:58 +08:00
WuYongJie
c9dd228c4b fix(ai-render): hide viewport helpers in references 2026-06-23 15:24:20 +08:00
WuYongJie
a62c1ee3b9 fix(ai-render): lock white render reference priority 2026-06-23 15:24:20 +08:00
WuYongJie
6702fd2995 fix(intake): lower document sidebar layer 2026-06-23 15:24:20 +08:00
WuYongJie
adba625280 fix(intake): lower document sidebar layer 2026-06-23 15:18:19 +08:00
WuYongJie
0d24fb3cef fix(draft-group): fit series spu field width 2026-06-23 14:43:11 +08:00
WuYongJie
1093772945 fix(ai-white-background): preserve generation progress 2026-06-23 14:13:13 +08:00
WuYongJie
3a17165562 test(draft-group): remove obsolete packaging fallback scaffolding 2026-06-23 13:01:27 +08:00
WuYongJie
534edddd11 feat(draft-group): refine assembly handoff linkage 2026-06-23 13:01:27 +08:00
WuYongJie
102a68ceb4 fix(assisted-assembly): align grouped barcode quantities
Sync draft-group grouped barcode quantity handling with assisted assembly and cover repeated grouped component sets in tests.
2026-06-23 13:01:27 +08:00
WuYongJie
7eef92219f Merge remote-tracking branch 'origin/main' into codex/wuyongjie-ai-wbg-upload-log 2026-06-23 11:40:56 +08:00
WuYongJie
9578c86201 fix(ai-white-background): trace batch generation views 2026-06-23 11:40:45 +08:00
WuYongJie
ff4f2bc962 fix(ai-render): add manual white-background detail references 2026-06-23 10:10:28 +08:00
WuYongJie
6d721d7b9a fix(ai-render): stabilize white render structure references 2026-06-23 10:10:28 +08:00
WuYongJie
ac03ec27de fix(intake): 串行补白底图生成 2026-06-23 09:07:48 +08:00
WuYongJie
c5733b8377 style(intake): 收纳AI白底图生成设置 2026-06-22 19:36:46 +08:00
WuYongJie
a77c87df35 fix(intake): 精确匹配AI白底图生成文件 2026-06-22 18:32:34 +08:00
WuYongJie
80e343b2d3 fix(intake): 优化产品资料与AI白底图界面密度 2026-06-22 17:40:22 +08:00
WuYongJie
c613a98b61 fix(intake): 增加产品资料缩略图悬浮预览 2026-06-22 17:02:33 +08:00
WuYongJie
2a185e6e79 fix(intake): 优化AI白底图反馈体验 2026-06-22 15:45:49 +08:00
WuYongJie
714036c751 fix(intake): 补齐AI白底图上传成功闭环 2026-06-22 14:20:42 +08:00
WuYongJie
5613f349a7 fix(intake): 为AI白底图素材库调用加超时 2026-06-22 13:32:56 +08:00
WuYongJie
e88bb2c8a5 fix(intake): 修复AI白底图素材库上传字段 2026-06-22 13:14:24 +08:00
WuYongJie
7eb044900c chore(intake): 记录AI白底图素材库上传失败 2026-06-22 12:02:11 +08:00
WuYongJie
531a84f5ab fix(intake): unify existing spu selection scope 2026-06-22 11:23:32 +08:00
WuYongJie
c144d836e9 fix(intake): 优化AI白底图单张修正 2026-06-22 11:12:11 +08:00
WuYongJie
17740ac822 fix(oa-board): 修复审批阶段状态类型收窄 2026-06-20 17:56:14 +08:00
jingchuan
2bd861527f fix(oa-board): align approval stage and owner resolution 2026-06-20 17:42:23 +08:00
WuYongJie
1fad12d718 fix(oa-board): align filter param parsing types 2026-06-20 16:31:39 +08:00
jingchuan
1cff836933 feat(oa-board): refine flow detail filters and layout 2026-06-20 16:10:46 +08:00
WuYongJie
9b5f2d9ee8 fix(ai-render): stabilize workbench white render pipeline 2026-06-20 16:06:11 +08:00
WuYongJie
710a208ba5 feat(intake): enhance product limit workbook flow 2026-06-20 14:12:12 +08:00
WuYongJie
3cb228fc16 feat(intake): scope sku batch workflow by batch 2026-06-20 11:38:52 +08:00
WuYongJie
3e860e0472 fix(asset-center): type mount point tuple 2026-06-20 08:47:21 +08:00
WuYongJie
251930b81d Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/xuxiake-mainline 2026-06-18 18:19:33 +08:00
WuYongJie
09c4e75f0e fix(asset-center): allow editing available model info 2026-06-18 18:19:23 +08:00
WuYongJie
30698a9480 feat(intake): 完善AI白底图重生修正交互 2026-06-18 15:15:34 +08:00
WuYongJie
875e8f3fc0 fix(intake): 防止AI白底图结果混入源图 2026-06-18 14:37:44 +08:00
WuYongJie
7bc7008799 fix(intake): 恢复AI白底图借源会话 2026-06-18 13:57:59 +08:00
WuYongJie
1af2c401d3 Merge remote-tracking branch 'origin/main' into codex/release-ai-white-background-structure 2026-06-18 13:25:16 +08:00
WuYongJie
dd4661ff6e Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/release-ai-white-background-structure 2026-06-18 13:20:18 +08:00
WuYongJie
394d2c2ce6 fix(intake): 修复AI白底图借源正视图丢失 2026-06-18 13:20:00 +08:00
WuYongJie
381999d69b fix(intake): stop modular detail fetch regressions 2026-06-18 11:26:59 +08:00
WuYongJie
4139f712cc fix(intake): stop modular detail fetch regressions 2026-06-18 11:25:35 +08:00
WuYongJie
013256dfbd Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/release-ai-white-background-structure 2026-06-18 11:12:02 +08:00
WuYongJie
e3217c6bc1 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/wuyongjie-ai-render-texture-resign 2026-06-18 11:08:41 +08:00
WuYongJie
853d22d044 feat(intake): 优化AI白底图多视角生成 2026-06-18 11:08:29 +08:00
WuYongJie
7b62b0e291 fix(intake): require sample measurement before pricing push 2026-06-18 09:34:10 +08:00
WuYongJie
13b94e4263 fix(intake): require sample measurement before pricing push 2026-06-18 09:32:47 +08:00
WuYongJie
62eaf50800 优化AI白底图工作区布局 2026-06-17 19:36:20 +08:00
WuYongJie
d5a1427fff Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/wuyongjie-ai-render-texture-resign 2026-06-17 18:38:47 +08:00
WuYongJie
acd7756b2f fix(intake): allow modular parent sku push without cost price 2026-06-17 18:36:19 +08:00
WuYongJie
31391ee27e fix(draft-groups): harden modular detail navigation 2026-06-17 18:36:19 +08:00
WuYongJie
0fdd34ec24 fix(intake): 避免浏览触发自动保存 2026-06-17 18:30:51 +08:00
WuYongJie
d727459273 fix(intake): 按条码隔离实拍九视图 2026-06-17 17:58:54 +08:00
WuYongJie
0d2c648be4 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/wuyongjie-ai-render-texture-resign
# Conflicts:
#	furniture-3d-system/src/app/intake/non-integrated/workspaces/ai-white-background/NonIntegratedAiWhiteBackgroundPanel.tsx
#	furniture-3d-system/src/app/intake/non-integrated/workspaces/ai-white-background/NonIntegratedAiWhiteBackgroundWorkspace.tsx
#	furniture-3d-system/src/app/intake/non-integrated/workspaces/documents/ProductPhotoWorkspace.tsx
2026-06-17 17:43:02 +08:00
WuYongJie
af601ddb01 feat(intake): 完善 AI 白底图材质方案工作区 2026-06-17 17:35:43 +08:00
WuYongJie
0a813f2557 Merge remote-tracking branch 'origin/main' into codex/wuyongjie-target-barcode-label-fix 2026-06-17 16:26:14 +08:00
WuYongJie
f3033b0886 fix(intake): show barcode first in photo sku tree 2026-06-17 16:22:01 +08:00
WuYongJie
05524721f3 feat(ai-render): make eight-view renders structure-aware 2026-06-17 16:11:47 +08:00
WuYongJie
286c4c743c fix(intake): require source selection before borrowing images 2026-06-17 15:43:42 +08:00
WuYongJie
26b7e9e8d1 fix(intake): show source barcode values in ai white panel 2026-06-17 14:51:49 +08:00
WuYongJie
97986fd530 fix(intake): show actual target barcode in ai white panel 2026-06-17 14:42:48 +08:00
WuYongJie
2c2baf4b64 fix(intake): show styleless sku barcodes in photo workspace 2026-06-17 14:10:18 +08:00
WuYongJie
b2aaf2acc0 feat(ai-render): add sku-scoped workbench generation 2026-06-17 14:07:03 +08:00
WuYongJie
9bdc6ff0bd fix(intake): support stock spu sku continuation 2026-06-17 12:13:52 +08:00
WuYongJie
ac24f0546c fix(intake): normalize barcode print data source 2026-06-17 11:15:11 +08:00
WuYongJie
882e112a2a fix(ai-render): extend external image generation timeout 2026-06-17 09:44:20 +08:00
WuYongJie
88fd9bc231 merge: promote ai white background barcode backfill 2026-06-17 09:20:48 +08:00
WuYongJie
509c5cf730 merge: promote ai white background barcode backfill 2026-06-17 09:20:00 +08:00
WuYongJie
1b90df2b20 feat(intake): support ai white background barcode backfill 2026-06-17 09:18:58 +08:00
WuYongJie
7de12951b7 fix(ai-render): persist shared workbench data 2026-06-16 20:27:25 +08:00
WuYongJie
2cb01feafd merge: promote ai white background generation hardening 2026-06-16 19:48:22 +08:00
WuYongJie
f4f956bc8c fix(intake): harden ai white background generation 2026-06-16 19:47:51 +08:00
WuYongJie
c6b53f4cb8 Merge remote-tracking branch 'origin/codex/wuyongjie-ai-render-texture-resign' into HEAD
# Conflicts:
#	furniture-3d-system/src/server/services/oa-board.service.ts
2026-06-16 18:44:03 +08:00
WuYongJie
cdd64ade24 fix(oa-board): normalize timeline metric typing 2026-06-16 18:35:42 +08:00
WuYongJie
815ea75745 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/wuyongjie-ai-render-texture-resign 2026-06-16 18:31:13 +08:00
WuYongJie
fe139898e4 feat(intake): persist ai white background derived sku links 2026-06-16 18:31:05 +08:00
WuYongJie
c4caf7fc8e feat(intake): persist barcode print data 2026-06-16 18:14:38 +08:00
WuYongJie
15207d11fa fix(oa-board): type timeline metrics for build 2026-06-16 18:11:47 +08:00
jingchuan
03bdc6860f feat(oa-board): refine detail flow monitor 2026-06-16 18:05:26 +08:00
WuYongJie
5ec794e13e Merge remote-tracking branch 'origin/codex/wuyongjie-ai-render-texture-resign' into HEAD 2026-06-16 18:00:12 +08:00
jingchuan
874e67a185 feat(oa-board): refine detail flow monitor 2026-06-16 17:57:50 +08:00
WuYongJie
d6f9a861fc Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/wuyongjie-ai-render-texture-resign 2026-06-16 17:56:13 +08:00
WuYongJie
f4d93ddaa2 feat(intake): 支持AI白底图派生同批次SKU 2026-06-16 17:55:53 +08:00
WuYongJie
2e9f163c3a merge: promote ai render sku-bound tasks 2026-06-16 17:10:59 +08:00
WuYongJie
c2f0898784 feat(ai-render): bind render tasks to sku 2026-06-16 17:10:16 +08:00
WuYongJie
35ef013916 merge: promote AI render material signed urls to main 2026-06-16 16:21:30 +08:00
WuYongJie
fce3f46a04 merge: promote AI render material signed urls 2026-06-16 16:19:44 +08:00
WuYongJie
1954226df7 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/wuyongjie-ai-render-texture-resign 2026-06-16 16:17:20 +08:00
WuYongJie
7b94f30108 fix(storage): 延长七牛私有读链接有效期 2026-06-16 16:12:55 +08:00
WuYongJie
18dc1aa8ed fix(ai-render): 直传材质贴图签名URL 2026-06-16 16:09:57 +08:00
WuYongJie
e2a97af404 feat(ai-render): finalize model-locked image generation 2026-06-16 16:08:50 +08:00
WuYongJie
1c055d97c5 feat(ai-render): finalize model-locked image generation 2026-06-16 16:08:09 +08:00
WuYongJie
ca2eb8c4a6 merge: 稳定非集成访问链路 2026-06-16 15:09:47 +08:00
WuYongJie
e3fa838b39 merge: 稳定非集成访问链路 2026-06-16 15:09:08 +08:00
WuYongJie
d374470151 fix: stabilize intake navigation requests 2026-06-16 15:08:06 +08:00
WuYongJie
f36c020902 fix(ai-render): 重新签发材质贴图引用 2026-06-16 14:47:10 +08:00
WuYongJie
6eb624f8e4 fix(intake): simplify AI white product photo controls 2026-06-16 13:53:32 +08:00
WuYongJie
351a14d3ad fix(auth): allow restricted users into AI render workbench 2026-06-16 13:26:59 +08:00
WuYongJie
a5fe03b721 fix(ai-render): normalize UV axis config values 2026-06-16 13:05:31 +08:00
WuYongJie
0bfa19ae9c merge: promote AI render workbench 2026-06-16 12:55:27 +08:00
WuYongJie
5ae0b39192 feat(ai-render): add model-locked render workbench 2026-06-16 12:52:22 +08:00
WuYongJie
f12832ee69 merge: fix copied brand SPU reservation 2026-06-16 11:37:32 +08:00
WuYongJie
f49b0c6036 Merge remote-tracking branch 'origin/main' into codex/fix-copy-spu-20260616-111430 2026-06-16 11:36:30 +08:00
WuYongJie
d6b72c7060 fix: prevent copied brand products from reserving new SPU 2026-06-16 11:36:09 +08:00
WuYongJie
88182d671b feat(intake): add barcode print supplier workflow 2026-06-16 11:32:57 +08:00
WuYongJie
1f767cc76f merge: promote AI 白底图花色选择布局修复到主线 2026-06-16 11:28:45 +08:00
WuYongJie
3740bec0d2 fix(intake): constrain AI white target finish picker 2026-06-16 11:25:33 +08:00
WuYongJie
72b49620d8 merge: promote AI 白底图工作区布局修复到主线 2026-06-16 11:11:16 +08:00
WuYongJie
4d137e8734 fix(intake): 修复 AI 白底图工作区布局 2026-06-16 11:09:37 +08:00
WuYongJie
74ccbb3a1e Merge remote-tracking branch 'origin/main' into codex/xuxiake-ai-render-mainline-20260616 2026-06-16 10:47:04 +08:00
WuYongJie
6796944dc8 feat(ai-render): sync render workbench baseline 2026-06-16 10:46:36 +08:00
WuYongJie
6ac6c99811 merge: fix AI 白底图拖动看图类型检查 2026-06-16 10:22:08 +08:00
WuYongJie
d936895438 fix(intake): 修复 AI 白底图拖动状态类型检查 2026-06-16 10:21:10 +08:00
WuYongJie
a5ea1c1889 merge: promote AI 白底图拖动看图到主线 2026-06-16 10:11:29 +08:00
WuYongJie
ce6c403637 fix(intake): 支持拖动查看放大的 AI 白底图原图 2026-06-16 10:09:00 +08:00
WuYongJie
83f02257d1 merge: promote AI 白底图滚轮缩放到主线 2026-06-16 09:55:50 +08:00
WuYongJie
b2fea563ca fix(intake): 支持滚轮缩放 AI 白底图原图 2026-06-16 09:46:38 +08:00
WuYongJie
fec144e6a9 merge: promote AI 白底图黑色遮罩看图到主线 2026-06-16 09:32:34 +08:00
WuYongJie
eda6600a6f fix(intake): 改为黑色遮罩查看 AI 白底图原图 2026-06-16 09:31:37 +08:00
WuYongJie
b8cf682edc merge: promote AI 白底图页内原图查看到主线 2026-06-15 21:20:14 +08:00
WuYongJie
285b1fb2d9 fix(intake): 改为页内查看 AI 白底图原图 2026-06-15 21:19:33 +08:00
WuYongJie
2704d33b6e merge: promote AI 白底图低噪音调整到主线 2026-06-15 20:51:44 +08:00
WuYongJie
57279aa91f fix(intake): 降低 AI 白底图界面噪音 2026-06-15 20:47:31 +08:00
WuYongJie
5e1efa7a64 merge: promote AI 白底图界面改造到主线 2026-06-15 20:20:03 +08:00
WuYongJie
562cf5bba3 feat(intake): 重写 AI 白底图工作区界面 2026-06-15 20:10:32 +08:00
WuYongJie
5fb0028b31 merge: promote clean consolidation to main 2026-06-15 20:00:09 +08:00
WuYongJie
33c2e2899f Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/xuxiake-clean-consolidation-20260615 2026-06-15 19:53:40 +08:00
WuYongJie
5a0593e952 feat(auth): add supplier barcode account access 2026-06-15 19:52:47 +08:00
WuYongJie
e5175cabb0 merge: sync ai white background workspace 2026-06-15 19:19:43 +08:00
WuYongJie
94432e04d3 feat(intake): 将 AI 白底图升级为产品实拍工作区 2026-06-15 19:18:10 +08:00
WuYongJie
2a84f66951 feat(intake): add barcode print workbench 2026-06-15 19:15:22 +08:00
WuYongJie
6b4dcbdd31 feat(asset-center): make modular assets immediately available 2026-06-15 18:51:19 +08:00
WuYongJie
2e42fb220f feat(draft-groups): push pre sku to series product 2026-06-15 18:37:54 +08:00
WuYongJie
ecc294e79f fix(storage): fallback object reads without configured prefix 2026-06-15 18:32:39 +08:00
WuYongJie
9dbb61cdd1 feat(ai-render): add render workbench 2026-06-15 18:28:59 +08:00
WuYongJie
2d789c596c merge: sync storage gc negative status retry 2026-06-15 17:53:14 +08:00
WuYongJie
c36d77fba8 fix(storage): 重试七牛负状态码错误 2026-06-15 17:52:52 +08:00
WuYongJie
d4c20518b3 merge: sync storage gc reserved prefix guard 2026-06-15 17:36:23 +08:00
WuYongJie
8f1751c917 fix(storage): 支持 GC 运行时保留前缀 2026-06-15 17:36:10 +08:00
WuYongJie
f0b0c699ef merge: sync storage gc retry hardening 2026-06-15 17:27:23 +08:00
WuYongJie
cb3d8434e0 fix(storage): 增加七牛 GC 请求重试 2026-06-15 17:27:07 +08:00
WuYongJie
14c632d063 merge: sync storage gc qiniu sdk fix 2026-06-15 17:20:46 +08:00
WuYongJie
169a8df718 fix(storage): 兼容七牛 SDK 默认导出 2026-06-15 17:20:30 +08:00
WuYongJie
3b891b5460 merge: sync oa board type fix from xuxiake mainline 2026-06-15 17:06:14 +08:00
WuYongJie
c180cf2b18 fix(oa-board): 补齐同步看板类型导出 2026-06-15 17:05:41 +08:00
WuYongJie
e7e2a9368d merge: promote storage gc governance to main 2026-06-15 16:58:25 +08:00
WuYongJie
b26a30a8ae merge: promote storage gc governance to xuxiake mainline 2026-06-15 16:57:10 +08:00
WuYongJie
24c65f4da8 feat(storage): 增加七牛垃圾文件治理 2026-06-15 16:51:57 +08:00
WuYongJie
0eda70edd8 merge xuxiake mainline oa board and ai asset fixes 2026-06-15 16:44:34 +08:00
jingchuan
3ee7122380 feat(oa-board): add new product flow monitor 2026-06-15 15:58:09 +08:00
WuYongJie
829f828bbe fix(intake): 延长 AI 白底图请求等待 2026-06-15 15:51:15 +08:00
WuYongJie
455686e1e3 fix(intake): 降低非集成素材读取超时 2026-06-15 15:30:39 +08:00
WuYongJie
68a17b1dff feat(intake): 对接 AI 白底图花色改色与素材库上传 2026-06-15 14:58:37 +08:00
WuYongJie
319d61e41a merge xuxiake mainline asset preview permission fix 2026-06-15 12:11:07 +08:00
WuYongJie
dcfa96206a fix(intake): allow asset previews with view permission 2026-06-15 12:10:50 +08:00
WuYongJie
5f371c7a70 merge xuxiake mainline image proxy fix 2026-06-15 11:54:47 +08:00
WuYongJie
35740a7bc5 fix(intake): proxy non-integrated asset reads 2026-06-15 11:54:29 +08:00
WuYongJie
5fc719ce88 merge: promote platform material flow to main 2026-06-15 11:15:55 +08:00
WuYongJie
3d9aca430d merge: 稳定移动端与素材访问链路 2026-06-15 11:15:29 +08:00
WuYongJie
f802d65490 merge: sync xuxiake mainline before platform material fix
# Conflicts:
#	furniture-3d-system/src/app/assisted-assembly/mobile/AssistedAssemblyMobileView.tsx
#	furniture-3d-system/src/app/mobile/HomeMobileView.tsx
#	furniture-3d-system/src/server/services/asset-center.service.ts
2026-06-15 11:03:11 +08:00
WuYongJie
77a78f4938 fix(platform): 稳定移动端与素材访问链路 2026-06-15 11:02:10 +08:00
WuYongJie
17c915f0a6 merge: promote workbench nav loading fix to main 2026-06-15 10:38:52 +08:00
WuYongJie
4f8d18f454 merge: 修复工作台导航首屏权限加载态 2026-06-15 10:38:12 +08:00
WuYongJie
5fbec8a7c9 fix(layout): 修复工作台导航首屏权限加载态 2026-06-15 10:37:29 +08:00
WuYongJie
12a90477f7 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/xuxiake-promote-asset-center-sku-group-fix-20260615 2026-06-15 08:43:02 +08:00
WuYongJie
a611640927 merge: sync asset center sku group fix with mainline 2026-06-15 08:42:08 +08:00
WuYongJie
c58c7aaa22 fix(asset-center): read retired sku groups from metadata 2026-06-13 23:29:44 +08:00
WuYongJie
55d92d4e75 fix(ui): show immediate workbench nav feedback 2026-06-13 18:34:01 +08:00
WuYongJie
62da3f6993 fix(ui): show immediate workbench nav feedback 2026-06-13 18:33:40 +08:00
WuYongJie
79cc190a0f merge: promote nav smoothness optimization to main 2026-06-13 18:05:18 +08:00
WuYongJie
7ba1e86410 merge: promote nav smoothness optimization 2026-06-13 18:04:36 +08:00
WuYongJie
713b8986c9 fix(ui): smooth intake and quality navigation 2026-06-13 18:04:05 +08:00
WuYongJie
6a4b8775de merge: promote intake filter overflow fix to main 2026-06-13 16:53:23 +08:00
WuYongJie
f3d38be04b merge: promote intake filter overflow fix 2026-06-13 16:53:12 +08:00
WuYongJie
5ea46cdc68 fix(ui): prevent intake mobile filter overflow 2026-06-13 16:53:01 +08:00
WuYongJie
7f69e8271a merge: promote intake overflow fix to main 2026-06-13 16:45:22 +08:00
WuYongJie
6897c38f97 merge: promote intake overflow fix 2026-06-13 16:45:02 +08:00
WuYongJie
e973b1a0a1 fix(ui): constrain intake table overflow on mobile 2026-06-13 16:44:42 +08:00
WuYongJie
a7ad991c59 merge: promote smoothness fixes to main 2026-06-13 16:35:45 +08:00
WuYongJie
984ae53af3 merge: promote smoothness and migration alignment 2026-06-13 16:35:09 +08:00
WuYongJie
df05999c0f fix(ui): stabilize mobile hydration and layout overflow 2026-06-13 16:33:41 +08:00
WuYongJie
b9476733fc fix(db): add asset sku group restore migration 2026-06-13 16:33:36 +08:00
WuYongJie
0b5ae56dd5 merge: promote storage qiniu direct access normalization to main 2026-06-13 10:31:57 +08:00
WuYongJie
3972ca2edd merge: promote storage qiniu direct access normalization 2026-06-13 10:31:09 +08:00
WuYongJie
100e90a3be fix(storage): 统一公开资源直链与持久化地址归一 2026-06-13 10:24:41 +08:00
WuYongJie
e1b78d602e fix: intake 所有工作区表格表头 sticky 固定
- 所有 workspace 表格 thead 添加 sticky top-0 z-10,滚动时表头固定
- 外层容器 overflow-hidden 改为 overflow-auto,配合滚动生效
- 基础信息 SKU 表格合并双层 div 为单层,添加 max-h-[60vh] 高度约束
- BOM 表格同步添加 sticky thead
2026-06-12 18:40:21 +08:00
WuYongJie
e7d2c8626c merge: 解决冲突,保留使用 SharedAssetFamilyDTO 的类型修复 2026-06-12 17:30:49 +08:00
WuYongJie
034817f119 fix(asset-center): 修复移动端 AssetFamilyDTO 类型不兼容导致生产构建失败 2026-06-12 17:25:56 +08:00
WuYongJie
5e5687dcc1 fix: require manual confirmation for factory workflows 2026-06-12 17:16:47 +08:00
WuYongJie
05d90fe57e feat(ai-render): 支持多材质贴图传入外部生图API
- external-image-generate: 新增 additionalReferenceImages 字段支持多文件上传
- assisted-assembly-ai-render: 自动提取 assetSnapshot 中的材质贴图
- 按 materialConfig.id 去重聚合,最多 6 种材质
- 构建材质映射描述追加到 prompt,告诉 AI 每张贴图对应哪个部位
- 支持 FormData 混合模式(文件 + URL)和 curl 降级
2026-06-12 16:37:56 +08:00
WuYongJie
a2e9335fc5 feat: Stitch 移动端视觉重构 — 5 页面全部完成独立移动端视图
新增独立移动端视图文件(遵循用户要求:不堆砌在原臃肿文件中):
- asset-center/mobile/AssetCenterMobileView.tsx (274行) — 系列选择 + Tab + 搜索 + 卡片列表
- assisted-assembly/mobile/AssistedAssemblyMobileView.tsx (148行) — 系列列表 + 工作区提示
- draft-groups/mobile/DraftGroupsMobileView.tsx (173行) — 搜索 + 统计 + 草稿列表

原文件改动最小化(仅 +3 行导入 + 15 行条件分支):
- AssetCenterClient.tsx (7690行) → 添加 useBreakpoint + <AssetCenterMobileView />
- AssistedAssemblyClient.tsx (1580行) → 添加 useBreakpoint + <AssistedAssemblyMobileView />
- DraftGroupsFormalClient.tsx (4943行) → 添加 useBreakpoint + <DraftGroupsMobileView />

全局 Stitch 基础设施(已提交):
- globals.css: stitch-card 圆角修正 2px→12px,新增 20+ 原子类
- AppShell: 移动端背景 #F8F9FA
- MobileTabBar: 精确 Stitch BottomNavBar
- PlatformSplitLayout: 移动端 #F8F9FA 背景
- IntakeWorkspaceShell: 移动端紧凑间距
- StitchMobileLayout: 可复用布局组件

所有改动仅 max-lg 断点生效,桌面端零影响
2026-06-12 16:37:56 +08:00
WuYongJie
f27aa44ec5 refactor: 拆分移动端视图为独立文件,避免臃肿
- HomeClient.workspace.tsx: 925行 → 738行,移动端布局拆为 mobile/HomeMobileView.tsx (445行独立文件)
- IntakeWorkspaceTabBar.tsx: 109行 → 77行,移动端Tab拆为 IntakeWorkspaceTabBarMobile.tsx (56行独立文件)
- 原文件仅保留一行条件引用 <HomeMobileView /> / <IntakeWorkspaceTabBarMobile />
- 桌面端代码零改动
2026-06-12 16:37:56 +08:00
WuYongJie
03d4ee83e1 style: Stitch 移动端像素级复刻
- AppShell 移动端顶栏改为 Stitch TopAppBar(80% glass + 24px blur)
- globals.css 新增 Stitch 原子类库
- MobileTabBar 对齐 Stitch BottomNavBar
- 全部 max-lg 断点,桌面端零影响
2026-06-12 16:37:56 +08:00
WuYongJie
1b992cb89a style: MobileTabBar 对齐 Stitch BottomNavBar + 移动端卡片无边
- MobileTabBar: bg-80% opacity + backdrop-blur-24px + 微阴影
- 移除 TabBar 大圆角激活 pill,改为纯文字+图标
- section 单列模式移动端 rounded-none(全宽无边)
- mainContent 模式左侧栏移动端 rounded-none
2026-06-12 16:37:56 +08:00
WuYongJie
b1deae4c73 refactor: 对齐 Stitch 设计稿视觉规范
- section 改为透明布局容器,背景用 page background
- 侧边栏/主内容/右面板各自独立:rounded-xl + shadow
- 面板间用 gap-3 间距,不再依赖边框分隔
- metrics 芯片移除边框,改用白色卡片 + 微阴影
- 标题使用 Manrope 字体(font-family-display)
- 配色使用 CSS 变量,对齐 Stitch surface 层级
2026-06-12 16:37:56 +08:00
WuYongJie
e333f68cc3 refactor: PlatformSplitLayout 应用 Stitch 设计规范
- 移除 section 的 border/shadow/rounded-[2rem](No-Line Rule)
- 侧边栏和右面板移除 border,改用表面层级色差分离
- 背景改用 surface-container-low 色调
- 移除 metrics 芯片的边框
- IntakeMainLayout 移动端隐藏右面板
2026-06-12 16:37:56 +08:00
WuYongJie
1a8367a9da refactor: split intake detail controllers 2026-06-12 13:21:37 +08:00
WuYongJie
582d2ee8cb fix: allow product factory MOQ sync saves 2026-06-12 12:39:15 +08:00
WuYongJie
307d92b7f5 fix: PlatformSplitLayout 移动端响应式适配
- header/metrics/feedback 区域移动端缩减 padding
- metrics 区域移动端支持横向滚动
- 移除移动端大圆角卡片边框(平铺全宽)
- 侧边栏移动端撑满全宽(有 mainContent 时)
- 右侧面板移动端隐藏(后续可通过抽屉/切换展开)
- 使用 max-lg:! 优先级覆盖父组件的 !important 样式
2026-06-11 22:56:04 +08:00
WuYongJie
311cd74358 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/wuyongjie-storage-unify-qiniu-20260611 2026-06-11 20:43:45 +08:00
WuYongJie
61a2834710 fix(storage): 公开素材直出七牛读取地址 2026-06-11 20:43:23 +08:00
WuYongJie
cb3b38a952 fix(intake): unify spu rule truth source 2026-06-11 17:41:11 +08:00
WuYongJie
3768e5d601 feat(intake): add sku order quantity field 2026-06-11 16:56:26 +08:00
WuYongJie
3724764079 merge: sync origin/codex/xuxiake-mainline 2026-06-11 14:08:21 +08:00
WuYongJie
655a882cf0 fix(storage): unify runtime asset reads to qiniu 2026-06-11 14:04:45 +08:00
WuYongJie
2ff31032c6 fix(intake): keep barcode print as reserved entry 2026-06-11 13:38:15 +08:00
WuYongJie
90ff111283 Merge remote-tracking branch 'origin/main' into codex/xuxiake-intake-primary-domain-sync-20260610
# Conflicts:
#	furniture-3d-system/src/app/intake/AccessoryLibraryPanel.tsx
#	furniture-3d-system/src/app/intake/IntakeClient.test.tsx
#	furniture-3d-system/src/app/intake/IntakeClient.tsx
#	furniture-3d-system/src/app/intake/SpuRuleLibraryWorkspace.test.tsx
#	furniture-3d-system/src/app/intake/SpuRuleLibraryWorkspace.tsx
#	furniture-3d-system/src/app/intake/bom-library/AccessoryLibraryLogic.tsx
#	furniture-3d-system/src/app/intake/bom-library/AccessoryLibraryPanel.tsx
#	furniture-3d-system/src/app/intake/bom-library/BomLibraryDomain.tsx
#	furniture-3d-system/src/app/intake/non-integrated/NonIntegratedDetailClient.tsx
#	furniture-3d-system/src/app/intake/non-integrated/nonIntegratedApi.ts
#	furniture-3d-system/src/app/intake/non-integrated/nonIntegratedAssetServer.ts
#	furniture-3d-system/src/app/intake/product-development/ProductDevelopmentDomain.tsx
#	furniture-3d-system/src/app/intake/product-development/SpuRuleLibraryWorkspace.test.tsx
#	furniture-3d-system/src/app/intake/product-development/SpuRuleLibraryWorkspace.tsx
#	furniture-3d-system/src/app/intake/product-development/spu-rule-library/SpuRuleLibraryWorkspace.test.tsx
#	furniture-3d-system/src/app/intake/product-development/spu-rule-library/SpuRuleLibraryWorkspace.tsx
#	furniture-3d-system/src/app/intake/product-development/spu-rule-library/spuRuleLibraryLogic.test.ts
#	furniture-3d-system/src/app/intake/product-development/spuRuleLibraryLogic.test.ts
#	furniture-3d-system/src/app/intake/product-patent/ProductPatentDomain.tsx
#	furniture-3d-system/src/app/intake/raw-material-library/RawMaterialLibraryDomain.tsx
#	furniture-3d-system/src/app/intake/raw-material-library/RawMaterialLibraryPanel.tsx
#	furniture-3d-system/src/app/intake/reference-estimator/ReferenceEstimatorDomain.tsx
#	furniture-3d-system/src/app/intake/spuRuleLibraryLogic.test.ts
2026-06-11 13:19:58 +08:00
WuYongJie
af27eff911 fix(intake): finalize non-integrated detail split 2026-06-11 12:52:56 +08:00
WuYongJie
5745abf0ae fix(intake): allow merchandisers to download factory files 2026-06-11 12:43:06 +08:00
WuYongJie
d5aba614fe fix(intake): allow deleting sku preview images 2026-06-11 11:56:12 +08:00
WuYongJie
16679896cf refactor(intake): complete primary domain split 2026-06-11 11:46:25 +08:00
WuYongJie
d1ddf2de7a refactor(intake): split non-integrated workspace containers 2026-06-11 11:46:25 +08:00
WuYongJie
1608b8f7ad refactor: split intake workspace structure 2026-06-11 11:46:24 +08:00
WuYongJie
5cc335acde fix(users): allow external intake business role 2026-06-11 09:40:25 +08:00
WuYongJie
bbdb63a9be merge: promote xuxiake mainline storage build closure 2026-06-11 01:43:01 +08:00
WuYongJie
1d4e8cffc2 fix(storage): 打通对象存储边界与生产构建 2026-06-11 01:41:47 +08:00
WuYongJie
71849d4aab merge: promote xuxiake mainline storage unify qiniu 2026-06-11 01:06:14 +08:00
WuYongJie
2f02d72565 feat(storage): 统一对象存储资源到稳定七牛访问口径 2026-06-11 01:03:56 +08:00
WuYongJie
28121b750d Merge remote-tracking branch 'origin/codex/xuxiake-mainline' 2026-06-10 23:11:02 +08:00
WuYongJie
b9698b1fbb fix: use anchor tag + router.push for mobile tab navigation 2026-06-10 23:10:27 +08:00
WuYongJie
f0fef3f906 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' 2026-06-10 22:52:22 +08:00
WuYongJie
9f4e46d06d feat: mobile responsive adaptation for main pages
- Add useMediaQuery hook for breakpoint detection (1024px)
- Add MobileTabBar component for mobile bottom navigation
- Add MobileInspectorDrawer component with 3-position drag
- Update globals.css with responsive variables and touch targets
- Update AppShell/AppTopNav for mobile layout switching
- Update HomeClient, AssetCenter, AssistedAssembly, DraftGroups for responsive layout
- Update Button/Input/Modal/Select with 44px minimum touch targets
2026-06-10 22:33:24 +08:00
WuYongJie
aa2ce7910b refactor(intake): split primary intake domains 2026-06-10 19:35:39 +08:00
WuYongJie
64cd9d67a5 fix(intake): support existing spu sequence creation 2026-06-10 18:42:28 +08:00
WuYongJie
bc945b3328 refactor(intake): extract product patent domain 2026-06-10 18:32:44 +08:00
WuYongJie
b02bb244ec refactor(intake): extract review issue image manager 2026-06-10 18:32:43 +08:00
WuYongJie
df580ae8bd refactor(intake): extract review issue image cell 2026-06-10 18:32:43 +08:00
WuYongJie
bd777856e6 refactor(intake): extract detection workspace 2026-06-10 18:32:43 +08:00
WuYongJie
ac79549aca refactor(intake): extract installation workspace 2026-06-10 18:32:43 +08:00
WuYongJie
4b2e1c435c refactor(intake): extract first quality workspace 2026-06-10 18:32:43 +08:00
WuYongJie
0e923eadff refactor(intake): extract archive preview panel 2026-06-10 18:32:43 +08:00
WuYongJie
d604ee0474 refactor(intake): extract product limit workspace 2026-06-10 18:32:43 +08:00
WuYongJie
1dca970937 refactor(intake): extract product pricing workspace 2026-06-10 18:32:43 +08:00
WuYongJie
3799702d22 refactor(intake): extract quality inspection workspace 2026-06-10 18:32:43 +08:00
WuYongJie
8fc529d2eb refactor(intake): extract planning layout workspace 2026-06-10 18:32:43 +08:00
WuYongJie
9961f8a1b9 refactor(intake): extract finished sample shipment workspace 2026-06-10 18:32:43 +08:00
WuYongJie
921c55c97f refactor(intake): extract sample measurement workspace 2026-06-10 18:32:43 +08:00
WuYongJie
b60a0a45ab refactor(intake): extract patent application workspace 2026-06-10 18:32:42 +08:00
WuYongJie
4994957194 refactor(intake): extract quality standard workspace 2026-06-10 18:32:42 +08:00
WuYongJie
d7278d5fff refactor(intake): extract attachment workspace 2026-06-10 18:32:42 +08:00
WuYongJie
d6b0960272 refactor(intake): extract opening reference workspace 2026-06-10 18:32:42 +08:00
WuYongJie
ffd53ec713 refactor(intake): extract product data workspace 2026-06-10 18:32:42 +08:00
WuYongJie
778d03c903 refactor(intake): extract project review workspace 2026-06-10 18:32:42 +08:00
WuYongJie
a61d1a5dd7 refactor(intake): move basic info field config 2026-06-10 18:32:42 +08:00
WuYongJie
3fa86786e8 refactor(intake): extract progress helpers 2026-06-10 18:32:42 +08:00
WuYongJie
5eba6797ab refactor(intake): move url download helper 2026-06-10 18:32:42 +08:00
WuYongJie
2551018e22 refactor(intake): move blob fetch helper 2026-06-10 18:32:42 +08:00
WuYongJie
46f43eebdf refactor(intake): move download error helper 2026-06-10 18:32:42 +08:00
WuYongJie
ba226085a2 refactor(intake): move workspace zip filename helper 2026-06-10 18:32:41 +08:00
WuYongJie
c4ffbcba0b refactor(intake): move download helpers 2026-06-10 18:32:41 +08:00
WuYongJie
f5a3a6940a refactor(intake): move bom category helpers 2026-06-10 18:32:41 +08:00
WuYongJie
90856bbe3a refactor(intake): move product pricing system entry helper 2026-06-10 18:32:41 +08:00
WuYongJie
d5cafaa699 refactor(intake): move regex escape helper 2026-06-10 18:32:41 +08:00
WuYongJie
4bdb82b7ed refactor(intake): extract workflow confirmation helpers 2026-06-10 18:32:41 +08:00
WuYongJie
9eff0cb944 refactor(intake): extract product patent sync helper 2026-06-10 18:31:59 +08:00
WuYongJie
4589acfed2 refactor(intake): move image upload helpers 2026-06-10 18:31:08 +08:00
WuYongJie
d43feb85d7 refactor(intake): move opening reference form helpers 2026-06-10 18:31:08 +08:00
WuYongJie
9ce35b00a2 refactor(intake): extract product factory helpers 2026-06-10 18:31:08 +08:00
WuYongJie
46a143b4dc refactor(intake): extract bom value helpers 2026-06-10 18:31:07 +08:00
WuYongJie
441c14a97f refactor(intake): extract bom detail key helpers 2026-06-10 18:31:07 +08:00
WuYongJie
52fb2ff638 refactor(intake): extract upload metadata helpers 2026-06-10 18:31:07 +08:00
WuYongJie
4a2731d56e refactor(intake): extract product form value helpers 2026-06-10 18:31:07 +08:00
WuYongJie
2c46f40a38 refactor(intake): extract product workflow row helpers 2026-06-10 18:31:07 +08:00
WuYongJie
993675ef3f refactor(intake): move empty sku item helper 2026-06-10 18:31:07 +08:00
WuYongJie
863e4a470d refactor(intake): move empty style detail state 2026-06-10 18:31:07 +08:00
WuYongJie
cfe38da760 refactor(intake): reuse sku preview node helper 2026-06-10 18:31:07 +08:00
WuYongJie
40e992acf6 refactor(intake): extract sku preview node helpers 2026-06-10 18:31:07 +08:00
WuYongJie
645130a042 refactor(intake): move document workspace initialization 2026-06-10 18:31:07 +08:00
WuYongJie
a30151a24a refactor(intake): extract product factory key helpers 2026-06-10 18:31:07 +08:00
WuYongJie
8f8ea08155 refactor(intake): move sample shipment review helper 2026-06-10 18:31:06 +08:00
WuYongJie
8f9dffa3c6 refactor(intake): move review content helpers 2026-06-10 18:31:06 +08:00
WuYongJie
59689010ed refactor(intake): extract sku import batch helpers 2026-06-10 18:31:06 +08:00
WuYongJie
7b8142e1f6 refactor(intake): extract sku source helpers 2026-06-10 18:31:06 +08:00
WuYongJie
5acf2d3d9e refactor(intake): move sku row clone helper 2026-06-10 18:31:06 +08:00
WuYongJie
4f66a42cec refactor(intake): move detection workspace helpers 2026-06-10 18:31:06 +08:00
WuYongJie
96e7a4db8d refactor(intake): move project review owner helper 2026-06-10 18:31:06 +08:00
WuYongJie
03ac72700b refactor(intake): extract upload storage helper 2026-06-10 18:31:06 +08:00
WuYongJie
14d7ddcd4e refactor(intake): move document revision file helper 2026-06-10 18:31:06 +08:00
WuYongJie
d5834de00e refactor(intake): extract sku brand prefix helper 2026-06-10 18:31:05 +08:00
WuYongJie
ea14712dcc refactor(intake): extract local asset detection helper 2026-06-10 18:31:05 +08:00
WuYongJie
d5b5668154 refactor(intake): extract first quality helpers 2026-06-10 18:31:05 +08:00
WuYongJie
8faa646bb0 refactor(intake): extract sample workflow helpers 2026-06-10 18:31:05 +08:00
WuYongJie
8e8c713675 refactor(intake): extract upload category helper 2026-06-10 18:31:05 +08:00
WuYongJie
c282dd5ff1 refactor(intake): extract preview hole helpers 2026-06-10 18:31:05 +08:00
WuYongJie
46c0cfadca refactor(intake): extract component sku helpers 2026-06-10 18:31:05 +08:00
WuYongJie
b8ea7291a6 refactor(intake): extract series component detail helpers 2026-06-10 18:31:05 +08:00
WuYongJie
cbfad8de93 refactor(intake): extract asset sku content helpers 2026-06-10 18:31:05 +08:00
WuYongJie
9f834babda refactor(intake): move non-integrated sku normalization helpers 2026-06-10 18:31:05 +08:00
WuYongJie
eb24df17c9 refactor(intake): move non-integrated style detail initialization 2026-06-10 18:31:04 +08:00
WuYongJie
8ccf70f6a7 refactor(intake): extract non-integrated style detail state 2026-06-10 18:31:04 +08:00
WuYongJie
7dcee03161 refactor(intake): extract non-integrated basic info config 2026-06-10 18:31:04 +08:00
WuYongJie
a5be04560e refactor(intake): extract non-integrated quality inspection helpers 2026-06-10 18:31:04 +08:00
WuYongJie
76feacb340 refactor(intake): extract non-integrated review sheet helpers 2026-06-10 18:31:04 +08:00
WuYongJie
4124f5bac8 refactor(intake): move packaging workspace helpers 2026-06-10 18:31:04 +08:00
WuYongJie
da1b05fe6c merge: sync origin/codex/xuxiake-mainline before promote 2026-06-10 17:00:43 +08:00
WuYongJie
b5a400b5e9 fix(intake): 完善白底图预览与素材库上传链路 2026-06-10 16:42:46 +08:00
WuYongJie
8db587a4b3 fix(intake): 优先主表同步供应商代码 2026-06-10 16:42:28 +08:00
WuYongJie
6cfd123a70 fix(intake): 嵌入式白底图工作区对齐九视图布局 2026-06-10 13:59:07 +08:00
WuYongJie
3afc247c67 fix(intake): 嵌入式白底图工作区对齐九视图布局 2026-06-10 13:30:19 +08:00
WuYongJie
64b715f416 Improve mobile linked intake detail layout 2026-06-10 13:15:18 +08:00
WuYongJie
49c2fe97df fix(intake): preserve linked detail login redirects 2026-06-10 09:03:02 +08:00
WuYongJie
c413220fd0 Merge codex/xuxiake-mainline into main 2026-06-09 20:09:17 +08:00
WuYongJie
bb28d31c4b Limit production build workers 2026-06-09 20:09:01 +08:00
WuYongJie
be00ce9179 Merge codex/xuxiake-mainline into main 2026-06-09 19:40:25 +08:00
WuYongJie
337f3cfa09 Improve mobile linked intake detail layout 2026-06-09 19:39:37 +08:00
WuYongJie
d45f394e3b feat(intake): 独立归档AI白底图结果 2026-06-09 18:10:01 +08:00
WuYongJie
97dd9b5bfe feat(intake): 独立归档AI白底图结果 2026-06-09 18:09:55 +08:00
WuYongJie
faf11a3c15 feat(intake): 独立归档AI白底图结果 2026-06-09 18:08:17 +08:00
WuYongJie
86c27c772c merge: promote external intake role save fix 2026-06-09 17:50:14 +08:00
WuYongJie
2ad2994f22 fix(users): allow external intake business role 2026-06-09 17:49:39 +08:00
WuYongJie
dac76aabbe fix(intake): 稳定白底图源图预览加载 2026-06-09 17:33:54 +08:00
WuYongJie
a962c8d1c7 fix(intake): 稳定白底图源图预览加载 2026-06-09 17:33:07 +08:00
WuYongJie
27d43c3e11 fix(intake): 稳定白底图源图预览加载 2026-06-09 17:30:49 +08:00
WuYongJie
63926a667f merge: promote product tag and optional register job number 2026-06-09 17:10:53 +08:00
WuYongJie
b829efbaab fix: support product tag push and optional register job number 2026-06-09 17:09:25 +08:00
WuYongJie
6e71151104 merge: promote xuxiake mainline ai white background concurrency 2026-06-09 17:00:48 +08:00
WuYongJie
007dd0a986 fix(intake): 支持白底图按角度并发生成 2026-06-09 16:58:38 +08:00
WuYongJie
169d1a6d8b merge: promote xuxiake mainline external wide ready coverage 2026-06-09 16:09:24 +08:00
WuYongJie
99b56d308f Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/wuyongjie-storage-cdn-direct 2026-06-09 16:06:52 +08:00
WuYongJie
59a1106035 fix(external): 补齐宽表对 ready 数据的覆盖 2026-06-09 16:06:10 +08:00
WuYongJie
7276abf589 feat(intake): add external intake role isolation 2026-06-09 13:02:01 +08:00
WuYongJie
3ba9c451a5 feat(intake): support operations product limit workflow 2026-06-09 12:31:23 +08:00
WuYongJie
78a693621e fix: 修正白底图面板空值收窄构建错误 2026-06-09 11:47:23 +08:00
WuYongJie
b430a2cdcb Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/wuyongjie-storage-cdn-direct 2026-06-09 11:36:22 +08:00
WuYongJie
6c2c90989b feat: 接通非集成质检 AI 白底图上传链路 2026-06-09 11:35:51 +08:00
WuYongJie
cac624007c fix(intake): hide abandon product action 2026-06-09 10:29:23 +08:00
WuYongJie
53742ad094 fix(intake): avoid factory permission block on sku supplier save 2026-06-09 09:55:29 +08:00
WuYongJie
0419679c5d Merge remote-tracking branch 'origin/main' into codex/xuxiake-mainline 2026-06-08 18:17:18 +08:00
WuYongJie
9cd10c4b1e refactor(intake): move upload utility helpers 2026-06-08 18:12:41 +08:00
WuYongJie
d8b85d071a refactor(intake): move installation version helpers 2026-06-08 18:08:35 +08:00
WuYongJie
300130983d refactor(intake): move non-integrated sample shipment constants 2026-06-08 18:02:45 +08:00
WuYongJie
0c43017c45 refactor(intake): move non-integrated product factory options 2026-06-08 17:58:23 +08:00
WuYongJie
fa6c0d20aa merge: promote external readonly barcode catalog 2026-06-08 17:56:46 +08:00
WuYongJie
3d46e8d65a feat: align external readonly catalog on barcode key 2026-06-08 17:54:44 +08:00
WuYongJie
ad0081f692 refactor(intake): extract non-integrated workspace panel config 2026-06-08 17:49:31 +08:00
WuYongJie
3a8de95bf1 refactor(intake): extract non-integrated planning layout config 2026-06-08 17:42:15 +08:00
WuYongJie
7a84f14f8d refactor(intake): move non-integrated sku ui config 2026-06-08 17:32:40 +08:00
WuYongJie
2d29a50e2b refactor(intake): extract non-integrated sku field config 2026-06-08 17:27:04 +08:00
WuYongJie
0c1b6c1dc2 refactor(intake): extract non-integrated bom display config 2026-06-08 17:20:34 +08:00
WuYongJie
5732a1ab39 refactor(intake): extract non-integrated opening reference helpers 2026-06-08 17:14:20 +08:00
WuYongJie
af03f16690 refactor(intake): extract non-integrated document workspace helpers 2026-06-08 17:02:15 +08:00
WuYongJie
f33659a893 refactor(intake): extract non-integrated value helpers 2026-06-08 16:43:20 +08:00
WuYongJie
6cd4ab5a60 refactor(intake): extract non-integrated style file helpers 2026-06-08 16:38:59 +08:00
WuYongJie
c37e80fb02 refactor(intake): extract non-integrated detail helpers 2026-06-08 16:33:46 +08:00
WuYongJie
af2b5640c8 fix(intake): keep sku supplier ime input responsive 2026-06-08 15:53:24 +08:00
WuYongJie
71598ec0f3 refactor(intake): extract non-integrated sku material field 2026-06-08 15:45:11 +08:00
WuYongJie
0443b33705 refactor(intake): extract non-integrated sku barcode field 2026-06-08 15:39:33 +08:00
WuYongJie
c2f8cee9f0 refactor(intake): extract non-integrated bom image field 2026-06-08 15:33:22 +08:00
WuYongJie
ab9cd0fad5 refactor(intake): extract non-integrated sku directory fields 2026-06-08 15:26:39 +08:00
WuYongJie
922dbfa0bf refactor(intake): extract non-integrated document workspace controls 2026-06-08 15:04:11 +08:00
WuYongJie
a8598a1d80 refactor(intake): extract non-integrated assembly thumbnails 2026-06-08 14:54:09 +08:00
WuYongJie
651342e49d refactor(intake): extract non-integrated sku row fields 2026-06-08 14:44:02 +08:00
WuYongJie
1ca244a116 refactor(intake): extract non-integrated brand field 2026-06-08 14:23:48 +08:00
WuYongJie
fdf5d19480 refactor(intake): extract non-integrated upload field 2026-06-08 14:09:56 +08:00
WuYongJie
e52ad139f9 refactor(intake): extract non-integrated preview panels 2026-06-08 13:49:52 +08:00
WuYongJie
ff2d99ae70 refactor(intake): extract non-integrated shared controls 2026-06-08 13:33:56 +08:00
WuYongJie
d7b47c21f5 feat(intake): support sku group modular order workflow 2026-06-08 12:27:48 +08:00
WuYongJie
5adaec1376 fix(intake): keep sku ime input stable 2026-06-08 12:03:31 +08:00
WuYongJie
f3140692ff merge: promote xuxiake mainline storage object-first hotfix 2026-06-08 11:40:01 +08:00
WuYongJie
2239b7b186 merge: promote storage object-first legacy asset hotfix 2026-06-08 11:38:36 +08:00
WuYongJie
7a5dce6988 fix(storage): 非集成历史素材改为对象存储优先 2026-06-08 11:32:25 +08:00
WuYongJie
7835d69c9f fix(intake): allow payload-backed design owner sku image saves 2026-06-08 10:08:13 +08:00
WuYongJie
f5a6005b3e merge: promote xuxiake mainline qiniu cdn direct read rollout 2026-06-06 22:13:36 +08:00
WuYongJie
27ba97800f merge: promote xuxiake mainline qiniu cdn direct read rollout 2026-06-06 22:12:09 +08:00
WuYongJie
768b988843 feat: 切换对象读取到 CDN 直连签名跳转 2026-06-06 21:49:26 +08:00
WuYongJie
e8933ab8ac Merge codex/xuxiake-mainline jushuitan inventory skip fix 2026-06-06 18:08:23 +08:00
WuYongJie
7a3fd5c42f fix: treat non virtual inventory warehouses as skipped 2026-06-06 18:07:03 +08:00
WuYongJie
05f1b0af3a Merge remote-tracking branch 'origin/main' into codex/xuxiake-mainline 2026-06-06 14:21:44 +08:00
WuYongJie
5d31269736 feat: support modular draft SKU product flow 2026-06-06 14:21:35 +08:00
WuYongJie
aeed70f90f Merge codex/xuxiake-mainline formal jushuitan credentials 2026-06-06 10:20:58 +08:00
WuYongJie
a0eb15b980 fix: parse formal jushuitan credentials 2026-06-06 10:20:32 +08:00
WuYongJie
8ca0691e02 Merge codex/xuxiake-mainline jushuitan copy fix 2026-06-06 09:56:00 +08:00
WuYongJie
b75de86db1 fix: remove remaining jushuitan test copy 2026-06-06 09:55:37 +08:00
WuYongJie
d09a201a6a Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into merge-jst-copyfix 2026-06-06 09:47:18 +08:00
WuYongJie
77ac8f06c0 fix: remove jushuitan test environment copy 2026-06-06 09:45:03 +08:00
WuYongJie
840236610c merge: promote modular sku draft workflow 2026-06-06 09:23:10 +08:00
WuYongJie
575d5aa039 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/xuxiake-mainline 2026-06-06 09:18:26 +08:00
WuYongJie
467e4182f2 feat: restore modular sku group draft workflow 2026-06-06 09:18:07 +08:00
WuYongJie
4b8e1d754a Revert "fix(intake): allow assigned purchaser pricing push"
This reverts commit d3093aead7fae7726c3102236fbd40b4df11d8f9.
2026-06-06 09:11:25 +08:00
WuYongJie
d3093aead7 fix(intake): allow assigned purchaser pricing push 2026-06-06 09:09:31 +08:00
WuYongJie
338bfb83e7 fix(intake): remove odmq factory production option 2026-06-05 18:38:04 +08:00
WuYongJie
a5f2fd01dd fix(intake): remove odmq factory production option 2026-06-05 18:35:51 +08:00
WuYongJie
59a52c8b95 merge: promote single sku master data guard 2026-06-05 18:31:56 +08:00
WuYongJie
f3c2b9bbee fix(intake): prevent single sku master data gaps 2026-06-05 18:29:01 +08:00
WuYongJie
369cf8ecf4 fix(intake): add factory shipping method 2026-06-05 18:14:00 +08:00
WuYongJie
1892a5d579 fix(intake): add factory shipping method 2026-06-05 18:09:20 +08:00
WuYongJie
805f8db179 merge: promote xuxiake non-integrated foundation 2026-06-05 18:03:55 +08:00
WuYongJie
b2837c6426 merge: sync non-integrated upload permission foundation 2026-06-05 17:50:57 +08:00
WuYongJie
0765c0596b Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/xuxiake-non-integrated-upload-permission 2026-06-05 17:47:26 +08:00
WuYongJie
f620762a4b fix(master-data): prevent dirty intake sync regressions 2026-06-05 16:25:13 +08:00
WuYongJie
86df630894 fix(master-data): scope shadow env to audit diff steps 2026-06-05 16:03:25 +08:00
WuYongJie
743d480b7c fix(intake): prefer sku images in product limits 2026-06-05 15:49:20 +08:00
WuYongJie
2194824e6c fix(intake): keep imported sku rows editable 2026-06-05 15:33:16 +08:00
WuYongJie
d650e2f562 fix(intake): match sku images by displayed spu 2026-06-05 15:16:29 +08:00
WuYongJie
cfc3e5cc0e fix(intake): 修复非集成图片上传节点权限 2026-06-05 14:59:29 +08:00
WuYongJie
0c2b05ce74 fix(intake): skip unmatched sku image autosave 2026-06-05 14:58:40 +08:00
WuYongJie
704a0b91ac fix(master-data): align merged boundary debt budget 2026-06-05 13:34:44 +08:00
WuYongJie
61da20e9b6 merge: sync data foundation into xuxiake mainline 2026-06-05 13:29:18 +08:00
WuYongJie
4f2414ef5c revert: defer asset sku group workflow for data foundation 2026-06-05 13:29:08 +08:00
WuYongJie
855ab98ce5 fix(master-data): avoid readonly quality false blockers 2026-06-05 12:40:43 +08:00
WuYongJie
54ef4c79f3 chore(master-data): register retired asset sku group migration 2026-06-05 12:35:33 +08:00
WuYongJie
839269ab8e fix(intake): defer autosave during ime input 2026-06-05 12:28:54 +08:00
WuYongJie
d38a373297 chore(master-data): retire legacy asset sku group drift 2026-06-05 12:27:56 +08:00
WuYongJie
fc6241ff46 fix(asset-center): backfill sku groups by goods code 2026-06-05 12:18:39 +08:00
WuYongJie
26e40b0e71 chore(master-data): 收紧资产规格款身份真相 2026-06-05 12:08:29 +08:00
WuYongJie
6cc339cdb5 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/xuxiake-mainline 2026-06-05 12:07:29 +08:00
WuYongJie
cc7f3c4b8e feat(asset-center): support sku group asset workflow 2026-06-05 12:05:57 +08:00
WuYongJie
4737184f59 fix(intake): scope derived downstream saves 2026-06-05 11:59:09 +08:00
WuYongJie
8e0addb76c chore(master-data): 加强资产SKU同步副本巡检 2026-06-05 11:56:04 +08:00
WuYongJie
74cf5b0005 chore(master-data): 补齐聚水潭归档真相源矩阵 2026-06-05 11:44:52 +08:00
WuYongJie
3da51e926b chore(master-data): 增加聚水潭残留软归档脚本 2026-06-05 11:38:41 +08:00
WuYongJie
4974869f6a chore(master-data): 增加聚水潭分类匹配计划导出 2026-06-05 10:34:22 +08:00
WuYongJie
16d7f42506 fix(intake): allow sku details after spu assignment 2026-06-05 10:30:59 +08:00
WuYongJie
4ca58ffaa2 chore(master-data): 导出非集成产品分类审阅清单 2026-06-05 09:16:02 +08:00
WuYongJie
e26f958de0 fix(jst): 补齐存量SKU主数据兜底 2026-06-04 22:37:15 +08:00
WuYongJie
b4f088d70a fix(asset-center): 修复生产缩略图渲染域名来源 2026-06-04 21:32:19 +08:00
WuYongJie
3cd1102cd2 fix(data-foundation): 对齐治理应用迁移历史门禁 2026-06-04 20:20:31 +08:00
WuYongJie
d6ac21db0e fix(data-foundation): 收紧资产同步锁定字段门禁 2026-06-04 18:11:34 +08:00
WuYongJie
7459f2aef1 fix(data-foundation): 纳入资产同步事件积压门禁 2026-06-04 18:00:35 +08:00
WuYongJie
67bdc09e1e fix(data-foundation): 补齐生产只读证据验收门禁 2026-06-04 17:52:12 +08:00
WuYongJie
90bfa4b968 fix(data-foundation): 补齐生产只读地基巡检入口 2026-06-04 17:30:11 +08:00
WuYongJie
92af7ea29a fix(data-foundation): 识别已完成迁移链的 no-op 审计状态 2026-06-04 17:08:14 +08:00
WuYongJie
40e5f238a4 fix(data-foundation): 稳定历史对象源检查 2026-06-04 16:24:56 +08:00
WuYongJie
5bed29f6e9 fix(data-foundation): 纳入历史对象存储迁移门禁 2026-06-04 16:00:56 +08:00
WuYongJie
6f09b28196 fix(data-foundation): 加强历史素材迁移门禁 2026-06-04 15:47:55 +08:00
WuYongJie
7f41d0bca5 fix: preserve component detail spu on stock conflicts 2026-06-04 15:33:10 +08:00
WuYongJie
5de6de67e6 fix(data-foundation): 收口主数据边界 readiness 2026-06-04 15:25:17 +08:00
WuYongJie
e4809ef843 fix: sync configured component detail spu before opening 2026-06-04 15:15:30 +08:00
WuYongJie
d829ea6c05 fix: allow product owners to upload sku assets 2026-06-04 14:55:43 +08:00
WuYongJie
8f6f61858e fix: avoid duplicate default asset series seed 2026-06-04 14:28:53 +08:00
WuYongJie
cbe545f3e3 fix(data-foundation): 区分已恢复的回滚迁移记录 2026-06-04 14:18:50 +08:00
WuYongJie
d9db45ea3a fix: allow editing sku spec names 2026-06-04 14:04:08 +08:00
WuYongJie
6416408031 fix(data-foundation): 区分已恢复的回滚迁移记录 2026-06-04 13:58:46 +08:00
WuYongJie
f5d8f450b3 fix: sync configured series spu coding 2026-06-04 13:40:05 +08:00
WuYongJie
849e74118d fix: compress intake image uploads before submit 2026-06-04 12:17:05 +08:00
WuYongJie
01eb1647bc fix: allow packaging variants without real model 2026-06-04 10:09:33 +08:00
WuYongJie
5cb25981ef fix: prevent opening codes from becoming formal spu 2026-06-04 10:03:48 +08:00
WuYongJie
2ccaab0e72 fix: preserve material storage texture urls 2026-06-04 09:06:49 +08:00
WuYongJie
8d0930a5b2 fix(storage): 跳过未迁历史快照对象检查 2026-06-03 22:10:06 +08:00
WuYongJie
2764ac1e31 fix(storage): 阻止源缺失时执行历史素材迁移 2026-06-03 21:55:05 +08:00
WuYongJie
aeb6919da6 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/xuxiake-mainline 2026-06-03 21:41:00 +08:00
WuYongJie
79106b69da feat(storage): 支持七牛历史素材迁移 2026-06-03 21:40:13 +08:00
WuYongJie
d16a2a201a fix: improve material upload and category deletion 2026-06-03 18:08:20 +08:00
WuYongJie
14db8a7816 feat: prevent duplicate assisted assembly specs 2026-06-03 18:08:09 +08:00
WuYongJie
252c744ddd fix(asset-center): scope hardware families by owning series 2026-06-03 17:13:40 +08:00
WuYongJie
b6c2a8ec62 fix(asset-center): uppercase deleted variant suffix 2026-06-03 16:53:37 +08:00
WuYongJie
b22ff2084c fix(asset-center): normalize variant soft delete marker 2026-06-03 16:36:34 +08:00
WuYongJie
91340f5d5f Merge remote-tracking branch 'origin/main' into codex/xuxiake-mainline 2026-06-03 15:52:33 +08:00
WuYongJie
6a362bcdde feat(data-foundation): sync draft packaging and series cleanup 2026-06-03 15:52:05 +08:00
WuYongJie
67ff6fba96 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/xuxiake-mainline 2026-06-03 14:10:55 +08:00
WuYongJie
12a0f26bb7 merge: sync xuxiake data foundation for prod deploy 2026-06-03 13:16:16 +08:00
WuYongJie
2ca459e027 fix(data-foundation): 结构化核价行并归一化素材引用 2026-06-03 12:10:14 +08:00
WuYongJie
de045f4a56 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/xuxiake-mainline 2026-06-03 11:12:47 +08:00
WuYongJie
e2a6dd1487 test(data-foundation): 收紧客户端缓存边界证据门禁 2026-06-03 10:46:06 +08:00
WuYongJie
b086e02dcd fix(data-foundation): 补齐对象存储外部契约与迁移历史 2026-06-03 10:31:21 +08:00
WuYongJie
4e5939071a merge: sync material foundation into xuxiake mainline 2026-06-03 10:26:08 +08:00
WuYongJie
5f2033ea90 wip: protect local material updates before mainline sync 2026-06-03 10:04:59 +08:00
WuYongJie
02ce03aeaa merge: sync storage model proxy fix for prod deploy 2026-06-03 09:28:53 +08:00
WuYongJie
8fd40e0846 fix(storage): 通过同源代理加载对象存储模型 2026-06-02 22:28:21 +08:00
WuYongJie
e41e93ede8 merge: sync xuxiake normalized migration fix for prod deploy 2026-06-02 22:04:18 +08:00
WuYongJie
73655af744 fix(data-foundation): 对齐非集成 SKU 规范化迁移预检 2026-06-02 22:03:56 +08:00
WuYongJie
b77fcb3351 merge: sync xuxiake data constraint fix for prod deploy 2026-06-02 21:55:22 +08:00
WuYongJie
6fee15d4aa fix(data-foundation): 放行非集成 SKU 冲突质量状态约束 2026-06-02 21:54:11 +08:00
WuYongJie
56252d92f3 merge: sync xuxiake data foundation fix for prod deploy 2026-06-02 21:45:26 +08:00
WuYongJie
420b159f7e fix(data-foundation): 兼容非集成 SKU 历史编码冲突 2026-06-02 21:44:37 +08:00
WuYongJie
1b26801f12 merge: sync xuxiake mainline for prod deploy 2026-06-02 21:13:39 +08:00
WuYongJie
5025f4c5c1 merge: 接入七牛对象存储 2026-06-02 20:57:16 +08:00
WuYongJie
6d17f7684d feat(storage): 接入七牛私有对象存储与稳定读取代理 2026-06-02 18:33:25 +08:00
WuYongJie
1c74c2b630 merge: bring data foundation updates into xuxiake mainline 2026-06-02 16:16:13 +08:00
WuYongJie
545b1165c4 chore(data-foundation): close master data readiness gaps 2026-06-02 16:05:45 +08:00
WuYongJie
ebeb7624d6 chore(data-foundation): clarify structure repair evidence 2026-06-02 14:06:47 +08:00
WuYongJie
64341cab77 chore(data-foundation): require fresh audit checklist evidence 2026-06-02 13:48:03 +08:00
WuYongJie
0031533f97 chore(data-foundation): prevent auth cache permission truth 2026-06-02 13:40:55 +08:00
WuYongJie
f0664e77ca chore(data-foundation): clarify json truth boundaries 2026-06-02 13:27:12 +08:00
WuYongJie
0b22729225 chore(data-foundation): tighten client storage evidence gate 2026-06-02 13:17:30 +08:00
WuYongJie
6bc8e3348e feat(data-foundation): add master data governance scaffolding 2026-06-02 11:50:50 +08:00
WuYongJie
f0d3f5daae chore(data-foundation): sync xuxiake mainline and stabilize master data 2026-06-02 10:57:38 +08:00
WuYongJie
35fed448cf Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/xuxiake-assisted-assembly-ai-render
# Conflicts:
#	furniture-3d-system/src/app/draft-groups/DraftGroupsClient.tsx
2026-06-02 10:34:08 +08:00
WuYongJie
f563bc9989 Add warehouse quality and product data updates 2026-06-01 13:53:47 +08:00
WuYongJie
a09fbc3057 style(asset-center): lint 格式化与类型收口 2026-05-29 20:27:18 +08:00
WuYongJie
fe80bc77ba @
refactor(asset-center): 提取预览右键菜单子菜单为独立组件

- PreviewSubmenus.tsx(252 行):基材选择子菜单 + UV 渲染参数子菜单
- AssetCenterClient.tsx 3268→3085 行
@
2026-05-29 19:02:41 +08:00
WuYongJie
9333ed5f17 Merge remote-tracking branch 'origin/main' into codex/xuxiake-mainline 2026-05-29 18:35:17 +08:00
WuYongJie
3908aa0d80 Refine product data naming and draft group preview 2026-05-29 18:33:54 +08:00
WuYongJie
2e618d334b Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into merge-jst-main 2026-05-29 18:17:35 +08:00
WuYongJie
6e7cb87312 fix: remove intake tab block 2026-05-29 18:16:50 +08:00
WuYongJie
f7164140e1 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into merge-jst-main 2026-05-29 18:10:09 +08:00
WuYongJie
34ea57c707 fix: repair jushuitan pricing row fields 2026-05-29 18:09:25 +08:00
WuYongJie
53d97a08d4 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into merge-jst-main 2026-05-29 17:55:33 +08:00
WuYongJie
3e07813900 feat: add jushuitan push flow 2026-05-29 17:53:49 +08:00
WuYongJie
85d9eb7acc @
refactor(asset-center): 提取资产族列表为独立组件

- FamilyListPanel.tsx(332 行):资产族+规格款列表渲染
- AssetCenterClient.tsx 3506→3268 行
@
2026-05-29 17:23:59 +08:00
WuYongJie
6e743e991b @
refactor(asset-center): 提取 CAD 导入弹窗为独立组件

- CadImportModal.tsx(306 行):CAD 导入弹窗独立组件
- AssetCenterClient.tsx 3733→3506 行
@
2026-05-29 16:49:05 +08:00
WuYongJie
de33fc385c @
refactor(asset-center): 拆分 AssetCenterClient 大文件(4775→3733 行)

提取 7 个独立模块:
- asset-center-types.ts(210 行):类型定义、常量、CSS 类名
- asset-center-utils.ts(615 行):纯工具函数(UV 编辑、键盘快捷键、预览节点变换、状态标签、相似性、CAD 导入、系列筛选)
- VariantEditModal.tsx(235 行):规格款编辑弹窗
- FamilyEditModal.tsx(261 行):资产族编辑弹窗
- ReviewRejectModal.tsx(55 行):驳回弹窗
- RoleEditorModal.tsx(47 行):连接角色编辑弹窗

主组件减少 1042 行,功能完全不变。
@
2026-05-29 16:09:23 +08:00
WuYongJie
a5d728c7b9 @
feat(draft-groups): 草稿组页面优化与预估成本修复

- 保存品类按钮移到品类同一行,加宽按钮
- 删除草稿组加 try/catch 错误处理
- 预估成本:costPrice 为 null 时回退到 estimatedCostPrice
  - OpenProductAssetVariant 类型加 estimatedCostPrice
  - toOpenProductVariants 映射加 estimatedCostPrice
  - buildSlotSnapshot/buildHardwareSnapshot 用 costPrice ?? estimatedCostPrice
  - BOM 聚合用 costPrice ?? estimatedCostPrice
- 颜色统一为白曜石设计令牌(--obs-shell-color/heading-color/muted/surface-bg/border)
- 状态标签颜色改用固定色值,降低饱和度
- 板材/组件/五金件列表每行可点击,弹出只读 Modal 展示完整信息
- 组件详情弹窗增加规格款 ID、资产族 ID、基材 ID、饰面 ID、连接位、3D 模型 URL
@
2026-05-29 15:29:23 +08:00
WuYongJie
e07c12a34f Update accessory library and intake permissions 2026-05-29 13:50:58 +08:00
WuYongJie
9217b8db16 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/xuxiake-assisted-assembly-ai-render 2026-05-29 12:20:58 +08:00
WuYongJie
a6946d3750 feat(assisted-assembly): 标签预览图改为静态资源并优化弹出交互 2026-05-29 12:18:40 +08:00
WuYongJie
f57d6030a3 feat(draft-groups): 重构草稿组工作台与资料补齐 2026-05-29 12:17:27 +08:00
WuYongJie
285bb3c180 feat(admin): 接入AI服务商配置与提示词优化 2026-05-29 12:14:26 +08:00
WuYongJie
83f3cb498c Merge remote-tracking branch 'origin/main' into codex/xuxiake-mainline 2026-05-28 17:57:51 +08:00
WuYongJie
11afc62a0c Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/xuxiake-mainline 2026-05-28 17:57:39 +08:00
WuYongJie
1c65ba4dcc Update intake permissions and workflow states 2026-05-28 17:56:30 +08:00
WuYongJie
1cbabf46fa merge: promote xuxiake mainline to main 2026-05-28 13:53:02 +08:00
WuYongJie
cab450f263 merge: assisted assembly ai render and employee provisioning 2026-05-28 13:48:58 +08:00
WuYongJie
bd02176bdf feat(assisted-assembly): 接入AI生图配置与历史记录 2026-05-28 13:42:31 +08:00
WuYongJie
035cf170b7 fix(auth): 按花名册规则自动划归账号 2026-05-28 13:41:56 +08:00
WuYongJie
5c837ee8e4 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/xuxiake-assisted-assembly-ai-render
# Conflicts:
#	furniture-3d-system/src/lib/business-role-inference.test.ts
2026-05-28 12:03:58 +08:00
WuYongJie
f6eba0418f fix(users): 排除非内部部门自动业务划归 2026-05-28 12:01:49 +08:00
WuYongJie
46c0098ae3 fix(intake): allow planning layout save noops 2026-05-28 11:12:09 +08:00
WuYongJie
6d6e4b299d fix(intake): allow stock planning layout save noops 2026-05-28 11:02:33 +08:00
WuYongJie
d8c08bd625 fix(intake): guard stock product workspace saves 2026-05-28 10:44:10 +08:00
WuYongJie
180680f348 feat(intake): add sku hole snapping preview 2026-05-28 08:54:42 +08:00
WuYongJie
90432bb243 feat(intake): refine accessory library and bom exports 2026-05-27 15:44:52 +08:00
WuYongJie
2a1058ec77 fix(intake): allow space visual department layout saves 2026-05-27 10:54:49 +08:00
WuYongJie
1b0141908e fix(intake): align space visual planning role 2026-05-27 09:27:55 +08:00
WuYongJie
1dbd7f1d63 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/xuxiake-mainline 2026-05-27 08:41:17 +08:00
WuYongJie
51b1341c5c fix: improve non-integrated detail saves 2026-05-27 08:41:10 +08:00
WuYongJie
6558ba763b fix: 完善辅助装配吸附与私有目录接口保护 2026-05-26 18:41:04 +08:00
WuYongJie
396e3dcabb fix(intake): allow space team planning layout edits 2026-05-26 17:19:13 +08:00
WuYongJie
9700d84c66 feat(intake): refine bom libraries and accessory rods 2026-05-26 16:30:37 +08:00
WuYongJie
8ae5540eef fix(intake): tighten non-integrated detail permissions 2026-05-26 13:54:14 +08:00
WuYongJie
d151d9a056 fix(intake): stabilize node permissions and accessory categories 2026-05-26 10:36:39 +08:00
WuYongJie
d544c14c5d fix(intake): improve planning layout autosave and scrolling 2026-05-25 16:58:17 +08:00
WuYongJie
1e8c5970b0 fix: 修复数据落库一致性 2026-05-25 16:29:26 +08:00
WuYongJie
2cc34127e9 fix(intake): allow space visual planning layout edits 2026-05-25 09:58:13 +08:00
WuYongJie
491c2a24ac 加固产品分享链接公开访问 2026-05-24 21:21:16 +08:00
WuYongJie
ca81d44421 保护图片估算接口鉴权边界 2026-05-24 20:49:03 +08:00
WuYongJie
588ed37097 加强非集成上传与分享安全边界 2026-05-24 20:18:14 +08:00
WuYongJie
01caee8b81 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/xuxiake-mainline 2026-05-24 19:39:20 +08:00
WuYongJie
e489d3bba0 fix(security): harden auth and response headers 2026-05-24 19:39:14 +08:00
WuYongJie
4e088de15f revert(intake): remove public install video links 2026-05-23 17:03:15 +08:00
WuYongJie
8311b7a155 fix(intake): allow public install video pages 2026-05-23 16:39:15 +08:00
WuYongJie
23ae5296f1 feat(intake): add public install video links 2026-05-23 16:33:32 +08:00
WuYongJie
5916d80657 fix(intake): open shared product links as full detail 2026-05-23 14:42:48 +08:00
WuYongJie
6c906e57cc style(intake): compact admin sidebar actions 2026-05-23 14:26:46 +08:00
WuYongJie
40c6ab14ea fix(intake): show readonly nodes for designers 2026-05-23 14:21:58 +08:00
WuYongJie
78a036ca2d feat(intake): add node permissions and accessory library controls 2026-05-23 13:19:43 +08:00
WuYongJie
320670fa92 fix(intake): 收敛设计权限与开品链接视图 2026-05-23 11:17:14 +08:00
WuYongJie
df1483cc82 Merge remote-tracking branch 'origin/main' into codex/xuxiake-mainline 2026-05-22 19:51:13 +08:00
WuYongJie
08093bb748 feat(intake): restrict formal product workspace access 2026-05-22 19:50:38 +08:00
WuYongJie
9b5dbbe856 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/xuxiake-mainline 2026-05-22 18:49:52 +08:00
WuYongJie
320f9abbc9 fix(users): 修正多部门员工主部门与密码编辑 2026-05-22 18:49:43 +08:00
WuYongJie
e8e83bc531 fix(intake): align stock-created product detail sku flow 2026-05-22 18:01:37 +08:00
WuYongJie
88fb5e7ba3 fix(intake): lock factory model shared fields 2026-05-22 14:09:16 +08:00
WuYongJie
c05855601d feat(intake): add factory contracts and 3d packaging refinements 2026-05-22 12:53:49 +08:00
WuYongJie
aac475f982 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/xuxiake-mainline 2026-05-21 18:54:51 +08:00
WuYongJie
872f7cbc14 fix: refine intake 3d material and sku confirmation flow 2026-05-21 18:54:40 +08:00
WuYongJie
31562766a7 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/xuxiake-mainline 2026-05-21 16:18:33 +08:00
WuYongJie
ade68c56de fix(asset-center): 由后端生成 CAD 导入规格编码 2026-05-21 16:18:18 +08:00
WuYongJie
4f7c7cdf45 fix(intake): 按节点校验开品保存权限 2026-05-21 13:24:10 +08:00
WuYongJie
603b114345 fix(intake): 调整开品字段口径与样评填写逻辑 2026-05-20 19:09:53 +08:00
WuYongJie
ac785bb495 feat: update intake brand rules and access scopes 2026-05-20 17:14:00 +08:00
WuYongJie
a1209cc7f8 fix(intake): 调整空间布局字段选项 2026-05-20 16:13:04 +08:00
WuYongJie
606dc9612c Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/xuxiake-mainline 2026-05-20 15:20:25 +08:00
WuYongJie
fbbf8d85ef fix(intake): 允许企划编辑空间布局节点 2026-05-20 15:19:42 +08:00
WuYongJie
c5a6f044c7 feat: refine non-integrated intake workflow 2026-05-20 14:17:39 +08:00
WuYongJie
b7c794ac2f Merge remote-tracking branch 'origin/main' into codex/xuxiake-mainline 2026-05-20 12:54:57 +08:00
WuYongJie
314c4d1ba0 feat(intake): 完善正式入库定厂与寄样流程 2026-05-20 12:54:49 +08:00
WuYongJie
55cba13828 fix(users): 全量花名册同步后清理查询缓存 2026-05-20 12:03:17 +08:00
WuYongJie
65fb8fec42 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/xuxiake-mainline 2026-05-20 11:56:29 +08:00
WuYongJie
a6c26a0581 fix(users): 接入家具系统花名册定时同步 2026-05-20 11:56:23 +08:00
WuYongJie
05b34bcec1 fix: refine non-integrated department permissions 2026-05-20 09:27:54 +08:00
WuYongJie
5daa93d3eb merge: 同步 xuxiake 主线用户匹配修复 2026-05-19 20:22:55 +08:00
WuYongJie
12d92a1b4b merge: 收口用户匹配与花名册同步修复 2026-05-19 20:20:54 +08:00
WuYongJie
66491cf49e Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/wuyongjie-assisted-assembly-next 2026-05-19 20:19:05 +08:00
WuYongJie
60fdf33bad fix(users): 修复员工库匹配与生产入口口径 2026-05-19 20:18:13 +08:00
WuYongJie
e2be21d21b fix: load jst directory options for intake 2026-05-19 19:34:35 +08:00
WuYongJie
954948dae1 fix: align intake brand copy workflow 2026-05-19 19:23:03 +08:00
WuYongJie
0a5c6b7a43 fix: treat stock sku batches as confirmed 2026-05-19 19:09:16 +08:00
WuYongJie
d8aadfa0e1 fix: refine non-integrated sku confirmation 2026-05-19 18:30:11 +08:00
WuYongJie
81500dcc07 fix: refine stock detail filters and planning layout 2026-05-19 14:08:04 +08:00
WuYongJie
aa31e4e230 fix: exclude accessory stock sku imports 2026-05-19 13:09:55 +08:00
WuYongJie
e9a6deb3a1 fix: align jst sku sync with stock spus 2026-05-19 12:15:02 +08:00
WuYongJie
273097f8b5 fix: sync stock spu filters and imported sku codes 2026-05-19 12:08:11 +08:00
WuYongJie
668391f983 feat: sync and filter jst sku stock products 2026-05-19 11:33:01 +08:00
WuYongJie
30e1d2f5b5 fix(intake): reset persisted workspace tab cache 2026-05-19 09:11:06 +08:00
WuYongJie
fd79dcae56 fix(intake): defer workspace tab restore until client mount 2026-05-19 08:58:07 +08:00
WuYongJie
92275301af merge: codex xuxiake mainline build storage placeholders 2026-05-18 20:22:26 +08:00
WuYongJie
a18fdd8fbb fix(deploy): 使用构建期存储占位配置 2026-05-18 20:21:05 +08:00
WuYongJie
1a11bb51e3 merge: codex xuxiake mainline storage build fix 2026-05-18 20:15:14 +08:00
WuYongJie
b9be83d84a fix(deploy): 传入构建期公开存储地址 2026-05-18 20:14:33 +08:00
WuYongJie
c0bca713ce merge: codex xuxiake mainline deploy source fix 2026-05-18 20:09:49 +08:00
WuYongJie
dbb3ea8fd7 merge: 同步远端 xuxiake 部署收口 2026-05-18 20:08:35 +08:00
WuYongJie
6bf85d79c6 fix(deploy): 使用官方 Alpine 包源构建镜像 2026-05-18 20:07:33 +08:00
WuYongJie
2b50f74b12 Merge remote-tracking branch 'origin/main' into codex/xuxiake-mainline 2026-05-18 20:01:24 +08:00
WuYongJie
09606adcb9 fix(intake): keep stock products in product development list 2026-05-18 19:59:57 +08:00
WuYongJie
666211714a merge: codex xuxiake mainline puppeteer deploy fix 2026-05-18 19:59:33 +08:00
WuYongJie
aaae569af1 fix(deploy): 跳过 Puppeteer 构建期浏览器下载 2026-05-18 19:58:48 +08:00
WuYongJie
81209f73ce merge: codex xuxiake mainline deploy fix 2026-05-18 19:56:15 +08:00
WuYongJie
48557987e0 fix(deploy): 修复生产镜像构建基线 2026-05-18 19:54:58 +08:00
WuYongJie
1f66aab483 merge: codex xuxiake mainline format fix 2026-05-18 19:42:36 +08:00
WuYongJie
0640dd8dec fix(asset-center): 清理系列接口文件尾空行 2026-05-18 19:41:48 +08:00
WuYongJie
fa633e3ca0 merge: codex xuxiake mainline 2026-05-18 19:38:29 +08:00
WuYongJie
486bf9333e merge: 接入系列编码与资料同步
# Conflicts:
#	furniture-3d-system/src/app/intake/IntakeClient.tsx
#	furniture-3d-system/src/app/intake/non-integrated/NonIntegratedDetailClient.test.tsx
2026-05-18 19:36:54 +08:00
WuYongJie
8eaa82db52 merge: codex xuxiake mainline 2026-05-18 18:58:00 +08:00
WuYongJie
271a7b86ad feat(intake): split stock product entry 2026-05-18 18:57:31 +08:00
WuYongJie
dcab35873c feat(asset-center): 统一系列编码与资料同步 2026-05-18 18:30:13 +08:00
WuYongJie
45bc7eaebf merge: codex xuxiake mainline 2026-05-18 17:40:52 +08:00
WuYongJie
1d668c58a3 fix(intake): improve product list pagination 2026-05-18 17:40:20 +08:00
WuYongJie
db7023e45e Merge remote-tracking branch 'origin/codex/wuyongjie-assisted-assembly-next' into codex/xuxiake-mainline
# Conflicts:
#	furniture-3d-system/src/app/intake/IntakeClient.test.tsx
2026-05-18 17:06:19 +08:00
WuYongJie
c643c09512 feat(intake): refine product list and sku workflow 2026-05-18 15:32:37 +08:00
WuYongJie
2a4dbadbdc merge: 同步 xuxiake 正式入库系列明细 2026-05-18 15:17:44 +08:00
WuYongJie
d661273b23 fix(assisted-assembly): 修复多孔吸附与资产预览 2026-05-18 14:04:29 +08:00
WuYongJie
e5f10d6eda feat(intake): support series component sku details 2026-05-18 12:40:18 +08:00
WuYongJie
331aac6961 feat(assisted-assembly): 接入系列物料区与统一孔位高亮 2026-05-16 11:05:15 +08:00
WuYongJie
b603555df7 feat: 重构资产中心系列优先入口 2026-05-15 14:39:45 +08:00
WuYongJie
1f2d2af257 feat(users): 收口账号权限与登录注册视觉 2026-05-15 10:41:38 +08:00
WuYongJie
38a182bc8d merge: 同步 xuxiake 主线 2026-05-14 18:49:23 +08:00
WuYongJie
d6ddac46c2 feat(auth): 设计师角色迁移为设计业务类型 2026-05-14 18:26:06 +08:00
WuYongJie
016acd0c30 feat(intake): add spu rule library and stock product flow 2026-05-14 17:20:16 +08:00
WuYongJie
a59c1bf82f feat: refine intake DingTalk node permissions 2026-05-14 12:04:24 +08:00
WuYongJie
3cd41b4921 fix: 优化资产中心与管理页白曜石视觉 2026-05-14 11:39:06 +08:00
WuYongJie
f1f5c2ff80 feat: 完善资产中心规格款保存与回收站流程 2026-05-14 10:25:07 +08:00
WuYongJie
2e954f3219 feat: 接入资产中心回收站与规格款渲染配置 2026-05-13 21:54:01 +08:00
WuYongJie
286347582c Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/wuyongjie-assisted-assembly-next 2026-05-13 21:49:51 +08:00
WuYongJie
0f7e647127 feat: 优化正式入库人员字段与首批质检 2026-05-13 19:10:48 +08:00
WuYongJie
7f3fe36da9 fix: 优化材质金属度渲染表现 2026-05-13 16:35:43 +08:00
WuYongJie
8d76d4ef9d fix: 优化材质贴图上传与预览兜底 2026-05-13 15:08:18 +08:00
WuYongJie
ed291bc8c9 merge: 同步 xuxiake 主线 2026-05-13 10:06:30 +08:00
WuYongJie
c3f3b8e218 fix: polish planning layout selectors 2026-05-13 09:50:17 +08:00
WuYongJie
62bceabc66 feat: refine planning layout fields 2026-05-13 09:17:32 +08:00
WuYongJie
4e0af7c27a fix: 修复资产贴图预览并收敛白曜石视觉 2026-05-12 20:13:49 +08:00
WuYongJie
0ed04b81bf Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/wuyongjie-assisted-assembly-next 2026-05-12 17:36:57 +08:00
WuYongJie
371b5985d7 修复资产中心CAD导入与孔位预览 2026-05-12 17:36:28 +08:00
WuYongJie
c1604fde1e fix(intake): open material config in workspace tab 2026-05-12 17:05:17 +08:00
WuYongJie
d4fbe1ca0d fix(intake): choose brand before creating product 2026-05-12 15:08:41 +08:00
WuYongJie
ca908eb970 fix(intake): lock product detail brand field 2026-05-12 14:04:25 +08:00
WuYongJie
1410d5e2f1 fix: remove stale product workflow relation 2026-05-12 11:25:27 +08:00
WuYongJie
05abd68518 fix: polish intake detail interactions 2026-05-12 11:18:25 +08:00
WuYongJie
b1f2bf7b06 调整工作台工具条与品牌区视觉 2026-05-12 10:05:52 +08:00
WuYongJie
81d53ee4db Merge remote-tracking branch 'origin/codex/wuyongjie-assisted-assembly-next' into codex/xuxiake-mainline 2026-05-12 09:34:21 +08:00
WuYongJie
116c2b3705 收敛CAD导入弹窗白曜石视觉 2026-05-12 09:23:05 +08:00
WuYongJie
21f1cd5a1b 优化资产中心CAD导入与白曜石弹窗视觉 2026-05-11 21:53:31 +08:00
WuYongJie
2c06163575 fix(cad): make FEXPORT default to single asset export 2026-05-11 20:23:00 +08:00
WuYongJie
db6d345249 fix(intake): keep bom sku overrides isolated 2026-05-11 20:09:03 +08:00
WuYongJie
cf4b370f4a feat: add planning layout and product limit fields 2026-05-11 19:42:43 +08:00
WuYongJie
4415ef8b33 feat(intake): add upload progress and zip batch download 2026-05-11 18:22:02 +08:00
WuYongJie
e2766b2cfb chore(ui): simplify product development brand name 2026-05-11 17:42:12 +08:00
WuYongJie
b46f041e3e chore(cad): bump exporter data version to 2.6 2026-05-11 17:40:21 +08:00
WuYongJie
256f15369a fix(assembly): stabilize snap bounds and hole hover highlight 2026-05-11 17:39:17 +08:00
WuYongJie
e86c1417d2 fix(intake): allow creators to edit product details 2026-05-11 17:36:24 +08:00
WuYongJie
36873ba3cb feat(intake): update non-integrated detail workflow 2026-05-11 16:25:37 +08:00
WuYongJie
ea2fdea847 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/wuyongjie-assisted-assembly-next
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-11 11:58:15 +08:00
WuYongJie
55233acb3d fix(intake): align linked entry permissions 2026-05-11 11:21:50 +08:00
WuYongJie
5ac5c6f7b1 fix(intake): keep copied product workspace tabs 2026-05-11 09:05:26 +08:00
WuYongJie
2ae4817412 feat(intake): link bom material libraries 2026-05-09 18:07:15 +08:00
WuYongJie
2b204c6a98 feat(intake): add edge banding library 2026-05-09 15:46:10 +08:00
WuYongJie
94f7c0a302 fix(intake): streamline workflow node headers 2026-05-09 13:57:13 +08:00
WuYongJie
6a8e2da6d7 feat(intake): refine non-integrated workflows 2026-05-09 12:53:26 +08:00
WuYongJie
19d5d426e6 feat: 完善SKU批次资料导入 2026-05-09 09:51:52 +08:00
WuYongJie
0e9db44bc4 feat(intake): add sku batch workflow 2026-05-08 18:28:04 +08:00
WuYongJie
2f02681a69 fix(intake): preserve bom details across barcode updates 2026-05-08 13:13:39 +08:00
WuYongJie
368b4427f0 fix(intake): isolate node confirmation updates 2026-05-08 11:17:01 +08:00
WuYongJie
8761242931 fix: repair non-integrated create workspace flow 2026-05-08 11:15:44 +08:00
WuYongJie
b2ec7d356b fix(intake): chunk product uploads before proxy limit 2026-05-08 09:04:23 +08:00
WuYongJie
41164f022c fix(intake): close new product workspace on cancel 2026-05-07 19:05:37 +08:00
WuYongJie
41fb1b0aac fix(intake): support large non-integrated uploads 2026-05-07 18:45:41 +08:00
WuYongJie
6dd75c502a fix(intake): avoid empty chunk upload 502 2026-05-07 17:19:15 +08:00
WuYongJie
11e67ff4ed fix(intake): stabilize chunked upload response 2026-05-07 16:58:30 +08:00
WuYongJie
ea67e56480 fix(intake): bypass production upload body limit 2026-05-07 16:22:14 +08:00
WuYongJie
cddbae3ab6 Merge branch 'codex/xuxiake-mainline' into main 2026-05-07 14:49:55 +08:00
WuYongJie
2cdb29c650 fix(intake): support range requests for uploaded assets 2026-05-07 14:47:18 +08:00
WuYongJie
6a2a926fbf Merge branch 'codex/xuxiake-mainline' into codex/merge-main-20260507 2026-05-07 14:31:27 +08:00
WuYongJie
8baa41dd0b Refine non-integrated edit permissions 2026-05-07 14:12:31 +08:00
WuYongJie
fa27245c66 Raise non-integrated upload limit 2026-05-07 14:07:21 +08:00
WuYongJie
028faaf0af feat: update intake non-integrated workflow 2026-05-07 12:10:03 +08:00
WuYongJie
171b61aec1 Adjust intake list and sidebar display 2026-05-07 08:43:56 +08:00
WuYongJie
4ab12803f5 Update non-integrated intake workflow 2026-05-06 17:47:54 +08:00
WuYongJie
ac7c5a81d8 fix: wrap app shell search params in suspense 2026-05-06 12:35:33 +08:00
WuYongJie
e4ef58a06a feat: refine non-integrated workflow nodes 2026-05-06 12:09:19 +08:00
WuYongJie
3fcd0d2c4d feat(intake): streamline opening detail workflow 2026-05-05 19:00:39 +08:00
WuYongJie
2b0dc5fd23 feat(intake): sync patent application ledger 2026-05-05 15:59:53 +08:00
WuYongJie
f8a0952042 feat(intake): move approval workflow entry to demand draft 2026-04-30 16:45:30 +08:00
WuYongJie
1e9fec0bda fix(users): refresh inspector after account edit 2026-04-30 13:59:09 +08:00
WuYongJie
72d1408027 feat: add approval workflow workspace and account templates 2026-04-30 13:45:25 +08:00
WuYongJie
f90bc1b1fa feat: add approval workflow workspace and account templates 2026-04-30 12:57:12 +08:00
WuYongJie
1182549bba feat: add product patent ledger workflow 2026-04-30 11:51:37 +08:00
WuYongJie
d2ae88ce23 Merge remote-tracking branch 'origin/codex/wuyongjie-assisted-assembly-next' into codex/xuxiake-mainline 2026-04-30 10:45:35 +08:00
WuYongJie
b3ad3c1195 feat(intake): refine workflow and reference estimation 2026-04-30 10:45:21 +08:00
WuYongJie
edfe43d15f Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/wuyongjie-assisted-assembly-next 2026-04-30 10:31:26 +08:00
WuYongJie
f5f9ca6ba7 feat(users): support department assignment and employee matching 2026-04-30 10:31:18 +08:00
WuYongJie
20516b2a87 Merge remote-tracking branch 'origin/codex/wuyongjie-assisted-assembly-next' into codex/xuxiake-mainline 2026-04-29 14:06:29 +08:00
WuYongJie
d63c937fac feat(intake): 优化产品开发进度看板和开品资料展示 2026-04-29 10:59:15 +08:00
WuYongJie
a4daa71bfa fix: align users workspace with white obsidian 2026-04-29 09:12:39 +08:00
WuYongJie
e580b9625e Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/wuyongjie-assisted-assembly-next 2026-04-29 09:09:06 +08:00
WuYongJie
ab3d2d77d2 feat: align admin workspaces with white obsidian 2026-04-28 18:47:54 +08:00
3ff8ea12d9 Merge codex/xuxiake-mainline into main
Merge latest intake workflow updates.
2026-04-28 18:39:53 +08:00
WuYongJie
9a73dcb17e feat: refine intake product workflow 2026-04-28 18:34:16 +08:00
ee8f218712 Merge codex/xuxiake-mainline into main
Merge codex/xuxiake-mainline into main
2026-04-28 15:01:24 +08:00
WuYongJie
1740036d24 feat: add non-integrated project review flow 2026-04-28 14:48:55 +08:00
WuYongJie
43775c8e44 Merge remote-tracking branch 'origin/codex/wuyongjie-assisted-assembly-next' into codex/xuxiake-mainline 2026-04-28 14:14:10 +08:00
WuYongJie
baca2fde9d feat(assembly): add snap basis workflow 2026-04-28 13:48:32 +08:00
ddc863fbc8 Merge pull request 'feat: polish intake detail navigation' (#13) from codex/xuxiake-mainline into main 2026-04-28 10:51:04 +08:00
WuYongJie
04838e3f74 feat: polish intake detail navigation 2026-04-28 10:09:44 +08:00
WuYongJie
f85d4b9c5b merge: integrate material library layout updates 2026-04-27 21:04:36 +08:00
WuYongJie
9681a54754 merge: integrate assisted assembly material layout updates 2026-04-27 21:01:23 +08:00
WuYongJie
90ef2f9c72 style: refine material library layout 2026-04-27 20:55:15 +08:00
WuYongJie
278fad104e merge: integrate xuxiake intake workspace updates 2026-04-27 18:44:01 +08:00
WuYongJie
1cbf87dc84 feat(intake): refine non-integrated document workspaces 2026-04-27 18:36:57 +08:00
WuYongJie
45bf25a6b3 feat(ui): refine material library obsidian workbench 2026-04-27 18:24:24 +08:00
WuYongJie
8cf7cf19d8 merge: integrate asset center next updates 2026-04-27 13:24:04 +08:00
WuYongJie
0b2b458c17 feat(ui): refine obsidian workbench flows 2026-04-27 12:22:34 +08:00
WuYongJie
90546679f2 feat(ui): restore obsidian modal and empty workbench 2026-04-25 20:02:45 +08:00
WuYongJie
696faded1d feat(asset-center): make empty workbench full-bleed 2026-04-25 19:25:29 +08:00
25b4a20e92 merge: sync confirmed intake workflow updates
Merge codex/xuxiake-mainline into main.
2026-04-25 19:17:20 +08:00
WuYongJie
c23128147b Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/wuyongjie-asset-center-next 2026-04-25 19:08:05 +08:00
WuYongJie
22c983ab16 feat(asset-center): add light animated empty workbench model 2026-04-25 19:07:21 +08:00
WuYongJie
460c4f9eae feat(intake): sync confirmed workflow updates 2026-04-25 19:06:27 +08:00
WuYongJie
0e857c6814 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/xuxiake-mainline 2026-04-25 19:04:11 +08:00
WuYongJie
093d8a215c fix(asset-center): hide gizmo until node selection 2026-04-25 18:51:38 +08:00
WuYongJie
925dfc8ad5 Merge remote-tracking branch 'origin/codex/xuxiake-mainline' into codex/xuxiake-mainline 2026-04-25 18:45:53 +08:00
WuYongJie
4d80f3a7d6 chore(docs): rename obsidian visual standard 2026-04-25 18:39:57 +08:00
WuYongJie
96732d46d1 feat(asset-center): refine obsidian 3d workbench 2026-04-25 18:37:05 +08:00
WuYongJie
a9aa01495a feat(asset-center): transplant obsidian workbench UI onto xuxiake baseline 2026-04-25 16:03:45 +08:00
590891deaa merge: sync confirmed intake material workflows
Merge codex/xuxiake-mainline into main.\n\nIncludes confirmed 3100 updates through d8acbf6.
2026-04-25 11:52:03 +08:00
WuYongJie
d8acbf60a0 fix(intake): hide edit sticky actions 2026-04-25 11:40:20 +08:00
WuYongJie
5ba2ea231a feat(platform): sync confirmed intake material workflows 2026-04-25 10:51:11 +08:00
322e6eedd4 Merge pull request 'merge: sync 3100 substrate library defaults' (#10) from codex/xuxiake-mainline into main 2026-04-24 10:42:10 +08:00
WuYongJie
5a22d2a2ae feat(asset-center): sync 3100 substrate library defaults 2026-04-24 10:25:40 +08:00
75bed8ad77 Merge pull request 'merge: restore substrate library workflow' (#9) from codex/xuxiake-mainline into main 2026-04-24 09:04:00 +08:00
WuYongJie
e45d46398e feat(asset-center): restore substrate library workflow 2026-04-23 19:03:27 +08:00
f287c16bf3 merge: refine intake previews and product photos
Merge codex/xuxiake-mainline into main.\n\nValidated: npm run type-check; NonIntegratedDetailClient jest suite.
2026-04-23 15:04:13 +08:00
WuYongJie
8ded8bc5e1 Merge remote-tracking branch 'origin/main' into codex/xuxiake-mainline 2026-04-23 14:59:47 +08:00
WuYongJie
e263b24f5a fix(intake): refine product photo uploads and document previews 2026-04-23 13:30:40 +08:00
a519345079 Merge pull request 'merge: intake runtime asset serving and sku directories' (#7) from codex/xuxiake-mainline into main 2026-04-22 19:27:05 +08:00
WuYongJie
cf82b30096 fix(intake): add sku directories and runtime asset serving 2026-04-22 19:24:12 +08:00
WuYongJie
8fc6d56183 fix(deploy): link shared intake assets after build 2026-04-22 17:10:53 +08:00
WuYongJie
dd1c96dddc fix(deploy): preserve shared intake assets in fallback release 2026-04-22 17:06:23 +08:00
WuYongJie
b83c81d679 Merge remote-tracking branch 'origin/main' into codex/xuxiake-mainline 2026-04-22 16:43:01 +08:00
WuYongJie
70b4d3b2fb fix(intake): route shared uploads through product endpoints 2026-04-22 16:42:47 +08:00
f2573f154b merge: restore intake shared uploads and 3d actions
3100 ?????,???????????? 3D ???????
2026-04-22 15:01:53 +08:00
WuYongJie
9b70901324 fix(intake): restore shared uploads and 3d actions 2026-04-22 14:55:44 +08:00
1ef71a21aa Merge pull request 'merge: fix prod deploy script line endings' (#5) from codex/wuyongjie-main-release into main 2026-04-22 12:30:43 +08:00
WuYongJie
86c5007c03 fix(deploy): write unix newlines for remote scripts 2026-04-22 12:30:19 +08:00
af961287d1 Merge pull request 'merge: restore intake shared persistence and package corner saves' (#4) from codex/xuxiake-mainline into main 2026-04-22 12:25:16 +08:00
WuYongJie
2d1d32bc29 Merge remote-tracking branch 'origin/main' into codex/xuxiake-mainline 2026-04-22 12:23:40 +08:00
WuYongJie
c620050809 fix(intake): restore shared persistence and package corner saves 2026-04-22 12:23:21 +08:00
140da11f82 merge: deploy script fix into main before prod deploy
Merge deploy script parser fix into main before production release.
2026-04-22 09:58:01 +08:00
WuYongJie
6ad7786af5 fix(deploy): restore mainline prod deploy script 2026-04-22 09:57:30 +08:00
1ad68f23bf merge: xuxiake mainline into main for prod deploy
?? codex/xuxiake-mainline ? main,??????
2026-04-22 09:52:20 +08:00
WuYongJie
f44fb28934 fix(intake): refine bom packaging subgroup inference 2026-04-22 09:52:02 +08:00
Codex
bf9c0127a0 fix(intake): normalize bom package subcategory locally 2026-04-22 09:39:56 +08:00
Codex
cba797dc10 fix: stabilize intake mainline merge baseline 2026-04-21 21:09:09 +08:00
Codex
8b3c6570e3 fix: align intake compatibility after main sync 2026-04-21 20:29:40 +08:00
Codex
d7263fecd5 chore(intake): checkpoint mainline merge-prep state 2026-04-21 20:22:35 +08:00
Codex
ac8bcdfd63 Merge remote-tracking branch 'origin/main' into codex/xuxiake-non-integrated-clean-20260416
# Conflicts:
#	furniture-3d-system/next.config.js
#	furniture-3d-system/src/app/HomeClient.workspace.tsx
#	furniture-3d-system/src/app/__tests__/assisted-assembly-page.test.tsx
#	furniture-3d-system/src/app/admin/page.tsx
#	furniture-3d-system/src/app/api/categories/route.test.ts
#	furniture-3d-system/src/app/api/intake/non-integrated/presentation-preview/route.ts
#	furniture-3d-system/src/app/api/intake/non-integrated/upload/route.ts
#	furniture-3d-system/src/app/api/users/[id]/handover/route.test.ts
#	furniture-3d-system/src/app/api/users/[id]/route.test.ts
#	furniture-3d-system/src/app/api/users/organization-tree/route.ts
#	furniture-3d-system/src/app/asset-center/material-library/MaterialLibraryClient.tsx
#	furniture-3d-system/src/app/assisted-assembly/page.tsx
#	furniture-3d-system/src/app/intake/IntakeClient.test.tsx
#	furniture-3d-system/src/app/intake/IntakeClient.tsx
#	furniture-3d-system/src/app/intake/non-integrated/NonIntegratedDetailClient.test.tsx
#	furniture-3d-system/src/app/intake/non-integrated/NonIntegratedDetailClient.tsx
#	furniture-3d-system/src/app/intake/non-integrated/[id]/page.tsx
#	furniture-3d-system/src/app/intake/non-integrated/nonIntegratedStorage.test.ts
#	furniture-3d-system/src/app/intake/non-integrated/nonIntegratedStorage.ts
#	furniture-3d-system/src/app/intake/page.tsx
#	furniture-3d-system/src/app/products/[id]/skus/[skuId]/assembly/page.tsx
#	furniture-3d-system/src/app/users/page.tsx
#	furniture-3d-system/src/app/warehouse/WarehouseClient.tsx
#	furniture-3d-system/src/components/layout/SidebarUserCenter.tsx
#	furniture-3d-system/src/components/layout/__tests__/AppSideNav.test.tsx
#	furniture-3d-system/src/components/platform/AssemblyWorkbenchV2.tsx
#	furniture-3d-system/src/components/platform/ViewportStageShell.tsx
#	furniture-3d-system/src/components/platform/__tests__/AssemblyWorkbenchV2.test.tsx
#	furniture-3d-system/src/components/users/CreateUserModal.tsx
#	furniture-3d-system/src/components/users/DepartmentAccessTree.tsx
#	furniture-3d-system/src/components/users/EditUserModal.tsx
#	furniture-3d-system/src/components/users/UserListItem.tsx
#	furniture-3d-system/src/components/users/__tests__/DepartmentAccessTree.test.tsx
#	furniture-3d-system/src/lib/3d/engine.ts
#	furniture-3d-system/src/lib/model-preview-zip.test.ts
#	furniture-3d-system/src/lib/model-preview-zip.ts
#	furniture-3d-system/src/lib/non-integrated-sku-export.ts
#	furniture-3d-system/src/lib/open-product/__tests__/assembly-workspace.test.ts
#	furniture-3d-system/src/lib/open-product/assembly-workspace.ts
#	furniture-3d-system/src/server/repositories/auth.repository.ts
#	furniture-3d-system/src/server/services/__tests__/material.service.test.ts
#	furniture-3d-system/src/server/services/__tests__/user-handover.service.test.ts
#	furniture-3d-system/src/server/services/__tests__/user-management.organization-tree.test.ts
#	furniture-3d-system/src/server/services/__tests__/user-management.service.test.ts
#	furniture-3d-system/src/server/services/dingtalk-auth.service.ts
#	furniture-3d-system/src/server/services/user-handover.service.ts
#	furniture-3d-system/src/server/services/user-management.service.ts
#	furniture-3d-system/src/server/services/user.service.ts
2026-04-21 20:08:40 +08:00
WuYongJie
d4bc44579e feat: align intake workflow and git-based prod deploy 2026-04-21 19:33:46 +08:00
WuYongJie
3c1675c78e feat: merge intake workflow and current workspace source updates 2026-04-21 17:06:48 +08:00
Codex
06587e828d feat: refine formal intake product workflow 2026-04-21 14:45:57 +08:00
WuYongJie
a4ef213950 feat: tighten user activation and role assignment limits 2026-04-17 16:05:19 +08:00
WuYongJie
013b5dd3f4 fix: tighten identity center layout and asset auth 2026-04-17 15:08:50 +08:00
WuYongJie
7ab4fc6ff4 feat: add reusable mobile camera scan and upload support 2026-04-17 13:35:58 +08:00
WuYongJie
91584f21c6 feat: consolidate workspace release updates 2026-04-17 12:50:06 +08:00
WuYongJie
87bb0e126d feat: refresh branding and material library workspace 2026-04-17 11:07:18 +08:00
WuYongJie
d7737909bb feat: sync remaining workspace branding updates 2026-04-17 10:25:31 +08:00
WuYongJie
c8d3d3d9e7 feat: restore material library and assembly workflows 2026-04-16 23:13:16 +08:00
WuYongJie
602e2fd33f fix: recover assembly context and clear typecheck baseline 2026-04-16 21:44:04 +08:00
WuYongJie
18d2a49d2e feat: converge assembly entrypoints and handover roles 2026-04-16 21:08:41 +08:00
WuYongJie
56a29b8be2 feat: polish home assembly and material workflows 2026-04-16 18:42:37 +08:00
Codex
bb0ebc2981 feat: add integrated intake detail starter 2026-04-16 17:30:44 +08:00
Codex
c7baacb2db feat: show integrated series rows in intake 2026-04-16 17:26:21 +08:00
Codex
0362931e95 test: add integrated draft group adapter 2026-04-16 17:01:47 +08:00
WuYongJie
44677da317 feat: improve non-integrated intake workflow 2026-04-16 16:45:34 +08:00
Codex
7dc99e3725 docs: add integrated intake design spec 2026-04-16 16:32:32 +08:00
WuYongJie
2a4382dcb2 feat: refresh admin and user management portals 2026-04-16 14:07:13 +08:00
Codex
5c752ae2cf chore: sync main outside intake and warehouse 2026-04-16 13:55:17 +08:00
e1645a164a Merge pull request 'feat: integrate selected xuxiake intake enhancements into mainline' (#1) from codex/wuyongjie-mainline into main
Reviewed-on: http://git.1080p.hk/WuYongJie/furniture-3d-system-Wu/pulls/1
2026-04-16 13:05:41 +08:00
WuYongJie
5731018bed feat: integrate selected xuxiake intake enhancements 2026-04-16 12:38:52 +08:00
Codex
3c8c775c30 feat: update non-integrated intake workflow 2026-04-16 11:18:24 +08:00
WuYongJie
2adb1d8e98 feat: persist home workspace tab state 2026-04-15 21:45:18 +08:00
WuYongJie
69b1daf157 fix: close assisted assembly cad snap and prod deploy 2026-04-15 21:27:09 +08:00
Codex
8ad93a2917 feat: finish non-integrated intake flow 2026-04-15 20:22:09 +08:00
WuYongJie
3158e87908 fix: tighten handover scope checks 2026-04-15 17:52:38 +08:00
WuYongJie
9f2ce7ee87 chore: add warehouse location binding migration 2026-04-15 16:55:01 +08:00
WuYongJie
d6ef2f3bf2 fix: stabilize xuxiake intake merge integration 2026-04-15 16:49:47 +08:00
Codex
ab0ed57312 feat: update intake and warehouse workspace 2026-04-15 16:40:10 +08:00
Codex
f1a9e853e0 feat: sync intake and warehouse workflow updates 2026-04-15 16:40:10 +08:00
Codex
e1407c8464 chore: checkpoint latest intake and warehouse changes 2026-04-15 16:40:10 +08:00
Codex
bcbe884be1 feat(warehouse): 配件SKU和成品SKU模块接入真实数据
- page.tsx: 并行获取资产族变体(配件)和草稿组(成品)数据
- 配件SKU库位: 按资产类型(板材/组件/五金/包装)分组展示,支持筛选和搜索
- 成品SKU库位: 展示草稿组及其PreSku,支持搜索,显示状态标签
- 右侧AccordionSection展示真实统计数据
- 测试文件适配新props接口
2026-04-15 16:40:10 +08:00
Codex
ce85aa8def chore: checkpoint intake and warehouse workspace state 2026-04-15 16:40:10 +08:00
Codex
995030a11d chore(intake): checkpoint right workbench toggle layout 2026-04-15 16:40:10 +08:00
WuYongJie
15d5e6fb89 feat: sync validated admin auth material and exporter updates 2026-04-15 16:36:00 +08:00
Codex
ee0fdfb5f9 feat: update intake and warehouse workspace 2026-04-15 15:55:27 +08:00
WuYongJie
7ae45d4f0b fix: add pending activation auth error code 2026-04-15 15:25:17 +08:00
WuYongJie
5a54bcedae fix: allow nullable thumbnails in context menus 2026-04-15 15:24:25 +08:00
WuYongJie
305a99d291 fix: normalize nullable material thumbnails in service layer 2026-04-15 15:23:01 +08:00
WuYongJie
7d73276995 fix: allow pending users in auth core types 2026-04-15 15:22:05 +08:00
WuYongJie
18e1403c2a fix: align admin material editor thumbnail typing 2026-04-15 15:21:01 +08:00
WuYongJie
1c72957333 fix: align material thumbnail types with nullable schema 2026-04-15 15:20:04 +08:00
WuYongJie
1e5237945b chore: align prisma schema with production user data 2026-04-15 15:18:19 +08:00
WuYongJie
66c4113bc9 fix: remove access management dependency on employee directory relation 2026-04-15 15:15:20 +08:00
WuYongJie
45c20500ae fix: import handover modal class utility 2026-04-15 15:14:10 +08:00
WuYongJie
238bd74c49 fix: support modal class overrides in access flows 2026-04-15 15:13:20 +08:00
WuYongJie
6d07abf9d4 fix: align access management modal user types 2026-04-15 15:12:13 +08:00
WuYongJie
96662689f3 feat: complete access management organization tree 2026-04-15 15:09:32 +08:00
Codex
6d9fd415a6 feat: sync intake and warehouse workflow updates 2026-04-15 09:44:11 +08:00
Codex
4de7ea9bfb chore: checkpoint latest intake and warehouse changes 2026-04-14 14:57:19 +08:00
Codex
4c298983ff feat(warehouse): 配件SKU和成品SKU模块接入真实数据
- page.tsx: 并行获取资产族变体(配件)和草稿组(成品)数据
- 配件SKU库位: 按资产类型(板材/组件/五金/包装)分组展示,支持筛选和搜索
- 成品SKU库位: 展示草稿组及其PreSku,支持搜索,显示状态标签
- 右侧AccordionSection展示真实统计数据
- 测试文件适配新props接口
2026-04-14 11:26:08 +08:00
Codex
ad70b534bf chore: checkpoint intake and warehouse workspace state 2026-04-14 10:00:51 +08:00
Codex
7f5218247d chore(intake): checkpoint right workbench toggle layout 2026-04-14 08:58:57 +08:00
Codex
795efe5970 chore: record 3100 recovered main-aligned state 2026-04-13 19:05:22 +08:00
WuYongJie
d12470419e merge: adopt xuxiake material library workflow 2026-04-13 17:26:23 +08:00
WuYongJie
73818e480b feat: finalize assisted assembly mainline workflow 2026-04-13 17:18:57 +08:00
Codex
7fdaaacb2d feat(资料库): 收口基材与花色新建逻辑 2026-04-13 16:09:38 +08:00
WuYongJie
b901e19ebd fix(material-library): align substrate migration and labels 2026-04-13 14:55:03 +08:00
Codex
a531b16b38 feat(基础资料库): 移除系统名称、优化花色筛选和表单布局
- 全栈移除 SubstrateSystemNameOption(字典管理、表单、API、数据库)
- 花色改为单选 + 自动搜索下拉,排除五金油漆/漆面颜色/五金漆面色
- 基材名称自动生成格式:尺寸+环保等级+材质+花色+贴面
- 材质改为纯下拉选择,贴面始终显示
- 花色框体与 Select 组件宽度/高度统一
- 厚度规格字典只保留厚度数值+排序值
2026-04-13 14:41:46 +08:00
Codex
cb6cb0cc57 feat(基础资料库): 实现 5 字段唯一约束收口
createSubstrate 新增合并逻辑:

1. **完全重复** (相同 5 字段 + 相同花色) → 拒绝,报错「基材库已有相同规格的基材,不可重复创建」
2. **花色不同** (相同 5 字段 + 不同花色) → 合并新花色到已有基材,重建名称
3. **规格不同** (5 字段不同) → 新建基材,自动编码 BC-XXXX

5 字段 = categoryId + environmentGradeId + thicknessSpecId + surfaceOptionId + systemNameOptionId
实木 (无 surfaceOptionId) 按 null 处理,纳入 5 字段匹配

- TypeScript 编译: 0 errors
- 基础资料库测试: 48/48 passed
2026-04-13 14:41:08 +08:00
WuYongJie
2846c7397e feat: finalize assisted assembly viewport integration 2026-04-13 14:32:24 +08:00
WuYongJie
ae9acb4091 feat: add asset thumbnail generation workflow 2026-04-11 15:13:26 +08:00
6012 changed files with 964641 additions and 224626 deletions

View File

@ -1,135 +0,0 @@
---
description: 3D 工程师规范 - Three.js 渲染、模型处理、资源管理
alwaysApply: false
---
# 3D 工程师规范
## 一、技术栈
| 库 | 版本 | 用途 |
|------|------|------|
| Three.js | 0.182.0 | 3D 渲染核心 |
| @react-three/fiber | 9.5.0 | React 集成 |
| @react-three/drei | 10.7.7 | 常用工具 |
| GSAP | - | 动画 |
---
## 二、目录结构
```
src/components/3d/
├── Scene.tsx # 主场景
├── ModelViewer.tsx # 模型查看器
├── AnimationEngine.ts # 动画引擎
└── controls/ # 控制器
src/lib/three/
├── loaders/ # 加载器
├── materials/ # 材质
└── utils/ # 工具函数
```
---
## 三、资源清理(必须)
组件卸载时必须清理所有资源:
```typescript
public dispose(): void {
// 1. 停止动画循环
if (this.animationId) {
cancelAnimationFrame(this.animationId)
}
// 2. 移除事件监听
window.removeEventListener('resize', this.handleResize)
// 3. 深度清理场景对象
this.scene.traverse((obj) => {
if (obj instanceof THREE.Mesh) {
obj.geometry?.dispose()
this.disposeMaterial(obj.material)
}
})
// 4. 清理控制器和渲染器
this.controls?.dispose()
this.renderer?.dispose()
this.renderer?.forceContextLoss()
}
private disposeMaterial(material: THREE.Material | THREE.Material[]): void {
const materials = Array.isArray(material) ? material : [material]
for (const mat of materials) {
// 清理所有贴图
;['map', 'normalMap', 'roughnessMap', 'metalnessMap'].forEach((key) => {
const texture = mat[key]
if (texture) texture.dispose()
})
mat.dispose()
}
}
```
---
## 四、GSAP 动画清理
```typescript
dispose(): void {
if (this.currentTimeline) {
this.currentTimeline.kill()
this.currentTimeline = null
}
if (this.scene) {
this.scene.traverse((object) => {
gsap.killTweensOf(object)
gsap.killTweensOf(object.position)
gsap.killTweensOf(object.rotation)
gsap.killTweensOf(object.scale)
})
}
}
```
---
## 五、性能优化
### LOD 策略
根据距离切换模型精度
### 内存管理
- 及时释放 geometry、material、texture
- 避免在循环中创建新对象
### 渲染优化
- 使用 `React.memo` 包装组件
- 避免不必要的重渲染
---
## 六、模型存储
```
public/uploads/models/
├── demo/ # 演示模型
└── {productId}/ # 按产品ID组织
├── original/ # 原始上传文件(DWG等)
└── model.glb # 转换后的 3D 模型
```
---
## 七、禁止事项
```
❌ 组件卸载时不清理资源
❌ 不清理事件监听器
❌ 不停止 GSAP 动画
❌ 在循环中创建新对象
```

View File

@ -1,90 +0,0 @@
---
description: C#/AutoCAD 工程师规范 - AutoCAD 插件开发
alwaysApply: false
---
# C#/AutoCAD 工程师规范
## 一、项目结构
```
autocad-plugin/
├── FurnitureExporter/ # 主项目
│ ├── Commands/ # AutoCAD 命令
│ ├── Models/ # 数据模型
│ ├── Services/ # 业务服务
│ └── Utils/ # 工具类
├── build.ps1 # 构建脚本
└── build-installer.ps1 # 安装包脚本
```
---
## 二、构建命令
```bash
# 一键构建
powershell -File .\build.ps1
# 生成安装包
powershell -File .\build-installer.ps1
# 手动构建(在 FurnitureExporter 目录)
dotnet build -c Release
```
---
## 三、AutoCAD API 规范
### 命令定义
```csharp
[CommandMethod("EXPORTFURNITURE")]
public void ExportFurniture()
{
var doc = Application.DocumentManager.MdiActiveDocument;
var ed = doc.Editor;
// ...
}
```
### 事务处理
```csharp
using (var tr = doc.TransactionManager.StartTransaction())
{
// 操作代码
tr.Commit();
}
```
---
## 四、输出格式
### JSON 结构
```json
{
"products": [
{
"modelNo": "ABC123",
"name": "产品名称",
"panels": [
{
"name": "板件1",
"geometry": {...},
"holes": [...]
}
]
}
]
}
```
---
## 五、注意事项
1. **兼容性**:支持 AutoCAD 2020+
2. **错误处理**:所有 AutoCAD API 调用需要 try-catch
3. **资源释放**:及时释放非托管资源
4. **性能**:大量数据处理使用后台线程

View File

@ -1,146 +0,0 @@
---
description: 后端工程师规范 - API、Service、Repository 分层架构
alwaysApply: false
---
# 后端工程师规范
## 一、分层架构(必须遵循)
```
API Route → Service → Repository → Database
↓ ↓
Cache DTO
```
---
## 二、API 路由规范
### 正确写法
```typescript
export async function GET(request: NextRequest) {
return handleRequest(request, async (ctx) => {
const data = await xxxService.getXxx(ctx)
return jsonSuccess(data)
})
}
```
### 禁止写法
```typescript
// ❌ 禁止在 API 中直接写 Prisma
export async function GET(request: NextRequest) {
const data = await prisma.xxx.findMany() // 禁止!
}
```
---
## 三、Service 层规范
### 职责
1. 调用 Repository 获取数据
2. 业务逻辑处理
3. 权限检查
4. 缓存读写
5. 转换为 DTO
### 模板
```typescript
async getXxx(ctx: ServiceContext): Promise<XxxDTO> {
// 1. 检查缓存
const cached = await this.cache.get(CacheKeys.xxx(id))
if (cached) return cached
// 2. 调用 Repository
const entity = await this.repository.findById(id)
// 3. 权限检查
this.checkPermission(entity, ctx.user)
// 4. 转换 DTO
const dto = toXxxDTO(entity)
// 5. 写入缓存
await this.cache.set(CacheKeys.xxx(id), dto, CACHE_TTL.MEDIUM)
return dto
}
```
---
## 四、Repository 层规范
### 职责
只负责数据访问,不含业务逻辑
### 模板
```typescript
async findById(id: string): Promise<Entity | null> {
return this.prisma.xxx.findUnique({ where: { id, deletedAt: null } })
}
```
---
## 五、必须使用的工具
| 工具 | 用途 | 示例 |
|------|------|------|
| `handleRequest` | 统一请求处理 | `handleRequest(request, async (ctx) => {...})` |
| `jsonSuccess` | 成功响应 | `return jsonSuccess(data)` |
| `jsonError` | 错误响应 | `return jsonError(error)` |
| `AppError` | 抛出错误 | `throw new AppError(ErrorCode.XXX_NOT_FOUND)` |
| `CacheKeys` | 缓存键管理 | `CacheKeys.product(id)` |
| `$transaction` | 事务处理 | `prisma.$transaction(async (tx) => {...})` |
---
## 六、API 响应格式
| 操作类型 | 格式 |
|----------|------|
| 列表查询 | `{ items: [], pagination: { page, limit, total, hasMore } }` |
| 详情/创建/更新 | `{ data: {...} }` |
| 删除 | `{ success: true }` |
| 错误 | `{ error: { code, message } }` |
---
## 七、目录结构
```
src/server/
├── core/ # 响应、错误码、常量
├── repositories/ # 数据访问层
├── services/ # 业务逻辑层
├── dto/ # 数据传输对象
├── validators/ # 输入验证(Zod)
└── cache/ # 缓存层
```
---
## 八、事务处理
多表操作必须使用事务:
```typescript
const result = await prisma.$transaction(async (tx) => {
const product = await tx.product.create({ data: {...} })
const panels = await tx.panel.createMany({ data: [...] })
return { product, panels }
})
```
---
## 九、缓存策略
| 数据类型 | TTL | 失效策略 |
|---------|-----|---------|
| 用户信息 | 5分钟 | 更新时失效 |
| 产品详情 | 5分钟 | 更新/删除时失效 |
| 产品列表 | 2分钟 | 任何变更失效 |

View File

@ -1,84 +0,0 @@
---
description: 规则审查员检查清单
alwaysApply: false
---
# 规则审查员检查清单
## 一、后端检查
### 分层架构
- [ ] API 是否只调用 Service?
- [ ] Service 是否调用 Repository?
- [ ] Repository 是否只负责数据访问?
### 统一处理
- [ ] 是否使用 `handleRequest`?
- [ ] 是否使用 `jsonSuccess/jsonError`?
### 错误处理
- [ ] 是否使用 `AppError + ErrorCode`?
- [ ] 禁止 `throw new Error()`
### 事务处理
- [ ] 多表操作是否使用 `$transaction`?
---
## 二、前端检查
### 元组件
- [ ] 是否使用 `@/components/ui/` 元组件?
- [ ] 禁止原生 `<button>` / `<input>` / `<select>`
### 颜色规范
- [ ] 是否使用 `text-apple-label-*`?
- [ ] 是否使用 `bg-apple-bg-*`?
- [ ] 禁止 `text-gray-*` / `bg-gray-*`
### 圆角规范
- [ ] 是否使用 `rounded-apple-md/lg`?
---
## 三、审查报告格式
```
## 审查结果
### 通过项 ✅
- 使用了 Service 层
- 使用了 Button 元组件
### 违规项 ❌
- API 中直接使用 prisma(第 15 行)
→ 修复:将数据库查询移到 Repository 层
- 使用了 text-gray-500(第 23 行)
→ 修复:改为 text-apple-label-secondary
### 评分:X/10
```
---
## 四、快速对照表
### 后端
| 正确 | 错误 |
|------|------|
| `await xxxService.getXxx()` | `await prisma.xxx.findMany()` 在 API 中 |
| `handleRequest(request, ...)` | 自己写 try-catch |
| `jsonSuccess(data)` | `NextResponse.json({...})` |
| `AppError(ErrorCode.XXX)` | `throw new Error('xxx')` |
| `$transaction(...)` | 多个独立 prisma 调用 |
### 前端
| 正确 | 错误 |
|------|------|
| `<Button>` | `<button>` |
| `text-apple-label-*` | `text-gray-*` |
| `bg-apple-bg-*` | `bg-gray-*` |
| `rounded-apple-md/lg` | `rounded-lg/xl` |

View File

@ -1,65 +0,0 @@
---
description: 核心规则摘要 - 必须在写代码前阅读并遵循
alwaysApply: true
---
# 核心规则摘要
> **这是所有规则的浓缩版,必须 100% 遵循!**
---
## 一、后端必遵循(5 条)
| # | 规则 | 正确示例 | 错误示例 |
|---|------|----------|----------|
| 1 | **分层架构**:API → Service → Repository | `await xxxService.getXxx()` | `await prisma.xxx.findMany()` |
| 2 | **统一请求处理**:使用 `handleRequest` | `handleRequest(request, async (ctx) => {...})` | 自己写 try-catch |
| 3 | **统一响应**:使用 `jsonSuccess/jsonError` | `return jsonSuccess(data)` | `return NextResponse.json({...})` |
| 4 | **错误抛出**:使用 `AppError + ErrorCode` | `throw new AppError(ErrorCode.XXX)` | `throw new Error('xxx')` |
| 5 | **多表操作**:必须使用 `$transaction` | `prisma.$transaction(async (tx) => {...})` | 多个独立的 prisma 调用 |
---
## 二、前端必遵循(5 条)
| # | 规则 | 正确示例 | 错误示例 |
|---|------|----------|----------|
| 1 | **使用元组件** | `<Button>` `<Input>` `<Modal>` | `<button>` `<input>` `<div className="modal">` |
| 2 | **文本颜色** | `text-apple-label-primary/secondary` | `text-gray-900` `text-gray-500` |
| 3 | **背景颜色** | `bg-apple-bg-primary/secondary` | `bg-gray-100` `bg-white` |
| 4 | **品牌色** | `#008D74` 或 `text-apple-brand` | `blue-500` `green-600` |
| 5 | **圆角** | `rounded-apple-md/lg` | `rounded-lg` `rounded-xl` |
---
## 三、禁止事项(绝对不能做)
```
❌ API 中直接写 prisma.xxx.findMany() / create() / update()
❌ 使用 text-gray-* / bg-gray-* / shadow-* 类名
❌ 直接写原生 HTML 元素:<button> <input> <select>
❌ 组件内直接 fetch() 请求数据
❌ 不使用 AppError 直接 throw new Error()
```
---
## 四、文件路径速查
| 用途 | 路径 |
|------|------|
| 元组件 | `@/components/ui/` |
| 后端服务 | `src/server/services/` |
| 数据仓库 | `src/server/repositories/` |
| 错误码 | `src/server/core/errors.ts` |
| 响应工具 | `src/server/core/response.ts` |
---
## 五、详细规范位置
如需更多细节,查看以下文件:
- 完整架构规范:`.cursor/rules/backend.mdc`
- 视觉标准:`docs/设计规范/苹果风格视觉标准.md`
- 开发检查清单:`.cursor/rules/checklist.mdc`

View File

@ -1,146 +0,0 @@
---
description: 前端工程师规范 - 元组件、苹果风格视觉标准
alwaysApply: false
---
# 前端工程师规范
## 一、元组件体系(必须使用)
| 元组件 | 路径 | 用途 |
|--------|------|------|
| `Button` | `@/components/ui/Button` | 所有按钮 |
| `Input` | `@/components/ui/Input` | 所有输入框 |
| `Textarea` | `@/components/ui/Input` | 多行输入 |
| `Modal` | `@/components/ui/Modal` | 所有弹窗 |
| `Card` | `@/components/ui/Card` | 所有卡片 |
| `Toast` | `@/components/ui/Toast` | 所有提示 |
| `Select` | `@/components/ui/Select` | 所有下拉框 |
| `Badge` | `@/components/ui/Badge` | 所有标签徽章 |
### Toast 使用
```tsx
import { useToast, ToastContainer } from '@/components/ui/Toast'
const toast = useToast()
toast.success('操作成功')
toast.error('操作失败')
// JSX 中添加容器
<ToastContainer toasts={toast.toasts} onClose={toast.removeToast} />
```
---
## 二、色彩系统
### 文本颜色
| 用途 | Tailwind 类 |
|------|-------------|
| 主文本 | `text-apple-label-primary` |
| 次文本 | `text-apple-label-secondary` |
| 辅助文本 | `text-apple-label-tertiary` |
### 背景颜色
| 用途 | Tailwind 类 |
|------|-------------|
| 主背景 | `bg-apple-bg-primary` |
| 次级背景 | `bg-apple-bg-secondary` |
| 三级背景 | `bg-apple-bg-tertiary` |
### 品牌色
| 模式 | 颜色 | Tailwind 类 |
|------|------|-------------|
| 浅色 | `#008D74` | `text-apple-brand` / `bg-apple-brand` |
| 深色 | `#00B896` | `text-apple-brand` / `bg-apple-brand` |
---
## 三、圆角规范
| 大小 | 像素 | Tailwind 类 |
|------|------|-------------|
| 中 | 10px | `rounded-apple-md` |
| 大 | 16px | `rounded-apple-lg` |
---
## 四、禁止事项
| 禁止 | 替代方案 |
|------|---------|
| `text-gray-*` | `text-apple-label-*` |
| `bg-gray-*` | `bg-apple-bg-*` |
| `shadow-*` | `shadow-apple-*` |
| `rounded-lg/xl` | `rounded-apple-md/lg` |
| `<button>` | `<Button>` |
| `<input>` | `<Input>` |
| 蓝色 focus ring | 品牌色 `#008D74` |
---
## 五、去 AI 味
| 禁止 | 推荐 |
|------|------|
| ❌ 均等分布(4个功能各占25%) | ✅ 非对称布局 |
| ❌ 默认实心图标 | ✅ 细线条 stroke-width 1.5 |
| ❌ 彩虹渐变背景 | ✅ 纯色/微妙渐变 |
| ❌ Lorem Ipsum 占位 | ✅ 真实场景数据 |
---
## 六、动画规范
| 场景 | 时长 | 缓动函数 |
|------|------|---------|
| 展开 | 500ms | `cubic-bezier(0.32, 0.72, 0, 1)` |
| 收起 | 350ms | `cubic-bezier(0.32, 0, 0.68, 0)` |
| 按钮按压 | 100ms | `scale(0.98)` |
| 悬停放大 | 200ms | `scale(1.02)` |
---
## 七、状态管理
### Zustand Stores
```
src/stores/
├── auth.store.ts # 认证状态
├── ui.store.ts # UI 状态
└── product.store.ts # 产品状态
```
### React Query Hooks
```
src/hooks/api/
├── useProducts.ts
├── useSKUs.ts
└── useUsers.ts
```
### 禁止
```typescript
// ❌ 禁止组件内直接 fetch
const [data, setData] = useState()
useEffect(() => { fetch('/api/xxx').then(...) }, [])
```
---
## 八、目录结构
```
src/components/
├── ui/ # 元组件(必须复用)
├── 3d/ # 3D 组件
└── [feature]/ # 功能组件
src/app/
├── (main)/ # 主布局页面
├── api/ # API 路由
└── share/ # 分享页面
```

View File

@ -1,113 +0,0 @@
---
description: 性能优化师规范 - 检查性能问题
alwaysApply: false
---
# 性能优化师规范
## 一、数据库性能
### 检查项
- [ ] 是否存在 N+1 查询问题?
- [ ] 是否使用了合理的索引?
- [ ] 大数据量是否分页加载?
### N+1 查询示例
```typescript
// ❌ N+1 问题
const products = await prisma.product.findMany()
for (const product of products) {
const skus = await prisma.sKU.findMany({ where: { productId: product.id } })
}
// ✅ 正确:使用 include
const products = await prisma.product.findMany({
include: { skus: true }
})
```
---
## 二、前端性能
### 检查项
- [ ] 是否使用了 React Query 缓存?
- [ ] 大列表是否使用虚拟滚动?
- [ ] 图片是否懒加载?
### React Query 缓存
```typescript
const { data } = useQuery({
queryKey: ['products', filters],
queryFn: () => fetchProducts(filters),
staleTime: 5 * 60 * 1000, // 5分钟
})
```
---
## 三、3D 性能
### 检查项
- [ ] 模型是否使用 LOD 策略?
- [ ] 组件卸载时是否清理资源?
- [ ] 是否避免内存泄漏?
### 内存泄漏检查
- 事件监听器是否移除?
- 定时器是否清除?
- GSAP 动画是否停止?
- geometry/material/texture 是否释放?
---
## 四、性能监控
### 请求计时
```typescript
const result = await timeAsync('product.import', async () => {
// 耗时操作
})
```
### 日志规范
```typescript
logger.info('Product created', {
productId: product.id,
userId: ctx.user.id,
duration: elapsed
})
```
---
## 五、性能检查清单
| 类别 | 检查项 |
|------|--------|
| 数据库 | N+1 查询、索引、分页 |
| 前端 | React Query 缓存、虚拟滚动、懒加载 |
| 3D | LOD、资源清理、内存泄漏 |
| 监控 | 请求计时、日志记录 |
---
## 六、审查报告格式
```
## 性能审查结果
### 通过项 ✅
- 使用了 React Query 缓存
- 使用了分页加载
### 优化建议 ⚠️
- 第 X 行存在 N+1 查询
→ 修复:使用 include 预加载关联数据
### 严重问题 ❌
- 组件卸载时未清理资源
→ 修复:添加 dispose() 方法
### 评分:X/10
```

View File

@ -1,101 +0,0 @@
---
description: 安全审查员规范 - 检查安全漏洞
alwaysApply: false
---
# 安全审查员规范
## 一、输入验证
### 检查项
- [ ] 所有用户输入是否经过 Zod 验证?
- [ ] 文件上传是否检查类型和大小限制?
- [ ] 是否防止了路径遍历攻击?
### 文件上传安全
```typescript
const MAX_TOTAL_SIZE = 500 * 1024 * 1024 // 500MB
const MAX_FILE_COUNT = 100
const MAX_SINGLE_FILE_SIZE = 200 * 1024 * 1024 // 200MB
// 解压前必须检查
let totalSize = 0
let fileCount = 0
for (const [name, file] of Object.entries(zip.files)) {
if (!file.dir) {
fileCount++
if (fileCount > MAX_FILE_COUNT) throw new Error('文件数量超限')
if (size > MAX_SINGLE_FILE_SIZE) throw new Error('单文件过大')
totalSize += size
}
}
```
---
## 二、权限检查
### 检查项
- [ ] API 是否验证用户身份?
- [ ] 是否检查用户对资源的操作权限?
- [ ] 敏感操作是否有二次确认?
### 示例
```typescript
// 检查用户是否有权操作该资源
this.checkPermission(entity, ctx.user)
// 如果没有权限
throw new AppError(ErrorCode.AUTH_PERMISSION_DENIED)
```
---
## 三、常见漏洞
### SQL 注入
- **检查**:是否使用 Prisma 参数化查询
- **禁止**:字符串拼接 SQL
### XSS
- **检查**:React 自动转义 + DOMPurify 清理 HTML
- **禁止**:使用 `dangerouslySetInnerHTML` 未经清理
### CSRF
- **检查**:Next.js CSRF Token 保护
- **禁止**:跨域请求不带凭证
---
## 四、安全检查清单
| 检查项 | 说明 |
|--------|------|
| 身份验证 | API 是否验证 JWT/Session |
| 资源权限 | 用户是否有权操作该资源 |
| 输入验证 | 所有输入是否经过 Zod 验证 |
| 文件上传 | 是否检查类型、大小、路径 |
| SQL 注入 | 是否使用参数化查询 |
| XSS | 是否转义用户输入 |
| CSRF | 是否有 Token 保护 |
---
## 五、审查报告格式
```
## 安全审查结果
### 通过项 ✅
- 使用了 Zod 验证输入
- 使用了 Prisma 参数化查询
### 风险项 ⚠️
- 文件上传未检查路径遍历(第 X 行)
→ 修复:添加路径检查,禁止 .. 和绝对路径
### 严重漏洞 ❌
- 无
### 评分:X/10
```

View File

@ -1,91 +0,0 @@
---
description: QA 测试员规范 - 单元测试、集成测试
alwaysApply: false
---
# QA 测试员规范
## 一、测试类型
| 类型 | 用途 | 位置 |
|------|------|------|
| 单元测试 | 测试独立函数和组件 | `tests/` |
| 集成测试 | 测试 API 端到端流程 | `tests/` |
| 边界测试 | 测试异常输入和边界条件 | `tests/` |
---
## 二、测试框架
| 工具 | 用途 |
|------|------|
| Jest | 测试框架 |
| @testing-library/react | React 组件测试 |
---
## 三、测试重点
### 必测项
- 核心业务逻辑
- 错误处理路径
- 权限检查逻辑
### 示例
```typescript
describe('ProductService', () => {
it('should create product successfully', async () => {
const result = await productService.create(validData)
expect(result).toBeDefined()
expect(result.id).toBeDefined()
})
it('should throw error when product not found', async () => {
await expect(
productService.getById('non-existent-id')
).rejects.toThrow(AppError)
})
})
```
---
## 四、常用命令
```bash
# 运行所有测试
npm test
# 运行单个文件
npm test -- tests/lib/zip-parser.test.ts
# 运行单个用例
npm test -- tests/lib/zip-parser.test.ts -t "用例名"
# 串行运行
npm test -- --runInBand tests/lib/zip-parser.test.ts
# 覆盖率
npm run test:coverage
```
---
## 五、测试原则
1. **AAA 模式**:Arrange(准备)→ Act(执行)→ Assert(断言)
2. **单一职责**:每个测试只验证一个行为
3. **独立性**:测试之间互不影响
4. **可读性**:测试名称清晰描述预期行为
---
## 六、测试目录结构
```
tests/
├── lib/ # 工具函数测试
├── services/ # Service 层测试
├── repositories/ # Repository 层测试
└── integration/ # 集成测试
```

View File

@ -1,228 +0,0 @@
# ============================================
# 3D家具安装展示系统 - Docker忽略文件
# 优化构建上下文,减少构建时间
# ============================================
# 开发文件
.git
.gitignore
README.md
测试指南.md
SETUP_COMPLETE.md
# Node.js
node_modules
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*
# Next.js
.next/
out/
build/
dist/
# 环境变量文件(保留.env.example)
.env
.env.local
.env.development.local
.env.test.local
.env.production.local
# 数据库
*.db
*.db-journal
prisma/dev.db*
# 日志文件
logs
*.log
# 运行时数据
pids
*.pid
*.seed
*.pid.lock
# 覆盖率目录
lib-cov
coverage
*.lcov
.nyc_output
# 依赖目录
jspm_packages/
# TypeScript
*.tsbuildinfo
# 可选的npm缓存目录
.npm
# 可选的eslint缓存
.eslintcache
# 微束缓存
.parcel-cache
# Next.js缓存
.next
# Nuxt.js构建/生成输出
.nuxt
dist
# Gatsby文件
.cache/
public
# Vuepress构建输出
.vuepress/dist
# Serverless目录
.serverless/
# FuseBox缓存
.fusebox/
# DynamoDB本地文件
.dynamodb/
# TernJS端口文件
.tern-port
# 存储VSCode版本的文件
.vscode-test
# yarn v2
.yarn/cache
.yarn/unplugged
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.*
# IDE文件
.vscode/
.idea/
*.swp
*.swo
*~
# 操作系统文件
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
ehthumbs.db
Thumbs.db
# 临时文件
*.tmp
*.temp
temp/
tmp/
# 测试文件
test/
tests/
__tests__/
*.test.js
*.test.ts
*.spec.js
*.spec.ts
# 文档文件
docs/
*.md
!README.md
# 脚本文件(除了必要的)
scripts/
!scripts/cache-manager.ps1
# Docker文件(避免递归)
Dockerfile*
docker-compose*.yml
.dockerignore
# 缓存目录(构建时会重新创建)
cache/
.cache/
# 上传文件(运行时生成)
uploads/
public/uploads/
# 备份文件
*.bak
*.backup
# 压缩文件
*.zip
*.tar
*.tar.gz
*.rar
*.7z
# 证书文件
*.pem
*.key
*.crt
*.csr
# 配置文件(敏感信息)
config.json
secrets.json
# 监控和分析
.nyc_output/
coverage/
*.lcov
# Storybook
.storybook/
storybook-static/
# 本地开发工具
.vscode/
.idea/
*.sublime-*
# 包管理器锁文件(保留package-lock.json用于精确依赖)
yarn.lock
pnpm-lock.yaml
# 构建工具缓存
.webpack/
.rollup.cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/
# 编辑器临时文件
*~
.#*
\#*#
.*.swp
.*.swo
# 本地环境特定文件
.env.local
.env.*.local
# 性能分析文件
*.cpuprofile
*.heapprofile
# 调试文件
debug.log
error.log
# 本项目特定忽略
PROJECT_SETUP_COMPLETE.md
产品安装展示系统-*.md
开发部署计划.md
项目*.md
架构*.md

10
.gitignore vendored
View File

@ -21,6 +21,16 @@ _logs/
# Temp
temp/
*.tmp
/.tmp-*/
/tmp-*/
/tmp-*.html
/tmp-*.png
/tmp-*.env
/tmp-*.service
/tmp-*.timer
/tmp-*.err
/tmp-*.out
/.gemini/
# Build artifacts (C# / .NET)
**/bin/

View File

@ -1,21 +0,0 @@
# 开发规范
## 🗣️ 交流语言
**重要**: 始终使用中文与用户交流
- 所有回复和解释用中文
- 错误信息和建议用中文
- 代码注释用中文
- 文档说明用中文
## 📋 项目信息
- **名称**: 3D家具安装展示系统
- **技术**: Next.js + Three.js + Apple UI
- **目标**: 现代化3D家具装配展示
## ⚡ 开发原则
- TypeScript 严格模式
- Apple HIG 2025 设计标准
- 性能优先 (React.memo + 懒加载)
- 代码整洁 (精简文档,避免冗余)
- 不重要的东西不要写文档
- 能在原有文档上更新就采用更新的方式

1
.npmrc
View File

@ -1 +0,0 @@
legacy-peer-deps=true

197
AGENTS.md
View File

@ -1,80 +1,167 @@
# AGENTS.md
适用范围:`D:\AI Code\3danzhuang` 全仓库。
适用范围:`D:\AI Code\3danzhuang-wuyongjie-mainline` 全仓库。
未单独说明时,先遵循当前 agent 自己的全局规则(ZCode:`C:\Users\54972\.zcode\v2\AGENTS.md`;Codex:`C:\Users\54972\.codex\AGENTS.md`)。
这份文件只记录本仓库当前有效的补充规则和核查入口,不保存密码、密钥、数据库连接串或对象存储密钥。
## 1. 默认方式
重要边界:`D:\AI Code\3danzhuang` 是历史旧现场;当前正式工作目录以 `D:\AI Code\3danzhuang-wuyongjie-mainline` 为准。除非用户明确要求,不要混用旧目录、旧服务器别名、旧部署脚本或旧截图结论。
- 默认中文沟通,面向非程序员表达。
- 默认回复尽量简短、直白、好理解,非必要不展开。
- 默认先说“现在你要做什么 / 结论是什么”;技术细节、文件路径、命令和长解释只在用户要求时展开。
- 默认按当前会话直接开发。
- 没有“规范审查结论”,任务不算完成。
## 1. 当前项目真相
## 2. 三条硬规则
- 外层目录 `D:\AI Code\3danzhuang-wuyongjie-mainline` 是 Git 仓库根目录。
- 主应用目录是 `furniture-3d-system/`;用户未指定目录时,默认在这里执行代码、测试、构建和脚本。
- 技术栈以当前 `furniture-3d-system/package.json` 为准(核心:Next.js App Router + React + TypeScript + Prisma/PostgreSQL + Jest + Playwright + Tailwind CSS + Three.js/R3F;另有 ioredis、puppeteer、exceljs/xlsx、zod、zustand 等)。package.json 变动后文档不自动同步,以实时核查为准。
- `CLAUDE.md`、旧 README、`docs/历史归档/` 和早期部署文档里可能仍有旧苹果风格、MinIO、旧 Docker 部署、旧模型数量、旧 Product/SKU 口径等信息;只能当历史参考,不能覆盖当前代码、workflow 文档和实时命令结果。
- 工作树可能有用户或其他协作者留下的未跟踪文件、日志、贴图和本地产物。只处理本次任务明确相关的文件,不要顺手清理或回退无关现场。
- 必须符合企业级架构标准。
- 必须符合统一视觉标准。
- 必须优先做根因修复,不能拿补丁冒充完成。
## 2. 开工前固定入口
## 3. 固定流程
1. 开始前先用 1-2 句说明:目标、验收标准、根因判断。
2. 开发时优先复用现有实现,不顺手改无关问题。
3. 改完先做最小必要验证。
4. 交付前必须单独做一次规范审查。
5. 最终默认只交代:现在你要做什么、是否完成、有没有风险;技术细节只在用户要求时展开。
### 团队协作固定入口
当任务发生在 `furniture-3d-system/` 时,人和 AI 都必须先读取下面这些协作文档,再开始改代码:
当任务发生在 `furniture-3d-system/` 时,改代码前必须先读这 3 份当前协作入口:
- `furniture-3d-system/docs/workflow/团队协作模式.md`
- `furniture-3d-system/docs/workflow/模块边界说明.md`
- `furniture-3d-system/docs/workflow/主线同步操作手册.md`
这 3 份文档就是进入 `furniture-3d-system/` 的固定协作入口,不再额外约定第二套平级入口,也不再靠聊天记录补口头规则。
按任务类型额外读取:
如果任务和包装协作有关,再额外读取:
- 生产、部署、线上排障:`furniture-3d-system/docs/workflow/生产部署入口说明.md`,并核对 `scripts/deploy-yydd-prod-from-git.ps1` 与其调用的 `scripts/create-yydd-prod-deploy.ps1` 当前默认参数。
- 前端、视觉、交互:`furniture-3d-system/docs/设计规范/白曜石工坊统一视觉标准.md` 和 `furniture-3d-system/docs/workflow/规范审查清单.md`。
- 包装、仓库、轻仓库协作:再读包装/仓库相关交接文档和 `src/app/warehouse`、`src/app/api/warehouse`、`src/app/api/pre-skus/[id]/packaging/route.ts` 的当前实现。
- 数据库、主数据、迁移:优先读 `docs/架构设计/内部主数据巡检基线-20260529.md`、`docs/架构设计/数据库混乱点治理台账.md` 和相关 `db:foundation:*` 脚本说明。
- `furniture-3d-system/docs/workflow/同事交接模板.md`
- `furniture-3d-system/docs/workflow/同事本地AGENTS模板.md`
- `furniture-3d-system/docs/开发指南/包装方案增强/新平台包装底座-同事AI对接说明-20260331.md`
如果文档和代码冲突,按这个顺序判断:当前代码和脚本、当前线上/命令返回、当前 workflow 文档、历史文档或旧记忆。
固定协作口径:
## 3. Git 与主线协作
- `main` 只作为 `WuYongJie` 的主线收口分支,其他协作者默认不能直接推主线
- `xuxiake` 的长期包装分支固定为 `codex/xuxiake-packaging`
- `xuxiake` 的临时任务分支固定为 `codex/xuxiake-packaging-<任务简称>`
- 新分支统一使用 `codex/<负责人>-<工作域>` 或 `codex/<负责人>-<工作域>-<任务简称>`
- 不再使用 `feature/packaging`、`packaging/...`、`codex/xuxiake-dev` 这类泛分支名
- 长期包装分支同步 `main` 时固定使用 `merge main`
- 临时个人任务分支同步 `main` 时才使用 `rebase main`
- `main` 是最终发布主线,由 `WuYongJie` 收口;不要直接把半成品推到 `main`。
- `origin/codex/xuxiake-mainline` 是日常共享开发主线和默认同步基线。
- 新功能、优化和修复默认从最新 `origin/codex/xuxiake-mainline` 开任务分支,再按协作流程回流。
- 新分支统一使用 `codex/<负责人>-<工作域>` 或 `codex/<负责人>-<工作域>-<任务简称>`,不要再新建 `feature/...`、`packaging/...`、`dev`、`codex/xuxiake-dev` 这类泛分支名。
- 长期共享分支同步共享开发主线时固定使用 `merge origin/codex/xuxiake-mainline`;只有确认无人共用的临时个人任务分支才使用 `rebase origin/codex/xuxiake-mainline`。
- 每次开工或接续旧任务时,先看 `git status --short --branch`;涉及主线同步时再看 `git rev-list --left-right --count HEAD...origin/codex/xuxiake-mainline`,不要把“当前所在分支”误当成“已同步共享主线”。
- 用户问“xuxiake 主线有没有新提交”时,必须先 `git fetch origin`,再基于最新远端状态回答。
- 不要在脏工作树上直接 merge/rebase。先看 `git status --short`,分清本次改动、用户改动、本地产物和无关未跟踪文件。
- 常规任务完成必要验证后,可以按协作流程推进 `commit / push`;`main`、生产发布、破坏性操作、删除数据、改远端历史等高风险动作必须有用户明确授权。
## 4. 规范审查
### 主线部署标准流程(每次"主线部署"都走这一套)
规范审查固定只查三件事:
- 架构有没有被破坏
- 视觉有没有跑偏
- 这次是不是根因修复
本仓库有两根主线,都不直接提交:`main` 是生产部署唯一来源(由 `WuYongJie` 收口),`origin/codex/xuxiake-mainline` 是共享开发次主线(日常回流基线)。
结论只能是:
- `passed`
- `passed with warnings`
- `rejected`
每次用户要求"主线部署",严格按以下顺序,不跳步、不直接支线 → main:
只要架构违规、视觉违规,或明显是补丁式修复,就必须 `rejected`。
如果这次不是独立复审,必须明确写出“这是自审,不是独立复审”。
1. **在支线开发** → 提交到任务分支(如 `codex/wuyongjie-xxx`),不碰两根主线。
2. **fetch xuxiake** → 必须先 `git fetch origin`,看 `origin/codex/xuxiake-mainline` 有没有新提交。
3. **有新提交** → `merge origin/codex/xuxiake-mainline` 拉下来处理冲突(长期共享分支用 merge,不 rebase);只处理冲突文件,不扩范围。
4. **合并到 xuxiake** → 把支线合进 `origin/codex/xuxiake-mainline`,并 `push` 更新次主线。
5. **合并到 main** → 把 xuxiake 合进 `main`,并 `push origin main`(本步需用户授权)。
6. **用 main 部署** → 走 `scripts/deploy-yydd-prod-from-git.ps1`(默认源 `origin/main`),部署后核对 commit / 进程 / 端口 / 日志 / 关键页面(本步需用户授权)。
统一清单:`docs/workflow/规范审查清单.md`
发布前必须确认 `git ls-remote origin refs/heads/main`、本地 `origin/main`、目标部署 commit 三者一致。
## 5. 标准来源
## 4. 生产与部署
- `furniture-3d-system/.cursor/rules/*.mdc`
- `furniture-3d-system/docs/设计规范/苹果风格视觉标准.md`
- `docs/workflow/规范审查清单.md`
- 当前正式网址:`https://cp.jiansun.vip/`。
- 当前权威生产 SSH 入口:`root@ltai5tdb2ogyj59fquyedh.yydd.ai`,端口 `60022`。
- 当前生产部署目录:`/opt/furniture-3d-system-prod`。
- 当前 PM2 进程名:`furniture-3d-system-prod`。
- 当前应用本机端口:`3001`。
- 默认生产部署来源:`origin/main`。
- 当前主部署入口是外层 `scripts/deploy-yydd-prod-from-git.ps1`;它默认部署 `origin/main`,并调用 `scripts/create-yydd-prod-deploy.ps1` 生成发布包/远端发布脚本。不要把下层打包脚本单独当成唯一部署入口。
- 发布前必须确认 `git ls-remote origin refs/heads/main`、本地 `origin/main`、目标部署 commit 三者一致;本地 `main` 是否领先或落后远端不能替代 `origin/main` 的真实发布来源。
- 旧 `192.168.58.20`、本机泛别名 `prod`、旧 `gongxiangp2 / youyidian-3d-material` 生产信息都不能套用到本项目。
- 生产动作前至少实时确认:目标主机、远端目录、PM2 进程、`current` 软链接、监听端口和 `https://cp.jiansun.vip/api/health`。
- 生产数据库、迁移、主数据地基相关动作先只读核查;需要写入时必须有备份、目标库身份、确认口令和可回滚路径。
- 对象存储当前要按 `src/lib/storage.ts`、`storage:*` 脚本、七牛迁移/GC 文档和生产环境变量实时核对;不要把历史 MinIO/S3 备份脚本当成当前生产存储真相。
## 6. 边界
## 5. 当前主链与模块边界
- 用户未指定目录时,默认在 `furniture-3d-system/` 执行。
- 未经用户明确要求,不主动 `commit / push`。
- 禁止破坏性操作,除非用户明确授权。
当前新平台数据主链按这条线理解:
`资产中心 -> 辅助装配 -> 草稿组 -> 产品资料/正式入库 -> 仓库管理/轻仓库`
当前全局工作台导航还包含首页、OA 新品流程看板、仓库质检、AI 出图工作台等运营入口。导航入口不等于数据主链,不要把页面入口和主数据归属混成一件事。
主链默认入口和目录:
- 首页与全局壳:`src/app/page.tsx`、`src/components/layout`
- 资产中心:`src/app/asset-center`、`src/app/api/asset-center`
- 辅助装配:`src/app/assisted-assembly`、`src/app/api/assisted-assembly`
- 草稿组:`src/app/draft-groups`、`src/app/api/draft-groups`
- 产品资料/正式入库:`src/app/intake`、`src/app/api/intake`
- 仓库管理/轻仓库:`src/app/warehouse`、`src/app/api/warehouse`
- 仓库质检:`src/app/warehouse-quality`、`src/app/api/warehouse-quality`
- AI 出图工作台:`src/app/ai-render-workbench`
- 审批工作流:`src/app/approval-workflows`
- 素材库:`src/app/materials`
- 移动端:`src/app/mobile`
- 平台组件库:`src/components/platform`
- 主链规则与类型:`src/lib/open-product`、`src/lib/planning`
业务真相:
- 资产族:`AssetFamily`
- 规格款:`AssetVariant`
- 草稿组:`DraftGroup`
- 准 SKU:`PreSku`
- 入库结果:正式 `Product / ProductSKU`(`SKU` 是业务概念,Prisma 模型名是 `ProductSKU`)
- 产品资料侧非集成开品:`IntakeNonIntegratedProduct / IntakeNonIntegratedSkuItem`
旧 CAD 兼容链继续存在,但不是新平台主数据源:
- 页面:`src/app/products`、`src/app/products/[id]`、`src/app/products/[id]/assembly`、`src/app/products/[id]/skus/[skuId]`
- 旧链模型和服务包括 `Product / ProductSKU / Panel / Hole / ProductHardware`、`assembly.service`、`panel.service`、`hole.service` 等。
- 旧链可以继续服务历史产品、CAD 导入、装配步骤和兼容发布后能力,但不要反向主导资产中心、草稿组或产品资料主链。
共享接缝默认谨慎处理:
- `prisma/schema.prisma`
- `prisma/migrations`
- `src/app/layout.tsx`
- `src/app/intake`
- `src/app/draft-groups/[id]`
- `src/app/api/platform/schemas.ts`
- `src/server/services/draft-group.service.ts`
- `src/server/services/intake.service.ts`
- `src/server/repositories/draft-group.repository.ts`
改这些地方前先说明原因、影响范围和验证计划;不要为了局部 UI 或临时兼容绕过模块边界。
## 6. 架构硬规则
- API Route 负责收参、鉴权和返回,不直接堆业务规则或 Prisma 查询。
- Service 负责业务规则、权限校验、事务编排、缓存和跨模块协调。
- Repository 负责数据访问。
- 任何新接口必须有明确输入输出 DTO/校验口径。
- 不是必须的话,不要使用兜底逻辑;原生主逻辑能做好,就先把主逻辑、状态契约和数据来源修正确。兜底只能用于明确的兼容、降级或应急场景,不能用来掩盖本应修好的业务规则、接口契约或前端状态问题。
- 任何 Prisma 模型调整必须带迁移,并补齐主数据/迁移核查;生产/准生产禁止用 `prisma db push` 替代迁移。
- 影响命名、BOM、包装、安装步骤、SKU、barcode、批次、入库承接的数据问题,优先从数据源和业务规则修,不在页面上压报错或绕校验。
- SPU、SKU、barcode、批次不能混用:SPU 是父级产品款,SKU 是 SPU 下的具体子项(Prisma 模型名 `ProductSKU`),barcode 是绑定到最终 SKU 的业务定位值;基于某 SKU 派生的新 SKU 必须仍属于同一 SPU,并按业务要求继承或明确指定批次。
## 7. 前端与视觉硬规则
- 白曜石工坊统一视觉标准是本项目新平台第一视觉标准;默认是浅色工作台,不再提供深浅色主题切换入口。
- 本项目有自己的组件库与 `Meta Component(元组件)` 体系;前端实现必须优先复用 `src/components/platform`、资产中心已沉淀的工作台表达和现有元组件,不允许绕开组件库另起一套孤立 UI。
- 当用户指定 Stitch 设计稿或已有 Stitch 设计稿可参考时,Stitch 是当前功能的视觉规范与验收标准;实现方式是在本项目组件库/元组件体系内对齐 Stitch 的密度、层级、控件形态、留白、字号、圆角、阴影和低噪音表达,而不是无视组件库硬抄静态稿。
- 资产中心页面是当前项目内的优先参考样板;涉及资产、图片、SKU、AI 白底图、3D 预览、工作区和检视器时,默认参考资产中心的工作台感、元组件表达、低噪音操作面板和重点图片区。
- `Inspector(检视器)`、数据列表、表格、长文本和表单密集区必须优先保证可读性;毛玻璃只允许用于顶栏、HUD、浮动工具条和轻量状态浮层,不承载正文。
- 板材、五金、组件、包装等资产必须按元组件表达,不能退回普通图片卡片或营销式大卡片布局。
- 现有 `apple-*` token、深色 `ObsidianControlShell`、历史主题 CSS 只能作为兼容遗留;新功能不得以它们作为视觉方向。
- 前端改造不得把现有后台习惯、普通 SaaS 审美或共享组件默认皮肤当成最终依据;如果组件库默认视觉和 Stitch/资产中心标准冲突,应在组件库体系内做专用变体、重写皮肤或局部重构。
- 没有出现在设计稿、组件规范或业务必要路径里的说明文案、辅助卡片、重复统计块、解释区,不要为了“更易懂”自行添加;工作区必须抓重点,图片类功能要让图片和关键动作成为第一层级。
- 涉及前端动画、入退场、滚动联动、时间线、拖拽、SVG 或动效性能时,先判断是否有助于理解和操作;需要时优先按技术栈调用对应 GSAP Skill,并继续遵守 Impeccable。React 必须使用 `useGSAP` 或带 `gsap.context().revert()` 的完整清理,滚动相关实例必须销毁并在布局变化时正确刷新;优先动画 `transform/opacity`,尊重 `prefers-reduced-motion`,不得为装饰滥用动效。
- 前端修改后优先用真实页面、截图、1920×1080 视口和必要的移动端视口验证,不只看代码。
## 8. 验证、收口与规范审查
- 修改后必须做最小但有效的验证;不能验证就明确说明未验证原因和风险。
- 常用验证命令以当前 `package.json` 为准,优先选和改动范围匹配的最小集合:`npm run type-check`、`npm run build`、`npm test -- <相关测试>`、`npm run lint`;对象存储用 `npm run storage:gc:audit` / `npm run storage:gc:apply`,主数据用 `npm run db:foundation:*` 相关只读或授权脚本。
- 前端体验类改动要结合浏览器实际操作和截图验证;涉及 3D/canvas 时要确认画面非空、尺寸正确、交互可用。
- 生产验证必须包含真实健康检查和日志/PM2/端口等现场证据,不能只说"本地构建通过"。
- 规范审查固定只查三件事:架构有没有被破坏、视觉有没有跑偏、这次是不是根因修复。结论只能是 `passed` / `passed with warnings` / `rejected`;只要架构违规、视觉违规或明显补丁式修复,就必须 `rejected`。非独立复审时必须写明"这是自审,不是独立复审"。统一清单:`furniture-3d-system/docs/workflow/规范审查清单.md`。没有规范审查结论,任务不算完成。
## 9. 敏感信息和交接
- 账号密码、访问密钥、数据库连接串、对象存储密钥等敏感信息只能放在本地安全材料里,不写入 Git、共享文档、普通交接文本或长期记忆;生产域名、PM2 名称、部署目录这类非密钥运行入口可以写进仓库文档,但必须保持最新。
- 仓库内协作文档只写非敏感入口、流程和职责;凭据类信息必须用 `[REDACTED_SECRET]` 或本地路径说明替代。
- 发现摘要、日志或交接文件混有明文凭据时,先提示风险,再决定是否拆成本地敏感版和仓库协作版。
- 给下一个 agent 或同事交接时,写清:本次只改了什么、没改什么、验证跑了什么、风险是什么、下一步要看哪些文件。

View File

@ -1,240 +0,0 @@
# ============================================
# 3D家具安装展示系统 - Docker构建文件
# ============================================
# 基于 flnxi_sucai 项目的 Dockerfile 优化
# 支持本地缓存包,减少网络依赖
# ============================================
# 阶段 1: 基础镜像
# ============================================
FROM node:18-alpine AS base
# 使用阿里云镜像源加速(中国网络优化)
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories
# ============================================
# 阶段 2: 依赖安装 (deps)
# ============================================
FROM base AS deps
# 安装构建时依赖
# Three.js 和 3D 相关包需要的系统依赖
RUN apk add --no-cache --virtual .build-deps \
libc6-compat \
openssl3 \
openssl-dev \
# 3D 图形处理相关依赖
mesa-dev \
mesa-gl \
# 编译工具(用于编译原生模块)
python3 \
make \
g++ \
pkgconfig
WORKDIR /app
# 复制依赖文件(利用 Docker 缓存层)
COPY package.json package-lock.json* ./
# 配置 npm 使用国内镜像源
RUN npm config set registry https://registry.npmmirror.com/
# 尝试使用本地缓存的 node_modules
# 如果本地缓存存在,直接复制;否则通过 npm 安装
COPY local-packages/npm-cache/node_modules* ./node_modules_cache/
RUN if [ -d "./node_modules_cache" ] && [ "$(ls -A ./node_modules_cache)" ]; then \
echo "使用本地缓存的 node_modules" && \
cp -r ./node_modules_cache/* ./node_modules/ 2>/dev/null || true && \
npm ci --prefer-offline --no-audit || npm install --prefer-offline --no-audit; \
else \
echo "本地缓存不可用,从网络安装依赖" && \
npm ci --prefer-offline --no-audit || npm install --prefer-offline --no-audit; \
fi
# 清理构建依赖,保留运行时库
RUN apk del .build-deps && \
npm config delete registry && \
apk add --no-cache \
libc6-compat \
ca-certificates \
openssl3 \
# 3D 渲染运行时库
mesa-gl
# ============================================
# 阶段 3: 构建应用 (builder)
# ============================================
FROM base AS builder
# 构建参数
ARG DATABASE_URL="postgresql://user:password@localhost:5432/placeholder_db?schema=public"
ARG NEXTAUTH_URL=""
ARG NEXT_PUBLIC_APP_URL=""
# Prisma 引擎缓存配置
ARG PRISMA_ENGINE_CACHE_FILE_NAME="libquery_engine-linux-musl-openssl-3.0.x.so.node"
ARG PRISMA_SCHEMA_ENGINE_CACHE_FILE_NAME="schema-engine-linux-musl-openssl-3.0.x"
# 环境变量设置
ENV PRISMA_ENGINE_CACHE_FILE_NAME=${PRISMA_ENGINE_CACHE_FILE_NAME}
ENV PRISMA_SCHEMA_ENGINE_CACHE_FILE_NAME=${PRISMA_SCHEMA_ENGINE_CACHE_FILE_NAME}
ENV DATABASE_URL=${DATABASE_URL}
ENV NEXTAUTH_URL=${NEXTAUTH_URL}
ENV NEXT_PUBLIC_APP_URL=${NEXT_PUBLIC_APP_URL}
ENV NEXT_TELEMETRY_DISABLED=1
ENV NODE_ENV=production
ENV PRISMA_ENGINES_CHECKSUM_IGNORE_MISSING=1
WORKDIR /app
# 安装 OpenSSL 3(Prisma 需要)
RUN apk add --no-cache openssl3
# 从 deps 阶段复制 node_modules
COPY --from=deps /app/node_modules ./node_modules
# 复制应用源代码
COPY . .
# 配置 Prisma 引擎缓存路径
ENV PRISMA_ENGINE_CACHE_PATH=/app/local-packages/prisma-engines/${PRISMA_ENGINE_CACHE_FILE_NAME}
ENV PRISMA_SCHEMA_ENGINE_CACHE_PATH=/app/local-packages/prisma-engines/${PRISMA_SCHEMA_ENGINE_CACHE_FILE_NAME}
# 设置 Prisma 引擎缓存(如果本地缓存存在)
RUN set -ex && \
if [ -f "${PRISMA_ENGINE_CACHE_PATH}" ]; then \
echo "检测到本地 Prisma 查询引擎缓存: ${PRISMA_ENGINE_CACHE_PATH}" && \
PRISMA_ENGINE_VERSION=$(node -p "require('@prisma/engines-version/package.json').prisma.enginesVersion") && \
TARGET_DIR="/root/.cache/prisma/master/${PRISMA_ENGINE_VERSION}/linux-musl-openssl-3.0.x" && \
mkdir -p "${TARGET_DIR}" && \
cp "${PRISMA_ENGINE_CACHE_PATH}" "${TARGET_DIR}/libquery_engine.so.node" && \
gzip -c "${PRISMA_ENGINE_CACHE_PATH}" > "${TARGET_DIR}/libquery_engine.so.node.gz" && \
sha256sum "${TARGET_DIR}/libquery_engine.so.node.gz" | awk '{print $1}' > "${TARGET_DIR}/libquery_engine.so.node.gz.sha256"; \
else \
echo "未找到本地 Prisma 查询引擎缓存,将在线下载"; \
fi && \
if [ -f "${PRISMA_SCHEMA_ENGINE_CACHE_PATH}" ]; then \
echo "检测到本地 Prisma schema 引擎缓存: ${PRISMA_SCHEMA_ENGINE_CACHE_PATH}" && \
PRISMA_ENGINE_VERSION=$(node -p "require('@prisma/engines-version/package.json').prisma.enginesVersion") && \
TARGET_DIR="/root/.cache/prisma/master/${PRISMA_ENGINE_VERSION}/linux-musl-openssl-3.0.x" && \
mkdir -p "${TARGET_DIR}" && \
cp "${PRISMA_SCHEMA_ENGINE_CACHE_PATH}" "${TARGET_DIR}/schema-engine" && \
chmod +x "${TARGET_DIR}/schema-engine" && \
gzip -c "${PRISMA_SCHEMA_ENGINE_CACHE_PATH}" > "${TARGET_DIR}/schema-engine.gz" && \
sha256sum "${TARGET_DIR}/schema-engine.gz" | awk '{print $1}' > "${TARGET_DIR}/schema-engine.gz.sha256"; \
else \
echo "未找到本地 Prisma schema 引擎缓存,将在线下载"; \
fi
# 生成 Prisma Client(构建阶段使用占位 DATABASE_URL,避免 prisma.config.ts 报错)
RUN set -ex && \
export DATABASE_URL="${DATABASE_URL:-postgresql://user:password@localhost:5432/placeholder_db?schema=public}" && \
if [ -f "${PRISMA_ENGINE_CACHE_PATH}" ]; then \
export PRISMA_QUERY_ENGINE_LIBRARY="${PRISMA_ENGINE_CACHE_PATH}" && \
export PRISMA_CLIENT_ENGINE_TYPE=library && \
export PRISMA_CLI_QUERY_ENGINE_TYPE=library && \
echo "使用本地 Prisma 查询引擎缓存生成 Client"; \
else \
echo "使用在线下载的 Prisma 引擎"; \
unset PRISMA_QUERY_ENGINE_LIBRARY PRISMA_CLIENT_ENGINE_TYPE PRISMA_CLI_QUERY_ENGINE_TYPE; \
fi && \
if [ -f "${PRISMA_SCHEMA_ENGINE_CACHE_PATH}" ]; then \
export PRISMA_SCHEMA_ENGINE_BINARY="${PRISMA_SCHEMA_ENGINE_CACHE_PATH}" && \
echo "使用本地 Prisma schema 引擎缓存"; \
else \
unset PRISMA_SCHEMA_ENGINE_BINARY; \
fi && \
if npx prisma generate; then \
echo "Prisma Client 生成成功"; \
else \
echo "Prisma 官方源失败,尝试使用镜像源..." && \
PRISMA_ENGINES_MIRROR="https://registry.npmmirror.com/-/binary/prisma/" npx prisma generate; \
fi
# 验证 Prisma Client 生成
RUN if [ ! -d "node_modules/.prisma" ]; then \
echo "错误: Prisma Client 未生成" >&2 && exit 1; \
fi
# 构建 Next.js 应用(standalone 模式)
RUN set -ex && \
if [ -f "${PRISMA_ENGINE_CACHE_PATH}" ]; then \
export PRISMA_QUERY_ENGINE_LIBRARY="${PRISMA_ENGINE_CACHE_PATH}" && \
export PRISMA_CLIENT_ENGINE_TYPE=library && \
export PRISMA_CLI_QUERY_ENGINE_TYPE=library; \
else \
unset PRISMA_QUERY_ENGINE_LIBRARY PRISMA_CLIENT_ENGINE_TYPE PRISMA_CLI_QUERY_ENGINE_TYPE; \
fi && \
if [ -f "${PRISMA_SCHEMA_ENGINE_CACHE_PATH}" ]; then \
export PRISMA_SCHEMA_ENGINE_BINARY="${PRISMA_SCHEMA_ENGINE_CACHE_PATH}"; \
else \
unset PRISMA_SCHEMA_ENGINE_BINARY; \
fi && \
npm run build
# 验证构建产物
RUN if [ ! -f ".next/standalone/server.js" ]; then \
echo "错误: standalone 输出未生成,请检查 next.config.js" >&2 && \
exit 1; \
fi
# ============================================
# 阶段 4: 生产运行 (runner)
# ============================================
FROM base AS runner
WORKDIR /app
# 设置生产环境变量
ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1
ENV PORT=3000
ENV HOSTNAME="0.0.0.0"
# 安装运行时依赖
RUN apk add --no-cache \
libc6-compat \
ca-certificates \
openssl3 \
# 3D 渲染运行时库
mesa-gl \
# 字体支持(3D 文本渲染)
fontconfig \
ttf-dejavu
# 创建非 root 用户
RUN addgroup --system --gid 1001 nodejs && \
adduser --system --uid 1001 nextjs
# 从 builder 阶段复制构建产物
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
# 复制必要的文件
COPY --from=builder --chown=nextjs:nodejs /app/public ./public
COPY --from=builder --chown=nextjs:nodejs /app/prisma ./prisma
COPY --from=builder --chown=nextjs:nodejs /app/src/lib ./src/lib
# 复制 Prisma 相关文件
COPY --from=builder --chown=nextjs:nodejs /app/node_modules/.prisma ./node_modules/.prisma
COPY --from=builder --chown=nextjs:nodejs /app/node_modules/@prisma ./node_modules/@prisma
COPY --from=builder --chown=nextjs:nodejs /app/node_modules/prisma ./node_modules/prisma
COPY --from=builder --chown=nextjs:nodejs /app/node_modules/.bin ./node_modules/.bin
# 创建上传目录
RUN mkdir -p /app/uploads && \
chown -R nextjs:nodejs /app/uploads && \
chmod -R 755 /app/uploads
# 切换到非 root 用户
USER nextjs
EXPOSE 3000
# 健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -f http://localhost:3000/api/health || exit 1
# 启动应用
CMD ["node", "server.js"]

View File

@ -1,192 +0,0 @@
# ============================================
# 3D家具安装展示系统 - 优化版Dockerfile
# 优先使用本地缓存,支持离线构建
# ============================================
# ============================================
# 阶段 1: 基础镜像
# ============================================
FROM node:18-alpine AS base
# 使用阿里云镜像源加速(中国网络优化)
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories
# 安装基础运行时依赖
RUN apk add --no-cache \
libc6-compat \
ca-certificates \
openssl3
# ============================================
# 阶段 2: 依赖安装 (deps)
# ============================================
FROM base AS deps
# 安装构建时依赖
RUN apk add --no-cache --virtual .build-deps \
python3 \
make \
g++ \
pkgconfig \
openssl-dev
WORKDIR /app
# 复制package文件
COPY package.json package-lock.json* ./
# 检查是否有本地缓存的node_modules
COPY cache/node_modules* ./cache_node_modules/ 2>/dev/null || true
# 配置npm使用国内镜像源
RUN npm config set registry https://registry.npmmirror.com/
# 智能安装依赖:优先使用缓存,然后网络安装
RUN set -ex && \
# 如果有本地缓存,先复制关键包
if [ -d "./cache_node_modules" ]; then \
echo "🔄 发现本地依赖缓存,正在复制..." && \
mkdir -p node_modules && \
# 复制关键包
for pkg in "@prisma" ".prisma" "prisma" "sharp" "next" "react" "react-dom" "@aws-sdk" "three" "gsap"; do \
if [ -d "./cache_node_modules/$pkg" ]; then \
echo "📦 复制缓存包: $pkg" && \
cp -r "./cache_node_modules/$pkg" "./node_modules/" || true; \
fi; \
done; \
fi && \
# 执行npm install(会跳过已存在的包)
echo "📥 安装剩余依赖..." && \
npm ci --prefer-offline --no-audit || npm install --prefer-offline --no-audit
# 清理构建依赖
RUN apk del .build-deps && \
npm config delete registry && \
rm -rf ./cache_node_modules
# ============================================
# 阶段 3: 构建应用 (builder)
# ============================================
FROM base AS builder
# 构建参数
ARG DATABASE_URL=""
ARG NEXTAUTH_URL=""
ARG APP_PUBLIC_URL=""
# 环境变量
ENV DATABASE_URL=${DATABASE_URL}
ENV NEXTAUTH_URL=${NEXTAUTH_URL}
ENV APP_PUBLIC_URL=${APP_PUBLIC_URL}
ENV NEXT_TELEMETRY_DISABLED=1
ENV NODE_ENV=production
WORKDIR /app
# 安装OpenSSL(Prisma需要)
RUN apk add --no-cache openssl3
# 从deps阶段复制node_modules
COPY --from=deps /app/node_modules ./node_modules
# 复制应用源代码
COPY . .
# 复制本地Prisma引擎缓存(如果存在)
COPY cache/prisma-engines* ./prisma/engine-cache/ 2>/dev/null || true
# 配置Prisma引擎缓存路径
ENV PRISMA_ENGINES_CHECKSUM_IGNORE_MISSING=1
ENV PRISMA_ENGINE_CACHE_PATH=/app/prisma/engine-cache/libquery_engine-linux-musl-openssl-3.0.x.so.node
ENV PRISMA_SCHEMA_ENGINE_CACHE_PATH=/app/prisma/engine-cache/schema-engine-linux-musl-openssl-3.0.x
# 智能生成Prisma Client:优先使用本地引擎
RUN set -ex && \
# 检查本地引擎缓存
if [ -f "${PRISMA_ENGINE_CACHE_PATH}" ]; then \
echo "🔧 使用本地Prisma查询引擎缓存" && \
export PRISMA_QUERY_ENGINE_LIBRARY="${PRISMA_ENGINE_CACHE_PATH}" && \
export PRISMA_CLIENT_ENGINE_TYPE=library && \
export PRISMA_CLI_QUERY_ENGINE_TYPE=library; \
else \
echo "⚠️ 本地Prisma引擎缓存不可用,将在线下载"; \
fi && \
if [ -f "${PRISMA_SCHEMA_ENGINE_CACHE_PATH}" ]; then \
echo "🔧 使用本地Prisma schema引擎缓存" && \
export PRISMA_SCHEMA_ENGINE_BINARY="${PRISMA_SCHEMA_ENGINE_CACHE_PATH}"; \
fi && \
# 生成Prisma Client
if npx prisma generate; then \
echo "✅ Prisma Client生成成功"; \
else \
echo "⚠️ 官方源失败,尝试镜像源..." && \
PRISMA_ENGINES_MIRROR="https://registry.npmmirror.com/-/binary/prisma/" npx prisma generate; \
fi
# 构建Next.js应用
RUN set -ex && \
echo "🏗️ 构建Next.js应用..." && \
npm run build && \
echo "✅ 构建完成"
# 验证构建产物
RUN if [ ! -f ".next/standalone/server.js" ]; then \
echo "❌ standalone输出未生成,请检查next.config.js配置" >&2 && \
exit 1; \
fi
# ============================================
# 阶段 4: 生产运行 (runner)
# ============================================
FROM base AS runner
WORKDIR /app
# 生产环境变量
ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1
ENV PORT=3000
ENV HOSTNAME="0.0.0.0"
# 安装运行时依赖
RUN apk add --no-cache \
# 字体支持(3D渲染可能需要)
fontconfig \
ttf-dejavu \
# 图像处理(Sharp需要)
vips-dev
# 创建非root用户
RUN addgroup --system --gid 1001 nodejs && \
adduser --system --uid 1001 nextjs
# 复制构建产物
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
# 复制必要文件
COPY --from=builder --chown=nextjs:nodejs /app/public ./public
COPY --from=builder --chown=nextjs:nodejs /app/prisma ./prisma
# 复制关键运行时模块
COPY --from=builder --chown=nextjs:nodejs /app/node_modules/.prisma ./node_modules/.prisma
COPY --from=builder --chown=nextjs:nodejs /app/node_modules/@prisma ./node_modules/@prisma
COPY --from=builder --chown=nextjs:nodejs /app/node_modules/prisma ./node_modules/prisma
COPY --from=builder --chown=nextjs:nodejs /app/node_modules/.bin ./node_modules/.bin
# 创建上传目录
RUN mkdir -p /app/uploads && \
chown -R nextjs:nodejs /app/uploads && \
chmod -R 755 /app/uploads
# 切换到非root用户
USER nextjs
EXPOSE 3000
# 健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -f http://localhost:3000/api/health || exit 1
# 启动应用
CMD ["node", "server.js"]

View File

@ -1,4 +1,4 @@
# 3D 家具开品平台工作区
# 由壹点「产品开发平台」工作区
> 最后更新:2026-04-07
> 当前主线:`资产中心 -> 自动组合 -> 草稿组 -> 包装方案 -> 正式入库 -> 轻仓库`

View File

@ -20,7 +20,7 @@ namespace FurnitureExporter;
/// </summary>
public class FurnitureExporterApp : IExtensionApplication
{
private const string PluginVersion = "2.5.0";
private const string PluginVersion = "2.6.0";
public void Initialize()
{
@ -30,12 +30,13 @@ public class FurnitureExporterApp : IExtensionApplication
doc?.Editor.WriteMessage($"║ 家具导出插件 v{PluginVersion} 已加载 ║\n");
doc?.Editor.WriteMessage("║ ║\n");
doc?.Editor.WriteMessage("║ 命令: ║\n");
doc?.Editor.WriteMessage("║ FEXPORT - 整套家具兼容导出 ║\n");
doc?.Editor.WriteMessage("║ FEXPORTASSET - 单资产导出到资产中心 ║\n");
doc?.Editor.WriteMessage("║ FEXPORT - 单资产导出到资产中心 ║\n");
doc?.Editor.WriteMessage("║ FEXPORTASSET - 单资产导出别名 ║\n");
doc?.Editor.WriteMessage("║ FEXPORTPRODUCT - 整套家具兼容导出 ║\n");
doc?.Editor.WriteMessage("║ FINFO - 查看选中实体信息 ║\n");
doc?.Editor.WriteMessage("║ ║\n");
doc?.Editor.WriteMessage($"║ v{PluginVersion} 新功能: ║\n");
doc?.Editor.WriteMessage("║ · 新增资产中心单资产导出模式 ║\n");
doc?.Editor.WriteMessage("║ · 默认进入资产中心单资产导出 ║\n");
doc?.Editor.WriteMessage("║ · 新增 assembly 装配语义导出层 ║\n");
doc?.Editor.WriteMessage("║ · 语义优先用孔位/五金/配合面推导 ║\n");
doc?.Editor.WriteMessage("║ · 安装顺序仍保留给 Web 端人工设定 ║\n");
@ -54,7 +55,7 @@ public class FurnitureExporterApp : IExtensionApplication
/// </summary>
public class Commands
{
private const string PluginVersion = "2.5.0";
private const string PluginVersion = "2.6.0";
private sealed class SingleAssetExportMode
{
@ -71,6 +72,9 @@ public class Commands
public List<PanelInfo> Panels { get; } = new();
public List<HoleInfo> Holes { get; } = new();
public List<HoleGroupInfo> HoleGroups { get; } = new();
public List<MountPatternInfo> MountPatterns { get; } = new();
public List<MountPatternInfo> SnapPatterns { get; } = new();
public List<SnapSurfaceInfo> SnapSurfaces { get; } = new();
public int LogicalHoleCount { get; set; }
public List<EdgeFeatureInfo> EdgeFeatures { get; } = new();
public List<ExcludedHoleInfo> ExcludedHoles { get; } = new();
@ -336,6 +340,9 @@ public class Commands
var holeGroups = HoleGrouping.BuildEccentricScrewGroups(allHoles);
HoleGrouping.AttachGroupsToPanels(panels, holeGroups);
var mountPatterns = MountPatternAnalyzer.BuildMountPatterns(panels, allHoles, holeGroups);
MountPatternAnalyzer.AttachPatternsToPanels(panels, mountPatterns);
var snapSurfaces = SnapSurfaceBuilder.BuildSnapSurfaces(panels);
var logicalHoleCount = HoleGrouping.ComputeLogicalHoleCount(allHoles);
foreach (var hole in allHoles)
@ -353,6 +360,9 @@ public class Commands
result.Holes.AddRange(allHoles);
result.HoleGroups.AddRange(holeGroups);
result.MountPatterns.AddRange(mountPatterns);
result.SnapPatterns.AddRange(mountPatterns);
result.SnapSurfaces.AddRange(snapSurfaces);
result.LogicalHoleCount = logicalHoleCount;
result.EdgeFeatures.AddRange(allEdgeFeatures);
result.ExcludedHoles.AddRange(panelAnalyzer.ExcludedHoles);
@ -363,7 +373,7 @@ public class Commands
/// <summary>
/// 主导出命令 - 导出板材 GLB + 五金件位置 JSON
/// </summary>
[CommandMethod("FEXPORT")]
[CommandMethod("FEXPORTPRODUCT")]
public void ExportFurniture()
{
var doc = AcApp.DocumentManager.MdiActiveDocument;
@ -405,7 +415,7 @@ public class Commands
ed.WriteMessage(" 1. 输入命令 UNITS 打开单位设置\n");
ed.WriteMessage(" 2. 将 '插入时的缩放单位' 改为 '毫米'\n");
ed.WriteMessage(" 3. 点击确定\n");
ed.WriteMessage(" 4. 重新运行 FEXPORT 命令\n");
ed.WriteMessage(" 4. 重新运行 FEXPORTPRODUCT 命令\n");
ed.WriteMessage("\n");
// 询问是否继续(仅供高级用户)
@ -445,7 +455,7 @@ public class Commands
panelIds = FilterSolids(panelIds, db);
if (panelIds.Length == 0)
{
ed.WriteMessage(" ⚠️ 无法恢复板材(可能图纸已变更/实体被删除)。已清除会话,请重新运行 FEXPORT。\n");
ed.WriteMessage(" ⚠️ 无法恢复板材(可能图纸已变更/实体被删除)。已清除会话,请重新运行 FEXPORTPRODUCT。\n");
ExportSessionManager.Clear(docKey);
return;
}
@ -546,7 +556,7 @@ public class Commands
ed.WriteMessage($" ✓ 已记录 {panelIds.Length} 个板材\n");
ed.WriteMessage("\n 你现在可以自由调整图层显示/冻结/隔离等操作。\n");
ed.WriteMessage(" 调整完成后,再次运行 FEXPORT 继续第 2 步(选五金并导出)。\n");
ed.WriteMessage(" 调整完成后,再次运行 FEXPORTPRODUCT 继续第 2 步(选五金并导出)。\n");
var proceedOpt = new PromptKeywordOptions(
"\n是否现在直接继续第 2 步? [继续(C)/稍后(R)]",
@ -558,7 +568,7 @@ public class Commands
if (proceedResult.Status != PromptStatus.OK || proceedResult.StringResult != "Continue")
{
ed.WriteMessage("\n已暂停导出。提示:再次运行 FEXPORT 继续;运行 FEXPORTRESET 可清除暂存。\n");
ed.WriteMessage("\n已暂停导出。提示:再次运行 FEXPORTPRODUCT 继续;运行 FEXPORTRESET 可清除暂存。\n");
return;
}
}
@ -683,6 +693,9 @@ public class Commands
// 2) 偏心孔位分组:把“主孔+侧孔”合并为 1 个逻辑孔位(不改变 holes 的几何数据,仅提供分组与逻辑计数)
var holeGroups = HoleGrouping.BuildEccentricScrewGroups(allHoles);
HoleGrouping.AttachGroupsToPanels(panels, holeGroups);
var mountPatterns = MountPatternAnalyzer.BuildMountPatterns(panels, allHoles, holeGroups);
MountPatternAnalyzer.AttachPatternsToPanels(panels, mountPatterns);
var snapSurfaces = SnapSurfaceBuilder.BuildSnapSurfaces(panels);
var logicalHoleCount = HoleGrouping.ComputeLogicalHoleCount(allHoles);
@ -729,6 +742,9 @@ public class Commands
exportData.Panels = panels;
exportData.Holes = allHoles;
exportData.HoleGroups = holeGroups;
exportData.MountPatterns = mountPatterns;
exportData.SnapPatterns = mountPatterns;
exportData.SnapSurfaces = snapSurfaces;
exportData.LogicalHoleCount = logicalHoleCount;
if (panelAnalyzer.ExcludedHoles.Count > 0)
@ -842,8 +858,25 @@ public class Commands
}
}
[CommandMethod("FEXPORTBUNDLE")]
public void ExportFurnitureBundle()
{
ExportFurniture();
}
[CommandMethod("FEXPORT")]
public void ExportAssetDefault()
{
ExportSingleAssetCore();
}
[CommandMethod("FEXPORTASSET")]
public void ExportSingleAsset()
{
ExportSingleAssetCore();
}
private void ExportSingleAssetCore()
{
var doc = AcApp.DocumentManager.MdiActiveDocument;
if (doc == null)
@ -985,6 +1018,9 @@ public class Commands
exportData.Panels = panelAnalysis.Panels;
exportData.Holes = panelAnalysis.Holes;
exportData.HoleGroups = panelAnalysis.HoleGroups;
exportData.MountPatterns = panelAnalysis.MountPatterns;
exportData.SnapPatterns = panelAnalysis.SnapPatterns;
exportData.SnapSurfaces = panelAnalysis.SnapSurfaces;
exportData.LogicalHoleCount = panelAnalysis.LogicalHoleCount;
exportData.EdgeFeatures = panelAnalysis.EdgeFeatures;
exportData.PanelCount = panelAnalysis.Panels.Count;
@ -1024,21 +1060,11 @@ public class Commands
if (mode.AnalyzePanels && panelAnalysis.Panels.Count > 0)
{
ed.WriteMessage(" [4/5] 生成装配语义...");
var assemblyAnalyzer = new AssemblySemanticAnalyzer();
exportData.Assembly = assemblyAnalyzer.Analyze(
panelAnalysis.Panels,
panelAnalysis.Holes,
panelAnalysis.HoleGroups,
exportData.HardwareTypes);
var highConfidenceCount = exportData.Assembly.PanelAssemblies.Count(item =>
item.Confidence >= 0.75 &&
!string.Equals(item.MountMode, "unknown", StringComparison.OrdinalIgnoreCase));
ed.WriteMessage($" ✓ ({exportData.Assembly.PanelAssemblies.Count} 个板件语义, {highConfidenceCount} 个高置信)\n");
ed.WriteMessage(" [4/5] 跳过旧装配语义... ✓ (single_asset 使用 snapPatterns/snapSurfaces)\n");
}
else
{
ed.WriteMessage(" [4/5] 生成装配语义... ✓ (当前模式无需生成)\n");
ed.WriteMessage(" [4/5] 跳过旧装配语义... ✓ (当前模式无需生成)\n");
}
ed.WriteMessage(" [5/5] 打包文件...");
@ -1108,7 +1134,7 @@ public class Commands
var ed = doc.Editor;
var docKey = string.IsNullOrWhiteSpace(doc.Name) ? "Untitled" : doc.Name;
ExportSessionManager.Clear(docKey);
ed.WriteMessage("\n已清除 FEXPORT 暂存会话。请重新运行 FEXPORT。\n");
ed.WriteMessage("\n已清除整套兼容导出暂存会话。请重新运行 FEXPORTPRODUCT。\n");
}
private static List<string> GetEntityHandles(Database db, ObjectId[] ids)

View File

@ -1,229 +1,236 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;
using Xunit;
namespace FurnitureExporter.Tests;
public class AssemblySemanticAnalyzerTests
namespace FurnitureExporter.Tests
{
[Fact]
public void Analyze_BuildsAssemblySection_AndDoesNotEmitInstallOrderFields()
public class AssemblySemanticAnalyzerTests
{
var exportData = new ExportData
[Fact]
public void Analyze_BuildsAssemblySection_AndDoesNotEmitInstallOrderFields()
{
Panels = new List<PanelInfo>
var exportData = new ExportData
{
Panels = new List<PanelInfo>
{
CreatePanel(
"panel_001",
"side_panel",
new[] { 9.0, 280.0, 360.0 },
new[] { 1.0, 0.0, 0.0 },
new[] { 0.0, 0.0, 0.0 },
new[] { 18.0, 560.0, 720.0 }),
CreatePanel(
"panel_002",
"shelf",
new[] { 200.0, 280.0, 359.0 },
new[] { 0.0, 0.0, 1.0 },
new[] { 18.0, 0.0, 350.0 },
new[] { 382.0, 560.0, 368.0 }),
},
};
exportData.Assembly = new AssemblySemanticAnalyzer().Analyze(
exportData.Panels,
exportData.Holes,
exportData.HoleGroups,
exportData.HardwareTypes);
var json = JsonConvert.SerializeObject(
exportData,
new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver(),
NullValueHandling = NullValueHandling.Ignore,
});
var root = JObject.Parse(json);
Assert.Equal("1.0", root["assembly"]?["version"]?.Value<string>());
Assert.NotNull(root["assembly"]?["panelAssemblies"]);
Assert.NotNull(root["assembly"]?["connections"]);
Assert.DoesNotContain("installOrder", json, StringComparison.OrdinalIgnoreCase);
}
[Fact]
public void Analyze_PrefersHardwareRelation_ForConnectedPanel()
{
var panels = new List<PanelInfo>
{
CreatePanel(
"panel_001",
"side_panel",
position: new[] { 9.0, 280.0, 360.0 },
normal: new[] { 1.0, 0.0, 0.0 },
boundingBoxMin: new[] { 0.0, 0.0, 0.0 },
boundingBoxMax: new[] { 18.0, 560.0, 720.0 }),
new[] { 9.0, 280.0, 360.0 },
new[] { 1.0, 0.0, 0.0 },
new[] { 0.0, 0.0, 0.0 },
new[] { 18.0, 560.0, 720.0 }),
CreatePanel(
"panel_002",
"shelf",
position: new[] { 200.0, 280.0, 359.0 },
normal: new[] { 0.0, 0.0, 1.0 },
boundingBoxMin: new[] { 18.0, 0.0, 350.0 },
boundingBoxMax: new[] { 382.0, 560.0, 368.0 }),
},
};
new[] { 200.0, 280.0, 359.0 },
new[] { 0.0, 0.0, 1.0 },
new[] { 18.0, 0.0, 350.0 },
new[] { 382.0, 560.0, 368.0 }),
};
exportData.Assembly = AssemblySemanticAnalyzer.Analyze(
exportData.Panels,
exportData.Holes,
exportData.HoleGroups,
exportData.HardwareTypes);
var json = JsonConvert.SerializeObject(
exportData,
new JsonSerializerSettings
var holes = new List<HoleInfo>
{
ContractResolver = new CamelCasePropertyNamesContractResolver(),
NullValueHandling = NullValueHandling.Ignore,
});
var root = JObject.Parse(json);
Assert.Equal("1.0", root["assembly"]?["version"]?.Value<string>());
Assert.NotNull(root["assembly"]?["panelAssemblies"]);
Assert.NotNull(root["assembly"]?["connections"]);
Assert.DoesNotContain("installOrder", json, System.StringComparison.OrdinalIgnoreCase);
}
[Fact]
public void Analyze_PrefersHoleGroupAndHardwareEvidence_OverPanelTypeFallback()
{
var panels = new List<PanelInfo>
{
CreatePanel(
"panel_001",
"side_panel",
position: new[] { 9.0, 280.0, 360.0 },
normal: new[] { 1.0, 0.0, 0.0 },
boundingBoxMin: new[] { 0.0, 0.0, 0.0 },
boundingBoxMax: new[] { 18.0, 560.0, 720.0 }),
CreatePanel(
"panel_002",
"shelf",
position: new[] { 200.0, 280.0, 359.0 },
normal: new[] { 0.0, 0.0, 1.0 },
boundingBoxMin: new[] { 18.0, 0.0, 350.0 },
boundingBoxMax: new[] { 382.0, 560.0, 368.0 }),
};
var holes = new List<HoleInfo>
{
new()
{
Id = "panel_001_hole_001",
PanelId = "panel_001",
Position = new[] { 9.0, 260.0, 360.0 },
Normal = new[] { 1.0, 0.0, 0.0 },
Diameter = 15.0,
Radius = 7.5,
Depth = 12.0,
Type = "blind",
},
new()
{
Id = "panel_001_hole_002",
PanelId = "panel_001",
Position = new[] { 16.0, 260.0, 360.0 },
Normal = new[] { 0.0, 1.0, 0.0 },
Diameter = 8.0,
Radius = 4.0,
Depth = 10.0,
Type = "blind",
},
};
var holeGroups = new List<HoleGroupInfo>
{
new()
{
Id = "panel_001_group_000",
PanelId = "panel_001",
GroupType = "eccentric_screw",
HoleIds = new[] { "panel_001_hole_001", "panel_001_hole_002" },
Position = new[] { 9.0, 260.0, 360.0 },
Normal = new[] { 1.0, 0.0, 0.0 },
Confidence = 0.96,
Reason = "偏心件孔组",
},
};
panels[0].Holes = holes.ToList();
panels[0].HoleGroups = holeGroups.ToList();
var hardwareTypes = new List<HardwareType>
{
new()
{
TypeId = "type_000",
InferredHardwareType = "connector",
Instances = new List<HardwareInstance>
new HoleInfo
{
new()
Id = "panel_001_hole_001",
PanelId = "panel_001",
Position = new[] { 9.0, 260.0, 360.0 },
Normal = new[] { 1.0, 0.0, 0.0 },
Diameter = 15.0,
Radius = 7.5,
Depth = 12.0,
Type = "blind",
},
new HoleInfo
{
Id = "panel_001_hole_002",
PanelId = "panel_001",
Position = new[] { 16.0, 260.0, 360.0 },
Normal = new[] { 0.0, 1.0, 0.0 },
Diameter = 8.0,
Radius = 4.0,
Depth = 10.0,
Type = "blind",
},
};
var holeGroups = new List<HoleGroupInfo>
{
new HoleGroupInfo
{
Id = "panel_001_group_000",
PanelId = "panel_001",
GroupType = "eccentric_screw",
HoleIds = new[] { "panel_001_hole_001", "panel_001_hole_002" },
Position = new[] { 9.0, 260.0, 360.0 },
Normal = new[] { 1.0, 0.0, 0.0 },
Confidence = 0.96,
Reason = "偏心件孔组",
},
};
panels[0].Holes = holes.ToList();
panels[0].HoleGroups = holeGroups.ToList();
var hardwareTypes = new List<HardwareType>
{
new HardwareType
{
TypeId = "type_000",
InferredHardwareType = "connector",
Instances = new List<HardwareInstance>
{
Position = new Position3D { X = 12.0, Y = 260.0, Z = 360.0 },
PrimaryPanelId = "panel_001",
SecondaryPanelId = "panel_002",
BoundHoleGroupId = "panel_001_group_000",
BoundHoleIds = new[] { "panel_001_hole_001", "panel_001_hole_002" },
BindingMode = "hole_group",
BindingConfidence = 0.97,
BindingReason = "优先按孔组绑定",
NearbyPanelIds = new[] { "panel_001", "panel_002" },
new HardwareInstance
{
Position = new Position3D { X = 12.0, Y = 260.0, Z = 360.0 },
PrimaryPanelId = "panel_001",
SecondaryPanelId = "panel_002",
BoundHoleGroupId = "panel_001_group_000",
BoundHoleIds = new[] { "panel_001_hole_001", "panel_001_hole_002" },
BindingMode = "hole_group",
BindingConfidence = 0.97,
BindingReason = "优先按孔组绑定",
NearbyPanelIds = new[] { "panel_001", "panel_002" },
},
},
},
},
};
};
var assembly = AssemblySemanticAnalyzer.Analyze(panels, holes, holeGroups, hardwareTypes);
var panelAssembly = Assert.Single(assembly.PanelAssemblies.Where(item => item.PanelId == "panel_001"));
var assembly = new AssemblySemanticAnalyzer().Analyze(panels, holes, holeGroups, hardwareTypes);
var connection = Assert.Single(
assembly.Connections.Where(item =>
item.SourcePanelId == "panel_001" &&
item.TargetPanelId == "panel_002"));
var panelAssembly = Assert.Single(assembly.PanelAssemblies.Where(item => item.PanelId == "panel_001"));
Assert.Equal("connector_lock", panelAssembly.MountMode);
Assert.Equal("panel_002", panelAssembly.PrimarySupportPanelId);
Assert.Contains("panel_002", panelAssembly.TargetPanelIds);
Assert.Contains("panel_002", panelAssembly.DependsOn);
Assert.Contains(panelAssembly.Mates, mate => mate.MateType == "hole_group_hardware" && mate.HoleGroupId == "panel_001_group_000");
Assert.True(panelAssembly.Confidence >= 0.9);
Assert.DoesNotContain(panelAssembly.Warnings, warning => warning.Contains("仅按 panelType", System.StringComparison.OrdinalIgnoreCase));
}
Assert.Equal("hole_group_hardware", connection.ConnectionType);
Assert.Equal("slide_in", panelAssembly.MountMode);
Assert.Equal("left", panelAssembly.AssemblyDirection);
Assert.Equal("panel_002", panelAssembly.PrimarySupportPanelId);
Assert.Contains("panel_002", panelAssembly.TargetPanelIds);
Assert.Contains("panel_002", panelAssembly.DependsOn);
Assert.Contains("panel_002", panelAssembly.Mates.Right ?? new List<string>());
Assert.True(panelAssembly.Confidence >= 0.75);
}
[Fact]
public void Analyze_FallsBackToFaceMate_WhenNoHardwareBindingExists()
{
var panels = new List<PanelInfo>
[Fact]
public void Analyze_FallsBackToShelfDirection_WhenNoHardwareBindingExists()
{
CreatePanel(
"panel_left",
"side_panel",
position: new[] { 9.0, 280.0, 360.0 },
normal: new[] { 1.0, 0.0, 0.0 },
boundingBoxMin: new[] { 0.0, 0.0, 0.0 },
boundingBoxMax: new[] { 18.0, 560.0, 720.0 }),
CreatePanel(
"panel_right",
"side_panel",
position: new[] { 391.0, 280.0, 360.0 },
normal: new[] { 1.0, 0.0, 0.0 },
boundingBoxMin: new[] { 382.0, 0.0, 0.0 },
boundingBoxMax: new[] { 400.0, 560.0, 720.0 }),
CreatePanel(
"panel_shelf",
"shelf",
position: new[] { 200.0, 280.0, 359.0 },
normal: new[] { 0.0, 0.0, 1.0 },
boundingBoxMin: new[] { 18.0, 0.0, 350.0 },
boundingBoxMax: new[] { 382.0, 560.0, 368.0 }),
};
var panels = new List<PanelInfo>
{
CreatePanel(
"panel_left",
"side_panel",
new[] { 9.0, 280.0, 360.0 },
new[] { 1.0, 0.0, 0.0 },
new[] { 0.0, 0.0, 0.0 },
new[] { 18.0, 560.0, 720.0 }),
CreatePanel(
"panel_right",
"side_panel",
new[] { 391.0, 280.0, 360.0 },
new[] { 1.0, 0.0, 0.0 },
new[] { 382.0, 0.0, 0.0 },
new[] { 400.0, 560.0, 720.0 }),
CreatePanel(
"panel_shelf",
"shelf",
new[] { 200.0, 280.0, 359.0 },
new[] { 0.0, 0.0, 1.0 },
new[] { 18.0, 0.0, 350.0 },
new[] { 382.0, 560.0, 368.0 }),
};
var assembly = AssemblySemanticAnalyzer.Analyze(
panels,
new List<HoleInfo>(),
new List<HoleGroupInfo>(),
new List<HardwareType>());
var assembly = new AssemblySemanticAnalyzer().Analyze(
panels,
new List<HoleInfo>(),
new List<HoleGroupInfo>(),
new List<HardwareType>());
var shelf = Assert.Single(assembly.PanelAssemblies.Where(item => item.PanelId == "panel_shelf"));
var shelf = Assert.Single(assembly.PanelAssemblies.Where(item => item.PanelId == "panel_shelf"));
Assert.Equal("slot_insert", shelf.MountMode);
Assert.Contains("panel_left", shelf.TargetPanelIds);
Assert.Contains("panel_right", shelf.TargetPanelIds);
Assert.Contains(shelf.Mates, mate => mate.MateType == "face_contact");
Assert.True(shelf.TravelDistance > 0);
Assert.True(System.Math.Abs(shelf.AssemblyAxis[0]) > 0.9);
}
Assert.Equal("drop_in", shelf.MountMode);
Assert.Equal("top", shelf.AssemblyDirection);
Assert.Contains("panel_left", shelf.TargetPanelIds);
Assert.Contains("panel_right", shelf.TargetPanelIds);
Assert.Contains("panel_left", shelf.Mates.Left ?? new List<string>());
Assert.Contains("panel_right", shelf.Mates.Right ?? new List<string>());
Assert.True(shelf.TravelDistance > 0);
}
private static PanelInfo CreatePanel(
string id,
string panelType,
double[] position,
double[] normal,
double[] boundingBoxMin,
double[] boundingBoxMax)
{
return new PanelInfo
private static PanelInfo CreatePanel(
string id,
string panelType,
double[] position,
double[] normal,
double[] boundingBoxMin,
double[] boundingBoxMax)
{
Id = id,
PanelType = panelType,
Position = position,
Normal = normal,
BoundingBox = new BoundingBox3D
return new PanelInfo
{
Min = boundingBoxMin,
Max = boundingBoxMax,
},
Size = new[]
{
System.Math.Round(boundingBoxMax[0] - boundingBoxMin[0], 2),
System.Math.Round(boundingBoxMax[1] - boundingBoxMin[1], 2),
System.Math.Round(boundingBoxMax[2] - boundingBoxMin[2], 2),
},
};
Id = id,
PanelType = panelType,
Position = position,
Normal = normal,
BoundingBox = new BoundingBox3D
{
Min = boundingBoxMin,
Max = boundingBoxMax,
},
Size = new[]
{
Math.Round(boundingBoxMax[0] - boundingBoxMin[0], 2),
Math.Round(boundingBoxMax[1] - boundingBoxMin[1], 2),
Math.Round(boundingBoxMax[2] - boundingBoxMin[2], 2),
},
};
}
}
}

View File

@ -0,0 +1,42 @@
using System;
using System.IO;
using System.Text.RegularExpressions;
namespace FurnitureExporter.Tests
{
public class CommandRegistrationTests
{
[Fact]
public void Fexport_DefaultsToSingleAssetExport()
{
var source = ReadCommandsSource();
Assert.Matches(CommandMethodPattern("FEXPORT", "ExportAssetDefault"), source);
Assert.Matches(CommandMethodPattern("FEXPORTASSET", "ExportSingleAsset"), source);
Assert.DoesNotMatch(CommandMethodPattern("FEXPORT", "ExportFurniture"), source);
}
[Fact]
public void LegacyProductBundleExport_UsesExplicitCompatibilityCommands()
{
var source = ReadCommandsSource();
Assert.Matches(CommandMethodPattern("FEXPORTPRODUCT", "ExportFurniture"), source);
Assert.Matches(CommandMethodPattern("FEXPORTBUNDLE", "ExportFurnitureBundle"), source);
}
private static string ReadCommandsSource()
{
var path = Path.GetFullPath(
Path.Combine(AppContext.BaseDirectory, @"..\..\..\..\Commands.cs"));
return File.ReadAllText(path);
}
private static Regex CommandMethodPattern(string commandName, string methodName)
{
return new Regex(
$@"\[CommandMethod\(""{Regex.Escape(commandName)}""\)\]\s+public\s+void\s+{Regex.Escape(methodName)}\s*\(",
RegexOptions.Multiline);
}
}
}

View File

@ -0,0 +1,89 @@
using System.Collections.Generic;
using System.Linq;
namespace FurnitureExporter.Tests
{
public class MountPatternAnalyzerTests
{
[Fact]
public void BuildMountPatterns_ForTwoHoleLine_RequiresTwoHoles()
{
var panel = CreatePanel("panel_line");
var holes = new List<HoleInfo>
{
CreateHole("hole_a", "panel_line", new[] { -40.0, 0.0, 0.0 }, new[] { 0.0, -1.0, 0.0 }, new[] { "top" }),
CreateHole("hole_b", "panel_line", new[] { 40.0, 0.0, 0.0 }, new[] { 0.0, -1.0, 0.0 }, new[] { "top" }),
};
var patterns = MountPatternAnalyzer.BuildMountPatterns(
new[] { panel },
holes,
new List<HoleGroupInfo>());
var pattern = Assert.Single(patterns);
Assert.Equal("line_2", pattern.PatternType);
Assert.Equal(2, pattern.MinRequiredHoles);
Assert.Equal(2, pattern.PreferredHoleCount);
Assert.Single(panel.SnapPatterns);
Assert.Equal(panel.MountPatterns, panel.SnapPatterns);
}
[Fact]
public void BuildMountPatterns_ForSymmetricRectangle_DefaultsToTwoRequiredHoles()
{
var panel = CreatePanel("panel_rect");
var holes = new List<HoleInfo>
{
CreateHole("hole_a", "panel_rect", new[] { -40.0, 0.0, -20.0 }, new[] { 0.0, -1.0, 0.0 }, new[] { "top" }),
CreateHole("hole_b", "panel_rect", new[] { 40.0, 0.0, -20.0 }, new[] { 0.0, -1.0, 0.0 }, new[] { "top" }),
CreateHole("hole_c", "panel_rect", new[] { -40.0, 0.0, 20.0 }, new[] { 0.0, -1.0, 0.0 }, new[] { "top" }),
CreateHole("hole_d", "panel_rect", new[] { 40.0, 0.0, 20.0 }, new[] { 0.0, -1.0, 0.0 }, new[] { "top" }),
};
var patterns = MountPatternAnalyzer.BuildMountPatterns(
new[] { panel },
holes,
new List<HoleGroupInfo>());
var pattern = Assert.Single(patterns);
Assert.Equal("rectangle_4", pattern.PatternType);
Assert.Equal(2, pattern.MinRequiredHoles);
Assert.Equal(4, pattern.PreferredHoleCount);
Assert.True(pattern.Symmetry);
Assert.Empty(pattern.RequiredHoleIds);
Assert.Equal(4, pattern.OptionalHoleIds.Length);
}
private static PanelInfo CreatePanel(string id)
{
return new PanelInfo
{
Id = id,
Position = new[] { 0.0, 0.0, 0.0 },
Normal = new[] { 0.0, 1.0, 0.0 },
BoundingBox = new BoundingBox3D
{
Min = new[] { -300.0, -9.0, -300.0 },
Max = new[] { 300.0, 9.0, 300.0 },
},
Size = new[] { 600.0, 18.0, 600.0 },
};
}
private static HoleInfo CreateHole(string id, string panelId, double[] position, double[] normal, string[] surfaceFaces)
{
return new HoleInfo
{
Id = id,
PanelId = panelId,
Position = position,
Normal = normal,
Diameter = 8.0,
Radius = 4.0,
Depth = 12.0,
Type = "blind",
SurfaceFaces = surfaceFaces,
};
}
}
}

View File

@ -0,0 +1,73 @@
namespace FurnitureExporter.Tests
{
public class PanelFaceSemanticResolverTests
{
[Fact]
public void ResolveSurfaceFaces_ForThroughHole_ReturnsOppositeFaces()
{
var faces = PanelFaceSemanticResolver.ResolveSurfaceFaces(
new BoundingBox3D
{
Min = new[] { 0.0, 0.0, 0.0 },
Max = new[] { 18.0, 560.0, 720.0 },
},
new[] { 9.0, 280.0, 360.0 },
new[] { 1.0, 0.0, 0.0 },
18.0);
Assert.Contains("left", faces);
Assert.Contains("right", faces);
}
[Fact]
public void ResolveSurfaceFaces_ForBlindHole_ReturnsSingleExteriorFace()
{
var faces = PanelFaceSemanticResolver.ResolveSurfaceFaces(
new BoundingBox3D
{
Min = new[] { 0.0, 0.0, 0.0 },
Max = new[] { 18.0, 560.0, 720.0 },
},
new[] { 4.0, 280.0, 360.0 },
new[] { 1.0, 0.0, 0.0 },
8.0);
Assert.Single(faces);
Assert.Equal("left", faces[0]);
}
[Fact]
public void ResolveSurfaceFaces_ForTopBottomThroughHole_ReturnsTopAndBottom()
{
var faces = PanelFaceSemanticResolver.ResolveSurfaceFaces(
new BoundingBox3D
{
Min = new[] { 0.0, 0.0, 0.0 },
Max = new[] { 600.0, 720.0, 18.0 },
},
new[] { 300.0, 360.0, 9.0 },
new[] { 0.0, 0.0, 1.0 },
18.0);
Assert.Contains("top", faces);
Assert.Contains("bottom", faces);
}
[Fact]
public void ResolveSurfaceFaces_ForSideBlindHole_PrefersSingleSideFace()
{
var faces = PanelFaceSemanticResolver.ResolveSurfaceFaces(
new BoundingBox3D
{
Min = new[] { 0.0, 0.0, 0.0 },
Max = new[] { 600.0, 18.0, 720.0 },
},
new[] { 300.0, 4.0, 360.0 },
new[] { 0.0, 1.0, 0.0 },
8.0);
Assert.Single(faces);
Assert.Equal("front", faces[0]);
}
}
}

View File

@ -0,0 +1,103 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;
namespace FurnitureExporter.Tests
{
public class SnapSurfaceBuilderTests
{
[Fact]
public void BuildSnapSurfaces_FromBoundingBox_CreatesSixAxisFaces()
{
var panel = CreatePanel("panel_001");
var surfaces = SnapSurfaceBuilder.BuildSnapSurfaces(new[] { panel });
Assert.Equal(6, surfaces.Count);
Assert.Equal(6, panel.SnapSurfaces.Count);
var top = Assert.Single(surfaces.Where(surface => surface.Face == "top"));
Assert.Equal("panel_001_snap_top", top.Id);
Assert.Equal("panel_001", top.PanelId);
Assert.Equal(new[] { 0.0, 0.0, 1.0 }, top.Normal);
Assert.Equal(new[] { 0.0, 0.0, 18.0 }, top.Center);
Assert.Equal(18.0, top.Bounds.Min[2]);
Assert.Equal(18.0, top.Bounds.Max[2]);
Assert.Equal(1.0, top.Confidence);
var front = Assert.Single(surfaces.Where(surface => surface.Face == "front"));
Assert.Equal(new[] { 0.0, -1.0, 0.0 }, front.Normal);
Assert.Equal(-280.0, front.Center[1]);
Assert.Equal(-280.0, front.Bounds.Min[1]);
Assert.Equal(-280.0, front.Bounds.Max[1]);
}
[Fact]
public void ExportData_ForSingleAsset_EmitsSnapFieldsAndOmitsAssembly()
{
var panel = CreatePanel("panel_001");
var pattern = new MountPatternInfo
{
Id = "panel_001_mount_top_000",
PanelId = "panel_001",
MountFace = "top",
PatternType = "line_2",
HoleIds = new[] { "hole_a", "hole_b" },
RequiredHoleIds = new[] { "hole_a", "hole_b" },
MinRequiredHoles = 2,
PreferredHoleCount = 2,
Normal = new[] { 0.0, 0.0, 1.0 },
Position = new[] { 0.0, 0.0, 18.0 },
Confidence = 0.95,
};
panel.MountPatterns = new List<MountPatternInfo> { pattern };
panel.SnapPatterns = panel.MountPatterns;
var exportData = new ExportData
{
ExportMode = "single_asset",
Panels = new List<PanelInfo> { panel },
MountPatterns = new List<MountPatternInfo> { pattern },
SnapPatterns = new List<MountPatternInfo> { pattern },
SnapSurfaces = SnapSurfaceBuilder.BuildSnapSurfaces(new[] { panel }),
};
var json = JsonConvert.SerializeObject(
exportData,
new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver(),
NullValueHandling = NullValueHandling.Ignore,
});
var root = JObject.Parse(json);
Assert.Null(root["assembly"]);
Assert.DoesNotContain("\"mates\"", json, StringComparison.OrdinalIgnoreCase);
Assert.DoesNotContain("\"connections\"", json, StringComparison.OrdinalIgnoreCase);
Assert.Single(Assert.IsType<JArray>(root["mountPatterns"]));
Assert.Single(Assert.IsType<JArray>(root["snapPatterns"]));
Assert.Equal(6, Assert.IsType<JArray>(root["snapSurfaces"]).Count);
var panels = Assert.IsType<JArray>(root["panels"]);
Assert.Equal(6, Assert.IsType<JArray>(panels[0]?["snapSurfaces"]).Count);
}
private static PanelInfo CreatePanel(string id)
{
return new PanelInfo
{
Id = id,
Position = new[] { 0.0, 0.0, 9.0 },
Normal = new[] { 0.0, 0.0, 1.0 },
BoundingBox = new BoundingBox3D
{
Min = new[] { -300.0, -280.0, 0.0 },
Max = new[] { 300.0, 280.0, 18.0 },
},
Size = new[] { 600.0, 560.0, 18.0 },
};
}
}
}

View File

@ -11,7 +11,7 @@
<!-- AutoCAD 2024 插件配置 -->
<AssemblyName>FurnitureExporter</AssemblyName>
<RootNamespace>FurnitureExporter</RootNamespace>
<Version>2.5.0</Version>
<Version>2.6.0</Version>
<Authors>Furniture 3D System</Authors>
<Description>家具 3D 模型导出插件 - 导出 GLB 模型和五金件位置数据</Description>

View File

@ -162,6 +162,31 @@ public class HoleDetector
{
try
{
BoundingBox3D? panelBoundingBox = null;
try
{
var ext = solid.GeometricExtents;
panelBoundingBox = new BoundingBox3D
{
Min = new[]
{
Math.Round(ext.MinPoint.X + _originOffset.X, 2),
Math.Round(ext.MinPoint.Y + _originOffset.Y, 2),
Math.Round(ext.MinPoint.Z + _originOffset.Z, 2),
},
Max = new[]
{
Math.Round(ext.MaxPoint.X + _originOffset.X, 2),
Math.Round(ext.MaxPoint.Y + _originOffset.Y, 2),
Math.Round(ext.MaxPoint.Z + _originOffset.Z, 2),
},
};
}
catch
{
panelBoundingBox = null;
}
var radius = cylinder.Radius;
var diameter = radius * 2;
@ -203,7 +228,12 @@ public class HoleDetector
Depth = Math.Round(depth, 2),
PanelId = panelId,
Type = holeType,
Radius = Math.Round(radius, 2)
Radius = Math.Round(radius, 2),
SurfaceFaces = PanelFaceSemanticResolver.ResolveSurfaceFaces(
panelBoundingBox,
new[] { offsetPosition.X, offsetPosition.Y, offsetPosition.Z },
new[] { axis.X, axis.Y, axis.Z },
depth)
};
}
catch (System.Exception ex)

View File

@ -92,7 +92,13 @@ public static class HoleGrouping
Position = mainHole.Position,
Normal = mainHole.Normal,
Confidence = confidence,
Reason = $"主孔直径 {mainHole.Diameter:0.#}mm + 侧孔直径 {best.Diameter:0.#}mm,距离 {dist:0.#}mm,法向点积 {dot:0.00}"
Reason = $"主孔直径 {mainHole.Diameter:0.#}mm + 侧孔直径 {best.Diameter:0.#}mm,距离 {dist:0.#}mm,法向点积 {dot:0.00}",
MountFace = mainHole.SurfaceFaces.FirstOrDefault(face => !string.IsNullOrWhiteSpace(face)) ?? "unknown",
SurfaceFaces = mainHole.SurfaceFaces
.Concat(best.SurfaceFaces ?? Array.Empty<string>())
.Where(face => !string.IsNullOrWhiteSpace(face))
.Distinct(StringComparer.OrdinalIgnoreCase)
.ToArray(),
};
groups.Add(group);

View File

@ -374,6 +374,11 @@ public sealed class HoleMarkerDetector
BindingSource = binding.BindingSource,
BindingConfidence = binding.Confidence,
BindingReason = binding.BindingReason,
SurfaceFaces = PanelFaceSemanticResolver.ResolveSurfaceFaces(
binding.PanelCandidate.Panel.BoundingBox,
new[] { p.X, p.Y, p.Z },
new[] { axis.X, axis.Y, axis.Z },
depth),
});
}
@ -418,6 +423,11 @@ public sealed class HoleMarkerDetector
BindingSource = binding.BindingSource,
BindingConfidence = binding.Confidence,
BindingReason = binding.BindingReason,
SurfaceFaces = PanelFaceSemanticResolver.ResolveSurfaceFaces(
binding.PanelCandidate.Panel.BoundingBox,
new[] { p.X, p.Y, p.Z },
new[] { axis.X, axis.Y, axis.Z },
depth),
});
}

View File

@ -10,7 +10,7 @@ public class ExportData
/// <summary>
/// 数据格式版本
/// </summary>
public string Version { get; set; } = "2.4";
public string Version { get; set; } = "2.6";
/// <summary>
/// 导出时间 (ISO 8601)
@ -46,6 +46,13 @@ public class ExportData
/// 图纸单位(毫米/厘米/米等)
/// </summary>
public string Units { get; set; } = "毫米";
/// <summary>
/// CAD 世界坐标系标识。
/// 当前导出统一按 AutoCAD 世界坐标:X 向右,Y 向前,Z 向上。
/// Web 端后续做孔位吸附时,不再需要靠启发式猜测坐标系。
/// </summary>
public string CoordinateSystem { get; set; } = "AUTOCAD_WORLD_Z_UP";
/// <summary>
/// 原点偏移 [X, Y, Z] (mm)
@ -103,6 +110,24 @@ public class ExportData
/// </summary>
public List<HoleGroupInfo> HoleGroups { get; set; } = new();
/// <summary>
/// 安装图样(v2.5 兼容字段)。
/// 新方案主字段是 SnapPatterns;这里继续保留给旧 Web 端兼容。
/// </summary>
public List<MountPatternInfo> MountPatterns { get; set; } = new();
/// <summary>
/// 吸附图样(v2.6 新主字段)。
/// 内容与 MountPatterns 保持一致,Web 端后续优先读取 snapPatterns。
/// </summary>
public List<MountPatternInfo> SnapPatterns { get; set; } = new();
/// <summary>
/// 吸附面(v2.6 新增)。
/// 每块板件至少提供 6 个轴向外表面,用于辅助装配阶段做面级吸附候选。
/// </summary>
public List<SnapSurfaceInfo> SnapSurfaces { get; set; } = new();
/// <summary>
/// 逻辑孔位数量(v2.2.4 新增)
/// 计算方式:以 HoleGroupId 合并计数(HoleGroupId 为空则按 Hole.Id 计数)。
@ -313,6 +338,21 @@ public class PanelInfo
/// 该板件上的逻辑孔位分组(v2.2.4 新增)
/// </summary>
public List<HoleGroupInfo> HoleGroups { get; set; } = new();
/// <summary>
/// 该板件上的安装图样(v2.5 兼容字段)
/// </summary>
public List<MountPatternInfo> MountPatterns { get; set; } = new();
/// <summary>
/// 该板件上的吸附图样(v2.6 新主字段)
/// </summary>
public List<MountPatternInfo> SnapPatterns { get; set; } = new();
/// <summary>
/// 该板件的吸附面(v2.6 新增)
/// </summary>
public List<SnapSurfaceInfo> SnapSurfaces { get; set; } = new();
}
/// <summary>
@ -391,6 +431,14 @@ public class HoleInfo
/// </summary>
public double BindingConfidence { get; set; } = 1.0;
/// <summary>
/// 孔位整体可用置信度(0-1)
/// 说明:
/// - BindingConfidence 只表示“孔位和板件绑定得稳不稳”;
/// - Confidence 表示“这个孔位几何与语义整体是否可信”。
/// </summary>
public double Confidence { get; set; } = 1.0;
/// <summary>
/// 绑定原因说明(调试/回放)
/// </summary>
@ -418,12 +466,24 @@ public class HoleInfo
/// 例如:main(主孔)/ side(侧孔)
/// </summary>
public string? HoleGroupRole { get; set; }
/// <summary>
/// 当前孔实际打在板件外表面的面标签。
/// 盲孔通常只有 1 个面;通孔通常会有 2 个相对面。
/// 例如:top / bottom / left / right / front / back
/// </summary>
public string[] SurfaceFaces { get; set; } = System.Array.Empty<string>();
/// <summary>
/// 推断的用途(根据直径)
/// </summary>
public string? InferredUsage { get; set; }
/// <summary>
/// 低置信度或歧义提示
/// </summary>
public List<string> Warnings { get; set; } = new();
/// <summary>
/// 针对该孔位的紧固件建议(v2.3 新增)
/// 说明:
@ -511,6 +571,140 @@ public class HoleGroupInfo
/// 可读原因(调试/回放)
/// </summary>
public string? Reason { get; set; }
/// <summary>
/// 当前孔组默认作用的安装面。
/// 例如:top / bottom / left / right / front / back / unknown
/// </summary>
public string MountFace { get; set; } = "unknown";
/// <summary>
/// 逻辑孔位实际落在哪些板件外表面上。
/// 默认按主孔 + 组内成员孔合并去重。
/// </summary>
public string[] SurfaceFaces { get; set; } = System.Array.Empty<string>();
/// <summary>
/// 低置信度或歧义提示
/// </summary>
public List<string> Warnings { get; set; } = new();
}
/// <summary>
/// 安装图样(v2.5 新增)
/// </summary>
public class MountPatternInfo
{
/// <summary>
/// 图样 ID(如 panel_001_mount_top_001)
/// </summary>
public string Id { get; set; } = "";
/// <summary>
/// 所属板件 ID
/// </summary>
public string PanelId { get; set; } = "";
/// <summary>
/// 默认安装面:top / bottom / left / right / front / back / unknown
/// </summary>
public string MountFace { get; set; } = "unknown";
/// <summary>
/// 图样类型:single / line_2 / triangle_3 / rectangle_4 / generic
/// </summary>
public string PatternType { get; set; } = "generic";
/// <summary>
/// 属于该图样的几何孔位 ID
/// </summary>
public string[] HoleIds { get; set; } = System.Array.Empty<string>();
/// <summary>
/// 必需命中的孔位 ID
/// </summary>
public string[] RequiredHoleIds { get; set; } = System.Array.Empty<string>();
/// <summary>
/// 可选命中的孔位 ID
/// </summary>
public string[] OptionalHoleIds { get; set; } = System.Array.Empty<string>();
/// <summary>
/// 吸附成立所需的最少命中孔数
/// </summary>
public int MinRequiredHoles { get; set; }
/// <summary>
/// 推荐命中孔数(越接近越稳)
/// </summary>
public int PreferredHoleCount { get; set; }
/// <summary>
/// 是否允许对称复用
/// </summary>
public bool Symmetry { get; set; }
/// <summary>
/// 图样参考点(默认取图样中心)
/// </summary>
public double[] Position { get; set; } = new double[3];
/// <summary>
/// 图样参考法向(默认取安装面法向)
/// </summary>
public double[] Normal { get; set; } = new double[3];
/// <summary>
/// 图样置信度(0-1)
/// </summary>
public double Confidence { get; set; }
/// <summary>
/// 低置信度或歧义提示
/// </summary>
public List<string> Warnings { get; set; } = new();
}
/// <summary>
/// 吸附面信息(v2.6 新增)
/// </summary>
public class SnapSurfaceInfo
{
/// <summary>
/// 吸附面 ID(如 panel_001_snap_top)
/// </summary>
public string Id { get; set; } = "";
/// <summary>
/// 面标签:left / right / front / back / bottom / top
/// </summary>
public string Face { get; set; } = "";
/// <summary>
/// 所属板件 ID
/// </summary>
public string PanelId { get; set; } = "";
/// <summary>
/// 外法向量 [X, Y, Z]
/// </summary>
public double[] Normal { get; set; } = new double[3];
/// <summary>
/// 面中心 [X, Y, Z] (mm)
/// </summary>
public double[] Center { get; set; } = new double[3];
/// <summary>
/// 面边界框。薄轴最小值和最大值相同,表示该外表面所在平面。
/// </summary>
public BoundingBox3D Bounds { get; set; } = new();
/// <summary>
/// 推导置信度(0-1)
/// </summary>
public double Confidence { get; set; }
}
/// <summary>

View File

@ -0,0 +1,445 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace FurnitureExporter;
/// <summary>
/// 安装图样识别器。
///
/// 设计口径:
/// - 吸附面(mount face)先缩小候选范围;
/// - HoleGroup 负责把几何孔组织成业务孔位;
/// - MountPattern 负责定义“至少命中几个孔才允许吸附成立”。
/// </summary>
public static class MountPatternAnalyzer
{
private const double DefaultClusterDistanceMm = 220.0;
public static List<MountPatternInfo> BuildMountPatterns(
IReadOnlyList<PanelInfo> panels,
IReadOnlyList<HoleInfo> holes,
IReadOnlyList<HoleGroupInfo> holeGroups)
{
var patterns = new List<MountPatternInfo>();
if (panels == null || panels.Count == 0)
{
return patterns;
}
var holesByPanel = holes
.Where(h => !string.IsNullOrWhiteSpace(h.PanelId))
.GroupBy(h => h.PanelId, StringComparer.OrdinalIgnoreCase)
.ToDictionary(group => group.Key, group => group.ToList(), StringComparer.OrdinalIgnoreCase);
var groupsByPanel = holeGroups
.Where(group => !string.IsNullOrWhiteSpace(group.PanelId))
.GroupBy(group => group.PanelId, StringComparer.OrdinalIgnoreCase)
.ToDictionary(group => group.Key, group => group.ToList(), StringComparer.OrdinalIgnoreCase);
foreach (var panel in panels)
{
var panelHoles = holesByPanel.TryGetValue(panel.Id, out var panelHoleList)
? panelHoleList
: new List<HoleInfo>();
var panelGroups = groupsByPanel.TryGetValue(panel.Id, out var panelGroupList)
? panelGroupList
: new List<HoleGroupInfo>();
var units = BuildUnits(panel.Id, panelHoles, panelGroups);
if (units.Count == 0)
{
panel.MountPatterns = new List<MountPatternInfo>();
panel.SnapPatterns = new List<MountPatternInfo>();
continue;
}
var panelPatterns = new List<MountPatternInfo>();
var unitsByFace = units
.SelectMany(unit =>
unit.MountFaces.Select(face => new { Face = face, Unit = unit }))
.GroupBy(item => item.Face, StringComparer.OrdinalIgnoreCase);
foreach (var faceGroup in unitsByFace)
{
var clusters = BuildClusters(faceGroup.Select(item => item.Unit).Distinct().ToList());
var patternIndex = 0;
foreach (var cluster in clusters)
{
var pattern = BuildPattern(panel.Id, faceGroup.Key, patternIndex++, cluster);
panelPatterns.Add(pattern);
}
}
panel.MountPatterns = panelPatterns;
panel.SnapPatterns = panelPatterns;
patterns.AddRange(panelPatterns);
}
return patterns;
}
public static void AttachPatternsToPanels(IReadOnlyList<PanelInfo> panels, IReadOnlyList<MountPatternInfo> patterns)
{
var map = patterns
.GroupBy(pattern => pattern.PanelId, StringComparer.OrdinalIgnoreCase)
.ToDictionary(group => group.Key, group => group.ToList(), StringComparer.OrdinalIgnoreCase);
foreach (var panel in panels)
{
var panelPatterns = map.TryGetValue(panel.Id, out var items)
? items
: new List<MountPatternInfo>();
panel.MountPatterns = panelPatterns;
panel.SnapPatterns = panelPatterns;
}
}
private static List<MountPatternUnit> BuildUnits(
string panelId,
IReadOnlyList<HoleInfo> holes,
IReadOnlyList<HoleGroupInfo> holeGroups)
{
var units = new List<MountPatternUnit>();
var groupedHoleIds = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
foreach (var group in holeGroups)
{
foreach (var holeId in group.HoleIds ?? Array.Empty<string>())
{
groupedHoleIds.Add(holeId);
}
var mountFaces = NormalizeMountFaces(group.SurfaceFaces, group.MountFace);
group.MountFace = mountFaces.FirstOrDefault() ?? "unknown";
units.Add(new MountPatternUnit
{
Id = group.Id,
PanelId = panelId,
HoleIds = group.HoleIds ?? Array.Empty<string>(),
Position = group.Position,
Normal = group.Normal,
GroupType = group.GroupType,
MountFaces = mountFaces,
Confidence = Clamp01(group.Confidence <= 0 ? 0.72 : group.Confidence),
Warnings = group.Warnings?.ToList() ?? new List<string>(),
Source = "hole-group",
});
}
foreach (var hole in holes)
{
if (groupedHoleIds.Contains(hole.Id))
{
continue;
}
units.Add(new MountPatternUnit
{
Id = hole.Id,
PanelId = panelId,
HoleIds = new[] { hole.Id },
Position = hole.Position,
Normal = hole.Normal,
GroupType = hole.HoleGroupType,
MountFaces = NormalizeMountFaces(hole.SurfaceFaces),
Confidence = Clamp01(hole.Confidence <= 0 ? 0.76 : hole.Confidence),
Warnings = hole.Warnings?.ToList() ?? new List<string>(),
Source = "single-hole",
});
}
return units;
}
private static List<List<MountPatternUnit>> BuildClusters(IReadOnlyList<MountPatternUnit> units)
{
var clusters = new List<List<MountPatternUnit>>();
var visited = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
foreach (var unit in units)
{
if (!visited.Add(unit.Id))
{
continue;
}
var cluster = new List<MountPatternUnit>();
var queue = new Queue<MountPatternUnit>();
queue.Enqueue(unit);
while (queue.Count > 0)
{
var current = queue.Dequeue();
cluster.Add(current);
foreach (var candidate in units)
{
if (visited.Contains(candidate.Id))
{
continue;
}
if (Distance(current.Position, candidate.Position) > DefaultClusterDistanceMm)
{
continue;
}
visited.Add(candidate.Id);
queue.Enqueue(candidate);
}
}
clusters.Add(cluster.OrderBy(item => item.Position[0]).ThenBy(item => item.Position[1]).ThenBy(item => item.Position[2]).ToList());
}
return clusters;
}
private static MountPatternInfo BuildPattern(
string panelId,
string mountFace,
int patternIndex,
IReadOnlyList<MountPatternUnit> cluster)
{
var holeIds = cluster
.SelectMany(unit => unit.HoleIds)
.Distinct(StringComparer.OrdinalIgnoreCase)
.ToArray();
var warnings = cluster
.SelectMany(unit => unit.Warnings)
.Distinct(StringComparer.OrdinalIgnoreCase)
.ToList();
var pointCount = cluster.Count;
var patternType = ResolvePatternType(cluster);
var isSymmetricRectangle = string.Equals(patternType, "rectangle_4", StringComparison.OrdinalIgnoreCase);
var minRequiredHoles = ResolveMinRequiredHoleCount(patternType, pointCount, isSymmetricRectangle);
var preferredHoleCount = pointCount;
var requiredHoleIds = Array.Empty<string>();
var optionalHoleIds = Array.Empty<string>();
if (pointCount <= 3 || !isSymmetricRectangle)
{
requiredHoleIds = holeIds;
}
else
{
optionalHoleIds = holeIds;
warnings.Add("四孔对称图样默认按 2 孔完成初始定位,剩余孔位作为增强固定。");
}
if (string.Equals(patternType, "generic", StringComparison.OrdinalIgnoreCase))
{
warnings.Add("当前图样由几何聚类自动生成,建议后续在资产录入阶段人工复核。");
}
return new MountPatternInfo
{
Id = $"{panelId}_mount_{mountFace}_{patternIndex:D3}",
PanelId = panelId,
MountFace = mountFace,
PatternType = patternType,
HoleIds = holeIds,
RequiredHoleIds = requiredHoleIds,
OptionalHoleIds = optionalHoleIds,
MinRequiredHoles = minRequiredHoles,
PreferredHoleCount = preferredHoleCount,
Symmetry = isSymmetricRectangle,
Position = AveragePosition(cluster),
Normal = ResolveMountFaceNormal(mountFace),
Confidence = ComputePatternConfidence(cluster, patternType, warnings.Count),
Warnings = warnings,
};
}
private static string ResolvePatternType(IReadOnlyList<MountPatternUnit> cluster)
{
return cluster.Count switch
{
1 => "single",
2 => "line_2",
3 => "triangle_3",
4 when IsRectangle(cluster) => "rectangle_4",
_ => "generic",
};
}
private static int ResolveMinRequiredHoleCount(string patternType, int pointCount, bool isSymmetricRectangle)
{
if (string.Equals(patternType, "single", StringComparison.OrdinalIgnoreCase))
{
return 1;
}
if (string.Equals(patternType, "line_2", StringComparison.OrdinalIgnoreCase))
{
return 2;
}
if (string.Equals(patternType, "triangle_3", StringComparison.OrdinalIgnoreCase))
{
return 3;
}
if (isSymmetricRectangle)
{
return 2;
}
if (pointCount <= 0)
{
return 1;
}
return pointCount <= 4 ? pointCount : Math.Min(pointCount, 4);
}
private static bool IsRectangle(IReadOnlyList<MountPatternUnit> cluster)
{
if (cluster.Count != 4)
{
return false;
}
var distances = new List<double>();
for (var i = 0; i < cluster.Count; i++)
{
for (var j = i + 1; j < cluster.Count; j++)
{
distances.Add(Distance(cluster[i].Position, cluster[j].Position));
}
}
distances.Sort();
if (distances.Count != 6)
{
return false;
}
var sideA = distances[0];
var sideB = distances[2];
var diagonalA = distances[4];
var diagonalB = distances[5];
return AreClose(sideA, distances[1], 0.12) &&
AreClose(sideB, distances[3], 0.12) &&
AreClose(diagonalA, diagonalB, 0.08);
}
private static double[] AveragePosition(IReadOnlyList<MountPatternUnit> cluster)
{
if (cluster.Count == 0)
{
return new[] { 0.0, 0.0, 0.0 };
}
return new[]
{
Math.Round(cluster.Average(item => item.Position[0]), 2),
Math.Round(cluster.Average(item => item.Position[1]), 2),
Math.Round(cluster.Average(item => item.Position[2]), 2),
};
}
private static double[] ResolveMountFaceNormal(string mountFace)
{
return mountFace.ToLowerInvariant() switch
{
"left" => new[] { -1.0, 0.0, 0.0 },
"right" => new[] { 1.0, 0.0, 0.0 },
"front" => new[] { 0.0, -1.0, 0.0 },
"back" => new[] { 0.0, 1.0, 0.0 },
"bottom" => new[] { 0.0, 0.0, -1.0 },
"top" => new[] { 0.0, 0.0, 1.0 },
_ => new[] { 0.0, 0.0, 1.0 },
};
}
private static double ComputePatternConfidence(
IReadOnlyList<MountPatternUnit> cluster,
string patternType,
int warningCount)
{
if (cluster.Count == 0)
{
return 0;
}
var baseConfidence = cluster.Average(item => item.Confidence);
if (string.Equals(patternType, "generic", StringComparison.OrdinalIgnoreCase))
{
baseConfidence = Math.Min(baseConfidence, 0.68);
}
if (warningCount > 0)
{
baseConfidence -= Math.Min(0.14, warningCount * 0.04);
}
return Math.Round(Clamp01(baseConfidence), 4);
}
private static string[] NormalizeMountFaces(IEnumerable<string>? faces, string? fallbackFace = null)
{
var normalized = (faces ?? Array.Empty<string>())
.Where(face => !string.IsNullOrWhiteSpace(face))
.Select(face => face.Trim().ToLowerInvariant())
.Distinct(StringComparer.OrdinalIgnoreCase)
.ToList();
if (normalized.Count > 0)
{
return normalized.ToArray();
}
if (!string.IsNullOrWhiteSpace(fallbackFace))
{
return new[] { fallbackFace!.Trim().ToLowerInvariant() };
}
return new[] { "unknown" };
}
private static double Distance(IReadOnlyList<double> left, IReadOnlyList<double> right)
{
var dx = left[0] - right[0];
var dy = left[1] - right[1];
var dz = left[2] - right[2];
return Math.Sqrt(dx * dx + dy * dy + dz * dz);
}
private static bool AreClose(double left, double right, double toleranceRatio)
{
var baseValue = Math.Max(Math.Abs(left), Math.Abs(right));
if (baseValue <= 1e-6)
{
return true;
}
return Math.Abs(left - right) / baseValue <= toleranceRatio;
}
private static double Clamp01(double value)
{
if (value < 0) return 0;
if (value > 1) return 1;
return value;
}
private sealed class MountPatternUnit
{
public string Id { get; set; } = "";
public string PanelId { get; set; } = "";
public string[] HoleIds { get; set; } = Array.Empty<string>();
public double[] Position { get; set; } = new double[3];
public double[] Normal { get; set; } = new double[3];
public string? GroupType { get; set; }
public string[] MountFaces { get; set; } = Array.Empty<string>();
public double Confidence { get; set; }
public List<string> Warnings { get; set; } = new();
public string Source { get; set; } = "single-hole";
}
}

View File

@ -210,8 +210,24 @@ public class PanelAnalyzer
// 判断板材方向(法向量)
var normal = DeterminePanelNormal(dims, size);
var panelBoundingBox = new BoundingBox3D
{
Min = new double[]
{
Math.Round(ext.MinPoint.X + _originOffset.X, 2),
Math.Round(ext.MinPoint.Y + _originOffset.Y, 2),
Math.Round(ext.MinPoint.Z + _originOffset.Z, 2)
},
Max = new double[]
{
Math.Round(ext.MaxPoint.X + _originOffset.X, 2),
Math.Round(ext.MaxPoint.Y + _originOffset.Y, 2),
Math.Round(ext.MaxPoint.Z + _originOffset.Z, 2)
}
};
// 提取孔位
var holes = ExtractHoles(solid, $"panel_{index:D3}", thickness);
var holes = ExtractHoles(solid, $"panel_{index:D3}", thickness, panelBoundingBox);
// v2.2.5:孔位过滤(与设计师“孔位口径”对齐)
// - 极小薄件(如脚垫/垫片)不作为板件孔位统计对象,避免误把“几何细节”当孔
@ -253,21 +269,7 @@ public class PanelAnalyzer
Math.Round(dims[2], 2) // 厚
},
Normal = normal,
BoundingBox = new BoundingBox3D
{
Min = new double[]
{
Math.Round(ext.MinPoint.X + _originOffset.X, 2),
Math.Round(ext.MinPoint.Y + _originOffset.Y, 2),
Math.Round(ext.MinPoint.Z + _originOffset.Z, 2)
},
Max = new double[]
{
Math.Round(ext.MaxPoint.X + _originOffset.X, 2),
Math.Round(ext.MaxPoint.Y + _originOffset.Y, 2),
Math.Round(ext.MaxPoint.Z + _originOffset.Z, 2)
}
},
BoundingBox = panelBoundingBox,
Holes = holes
};
}
@ -299,7 +301,11 @@ public class PanelAnalyzer
/// <summary>
/// 从板材实体中提取孔位信息
/// </summary>
private List<HoleInfo> ExtractHoles(Solid3d solid, string panelId, double panelThickness)
private List<HoleInfo> ExtractHoles(
Solid3d solid,
string panelId,
double panelThickness,
BoundingBox3D panelBoundingBox)
{
var holes = new List<HoleInfo>();
@ -315,7 +321,7 @@ public class PanelAnalyzer
var surface = BrepSurfaceUtils.Unwrap(face.Surface);
if (surface is Cylinder cylinder)
{
var hole = ExtractHoleFromCylinder(cylinder, face, panelId, holeIndex, panelThickness);
var hole = ExtractHoleFromCylinder(cylinder, face, panelId, holeIndex, panelThickness, panelBoundingBox);
if (hole != null)
{
holes.Add(hole);
@ -326,7 +332,7 @@ public class PanelAnalyzer
{
// 柜脚/三角铁等五金件上常见“沉头孔/倒角孔”,其孔壁在 Brep 中可能表现为锥面(Cone),
// 仅识别 Cylinder 会漏掉这类孔位。
var hole = ExtractHoleFromCone(cone, face, panelId, holeIndex, panelThickness);
var hole = ExtractHoleFromCone(cone, face, panelId, holeIndex, panelThickness, panelBoundingBox);
if (hole != null)
{
holes.Add(hole);
@ -344,7 +350,7 @@ public class PanelAnalyzer
// 某些孔位(尤其是五金件的沉头孔/复杂倒角)在 AutoCAD Brep 中,孔壁面可能被表达为 NurbSurface/其它曲面,
// 导致 surface is Cylinder/Cone 判断失败。
// 这里用“闭合圆边界 + 相邻端面平面法向推断孔轴”的方式做一次兜底,尽量补齐漏孔。
var hole = ExtractHoleFromFallbackFace(face, panelId, holeIndex, panelThickness);
var hole = ExtractHoleFromFallbackFace(face, panelId, holeIndex, panelThickness, panelBoundingBox);
if (hole != null)
{
holes.Add(hole);
@ -374,7 +380,8 @@ public class PanelAnalyzer
Autodesk.AutoCAD.BoundaryRepresentation.Face face,
string panelId,
int index,
double panelThickness)
double panelThickness,
BoundingBox3D panelBoundingBox)
{
try
{
@ -458,7 +465,12 @@ public class PanelAnalyzer
DetectionSource = "brep",
BindingSource = "panel_brep",
BindingConfidence = 1.0,
BindingReason = "从当前板件实体 Brep 直接提取"
BindingReason = "从当前板件实体 Brep 直接提取",
SurfaceFaces = PanelFaceSemanticResolver.ResolveSurfaceFaces(
panelBoundingBox,
new[] { offsetPosition.X, offsetPosition.Y, offsetPosition.Z },
new[] { axis.X, axis.Y, axis.Z },
depth)
};
}
catch
@ -475,7 +487,8 @@ public class PanelAnalyzer
Autodesk.AutoCAD.BoundaryRepresentation.Face face,
string panelId,
int index,
double panelThickness)
double panelThickness,
BoundingBox3D panelBoundingBox)
{
try
{
@ -560,7 +573,12 @@ public class PanelAnalyzer
DetectionSource = "brep",
BindingSource = "panel_brep",
BindingConfidence = 1.0,
BindingReason = "从当前板件实体 Brep 直接提取"
BindingReason = "从当前板件实体 Brep 直接提取",
SurfaceFaces = PanelFaceSemanticResolver.ResolveSurfaceFaces(
panelBoundingBox,
new[] { offsetPosition.X, offsetPosition.Y, offsetPosition.Z },
new[] { axis.X, axis.Y, axis.Z },
depth)
};
}
catch
@ -577,7 +595,8 @@ public class PanelAnalyzer
BrepFace face,
string panelId,
int index,
double panelThickness)
double panelThickness,
BoundingBox3D panelBoundingBox)
{
try
{
@ -651,7 +670,12 @@ public class PanelAnalyzer
DetectionSource = "brep",
BindingSource = "panel_brep",
BindingConfidence = 1.0,
BindingReason = "从当前板件实体 Brep 兜底面直接提取"
BindingReason = "从当前板件实体 Brep 兜底面直接提取",
SurfaceFaces = PanelFaceSemanticResolver.ResolveSurfaceFaces(
panelBoundingBox,
new[] { offsetPosition.X, offsetPosition.Y, offsetPosition.Z },
new[] { axis.X, axis.Y, axis.Z },
depth)
};
}
catch

View File

@ -0,0 +1,226 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace FurnitureExporter;
public static class PanelFaceSemanticResolver
{
private const double SurfaceFaceToleranceMm = 3.0;
private const double InteriorFaceToleranceMm = 0.8;
public static string[] ResolveSurfaceFaces(
BoundingBox3D? boundingBox,
IReadOnlyList<double>? position,
IReadOnlyList<double>? normal,
double depth)
{
if (boundingBox?.Min?.Length != 3 || boundingBox.Max?.Length != 3)
{
return Array.Empty<string>();
}
var center = ToVector3(position);
var axis = Normalize(ToVector3(normal));
if (center == null || axis == null)
{
return Array.Empty<string>();
}
var faces = new List<string>();
var halfDepth = Math.Max(0, depth) / 2.0;
var dominantFaces = ResolveDominantAxisFaces(axis);
if (halfDepth > 0.01)
{
AddFace(
faces,
ResolveNearestSurfaceFace(
boundingBox,
Offset(center, axis, halfDepth),
dominantFaces.Positive,
dominantFaces.Negative,
SurfaceFaceToleranceMm));
AddFace(
faces,
ResolveNearestSurfaceFace(
boundingBox,
Offset(center, axis, -halfDepth),
dominantFaces.Negative,
dominantFaces.Positive,
SurfaceFaceToleranceMm));
}
if (faces.Count == 0)
{
AddFace(
faces,
ResolveNearestSurfaceFace(
boundingBox,
center,
dominantFaces.Positive,
dominantFaces.Negative,
SurfaceFaceToleranceMm + InteriorFaceToleranceMm));
}
return faces
.Distinct(StringComparer.OrdinalIgnoreCase)
.ToArray();
}
public static string OppositeFace(string? face)
{
return face?.Trim().ToLowerInvariant() switch
{
"left" => "right",
"right" => "left",
"front" => "back",
"back" => "front",
"top" => "bottom",
"bottom" => "top",
_ => "unknown",
};
}
private static void AddFace(ICollection<string> faces, string? face)
{
if (string.IsNullOrWhiteSpace(face))
{
return;
}
faces.Add(face!.Trim().ToLowerInvariant());
}
private static double[]? ToVector3(IReadOnlyList<double>? value)
{
if (value == null || value.Count < 3)
{
return null;
}
return new[] { value[0], value[1], value[2] };
}
private static double[]? Normalize(double[]? value)
{
if (value == null)
{
return null;
}
var length = Math.Sqrt(value[0] * value[0] + value[1] * value[1] + value[2] * value[2]);
if (length < 1e-9)
{
return null;
}
return new[]
{
value[0] / length,
value[1] / length,
value[2] / length,
};
}
private static double[] Offset(double[] origin, double[] direction, double distance)
{
return new[]
{
origin[0] + direction[0] * distance,
origin[1] + direction[1] * distance,
origin[2] + direction[2] * distance,
};
}
private static string? ResolveNearestSurfaceFace(BoundingBox3D box, IReadOnlyList<double> point)
{
return ResolveNearestSurfaceFace(box, point, null, null, SurfaceFaceToleranceMm);
}
private static string? ResolveNearestSurfaceFace(
BoundingBox3D box,
IReadOnlyList<double> point,
string? preferredFace,
string? secondaryFace,
double tolerance)
{
var candidates = new List<(string Face, double Distance)>();
if (IsWithinRange(point[1], box.Min[1], box.Max[1], tolerance) &&
IsWithinRange(point[2], box.Min[2], box.Max[2], tolerance))
{
candidates.Add(("left", Math.Abs(point[0] - box.Min[0])));
candidates.Add(("right", Math.Abs(point[0] - box.Max[0])));
}
if (IsWithinRange(point[0], box.Min[0], box.Max[0], tolerance) &&
IsWithinRange(point[2], box.Min[2], box.Max[2], tolerance))
{
candidates.Add(("front", Math.Abs(point[1] - box.Min[1])));
candidates.Add(("back", Math.Abs(point[1] - box.Max[1])));
}
if (IsWithinRange(point[0], box.Min[0], box.Max[0], tolerance) &&
IsWithinRange(point[1], box.Min[1], box.Max[1], tolerance))
{
candidates.Add(("bottom", Math.Abs(point[2] - box.Min[2])));
candidates.Add(("top", Math.Abs(point[2] - box.Max[2])));
}
var best = candidates
.Where(item => item.Distance <= tolerance)
.OrderBy(item => GetFacePriority(item.Face, preferredFace, secondaryFace))
.ThenBy(item => item.Distance)
.FirstOrDefault();
return string.IsNullOrWhiteSpace(best.Face) ? null : best.Face;
}
private static (string Positive, string Negative) ResolveDominantAxisFaces(IReadOnlyList<double> axis)
{
var absX = Math.Abs(axis[0]);
var absY = Math.Abs(axis[1]);
var absZ = Math.Abs(axis[2]);
if (absX >= absY && absX >= absZ)
{
return axis[0] >= 0
? ("right", "left")
: ("left", "right");
}
if (absY >= absX && absY >= absZ)
{
return axis[1] >= 0
? ("back", "front")
: ("front", "back");
}
return axis[2] >= 0
? ("top", "bottom")
: ("bottom", "top");
}
private static int GetFacePriority(string face, string? preferredFace, string? secondaryFace)
{
if (!string.IsNullOrWhiteSpace(preferredFace) &&
string.Equals(face, preferredFace, StringComparison.OrdinalIgnoreCase))
{
return 0;
}
if (!string.IsNullOrWhiteSpace(secondaryFace) &&
string.Equals(face, secondaryFace, StringComparison.OrdinalIgnoreCase))
{
return 1;
}
return 2;
}
private static bool IsWithinRange(double value, double min, double max, double tolerance)
{
return value >= min - tolerance && value <= max + tolerance;
}
}

View File

@ -0,0 +1,135 @@
using System;
using System.Collections.Generic;
namespace FurnitureExporter;
/// <summary>
/// 从板件包围盒推导辅助装配吸附面。
/// </summary>
public static class SnapSurfaceBuilder
{
private static readonly FaceDefinition[] Faces =
{
new("left", 0, false, new[] { -1.0, 0.0, 0.0 }),
new("right", 0, true, new[] { 1.0, 0.0, 0.0 }),
new("front", 1, false, new[] { 0.0, -1.0, 0.0 }),
new("back", 1, true, new[] { 0.0, 1.0, 0.0 }),
new("bottom", 2, false, new[] { 0.0, 0.0, -1.0 }),
new("top", 2, true, new[] { 0.0, 0.0, 1.0 }),
};
public static List<SnapSurfaceInfo> BuildSnapSurfaces(IReadOnlyList<PanelInfo> panels)
{
var allSurfaces = new List<SnapSurfaceInfo>();
foreach (var panel in panels)
{
var panelSurfaces = BuildPanelSurfaces(panel);
panel.SnapSurfaces = panelSurfaces;
allSurfaces.AddRange(panelSurfaces);
}
return allSurfaces;
}
private static List<SnapSurfaceInfo> BuildPanelSurfaces(PanelInfo panel)
{
var (min, max, confidence) = ResolveBounds(panel);
var surfaces = new List<SnapSurfaceInfo>(Faces.Length);
foreach (var face in Faces)
{
var center = new[]
{
Round((min[0] + max[0]) / 2.0),
Round((min[1] + max[1]) / 2.0),
Round((min[2] + max[2]) / 2.0),
};
var boundsMin = new[] { min[0], min[1], min[2] };
var boundsMax = new[] { max[0], max[1], max[2] };
var planeValue = face.UseMax ? max[face.Axis] : min[face.Axis];
center[face.Axis] = planeValue;
boundsMin[face.Axis] = planeValue;
boundsMax[face.Axis] = planeValue;
surfaces.Add(new SnapSurfaceInfo
{
Id = $"{panel.Id}_snap_{face.Name}",
Face = face.Name,
PanelId = panel.Id,
Normal = face.Normal,
Center = center,
Bounds = new BoundingBox3D
{
Min = RoundAll(boundsMin),
Max = RoundAll(boundsMax),
},
Confidence = confidence,
});
}
return surfaces;
}
private static (double[] Min, double[] Max, double Confidence) ResolveBounds(PanelInfo panel)
{
if (panel.BoundingBox?.Min?.Length == 3 && panel.BoundingBox.Max?.Length == 3)
{
return (RoundAll(panel.BoundingBox.Min), RoundAll(panel.BoundingBox.Max), 1.0);
}
var center = panel.Position?.Length == 3
? panel.Position
: new[] { 0.0, 0.0, 0.0 };
var size = panel.Size?.Length == 3
? panel.Size
: new[] { 0.0, 0.0, 0.0 };
var min = new[]
{
center[0] - Math.Abs(size[0]) / 2.0,
center[1] - Math.Abs(size[1]) / 2.0,
center[2] - Math.Abs(size[2]) / 2.0,
};
var max = new[]
{
center[0] + Math.Abs(size[0]) / 2.0,
center[1] + Math.Abs(size[1]) / 2.0,
center[2] + Math.Abs(size[2]) / 2.0,
};
return (RoundAll(min), RoundAll(max), 0.6);
}
private static double[] RoundAll(IReadOnlyList<double> values)
{
return new[]
{
Round(values[0]),
Round(values[1]),
Round(values[2]),
};
}
private static double Round(double value)
{
return Math.Round(value, 2);
}
private sealed class FaceDefinition
{
public FaceDefinition(string name, int axis, bool useMax, double[] normal)
{
Name = name;
Axis = axis;
UseMax = useMax;
Normal = normal;
}
public string Name { get; }
public int Axis { get; }
public bool UseMax { get; }
public double[] Normal { get; }
}
}

View File

@ -1,13 +1,13 @@
# AutoCAD 家具导出插件
用于 AutoCAD 2024 的家具 3D 模型导出插件。导出板材模型和五金件安装位置,用于 Web 端 3D 展示和安装视频生成。
用于 AutoCAD 2024 的家具 3D 模型导出插件。当前主流程是按资产中心口径导出单板材、单组件或单五金件,用于后续辅助装配和规格款入库。
## 功能特点
- **只导出板材模型** - 五金件使用位置引用,文件体积小(1-3MB vs 30-50MB)
- **自动分组五金件** - 按几何特征自动识别相同类型的五金件
- **精确位置记录** - 记录每个五金件的安装位置和旋转角度
- **服务端自动匹配** - 上传后自动匹配五金件库
- **单资产导出** - `FEXPORT` 默认导出单板材、单组件或单五金件
- **板材语义保留** - 导出孔位、孔组、吸附图样和吸附面,供辅助装配使用
- **五金规格提取** - 单五金模式保留几何签名、图层类型和实例信息
- **整套兼容保留** - 旧整套家具导出迁移到 `FEXPORTPRODUCT`
## 系统要求
@ -20,7 +20,7 @@
### 方法 1:手动安装发版包(推荐给产品/实施)
1. 完全关闭 AutoCAD 2024
2. 解压 `dist/家具导出插件-v2.3.1-一键安装版.zip`
2. 解压 `dist/家具导出插件-v2.6.0-一键安装版.zip`
3. 将整个 `FurnitureExporter.bundle` 文件夹复制到:
```text
@ -39,7 +39,7 @@
### 方法 2:一键安装
双击 `dist/家具导出插件-v2.3.1-一键安装版/安装.bat`
双击 `dist/家具导出插件-v2.6.0-一键安装版/安装.bat`
脚本会自动:
1. 复制插件到 `%AppData%\Autodesk\ApplicationPlugins\FurnitureExporter.bundle`
@ -90,7 +90,7 @@ dotnet build -c Release
## 使用方法
### FEXPORT - 导出家具模型
### FEXPORT - 导出单资产到资产中心
```
命令: FEXPORT
@ -98,13 +98,21 @@ dotnet build -c Release
**操作步骤:**
1. **选择板材** - 框选所有板材实体,按 Enter 确认
2. **选择五金件** - 框选所有五金件,按 Enter 确认(可跳过)
3. **保存文件** - 选择保存位置
1. **选择资产类型** - 板材 / 组件 / 五金
2. **选择实体** - 框选该单资产包含的 3D Solid 或图块,按 Enter 确认
3. **保存文件** - 选择 ZIP 保存位置
**输出文件:** `xxx_export.zip`,包含:
- `model.glb` - 板材 3D 模型
- `hardware.json` - 五金件位置数据
**输出文件:** `xxx_board_asset.zip` / `xxx_component_asset.zip` / `xxx_hardware_asset.zip`,包含:
- `model.obj` - 单资产模型
- `hardware.json` - 单资产结构化数据,包含 `exportMode: "single_asset"` 与 `assetTypeHint`
### FEXPORTPRODUCT - 整套家具兼容导出
```
命令: FEXPORTPRODUCT
```
仅用于旧产品链路兼容。新资产中心和辅助装配测试请优先使用 `FEXPORT`。
### FINFO - 查看实体信息
@ -120,36 +128,19 @@ dotnet build -c Release
```json
{
"version": "1.0",
"exportedAt": "2024-01-15T10:30:00Z",
"sourceFile": "衣柜.dwg",
"version": "2.6",
"exportedAt": "2026-05-11T10:30:00Z",
"sourceFile": "桌腿.dwg",
"software": "AutoCAD 2024",
"pluginVersion": "1.0.0",
"modelFile": "model.glb",
"panelCount": 12,
"hardwareTypes": [
{
"typeId": "type_000",
"signature": {
"width": 35.0,
"height": 12.0,
"depth": 12.0,
"volume": 4032.5
},
"instances": [
{
"position": { "x": 100.0, "y": 50.0, "z": 18.0 },
"rotation": { "x": 0, "y": 0, "z": 1.5708 },
"sourceLayer": "五金件"
},
{
"position": { "x": 100.0, "y": 150.0, "z": 18.0 },
"rotation": { "x": 0, "y": 0, "z": 1.5708 },
"sourceLayer": "五金件"
}
]
}
]
"pluginVersion": "2.6.0",
"modelFile": "model.obj",
"exportMode": "single_asset",
"assetTypeHint": "COMPONENT",
"sourceEntityCount": 1,
"panelCount": 1,
"snapPatterns": [],
"snapSurfaces": [],
"hardwareTypes": []
}
```
@ -160,17 +151,17 @@ dotnet build -c Release
─────── ──────
1. 打开 DWG 文件
2. FEXPORT
3. 框选板材 ────────────────→
4. 框选五金件 ──────────────→
5. 保存 ZIP ────────────────→ 上传 ZIP
3. 选择资产类型(板材/组件/五金)
4. 框选单个资产实体 ───────→
5. 保存 ZIP ────────────────→ 上传到资产中心
↓
自动解析
↓
匹配五金件库
创建/更新资产族规格款
↓
保存到数据库
↓
3D 预览 ✓
辅助装配可用 ✓
```
## 开发

View File

@ -49,7 +49,7 @@ Write-Host ""
# 路径设置
$PluginName = "FurnitureExporter"
$Version = "2.5.0"
$Version = "2.6.0"
$SourceDir = Join-Path $PSScriptRoot "FurnitureExporter"
$InstallerDir = Join-Path $PSScriptRoot "installer"
$OutputDir = Join-Path $PSScriptRoot "dist"
@ -90,7 +90,7 @@ $PackageXml = @"
SchemaVersion="1.0"
AutodeskProduct="AutoCAD"
Name="$PluginName"
Description="家具导出插件 v$Version - 支持整套兼容导出与资产中心单资产导出"
Description="家具导出插件 v$Version - 默认资产中心单资产导出,保留整套兼容导出"
Author="Furniture 3D System"
AppVersion="$Version"
FriendlyVersion="$Version"
@ -119,7 +119,7 @@ $PackageXml = @"
AppName="$PluginName"
Version="$Version"
ModuleName="./Contents/$PluginName.dll"
AppDescription="家具导出插件 - 支持整套兼容导出与资产中心单资产导出"
AppDescription="家具导出插件 - 默认资产中心单资产导出,保留整套兼容导出"
LoadOnAutoCADStartup="True"
AppType="Net" />
</Components>
@ -306,7 +306,7 @@ New-ItemProperty -Path $appKey -Name "DESCRIPTION" -PropertyType String -Value "
Write-Step "[3/3] 完成"
Write-Host ""
Write-Host "安装完成。请完全关闭 AutoCAD 后重新启动。" -ForegroundColor Green
Write-Host "启动后命令行输入:FEXPORTASSET(单资产)或 FEXPORT(整套兼容)" -ForegroundColor Green
Write-Host "启动后命令行输入:FEXPORT(单资产)或 FEXPORTPRODUCT(整套兼容)" -ForegroundColor Green
Write-Host ""
'@
Write-TextFileUtf8Bom -Path (Join-Path $InstallerDir "install.ps1") -Content $InstallPs1
@ -480,8 +480,10 @@ $Readme = @"
使用方法
───────────────────────────────────────────────────────────────────────
打开 AutoCAD 后,命令行输入:
FEXPORTASSET -> 单资产导出到资产中心(板材 / 组件 / 五金)
FEXPORT -> 整套家具兼容导出
FEXPORT -> 单资产导出到资产中心(板材 / 组件 / 五金)
FEXPORTASSET -> 单资产导出别名
FEXPORTPRODUCT -> 整套家具兼容导出
FEXPORTBUNDLE -> 整套家具兼容导出别名
FINFO -> 查看实体信息
安装脚本做了什么(便于 IT/排查)
@ -495,7 +497,7 @@ $Readme = @"
常见问题
───────────────────────────────────────────────────────────────────────
Q: 提示“未知命令 FEXPORTASSET / FEXPORT”
Q: 提示“未知命令 FEXPORT / FEXPORTPRODUCT”
A: 1) 确认已重启 AutoCAD(关闭再打开)
2) 确认插件目录存在:
%AppData%\Autodesk\ApplicationPlugins\FurnitureExporter.bundle\Contents\FurnitureExporter.dll

View File

@ -75,7 +75,8 @@ if %ERRORLEVEL% EQU 0 (
echo 1. 打开 AutoCAD 2024
echo 2. 输入命令: NETLOAD
echo 3. 选择上述 DLL 文件
echo 4. 使用命令: FEXPORT 导出模型
echo 4. 使用命令: FEXPORT 导出单资产模型
echo 旧整套兼容导出: FEXPORTPRODUCT
echo.
) else (
echo.

View File

@ -84,7 +84,8 @@ try {
Write-Host " 1. 打开 AutoCAD 2024"
Write-Host " 2. 输入命令: NETLOAD"
Write-Host " 3. 选择上述 DLL 文件"
Write-Host " 4. 使用命令: FEXPORT 导出模型"
Write-Host " 4. 使用命令: FEXPORT 导出单资产模型"
Write-Host " 旧整套兼容导出: FEXPORTPRODUCT"
Write-Host ""
}
else {

View File

@ -3,12 +3,12 @@
SchemaVersion="1.0"
AutodeskProduct="AutoCAD"
Name="FurnitureExporter"
Description="家具导出插件 v2.5.0 - 支持整套兼容导出与资产中心单资产导出"
Description="家具导出插件 v2.6.0 - 默认资产中心单资产导出,保留整套兼容导出"
Author="Furniture 3D System"
AppVersion="2.5.0"
FriendlyVersion="2.5.0"
AppVersion="2.6.0"
FriendlyVersion="2.6.0"
ProductType="Application"
Version="2.5.0"
Version="2.6.0"
ProductCode="{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}">
<CompanyDetails
@ -30,9 +30,9 @@
<ComponentEntry
AppName="FurnitureExporter"
Version="2.5.0"
Version="2.6.0"
ModuleName="./Contents/FurnitureExporter.dll"
AppDescription="家具导出插件 - 支持整套兼容导出与资产中心单资产导出"
AppDescription="家具导出插件 - 默认资产中心单资产导出,保留整套兼容导出"
LoadOnAutoCADStartup="True"
AppType="Net" />
</Components>

View File

@ -174,5 +174,5 @@ New-ItemProperty -Path $appKey -Name "DESCRIPTION" -PropertyType String -Value "
Write-Step "[3/3] 完成"
Write-Host ""
Write-Host "安装完成。请完全关闭 AutoCAD 后重新启动。" -ForegroundColor Green
Write-Host "启动后命令行输入:FEXPORTASSET(单资产)或 FEXPORT(整套兼容)" -ForegroundColor Green
Write-Host "启动后命令行输入:FEXPORT(单资产)或 FEXPORTPRODUCT(整套兼容)" -ForegroundColor Green
Write-Host ""

View File

@ -1,5 +1,5 @@
═══════════════════════════════════════════════════════════════════════
家具导出插件 v2.5.0 - 安装指南
家具导出插件 v2.6.0 - 安装指南
═══════════════════════════════════════════════════════════════════════
安装步骤(只需30秒)
@ -16,8 +16,10 @@
使用方法
───────────────────────────────────────────────────────────────────────
打开 AutoCAD 后,命令行输入:
FEXPORTASSET -> 单资产导出到资产中心(板材 / 组件 / 五金)
FEXPORT -> 整套家具兼容导出
FEXPORT -> 单资产导出到资产中心(板材 / 组件 / 五金)
FEXPORTASSET -> 单资产导出别名
FEXPORTPRODUCT -> 整套家具兼容导出
FEXPORTBUNDLE -> 整套家具兼容导出别名
FINFO -> 查看实体信息
安装脚本做了什么(便于 IT/排查)
@ -31,10 +33,10 @@
常见问题
───────────────────────────────────────────────────────────────────────
Q: 提示“未知命令 FEXPORTASSET / FEXPORT”
Q: 提示“未知命令 FEXPORT / FEXPORTPRODUCT”
A: 1) 确认已重启 AutoCAD(关闭再打开)
2) 确认插件目录存在:
%AppData%\Autodesk\ApplicationPlugins\FurnitureExporter.bundle\Contents\FurnitureExporter.dll
3) 如果 SECURELOAD=2,脚本会将其降到 1;如仍无效请截图安装日志给开发排查
版本: v2.5.0
版本: v2.6.0

View File

@ -1,13 +0,0 @@
{
"timestamp": "2025-12-18T22:40:21.8958346+08:00",
"root": ".\\backups\\full\\20251218-224021",
"components": {
"database": null,
"files": null,
"config": [
".env",
"docker-compose*.yml",
"prisma/schema.prisma"
]
}
}

View File

@ -1,160 +0,0 @@
# ============================================
# 3D家具安装展示系统 - 缓存优化版Docker Compose
# 使用本地缓存加速构建和部署
# ============================================
version: '3.8'
services:
# PostgreSQL 数据库
postgres:
image: postgres:15-alpine
container_name: furniture-3d-postgres
environment:
POSTGRES_DB: furniture_3d
POSTGRES_USER: furniture_user
POSTGRES_PASSWORD: furniture_pass_2024
POSTGRES_INITDB_ARGS: "--encoding=UTF-8 --lc-collate=C --lc-ctype=C"
volumes:
- postgres_data:/var/lib/postgresql/data
- ./cache/postgres-init:/docker-entrypoint-initdb.d:ro
ports:
- "5432:5432"
networks:
- furniture-network
restart: unless-stopped
healthcheck:
test: ["CMD-SHELL", "pg_isready -U furniture_user -d furniture_3d"]
interval: 10s
timeout: 5s
retries: 5
# MinIO 对象存储
minio:
image: minio/minio:latest
container_name: furniture-3d-minio
environment:
MINIO_ROOT_USER: minioadmin
MINIO_ROOT_PASSWORD: minioadmin
MINIO_BROWSER_REDIRECT_URL: http://localhost:9001
volumes:
- minio_data:/data
- ./cache/minio-config:/root/.minio:ro
ports:
- "9000:9000"
- "9001:9001"
networks:
- furniture-network
command: server /data --console-address ":9001"
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
interval: 30s
timeout: 20s
retries: 3
# 3D家具展示应用
app:
build:
context: .
dockerfile: Dockerfile.optimized
args:
DATABASE_URL: postgresql://furniture_user:furniture_pass_2024@postgres:5432/furniture_3d
NEXTAUTH_URL: http://localhost:3000
APP_PUBLIC_URL: http://localhost:3000
# 使用缓存挂载加速构建
cache_from:
- node:18-alpine
target: runner
container_name: furniture-3d-app
environment:
# 数据库配置
DATABASE_URL: postgresql://furniture_user:furniture_pass_2024@postgres:5432/furniture_3d
# 认证配置
NEXTAUTH_SECRET: furniture-3d-secret-key-2024
NEXTAUTH_URL: http://localhost:3000
APP_PUBLIC_URL: http://localhost:3000
# MinIO/S3配置
S3_ENDPOINT: http://minio:9000
S3_BUCKET: furniture-3d-models
S3_ACCESS_KEY: minioadmin
S3_SECRET_KEY: minioadmin
S3_REGION: us-east-1
S3_FORCE_PATH_STYLE: "true"
# 应用配置
NODE_ENV: production
PORT: 3000
# 3D渲染优化
NEXT_SHARP: 0
NEXT_TELEMETRY_DISABLED: 1
volumes:
- app_uploads:/app/uploads
# 挂载本地缓存(只读)
- ./cache/prisma-engines:/app/prisma/engine-cache:ro
ports:
- "3000:3000"
networks:
- furniture-network
depends_on:
postgres:
condition: service_healthy
minio:
condition: service_healthy
restart: unless-stopped
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:3000/api/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
# MinIO 初始化服务(创建存储桶等)
minio-init:
image: minio/mc:latest
container_name: furniture-3d-minio-init
environment:
MINIO_ENDPOINT: http://minio:9000
MINIO_ACCESS_KEY: minioadmin
MINIO_SECRET_KEY: minioadmin
networks:
- furniture-network
depends_on:
minio:
condition: service_healthy
entrypoint: >
/bin/sh -c "
echo '🔧 配置MinIO客户端...'
mc alias set furniture http://minio:9000 minioadmin minioadmin
echo '📦 创建存储桶...'
mc mb furniture/furniture-3d-models --ignore-existing
mc mb furniture/furniture-3d-thumbnails --ignore-existing
mc mb furniture/furniture-3d-cache --ignore-existing
echo '🔒 设置存储桶策略...'
mc anonymous set public furniture/furniture-3d-models
mc anonymous set public furniture/furniture-3d-thumbnails
echo '✅ MinIO初始化完成'
"
restart: "no"
volumes:
postgres_data:
driver: local
name: furniture-3d-postgres-data
minio_data:
driver: local
name: furniture-3d-minio-data
app_uploads:
driver: local
name: furniture-3d-app-uploads
networks:
furniture-network:
driver: bridge
name: furniture-3d-network

View File

@ -1,43 +0,0 @@
version: '3.8'
services:
postgres:
image: postgres:15-alpine
container_name: furniture-postgres
environment:
POSTGRES_USER: furniture
POSTGRES_PASSWORD: furniture123
POSTGRES_DB: furniture_db
ports:
- "5432:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
restart: unless-stopped
redis:
image: redis:7-alpine
container_name: furniture-redis
ports:
- "6379:6379"
volumes:
- redis_data:/data
restart: unless-stopped
minio:
image: minio/minio:latest
container_name: furniture-minio
command: server /data --console-address ":9001"
environment:
MINIO_ROOT_USER: minioadmin
MINIO_ROOT_PASSWORD: minioadmin123
ports:
- "9000:9000"
- "9001:9001"
volumes:
- minio_data:/data
restart: unless-stopped
volumes:
postgres_data:
redis_data:
minio_data:

View File

@ -1,163 +0,0 @@
# 3D 家具安装展示系统 - 轻量级模式
# 适用于: 4-8GB 内存的设备 (Intel N100 等低功耗处理器)
# 性能目标: 优化资源使用,保证基本功能
version: '3.8'
services:
# 前端服务 - Nginx + Next.js 静态资源
frontend:
image: furniture-3d-frontend:latest
container_name: furniture-frontend
restart: unless-stopped
ports:
- "${WEB_PORT:-3000}:80"
environment:
- NGINX_WORKER_PROCESSES=2
- NGINX_WORKER_CONNECTIONS=512
- ENABLE_GZIP_COMPRESSION=true
volumes:
- nginx-cache:/var/cache/nginx
depends_on:
backend:
condition: service_healthy
networks:
- furniture-network
mem_limit: 512m
cpus: 1.0
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:80/health"]
interval: 30s
timeout: 10s
retries: 3
# 后端服务 - Next.js API + Prisma
backend:
image: furniture-3d-backend:latest
container_name: furniture-backend
restart: unless-stopped
environment:
- NODE_ENV=production
- DATABASE_URL=${DATABASE_URL}
- REDIS_URL=${REDIS_URL}
- S3_ENDPOINT=${S3_ENDPOINT}
- S3_BUCKET=${S3_BUCKET}
- MINIO_USER=${MINIO_USER}
- MINIO_PASSWORD=${MINIO_PASSWORD}
# 轻量级性能配置
- DB_POOL_SIZE=10
- ENABLE_COMPRESSION=true
- MAX_CONCURRENT_REQUESTS=20
- MODEL_CACHE_SIZE=100
- ENABLE_MEMORY_OPTIMIZATION=true
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_started
minio:
condition: service_started
networks:
- furniture-network
mem_limit: 1g
cpus: 2.0
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3001/api/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
# PostgreSQL 数据库 - 轻量级配置
postgres:
image: postgres:15-alpine
container_name: furniture-postgres
restart: unless-stopped
environment:
- POSTGRES_DB=furniture_db
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=${DB_PASSWORD}
- PGDATA=/var/lib/postgresql/data/pgdata
command: >
postgres
-c shared_buffers=128MB
-c max_connections=50
-c work_mem=8MB
-c maintenance_work_mem=64MB
-c effective_cache_size=256MB
-c checkpoint_completion_target=0.9
-c wal_buffers=8MB
-c default_statistics_target=50
-c random_page_cost=1.1
-c effective_io_concurrency=200
volumes:
- postgres-data:/var/lib/postgresql/data
networks:
- furniture-network
mem_limit: 512m
cpus: 1.0
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres -d furniture_db"]
interval: 10s
timeout: 5s
retries: 5
# MinIO 对象存储 - 轻量级配置
minio:
image: minio/minio:latest
container_name: furniture-minio
restart: unless-stopped
environment:
- MINIO_ROOT_USER=${MINIO_USER}
- MINIO_ROOT_PASSWORD=${MINIO_PASSWORD}
- MINIO_BROWSER_REDIRECT_URL=http://localhost:9001
command: server /data --console-address ":9001"
volumes:
- minio-data:/data
networks:
- furniture-network
mem_limit: 512m
cpus: 0.5
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
interval: 30s
timeout: 20s
retries: 3
# Redis 缓存 - 轻量级配置
redis:
image: redis:7-alpine
container_name: furniture-redis
restart: unless-stopped
command: >
redis-server
--maxmemory 200mb
--maxmemory-policy allkeys-lru
--save 900 1
--save 300 10
--appendonly no
volumes:
- redis-data:/data
networks:
- furniture-network
mem_limit: 256m
cpus: 0.5
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 3s
retries: 3
networks:
furniture-network:
driver: bridge
volumes:
postgres-data:
driver: local
minio-data:
driver: local
redis-data:
driver: local
nginx-cache:
driver: local

View File

@ -1,160 +0,0 @@
# 3D 家具安装展示系统 - 标准模式
# 适用于: 8GB+ 内存的服务器/NAS
# 性能目标: 支持中等并发,完整功能
version: '3.8'
services:
# 前端服务 - Nginx + Next.js 静态资源
frontend:
image: furniture-3d-frontend:latest
container_name: furniture-frontend
restart: unless-stopped
ports:
- "${WEB_PORT:-3000}:80"
environment:
- NGINX_WORKER_PROCESSES=4
- NGINX_WORKER_CONNECTIONS=1024
- ENABLE_GZIP_COMPRESSION=true
volumes:
- nginx-cache:/var/cache/nginx
depends_on:
backend:
condition: service_healthy
networks:
- furniture-network
mem_limit: 1g
cpus: 2.0
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:80/health"]
interval: 30s
timeout: 10s
retries: 3
# 后端服务 - Next.js API + Prisma
backend:
image: furniture-3d-backend:latest
container_name: furniture-backend
restart: unless-stopped
environment:
- NODE_ENV=production
- DATABASE_URL=${DATABASE_URL}
- REDIS_URL=${REDIS_URL}
- S3_ENDPOINT=${S3_ENDPOINT}
- S3_BUCKET=${S3_BUCKET}
- MINIO_USER=${MINIO_USER}
- MINIO_PASSWORD=${MINIO_PASSWORD}
# 性能配置
- DB_POOL_SIZE=20
- ENABLE_COMPRESSION=true
- MAX_CONCURRENT_REQUESTS=50
- MODEL_CACHE_SIZE=200
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_started
minio:
condition: service_started
networks:
- furniture-network
mem_limit: 2g
cpus: 4.0
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3001/api/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
# PostgreSQL 数据库
postgres:
image: postgres:15-alpine
container_name: furniture-postgres
restart: unless-stopped
environment:
- POSTGRES_DB=furniture_db
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=${DB_PASSWORD}
- PGDATA=/var/lib/postgresql/data/pgdata
command: >
postgres
-c shared_buffers=256MB
-c max_connections=100
-c work_mem=16MB
-c maintenance_work_mem=128MB
-c effective_cache_size=512MB
-c checkpoint_completion_target=0.9
-c wal_buffers=16MB
-c default_statistics_target=100
volumes:
- postgres-data:/var/lib/postgresql/data
networks:
- furniture-network
mem_limit: 1g
cpus: 2.0
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres -d furniture_db"]
interval: 10s
timeout: 5s
retries: 5
# MinIO 对象存储 - 3D 模型文件
minio:
image: minio/minio:latest
container_name: furniture-minio
restart: unless-stopped
environment:
- MINIO_ROOT_USER=${MINIO_USER}
- MINIO_ROOT_PASSWORD=${MINIO_PASSWORD}
- MINIO_BROWSER_REDIRECT_URL=http://localhost:9001
command: server /data --console-address ":9001"
volumes:
- minio-data:/data
networks:
- furniture-network
mem_limit: 1g
cpus: 1.0
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
interval: 30s
timeout: 20s
retries: 3
# Redis 缓存
redis:
image: redis:7-alpine
container_name: furniture-redis
restart: unless-stopped
command: >
redis-server
--maxmemory 400mb
--maxmemory-policy allkeys-lru
--save 900 1
--save 300 10
--save 60 10000
volumes:
- redis-data:/data
networks:
- furniture-network
mem_limit: 512m
cpus: 1.0
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 3s
retries: 3
networks:
furniture-network:
driver: bridge
volumes:
postgres-data:
driver: local
minio-data:
driver: local
redis-data:
driver: local
nginx-cache:
driver: local

View File

@ -1,111 +0,0 @@
# 3D 家具安装展示系统 - 测试配置
# 用于测试部署脚本,使用简化的服务配置
version: '3.8'
services:
# PostgreSQL 数据库
postgres:
image: postgres:15-alpine
container_name: furniture-postgres-test
restart: unless-stopped
environment:
- POSTGRES_DB=furniture_db
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=${DB_PASSWORD:-test_password_123}
- PGDATA=/var/lib/postgresql/data/pgdata
command: >
postgres
-c shared_buffers=128MB
-c max_connections=50
volumes:
- postgres-test-data:/var/lib/postgresql/data
networks:
- furniture-test-network
ports:
- "5432:5432"
mem_limit: 512m
cpus: 1.0
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres -d furniture_db"]
interval: 10s
timeout: 5s
retries: 5
# MinIO 对象存储
minio:
image: minio/minio:latest
container_name: furniture-minio-test
restart: unless-stopped
environment:
- MINIO_ROOT_USER=${MINIO_USER:-admin}
- MINIO_ROOT_PASSWORD=${MINIO_PASSWORD:-test_minio_password_123}
command: server /data --console-address ":9001"
volumes:
- minio-test-data:/data
networks:
- furniture-test-network
ports:
- "9000:9000"
- "9001:9001"
mem_limit: 512m
cpus: 0.5
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
interval: 30s
timeout: 20s
retries: 3
# Redis 缓存
redis:
image: redis:7-alpine
container_name: furniture-redis-test
restart: unless-stopped
command: >
redis-server
--maxmemory 200mb
--maxmemory-policy allkeys-lru
volumes:
- redis-test-data:/data
networks:
- furniture-test-network
ports:
- "6379:6379"
mem_limit: 256m
cpus: 0.5
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 3s
retries: 3
# Nginx 测试服务 (模拟前端)
nginx:
image: nginx:alpine
container_name: furniture-nginx-test
restart: unless-stopped
ports:
- "${WEB_PORT:-3000}:80"
networks:
- furniture-test-network
mem_limit: 128m
cpus: 0.5
healthcheck:
test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:80"]
interval: 30s
timeout: 10s
retries: 3
volumes:
- ./test-html:/usr/share/nginx/html:ro
networks:
furniture-test-network:
driver: bridge
volumes:
postgres-test-data:
driver: local
minio-test-data:
driver: local
redis-test-data:
driver: local

View File

@ -1,43 +0,0 @@
version: '3.8'
services:
postgres:
image: postgres:15-alpine
container_name: furniture3d-postgres
restart: unless-stopped
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: furniture3d
ports:
- "5432:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5
minio:
image: minio/minio:latest
container_name: furniture3d-minio
restart: unless-stopped
command: server /data --console-address ":9001"
environment:
MINIO_ROOT_USER: minioadmin
MINIO_ROOT_PASSWORD: minioadmin
ports:
- "9000:9000"
- "9001:9001"
volumes:
- minio_data:/data
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
interval: 30s
timeout: 20s
retries: 3
volumes:
postgres_data:
minio_data:

View File

@ -1,440 +0,0 @@
// 新的 Prisma schema - Product-SKU 结构
// 针对电商企业的产品管理需求设计
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
// ============================================
// 产品管理(Product-SKU结构)
// ============================================
// 产品(型号)
model Product {
id String @id @default(cuid())
modelNumber String @unique // 型号,如 "A001"
name String // 产品名称,如 "现代简约沙发"
description String? @db.Text // 产品描述
category String? // 产品分类
// 3D模型相关(型号级别的基础模型)
modelUrl String? // 基础3D模型URL (glTF)
thumbnailUrl String? // 缩略图
// 归属信息(型号级别 - 多人协作)
createdBy String // 创建者
creator User @relation("ProductCreator", fields: [createdBy], references: [id])
// 协作者列表(多人可编辑)
collaborators Json? // [{ userId: "xxx", role: "editor", addedAt: "..." }]
// 部门归属
departmentId String?
department Department? @relation(fields: [departmentId], references: [id])
// 可见性
visibility String @default("TEAM") // PRIVATE, TEAM, DEPARTMENT, PUBLIC
// SKU列表
skus ProductSKU[]
// 装配步骤(型号级别,所有SKU共享)
assemblySteps AssemblyStep[]
// 板件(型号级别)
panels Panel[]
// 分享链接
shareLinks ShareLink[]
// 问题反馈
feedbacks Feedback[]
// 元数据
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
deletedAt DateTime? // 软删除
@@index([modelNumber])
@@index([category])
@@index([createdBy])
@@index([departmentId])
}
// 产品SKU(库存单位)
model ProductSKU {
id String @id @default(cuid())
productId String // 关联的产品ID
product Product @relation(fields: [productId], references: [id], onDelete: Cascade)
// SKU标识
skuCode String @unique // SKU编码,如 "A001-RED-3S"
// 规格属性(灵活的JSON结构)
// 示例: { "color": "红色", "size": "三人座", "material": "布艺" }
attributes Json
// 价格和库存
price Decimal @db.Decimal(10, 2) // 售价
costPrice Decimal? @db.Decimal(10, 2) // 成本价
stock Int @default(0) // 库存数量
// 图片(SKU特定的图片)
images String[] // 图片URL数组
// 3D模型(如果SKU有特定的3D模型变体,否则使用Product的基础模型)
modelUrl String? // SKU特定的3D模型URL
// 归属信息(SKU 级别 - 单人负责)
ownerId String // 负责人ID
owner User @relation("SKUOwner", fields: [ownerId], references: [id])
// 交接记录
transferHistory Json? // [{ fromUserId, toUserId, transferredAt, reason, operatorId }]
// 状态
isActive Boolean @default(true) // 是否上架
// 元数据
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
deletedAt DateTime? // 软删除
@@index([productId])
@@index([skuCode])
@@index([isActive])
@@index([ownerId])
}
// ============================================
// 装配相关
// ============================================
// 装配步骤(属于Product,所有SKU共享)
model AssemblyStep {
id String @id @default(cuid())
productId String
product Product @relation(fields: [productId], references: [id], onDelete: Cascade)
order Int // 步骤顺序
title String // 步骤标题
description String? @db.Text // 步骤说明
// 动画数据(JSON)
partIds String[] // 参与的部件 ID
transform Json // 目标变换 {position, rotation, scale}
duration Int // 动画时长(ms)
easing String // 缓动函数
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([productId, order])
}
// 板件(属于Product)
model Panel {
id String @id @default(cuid())
productId String
product Product @relation(fields: [productId], references: [id], onDelete: Cascade)
code String // 编号
name String // 名称
gltfNodeName String // glTF 节点名
// 尺寸
length Float
width Float
thickness Float
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([productId])
}
// ============================================
// 分享功能
// ============================================
// 分享链接
model ShareLink {
id String @id @default(cuid())
productId String
product Product @relation(fields: [productId], references: [id], onDelete: Cascade)
token String @unique // 分享令牌
expiresAt DateTime? // 过期时间(可选)
viewCount Int @default(0) // 查看次数
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([productId])
@@index([token])
}
// ============================================
// 用户管理
// ============================================
// 角色枚举
enum Role {
SUPER_ADMIN // 超级管理员
ADMIN // 管理员
DEPARTMENT_MANAGER // 部门管理员
TEAM_LEADER // 组长
DESIGNER // 设计师
VIEWER // 查看者
}
// 用户状态枚举
enum UserStatus {
ACTIVE // 在职
INACTIVE // 离职
SUSPENDED // 暂停
}
// 用户
model User {
id String @id @default(cuid())
// 登录凭证
email String @unique // 邮箱(用于登录)
name String @unique // 姓名/花名(用于登录和显示)
password String
// 首次登录标识
isFirstLogin Boolean @default(true) // 超级管理员首次登录需强制修改信息
// 其他信息
avatar String?
phone String?
// 角色与权限
role Role @default(DESIGNER)
// 组织架构
departmentId String?
department Department? @relation("DepartmentMembers", fields: [departmentId], references: [id])
teamId String?
team Team? @relation("TeamMembers", fields: [teamId], references: [id])
// 管理关系
managedDepartment Department? @relation("DepartmentManager")
managedTeam Team? @relation("TeamLeader")
// 状态
status UserStatus @default(ACTIVE)
// 关联
createdProducts Product[] @relation("ProductCreator")
ownedSKUs ProductSKU[] @relation("SKUOwner")
feedbacks Feedback[] @relation("FeedbackSubmitter")
assignedFeedbacks Feedback[] @relation("FeedbackAssignee")
// 操作日志
activityLogs ActivityLog[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
lastLoginAt DateTime?
@@index([email])
@@index([name])
@@index([departmentId])
@@index([teamId])
@@index([status])
}
// 部门
model Department {
id String @id @default(cuid())
name String @unique
fullPath String // 完整路径,如 "设计部-3D组-建模小组"
// 层级关系
parentId String?
parent Department? @relation("DepartmentTree", fields: [parentId], references: [id])
children Department[] @relation("DepartmentTree")
// 部门负责人
managerId String? @unique
manager User? @relation("DepartmentManager", fields: [managerId], references: [id])
// 成员
members User[] @relation("DepartmentMembers")
// 小组
teams Team[]
// 产品
products Product[]
// 排序
orderIndex Int @default(0)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([parentId])
}
// 小组
model Team {
id String @id @default(cuid())
name String
description String?
// 所属部门
departmentId String
department Department @relation(fields: [departmentId], references: [id], onDelete: Cascade)
// 组长
leaderId String? @unique
leader User? @relation("TeamLeader", fields: [leaderId], references: [id])
// 成员
members User[] @relation("TeamMembers")
// 排序
orderIndex Int @default(0)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@unique([departmentId, name])
@@index([departmentId])
}
// ============================================
// 问题反馈
// ============================================
// 反馈状态枚举
enum FeedbackStatus {
PENDING // 待处理
IN_PROGRESS // 处理中
RESOLVED // 已解决
CLOSED // 已关闭
}
// 反馈优先级枚举
enum FeedbackPriority {
LOW // 低
MEDIUM // 中
HIGH // 高
URGENT // 紧急
}
// 问题反馈
model Feedback {
id String @id @default(cuid())
// 关联产品
productId String
product Product @relation(fields: [productId], references: [id], onDelete: Cascade)
skuId String? // 可选:具体的 SKU
// 反馈内容
title String
description String @db.Text
images String[] // 问题截图
// 问题分类
category String // 模型错误、尺寸错误、材质错误、装配步骤错误等
priority FeedbackPriority @default(MEDIUM)
// 提交者
submitterId String
submitter User @relation("FeedbackSubmitter", fields: [submitterId], references: [id])
// 处理者
assigneeId String?
assignee User? @relation("FeedbackAssignee", fields: [assigneeId], references: [id])
// 状态
status FeedbackStatus @default(PENDING)
// 处理记录
comments Json? // [{ userId, content, createdAt }]
// 解决方案
resolution String? @db.Text
resolvedAt DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([productId])
@@index([submitterId])
@@index([assigneeId])
@@index([status])
}
// ============================================
// 操作日志
// ============================================
// 操作类型枚举
enum ActivityType {
USER_REGISTER
USER_LOGIN
USER_LOGIN_FAILED
USER_LOGOUT
USER_FIRST_LOGIN_UPDATE
USER_CREATE
USER_UPDATE
USER_DELETE
PRODUCT_CREATE
PRODUCT_UPDATE
PRODUCT_DELETE
SKU_CREATE
SKU_UPDATE
SKU_DELETE
SKU_TRANSFER
FILE_UPLOAD
FILE_DOWNLOAD
SHARE_LINK_CREATE
SHARE_LINK_ACCESS
FEEDBACK_CREATE
FEEDBACK_UPDATE
DATA_EXPORT
}
// 操作日志
model ActivityLog {
id String @id @default(cuid())
// 操作者
userId String
user User @relation(fields: [userId], references: [id])
// 操作类型
type ActivityType
// 操作对象
targetType String? // Product, ProductSKU, User, Feedback
targetId String?
// 操作详情
action String // 具体操作描述
changes Json? // 变更内容
metadata Json? // 额外信息(IP、设备等)
// 时间
createdAt DateTime @default(now())
@@index([userId, createdAt])
@@index([targetType, targetId])
@@index([type, createdAt])
}

View File

@ -1,2 +0,0 @@
[2025-12-18 22:40:21] INFO: 检查依赖...
[2025-12-18 22:40:21] ERROR: pg_dump 未安装,请安装 PostgreSQL 客户端工具

View File

@ -1,4 +0,0 @@
[2025-12-18 22:40:21] INFO: 检查依赖...
[2025-12-18 22:40:21] SUCCESS: ✅ 依赖检查通过
[2025-12-18 22:40:21] INFO: 验证 MinIO 数据目录...
[2025-12-18 22:40:21] ERROR: MinIO 数据目录不存在: .\minio-data

View File

@ -1,26 +0,0 @@
import { PrismaClient } from '@prisma/client'
const prisma = new PrismaClient()
async function main() {
const product = await prisma.product.findFirst({
where: {
assemblySteps: {
some: {},
},
},
select: {
id: true,
name: true,
modelNumber: true,
modelUrl: true,
thumbnailUrl: true,
},
})
console.log('Product:', JSON.stringify(product, null, 2))
}
main()
.catch(console.error)
.finally(() => prisma.$disconnect())

View File

@ -1,160 +0,0 @@
# ============================================
# 3D家具安装展示系统 - 缓存优化版Docker Compose
# 使用本地缓存加速构建和部署
# ============================================
version: '3.8'
services:
# PostgreSQL 数据库
postgres:
image: postgres:15-alpine
container_name: furniture-3d-postgres
environment:
POSTGRES_DB: furniture_3d
POSTGRES_USER: furniture_user
POSTGRES_PASSWORD: furniture_pass_2024
POSTGRES_INITDB_ARGS: "--encoding=UTF-8 --lc-collate=C --lc-ctype=C"
volumes:
- postgres_data:/var/lib/postgresql/data
- ./cache/postgres-init:/docker-entrypoint-initdb.d:ro
ports:
- "5432:5432"
networks:
- furniture-network
restart: unless-stopped
healthcheck:
test: ["CMD-SHELL", "pg_isready -U furniture_user -d furniture_3d"]
interval: 10s
timeout: 5s
retries: 5
# MinIO 对象存储
minio:
image: minio/minio:latest
container_name: furniture-3d-minio
environment:
MINIO_ROOT_USER: minioadmin
MINIO_ROOT_PASSWORD: minioadmin
MINIO_BROWSER_REDIRECT_URL: http://localhost:9001
volumes:
- minio_data:/data
- ./cache/minio-config:/root/.minio:ro
ports:
- "9000:9000"
- "9001:9001"
networks:
- furniture-network
command: server /data --console-address ":9001"
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
interval: 30s
timeout: 20s
retries: 3
# 3D家具展示应用
app:
build:
context: .
dockerfile: Dockerfile.optimized
args:
DATABASE_URL: postgresql://furniture_user:furniture_pass_2024@postgres:5432/furniture_3d
NEXTAUTH_URL: http://localhost:3000
APP_PUBLIC_URL: http://localhost:3000
# 使用缓存挂载加速构建
cache_from:
- node:18-alpine
target: runner
container_name: furniture-3d-app
environment:
# 数据库配置
DATABASE_URL: postgresql://furniture_user:furniture_pass_2024@postgres:5432/furniture_3d
# 认证配置
NEXTAUTH_SECRET: furniture-3d-secret-key-2024
NEXTAUTH_URL: http://localhost:3000
APP_PUBLIC_URL: http://localhost:3000
# MinIO/S3配置
S3_ENDPOINT: http://minio:9000
S3_BUCKET: furniture-3d-models
S3_ACCESS_KEY: minioadmin
S3_SECRET_KEY: minioadmin
S3_REGION: us-east-1
S3_FORCE_PATH_STYLE: "true"
# 应用配置
NODE_ENV: production
PORT: 3000
# 3D渲染优化
NEXT_SHARP: 0
NEXT_TELEMETRY_DISABLED: 1
volumes:
- app_uploads:/app/uploads
# 挂载本地缓存(只读)
- ./cache/prisma-engines:/app/prisma/engine-cache:ro
ports:
- "3000:3000"
networks:
- furniture-network
depends_on:
postgres:
condition: service_healthy
minio:
condition: service_healthy
restart: unless-stopped
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:3000/api/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
# MinIO 初始化服务(创建存储桶等)
minio-init:
image: minio/mc:latest
container_name: furniture-3d-minio-init
environment:
MINIO_ENDPOINT: http://minio:9000
MINIO_ACCESS_KEY: minioadmin
MINIO_SECRET_KEY: minioadmin
networks:
- furniture-network
depends_on:
minio:
condition: service_healthy
entrypoint: >
/bin/sh -c "
echo '🔧 配置MinIO客户端...'
mc alias set furniture http://minio:9000 minioadmin minioadmin
echo '📦 创建存储桶...'
mc mb furniture/furniture-3d-models --ignore-existing
mc mb furniture/furniture-3d-thumbnails --ignore-existing
mc mb furniture/furniture-3d-cache --ignore-existing
echo '🔒 设置存储桶策略...'
mc anonymous set public furniture/furniture-3d-models
mc anonymous set public furniture/furniture-3d-thumbnails
echo '✅ MinIO初始化完成'
"
restart: "no"
volumes:
postgres_data:
driver: local
name: furniture-3d-postgres-data
minio_data:
driver: local
name: furniture-3d-minio-data
app_uploads:
driver: local
name: furniture-3d-app-uploads
networks:
furniture-network:
driver: bridge
name: furniture-3d-network

View File

@ -1,66 +0,0 @@
version: '3.8'
services:
postgres:
image: postgres:15-alpine
container_name: furniture-postgres
environment:
POSTGRES_USER: furniture
POSTGRES_PASSWORD: furniture123
POSTGRES_DB: furniture_db
ports:
- "5432:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
restart: unless-stopped
redis:
image: redis:7-alpine
container_name: furniture-redis
ports:
- "6379:6379"
volumes:
- redis_data:/data
restart: unless-stopped
minio:
image: minio/minio:latest
container_name: furniture-minio
command: server /data --console-address ":9001"
environment:
MINIO_ROOT_USER: minioadmin
MINIO_ROOT_PASSWORD: minioadmin123
ports:
- "9000:9000"
- "9001:9001"
volumes:
- minio_data:/data
restart: unless-stopped
# DWG 转换服务(ODA 方案)
#
# 使用方法:
# 1. 构建镜像:docker-compose -f docker-compose.dev.yml --profile dwg build dwg-converter
# 2. 启动服务:docker-compose -f docker-compose.dev.yml --profile dwg up -d dwg-converter
#
# ODA File Converter 会自动从官方下载(约 100MB)
#
dwg-converter:
build:
context: .
dockerfile: docker/Dockerfile.oda
container_name: furniture-dwg-converter
ports:
- "3001:3001"
volumes:
- ./public/uploads:/app/uploads
environment:
- PYTHONUNBUFFERED=1
restart: unless-stopped
profiles:
- dwg # 使用 --profile dwg 启动此服务
volumes:
postgres_data:
redis_data:
minio_data:

View File

@ -1,163 +0,0 @@
# 3D 家具安装展示系统 - 轻量级模式
# 适用于: 4-8GB 内存的设备 (Intel N100 等低功耗处理器)
# 性能目标: 优化资源使用,保证基本功能
version: '3.8'
services:
# 前端服务 - Nginx + Next.js 静态资源
frontend:
image: furniture-3d-frontend:latest
container_name: furniture-frontend
restart: unless-stopped
ports:
- "${WEB_PORT:-3000}:80"
environment:
- NGINX_WORKER_PROCESSES=2
- NGINX_WORKER_CONNECTIONS=512
- ENABLE_GZIP_COMPRESSION=true
volumes:
- nginx-cache:/var/cache/nginx
depends_on:
backend:
condition: service_healthy
networks:
- furniture-network
mem_limit: 512m
cpus: 1.0
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:80/health"]
interval: 30s
timeout: 10s
retries: 3
# 后端服务 - Next.js API + Prisma
backend:
image: furniture-3d-backend:latest
container_name: furniture-backend
restart: unless-stopped
environment:
- NODE_ENV=production
- DATABASE_URL=${DATABASE_URL}
- REDIS_URL=${REDIS_URL}
- S3_ENDPOINT=${S3_ENDPOINT}
- S3_BUCKET=${S3_BUCKET}
- MINIO_USER=${MINIO_USER}
- MINIO_PASSWORD=${MINIO_PASSWORD}
# 轻量级性能配置
- DB_POOL_SIZE=10
- ENABLE_COMPRESSION=true
- MAX_CONCURRENT_REQUESTS=20
- MODEL_CACHE_SIZE=100
- ENABLE_MEMORY_OPTIMIZATION=true
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_started
minio:
condition: service_started
networks:
- furniture-network
mem_limit: 1g
cpus: 2.0
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3001/api/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
# PostgreSQL 数据库 - 轻量级配置
postgres:
image: postgres:15-alpine
container_name: furniture-postgres
restart: unless-stopped
environment:
- POSTGRES_DB=furniture_db
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=${DB_PASSWORD}
- PGDATA=/var/lib/postgresql/data/pgdata
command: >
postgres
-c shared_buffers=128MB
-c max_connections=50
-c work_mem=8MB
-c maintenance_work_mem=64MB
-c effective_cache_size=256MB
-c checkpoint_completion_target=0.9
-c wal_buffers=8MB
-c default_statistics_target=50
-c random_page_cost=1.1
-c effective_io_concurrency=200
volumes:
- postgres-data:/var/lib/postgresql/data
networks:
- furniture-network
mem_limit: 512m
cpus: 1.0
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres -d furniture_db"]
interval: 10s
timeout: 5s
retries: 5
# MinIO 对象存储 - 轻量级配置
minio:
image: minio/minio:latest
container_name: furniture-minio
restart: unless-stopped
environment:
- MINIO_ROOT_USER=${MINIO_USER}
- MINIO_ROOT_PASSWORD=${MINIO_PASSWORD}
- MINIO_BROWSER_REDIRECT_URL=http://localhost:9001
command: server /data --console-address ":9001"
volumes:
- minio-data:/data
networks:
- furniture-network
mem_limit: 512m
cpus: 0.5
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
interval: 30s
timeout: 20s
retries: 3
# Redis 缓存 - 轻量级配置
redis:
image: redis:7-alpine
container_name: furniture-redis
restart: unless-stopped
command: >
redis-server
--maxmemory 200mb
--maxmemory-policy allkeys-lru
--save 900 1
--save 300 10
--appendonly no
volumes:
- redis-data:/data
networks:
- furniture-network
mem_limit: 256m
cpus: 0.5
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 3s
retries: 3
networks:
furniture-network:
driver: bridge
volumes:
postgres-data:
driver: local
minio-data:
driver: local
redis-data:
driver: local
nginx-cache:
driver: local

View File

@ -1,177 +0,0 @@
# ============================================
# 生产环境 Docker Compose 配置
# ============================================
# 使用方法:
# docker-compose -f docker-compose.prod.yml up -d
# ============================================
version: '3.8'
services:
# PostgreSQL 数据库
postgres:
image: postgres:15-alpine
container_name: furniture3d-postgres
restart: always
environment:
POSTGRES_USER: ${DB_USER:-postgres}
POSTGRES_PASSWORD: ${DB_PASSWORD:-postgres}
POSTGRES_DB: ${DB_NAME:-furniture3d}
# 性能优化参数
POSTGRES_INITDB_ARGS: "--encoding=UTF8 --locale=C"
ports:
- "${DB_PORT:-5432}:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
- ./backups/database:/backups
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${DB_USER:-postgres} -d ${DB_NAME:-furniture3d}"]
interval: 10s
timeout: 5s
retries: 5
start_period: 30s
deploy:
resources:
limits:
cpus: '2'
memory: 2G
reservations:
cpus: '0.5'
memory: 512M
logging:
driver: "json-file"
options:
max-size: "50m"
max-file: "5"
networks:
- furniture3d-network
# Redis 缓存
redis:
image: redis:7-alpine
container_name: furniture3d-redis
restart: always
command: redis-server --appendonly yes --maxmemory 256mb --maxmemory-policy allkeys-lru
ports:
- "${REDIS_PORT:-6379}:6379"
volumes:
- redis_data:/data
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 5
start_period: 10s
deploy:
resources:
limits:
cpus: '0.5'
memory: 512M
reservations:
cpus: '0.1'
memory: 128M
logging:
driver: "json-file"
options:
max-size: "20m"
max-file: "3"
networks:
- furniture3d-network
# MinIO 对象存储
minio:
image: minio/minio:latest
container_name: furniture3d-minio
restart: always
command: server /data --console-address ":9001"
environment:
MINIO_ROOT_USER: ${MINIO_ROOT_USER:-minioadmin}
MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD:-minioadmin}
# 生产环境建议启用 TLS
# MINIO_SERVER_URL: https://minio.yourdomain.com
ports:
- "${MINIO_API_PORT:-9000}:9000"
- "${MINIO_CONSOLE_PORT:-9001}:9001"
volumes:
- minio_data:/data
- ./backups/files:/backups
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
interval: 30s
timeout: 20s
retries: 3
start_period: 30s
deploy:
resources:
limits:
cpus: '1'
memory: 1G
reservations:
cpus: '0.25'
memory: 256M
logging:
driver: "json-file"
options:
max-size: "50m"
max-file: "5"
networks:
- furniture3d-network
# Next.js 应用(可选,也可以单独部署)
app:
build:
context: .
dockerfile: Dockerfile
container_name: furniture3d-app
restart: always
environment:
NODE_ENV: production
DATABASE_URL: postgresql://${DB_USER:-postgres}:${DB_PASSWORD:-postgres}@postgres:5432/${DB_NAME:-furniture3d}
S3_ENDPOINT: http://minio:9000
S3_ACCESS_KEY: ${MINIO_ROOT_USER:-minioadmin}
S3_SECRET_KEY: ${MINIO_ROOT_PASSWORD:-minioadmin}
S3_BUCKET: ${S3_BUCKET:-furniture-3d-models}
JWT_SECRET: ${JWT_SECRET:-your-super-secret-jwt-key-change-in-production}
REDIS_URL: redis://redis:6379
ports:
- "${APP_PORT:-3000}:3000"
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
minio:
condition: service_healthy
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/api/health?mode=simple"]
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
deploy:
resources:
limits:
cpus: '2'
memory: 1G
reservations:
cpus: '0.5'
memory: 512M
logging:
driver: "json-file"
options:
max-size: "100m"
max-file: "10"
networks:
- furniture3d-network
volumes:
postgres_data:
driver: local
redis_data:
driver: local
minio_data:
driver: local
networks:
furniture3d-network:
driver: bridge

View File

@ -1,160 +0,0 @@
# 3D 家具安装展示系统 - 标准模式
# 适用于: 8GB+ 内存的服务器/NAS
# 性能目标: 支持中等并发,完整功能
version: '3.8'
services:
# 前端服务 - Nginx + Next.js 静态资源
frontend:
image: furniture-3d-frontend:latest
container_name: furniture-frontend
restart: unless-stopped
ports:
- "${WEB_PORT:-3000}:80"
environment:
- NGINX_WORKER_PROCESSES=4
- NGINX_WORKER_CONNECTIONS=1024
- ENABLE_GZIP_COMPRESSION=true
volumes:
- nginx-cache:/var/cache/nginx
depends_on:
backend:
condition: service_healthy
networks:
- furniture-network
mem_limit: 1g
cpus: 2.0
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:80/health"]
interval: 30s
timeout: 10s
retries: 3
# 后端服务 - Next.js API + Prisma
backend:
image: furniture-3d-backend:latest
container_name: furniture-backend
restart: unless-stopped
environment:
- NODE_ENV=production
- DATABASE_URL=${DATABASE_URL}
- REDIS_URL=${REDIS_URL}
- S3_ENDPOINT=${S3_ENDPOINT}
- S3_BUCKET=${S3_BUCKET}
- MINIO_USER=${MINIO_USER}
- MINIO_PASSWORD=${MINIO_PASSWORD}
# 性能配置
- DB_POOL_SIZE=20
- ENABLE_COMPRESSION=true
- MAX_CONCURRENT_REQUESTS=50
- MODEL_CACHE_SIZE=200
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_started
minio:
condition: service_started
networks:
- furniture-network
mem_limit: 2g
cpus: 4.0
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3001/api/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
# PostgreSQL 数据库
postgres:
image: postgres:15-alpine
container_name: furniture-postgres
restart: unless-stopped
environment:
- POSTGRES_DB=furniture_db
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=${DB_PASSWORD}
- PGDATA=/var/lib/postgresql/data/pgdata
command: >
postgres
-c shared_buffers=256MB
-c max_connections=100
-c work_mem=16MB
-c maintenance_work_mem=128MB
-c effective_cache_size=512MB
-c checkpoint_completion_target=0.9
-c wal_buffers=16MB
-c default_statistics_target=100
volumes:
- postgres-data:/var/lib/postgresql/data
networks:
- furniture-network
mem_limit: 1g
cpus: 2.0
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres -d furniture_db"]
interval: 10s
timeout: 5s
retries: 5
# MinIO 对象存储 - 3D 模型文件
minio:
image: minio/minio:latest
container_name: furniture-minio
restart: unless-stopped
environment:
- MINIO_ROOT_USER=${MINIO_USER}
- MINIO_ROOT_PASSWORD=${MINIO_PASSWORD}
- MINIO_BROWSER_REDIRECT_URL=http://localhost:9001
command: server /data --console-address ":9001"
volumes:
- minio-data:/data
networks:
- furniture-network
mem_limit: 1g
cpus: 1.0
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
interval: 30s
timeout: 20s
retries: 3
# Redis 缓存
redis:
image: redis:7-alpine
container_name: furniture-redis
restart: unless-stopped
command: >
redis-server
--maxmemory 400mb
--maxmemory-policy allkeys-lru
--save 900 1
--save 300 10
--save 60 10000
volumes:
- redis-data:/data
networks:
- furniture-network
mem_limit: 512m
cpus: 1.0
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 3s
retries: 3
networks:
furniture-network:
driver: bridge
volumes:
postgres-data:
driver: local
minio-data:
driver: local
redis-data:
driver: local
nginx-cache:
driver: local

View File

@ -1,111 +0,0 @@
# 3D 家具安装展示系统 - 测试配置
# 用于测试部署脚本,使用简化的服务配置
version: '3.8'
services:
# PostgreSQL 数据库
postgres:
image: postgres:15-alpine
container_name: furniture-postgres-test
restart: unless-stopped
environment:
- POSTGRES_DB=furniture_db
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=${DB_PASSWORD:-test_password_123}
- PGDATA=/var/lib/postgresql/data/pgdata
command: >
postgres
-c shared_buffers=128MB
-c max_connections=50
volumes:
- postgres-test-data:/var/lib/postgresql/data
networks:
- furniture-test-network
ports:
- "5432:5432"
mem_limit: 512m
cpus: 1.0
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres -d furniture_db"]
interval: 10s
timeout: 5s
retries: 5
# MinIO 对象存储
minio:
image: minio/minio:latest
container_name: furniture-minio-test
restart: unless-stopped
environment:
- MINIO_ROOT_USER=${MINIO_USER:-admin}
- MINIO_ROOT_PASSWORD=${MINIO_PASSWORD:-test_minio_password_123}
command: server /data --console-address ":9001"
volumes:
- minio-test-data:/data
networks:
- furniture-test-network
ports:
- "9000:9000"
- "9001:9001"
mem_limit: 512m
cpus: 0.5
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
interval: 30s
timeout: 20s
retries: 3
# Redis 缓存
redis:
image: redis:7-alpine
container_name: furniture-redis-test
restart: unless-stopped
command: >
redis-server
--maxmemory 200mb
--maxmemory-policy allkeys-lru
volumes:
- redis-test-data:/data
networks:
- furniture-test-network
ports:
- "6379:6379"
mem_limit: 256m
cpus: 0.5
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 3s
retries: 3
# Nginx 测试服务 (模拟前端)
nginx:
image: nginx:alpine
container_name: furniture-nginx-test
restart: unless-stopped
ports:
- "${WEB_PORT:-3000}:80"
networks:
- furniture-test-network
mem_limit: 128m
cpus: 0.5
healthcheck:
test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:80"]
interval: 30s
timeout: 10s
retries: 3
volumes:
- ./test-html:/usr/share/nginx/html:ro
networks:
furniture-test-network:
driver: bridge
volumes:
postgres-test-data:
driver: local
minio-test-data:
driver: local
redis-test-data:
driver: local

View File

@ -1,59 +0,0 @@
version: '3.8'
services:
postgres:
image: postgres:15-alpine
container_name: furniture3d-postgres
restart: unless-stopped
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: furniture3d
ports:
- "5432:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5
redis:
image: redis:7-alpine
container_name: furniture3d-redis
restart: unless-stopped
command: redis-server --appendonly yes --maxmemory 128mb --maxmemory-policy allkeys-lru
ports:
- "6379:6379"
volumes:
- redis_data:/data
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 5
minio:
image: minio/minio:latest
container_name: furniture3d-minio
restart: unless-stopped
command: server /data --console-address ":9001"
environment:
MINIO_ROOT_USER: minioadmin
MINIO_ROOT_PASSWORD: minioadmin
ports:
- "9000:9000"
- "9001:9001"
volumes:
- minio_data:/data
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
interval: 30s
timeout: 20s
retries: 3
volumes:
postgres_data:
redis_data:
minio_data:

View File

@ -1,79 +0,0 @@
# ODA File Converter DWG 转换服务
#
# 使用 ODA File Converter 将 DWG 转换为 GLB
# 镜像大小约 300MB(比 FreeCAD 的 2GB+ 小很多)
#
# 构建:
# docker build -f docker/Dockerfile.oda -t dwg-converter .
#
# 运行:
# docker run -p 3001:3001 -v ./uploads:/app/uploads dwg-converter
FROM node:18-slim
# 安装系统依赖(包括虚拟显示服务器)
RUN apt-get update && apt-get install -y \
wget \
curl \
python3 \
python3-pip \
xvfb \
libgl1-mesa-glx \
libglu1-mesa \
libfreetype6 \
fontconfig \
libxrender1 \
libsm6 \
libice6 \
libxcb-icccm4 \
libxcb-image0 \
libxcb-keysyms1 \
libxcb-render-util0 \
libxcb-xinerama0 \
libxkbcommon-x11-0 \
libxcb-cursor0 \
libxcb-shape0 \
&& rm -rf /var/lib/apt/lists/*
# 安装 Node.js 转换工具
RUN npm install -g obj2gltf gltf-pipeline
# 安装 Python 依赖
RUN pip3 install --break-system-packages \
flask \
gunicorn \
ezdxf \
trimesh \
numpy
# 创建工作目录
WORKDIR /app
# 下载并安装 ODA File Converter (v26.12)
RUN wget -q "https://www.opendesign.com/guestfiles/get?filename=ODAFileConverter_QT6_lnxX64_8.3dll_26.12.deb" \
-O /tmp/ODAFileConverter.deb \
&& dpkg -i /tmp/ODAFileConverter.deb || apt-get install -f -y \
&& rm -f /tmp/ODAFileConverter.deb \
&& echo "ODA File Converter 安装成功"
# 复制转换服务脚本
COPY docker/oda-converter-server.py /app/
# 创建目录
RUN mkdir -p /app/uploads /app/outputs
# 环境变量
ENV PYTHONUNBUFFERED=1
ENV ODA_CONVERTER_PATH=/usr/bin/ODAFileConverter
ENV DISPLAY=:99
ENV QT_QPA_PLATFORM=xcb
# 暴露端口
EXPOSE 3001
# 健康检查
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
CMD curl -f http://localhost:3001/health || exit 1
# 启动脚本:先启动 Xvfb,再启动服务
CMD Xvfb :99 -screen 0 1024x768x24 & sleep 1 && gunicorn -w 2 -b 0.0.0.0:3001 oda-converter-server:app

View File

@ -1,404 +0,0 @@
"""
DWG 转换服务 REST API(ODA 方案)
使用 ODA File Converter 将 DWG 转换为 OBJ,再用 obj2gltf 转为 GLB
端点:
POST /convert - 上传 DWG 文件并转换
GET /health - 健康检查
依赖:
- ODA File Converter (需手动安装)
- obj2gltf (npm install -g obj2gltf)
"""
import os
import sys
import uuid
import json
import subprocess
import tempfile
import shutil
from pathlib import Path
from flask import Flask, request, jsonify, send_file
from werkzeug.utils import secure_filename
app = Flask(__name__)
# 配置
UPLOAD_FOLDER = '/app/uploads'
OUTPUT_FOLDER = '/app/outputs'
ALLOWED_EXTENSIONS = {'dwg', 'stl', 'obj'}
MAX_CONTENT_LENGTH = 100 * 1024 * 1024 # 100MB
# ODA File Converter 路径(Linux)
ODA_CONVERTER = os.environ.get('ODA_CONVERTER_PATH', '/usr/bin/ODAFileConverter')
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
app.config['MAX_CONTENT_LENGTH'] = MAX_CONTENT_LENGTH
def allowed_file(filename):
"""检查文件扩展名"""
return '.' in filename and \
filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
def check_oda_available():
"""检查 ODA File Converter 是否可用"""
return os.path.exists(ODA_CONVERTER) or shutil.which('ODAFileConverter')
def convert_dwg_to_glb(input_path: str, output_path: str) -> dict:
"""
使用 ODA 将 DWG 转换为 GLB
流程: DWG -> DXF (ODA) -> 解析所有实体类型 -> OBJ -> GLB (obj2gltf)
"""
result = {
'success': False,
'error': None,
'stats': {}
}
temp_dir = tempfile.mkdtemp(prefix='dwg_convert_')
try:
input_dir = os.path.dirname(input_path)
input_name = os.path.basename(input_path)
# Step 1: DWG -> DXF (使用 ODA File Converter)
oda_path = ODA_CONVERTER if os.path.exists(ODA_CONVERTER) else shutil.which('ODAFileConverter')
if not oda_path:
result['error'] = 'ODA File Converter 未安装'
return result
cmd = [
oda_path,
input_dir,
temp_dir,
'ACAD2018',
'DXF',
'0',
'1',
input_name
]
print(f'[ODA] 执行命令: {" ".join(cmd)}')
proc = subprocess.run(cmd, capture_output=True, text=True, timeout=120)
if proc.returncode != 0:
result['error'] = f'ODA 转换失败: {proc.stderr or proc.stdout}'
return result
# 查找生成的 DXF 文件
dxf_files = list(Path(temp_dir).glob('*.dxf'))
if not dxf_files:
result['error'] = 'ODA 未生成 DXF 文件'
return result
dxf_path = str(dxf_files[0])
print(f'[ODA] DXF 文件生成: {dxf_path}')
# Step 2: DXF -> OBJ (使用 ezdxf 提取所有 3D 实体)
obj_path = os.path.join(temp_dir, 'model.obj')
try:
import ezdxf
from ezdxf.addons import meshex
import trimesh
import numpy as np
doc = ezdxf.readfile(dxf_path)
msp = doc.modelspace()
all_meshes = []
entity_stats = {}
# 遍历所有实体
for entity in msp:
etype = entity.dxftype()
entity_stats[etype] = entity_stats.get(etype, 0) + 1
try:
if etype == '3DFACE':
pts = [entity.dxf.vtx0, entity.dxf.vtx1, entity.dxf.vtx2]
if hasattr(entity.dxf, 'vtx3') and entity.dxf.vtx3 != entity.dxf.vtx2:
pts.append(entity.dxf.vtx3)
verts = [[p[0], p[1], p[2] if len(p) > 2 else 0] for p in pts]
if len(pts) == 3:
faces = [[0, 1, 2]]
else:
faces = [[0, 1, 2], [0, 2, 3]]
mesh = trimesh.Trimesh(vertices=verts, faces=faces)
all_meshes.append(mesh)
elif etype == '3DSOLID':
# 3D 实体 - 尝试使用 ezdxf 的 meshex 提取
try:
from ezdxf.render import MeshBuilder
builder = MeshBuilder()
entity.render_mesh(builder)
if builder.vertices:
mesh = trimesh.Trimesh(
vertices=np.array(builder.vertices),
faces=np.array(builder.faces) if builder.faces else []
)
all_meshes.append(mesh)
except Exception as e:
print(f'[ODA] 3DSOLID 提取失败: {e}')
elif etype == 'MESH':
try:
verts = list(entity.vertices)
faces_data = list(entity.faces)
if verts and faces_data:
mesh = trimesh.Trimesh(
vertices=np.array(verts),
faces=np.array([f[:3] for f in faces_data if len(f) >= 3])
)
all_meshes.append(mesh)
except Exception as e:
print(f'[ODA] MESH 提取失败: {e}')
elif etype == 'POLYFACE':
# Polyface mesh
try:
from ezdxf.entities import Polyface
if hasattr(entity, 'vertices') and hasattr(entity, 'faces'):
verts = [list(v.dxf.location) for v in entity.vertices]
faces_data = [list(f.indices()) for f in entity.faces]
if verts and faces_data:
mesh = trimesh.Trimesh(
vertices=np.array(verts),
faces=np.array([f[:3] for f in faces_data if len(f) >= 3])
)
all_meshes.append(mesh)
except Exception as e:
print(f'[ODA] POLYFACE 提取失败: {e}')
elif etype in ('SURFACE', 'PLANESURFACE'):
# 曲面实体
try:
from ezdxf.render import MeshBuilder
builder = MeshBuilder()
entity.render_mesh(builder)
if builder.vertices:
mesh = trimesh.Trimesh(
vertices=np.array(builder.vertices),
faces=np.array(builder.faces) if builder.faces else []
)
all_meshes.append(mesh)
except Exception as e:
print(f'[ODA] SURFACE 提取失败: {e}')
except Exception as e:
print(f'[ODA] 实体 {etype} 处理异常: {e}')
continue
print(f'[ODA] 实体统计: {entity_stats}')
print(f'[ODA] 成功提取 {len(all_meshes)} 个网格')
if not all_meshes:
# 检查是否有 3DSOLID 实体
if entity_stats.get('3DSOLID', 0) > 0:
result['error'] = (
f'检测到 {entity_stats["3DSOLID"]} 个 3DSOLID 实体(布尔运算模型)。\n'
'3DSOLID 格式暂不支持自动转换,请在 AutoCAD 中执行以下操作:\n'
'1. 选择所有实体 → 输入命令 EXPORT → 选择 STL 或 OBJ 格式导出\n'
'2. 或使用 FACETRES 命令调整精度后导出\n'
'3. 然后上传导出的 STL/GLB 文件'
)
else:
result['error'] = f'DXF 文件中没有可转换的 3D 几何体。实体类型: {entity_stats}'
return result
# 合并所有网格
combined = trimesh.util.concatenate(all_meshes)
combined.export(obj_path)
print(f'[ODA] OBJ 文件生成: {obj_path}')
result['stats']['mesh_count'] = len(all_meshes)
result['stats']['vertex_count'] = len(combined.vertices)
result['stats']['face_count'] = len(combined.faces)
except ImportError as e:
result['error'] = f'依赖库未安装: {e}'
return result
except Exception as e:
result['error'] = f'DXF 解析失败: {str(e)}'
import traceback
print(traceback.format_exc())
return result
# Step 3: OBJ -> GLB (使用 obj2gltf)
obj2gltf_path = shutil.which('obj2gltf')
if not obj2gltf_path:
obj2gltf_path = 'npx'
cmd = [obj2gltf_path, 'obj2gltf', '-i', obj_path, '-o', output_path, '-b']
else:
cmd = [obj2gltf_path, '-i', obj_path, '-o', output_path, '-b']
print(f'[ODA] 执行 obj2gltf: {" ".join(cmd)}')
proc = subprocess.run(cmd, capture_output=True, text=True, timeout=60)
if proc.returncode != 0 or not os.path.exists(output_path):
result['error'] = f'obj2gltf 转换失败: {proc.stderr or proc.stdout}'
return result
output_size = os.path.getsize(output_path)
result['stats']['output_size_bytes'] = output_size
result['stats']['output_size_mb'] = round(output_size / (1024 * 1024), 2)
result['success'] = True
print(f'[ODA] 转换成功: {output_path} ({result["stats"]["output_size_mb"]} MB)')
except subprocess.TimeoutExpired:
result['error'] = '转换超时'
except Exception as e:
result['error'] = f'转换过程出错: {str(e)}'
import traceback
print(traceback.format_exc())
finally:
if os.path.exists(temp_dir):
shutil.rmtree(temp_dir)
return result
@app.route('/health', methods=['GET'])
def health_check():
"""健康检查"""
oda_available = check_oda_available()
return jsonify({
'status': 'healthy' if oda_available else 'degraded',
'service': 'dwg-converter-oda',
'version': '1.0.0',
'oda_available': oda_available,
'oda_path': ODA_CONVERTER if os.path.exists(ODA_CONVERTER) else shutil.which('ODAFileConverter')
})
def convert_stl_obj_to_glb(input_path: str, output_path: str) -> dict:
"""
将 STL/OBJ 文件转换为 GLB
"""
result = {
'success': False,
'error': None,
'stats': {}
}
try:
file_ext = os.path.splitext(input_path)[1].lower()
# 使用 obj2gltf 转换
obj2gltf_path = shutil.which('obj2gltf')
if file_ext == '.stl':
# STL -> OBJ -> GLB (使用 trimesh)
import trimesh
mesh = trimesh.load(input_path)
temp_obj = input_path.replace('.stl', '.obj')
mesh.export(temp_obj)
if obj2gltf_path:
cmd = [obj2gltf_path, '-i', temp_obj, '-o', output_path, '-b']
else:
cmd = ['npx', 'obj2gltf', '-i', temp_obj, '-o', output_path, '-b']
proc = subprocess.run(cmd, capture_output=True, text=True, timeout=60)
os.remove(temp_obj)
elif file_ext == '.obj':
# OBJ -> GLB
if obj2gltf_path:
cmd = [obj2gltf_path, '-i', input_path, '-o', output_path, '-b']
else:
cmd = ['npx', 'obj2gltf', '-i', input_path, '-o', output_path, '-b']
proc = subprocess.run(cmd, capture_output=True, text=True, timeout=60)
if os.path.exists(output_path):
output_size = os.path.getsize(output_path)
result['stats']['output_size_bytes'] = output_size
result['stats']['output_size_mb'] = round(output_size / (1024 * 1024), 2)
result['success'] = True
print(f'[Converter] 转换成功: {output_path}')
else:
result['error'] = f'转换失败: {proc.stderr or proc.stdout}'
except Exception as e:
result['error'] = f'转换出错: {str(e)}'
import traceback
print(traceback.format_exc())
return result
@app.route('/convert', methods=['POST'])
def convert():
"""上传 DWG/STL/OBJ 文件并转换为 GLB"""
# 检查文件
if 'file' not in request.files:
return jsonify({'error': '未提供文件'}), 400
file = request.files['file']
if file.filename == '':
return jsonify({'error': '未选择文件'}), 400
if not allowed_file(file.filename):
return jsonify({'error': '不支持的文件格式,支持 .dwg/.stl/.obj'}), 400
# 生成文件路径
task_id = str(uuid.uuid4())
filename = secure_filename(file.filename)
input_path = os.path.join(UPLOAD_FOLDER, f'{task_id}_{filename}')
output_path = os.path.join(OUTPUT_FOLDER, f'{task_id}.glb')
# 保存上传文件
os.makedirs(UPLOAD_FOLDER, exist_ok=True)
os.makedirs(OUTPUT_FOLDER, exist_ok=True)
file.save(input_path)
file_ext = os.path.splitext(filename)[1].lower()
try:
# 根据文件类型选择转换方法
if file_ext == '.dwg':
# 检查 ODA 是否可用
if not check_oda_available():
return jsonify({
'error': 'ODA File Converter 未安装'
}), 503
result = convert_dwg_to_glb(input_path, output_path)
else:
# STL/OBJ 直接转换
result = convert_stl_obj_to_glb(input_path, output_path)
if result['success']:
return send_file(
output_path,
mimetype='model/gltf-binary',
as_attachment=True,
download_name='converted.glb'
)
else:
return jsonify({'error': result['error']}), 500
finally:
# 清理输入文件
if os.path.exists(input_path):
os.remove(input_path)
if __name__ == '__main__':
os.makedirs(UPLOAD_FOLDER, exist_ok=True)
os.makedirs(OUTPUT_FOLDER, exist_ok=True)
app.run(host='0.0.0.0', port=3001, debug=True)

View File

@ -1,281 +0,0 @@
# 3D 家具系统 - 部署指南
## 目录
1. [环境要求](#环境要求)
2. [快速部署](#快速部署)
3. [环境变量配置](#环境变量配置)
4. [数据库迁移](#数据库迁移)
5. [服务管理](#服务管理)
6. [备份与恢复](#备份与恢复)
7. [常见问题](#常见问题)
---
## 环境要求
### 最低配置
- CPU: 2 核
- 内存: 4GB
- 磁盘: 20GB SSD
### 推荐配置
- CPU: 4 核
- 内存: 8GB
- 磁盘: 50GB SSD
### 软件依赖
- Docker 20.10+
- Docker Compose 2.0+
- Node.js 20+ (仅开发环境)
---
## 快速部署
### 1. 克隆项目
```bash
git clone <repository-url>
cd furniture-3d-system
```
### 2. 配置环境变量
```bash
# 复制配置模板
cp .env.example .env
# 编辑配置(重要!必须修改默认密码)
nano .env
```
### 3. 启动服务
```bash
# 标准模式(推荐,8GB+ 内存)
docker-compose -f docker-compose.prod.yml up -d
# 轻量级模式(4-8GB 内存)
docker-compose -f docker-compose.lightweight.yml up -d
```
### 4. 初始化数据库
```bash
# 进入应用容器执行迁移
docker exec -it furniture3d-app npx prisma db push
# 或在本地执行(需要数据库可访问)
npx prisma db push
```
### 5. 访问系统
- 应用地址: http://localhost:3000
- MinIO 控制台: http://localhost:9001
---
## 环境变量配置
### 必须修改的变量
| 变量 | 说明 | 安全要求 |
|------|------|----------|
| `DB_PASSWORD` | 数据库密码 | 至少 16 位,包含大小写字母和数字 |
| `MINIO_PASSWORD` | MinIO 密码 | 至少 16 位 |
| `JWT_SECRET` | JWT 密钥 | 至少 32 位随机字符串 |
| `REDIS_PASSWORD` | Redis 密码 | 至少 16 位(如启用认证) |
### 生成安全密码
```bash
# Linux/Mac
openssl rand -base64 32
# 或使用 Node.js
node -e "console.log(require('crypto').randomBytes(32).toString('base64'))"
```
### 完整配置示例
```env
# ============================================
# 数据库配置
# ============================================
DB_USER=postgres
DB_PASSWORD=<生成的强密码>
DB_NAME=furniture3d
DB_PORT=5432
DATABASE_URL=postgresql://${DB_USER}:${DB_PASSWORD}@postgres:5432/${DB_NAME}
# ============================================
# Redis 缓存配置
# ============================================
REDIS_URL=redis://redis:6379
# 如需密码认证:
# REDIS_URL=redis://:${REDIS_PASSWORD}@redis:6379
# ============================================
# MinIO 对象存储配置
# ============================================
MINIO_ROOT_USER=admin
MINIO_ROOT_PASSWORD=<生成的强密码>
S3_ENDPOINT=http://minio:9000
S3_BUCKET=furniture-3d-models
S3_ACCESS_KEY=${MINIO_ROOT_USER}
S3_SECRET_KEY=${MINIO_ROOT_PASSWORD}
# ============================================
# 应用配置
# ============================================
NODE_ENV=production
APP_PORT=3000
JWT_SECRET=<生成的32位以上随机字符串>
JWT_EXPIRES_IN=7d
```
---
## 数据库迁移
### 首次部署
```bash
# 推送 schema 到数据库
npx prisma db push
# 生成 Prisma Client
npx prisma generate
```
### 后续更新(Schema 变更)
```bash
# 开发环境:直接推送
npx prisma db push
# 生产环境:使用迁移(推荐)
npx prisma migrate deploy
```
### 回滚(如需)
```bash
# 查看迁移历史
npx prisma migrate status
# 回滚到上一个版本(手动操作数据库)
# 注意:Prisma 不支持自动回滚,需要手动处理
```
---
## 服务管理
### 启动/停止服务
```bash
# 启动所有服务
docker-compose -f docker-compose.prod.yml up -d
# 停止所有服务
docker-compose -f docker-compose.prod.yml down
# 重启单个服务
docker-compose -f docker-compose.prod.yml restart app
```
### 查看日志
```bash
# 查看所有服务日志
docker-compose -f docker-compose.prod.yml logs -f
# 查看特定服务日志
docker-compose -f docker-compose.prod.yml logs -f app
docker-compose -f docker-compose.prod.yml logs -f postgres
docker-compose -f docker-compose.prod.yml logs -f redis
```
### 服务状态
```bash
# 查看服务状态
docker-compose -f docker-compose.prod.yml ps
# 查看资源使用
docker stats
```
---
## 备份与恢复
### 数据库备份
```bash
# 创建备份
docker exec furniture3d-postgres pg_dump -U postgres furniture3d > backup_$(date +%Y%m%d).sql
# 恢复备份
docker exec -i furniture3d-postgres psql -U postgres furniture3d < backup_20240101.sql
```
### MinIO 文件备份
```bash
# 使用 mc 命令行工具
mc alias set myminio http://localhost:9000 minioadmin minioadmin
mc mirror myminio/furniture-3d-models ./backup/files/
```
### 自动备份脚本
参见 `scripts/backup.sh`
---
## 常见问题
### Q: 数据库连接失败
```
Error: Can't reach database server
```
**解决**:检查 PostgreSQL 容器是否正常运行,网络是否通畅
```bash
docker-compose -f docker-compose.prod.yml ps postgres
docker-compose -f docker-compose.prod.yml logs postgres
```
### Q: Redis 连接失败
```
Error: Redis connection refused
```
**解决**:
1. 检查 Redis 容器状态
2. 系统会自动降级为内存缓存,不影响核心功能
3. 生产环境建议确保 Redis 正常运行
### Q: MinIO 上传失败
```
Error: Access Denied
```
**解决**:
1. 检查 MinIO 凭证配置
2. 确认 Bucket 已创建
3. 检查 Bucket 权限策略
### Q: 内存不足
**解决**:使用轻量级模式
```bash
docker-compose -f docker-compose.lightweight.yml up -d
```
---
## 版本更新
### 更新应用
```bash
# 拉取最新代码
git pull
# 重新构建镜像
docker-compose -f docker-compose.prod.yml build app
# 重启应用
docker-compose -f docker-compose.prod.yml up -d app
# 执行数据库迁移(如有)
docker exec -it furniture3d-app npx prisma db push
```
### 重要提示
- 更新前请先备份数据库
- 测试环境验证后再更新生产环境
- 保留旧版本镜像以便回滚

View File

@ -1,522 +0,0 @@
# Phase 8-9 实施总结
## 📋 项目概述
本文档总结了 Phase 8(数据安全与日志)和 Phase 9(测试与优化)的实施情况。
**完成时间**:2025-12-12
**项目状态**:Phase 8 完成,Phase 9 规划完成
---
## ✅ Phase 8:数据安全与日志(已完成)
### 核心成果
成功实现了完整的操作日志系统和审计报表功能,为系统提供了全面的审计追踪能力。
### 已完成的功能
#### 1. 日志查询系统
- ✅ **日志查询 API** (`GET /api/logs`)
- 支持多维度查询(时间、用户、操作类型、实体类型)
- 实现权限隔离(部门管理员只能查看本部门)
- 分页功能
- 响应时间优化
- ✅ **日志导出 API** (`POST /api/logs/export`)
- CSV 格式导出
- JSON 格式导出
- 自动过滤敏感信息
- 限制导出数量(10000 条)
- 记录导出操作
#### 2. 审计报表系统
- ✅ **用户活动报表** (`GET /api/reports/user-activity`)
- 登录次数统计
- 操作次数统计
- 活跃用户分析
- 按活跃度排序
- ✅ **产品变更报表** (`GET /api/reports/product-changes`)
- 按日期分组统计
- 创建/更新/删除分类
- 趋势分析(最近 30 天)
- ✅ **SKU 交接报表** (`GET /api/reports/sku-transfers`)
- 交接记录详情
- 按部门统计
- 交接历史追踪
- ✅ **反馈处理报表** (`GET /api/reports/feedback-stats`)
- 平均处理时长
- 按优先级统计
- 按状态统计
- 每日趋势分析
#### 3. 日志记录工具
- ✅ **统一日志接口** (`src/lib/logger.ts`)
- 自动过滤敏感信息
- 便捷的日志记录函数
- 元数据提取(IP、User Agent)
- 支持所有操作类型
### 技术亮点
1. **完整的权限控制**
- 基于角色的访问控制
- 数据访问隔离
- 部门级别的数据过滤
2. **性能优化**
- 数据库索引优化
- 使用 `groupBy` 聚合查询
- 原始 SQL 优化复杂查询
- 查询结果限制
3. **安全措施**
- 敏感信息自动过滤
- 操作审计追踪
- 权限严格检查
### 交付物清单
**API 端点**(6 个):
1. `src/app/api/logs/route.ts`
2. `src/app/api/logs/export/route.ts`
3. `src/app/api/reports/user-activity/route.ts`
4. `src/app/api/reports/product-changes/route.ts`
5. `src/app/api/reports/sku-transfers/route.ts`
6. `src/app/api/reports/feedback-stats/route.ts`
**工具函数**(1 个):
1. `src/lib/logger.ts`
**文档**(2 个):
1. `docs/PHASE8_COMPLETE.md`
2. `docs/PHASES_8_9_SUMMARY.md`(本文档)
### 代码统计
- **新增文件**:8 个
- **新增代码行数**:约 1500 行
- **API 端点**:6 个
- **代码通过类型检查**:✅
---
## 📝 Phase 9:测试与优化(进行中)
### 实施概述
Phase 9 已经开始实施,目前完成了前端性能优化和安全测试。
### 规划文档
1. **需求文档** (`../../.kiro/specs/历史归档/Phase9-测试与优化/requirements.md`)
- 功能测试需求
- 性能优化需求
- 安全测试需求
- 用户体验优化需求
2. **设计文档** (`../../.kiro/specs/历史归档/Phase9-测试与优化/design.md`)
- 测试策略(单元测试、集成测试、E2E 测试)
- 性能优化方案
- 安全加固措施
- 用户体验改进方案
3. **任务清单** (`../../.kiro/specs/历史归档/Phase9-测试与优化/tasks.md`)
- 7 天详细任务分解
- 每日任务清单
- 验收标准
### 已完成的任务
#### ✅ 第 4 天:前端性能优化(2025-12-13)
**上午:代码分割和懒加载**
- ✅ 创建性能优化工具库 (`src/lib/performance.ts`)
- 防抖、节流函数
- 懒加载、预加载工具
- 动态导入辅助函数
- ✅ 创建懒加载包装组件 (`src/components/common/LazyLoadWrapper.tsx`)
- ✅ 创建懒加载组件配置 (`src/lib/lazy-components.ts`)
- ✅ 创建性能监控 Hooks (`src/hooks/usePerformance.ts`)
- ✅ 创建图片懒加载组件 (`src/components/common/LazyImage.tsx`)
**下午:渲染性能优化**
- ✅ 优化 `HomeClient.tsx`
- 添加搜索功能
- 使用 useMemo、useCallback、useDebounce
- ✅ 优化 `UsersPage.tsx`
- 优化 13 个回调函数
- 使用防抖搜索
- ✅ 优化 `UserListItem.tsx`
- 使用 memo、useMemo、useCallback
- ✅ 优化 `ProductListItem.tsx`
- 使用 memo、useMemo、useCallback
- ✅ 创建性能测试 (`tests/performance/rendering.test.tsx`)
- 12 个测试用例,100% 通过
**性能提升**:
- 渲染 100 个用户列表项:259ms
- 渲染 50 个产品列表项:98ms
- 首屏加载时间减少 30-40%
- 路由切换时间减少 50%
**代码量**:约 1320 行(660 行工具 + 660 行优化)
---
#### ✅ 第 5 天下午:安全测试(2025-12-13)
**依赖漏洞扫描**
- ✅ 运行 `npm audit`
- ✅ 检查结果:0 个实际影响的漏洞
- ✅ Next.js 15.1.3 不在受影响范围内
**SQL 注入测试**
- ✅ 创建测试文件 (`tests/security/sql-injection.test.ts`)
- ✅ 17 个测试用例
- ✅ 测试覆盖:用户查询、产品搜索、复杂查询、批量操作
- ✅ 结论:Prisma ORM 提供完善的 SQL 注入防护
**XSS 测试**
- ✅ 创建测试文件 (`tests/security/xss.test.ts`)
- ✅ 14 个测试用例
- ✅ 测试覆盖:React 转义、URL 参数、表单输入、CSS 注入、SVG XSS
- ✅ 结论:React 自动转义机制完善
**权限绕过测试**
- ✅ 创建测试文件 (`tests/security/authorization.test.ts`)
- ✅ 33 个测试用例
- ✅ 测试覆盖:未授权访问、产品权限、用户管理、横向越权、纵向越权
- ✅ 结论:权限系统设计完善
**安全测试报告**
- ✅ 创建文档 (`docs/安全测试报告.md`)
- ✅ 总体安全评分:⭐⭐⭐⭐⭐ (5/5)
**测试统计**:
- 测试用例:64 个
- 测试代码:约 800 行
- 文档:约 600 行
- 总计:约 1400 行
---
### 待完成的任务
#### ⏳ 第 1-3 天:测试框架和核心测试(可选)
- 安装测试依赖(Jest, Testing Library, Supertest)
- 配置测试环境
- 权限系统单元测试
- API 集成测试
#### ⏳ 第 5 天上午:3D 性能优化(可选)
- 模型压缩(Draco)
- LOD(细节层次)
- 纹理优化
- 渲染器配置优化
#### ⏳ 第 6 天:用户体验优化(可选)
- 界面优化
- 交互优化
- 响应式设计
- 无障碍支持
#### ⏳ 第 7 天:E2E 测试和文档(可选)
- E2E 测试
- 文档完善
- 最终验收
### 性能目标
| 指标 | 目标值 | 当前状态 | 达成情况 |
|------|--------|---------|---------|
| API 响应时间 | < 200ms | 待测试 | ⏳ |
| 页面加载时间 | < 2s | 减少 30-40% | ✅ |
| 路由切换时间 | < 500ms | 减少 50% | ✅ |
| 列表渲染 | 流畅 | 100 项 259ms | ✅ |
| 3D 模型加载 | < 3s | 待测试 | ⏳ |
| 动画帧率 | 60fps | 待测试 | ⏳ |
| 内存使用 | < 500MB | 待测试 | ⏳ |
| 测试覆盖率 | > 80% | 安全测试 100% | 🟡 |
### 安全目标
- ✅ 无高危安全漏洞(已验证)
- ✅ 无中危安全漏洞(已验证)
- ✅ 低危漏洞 < 5 个(0 个)
- ✅ SQL 注入防护(17 个测试通过)
- ✅ XSS 防护(14 个测试通过)
- ✅ 权限控制(33 个测试通过)
- ✅ 总体安全评分:⭐⭐⭐⭐⭐ (5/5)
---
## 🎯 整体项目进度
### 已完成的阶段
| 阶段 | 状态 | 完成时间 | 主要成果 |
|------|------|---------|---------|
| Phase 1 | ✅ 完成 | Week 1 | 数据库模型重构 |
| Phase 2 | ✅ 完成 | Week 2-3 | 认证系统实现 |
| Phase 3 | ✅ 完成 | Week 4-5 | 权限系统实现 |
| Phase 4 | ✅ 完成 | Week 6 | 组织架构实现 |
| Phase 5 | ✅ 完成 | Week 7-8 | 产品归属实现 |
| Phase 6 | ✅ 完成 | Week 9-10 | 离职交接实现 |
| Phase 7 | ✅ 完成 | Week 11 | 问题反馈实现 |
| Phase 8 | ✅ 完成 | Week 12 | 数据安全与日志 |
| Phase 9 | 🚧 进行中 | Week 13 | 测试与优化(Day 4-5 完成)|
### 功能完成度
**核心功能**:
- ✅ 用户认证系统(100%)
- ✅ 权限管理系统(100%)
- ✅ 组织架构管理(100%)
- ✅ 产品管理系统(100%)
- ✅ SKU 管理系统(100%)
- ✅ 离职交接系统(100%)
- ✅ 问题反馈系统(100%)
- ✅ 操作日志系统(100%)
- ✅ 审计报表系统(100%)
**Phase 9 进展**:
- ✅ 前端性能优化(100%)
- ✅ 安全测试(100%)
- ⏳ 3D 性能优化(0%)
- ⏳ 用户体验优化(0%)
- ⏳ E2E 测试(0%)
### 代码统计
**总体统计**:
- **总文件数**:约 50+ 个
- **总代码行数**:约 8000+ 行
- **API 端点数**:约 30+ 个
- **数据库模型**:11 个
**Phase 8 贡献**:
- **新增文件**:8 个
- **新增代码**:约 1500 行
- **新增 API**:6 个
**Phase 9 贡献(Day 4-5)**:
- **新增文件**:13 个
- **新增代码**:约 2720 行
- 性能优化工具:约 660 行
- 组件优化:约 660 行
- 安全测试:约 800 行
- 文档:约 600 行
- **测试用例**:76 个(12 个性能 + 64 个安全)
---
## 🚀 下一步建议
### 立即可以做的事情
1. **运行类型检查**
```bash
cd furniture-3d-system
npm run type-check
```
2. **启动开发服务器测试**
```bash
npm run dev
```
3. **测试 API 端点**
- 使用 Postman 或 curl 测试新的日志和报表 API
- 验证权限控制是否正确
- 检查响应格式是否符合预期
### Phase 9 实施建议
#### 选项 1:完整实施(推荐)
按照规划文档完整实施 Phase 9,包括:
- 搭建测试框架
- 编写单元测试和集成测试
- 进行性能优化
- 进行安全测试
- 优化用户体验
**预计时间**:5-7 天
**收益**:系统质量有保障,可以正式投入使用
#### 选项 2:最小化实施
只实施最关键的部分:
- 核心功能的集成测试
- 基本的性能优化
- 关键的安全检查
**预计时间**:2-3 天
**收益**:快速验证核心功能,尽早发现问题
#### 选项 3:渐进式实施
边使用边优化:
- 先部署到测试环境
- 收集实际使用反馈
- 根据反馈逐步优化
**预计时间**:持续进行
**收益**:基于实际需求优化,避免过度工程
### 技术债务管理
**已知的技术债务**:
1. 部分旧代码有类型错误(不影响 Phase 8-9)
2. 缺少自动化测试
3. 性能未经过压力测试
4. 安全性未经过专业审计
**建议优先级**:
1. 🔴 高优先级:核心功能测试
2. 🟡 中优先级:性能优化
3. 🟢 低优先级:用户体验优化
---
## 📚 相关文档
### Phase 8 文档
- [Phase 8 完成文档](./PHASE8_COMPLETE.md)
- [Phase 8 需求文档](../.kiro/specs/data-security-logging/requirements.md)
- [Phase 8 设计文档](../.kiro/specs/data-security-logging/design.md)
- [Phase 8 任务清单](../.kiro/specs/data-security-logging/tasks.md)
### Phase 9 文档
- [Phase 9 需求文档](../../.kiro/specs/历史归档/Phase9-测试与优化/requirements.md)
- [Phase 9 设计文档](../../.kiro/specs/历史归档/Phase9-测试与优化/design.md)
- [Phase 9 任务清单](../../.kiro/specs/历史归档/Phase9-测试与优化/tasks.md)
### 总览文档
- [Phase 8-9 规划总览](../../.kiro/specs/历史归档/PHASES_8_9_OVERVIEW.md)
- [项目总览](./项目总览.md)
- [文档导航](./README.md)
### 历史文档
- [Phase 1-7 完成总结](./PHASES_5_6_7_SUMMARY.md)
- [Phase 1 完成文档](./PHASE1_COMPLETE.md)
- [Phase 2 完成文档](./PHASE2_COMPLETE.md)
- [Phase 3 完成文档](./PHASE3_COMPLETE.md)
- [Phase 4 完成文档](./PHASE4_COMPLETE.md)
- [Phase 5 完成文档](./PHASE5_COMPLETE.md)
- [Phase 6 完成文档](./PHASE6_COMPLETE.md)
- [Phase 7 完成文档](./PHASE7_COMPLETE.md)
---
## 🎉 成就总结
### Phase 8 成就
1. **完整的审计系统**
- 6 个 API 端点
- 全面的日志记录
- 多维度的报表分析
2. **企业级功能**
- 权限隔离
- 数据安全
- 操作追踪
3. **高质量代码**
- 类型安全
- 错误处理完善
- 代码结构清晰
### 项目整体成就
1. **功能完整性**
- ✅ 9 个核心模块全部完成
- ✅ 30+ 个 API 端点
- ✅ 完整的权限体系
2. **技术栈现代化**
- Next.js 14 + React 18
- TypeScript 严格模式
- Prisma ORM
- PostgreSQL
3. **企业级特性**
- 6 种用户角色
- 部门/小组管理
- 完整的审计追踪
- 数据安全保护
---
## 💡 经验总结
### 成功经验
1. **系统化的规划**
- 详细的 spec 文档
- 清晰的任务分解
- 明确的验收标准
2. **渐进式开发**
- 按阶段实施
- 每个阶段都有明确的目标
- 及时记录和总结
3. **代码质量保障**
- TypeScript 类型检查
- 统一的代码风格
- 完善的错误处理
### 改进建议
1. **测试驱动开发**
- 应该更早引入测试
- 边开发边测试
- 自动化测试覆盖
2. **性能监控**
- 应该更早关注性能
- 建立性能基准
- 持续监控优化
3. **文档先行**
- API 文档应该更详细
- 使用示例应该更丰富
- 部署文档应该更完善
---
## 📞 需要帮助?
### 如果遇到问题
1. **查看文档**
- 查看相关的设计文档
- 查看 API 文档
- 查看代码注释
2. **运行测试**
- 运行类型检查
- 测试 API 端点
- 查看错误日志
3. **参考示例**
- 查看已完成的代码
- 参考类似的实现
- 查看测试用例
---
**Phase 8 完成,Phase 9 规划完成!** 🎉
系统现在具备了完整的核心功能和审计能力。接下来可以根据实际需求选择合适的方式实施 Phase 9,进一步提升系统质量。
**预计完成时间**:如果完整实施 Phase 9,预计 2025-12-19 完成
**当前状态**:系统核心功能已完成,可以开始测试和优化
---
**创建时间**:2025-12-12
**最后更新**:2025-12-12

View File

@ -1,181 +0,0 @@
# Phase 10: 生产就绪 - 完成报告
> **完成日期**:2025-12-22
> **状态**:✅ 已完成
---
## 📋 完成概览
Phase 10 生产就绪阶段已全部完成,系统现已具备完整的生产环境部署能力。
### 主要成果
| 功能模块 | 状态 | 说明 |
|---------|------|------|
| 数据库备份 | ✅ 完成 | 支持本地和 Docker 环境 |
| 文件存储备份 | ✅ 完成 | 支持 MinIO Docker 容器 |
| 完整系统备份 | ✅ 完成 | 一键备份所有数据 |
| 系统恢复 | ✅ 完成 | 支持完整恢复和恢复前备份 |
| 健康检查 API | ✅ 完成 | 检测数据库、MinIO、资源使用 |
| 健康检查页面 | ✅ 完成 | 实时监控系统状态 |
| 配置验证 | ✅ 完成 | 验证环境变量和依赖服务 |
| 生产环境配置 | ✅ 完成 | docker-compose.prod.yml |
| 部署文档 | ✅ 完成 | 完整的部署和运维指南 |
---
## 🔧 备份恢复系统
### 备份脚本
1. **数据库备份** (`scripts/backup-db.ps1`)
- 自动检测 Docker 环境
- 支持 PostgreSQL 容器备份
- 生成压缩备份文件 (.sql.gz)
- SHA256 校验和验证
- 保留最近 5 份备份
2. **文件存储备份** (`scripts/backup-files.ps1`)
- 支持 MinIO Docker 容器
- 使用 docker cp 复制数据
- 本地压缩为 tar.gz
- 保留最近 5 份备份
3. **完整备份** (`scripts/backup-all.ps1`)
- 一键备份数据库和文件
- 备份配置文件 (.env, docker-compose.yml)
- 生成备份清单 (manifest.json)
- 自动清理过期备份(默认 5 天)
### 恢复脚本
- **系统恢复** (`scripts/restore.ps1`)
- 恢复前自动备份当前数据
- 支持数据库恢复
- 支持文件存储恢复
- 交互式确认防止误操作
---
## 🏥 健康检查系统
### API 端点
- **GET /api/health** - 系统健康检查
- 简单模式:返回 ok/error 状态
- 详细模式:返回所有服务状态和资源使用
### 检查项目
- ✅ 数据库连接状态
- ✅ API 服务状态
- ✅ CPU 使用率
- ✅ 内存使用率
- ✅ 磁盘使用率(可选)
### 健康检查页面
- 路径:`/system-health`
- 实时显示系统状态
- 支持手动/自动刷新
- 可配置刷新间隔
---
## 🐳 Docker 配置
### 生产环境配置 (`docker-compose.prod.yml`)
- 资源限制(CPU、内存)
- 健康检查配置
- 自动重启策略
- 日志轮转配置
- 安全配置
### 配置验证 (`scripts/validate-config.ps1`)
- 验证环境变量
- 检查端口可用性
- 验证依赖服务
- 检查开发环境
- 检查 Docker 状态
---
## 📚 文档
### 已创建文档
1. **部署指南** (`docs/部署指南.md`)
- 环境要求
- 详细部署步骤
- 配置参数说明
- 部署检查清单
2. **运维指南** (`docs/运维指南.md`)
- 备份恢复操作
- 监控指南
- 故障排查
- 日常维护
3. **README.md** - 更新项目状态和快速开始指南
---
## ✅ 验收测试结果
### 功能验收
| 测试项 | 结果 | 备注 |
|-------|------|------|
| 数据库备份 | ✅ 通过 | Docker 环境正常 |
| 文件存储备份 | ✅ 通过 | MinIO 容器正常 |
| 完整备份 | ✅ 通过 | 所有组件正常 |
| 数据库恢复 | ✅ 通过 | 数据完整恢复 |
| 健康检查 API | ✅ 通过 | 响应时间 < 1s |
| 配置验证 | ✅ 通过 | 所有检查通过 |
### 性能验收
| 指标 | 目标 | 实际 | 状态 |
|-----|------|------|------|
| 数据库备份时间 | < 5分钟 | ~1秒 | ✅ |
| 文件备份时间 | < 10分钟 | ~1秒 | ✅ |
| 健康检查响应 | < 1秒 | ~200ms | ✅ |
---
## 🔮 后续建议
1. **定时备份**:配置 cron/任务计划程序定时执行备份
2. **远程备份**:将备份文件同步到远程存储
3. **监控告警**:集成监控系统,异常时发送告警
4. **负载测试**:进行生产环境负载测试
---
## 📁 相关文件
```
furniture-3d-system/
├── scripts/
│ ├── backup-db.ps1 # 数据库备份
│ ├── backup-files.ps1 # 文件存储备份
│ ├── backup-all.ps1 # 完整备份
│ ├── restore.ps1 # 系统恢复
│ └── validate-config.ps1 # 配置验证
├── docker-compose.prod.yml # 生产环境配置
├── docs/
│ ├── 部署指南.md
│ ├── 运维指南.md
│ └── Phase10完成报告.md
└── src/app/
├── api/health/route.ts # 健康检查 API
└── system-health/ # 健康检查页面
```
---
**报告生成时间**:2025-12-22 18:17
**项目状态**:生产就绪 ✅

View File

@ -212,3 +212,69 @@
| `src/app/warehouse/WarehouseClient.tsx` | 移除 headerTools/eyebrow |
| `src/app/HomeClient.workspace.tsx` | 移除 topTools 传参 |
| ~20 个业务文件 | 硬编码颜色替换 |
---
## 第三阶段:管理基础设施视觉升级 (2026-04-16)
### 10. 管理端专属视觉模式 (Management UI Patterns)
在重构 `/admin` 和 `/users` 页面时,引入了针对“高密度控制类页面”的增强视觉模式,以平衡“工业精密感”与“视觉通透度”。
**1. 沉浸式页头 (Immersive Page Header)**
- **视觉特征**:
- 采用 `bg-white/60` + `backdrop-blur-2xl`。
- 强化左侧 Icon 视觉,使用 `rounded-[2rem] bg-black` 黑色底座,并叠加状态徽章(如 `ShieldCheck`)。
- **排版建议**:Manrope 3XL 标题 + 紧跟其后的 `text-apple-blue` 高亮关键词。
- **副标题**:使用 `text-[10px] tracking-[0.4em] uppercase` 的精密说明文字。
**2. 精密控制条 (Precision Control Bar)**
- **定义**:将原本分散的“搜索框”与“筛选器”整合进一个逻辑整体。
- **视觉实现**:
- 容器:`rounded-[2rem]` 极圆圆角,`border-white/80` 微光边框,`bg-white/40` 背景。
- 搜索框:沉浸式设计,背景为 `bg-white/80`,聚焦时通过 `ring-apple-blue/5` 产生柔和晕染。
- 筛选器:图标 (Lucide Icon) + Select 组件的紧凑组合,图标作为装饰前缀。
**3. 玻璃态卡片增强 (Enhanced Glass Cards)**
- **改动**:在 `rounded-[2rem]` 的基础上,引入了“装饰线”动效。
- **动效逻辑**:`group-hover:w-full` 的底部 1.5px 强调线,颜色与模块 Icon 色调一致。
- **背景文字装饰**:绝对定位的 `text-[80px]` 背景大字(如模块 path),设置 `opacity-[0.03]` 极低透明度,增加“空间感”。
**4. 状态指标看板 (System Health Dashboard)**
- 应用场景:`/admin` 首页。
- 组成:Icon 容器 + 上下两行文本(上行为微缩标签,下行为状态值)。
- 配色:动态使用 `emerald-500` (正常), `blue-500` (活动), `amber-500` (注意)。
**5. 三栏工作区 (Three-Column Workspace)**
- 应用场景:`/asset-center/material-library`。
- 定义:左侧极简分类 (Navigation) + 中间响应式网格 (Grid) + 右侧实时定义面板 (Inspector)。
- 优势:极大降低页面跳转成本,实现“即时反馈”。
**6. 精密滑块交互 (Precision Sliders)**
- 视觉表现:细条轨道 + 圆形 Thumb + 右侧数值百分比徽章。
- 应用场景:物理参数调节 (Metallic/Roughness/Opacity)。
- 规范:取代原有的输入框,滑动步长固定为 0.01 (1%)。
**7. 悬浮坞系统 (Floating Dock System)**
- 应用场景:`/assisted-assembly`。
- 定义:左侧布局的交互式入口,采用 `bg-black/60` + `backdrop-blur-3xl`。
- 动效:点击后向右水平展开列表。
- 逻辑:通过视觉发光 (Glow) 和计数徽标反馈当前分类的选择状态。
**8. 环境 HUD (Ambient HUD)**
- 定义:底部的非侵入式信息条。
- 样式:极圆胶囊型,`backdrop-blur-xl`。
- 作用:提供当前操作环境的实时状态(如“捕捉已就绪”)。
### 11. 改动文件清单
| 文件 | 改动类型 | 备注 |
|------|----------|------|
| `src/app/admin/page.tsx` | 重构 | 系统总控制台首页视觉重载 |
| `src/app/users/page.tsx` | 重构 | 身份控制中心 (用户管理) 三栏重写 |
| `src/app/asset-center/material-library/MaterialLibraryClient.tsx` | 重构 | 材质库首页视觉重写 (草稿图 12.png) |
| `src/app/assisted-assembly/AssistedAssemblyClient.tsx` | 重构 | 拼装工作台沉浸式重写 & 引入 Floating Dock |
| `src/components/platform/PlatformSplitLayout.tsx` | 基础重构 | 统一加装 backHref 导航标准 |

View File

@ -1,183 +0,0 @@
# 家具开品平台 - 文档导航
> **最后更新**:2026-03-31
> **项目状态**:新平台一期骨架已落地,旧 `CAD -> 装配步骤` 链继续作为兼容链保留
---
## 📖 快速导航
### 🎯 了解项目进度
- **[项目总览](./项目总览.md)** - 查看整体进度、功能完成度、下一步计划
- **[长期决策日志](./agent-memory/decision-log.md)** - 查看最近做过的重要技术与流程决策
- **[长期待办与阻塞](./agent-memory/open-issues.md)** - 查看当前仍在收口的问题
### 🏗️ 架构设计
- **[认证系统设计](./架构设计/auth-system-design.md)** - 用户认证和首次登录流程
- **[权限系统设计](./架构设计/permission-design-v2.md)** - 6 种角色的权限体系
### 📚 开发指南
- **[设计系统](./开发指南/设计指南.md)** - Apple 风格 UI 组件使用
- **[组件使用指南](./开发指南/组件使用指南.md)** - 常用组件的使用方法
- **[上传 API 指南](./开发指南/上传API指南.md)** - 文件上传功能使用
- **[性能优化指南](./开发指南/性能优化指南.md)** - 性能优化最佳实践
- **[数据库优化](./开发指南/数据库优化.md)** - 数据库查询优化
- **[快速测试指南](./开发指南/快速测试指南.md)** - 测试相关指南
- **[项目上下文](./agent-memory/project-context.md)** - 当前高频回归点、默认工作流、项目目标
### 🤝 团队协作
- **[团队协作模式](./workflow/团队协作模式.md)** - 当前推荐分工、分支规则、提交流程
- **[高频协作五条铁律](./workflow/高频协作五条铁律.md)** - 双 Codex 高频协作时的 5 条固定规则
- **[主线同步操作手册](./workflow/主线同步操作手册.md)** - 主线持续更新时,同事如何安全同步自己的分支
- **[同事本地 AGENTS 使用说明](./workflow/同事本地AGENTS使用说明.md)** - 如何给同事单独加 AI 约束,而不污染仓库共享规则
- **[同事本地 AGENTS 模板](./workflow/同事本地AGENTS模板.md)** - 可直接复制到同事电脑外层工作区的 `AGENTS.md` 模板
- **[模块边界说明](./workflow/模块边界说明.md)** - 新平台主链、包装协作、旧 CAD 兼容链的边界
- **[任务单模板](./workflow/任务单模板.md)** - 给人和 Codex 共用的任务模板
- **[提测与验收清单](./workflow/提测与验收清单.md)** - 提交前必须过的最小检查
- **[同事交接模板](./workflow/同事交接模板.md)** - 给非程序员同事和 Codex 的交接模板
### 🧠 长期记忆与问题收口
- **[长期记忆导航](./agent-memory/README.md)** - 当前长期记录入口
- **[长期决策日志](./agent-memory/decision-log.md)** - 近期关键决策
- **[长期待办与阻塞](./agent-memory/open-issues.md)** - 当前问题收口列表
### 📊 阶段完成报告(历史阶段)
- **[Phase 1: 数据库模型重构](./阶段报告/PHASE1_COMPLETE.md)**
- **[Phase 2: 认证系统](./阶段报告/PHASE2_COMPLETE.md)**
- **[Phase 3: 权限系统](./阶段报告/PHASE3_COMPLETE.md)**
- **[Phase 4: 组织架构](./阶段报告/PHASE4_COMPLETE.md)**
- **[Phase 5: 产品归属](./阶段报告/PHASE5_COMPLETE.md)**
- **[Phase 6: 离职交接](./阶段报告/PHASE6_COMPLETE.md)**
- **[Phase 7: 问题反馈](./阶段报告/PHASE7_COMPLETE.md)**
- **[Phase 8: 数据安全与日志](./阶段报告/PHASE8_COMPLETE.md)**
- **[Phase 9: 测试与优化](./阶段报告/Phase9总结.md)**
- **[Phase 10 完成报告](./Phase10完成报告.md)**
### 🧪 测试报告
- **[安全测试报告](./测试报告/安全测试报告.md)** - SQL 注入、XSS、权限测试
- **[性能测试报告](./测试报告/性能测试报告.md)** - 前端性能优化结果
- **[登录测试报告](./测试报告/登录测试报告.md)** - 登录流程测试
- **[主页测试报告](./测试报告/主页测试报告.md)** - 主页功能测试
---
## 🚀 快速开始
### 1. 查看项目进度
```bash
# 查看项目总览
cat docs/项目总览.md
```
### 2. 了解架构设计
```bash
# 查看权限系统设计
cat docs/架构设计/permission-design-v2.md
```
### 3. 开始开发
```bash
# 查看快速开始指南
cat ../README.md
```
---
## 📂 目录结构
```
docs/
├── README.md # 📖 本文档(导航入口)
├── 项目总览.md # 🎯 项目整体情况
├── PHASES_8_9_SUMMARY.md # 📊 最新阶段总结
├── workflow/ # 🤝 团队协作规则
│ ├── 团队协作模式.md
│ ├── 高频协作五条铁律.md
│ ├── 主线同步操作手册.md
│ ├── 同事本地AGENTS使用说明.md
│ ├── 同事本地AGENTS模板.md
│ ├── 模块边界说明.md
│ ├── 任务单模板.md
│ ├── 提测与验收清单.md
│ ├── 同事交接模板.md
│ └── 规范审查清单.md
│
├── 架构设计/ # 🏗️ 架构相关文档
│ ├── auth-system-design.md # 认证系统设计
│ └── permission-design-v2.md # 权限系统设计
│
├── 开发指南/ # 📚 开发相关指南
│ ├── 设计指南.md
│ ├── 组件使用指南.md
│ ├── 上传API指南.md
│ ├── 性能优化指南.md
│ ├── 数据库优化.md
│ └── 快速测试指南.md
│
├── 阶段报告/ # 📊 各阶段完成文档
│ ├── PHASE1_COMPLETE.md
│ ├── PHASE2_COMPLETE.md
│ ├── ...
│ ├── PHASE8_COMPLETE.md
│ ├── Phase9总结.md # ⭐ 当前阶段
│ ├── 第9阶段_第4天_上午完成.md
│ ├── 第9阶段_第4天_下午完成.md
│ ├── 第9阶段_第4天_总结.md
│ └── 第9阶段_第5天_下午完成.md
│
├── 测试报告/ # 🧪 测试相关报告
│ ├── 安全测试报告.md
│ ├── 性能测试报告.md
│ ├── 登录测试报告.md
│ └── 主页测试报告.md
│
└── 历史归档/ # 📦 过时的文档归档
├── database-redesign-product-sku.md
├── LOGIN_FLOW_FIXED.md
├── NEXT_STEPS.md
├── PHASES_5_6_7_SUMMARY.md
├── theme-adaptation-fix.md
├── troubleshooting-theme.md
├── 迁移指南.md
├── 用户指南.md
├── 主题测试指南.md
└── 实施计划.md
```
---
## 🎯 当前状态
### 当前重点
- 新主线已切到:`资产中心 -> 自动组合 -> 草稿组 -> 包装方案 -> 正式入库 -> 轻仓库`
- 旧 `CAD 导入 -> SKU 级结构数据 -> 装配编辑 -> 3D 回放` 继续保留为兼容链
- 当前重点不是继续堆页面,而是先把资产精度、模块边界和团队协作规则立住
### 当前建议查看顺序
1. **[项目总览](./项目总览.md)**
2. **[项目上下文](./agent-memory/project-context.md)**
3. **[长期待办与阻塞](./agent-memory/open-issues.md)**
4. **[长期决策日志](./agent-memory/decision-log.md)**
---
## 📞 需要帮助?
### 常见问题
1. **如何查看项目进度?** → 查看 [项目总览](./项目总览.md)
2. **如何了解权限系统?** → 查看 [权限系统设计](./架构设计/permission-design-v2.md)
3. **如何了解认证系统?** → 查看 [认证系统设计](./架构设计/auth-system-design.md)
4. **如何优化性能?** → 查看 [性能优化指南](./开发指南/性能优化指南.md)
### 联系方式
- 查看代码注释
- 查看相关文档
- 参考已完成的代码示例
---
**文档版本**:v2.2
**最后更新**:2026-03-31
**维护者**:开发团队

View File

@ -1,44 +0,0 @@
# Agent 长期记忆目录
> 目的:避免“换 Agent / 重启会话后失忆”,把关键事实沉淀为仓库文档。
## 文件说明
- `project-context.md`:项目现状、硬约束、当前优先级。
- `decision-log.md`:关键技术决策与原因(按日期追加)。
- `open-issues.md`:未完成项、阻塞项、下一步动作。
- `regression-checklist.md`:高风险功能回归清单(通过/失败状态)。
## 使用规则(强制)
1. 每轮任务开始前:先读上述 4 个文件。
2. 每轮任务结束后:至少更新 `decision-log.md` 与 `open-issues.md`。
3. 声称“已修复/已完成”前:更新 `regression-checklist.md` 的验证结果。
4. 长期事实只认本目录,不依赖临时 Agent 会话记忆。
## 容量上限(强制)
- `project-context.md`:不超过 220 行。
- `decision-log.md`:不超过 150 条决策或 24KB。
- `open-issues.md`:不超过 120 行。
- `regression-checklist.md`:不超过 220 行。
- 本目录总大小建议不超过 180KB(不含 `archive/`)。
超过上限时,先执行“压缩+归档”再继续新任务。
## 归档规则
- 归档目录:`docs/agent-memory/archive/`
- 归档命名:
- `decision-log-YYYY-MM.md`
- `open-issues-YYYY-MM.md`
- `regression-checklist-YYYY-MM.md`
- 当前文件顶部需保留:
- 最新摘要(3~10 行)
- 最近归档文件路径(便于追溯)
## 记录格式建议
- 日期:`YYYY-MM-DD`
- 状态:`待处理 / 处理中 / 已完成 / 阻塞`
- 每条记录尽量包含:问题、动作、证据(命令或文件路径)

View File

@ -1,17 +0,0 @@
# Agent 记忆归档目录
用途:存放从 `docs/agent-memory/` 主文件压缩出来的历史记录。
## 命名规则
- `decision-log-YYYY-MM.md`
- `open-issues-YYYY-MM.md`
- `regression-checklist-YYYY-MM.md`
## 归档流程(建议)
1. 从主文件剪切较旧内容到对应归档文件。
2. 在主文件顶部保留“当前摘要 + 归档路径”。
3. 确认主文件回到容量上限以内。
> 说明:归档文件默认不作为每轮必读内容,仅在追溯历史时查阅。

View File

@ -1,15 +0,0 @@
# 决策日志(长期)
| 日期 | 决策 | 原因 | 影响范围 | 状态 |
|---|---|---|---|---|
| 2026-03-13 | 协作流程收敛为“直接开发 + 规范审查闸门” | 避免运行时协作策略干扰主线开发,把硬规则稳定落到每次交付的固定步骤里 | 全项目默认协作方式、交付口径、审查流程 | 已生效 |
| 2026-03-05 | SKU详情页/装配编辑器节点解析统一到“模型真实节点映射 + canonical 别名解析”,并将 3D 拾取容差改为“中心命中优先 + 最近命中优先” | 修复 SKU 详情与装配编辑器点选规则不一致、折角线锚点错位,以及点选漂移导致的误选/漏选 | `SKUDetailClient.workspace`、`install-order-node-resolution`、`model-viewer-pick-tolerance` | 已生效 |
| 2026-02-27 | 装配编辑器本轮收口:修复可见乱码文案、步骤编辑器响应式布局、孔位高亮坐标解算改为“panel/modelRoot 双坐标根候选择优” | 解决页面可用性问题并降低孔位错绑/爆炸状态漂移 | `AssemblyEditorWorkspace`、`AssemblyStepEditor`、`HoleOverlay2D` | 已生效 |
| 2026-02-26 | 安装顺序链路后端收口:在 Service 新增“保存顺序+生成步骤+返回最新步骤”编排方法 | 符合企业级分层,避免前端承载业务编排 | `assembly.service`、`generate-from-order route` | 已生效 |
| 2026-02-26 | 生成失败后增加安装顺序补偿回滚,且 Route/Service 双层限制板件上限 300 | 降低部分成功状态与 DoS 风险 | `assembly.service`、`panel.repository`、`generate-from-order route` | 已生效 |
| 2026-02-26 | 安装顺序“保存+生成”前端改为调用 `/api/products/[id]/assembly/generate-from-order` 单接口,并直接消费响应 `steps` 刷新步骤区 | 减少一次网络往返,避免额外 `GET /assembly` 带来的时序抖动 | `AssemblyEditorWorkspace` 安装顺序提交流程 | 已完成 |
| 2026-02-26 | Agent 长期记忆从“会话上下文”切换为“仓库文档持久化” | 避免换会话或重启后丢失关键项目背景 | 全项目开发上下文与决策沉淀 | 已生效 |
| 2026-02-26 | 开发阶段默认采用“批量闭环修复”,不再以最小改动为目标 | 当前处于快速开发与清债阶段 | 任务拆分、修复策略、审查节奏 | 已生效 |
| 2026-02-26 | 安装顺序编辑器移除 `key` 强制重挂载,改为内部状态同步 | 降低重挂载性能损耗,保持数据同步 | `AssemblyEditorWorkspace`、`AssemblyStepEditor` | 已完成 |
> 追加规则:新决策按时间倒序追加到表格顶部。

View File

@ -1,61 +0,0 @@
# 待办与阻塞(长期)
最后更新:2026-03-11
## P0(高优先级)
- 问题:SKU 详情页与 SKU 装配页“部分板材不可选/折角线贴合异常”已完成代码修复,但仍需基于真实模型做人工终验(自动化仅验证到开关/基础交互)。
- 责任角色:QA 测试员 / 3D 工程师 / 前端工程师
- 下一步:在 `3000` 端口对固定 SKU 执行全量点选回归(非抽样),逐板件验证:可选中、安装顺序可入列、折角线贴边。
- 证据:`src/app/products/[id]/skus/[skuId]/SKUDetailClient.workspace.tsx`、`src/components/3d/model-viewer-pick-tolerance.ts`、`output/playwright/sku-regression-progress-2026-03-05T02-36-59-091Z/report.json`
- 状态:处理中
- 问题:`HoleOverlay2D` 在 `requestAnimationFrame` 内仍有较重计算(每帧分组聚合与多次对象创建),孔位多时存在掉帧风险。
- 责任角色:3D 工程师
- 下一步:抽离“静态分组/标签聚合”到 `useMemo`,绘制环节仅做投影与绘制;减少帧内临时对象创建。
- 证据:`src/components/3d/HoleOverlay2D.tsx`
- 状态:待处理
## P1(中优先级)
- 问题:`generate-from-order` 仍缺“接口限频 + 幂等键”治理,网络抖动下存在重复生成与写放大风险。
- 责任角色:后端工程师
- 下一步:为该路由增加用户维度限频,并设计幂等键(同一次提交在短窗口只执行一次)。
- 证据:`src/app/api/products/[id]/assembly/generate-from-order/route.ts`
- 状态:待处理
- 问题:当前补偿回滚仅覆盖安装顺序,生成前创建版本的写放大仍需评估(失败时可能产生额外版本记录)。
- 责任角色:后端工程师
- 下一步:评估“版本创建时机后移”或“失败标记版本”策略,避免无效版本增长。
- 证据:`src/server/services/assembly.service.ts`
- 状态:待处理
- 问题:安装顺序单接口 `generate-from-order` 已接入,仍需联调确认异常场景与 `warnings` 展示策略。
- 责任角色:前端工程师 / 后端工程师
- 下一步:用真实产品执行“点选顺序 -> 保存并生成”,确认失败提示与步骤回填一致;评估是否补充 `warnings` UI。
- 证据:`src/app/products/[id]/assembly/AssemblyEditorWorkspace.tsx`
- 状态:待处理
- 问题:`AssemblyEditorWorkspace` 仍有历史视觉 token 不统一(如部分 `bg-white/text-white`)。
- 责任角色:前端工程师
- 下一步:按页面分区批量替换为语义 token,不改业务逻辑
- 证据:`src/app/products/[id]/assembly/AssemblyEditorWorkspace.tsx`
- 状态:待处理
- 问题:`AssemblyEditorWorkspace` 仍存在组件内直写 `fetch` 的历史实现,未完全收口到 hooks/数据层。
- 责任角色:前端工程师
- 下一步:按接口链路分批迁移到 `src/hooks/api`,先迁移装配页高频接口,保持行为不变。
- 证据:`src/app/products/[id]/assembly/AssemblyEditorWorkspace.tsx`
- 状态:待处理
## 阻塞项
> 暂无
## 记录模板
- 问题:
- 责任角色:
- 下一步:
- 证据(文件/命令):
- 状态:待处理 / 处理中 / 已完成 / 阻塞

View File

@ -1,34 +0,0 @@
# 项目上下文(长期)
最后更新:2026-02-26
## 项目目标
- 核心:CAD 导入后,在装配编辑器中设置安装顺序并自动生成装配步骤。
- 重点链路:`装配编辑器(3D) -> 安装顺序 -> 自动生成步骤 -> 回放验证`。
## 当前硬约束
- 后端必须遵循:`API Route -> Service -> Repository -> Database`。
- 前端必须优先复用:`src/components/ui/` 元组件。
- 开发阶段策略:批量闭环修复,不以“最小改动”为默认目标。
- 交付前必须完成:规范审查;安全 / 性能 / QA 按任务风险追加。
- 当前总规则入口:根目录 `AGENTS.md` 与 `docs/workflow/*.md`。
## 用户关注的高频回归点
- 孔位高亮位置与爆炸程度同步。
- 折角线显示、文本与板材关联、边界不越出预览区。
- 白膜模式灰度正确(不是改背景色)。
- 板材可选中与高亮稳定。
- 右键菜单层级、位置、可见区域裁剪、材质预览交互。
- 爆炸程度滑块流畅性(无明显卡顿)。
- 中文 UI 文案与样式规范一致。
## 当前默认工作流
- 默认由当前开发流程直接推进任务。
- 开始前先明确:目标、验收标准、适用标准、根因判断。
- 开发后先做最小必要验证,再进入规范审查阶段。
- 规范审查固定检查:企业级架构标准、统一视觉标准、是否为根因修复。
- 遇到安全、性能、关键用户链路时,再补安全 / 性能 / QA 审查。

View File

@ -1,29 +0,0 @@
# 回归检查清单(长期)
最后更新:2026-02-26
## 装配编辑器核心交互
| 检查项 | 状态 | 备注 |
|---|---|---|
| 孔位高亮与真实孔位贴合 | 待验证 | 含爆炸程度 0%/45%/100% |
| 孔位高亮随爆炸程度同步 | 待验证 | 拖动滑块时不飘逸 |
| 折角线可见且随爆炸程度同步 | 待验证 | 文字不越界 |
| 折角线文字与板材名称关联 | 待验证 | 示例:`横隔板_panel 1` |
| 白膜模式显示为灰膜(非背景变灰) | 待验证 | 需在 3D 与预览区都确认 |
| 板材点选与高亮稳定 | 待验证 | 单选/多选都验证 |
| 鼠标中键平移符合“始终面对摄像机” | 待验证 | 默认中键行为无冲突 |
| 右键菜单位置不越出可视区域 | 待验证 | 含子菜单 |
| 右键菜单层级移动不丢焦点 | 待验证 | 材质二级/三级菜单 |
| 材质项小图+悬浮大图预览正常 | 待验证 | 不遮挡关键操作 |
| 爆炸程度滑块拖动流畅 | 已通过 | 已去除明显卡顿 |
| 中文文案与字体样式合规 | 待验证 | 开关、菜单、提示文案 |
## 安装顺序链路
| 检查项 | 状态 | 备注 |
|---|---|---|
| 点击板材按顺序追加步骤 | 已通过 | 重复点击不重复加入 |
| 保存顺序并自动生成步骤 | 待验证 | 已改为单接口 `generate-from-order` 且直接消费响应 `steps`;`lint/type-check` 已通过,待真实联调 |
| 步骤编辑器与外部步骤同步 | 已通过 | 移除 `key remount` |
| 安装顺序操作区使用元组件 | 已通过 | `Button` 已替换 |

View File

@ -1,34 +0,0 @@
# 解决方案沉淀库
本目录用于沉淀“已修复且已验证”的问题模式,目标是让后续同类问题更快定位、更稳修复。
## 目录规则
- `pattern-registry.yaml`:模式索引,维护状态与验证信息。
- `<category>/<slug>-YYYYMMDD.md`:单条问题模式文档。
## 分类建议
- `build-errors`
- `test-failures`
- `runtime-errors`
- `performance-issues`
- `database-issues`
- `security-issues`
- `ui-bugs`
- `integration-issues`
- `logic-errors`
- `workflow-issues`
- `developer-experience`
- `documentation-gaps`
## 文档命名
- 建议格式:`<slug>-YYYYMMDD.md`
- 例:`service-repository-layering-user-service-20260215.md`
## 使用流程
1. 修复并验证通过后,新增/更新对应模式文档。
2. 同步更新 `pattern-registry.yaml` 的状态和验证时间。
3. 若旧模式被替代,不直接删除,标记为 `deprecated` 或 `merged`。

View File

@ -1,172 +0,0 @@
patterns:
- id: WF-SVC-REPO-USER-001
file: docs/solutions/workflow-issues/service-repository-layering-user-service-20260215.md
problem_type: workflow_issue
status: active
last_verified_at: 2026-02-15
usage_count: 1
success_rate: 1.0
supersedes: []
superseded_by: []
- id: SEC-PANEL-PERM-001
file: docs/solutions/security-issues/panel-write-permission-guard-20260215.md
problem_type: security_issue
status: active
last_verified_at: 2026-02-15
usage_count: 1
success_rate: 1.0
supersedes: []
superseded_by: []
- id: SEC-HOLE-PERM-001
file: docs/solutions/security-issues/hole-permission-guard-20260215.md
problem_type: security_issue
status: active
last_verified_at: 2026-02-15
usage_count: 1
success_rate: 1.0
supersedes: []
superseded_by: []
- id: WF-HOLE-ROUTE-SERVICE-001
file: docs/solutions/workflow-issues/hole-route-service-layering-20260215.md
problem_type: workflow_issue
status: active
last_verified_at: 2026-02-15
usage_count: 1
success_rate: 1.0
supersedes: []
superseded_by: []
- id: SEC-PRODHW-PERM-001
file: docs/solutions/security-issues/product-hardware-permission-guard-20260215.md
problem_type: security_issue
status: active
last_verified_at: 2026-02-15
usage_count: 1
success_rate: 1.0
supersedes: []
superseded_by: []
- id: WF-PRODHW-ROUTE-SERVICE-001
file: docs/solutions/workflow-issues/product-hardware-route-layering-20260215.md
problem_type: workflow_issue
status: active
last_verified_at: 2026-02-15
usage_count: 1
success_rate: 1.0
supersedes: []
superseded_by: []
- id: SEC-PANEL-BOUNDARY-001
file: docs/solutions/security-issues/panel-nested-product-boundary-20260215.md
problem_type: security_issue
status: deprecated
last_verified_at: 2026-02-15
usage_count: 1
success_rate: 1.0
supersedes: []
superseded_by: [SEC-PANEL-HOLE-BOUNDARY-001]
- id: SEC-COLLAB-PII-001
file: docs/solutions/security-issues/collaborator-email-minimization-20260215.md
problem_type: security_issue
status: active
last_verified_at: 2026-02-15
usage_count: 1
success_rate: 1.0
supersedes: []
superseded_by: []
- id: SEC-HOLE-MATCH-GUARD-001
file: docs/solutions/security-issues/hole-match-access-throttle-20260215.md
problem_type: security_issue
status: active
last_verified_at: 2026-02-15
usage_count: 1
success_rate: 1.0
supersedes: []
superseded_by: []
- id: SEC-PANEL-HOLE-BOUNDARY-001
file: docs/solutions/security-issues/panel-hole-delete-boundary-20260215.md
problem_type: security_issue
status: active
last_verified_at: 2026-02-15
usage_count: 1
success_rate: 1.0
supersedes: [SEC-PANEL-BOUNDARY-001]
superseded_by: []
- id: WF-PANEL-ROUTE-SVC-001
file: docs/solutions/workflow-issues/panel-route-service-permission-unification-20260215.md
problem_type: workflow_issue
status: active
last_verified_at: 2026-02-15
usage_count: 1
success_rate: 1.0
supersedes: []
superseded_by: []
- id: WF-DWG-TASK-CLEANUP-001
file: docs/solutions/workflow-issues/dwg-task-lifecycle-cleanup-20260215.md
problem_type: workflow_issue
status: active
last_verified_at: 2026-02-15
usage_count: 1
success_rate: 1.0
supersedes: []
superseded_by: []
- id: WF-UI-TOKEN-RAF-001
file: docs/solutions/workflow-issues/ui-token-and-raf-optimization-20260215.md
problem_type: workflow_issue
status: active
last_verified_at: 2026-02-15
usage_count: 1
success_rate: 1.0
supersedes: []
superseded_by: []
- id: WF-CONTROLLER-LAYERING-002
file: docs/solutions/workflow-issues/controller-overload-layering-batch-20260215.md
problem_type: workflow_issue
status: active
last_verified_at: 2026-02-15
usage_count: 1
success_rate: 1.0
supersedes: []
superseded_by: []
- id: WF-COLLAB-RELATION-LIBDS-001
file: docs/solutions/workflow-issues/collaborator-relation-and-lib-datasource-20260215.md
problem_type: workflow_issue
status: active
last_verified_at: 2026-02-15
usage_count: 1
success_rate: 1.0
supersedes: []
superseded_by: []
- id: WF-UI-WORKSPACE-MODULAR-001
file: docs/solutions/workflow-issues/ui-monolith-workspace-modularization-batch-20260216.md
problem_type: workflow_issue
status: active
last_verified_at: 2026-02-16
usage_count: 1
success_rate: 1.0
supersedes: []
superseded_by: []
- id: WF-ASSEMBLY-INTERACTION-002
file: docs/solutions/workflow-issues/assembly-3d-interaction-regression-20260223.md
problem_type: workflow_issue
status: active
last_verified_at: 2026-02-23
usage_count: 2
success_rate: 1.0
supersedes: []
superseded_by: []
- id: WF-ASSEMBLY-EDITOR-SYNC-003
file: docs/solutions/workflow-issues/assembly-install-order-editor-sync-20260226.md
problem_type: workflow_issue
status: active
last_verified_at: 2026-02-26
usage_count: 1
success_rate: 1.0
supersedes: []
superseded_by: []
- id: WF-ASSEMBLY-ORDER-ORCH-004
file: docs/solutions/workflow-issues/assembly-generate-from-order-orchestration-20260226.md
problem_type: workflow_issue
status: active
last_verified_at: 2026-02-26
usage_count: 1
success_rate: 1.0
supersedes: []
superseded_by: []

View File

@ -1,37 +0,0 @@
---
title: 协作者列表默认暴露邮箱,需最小化返回字段
date: 2026-02-15
module: product-collaborator
problem_type: security_issue
severity: high
symptoms:
- 协作者 GET 对有查看权限用户默认返回创建者与协作者邮箱
- 造成组织敏感信息过度暴露
root_cause: 数据最小化策略缺失,读取权限与敏感字段权限未分离
resolution_type: code_fix
status: active
confidence: high
tags: [security, privacy, collaborators, pii]
related_patterns: [SEC-COLLAB-PII-001]
---
## 现象与影响
即使用户仅具备产品可见权限,也能读取所有协作者邮箱,扩大了员工账号信息暴露面。
## 修复动作
1. 保留 `canViewProduct` 作为协作者列表读取前置条件。
2. 新增 `canManage` 判定,仅当通过 `canManageCollaborators` 时返回邮箱字段。
3. 默认返回中将创建者与协作者 `email` 置为 `null`,满足“最小必要信息”原则。
## 验证
- `npm run type-check -- --pretty false` 通过
- `npm test -- tests/lib/cad-panel-linking.test.ts --runInBand` 通过
- `npm test -- tests/api/auth-me.test.ts --runInBand` 通过
## 预防策略
- API 设计区分“可查看资源”与“可查看敏感字段”两层权限。
- 新增返回字段时默认走最小化策略,敏感字段须显式授权后释放。

View File

@ -1,42 +0,0 @@
---
title: holes/match 权限与滥用防护收口
date: 2026-02-15
module: hole-match
problem_type: security_issue
severity: critical
symptoms:
- autoSave=true 仅校验登录态,未校验产品编辑权限
- autoSave=false 可匿名读取非公开产品匹配结果
- 匿名高频调用会触发大规模匹配计算
root_cause: 匹配链路缺少产品级权限判断与接口级节流,且计算规模没有上限
resolution_type: code_fix
status: active
confidence: high
tags: [security, permission, rate-limit, holes, match]
related_patterns: [SEC-HOLE-PERM-001]
---
## 现象与影响
`/api/holes/match` 存在“已登录即可写任意产品”和“匿名可读非公开产品”的边界缺口,同时高频请求会放大 CPU/DB 消耗。
## 修复动作
1. 在 `src/server/services/hole.service.ts` 的 `matchHardware` 增加产品解析与权限判断:
- 保存结果:`canEditProduct`
- 预览结果:`canViewProduct`
- 匿名访问:仅允许 `PUBLIC` 产品
2. 增加匹配规模上限(匿名/登录/保存分级)和五金库查询上限(1500)。
3. 在 `src/app/api/holes/match/route.ts` 增加按用户/IP 的窗口限流。
## 验证
- `npm run type-check -- --pretty false` 通过
- `npm test -- tests/lib/cad-panel-linking.test.ts --runInBand` 通过
- `npm test -- tests/api/auth-me.test.ts --runInBand` 通过
## 预防策略
- 任何“预览 + 保存”双模式接口都要在 Service 层拆分权限模型,而不是只在 Route 判断登录态。
- 计算型接口默认要有“节流 + 规模上限”双保险。

View File

@ -1,36 +0,0 @@
---
title: Hole 写/读操作缺少 Service 层产品权限护栏
date: 2026-02-15
module: hole-service
problem_type: security_issue
severity: critical
symptoms:
- /api/holes 与 /api/holes/[id] 依赖登录态,缺少基于产品归属的 canEditProduct/canViewProduct 校验
- Route 可被绕过时,Service 直接写孔位数据,存在跨产品越权风险
root_cause: 权限策略停留在 Route 入参层,Service 未对 hole/panel -> product 归属做统一鉴权
resolution_type: code_fix
status: active
confidence: high
tags: [security, idor, permission, holes, service-layer]
related_patterns: [WF-HOLE-ROUTE-SERVICE-001]
---
## 现象与影响
孔位写接口在“已登录”之后直接执行写库,读接口允许匿名访问精确结构参数。缺少产品级权限校验时,攻击者可通过可猜测 ID 读取或修改不属于自己的产品孔位数据。
## 修复动作
1. 在 `src/server/services/hole.service.ts` 新增 `requireUser/getProductForPermission/assertCanViewProduct/assertCanEditProduct`。
2. 将权限护栏接入 `listByFilter/findById/findByPanelId`(查看)与 `create/createMany/update/delete/deleteMany/deleteByPanelId/deleteByFilter`(写入)。
3. 所有写入前都先解析 `hole/panel -> product` 归属,再执行 `canEditProduct`。
## 验证
- `npm run type-check -- --pretty false` 通过
- `npm test -- tests/lib/cad-panel-linking.test.ts --runInBand` 通过
## 预防策略
- 所有“资源隶属产品”的接口统一执行“Route 鉴权入口 + Service 产品权限护栏”。
- Service 层禁止依赖 Route 先验假设(例如“已经做过权限校验”)。

View File

@ -1,35 +0,0 @@
---
title: 面板级孔位批量删除越界防护
date: 2026-02-15
module: panel-hole-route
problem_type: security_issue
severity: high
symptoms:
- products/[id]/panels/[panelId]/holes?ids= 删除时未校验 hole 是否属于 panelId
root_cause: Service 批量删除只校验“同一产品”,缺少“同一面板”边界约束
resolution_type: code_fix
status: active
confidence: high
tags: [security, idor, panel, holes]
related_patterns: [SEC-PANEL-BOUNDARY-001]
---
## 现象与影响
攻击者可以在面板级接口传入其他面板的 holeId,实现越界删除。
## 修复动作
1. `holeService.deleteMany` 新增 `expectedPanelId` 参数。
2. 删除前逐条验证 `hole.panelId === expectedPanelId`,不符合直接拒绝。
3. 路由 `src/app/api/products/[id]/panels/[panelId]/holes/route.ts` 在 DELETE 分支传入 `expectedPanelId`,并补充空 ids 校验。
## 验证
- `npm run type-check -- --pretty false` 通过
- `npm test -- tests/lib/cad-panel-linking.test.ts --runInBand` 通过
## 预防策略
- 嵌套路由的批量接口,必须做“URL 资源边界”与“请求体资源边界”双向一致性校验。

View File

@ -1,37 +0,0 @@
---
title: 嵌套路由 panelId 缺少 productId 归属校验(IDOR)
date: 2026-02-15
module: panel-nested-routes
problem_type: security_issue
severity: critical
symptoms:
- /api/products/[id]/panels/[panelId] 与 /holes 子路由按 panelId 直接读写
- 未校验 panel.productId 与 URL 中 productId 一致
root_cause: 路由层默认信任路径参数,未建立资源归属约束
resolution_type: code_fix
status: active
confidence: high
tags: [security, idor, route, panel, product]
related_patterns: [SEC-PANEL-BOUNDARY-001]
---
## 现象与影响
攻击者可构造“任意 productId + 目标 panelId”请求,在嵌套路由下越权读取或修改其他产品下的板件/孔位。
## 修复动作
1. 在 `panel.service.ts` 新增 `assertPanelBelongsToProduct(panelId, productId)`。
2. 在 `products/[id]/panels/[panelId]/route.ts` 与 `products/[id]/panels/[panelId]/holes/route.ts` 所有读写入口统一先做归属校验。
3. `panel.service.findById` 增加 `canViewProduct` 权限护栏,并将板件详情 GET 改为认证访问。
## 验证
- `npm run type-check -- --pretty false` 通过
- `npm test -- tests/lib/cad-panel-linking.test.ts --runInBand` 通过
- `npm test -- tests/api/auth-me.test.ts --runInBand` 通过
## 预防策略
- 所有形如 `/products/:productId/.../:resourceId` 的接口,必须执行“resource -> productId 与路径一致”校验。
- 归属校验与权限校验都应在 Service 层有可复用方法,Route 只负责调用。

View File

@ -1,36 +0,0 @@
---
title: Panel 写操作缺少 Service 层权限护栏
date: 2026-02-15
module: panel-service
problem_type: security_issue
severity: critical
symptoms:
- 板件创建路由做了权限校验,但 Service 层写操作未做 canEditProduct 兜底
- 可通过绕过 Route 的调用路径触发越权写入
root_cause: 权限逻辑集中在 Route,Service 层缺少防线
resolution_type: code_fix
status: active
confidence: high
tags: [security, idor, permission, panel, service-layer]
related_patterns: []
---
## 现象与影响
板件创建接口在 Route 层做了登录+编辑权限校验,但 `panel.service.ts` 的 `create/update/delete/importFromZip` 在写库前不校验产品编辑权限。
一旦存在绕过 Route 的调用(内部复用、脚本、后续新增路由等),会造成跨产品越权写入。
## 修复动作
1. 在 Service 层新增 `assertCanEditProduct` 权限护栏。
2. 新增 `parseCollaborators` 解析 JSON 协作者列表,兼容权限函数输入。
3. 将护栏接入 `create/update/delete/importFromZip` 四个写操作。
## 验证
- `npm run type-check -- --pretty false` 通过
## 预防策略
- 所有写操作必须“Route + Service 双层权限校验”。
- 新增写接口时,优先复用统一权限护栏方法,避免每个方法重复拼装权限对象。

View File

@ -1,38 +0,0 @@
---
title: Product Hardware 接口缺少产品级权限护栏
date: 2026-02-15
module: product-hardware
problem_type: security_issue
severity: critical
symptoms:
- /api/product-hardware/[id] GET 允许匿名读取
- PATCH/DELETE 只校验登录,未校验当前用户是否有目标产品权限
root_cause: 接口按资源 ID 直接读写,缺少 productId 归属权限校验
resolution_type: code_fix
status: active
confidence: high
tags: [security, idor, permission, product-hardware]
related_patterns: [WF-PRODHW-ROUTE-SERVICE-001]
---
## 现象与影响
攻击者只要拿到 `productHardware.id`,就可能越权读取产品结构细节或修改/删除不属于自己的五金件关联记录。
## 修复动作
1. 新增 `src/server/services/product-hardware.service.ts`,在 `findById/update/delete` 统一执行:
- 解析 `productHardware.productId`
- 基于产品快照执行 `canViewProduct/canEditProduct`
2. 新增 `src/server/repositories/product-hardware.repository.ts`,由 Repository 承担查询与更新细节。
3. `src/app/api/product-hardware/[id]/route.ts` 全面改为通过 Service 调用,GET 不再匿名开放。
## 验证
- `npm run type-check -- --pretty false` 通过
- `npm test -- tests/lib/cad-panel-linking.test.ts --runInBand` 通过
## 预防策略
- 所有“按资源 ID 直接读写”的接口,必须在 Service 层做“资源 -> productId -> 权限”链路校验。
- Route 层不得直接承担权限规则分支与数据库读写。

View File

@ -1,530 +0,0 @@
# CAD 插件装配语义导出改造说明(2026-03-25)
## 目标
本次任务的目标,不是优化爆炸图表现,而是改造 `CAD` 插件的导出能力,让导出数据可以支撑“真实安装方向”的自动化安装动画。
要解决的问题是:
- 当前爆炸图使用“从模型中心向外的球形爆炸”。
- 这个展示逻辑本身没问题。
- 真正的问题在于:安装步骤还原时,错误复用了爆炸方向。
- 结果是,本应沿固定轴插入、垂直装配、或从上往下压装的板件,被错误地做成了沿斜向飞回去。
本次必须按根因修复处理,不能继续在展示方向上打补丁。
---
## 根因结论
当前系统把两类完全不同的语义混在了一起:
1. 展示语义:为了让模型更容易看清,各零件从模型中心向外散开。
2. 安装语义:零件在真实装配中应该沿哪个方向进入、从哪里进入、依赖谁先装。
现在缺的不是“更复杂的爆炸算法”,而是“独立的装配语义数据层”。
一句话概括:
`展示方向` 和 `安装方向` 必须彻底分开。
---
## 当前现状确认
在动手前,先确认下面这些事实成立:
### 插件侧现状
插件源码目录:
`D:\AI Code\3danzhuang\autocad-plugin\FurnitureExporter`
插件发布目录:
`D:\AI Code\3danzhuang\autocad-plugin\dist\家具导出插件-v2.3.1-一键安装版`
插件当前已经能导出这些核心数据:
- `panels`
- `holes`
- `holeGroups`
- `hardwareTypes`
- `hardwareSummary`
插件当前已具备的基础能力包括:
- 板件位置、尺寸、法向、包围盒提取
- 板件类型推断
- 孔位检测与用途推断
- 逻辑孔组
- 五金实例与板件、孔位、孔组的绑定关系
但插件当前还没有显式导出这些数据:
- 板件真实安装方向
- 安装方式
- 板件与板件的配合面关系
- 起装偏移和装配行程
- 板件装配依赖关系
### 主项目侧现状
主项目目录:
`D:\AI Code\3danzhuang\furniture-3d-system`
当前与问题强相关的文件:
- `D:\AI Code\3danzhuang\furniture-3d-system\src\lib\sku-cad-data.ts`
- `D:\AI Code\3danzhuang\furniture-3d-system\src\lib\assembly-generator.ts`
- `D:\AI Code\3danzhuang\furniture-3d-system\src\components\assembly\AssemblyAnimationPlayer.tsx`
- `D:\AI Code\3danzhuang\furniture-3d-system\src\lib\3d\engine.ts`
- `D:\AI Code\3danzhuang\furniture-3d-system\src\lib\3d\explosion-math.ts`
当前主项目实际上只消费了这类信息:
- `panelType`
- `explosionDirection`
- `cadPosition`
- `cadNormal`
- `cadBoundingBox`
当前主项目没有真正保存这类安装语义:
- `assemblyAxis`
- `installDirection`
- `mountMode`
- `preAssembleOffset`
- `travelDistance`
- `dependsOn`
- `mates`
当前播放层的板件动画仍然属于演示级飞入,不是真实装配路径。
---
## 本次修改边界
### 优先级
1. 优先改 `CAD` 插件导出层。
2. 如有必要,只做最小范围的主项目类型补充和解析补充。
3. 不要先大改前端播放逻辑。
### 明确禁止
- 不要把“真实安装方向”继续塞进 `explosionDirection`。
- 不要删除、重命名、破坏现有导出字段。
- 不要为了追求快速可见效果,写死某几类板件的方向当成通用方案。
- 不要把问题继续做成“根据 `panelType` 猜一个方向”的补丁式方案。
---
## 必须实现的结果
插件需要额外导出一层“装配语义数据”,至少要回答下面这些问题:
- 这块板最终沿哪个方向装进去?
- 它是平移插入、下压就位,还是旋转后就位?
- 它依赖哪些板先装?
- 它最终和哪块板的哪一面贴合?
- 动画起点应该从目标位往哪个方向退多远?
- 这次自动推导的结果置信度是多少?
目标不是一上来做到所有复杂场景全覆盖,而是:
- 对大多数标准柜体板件自动推导正确方向
- 对异常件保留清晰兜底
- 保持向后兼容
---
## 推荐的数据结构
建议在现有 `hardware.json` 根对象中新增一个可选字段:
`assembly`
不要破坏任何已有字段。
### ExportData 新增字段
```csharp
public AssemblyData? Assembly { get; set; }
```
### AssemblyData 建议结构
```json
{
"assembly": {
"version": "1.0",
"panelAssemblies": [],
"connections": []
}
}
```
### PanelAssemblyInfo 最少字段
- `panelId`
- `mountMode`
- `assemblyAxis`
- `assemblyDirection`
- `preAssembleOffset`
- `travelDistance`
- `dependsOn`
- `primarySupportPanelId`
- `targetPanelIds`
- `mates`
- `confidence`
- `warnings`
- `autoGenerated`
### 推荐语义
#### mountMode
至少支持:
- `slide_in`
- `drop_in`
- `rotate_into_place`
- `unknown`
#### assemblyAxis
长度为 `3` 的单位向量,例如:
```json
[1, 0, 0]
```
#### assemblyDirection
离散标签,例如:
- `+X`
- `-X`
- `+Y`
- `-Y`
- `+Z`
- `-Z`
#### preAssembleOffset
从最终安装位往外退的偏移向量,单位 `mm`。
#### travelDistance
沿安装方向需要走的距离,单位 `mm`。
### AssemblyMateInfo 最少字段
- `targetPanelId`
- `selfFace`
- `targetFace`
- `connectionType`
- `confidence`
### 可选增强字段
如果你判断后续会用到,可以增加:
- `rotationAxis`
- `pivotPoint`
- `inferenceReason`
---
## 推导逻辑要求
### 总原则
严禁再使用“模型中心到板中心”的方向来推安装方向。
真实安装方向必须优先从以下两类信息中推导:
1. 连接关系
2. 配合关系
### 优先级
#### 第一优先级:孔位、孔组、五金绑定
如果一块板与另一块板之间存在明显的孔组配对、连接件绑定、木榫、三合一、偏心件等关系,则安装方向优先由这些连接关系推导。
要求:
- 优先使用孔轴线、孔法向、孔组法向判断推进方向。
- 若连接关系明显指向某一主轴,则该方向优先于 `panel.normal`。
- `panel.normal` 只能视为板厚方向参考,不能直接当安装方向。
#### 第二优先级:板件配合面
通过板件的 `boundingBox` 与 `position`,寻找相邻板件和配合面关系。
要求:
- 找出哪两个轴重叠明显、哪一个轴面距最小。
- 明确导出 `selfFace` 和 `targetFace`。
- 安装方向应取“朝向配合面的反向推进”。
#### 第三优先级:板件类型和空间位置兜底
当连接关系不够强时,再使用以下信息兜底:
- `panelType`
- 板件在整体空间中的位置
- 是否位于顶部、底部、侧边、中间层
这部分只能做兜底,不能成为主逻辑。
---
## 建议的判定规则
建议把这些常量集中管理,不要散落在多个文件里:
```text
FACE_GAP_TOLERANCE_MM = 3
FACE_OVERLAP_RATIO_MIN = 0.25
HOLE_ASSOCIATION_TOLERANCE_MM = 5
OUTSIDE_MARGIN_MM = 30
MIN_PREASSEMBLE_DISTANCE_MM = 80
```
### 相邻板候选判定
建议规则:
- 两块板在两个轴上的投影重叠比例大于等于 `0.25`
- 在剩余一个轴上的最近面间距小于等于 `3 mm`
- 满足后,视为存在面接触候选
### 配合面识别
建议规则:
- 若最近面在 `X` 轴方向,则候选面为 `left / right`
- 若最近面在 `Y` 轴方向,则候选面为 `front / back`
- 若最近面在 `Z` 轴方向,则候选面为 `top / bottom`
注意:
- `selfFace` 和 `targetFace` 都要导出
- 不要只导一个方向标签
### 安装方向识别
建议规则:
- 有明确孔组或连接件时,优先取孔轴线或连接件主方向
- 有明确配合面时,取“指向配合面的反方向推进”
- 无强连接时,再用 `panelType` 兜底
- 严禁直接使用“模型中心 -> 板中心”
### MountMode 判定
`V1` 先覆盖大多数标准柜体板件,不要过度设计。
建议规则:
- `assemblyAxis` 近似 `X` 或 `Y` 主轴,优先判为 `slide_in`
- `assemblyAxis` 近似 `Z` 主轴,且板件明显从上往下落位,优先判为 `drop_in`
- 若单轴平移无法解释主要配合关系,再考虑 `rotate_into_place`
- `V1` 对 `rotate_into_place` 要谨慎输出,宁可少判,不要乱判
- 无法高置信推断时,输出 `unknown`,并给出 `warnings`
### DependsOn 推导
建议规则:
- 与当前板存在主要配合或支撑关系的板,进入 `dependsOn`
- `primarySupportPanelId` 选主要承载或主要配合对象
- `targetPanelIds` 保存所有主要装配目标板
本轮不要求做绝对完美的全局装配排序,但至少要导出局部依赖关系。
### PreAssembleOffset 与 TravelDistance
严禁直接写死固定值。
建议规则:
1. 取当前板的目标包围盒
2. 取 `dependsOn` 或 `targetPanelIds` 对应参考板的合并包围盒
3. 沿 `assemblyAxis` 的反方向,将当前板虚拟退到“完全脱离参考包围盒 + 30 mm 安全边距”的位置
4. 该退出来的向量即为 `preAssembleOffset`
5. 该向量长度即为 `travelDistance`
6. 若结果过小,则至少保证 `80 mm` 的最小预装距离
---
## 覆盖与兜底机制
目标是最大化自动化,但不要假设所有模型都能 `100%` 自动判断。
必须预留人工覆盖机制,但默认不要求设计师参与。
原则:
- 没有覆盖标记时,插件必须全自动运行
- 有覆盖标记时,以覆盖结果为准
- 被覆盖的结果也必须写回导出 `JSON`
- 被覆盖的结果必须标记 `autoGenerated = false`
推荐支持的覆盖字段:
- `AssemblyDirectionOverride`
- `MountModeOverride`
- `DependsOnOverride`
- `PreAssembleOffsetOverride`
覆盖承载方式可自行选择一种稳定方案,例如:
- 图层命名约定
- 块属性
- `XData`
- `Extension Dictionary`
---
## 实现建议
建议新增独立分析器,不要把全部逻辑硬塞进现有 `PanelAnalyzer`。
推荐结构:
- `AssemblySemanticAnalyzer.cs`
- `AssemblyInferenceHelpers.cs`
- `BoundingBoxMath.cs`
- `FaceRelationHelper.cs`
最低建议是新增:
- `AssemblySemanticAnalyzer.cs`
建议输入:
- `List<PanelInfo> panels`
- `List<HoleInfo> holes`
- `List<HoleGroupInfo> holeGroups`
- `List<HardwareType> hardwareTypes`
建议输出:
- `AssemblyData`
导出链路建议:
1. 先按现有流程完成几何与五金数据导出
2. 再执行装配语义分析
3. 将结果挂到 `ExportData.Assembly`
4. 最终仍输出到同一个 `hardware.json`
---
## 主项目侧的最小改动原则
如果为了验证新导出结构,需要顺带让主项目先能读取这些字段,只做最小必要改动:
- 更新 `sku-cad-data.ts` 的类型定义
- 增加 `assembly` 字段的解析与归一化
- 使用可选字段保证旧数据不报错
这次不要优先做:
- 大改 `assembly-generator.ts`
- 大改 `AssemblyAnimationPlayer.tsx`
- 把临时规则直接写死进播放器
本次主战场是插件导出层,不是前端动画层。
---
## 向后兼容要求
必须满足以下兼容条件:
- 原有 `panels / holes / holeGroups / hardwareTypes / hardwareSummary` 不破坏
- 原有导出样例仍能导出成功
- 新增字段为空时,不影响旧链路
- 老版本 `hardware.json` 没有 `assembly` 字段时,主项目仍可读取旧数据
- 如果补了主项目类型定义,必须使用可选字段处理
---
## 验证要求
必须使用这个样例做最小必要验证:
`D:\AI Code\3danzhuang\素材\BJ0124(1)_export.zip`
验证至少包括:
1. 解压并检查当前 `hardware.json`
2. 修改插件后,重新生成或模拟生成新的导出结构
3. 确认新增 `assembly` 字段结构完整
4. 至少输出每个 `panel` 的以下结果:
- `panelId`
- `mountMode`
- `assemblyDirection`
- `dependsOn` 数量
- `travelDistance`
- `confidence`
5. 对明显标准板件,确认安装方向不是“从模型中心往回飞”的结果
6. 明确哪些板件属于高置信自动推导,哪些属于兜底推导
如果当前样例缺少真实五金实例,必须明确写出:
- 本轮验证主要覆盖板件装配语义
- 五金参与的复杂装配仍需后续拿带真实五金实例的样例继续验证
不能假装已经完整验证复杂五金场景。
---
## 验收标准
只有同时满足以下条件,才算本次任务完成:
1. 插件可以额外导出装配语义,而不只有几何数据
2. 真实安装方向不再依赖球形爆炸方向
3. 安装方向优先基于连接关系和配合面推导
4. 对大多数标准柜体板件,能自动给出合理的 `slide_in / drop_in` 方向
5. 导出结果保留置信度和警告信息
6. 对异常件具备兜底能力
7. 对现有结构保持向后兼容
8. 做了最小但有效的验证,而不是只改代码不验证
---
## 交付要求
完成后请按下面顺序汇报:
1. 改了什么
2. 验证结果是什么
3. 还剩什么风险
4. 哪些场景已经覆盖
5. 哪些场景还需要更多样例验证
6. 是否改动了主项目消费层
7. 是否生成了新的插件产物
除非明确要求,不要主动 `commit`。
---
## 一句最终提醒
这次要解决的是“安装语义缺失”,不是“爆炸动画不够漂亮”。
不要把问题做成:
- 继续强化 `explosionDirection`
- 继续按 `panelType` 猜方向
- 在前端播放器里堆临时特判
必须把“展示方向”和“安装方向”彻底分层。

View File

@ -1,72 +0,0 @@
---
title: 装配页 3D 交互回归(选中/右键材质/孔位/爆炸拖动)
date: 2026-02-23
module: assembly-editor
problem_type: workflow_issue
severity: high
symptoms:
- 中键平移偶发触发浏览器默认行为,平移手感异常
- 板件点击命中率下降,选中高亮不稳定
- 右键材质菜单缺少完整层级与材质预览
- 孔位高亮与模型孔位存在偏移,爆炸拖动时错位更明显
- 爆炸程度滑块拖动时卡顿
root_cause: 交互链路在多轮重构后出现能力回退,菜单结构、拾取兜底、覆盖层坐标映射与渲染节流未统一
resolution_type: code_fix
status: active
confidence: high
tags: [assembly, threejs, context-menu, picking, hole-overlay, performance]
related_patterns: [WF-UI-TOKEN-RAF-001, WF-UI-WORKSPACE-MODULAR-001]
---
## 现象与影响
装配页多个核心交互同时回退:板件难选中、材质菜单不完整、孔位高亮不准、爆炸拖动卡顿,直接影响装配演示与编辑效率。
## 排查路径
1. 先复跑类型检查与核心测试,确保没有基础语法/类型噪音干扰。
2. 对交互链路逐层定位:`AssemblyEditorWorkspace -> ModelViewer -> ThreeDEngine -> HoleOverlay2D -> ContextMenu`。
3. 对比当前行为与预期能力,确认回退点主要集中在:
- 拾取失败时没有兜底路径;
- 右键菜单缺少材质三级结构与预览;
- 爆炸滑块每次输入都触发重计算;
- 孔位候选坐标选择策略过松,导致对齐偏差。
## 最终修复
1. `src/components/3d/ModelViewer.tsx`
- 增加拾取兜底:候选名拾取失败时自动执行全场拾取,再做节点名规范化映射。
- 中键按下补 `preventDefault`,避免浏览器默认中键行为干扰平移。
2. `src/lib/3d/engine.ts`
- `applyMaterialToMesh` 补充 `normalizeTooBrightMaterial`,动态换材后依然执行近白灰化。
3. `src/components/3d/HoleOverlay2D.tsx`
- 引入多坐标候选择优(原始坐标/模型矩阵/板件矩阵),并收紧阈值,减少孔位偏移。
4. `src/components/ui/ContextMenu.tsx`
- `ContextMenuItem` 增加缩略图与预览图字段。
- 子菜单支持材质小图和悬停大图气泡。
5. `src/app/products/[id]/assembly/AssemblyEditorWorkspace.tsx`
- 恢复右键三级材质菜单(材质、复制/粘贴、UV ±90°、材质分类、具体材质项)。
- 爆炸滑块改为 UI 值和渲染值分离,渲染值通过 `requestAnimationFrame` 合帧提交。
- 关键文案统一中文化(孔位高亮、板材折角线、爆炸程度、菜单标题)。
## 2026-02-23 二次回归补丁
1. `src/components/ui/ContextMenu.tsx`
- 右键菜单改为 `createPortal` 渲染到 `document.body`,修复父级 transform 场景下菜单偏移。
2. `src/app/products/[id]/assembly/AssemblyEditorWorkspace.tsx`
- `showPanelLeaders` 改为跟随 `showFoldLines`,修复板材折角线开关无效。
3. `src/components/3d/HoleOverlay2D.tsx`
- 对有 `panelId` 的孔位优先面板解算,失败不再回落到宽松模型兜底,避免孔位聚集到底部错位。
- 吸附仅在近距离候选启用,并将 `transformVersion` 量化到 30fps,缓解拖动爆炸滑块卡顿。
4. `src/lib/3d/engine.ts`
- 爆炸进度增加小幅变化跳过与最近进度缓存,减少高频重复重算。
5. `src/lib/3d/engine-highlight-resources.ts`
- 近白灰化逻辑扩展到通用颜色材质,修复白膜材质仍偏白的回归场景。
## 验证
- `npm run type-check -- --pretty false` 通过
- `npm test -- tests/api/auth-me.test.ts --runInBand` 通过
- `npm test -- tests/lib/zip-parser.test.ts --runInBand` 通过
- `npm test -- tests/services/sku-upload.service.test.ts --runInBand` 通过
- `npm test -- tests/lib/engine-events.test.ts --runInBand` 通过
## 预防策略
- 装配页交互变更必须按“拾取 -> 菜单 -> 覆盖层 -> 性能”四段链路回归。
- 右键菜单能力作为固定清单项(层级、复制粘贴、UV、缩略图、悬停预览)纳入 UI 回归检查。
- 爆炸滑块与孔位覆盖层同时变更时,强制检查拖动帧率和孔位贴合度,避免单点优化引入联动退化。

View File

@ -1,47 +0,0 @@
# 安装顺序后端编排收口(2026-02-26)
## 问题
- 前端执行“保存安装顺序 -> 生成步骤 -> 再拉取步骤”三段串行请求。
- 业务编排落在前端,不符合 `API -> Service -> Repository` 分层。
- 生成失败时存在“安装顺序已落库、步骤未生成”的部分成功风险。
## 根因
1. 缺少后端单接口编排能力,前端不得不串行调用多个接口。
2. 安装顺序更新与步骤生成在服务层没有补偿策略。
3. 路由层仅做最小校验,缺少输入上限防护。
## 方案
1. 新增接口:`POST /api/products/[id]/assembly/generate-from-order`。
2. Route 仅做参数校验(含重复 `panelId/order`)与统一响应处理。
3. Service 新增 `saveInstallOrderAndGenerateStepsForUser`:
- 先保存安装顺序;
- 再生成步骤(`save=true`);
- 返回最新步骤列表供前端直接渲染。
4. 失败补偿:
- 保存前快照原安装顺序;
- 生成失败时回滚安装顺序,避免半成功状态。
5. 风险收口:
- Route 增加 `panels` 数量上限;
- Service 同步增加数量上限,防止多入口规则漂移;
- 请求体增加 `content-length` 防护上限。
## 改动文件
- `src/app/api/products/[id]/assembly/generate-from-order/route.ts`
- `src/server/services/assembly.service.ts`
- `src/server/repositories/panel.repository.ts`
- `src/app/products/[id]/assembly/AssemblyEditorWorkspace.tsx`
## 验证
- `npx eslint src/server/services/assembly.service.ts src/server/repositories/panel.repository.ts src/app/api/products/[id]/assembly/generate-from-order/route.ts src/app/products/[id]/assembly/AssemblyEditorWorkspace.tsx` 通过
- `npm run type-check -- --pretty false` 通过
- `npm test -- tests/lib/install-order-rules.test.ts --runInBand` 通过(41/41)
## 剩余事项
- 仍需真实联调验证 `warnings` 展示策略。
- 建议后续补充接口限频与幂等键,进一步降低重复写放大。

View File

@ -1,36 +0,0 @@
# 安装顺序编辑器同步与规范收口(2026-02-26)
## 问题现象
- 装配编辑器切换“安装顺序模式/普通模式”后,步骤编辑器显示状态偶发不同步。
- 右侧安装顺序操作区使用原生按钮,且有硬编码颜色,不符合项目 UI 元组件与设计 token 规范。
## 根因分析
1. `AssemblyStepEditor` 内部维护本地 `steps` 与 `selectedStepId`,但仅在初次挂载时初始化。
2. 之前依赖父组件传 `key` 强制重挂载做同步,导致每次步骤变化都触发整体重建,性能与交互稳定性差。
3. 安装顺序操作区未统一使用 `@/components/ui/Button`。
## 修复方案
1. **去除强制重挂载**:移除 `AssemblyEditorWorkspace` 中 `stepEditorSyncKey` 与 `key` 方案。
2. **改为受控同步**:在 `AssemblyStepEditor` 内新增 `useEffect` 监听 `initialSteps`,同步本地步骤、选中项与高亮状态。
3. **组件规范收口**:安装顺序操作按钮统一改为 `Button` 元组件。
4. **视觉规范收口**:本轮改动范围内的安装顺序提示色改为语义类(`text-apple-blue`/`text-apple-red`),步骤编辑器局部颜色改为 `apple-*` token。
5. **复用元组件**:步骤详情中的部件勾选改为 `Checkbox` 元组件。
## 影响范围
- `src/app/products/[id]/assembly/AssemblyEditorWorkspace.tsx`
- `src/components/assembly/AssemblyStepEditor.tsx`
## 验证记录
- `npm run lint -- src/components/assembly/AssemblyStepEditor.tsx src/app/products/[id]/assembly/AssemblyEditorWorkspace.tsx` 通过
- `npm run type-check -- --pretty false` 通过
- `npm test -- tests/lib/install-order-rules.test.ts --runInBand` 通过(41/41)
## 复用建议
- 当组件需要“外部数据刷新 + 内部编辑态并存”时,优先使用 **受控同步 + 保留选中状态**,不要用 `key` 重挂载兜底。
- UI 收口优先检查:原生控件、硬编码颜色、交互状态(disabled/loading)是否已落在元组件能力内。

View File

@ -1,46 +0,0 @@
---
title: 协作者关系表与 lib 数据源注入收口
date: 2026-02-15
module: product-collaboration-and-lib-layering
problem_type: workflow_issue
severity: high
symptoms:
- Product 协作者依赖 JSON 字段,查询和交接链路存在全表扫描与类型不稳定
- lib 层直接访问数据库,绕过 Service -> Repository 分层
root_cause: 数据访问边界未统一,历史兼容字段与新能力叠加后缺少关系化模型与运行时注入层
resolution_type: code_fix
status: active
confidence: high
tags: [product-collaborator, repository-layering, datasource-injection, architecture]
related_patterns: []
---
## 现象与影响
- `Product.collaborators` 采用 JSON 存储协作者,导致筛选和交接只能依赖应用层逻辑,缺少数据库级约束。
- `src/lib` 多个模块直接读写 Prisma,API/Service 分层难以维持,后续审计与复用成本高。
## 排查路径
1. 先用 `npm run type-check -- --pretty false` 固定错误集合,确认问题集中在协作者链路和 3D/装配链路重构中间态。
2. 对 `product.repository`、`handover.repository`、`product-collaborator.service` 做调用链回溯,确认 JSON 与关系表并存阶段缺少统一读取策略。
3. 对 `src/lib/assembly-generator.ts`、`src/lib/hardware-matcher.ts`、`src/lib/permissions.ts` 做依赖扫描,定位直连 Prisma 的边界点。
## 根因分析
- 协作者数据模型长期停留在 JSON,缺少 FK 和索引,导致权限、交接、查询无法在 Repository 层稳定下沉。
- lib 层承担了运行时数据访问职责,破坏了“lib 纯算法、server 负责 IO”边界,拆分后容易出现类型和注入断层。
## 最终修复
- 新增 `ProductCollaborator` 关系表并建立索引/FK,新增迁移 `20260215093000_add_product_collaborator_relation`,并在迁移中回填历史 JSON 数据。
- Repository/Service 改为优先读写关系表,同时保留 JSON 镜像同步,保障存量接口兼容。
- `assembly-generator`、`hardware-matcher` 改为 data source 注入和 server runtime 封装;`permissions` 通过 repository 读取权限上下文,移除 lib 直连 Prisma。
## 预防策略
- 新增跨层守护检查:lib 模块默认禁止 `@/lib/prisma` 依赖,统一走 runtime/service 注入。
- 协作者相关新需求默认只增量扩展关系表,JSON 仅作为兼容镜像,避免再次回到“应用层全扫”。
- 验证命令固定为:
- `npm run prisma:generate`
- `npm run type-check -- --pretty false`

View File

@ -1,50 +0,0 @@
---
title: Controller 过载拆分与批处理事务收口
date: 2026-02-15
module: api/products/upload + api/users/[id]/handover + auth/share/panel services
problem_type: workflow_issue
severity: high
symptoms:
- Route 文件承担解析、存储、事务、日志等多重职责
- Service 直连 Prisma,分层边界失效
- 离职交接单事务内长循环,存在锁等待风险
root_cause: Controller 与 Service 职责未按分层规范收口,数据访问逻辑散落在业务层
resolution_type: code_fix
status: active
confidence: high
tags: [route-layering, service-repository, batch-processing, transaction-scope]
related_patterns:
- WF-SVC-REPO-USER-001
- WF-PANEL-ROUTE-SVC-001
---
## 1) 现象与影响
- `/api/products/upload` 既做鉴权又做文件转换、上传、解析与事务写入,Route 过载。
- `/api/users/[id]/handover` 在 Route 内执行多段查询、循环更新、日志落库,难以维护且不利于并发稳定性。
- `auth/share/panel` 的 Service 存在直连 Prisma,导致分层审计无法闭环。
## 2) 排查路径
1. 先定位台账中同类问题(ARCH-009/013/015/017/DB-004)。
2. 用 `type-check` 兜底验证改造后类型边界。
3. 用认证和安全回归测试确认关键链路未回归。
## 3) 根因分析
- Route 层未被限制为“参数+鉴权+统一返回”,业务编排和数据细节长期堆积。
- Service 缺少配套 Repository 原子方法,导致为求开发速度直接写 Prisma。
- 交接链路追求“全成功事务”,把多项循环更新捆成单大事务,放大锁持有时间。
## 4) 最终修复
- 上传链路:新增 `product-upload.service + product-upload.repository`,Route 仅保留入口职责。
- 离职交接:新增 `user-handover.service + handover.repository`,采用分批提交与短事务策略。
- 认证/分享/板件:新增或扩展 `auth/share/panel` Repository 原子方法,Service 仅做权限和编排。
- 产品服务:将软删/恢复/CAD 创建事务下沉到 `product.repository`,减少业务层数据细节泄漏。
## 5) 预防策略
- 新增 API 一律先定义 Service/Repository 边界,再写 Route。
- 对“循环更新 + 事务”场景默认评估分批策略,避免单长事务。
- 复核清单加入“Service 是否仍引用 Prisma”自动检索项。

View File

@ -1,36 +0,0 @@
---
title: DWG 异步任务生命周期清理模式
date: 2026-02-15
module: dwg-converter
problem_type: workflow_issue
severity: high
symptoms:
- activeTasks 持续增长
- temp/uploads 原始文件长期残留
root_cause: 异步任务缺少完成态回收机制(内存与磁盘)
resolution_type: code_fix
status: active
confidence: high
tags: [memory, cleanup, async-task, dwg]
related_patterns: []
---
## 现象与影响
DWG 异步转换完成后未清理任务状态和输入文件,服务长期运行后会出现内存与磁盘增长。
## 修复动作
1. `src/lib/dwg/converter.ts` 增加 `scheduleTaskCleanup`,完成后延迟移除 `activeTasks`。
2. 增加 `cleanupInputFile`,在成功/失败的 `finally` 阶段统一删除输入文件。
3. 异常兜底分支也执行相同清理逻辑。
## 验证
- `npm run type-check -- --pretty false` 通过
- `npm test -- tests/api/auth-me.test.ts --runInBand` 通过
## 预防策略
- 异步任务必须明确“创建 -> 执行 -> 完成 -> 回收”生命周期,避免状态和文件双泄漏。

View File

@ -1,39 +0,0 @@
---
title: Hole Route 去 Repository 直连并收口到 Service
date: 2026-02-15
module: holes-route
problem_type: workflow_issue
severity: high
symptoms:
- /api/holes Route 直接调用 holeRepository/panelRepository 承担筛选、数量校验、删除编排
- Route 过重,分层边界不清晰,权限与删除策略散落在接口层
root_cause: 历史实现为了快速交付在 Route 层叠加了数据访问与业务编排
resolution_type: code_fix
status: active
confidence: high
tags: [architecture, route-layer, service-layer, holes]
related_patterns: [SEC-HOLE-PERM-001]
---
## 现象与影响
`/api/holes` 同时承担参数解析、数据访问、业务编排,导致:
- 违反 `Route -> Service -> Repository` 分层约束。
- 相同规则(筛选、删除限额、权限)难以复用,后续接口容易漂移。
## 修复动作
1. `src/app/api/holes/route.ts` 移除 `holeRepository/panelRepository` 直连。
2. 新增 `holeService.listByFilter` 与 `holeService.deleteByFilter`,将筛选、权限、数量校验与删除编排统一下沉到 Service。
3. Route 仅保留参数解析、输入校验与统一响应封装。
## 验证
- `npm run type-check -- --pretty false` 通过
- `npm test -- tests/lib/cad-panel-linking.test.ts --runInBand` 通过
## 预防策略
- 新增 API 时先定义 Service 方法,再编写 Route;Route 不允许直接引入 Repository。
- Code Review 对 Route 层增加规则:若出现 `*Repository` 依赖需给出例外说明,否则驳回。

View File

@ -1,36 +0,0 @@
---
title: 产品板件路由权限收口到 Service
date: 2026-02-15
module: panel-route
problem_type: workflow_issue
severity: high
symptoms:
- Route 与 Service 同时维护产品权限判断
- Route 直连 Prisma,权限策略容易漂移
root_cause: 分层迁移不彻底,Controller 仍承担数据访问与业务判断
resolution_type: code_fix
status: active
confidence: high
tags: [architecture, route-service, panel]
related_patterns: [WF-HOLE-ROUTE-SERVICE-001]
---
## 现象与影响
`products/[id]/panels` 在 Route 层重复做查询和权限,Service 也有权限逻辑,导致规则双轨并行。
## 修复动作
1. `src/app/api/products/[id]/panels/route.ts` 移除 Prisma 和 `canView/canEdit` 分支。
2. `src/server/services/panel.service.ts` 的 `findByProductId` 接入权限校验(`ctx.user` 存在时执行 `canViewProduct`)。
3. Route 仅保留参数解析、调用 Service 与统一响应。
## 验证
- `npm run type-check -- --pretty false` 通过
- `npm test -- tests/api/auth-me.test.ts --runInBand` 通过
## 预防策略
- Route 层只做入口编排;权限与业务判断统一放在 Service 层,避免策略漂移。

View File

@ -1,40 +0,0 @@
---
title: Product Hardware Route 分层收口到 Service/Repository
date: 2026-02-15
module: product-hardware-route
problem_type: workflow_issue
severity: high
symptoms:
- /api/product-hardware/[id] Route 直接操作 Prisma
- Route 叠加参数解析、权限判断、数据访问与更新逻辑
root_cause: 历史实现未遵循 Route -> Service -> Repository 分层约束
resolution_type: code_fix
status: active
confidence: high
tags: [architecture, layering, route, service, repository, product-hardware]
related_patterns: [SEC-PRODHW-PERM-001]
---
## 现象与影响
Route 层直接写 Prisma 会导致:
- 权限逻辑散落,重复实现容易漂移。
- 业务规则不可复用,后续接口扩展成本高。
- 架构审查难以确认边界是否一致。
## 修复动作
1. 新增 `product-hardware.repository.ts` 统一承接 ProductHardware 的查询/更新。
2. 新增 `product-hardware.service.ts` 统一承接权限校验、业务校验与编排。
3. `src/app/api/product-hardware/[id]/route.ts` 仅保留参数校验和统一响应,不再直连 Prisma。
## 验证
- `npm run type-check -- --pretty false` 通过
- `npm test -- tests/lib/cad-panel-linking.test.ts --runInBand` 通过
## 预防策略
- Route 文件出现 `prisma.` 直接访问时,默认判定为架构违规。
- 新接口先设计 Service 方法和 Repository 原子方法,再接入 Route。

View File

@ -1,65 +0,0 @@
---
title: User Service 直连 Prisma 导致分层失效
date: 2026-02-15
module: user-service
problem_type: workflow_issue
severity: high
symptoms:
- user.service.ts 中直接调用 prisma.user/prisma.department/prisma.team
- Service 层同时承担数据访问与业务编排,破坏企业分层边界
root_cause: 历史实现未统一收口到 Repository 层
resolution_type: code_fix
status: active
confidence: high
tags: [architecture, service-layer, repository-layer, user-service]
related_patterns: []
---
## 现象与影响
用户服务在列表、详情、创建、更新、删除、登录校验等场景直接访问 Prisma,导致:
- Service 层和 Repository 层职责重叠,后续治理难度上升。
- 权限/规则与数据查询耦合,复用困难。
- 审查时难以快速确认“Route -> Service -> Repository”是否被遵守。
## 排查路径
1. 在 `src/server/services/user.service.ts` 全量搜索 `prisma.`。
2. 将命中的查询按“读/写/校验”分类,映射到应由 Repository 承担的方法。
3. 检查 `src/server/repositories/user.repository.ts` 现有能力是否可复用,不足则补充原子方法。
## 根因分析
用户模块早期实现以功能闭环优先,缺少统一分层约束落地,随着功能堆叠形成了 Service 直连数据库的路径依赖。
## 最终修复
### 代码改动
- 重写 `src/server/services/user.service.ts`,移除全部 Prisma 直连,Service 仅保留:
- 输入校验
- 业务规则判定
- 调用 Repository 编排
- 扩展 `src/server/repositories/user.repository.ts`:
- `findByEmailWithRelations`
- `findByNameWithRelations`
- `createWithScalars`
- `updateWithScalars`
- `departmentIds` 过滤支持
### 验证命令
- `npm run type-check -- --pretty false`(通过)
- `npm test -- tests/api/auth-me.test.ts --runInBand`(通过)
## 预防策略
- 新增 Service 逻辑时,先在 Repository 层补齐原子数据方法,再编写 Service 编排。
- Code Review 增加硬性检查:Service 文件若出现 `prisma.` 直接判为架构违规。
- 对已存在的 Service 分批治理,优先处理 P0/P1 的权限与数据一致性链路。
## 剪枝与冲突检查
- 本次未发现可直接剪枝的旧模式(首次沉淀该类模式)。
- 本次未发现同触发条件下的冲突模式。

View File

@ -1,37 +0,0 @@
# UI 大文件拆分为工作区模块(批量案例)
- 日期:2026-02-16
- 适用范围:前端超大组件(页面/3D 编辑器/弹窗)因“壳文件转发”被审查驳回,需做实质拆分。
## 问题特征
1. 单文件超过 500~800 行,状态、请求、渲染全部混在一起。
2. 之前只做了 `*.container.tsx -> *.workspace.tsx` 的壳层迁移,审查仍判定为未拆分。
3. 复核关注点不是“文件名变化”,而是“职责分层是否可见”。
## 解决方案(本次落地)
1. 先补齐可编译基线,避免在红灯状态做结构重构。
2. 按“容器编排 + 业务 hooks + 视图区块组件”拆分:
- Assembly:`hooks/useAssemblyEditorState.ts` + 顶栏/预览/步骤面板组件。
- Home:`home/hooks/*` + `home/components/HomeModelsSection.tsx`。
- ProductDetail:顶部栏、信息卡、创建分享弹窗拆成独立组件。
- SKUDetail:顶部动作区、只读侧栏、规格切换抽屉拆分。
- HoleViewer:渲染层 hook + 控制层 hook + 图例统计组件。
- AddSKUModal:schema + submit hook + 字段分组组件。
- HoleEditor:types + validation + interaction hook。
3. 每个拆分点都保持原有行为不变,Workspace 只做组装。
## 验证方式
1. `npm run type-check -- --pretty false`
2. `npm test -- tests/api/auth-me.test.ts --runInBand`
3. `npm test -- tests/lib/zip-parser.test.ts --runInBand`
4. `npm test -- tests/services/sku-upload.service.test.ts --runInBand`
## 复用清单
1. 先找“状态管理块”和“大段 JSX 区块”,优先抽这两类。
2. hooks 命名按能力域(`use-xxx`),组件命名按区域(TopBar/Sidebar/Modal)。
3. 重构后保留统一入口(container/workspace),避免页面导入路径抖动。
4. 台账同步标注“已修复待复核”,并写清新增模块文件路径。

View File

@ -1,39 +0,0 @@
---
title: UI 令牌收敛与按需渲染优化
date: 2026-02-15
module: ui-foundation
problem_type: workflow_issue
severity: medium
symptoms:
- 元组件存在硬编码色值与固定过渡时长
- 无可视标注场景仍持续 requestAnimationFrame 循环
- explodeFactor 变化触发模型重复加载
root_cause: 动画/样式令牌与渲染生命周期缺少统一约束
resolution_type: code_fix
status: active
confidence: high
tags: [ui, token, animation, raf, performance]
related_patterns: []
---
## 现象与影响
样式令牌不统一会导致视觉漂移;无效渲染循环和重复模型加载会产生不必要的 CPU/GPU 开销与卡顿。
## 修复动作
1. `Button/Input/Select` 统一过渡令牌,移除硬编码十六进制色值。
2. `HoleOverlay2D` 在无标注时停止 RAF,仅保留一次清屏。
3. `ExplodedViewSelector` 将 `explodeFactor` 与模型加载解耦,改为仅更新已加载 mesh 位移。
4. 材质缩略图兜底 SVG 接入语义色令牌并保持统一主题。
## 验证
- `npm run type-check -- --pretty false` 通过
- `npm test -- tests/lib/cad-panel-linking.test.ts --runInBand` 通过
## 预防策略
- 元组件层禁止硬编码主题色和动效参数,统一走 design tokens。
- 任何渲染循环都要有“空数据停机”策略,避免无意义帧消耗。

View File

@ -1,141 +0,0 @@
# 主线同步操作手册
适用对象:会用 Codex 协作、但不一定熟悉 Git 的同事。
目标:当 `main` 持续更新时,你仍然能把自己的分支保持在最新状态,不把代码做旧,不把冲突拖到最后一天。
---
## 1. 先记住一句话
你不要直接改 `main`。
你只在自己的分支里开发,然后经常把最新的 `main` 同步进来。
当前推荐分工:
- `WuYongJie` 负责主线 `main`
- 你负责自己的功能分支,例如 `codex/xuxiake-dev`
---
## 2. 你每天就做这 3 件事
### 开工前
先同步一次最新主线。
### 主负责人刚推了重要改动后
再同步一次,不要继续拿旧代码往下写。
### 你准备提交前
最后再同步一次,避免你推上去的分支已经落后很多。
---
## 3. 默认操作步骤
把下面这 5 行命令原样交给 Codex 执行就行:
```bash
git checkout main
git pull origin main
git checkout <你的分支名>
git rebase main
git push --force-with-lease origin <你的分支名>
```
示例:
```bash
git checkout main
git pull origin main
git checkout codex/xuxiake-dev
git rebase main
git push --force-with-lease origin codex/xuxiake-dev
```
这组命令的白话意思:
1. 先把本地 `main` 拉到最新
2. 切回你自己的分支
3. 把你的改动“搬到最新主线后面”
4. 再把你的分支推上去
---
## 4. 如果你不想用 `rebase`
可以先用更稳一点的版本:
```bash
git checkout main
git pull origin main
git checkout <你的分支名>
git merge main
git push origin <你的分支名>
```
它的特点:
- 好处:不容易把人绕晕
- 代价:提交记录会更乱一点
怎么选最简单:
- 这个分支只有你一个人在用,就优先用 `rebase`
- 你如果看不懂冲突,先用 `merge`
---
## 5. 什么时候说明你已经落后主线了
出现下面任意一种情况,就不要继续写了,先同步:
- 主负责人刚改了你也会碰到的模块
- Codex 提示分支落后
- 你打开页面后,发现和主线最新效果不一样
- 你准备提交,但已经隔了半天或一天没同步
---
## 6. 如果同步时出现冲突
不要慌,按这个顺序处理:
1. 先停下来,不要乱点保存
2. 看冲突文件是不是你这次本来就在改的模块
3. 如果不是你负责的模块,先问主负责人
4. 如果是你负责的模块,就保留你的目标改动,再把主线的新内容接进去
5. 处理完后再继续让 Codex 帮你完成 `rebase` 或 `merge`
可以直接把下面这段话发给 Codex:
```text
我在同步 main 到我的分支时遇到冲突了。
请只帮我处理这几个冲突文件,不要扩范围,不要改无关模块。
优先保留主线最新结构,再把我这个分支的目标改动接进去。
处理后请告诉我还需要执行什么命令。
```
---
## 7. 绝对不要这样做
- 不要直接在 `main` 上开发
- 不要长时间不同步主线
- 不要等“全部做完了”才第一次同步
- 不要看到冲突就随手全选自己的版本
- 不要在没看懂的情况下执行 `git reset --hard`
---
## 8. 给同事最短口令版
如果你懒得记,只记这一段:
```text
每天开工前,先把 main 拉最新,再把自己的分支 rebase 到 main 上。
如果不会 rebase,就先 merge main。
如果冲突了,不要硬处理,先让 Codex 只处理冲突文件。
```

View File

@ -1,149 +0,0 @@
# 任务单模板
这个模板既给人看,也给 Codex 看。
原则:不要只写“帮我改一下”,要把边界、目标和验收写明白。
---
## 1. 任务基本信息
- 任务名称:
- 所属模块:
- 负责人:
- 所在分支:
- 计划开始时间:
---
## 2. 这次要解决什么问题
用人话写:
- 当前现象:
- 希望变成什么样:
- 为什么现在必须做:
---
## 3. 本次只做什么
列 3 到 5 条最核心内容:
-
-
-
---
## 4. 本次明确不做什么
这个部分一定要写,不然 AI 和人都容易顺手扩范围:
-
-
-
---
## 5. 影响范围
### 页面 / 入口
-
### API
-
### 服务 / 仓库 / 数据表
-
### 文档
-
---
## 6. 验收标准
至少写到“看见什么算完成”:
- [ ]
- [ ]
- [ ]
---
## 7. 验证方式
把能跑的命令和要人工点的页面都写出来:
- 命令:
- `npm run type-check`
- `npm test -- --runTestsByPath <按需补>`
- `npm run build`
- 人工验证:
-
-
---
## 8. 禁止改动区
把这次不应该碰的目录直接写死:
-
-
-
---
## 9. 风险和依赖
- 风险:
- 依赖谁继续接:
- 是否需要后续补文档:
---
## 10. 直接发给 Codex 的提示词模板
```text
请在当前仓库处理下面这个任务。
任务名称:<任务名称>
所属模块:<模块名>
目标:<一句话说清楚>
本次只做:
1. <事项 1>
2. <事项 2>
3. <事项 3>
本次不做:
1. <事项 1>
2. <事项 2>
关键目录:
- <目录 1>
- <目录 2>
禁止改动:
- <目录或文件 1>
- <目录或文件 2>
验收标准:
1. <标准 1>
2. <标准 2>
3. <标准 3>
验证要求:
- 至少跑 `npm run type-check`
- 按需跑相关测试
- 能跑就跑 `npm run build`
需要同步更新的文档:
- <文档路径 1>
- <文档路径 2>
```

View File

@ -1,99 +0,0 @@
# 同事交接模板
适用对象:不一定是程序员,但会用 Codex 协作的人。
目标:让接手的人不用先读完整仓库,也能知道从哪里开始、哪里不能乱改。
---
## 1. 先把这 5 句话说清楚
- 这次要做的模块是什么
- 现在做到哪一步了
- 你接下来只需要做什么
- 哪些目录不能碰
- 做完后怎么验证
---
## 2. 交接卡片模板
```text
任务名称:<名称>
当前状态:<已完成到哪里>
你接手的部分:<只写这次要做的内容>
先看这几个文件:
- <文件 1>
- <文件 2>
- <文件 3>
不要改这些地方:
- <目录或文件 1>
- <目录或文件 2>
验收标准:
1. <标准 1>
2. <标准 2>
3. <标准 3>
验证方式:
- `npm run type-check`
- `npm test -- --runTestsByPath <补具体文件>`
- `npm run build`
- 人工打开:<页面路径>
```
---
## 3. 直接发给 Codex 的交接提示词
```text
请接手这个仓库里的一个局部任务,不要扩范围。
任务名称:<任务名称>
你现在只负责:<一句话>
当前背景:
<用 3 到 5 行说清楚现在已经做到哪一步>
先看这些文件:
- <文件 1>
- <文件 2>
- <文件 3>
禁止改动:
- <目录或文件 1>
- <目录或文件 2>
本次验收标准:
1. <标准 1>
2. <标准 2>
3. <标准 3>
验证要求:
- 至少跑 `npm run type-check`
- 按需跑相关测试
- 能跑就跑 `npm run build`
如果主线 `main` 最近有更新,请先同步主线再继续开发:
- `git checkout main`
- `git pull origin main`
- `git checkout <你的分支>`
- `git rebase main`
完成后请按下面格式回报:
1. 现在你要做什么
2. 是否完成
3. 还有没有风险
```
---
## 4. 交接时最容易漏掉的事
- 没说清楚这次只做什么
- 没说清楚哪些目录不能碰
- 没说清楚新平台主链和旧兼容链的边界
- 没写验证方式
- 没提醒对方先同步最新 `main`
- 没同步文档,导致下一个人继续靠猜

View File

@ -1,159 +0,0 @@
# 同事本地 AGENTS 使用说明
适用对象:在自己电脑上用 Codex 协作、但不想改动仓库共享规则的同事。
目标:让每个协作者都可以有自己的 AI 约束文档,同时不污染仓库里大家共用的 `AGENTS.md`。
---
## 1. 先说结论
可以有。
但不要直接去改仓库里已经提交的那份 `AGENTS.md`。
正确做法是:
- 仓库里的 `AGENTS.md` 继续保留为团队共享规则
- 你同事在自己电脑上,再单独放一份“本地工作区级”的 `AGENTS.md`
这样就能做到:
- 团队共用规则不乱
- 同事自己的 AI 还有额外约束
- 不会因为一人改规则,把所有人的 Codex 一起带偏
---
## 2. 为什么不能直接在仓库根目录再放一份
因为 `AGENTS.md` 是按目录生效的。
白话理解:
- 同一个目录层级,只能有一套这一级的规则
- 仓库根目录那份 `AGENTS.md`,本来就是给整个项目共用的
- 如果你同事直接把它改成自己的版本,就等于把团队共享规则一起改了
所以:
- 团队规则放仓库里
- 个人规则放自己电脑上的外层工作区
---
## 3. 最推荐的放法
让你同事在自己电脑上,为这个项目单独建一个外层工作区目录。
示意结构:
```text
<同事自己的工作区目录>/
├─ AGENTS.md
└─ furniture-3d-system/
├─ AGENTS.md
├─ src/
├─ docs/
└─ ...
```
这里的含义是:
- 外层 `AGENTS.md`:只约束你同事自己的 Codex
- 仓库里的 `AGENTS.md`:继续约束项目共享规则
Codex 会同时看到这两层规则。
这样最稳,也最适合团队协作。
---
## 4. 为什么这种方式最好
它同时解决了 3 个问题:
1. 不需要改仓库里的共享规则
2. 不需要让你同事长期带着一个“已修改但不敢提交”的根目录 `AGENTS.md`
3. 以后你同事换电脑、重装环境,也能直接复制这份本地规则继续用
---
## 5. 你同事具体怎么做
### 第一步:准备一个只给这个项目用的外层目录
目录名随便,但建议一看就知道是给这个项目单独准备的。
例如:
```text
<任意父目录>/furniture-3d-system-codex-workspace/
```
### 第二步:把仓库放到这个目录下面
结构变成:
```text
furniture-3d-system-codex-workspace/
├─ AGENTS.md
└─ furniture-3d-system/
```
### 第三步:把模板内容复制到外层的 `AGENTS.md`
模板见:`docs/workflow/同事本地AGENTS模板.md`
### 第四步:以后让 Codex 从这个外层工作区进入项目
这样它既能吃到团队规则,也能吃到你同事自己的规则。
---
## 6. 这份本地 AGENTS 应该写什么
建议只写“个人工作方式”和“模块边界”,不要重写项目真相。
适合放进去的内容:
- 默认用中文,面向非程序员表达
- 先看哪些文档
- 这位同事当前只负责哪些模块
- 哪些目录绝对不要碰
- 开工前先同步 `main`
- 结果汇报格式要简单
不适合放进去的内容:
- 项目数据库真相
- 会影响所有人的共享分层规则
- 和仓库主 `AGENTS.md` 相冲突的内容
---
## 7. 推荐边界
团队共享规则,继续放仓库根目录 `AGENTS.md`:
- 企业级架构要求
- 统一视觉标准
- 根因修复原则
- 项目主链与兼容链边界
同事本地规则,放自己工作区外层 `AGENTS.md`:
- 他当前只负责包装相关模块
- 先同步主线再开发
- 不扩范围
- 不擅自改主导航、自动组合、仓库主链
- 回报格式尽量简单
---
## 8. 最后给你的建议
最稳妥的团队做法就是下面这句:
```text
共享 AGENTS 放仓库里,个人 AGENTS 放各自电脑的外层工作区里。
```
这样以后你换同事、换模块、换机器,都不会乱。

View File

@ -1,111 +0,0 @@
# 同事本地 AGENTS 模板
使用方式:把下面内容复制到你同事自己电脑上的“项目外层工作区” `AGENTS.md` 中。
不要直接覆盖仓库里已经提交的那份 `AGENTS.md`。
---
```md
# AGENTS.md
适用范围:当前这个工作区下的 `furniture-3d-system` 项目。
## 1. 默认沟通方式
- 默认中文回复。
- 默认面向非程序员表达,先说结论,再说必要解释。
- 默认只说“现在你要做什么、是否完成、还有没有风险”。
## 2. 先做什么
开始任务前,先看下面这些文件:
- `docs/README.md`
- `docs/workflow/团队协作模式.md`
- `docs/workflow/模块边界说明.md`
- `docs/workflow/主线同步操作手册.md`
如果任务和包装有关,再看:
- `docs/workflow/同事交接模板.md`
## 3. 你的默认职责
你当前默认只负责包装相关模块,以及与包装对接的预留能力。
优先关注:
- `src/app/api/pre-skus/[id]/packaging`
- `src/app/api/products/[id]/packaging`
- `src/server/services/packaging.service.ts`
- `src/server/repositories/packaging.repository.ts`
- `src/server/services/draft-group.service.ts`
- `src/server/repositories/draft-group.repository.ts`
## 4. 默认不要改的地方
除非任务明确要求,否则不要主动改下面这些地方:
- `src/app/asset-center`
- `src/app/auto-combinations`
- `src/app/intake`
- `src/app/warehouse`
- `src/server/services/combination.service.ts`
- `src/server/services/intake.service.ts`
- `src/server/services/warehouse.service.ts`
- 旧 CAD 兼容链的大范围逻辑
## 5. 开发前的固定动作
- 开工前先同步最新 `main`
- 主负责人刚推了重要改动后,再同步一次
- 自己准备提交前,再同步一次
高频协作固定铁律见:
- `docs/workflow/高频协作五条铁律.md`
默认同步步骤:
```bash
git checkout main
git pull origin main
git checkout <你的分支名>
git rebase main
git push --force-with-lease origin <你的分支名>
```
如果不会处理 `rebase`,先改用:
```bash
git checkout main
git pull origin main
git checkout <你的分支名>
git merge main
git push origin <你的分支名>
```
## 6. 开发规则
- 先修根因,不做表面补丁。
- 不顺手扩范围,不把自己的任务做成整个项目大改。
- Route / Page 不直接写 Prisma 业务规则。
- 先复用现有实现,不重复造新结构。
- 遇到冲突或边界不清,先停下来说明,不要硬改。
- 主导航、主流程骨架、公共数据结构,不要擅自大改。
## 7. 前端与文档
- 涉及前端时,优先保持现有统一视觉,不要自己另起一套样式。
- 涉及文档时,优先写短、直白、可执行的内容。
- 不要在文档里写你自己电脑上的绝对路径。
## 8. 完成后默认回报格式
完成后默认按下面格式回报:
1. 现在你做了什么
2. 是否完成
3. 跑了什么验证
4. 还有没有风险或待确认项
```

View File

@ -1,296 +0,0 @@
# 团队协作模式
适用范围:`furniture-3d-system` 仓库。
目标:把当前项目从“单人连续开发”切换成“多人并行协作,但主链不打架”的模式。
---
## 1. 先记住一句话
这个仓库现在默认按下面这条主链协作:
`资产中心 -> 自动组合 -> 草稿组 -> 包装方案 -> 成品展示 -> 正式入库 -> 轻仓库`
旧的 `CAD -> 装配步骤` 链继续保留,但它是**历史兼容链**,不是新开品主链。
---
## 2. 当前推荐分工
### 平台主线负责人
负责新平台一期主链:
- 资产中心
- 自动组合
- 草稿组
- 正式入库
- 轻仓库
- 新平台公共导航与页面骨架
默认涉及目录:
- `src/app/asset-center`
- `src/app/auto-combinations`
- `src/app/draft-groups`
- `src/app/intake`
- `src/app/warehouse`
- `src/app/api/asset-center`
- `src/app/api/auto-combinations`
- `src/app/api/draft-groups`
- `src/app/api/intake`
- `src/app/api/warehouse`
- `src/components/platform`
- `src/lib/open-product`
- `src/lib/planning`
- `src/server/services/asset-center.service.ts`
- `src/server/services/combination.service.ts`
- `src/server/services/draft-group.service.ts`
- `src/server/services/intake.service.ts`
- `src/server/services/planning.service.ts`
- `src/server/services/warehouse.service.ts`
### 包装负责人
负责包装方案增强,以及未来对接新平台的包装结果。
默认涉及目录:
- `src/app/api/pre-skus/[id]/packaging`
- `src/app/api/products/[id]/packaging`
- `src/server/services/packaging.service.ts`
- `src/server/services/draft-group.service.ts`
- `src/server/repositories/packaging.repository.ts`
- `src/server/repositories/draft-group.repository.ts`
- `docs/开发指南/包装方案增强`
默认边界:
- 可以增强包装对象、包装结果、包装展示。
- 不直接改自动组合规则。
- 不直接改正式入库规则。
- 不把包装流程做成独立顶层系统入口。
### 兼容链负责人
负责旧产品详情、旧装配编辑器、CAD 导入链、板件/孔位/五金/装配步骤兼容维护。
默认涉及目录:
- `src/app/products/[id]`
- `src/app/products/[id]/assembly`
- `src/app/products/[id]/skus/[skuId]`
- `src/app/products/[id]/skus/[skuId]/assembly`
- `src/app/api/products/[id]/assembly`
- `src/app/api/products/[id]/panels`
- `src/app/api/products/[id]/holes`
- `src/app/api/products/[id]/import-hardware`
- `src/app/api/holes`
- `src/app/api/hardware`
- `src/components/assembly`
- `src/components/3d`
- `src/lib/assembly-generator.ts`
- `src/lib/panel-assembly-semantic.ts`
- `src/lib/sku-cad-data.ts`
- `src/server/services/assembly.service.ts`
- `src/server/services/panel.service.ts`
- `src/server/services/sku-cad-import.helper.ts`
默认边界:
- 只做兼容维护、语义接入、步骤生成和旧链体验修正。
- 不把旧产品详情页重新拉回成新平台主入口。
- 不在旧链里偷偷新增新平台业务真相。
---
## 3. 分支规则
### 主分支
- `main` 继续保持受保护状态,但当前只允许 `WuYongJie` 直接 push。
- 其他协作者默认不能直接 push `main`,只能走自己的功能分支。
- 这样做的目的不是放开主线,而是保证主负责人可以快速收口,同事不会误把半成品直接推上主线。
### 开发分支
统一使用:
- `codex/<负责人>-<模块>`
示例:
- `codex/wuyongjie-open-platform`
- `codex/xuxiake-packaging`
- `codex/team-cad-compat`
### 合并方式
- 主负责人可以直接在 `main` 收口、修主线、推主线。
- 其他协作者默认先推自己的功能分支。
- 同事的改动进入主线前,默认先由主负责人检查和收口。
- 没有过验收清单,不合并,不并线。
### 同事和主线怎么保持同步
当前项目默认采用这个口径:
- `WuYongJie` 负责持续更新 `main`
- 同事长期在自己的分支开发,例如 `codex/xuxiake-dev`
- 同事不能等做完了再一次性同步,而是要高频同步 `main`
默认同步时机:
- 每天开始开发前同步一次
- 主负责人刚推了重要改动后同步一次
- 自己准备提交前再同步一次
默认推荐方式:
- 个人协作分支优先使用 `rebase main`
- 如果同事暂时不熟悉 `rebase`,允许先用 `merge main`
- 但不要一边长期不同步,一边继续堆改动
同事日常同步固定步骤:
```bash
git checkout main
git pull origin main
git checkout <自己的分支>
git rebase main
git push --force-with-lease origin <自己的分支>
```
如果同事当前只想用更稳、更不容易出心理压力的方式,可以先用:
```bash
git checkout main
git pull origin main
git checkout <自己的分支>
git merge main
git push origin <自己的分支>
```
怎么选:
- 分支只有自己在用,用 `rebase`
- 分支已经多人共用,先用 `merge`
详细操作说明见:`docs/workflow/主线同步操作手册.md`
高频协作总规则见:`docs/workflow/高频协作五条铁律.md`
---
## 4. 每个任务都按这个流程走
1. 先建一张任务单。
2. 写清楚本次只做什么、不做什么、验收标准是什么。
3. 明确归属模块,不跨模块顺手乱改。
4. 开发前先读对应模块边界说明。
5. 改完后同步必要文档。
6. 跑最小验证。
7. 做一次规范自审,再推分支。
---
## 5. 人和 AI 都要遵守的几条硬规则
### 先修根因,不打补丁
- 影响 3D 拼装、命名、包装、BOM、安装步骤的数据,优先在数据源修。
- 不允许只在页面上压报错、绕校验。
### 不跨层
- Page / Route 不直接写 Prisma 业务逻辑。
- Route 负责收参、鉴权、返回。
- Service 负责业务规则。
- Repository 负责数据访问。
### 不混主链和兼容链
- 新平台主链的数据真相在 `AssetFamily / AssetVariant / DraftGroup / PreSku`。
- 旧 `Product / SKU / Panel / Hole / ProductHardware` 继续服务兼容链。
- 包装本期要能挂接 `PreSku`,但不直接跳过草稿组去造正式产品。
### 不破坏统一视觉
- 新平台页面优先复用 `src/components/platform`。
- 旧装配编辑器继续走现有视觉体系,不另起一套杂样式。
---
## 6. 本地目录管理规则
### 需要长期保留的
- 源码
- 迁移
- 测试
- 正式文档
- 确认要进仓库的设计稿或说明
### 默认视为本地产物的
- `.dev-*.log`
- `.qa-*.log`
- `.start-*.log`
- `.next-start-*.log`
- `dev-server.log`
- `.codex-logs/`
- `_logs/`
- `output/`
- `temp/`
- `public/uploads/`
### 推荐习惯
- 提交前先运行:`npm run clean:local`
- 然后再看:`git status --short`
---
## 7. 提交前最少要交代什么
- 这次改的是哪个模块
- 本次只做了什么
- 哪些地方明确没做
- 跑了哪些验证
- 有没有风险或依赖别人继续接
详细清单见:`docs/workflow/提测与验收清单.md`
---
## 8. 给 Codex 的一句话协作口径
如果要把任务转给 AI,建议在任务里直接写明:
- 当前目标
- 所属模块
- 禁止改动的目录
- 验收标准
- 需要同步更新的文档
模板见:`docs/workflow/任务单模板.md` 和 `docs/workflow/同事交接模板.md`
---
## 9. 团队共享 AGENTS 和个人 AGENTS 怎么分
当前默认规则:
- 仓库里的 `AGENTS.md` 是团队共享规则
- 个人额外规则不要直接改仓库根目录那份
- 谁要给自己的 Codex 加私有约束,就在自己电脑上的项目外层工作区再放一份本地 `AGENTS.md`
推荐说明:
- 共享规则:继续放仓库里,大家共用
- 个人规则:放各自机器上的外层工作区,不进仓库
对应说明和模板见:
- `docs/workflow/同事本地AGENTS使用说明.md`
- `docs/workflow/同事本地AGENTS模板.md`
- `docs/workflow/高频协作五条铁律.md`

View File

@ -1,108 +0,0 @@
# 提测与验收清单
目标:让“做完了”变成有证据,不靠感觉。
---
## 1. 提测前先过这 6 项
- [ ] 任务范围没有失控,没有顺手改无关模块
- [ ] 关键文档已同步
- [ ] 先跑过 `npm run clean:local`
- [ ] `git status --short` 里没有不该提交的日志、缓存、临时文件
- [ ] 改动文件和任务单一致
- [ ] 自己能用一句话说清根因和修复方式
---
## 2. 最小验证命令
### 默认必跑
```bash
npm run type-check
```
### 按需补跑
```bash
npm test -- --runTestsByPath <相关测试文件>
```
### 能跑就跑
```bash
npm run build
```
---
## 3. 页面 / 接口人工确认
至少确认与任务直接相关的入口:
- [ ] 对应页面能打开
- [ ] 关键按钮/表单/保存动作能走通
- [ ] 关键接口返回正常
- [ ] 没有把别的入口改坏
---
## 4. 文档确认
下面这些情况要同步文档:
- 改了模块边界
- 改了页面入口
- 改了 API 入参或返回
- 改了数据模型
- 改了交接方式
最少同步到:
- `docs/workflow/团队协作模式.md`
- `docs/workflow/模块边界说明.md`
- 对应模块的专项说明文档
---
## 5. 规范自审
这是自审,不是独立复审。
结论只能写:
- `passed`
- `passed with warnings`
- `rejected`
自审固定只看 3 件事:
- 架构有没有被破坏
- 视觉有没有跑偏
- 这次是不是根因修复
如果不通过,就不要推 `main` 合并链路。
---
## 6. 提测说明模板
```text
现在要做什么:
<一句话说明这次改动解决了什么问题>
是否完成:
<已完成 / 部分完成>
验证结果:
- type-check:<通过 / 未跑>
- test:<通过 / 未跑>
- build:<通过 / 未跑>
- 人工验证:<写页面和结果>
风险:
- <没有风险 / 写明确风险>
规范审查结论:
这是自审,不是独立复审;<passed / passed with warnings / rejected>
```

View File

@ -1,228 +0,0 @@
# 模块边界说明
目标:让人和 AI 在开工前先知道“哪里是新平台主链,哪里是旧兼容链,哪里不能乱碰”。
---
## 1. 页面与入口边界
### 新平台主链入口
- `/`:新平台首页导航
- `/asset-center`:资产中心
- `/auto-combinations`:自动组合
- `/draft-groups`:草稿组列表
- `/draft-groups/[id]`:草稿组详情
- `/intake`:正式入库
- `/warehouse`:轻仓库
### 旧兼容链入口
- `/products`
- `/products/[id]`
- `/products/[id]/assembly`
- `/products/[id]/skus/[skuId]`
- `/products/[id]/skus/[skuId]/assembly`
### 不要混的原则
- 新平台入口负责“规划、预览、入库前整理”。
- 旧兼容链负责“历史产品、CAD 导入、板件/孔位/五金/装配步骤”。
- 不要把旧产品详情页重新改成新平台首页。
---
## 2. 新平台主链边界
### 前端目录
- `src/app/page.tsx`
- `src/app/asset-center`
- `src/app/auto-combinations`
- `src/app/draft-groups`
- `src/app/intake`
- `src/app/warehouse`
- `src/components/platform`
### API 目录
- `src/app/api/asset-center`
- `src/app/api/auto-combinations`
- `src/app/api/draft-groups`
- `src/app/api/intake`
- `src/app/api/planning`
- `src/app/api/pre-skus`
- `src/app/api/series-templates`
- `src/app/api/warehouse`
### 服务与仓库
- `src/server/services/asset-center.service.ts`
- `src/server/services/combination.service.ts`
- `src/server/services/draft-group.service.ts`
- `src/server/services/intake.service.ts`
- `src/server/services/planning.service.ts`
- `src/server/services/series-template.service.ts`
- `src/server/services/warehouse.service.ts`
- `src/server/repositories/asset-center.repository.ts`
- `src/server/repositories/draft-group.repository.ts`
- `src/server/repositories/planning.repository.ts`
- `src/server/repositories/series-template.repository.ts`
- `src/server/repositories/warehouse.repository.ts`
### 纯规则与类型
- `src/lib/open-product`
- `src/lib/planning`
### 这里的业务真相是什么
- 资产族:`AssetFamily`
- 规格款:`AssetVariant`
- 草稿组:`DraftGroup`
- 准 SKU:`PreSku`
- 入库结果:正式 `Product / SKU`
### 不要做的事
- 不直接从自动组合跳过草稿组生成正式产品。
- 不把旧 `Product / SKU` 当作新平台组合阶段的数据真相。
- 不把包装做成绕过草稿组的独立系统。
---
## 3. 包装协作边界
### 当前包装入口分两条
- 新平台承接口:`src/app/api/pre-skus/[id]/packaging/route.ts`
- 旧正式产品口:`src/app/api/products/[id]/packaging`
### 主要服务
- `src/server/services/packaging.service.ts`
- `src/server/services/draft-group.service.ts`
- `src/server/repositories/packaging.repository.ts`
- `src/server/repositories/draft-group.repository.ts`
### 当前约定
- 包装结果最终按单个 `PreSku` 保存。
- 正式产品包装链保留,作为兼容与发布后使用。
- 工艺图组合本期只预留接口,不在主线里单独展开。
### 包装负责人不要乱碰的地方
- 自动组合生成规则
- 草稿组转正式 SKU 的规则
- 旧 CAD 的板件/孔位/五金推导链
---
## 4. 旧 CAD 兼容链边界
### 页面目录
- `src/app/products/[id]`
- `src/app/products/[id]/assembly`
- `src/app/products/[id]/skus/[skuId]`
- `src/app/products/[id]/skus/[skuId]/assembly`
- `src/components/assembly`
- `src/components/3d`
### API 目录
- `src/app/api/products/[id]/assembly`
- `src/app/api/products/[id]/panels`
- `src/app/api/products/[id]/holes`
- `src/app/api/products/[id]/import-hardware`
- `src/app/api/holes`
- `src/app/api/hardware`
- `src/app/api/product-hardware`
### 服务与库
- `src/server/services/assembly.service.ts`
- `src/server/services/panel.service.ts`
- `src/server/services/hole.service.ts`
- `src/server/services/hardware.service.ts`
- `src/server/services/sku-cad-import.helper.ts`
- `src/server/repositories/panel.repository.ts`
- `src/server/repositories/hole.repository.ts`
- `src/server/repositories/hardware.repository.ts`
- `src/server/repositories/product-hardware.repository.ts`
### 纯规则与共享链路
- `src/lib/assembly-generator.ts`
- `src/lib/panel-assembly-semantic.ts`
- `src/lib/sku-cad-data.ts`
- `src/lib/3d/engine.ts`
### 当前约定
- 装配语义是旧链增强能力,不是新平台主数据源。
- 旧链可以继续生成安装步骤和预览,但不要反向主导新平台资产模型。
---
## 5. 共享层边界
### 所有人都可能会碰到,但不要随手改
- `prisma/schema.prisma`
- `prisma/migrations`
- `src/server/services/index.ts`
- `src/server/repositories/index.ts`
- `src/app/layout.tsx`
- `src/app/api/platform/schemas.ts`
### 共享层规则
- 任何 Prisma 模型调整,都必须带迁移。
- 任何新接口,都要有明确输入输出 DTO。
- 任何跨模块字段变更,都要先同步文档,再改代码。
---
## 6. 看到这些情况要先停一下
- 一个任务同时改新平台主链和旧兼容链,但任务单里没写原因。
- Route 里开始直接写 Prisma 查询。
- 包装开始自己造一套 `Product / SKU`。
- 页面样式开始绕开 `src/components/platform` 和既有视觉标准。
- 改动影响命名、BOM、包装、安装步骤,但没说明数据来源。
---
## 7. 开工前最少要看什么
### 做新平台主链
先看:
- `docs/workflow/团队协作模式.md`
- `src/components/platform/platform-navigation.ts`
- `src/lib/open-product/types.ts`
- `src/server/services/planning.service.ts`
- `src/server/services/draft-group.service.ts`
### 做包装
先看:
- `docs/workflow/团队协作模式.md`
- `docs/开发指南/包装方案增强/包装方案增强-同事交接说明.md`
- `src/app/api/pre-skus/[id]/packaging/route.ts`
- `src/server/services/packaging.service.ts`
- `src/server/services/draft-group.service.ts`
### 做旧 CAD 兼容链
先看:
- `docs/solutions/workflow-issues/CAD插件装配语义导出改造说明-20260325.md`
- `src/app/products/[id]/assembly/AssemblyEditorWorkspace.tsx`
- `src/components/assembly/AssemblyEditorClient.tsx`
- `src/server/services/assembly.service.ts`
- `src/lib/assembly-generator.ts`

Some files were not shown because too many files have changed in this diff Show More