Files
OnebotCatalog/开发提示词-批量导出购物车.md

140 lines
13 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 开发提示词:批量导出"购物车"(清单式收集 → 一键打包下载,离线版+在线版两端一致)
> 用途:把本文件交给 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 格式