首次提交: OnebotCatalog 项目代码与文档(含 NX 按需生成服务二期、后台、一键启动)

This commit is contained in:
wangruiguo
2026-09-03 17:55:45 +08:00
commit fafa86d3a6
241 changed files with 78656 additions and 0 deletions

View File

@@ -0,0 +1,139 @@
# 开发提示词:批量导出"购物车"(清单式收集 → 一键打包下载,离线版+在线版两端一致)
> 用途:把本文件交给 AI 会话执行。完成后按"验收标准"逐条核对,结果回写 OnebotCatalog\项目总览.md进展记录 + 踩坑表 + 最后更新行)。
> 背景必读OnebotCatalog\项目总览.md、OnebotCatalog\src\App\MainWindow.cs桌面 4 标签页 + 参数面板下载区 + 参数表、OnebotCatalog\web\app.js / index.html / style.css网页 4 标签页、OnebotCatalog\开发提示词-窗口内3D-WebView2方案B.md提示词文体参照
## 一、角色与任务
你是资深 WPF/前端工程师,在既有项目 **OnebotCatalog**C# / .NET Framework 4.8 代码式 WPF + 纯静态网页版)上实现**淘宝式购物车批量导出**:用户浏览选型过程中把多个型号"加入清单"(跨系列、跨型号,选型流程完全不受干扰),随时打开清单**一键打包下载**zip 含全部 STEP + BOM 清单)。**两端功能、交互、文案完全一致**(项目已定规矩)。
## 二、需求定稿(语义先行,避免歧义)
1. **购物车 = 跨系列清单**:可加入不同系列的不同型号;同一型号重复加入 → 提示"已在清单中"(不清空、不加量、不跳转)。
2. **不影响选型(淘宝式,用户 2026-08-24 明确)**:加入清单是"旁路操作"——加入后当前选型状态、3D 视图、参数面板**完全不变**、不跳转、不清空。
- **购物车生命周期**:网页 = 浏览器会话内(**刷新浏览器才清空**);桌面 = 软件运行期间(重启软件才清空)。
- **切换系列 / 切换型号 / 切标签页 / 搜索跳转 / 平替跳转 / 参数表任何操作,一律不触碰购物车**——购物车状态对象与选型状态彻底解耦(两端 cart 独立于 sel/series 状态)。
3. **三处入口(两端一致)**
- 参数面板下载区新增【加入清单】按钮(与【下载 STEP】【下载 PDF】并排选型完成才显示
- 参数表每行行尾"+"小按钮(一键加该行,**不触发行双击/筛选**
- 顶部栏常驻【清单 (N)】按钮N=件数实时角标,点击打开清单面板
4. **清单面板**
- 桌面:独立非模态 WindowOwner=主窗口DataGrid 列表;网页:右侧滑出抽屉(遮罩点击关闭,不误触面板外按钮)
- 列:型号 | 系列 | 规格摘要 | 文件名 | 数量(可编辑≥1默认1) | 操作(删除)
- 底部按钮:【清空】【下载全部 (zip + BOM)】;面板标题与角标实时同步件数
- 数量语义定死:**zip 中每型号只打包一份 STEP**,数量只体现在 BOM.csv 的"数量"列(不做重复文件、不改文件名)
5. **一键打包(两端产物结构完全一致)**
- `ONEBOT_清单_<时间戳>.zip`:内含各型号 STEP文件名=型号编码,保留原后缀)+ `BOM.csv` + `清单.txt`(人类可读版 BOM
- `BOM.csv` 列:序号, 型号编码, 系列代码, 系列名, 数量, 参数摘要(键=值 分号分隔), STEP文件名**UTF-8 带 BOM**Excel 中文不乱码);字段含逗号/引号按 CSV 规范转义
6. **打包引擎**
- 桌面System.IO.Compression.ZipArchivenet48 内置,零新依赖)
- 网页:**JSZip**MIT 开源,~100KB 单文件,放 `web\libs\jszip.min.js`**需用户批准下载**,交付说明注明版本/来源/许可)——纯静态无后端,前端逐项 fetch 同源 STEP 二进制 → 内存打包 → `URL.createObjectURL` 触发下载
7. **整合旧功能**:桌面参数表多选 +【批量导出所选】改造为【加入清单】(勾选行批量加入,提示"已加入 N 项"),删除旧直接导出逻辑,统一走清单(避免两套批量路径);网页参数表本就无批量导出,直接加"+"。
## 三、两端统一文案表(开发时直接抄,保证一致)
| 场景 | 中文 | 英文 |
|---|---|---|
| 加入按钮 | 加入清单 | Add to Cart |
| 顶栏角标 | 清单 (N) | Cart (N) |
| 重复加入提示 | 该型号已在清单中 | Already in cart |
| 加入成功 | 已加入清单 (共 N 项) | Added to cart (N items) |
| 批量加入 | 已加入清单 N 项 | N items added to cart |
| 面板标题 | 我的清单 | My Cart |
| 数量列 | 数量 | Qty |
| 删除 | 删除 | Remove |
| 清空 | 清空 | Clear All |
| 下载全部 | 下载全部 (zip + BOM) | Download All (zip + BOM) |
| 打包中 | 打包中... | Packing... |
| 空清单 | 清单为空, 请先加入型号 | Cart is empty |
| 部分失败 | 打包完成, 但以下型号文件缺失: xxx | Packed, but missing: xxx |
## 四、现状速览(改动前先读)
- 桌面 `src\App\MainWindow.cs``TryUpdateSelection()`(已选型号后 `_btnDownload/_btnDownloadPdf` 显隐、`_curModelCode` 平替过滤);参数面板 actions 区2026-08-24 加的 `_btnDownload/_btnDownloadPdf` StackPanel`BuildGridTab``_grid` 多选 + `ExportSelected()` + 右键列头筛选 + 双击 `NavigateToModel`);顶栏 StackPanel `top`4 标签页索引0=3D/尺寸图, 1=参数表, 2=搜索, 3=平替对照
- 桌面 STEP 读取:`_pkg.ReadAsset(v.step)` / `OpcPackage.ExtractStepTo(v, path)`Variant 有 `@params` 字典、`modelCode``step`
- 网页 `web\app.js``selectSeries`(重置 sel/ranges/tableFilter——**不得动 cart**)、`updateSelection`(下载按钮显隐 + `v.step` 相对路径如 `step/UCBM32.stp`)、`renderTable`(行点击带入选型 + 2026-08-24 列筛选,行尾加"+"注意 stopPropagation
- 网页 STEP 位置:站点根 `step\` 目录(发布时从 .opc 解包fetch 相对路径即可
- 版本号规范:网页 index.html 引 `app.js?v=N``style.css?v=M`,每次发布 +1桌面改 .cs 后必跑 `sample-data\tools\fix-bom.ps1`
## 五、硬性约束(违反即返工)
1. 完全离线可用(两端);桌面编译环境无 .NET SDKcsc + `lib\` DLL `/reference`,新库须放 lib\
2. 两端交互/文案/输出格式一致(见文案表);桌面中英双语 `_lang.T(zh,en)`,网页 `t(zh,en)`
3. 不影响选型主流程(需求第 2 条——验收重点)
4. 不改数据管线、.opc 格式、发布六步结构
5. JSZip 必须经用户批准下载并在交付说明注明版本/来源/许可MIT
6. 编辑含中文 .cs/.ps1 后必须 fix-bom网页文件 UTF-8 无 BOM 即可
7. 客户版与开发版同一代码(`#if CUSTOMER_BUILD` 只控制维护入口);清单功能两版都有
## 六、实施步骤
### 桌面src\App
1. **新文件 `Cart.cs`**(命名空间 Ounibo.Catalog.App
`class CartItem { string ModelCode; string SeriesCode; string SeriesName; string StepPath; string ParamsSummary; int Qty = 1; }`
2. **状态**`List<CartItem> _cart``int CartCount => _cart.Sum(x => x.Qty)`(角标显示**件数=数量总和**还是行数——定死角标显示行数BOM 数量列体现 Qty简单不混淆
3. **加入清单**`AddToCart(Variant v, Series s)`——重复判断ModelCode 忽略大小写)→ 提示已存在;成功仅更新角标 + 状态栏,**严禁写 `_sel`**
4. **三处入口**:参数面板 actions 区【加入清单】(`TryUpdateSelection` 里随 `_btnDownload` 同显隐,点击用当前已解析的 variant参数表"+"列(`DataGridTemplateColumn` 内 Button`Click``e.Handled` 防止干扰行选择/双击/右键筛选);顶栏【清单 (N)】
5. **清单窗口** `CartWindow`:非模态 WindowOwner 主窗口DataGrid 列:型号/系列/规格/数量(可编辑绑定 Qty)/删除(按钮列);底部【清空】【下载全部 (zip + BOM)】窗口关闭不丢数据_cart 在主窗口)
6. **打包**SaveFileDialog默认名 `ONEBOT_清单_yyyyMMddHHmmss.zip`)→ ZipArchive遍历 `_pkg.ReadAsset(item.StepPath)``ModelCode+原扩展名`BOM.csv 与 清单.txt 用 UTF8Encoding(true);打包完成后 MessageBox 提示路径
7. **整合**`ExportSelected` 改为"选中行批量 AddToCart + 提示已加入 N 项"`_btnExport` 文案改【加入清单】
8. 文案走文案表 + 状态栏反馈
### 网页web\
1. **引入 JSZip**:下载官方最新稳定版 jszip.min.js → `web\libs\jszip.min.js`index.html `<script src="libs/jszip.min.js?v=1"></script>`;交付说明注明版本/来源/许可
2. **状态**`state.cart = []`(结构同 CartItemStepPath=相对路径)——**selectSeries/refreshOptions/renderTable/jumpToModel 全部不得触碰**
3. **三处入口**`updateSelection()` 里下载区显【加入清单】;`renderTable` 每行尾"+"`onclick``ev.stopPropagation()` 防触发行点击header 加【清单 (N)】角标按钮
4. **清单抽屉**:右侧 fixed 面板 + 半透明遮罩;行含数量 `<input type=number min=1>`、删除按钮;底部【清空】【下载全部 (zip + BOM)】;遮罩点击只关面板(面板内点击 `stopPropagation`
5. **打包**`new JSZip()` → 逐项 `await fetch(item.step)`(失败收集到 missing 列表**继续**)→ `zip.file(name, blob)``zip.file('BOM.csv', '' + csv)``zip.file('清单.txt', txt)``generateAsync({type:'blob'})` → createObjectURL + a[download] 触发;打包中按钮文案"打包中..."并禁用防连点missing 非空时提示"打包完成, 但以下型号文件缺失: xxx"
6. 文案走文案表;不调用 selectSeries/refreshOptions
### 发布与回归
1. 桌面fix-bom → build.ps1双版→ 冒烟 → `--selftest` 31 项不变
2. 网页index.html 版本号 +1 → 停 serve-web → publish.ps1 → 重启 serve-web
3. 交付说明JSZip 来源/版本/许可 + 两端截图对照
## 七、验收标准(逐条核对)
1. 两端:选型号 A → 加入清单 → **选型界面无任何变化**参数不清空、3D 不跳)→ 换系列选型号 B → 加入 → 角标 (2);再切回系列 A、切所有标签页、搜索/平替跳转、参数表双击/列筛选,**清单仍 (2) 内容不变**(网页仅刷新、桌面仅重启才清空)
2. 重复加入同型号 → 提示"已在清单中",件数不变
3. 参数表"+"与勾选批量加入正常,且**不干扰**行双击带入选型、右键列筛选、范围筛选
4. 清单面板:数量改 3 → 删除一项 → 清空 → 角标实时同步
5. 下载全部 → zip 含全部 STEP + BOM.csv + 清单.txtExcel 打开中文无乱码、列齐全;数量 3 的型号 zip 中仍只有一份文件、BOM 数量列=3两端产物结构一致
6. 网页打包中防连点断网桌面全流程可用STEP 缺失时跳过并明确提示缺失型号(不整体失败)
7. 自测 31 项不变;客户版发布目录运行正常
8. 两端文案完全一致(对照文案表,中英切换正确)
## 八、已知陷阱(本项目血泪 + 本功能专属)
| # | 陷阱 | 对策 |
|---|---|---|
| 1 | 中文文件/CSV 乱码 | BOM.csv 必须 UTF-8 BOM桌面 UTF8Encoding(true) / 网页 '' 前缀);.cs/.ps1 改完 fix-bom |
| 2 | GUI exe 用 `&` 启动不等待,$LASTEXITCODE 空 | Start-Process -Wait -PassThru核对 log 时间戳 |
| 3 | 发布目录被运行中程序锁 | 发布前停 serve-web 与运行中 exe红线 |
| 4 | zip 内重名冲突(跨系列存在同名型号) | 打包前校验,冲突加后缀 `_系列码`BOM 列同步注明 |
| 5 | 网页逐项 fetch 大 STEP 内存峰值 | 逐项 fetch 后立即 zip.fileJSZip 持有 blob不必先全存数组避免一次性 concat |
| 6 | 空串枚举参数摘要显示 | 摘要统一走 displayValue/显示名映射,空值显示"(无)" |
| 7 | 加入清单误写 `_sel/state.sel` 导致选型被重置 | AddToCart 只读 variantcode review 时重点查 |
| 8 | 桌面 DataGridTemplateColumn 按钮点击干扰行选择/双击 | 按钮 Click 中 `e.Handled = true`"+"按钮 `Focusable=false` 避免抢焦点 |
| 9 | 网页"+"按钮事件冒泡触发整行 onclick带入选型 | `ev.stopPropagation()`;抽屉面板内所有点击同样处理 |
| 10 | 角标件数与 BOM 数量语义混淆 | 定死:角标=行数Qty 只在 BOM 体现(需求第 4 条) |
| 11 | 清单窗口关掉后数据丢失 | 购物车状态放主窗口/state面板只是视图 |
| 12 | 打包中用户再点加入/删除导致 zip 内容快照不一致 | 打包开始时先对清单做快照ToArray打包期间 UI 允许操作但只影响下一次下载 |
## 九、交付物
1. 两端可运行清单功能bin\ 开发版 + 发布目录客户版 + 网页站)
2. `web\libs\jszip.min.js`(注明版本/来源/许可 MIT
3. `src\App\Cart.cs` + MainWindow/网页改动(注释风格与现有一致)
4. 文档回写:项目总览(进展记录 + 踩坑 + 最后更新行)、维护手册、数据维护说明书(批量导出流程)
5. 本文件验收标准逐条核对结果
## 十、不做的事(范围外)
- 不做清单持久化(网页刷新/软件重启即清空;若要跨会话保留,用 localStorage/文件另立项)
- 不做价格/报价单/订单/账号对接BOM 只是清单文本)
- 不做网页服务端打包(保持纯静态)
- 不改选型核心逻辑、数据管线、.opc 格式