# 开发记录：NX 2506 批处理攻坚（2026-08-26 凌晨，接续用）

> 本文件是 2026-08-25/26 二期 NX 按需生成服务开发的全量记录与**接续入口**。
> 新对话先说：**"读一下 项目总览.md 和 OnebotCatalog\开发记录-NX2506批处理攻坚.md，继续开发欧霓博目录软件二期"**。

## 1. 项目背景速览

- 一期（参数化选型引擎）已上线：KC 系列试点，meta.json 加 `mode=parametric` + `modelCodeTemplate` + range 参数域；对拍门禁 2,628 编码；桌面 selftest 36/36、网页 e2e-parametric 16/16。
- 二期（NX 按需生成服务 A 版）：非标组合 → 网页/桌面点【在线生成数模】→ GenServer（轻量队列）→ NX 2506 批处理 worker 真实生成 → 输出留存 `output\<系列>\<型号>\`（检索先行复用）→ 按格式下载（全格式 zip / STEP / Parasolid / IGES / STL / **PRT**（用户新增需求，NX 原生参数化部件））。
- 用户新需求（2026-08-26 凌晨追加，**尚未实现 UI**）：生成后先回传 STEP 做 3D 预览，再选格式下载（目前是"生成→直接下载"，需改成"生成→预览→下载"两步）。

## 2. 已完成并验证的组件（可放心接续）

| 组件 | 文件 | 状态 |
|---|---|---|
| GenServer 轻量后端 | `src\GenServer\GenServer.cs`（csc 单独编译：`tools\build-genserver.ps1`，输出 `bin\GenServer.exe`） | ✅ 无 NX 联调全过：/gen、/gen-batch、/status（含 .prog 进度）、/file、/files（token 一次性）、/download（fmt 单格式）、/health、限流、CORS、匿名模式（apiKey 留空）、**行式键值任务文件**（journal 无 JSON 库）、worker-config.txt 自动生成 |
| NX worker journal | `sample-data\tools\worker_journal.vb` | ✅ **NX 2506 编译运行通过**：常驻轮询/认领/打开母模/改表达式/更新/写结果/心跳/循环，全管线机制验证过 |
| 母模配置 | `onebot-data\masters.json`（expressionMap/switchRules/exports 含 prt） | ✅ |
| 本地联调配置 | `genserver-local\genserver-config.json`（绝对路径，匿名）+ 启动时自动生成 worker-config.txt | ✅ |
| 网页端 | `web\config.js`（GEN_CONFIG.api）+ app.js（genApi/genSingle/批量打包联动/格式下拉含 PRT）+ index.html btnGenFmt | ✅ e2e-gen 8/8、参数化 16/16、购物车回归全过 |
| 桌面端 | MainWindow（_genApi/GenSingle/GenBatch/格式下拉/非标按钮升级）+ Cart.cs（Params/异步打包） | ✅ 编译通过、selftest 36/36；真实生成未在桌面实测 |
| 测试脚本 | `tools\e2e-parametric.js`、`tools\e2e-cart.js`、`tools\e2e-gen.js`（playwright-core 在 `C:\Users\ruigu\AppData\Local\Temp\nds3dtest\node_modules`，脚本已带绝对路径回退） | ✅ |

## 3. NX 2506 API 适配结论（已通过反射探针逐一验证，直接可用）

NX 2506 与老版本差异巨大，以下结论全部实测：

| 主题 | 2506 正确用法（老写法会失败） |
|---|---|
| 打开部件 | **`Parts.OpenBaseDisplay(path, status)`**——批处理下 OpenBase 打开后 `Parts.Work = NULL`（最大坑） |
| 关闭部件 | `Parts.CloseAll(CloseModified.CloseModified, Nothing)`——两参数（老版三参数） |
| 建表达式 | `Expressions.CreateExpression("Number", "bore=32")`（类型, "名=值"）；带单位 `CreateExpressionWithUnit("Number", "bore=32", mm)`；`mm = UnitCollection.FindObject("MilliMeter")` |
| 改表达式 | `ufs.Modl.EditExp("bore=50")`——只改已存在的（Deprecated 警告但可用）；不会自动创建 |
| 更新模型 | `ufs.Modl.Update()`——Session.CreateUpdate 已不存在 |
| STEP 导出 | `Session.DexManager.CreateStepCreator()`：ExportFrom(DisplayPart/ExistingPart)、ExportAs(Ap214)、OutputFile、InputFile、ColorAndLayers、Commit/Destroy |
| IGES 导出 | `Session.DexManager.CreateIgesCreator()`：ExportFrom、ExportModelData、OutputFile、Commit |
| Parasolid | `Session.DexManager.CreateParasolidExporter()`：ExportFrom(DisplayedPart)、ParasolidVersion(Current)、OutputFile、Commit |
| STL | `Session.DexManager.CreateStlCreator()`：OutputType(Binary)、ChordalTol、AdjacencyTol、AutoNormalGen、OutputFile、Commit（**无 ExportFrom/InputFile**） |
| PRT 导出 | `workPart.SaveAs(path)` ✅（已验证写入） |
| 建圆柱 | `ufs.Modl.CreateCyl1(FeatureSigns.Nullsign, origin, height, diam, direction, ByRef tag)`——六参数、dim 是表达式字符串 |
| Save | `part.Save(SaveComponents.True, CloseAfterSave.False)`（两参数，返回 PartSaveStatus） |
| journal 环境 | **无 System.Web.Script.Serialization**（任务文件用行式键值格式，由 GenServer 烘焙母模配置）；`Imports System.Collections.Generic` 必须显式加 |

## 4. 当前卡点（唯一未打通的一环）

**NX 2506 批处理模式（run_journal）下，翻译器导出全部输出空几何**：

- 交互式 NX 导出正常（用户真实导出 UCBM32.stp 等为证）
- 批处理下：STEP/IGES 产出 ~2-3KB 空文件（日志 "Total number of solids input: 0"）、Parasolid 抛 "Part has no valid export objects or all valid export objects are filtered out"、STL 连文件都不写
- 已排除：路径中文、只读属性、引用集（实体已加进 MODEL）、几何来源（UF 造的实体和导入的真 STEP 一样被拒）、模板问题
- worker 整体流程本身跑通（打开→改表达式→更新→写结果→心跳全部正常），仅导出几何这步为空

**已尝试过的路线**（都有对应诊断脚本在 `sample-data\tools\`）：probe-api*.vb（反射探针）、debug-save.vb、debug-export.vb、debug-export-all.vb、check-master.vb（查特征/实体/面数/表达式）、create-test-master.vb（UF 造仿真气缸母模）、add-expressions.vb、import-master.vb（STEP 导入构建母模——导入 WorkPart 成功但实体数=0）

## 4.5 根因重新定位（2026-08-27 重读全部诊断后）

**结论：不是翻译器 API 用错，而是母模本身是 0 实体废品 + 诊断脚本选了错误的导出模式。** 证据链：

1. `catalog-masters\KC\check-master.txt`：**特征数=1、实体数=0** —— 当前 `KC_master.prt` 是空壳。
2. `catalog-masters\KC\KC_imported.log`：`Total number of solids input: 0`、`Total 0` —— `import-master.vb` 导入 `src.step` 时源文件就没带进实体（源 STEP `夹爪_v2.0_1.stp` 的实体是 `manifold_solid_brep` 但导入结果为 0）。
3. `debug-export.vb` 用 `ExportFrom=ExistingPart + InputFile=masterPath` 读磁盘**未保存**的文件（实体还在内存里没写盘），双重叠加必然空。
4. **`worker_journal.vb` 的导出函数其实是对的**：`GenerateOne` 用 `OpenBaseDisplay`（批处理正确用法），`ExportStep214`/`ExportIges` 用 `ExportFrom=DisplayPart`（内存实体）、`ExportParasolid` 用 `DisplayedPart` —— 都是批处理下对内存工作部件的正确模式，**无需改翻译器 API**。

**修复 = 重建含实体的母模**，worker 不改：
- 验证脚本已就位：`sample-data\tools\rebuild-verify-master.vb`（UF CreateCyl1 造含实体母模 + 加入 MODEL 引用集 + Save，再分别用 DisplayPart / ExistingPart 双模式导出对比，证明「有实体就能导出」）。
- 一键启动：`catalog-masters\KC\_run_rebuild.bat`（或 `sample-data\tools\run-rebuild-verify.ps1`）；结果日志 `catalog-masters\KC\rebuild-verify-master.txt`，产物 `catalog-masters\KC\dbg_out\`。
- 真母模就位后同名替换 `catalog-masters\KC\KC_master.prt`，worker 直接可用。

## 4.6 最终结论：全链路已打通（2026-08-27 深夜实测）

**§4.5 的"母模 0 实体"是现象之一，但真根因更深一层**——六轮实测逐步排除后锁定：

1. 母模能造出真圆柱（`bodies=2`、`faces=3`、带 mm 单位、入 MODEL 引用集、save 成功）→ 排除"母模 0 实体"和"表达式单位"。
2. `Display=Work` 且 `Display.bodies=2` → 排除"批处理显示部件为空"。
3. `ExportSolidsAndSurfacesAs=Precise`（默认）、`ProcessHoldFlag=False` → 排除 flag。
4. **最硬证据**：`KC_imported.log` 里 STEP→UG **导入**含 `manifold_solid_brep:1` 的真实 STEP 也是 `Total solids input: 0` → 导入也空。

**真根因：NX 2506 的 ST-DEVELOPER 翻译器（第三方 STEP Tools "System Release v20"）在 `run_journal` 无 GUI 批处理会话里，导入导出都判 0 solid——与几何健康与否无关，是环境级限制。** 批处理内 `DexManager.CreateStepCreator/Commit` 是死路。

**正解：改用独立命令行翻译器**（不依赖 NX 会话、直接读写 .prt）：
- `step214ug.exe`（.prt→.step，双向）实测 `Total solids: 2`、`manifold_solid_brep: 2`、7KB
- `iges.exe`（.prt→.igs）实测 Face=6
- `ug_convert_part.exe`=仅单位转换、`ugtopv.exe`=JT 导出，均已排除

**worker 改造**（`sample-data\tools\worker_journal.vb`）：GenerateOne 改为 设表达式→Update→**Save 副本**→PRT SaveAs→CloseAll 释放句柄→**spawn 独立翻译器导出**；nxBin 从 worker-config.txt 读 + 自动探测（`C:\Program Files\Siemens\NX*\NXBIN`，覆盖 2506/2512）。Parasolid/STL 按用户要求砍掉（masters.json exports 只留 step/iges/prt）。

**全链路实测成功**：网页→GenServer→worker 消费任务 `job_3e788ae033a6`（KC0032-87），`.done` 显示 `OK=1 HIT=0 FILE=.stp/.igs/.prt`，STEP 日志 `Total solids input: 2`（非空壳）。**两天卡点彻底解决。**

**交付前剩余**：① 真母模替换（`catalog-masters\KC\KC_master.prt` 仍是仿真圆柱占位母模，待用户交互式建模真母模同名替换）；② 生成交互已改为"生成→网页内 3D 预览→选格式→下载"（GenServer 加 `/preview/{series}/{code}.stp` 端点），需重编译+重启 GenServer 生效；③ NX 2512 版本待实测。

## 5. 明天接续方案（二选一，预计 10-30 分钟）

**方案 A（首选）**：用户在交互式 NX 录制导出宏——
1. `工具 → 日记 → 录制` → `文件 → 导出 → STEP214`（任选一零件）→ 停止录制，保存 journal
2. 照录制的真实调用修正 worker 的 ExportStep214/ExportIges/ExportParasolid（大概率是某个未探测到的属性需要设置，如 ObjectTypes/SettingsFile 等）
3. 用用户的真母模（交互式建的、特征树完整）直接跑 worker

**方案 B**：用户把真母模（或任意带 bore/stroke 表达式的真实零件）放到 `catalog-masters\KC\KC_master.prt`，直接启动 worker 实测——真母模的特征树/引用集是交互式 NX 维护的，可能直接导出成功（批处理问题可能只影响程序化创建的几何）。

**实测启动命令**（本机）：
```powershell
# GenServer（已在跑; 若需重启）
Start-Process "$base\bin\GenServer.exe" -ArgumentList "$base\genserver-local\genserver-config.json" -WorkingDirectory "$base\genserver-local"
# worker（每席位一个; NX 空闲时跑）
Start-Process "C:\Program Files\Siemens\NX2506\NXBIN\run_journal.exe" -ArgumentList "$base\sample-data\tools\worker_journal.vb" -WorkingDirectory "$base\genserver-local"
# 触发测试
Invoke-RestMethod -Method Post -Uri "http://localhost:8899/gen" -Body '{"series":"KC","params":{"type":"00","bore":32,"stroke":87,"magnet":"","mount":""},"code":"KC0032-87"}' -ContentType "application/json"
```
**注意**：本机 worker 与用户交互式 NX 争 license 席位（批处理需独立席位）；停 worker 时**不要**按时间条件批量杀 ugraf（2026-08-26 凌晨误杀了用户会话，教训）。网页测试：`release\web_2026.08\config.js` 当前 api 指向 `http://localhost:8899`（正式部署默认空）。

## 6. 待办收尾清单

1. ~~格式选择（含 PRT）~~ ✅
2. ~~批处理翻译器导出~~ ✅ **已解决**（§4.6：正解=独立命令行翻译器 step214ug.exe/iges.exe，全链路实测通过，Parasolid/STL 已砍）
3. ~~生成后先 3D 预览再下载~~ ✅ 已实现（GenServer `/preview/{series}/{code}.stp` 端点 + 前端「生成→预览→选格式→下载」）
4. 全链路真实验证（网页点生成 → 用户 NX 打开导出文件核对）—— ⏳ 待真母模就位
5. 部署：netsh urlacl 授权、网页 config.js 填生产地址、桌面端 catalog.json genApi 字段 + 重建发布 —— ⏳
6. masters.json 表达式名按真母模核对（现用 bore/stroke/magOn/mountIdx 与 nx-batch-export.vb 一致）—— ⏳ 待真母模
7. ~~参数映射网页后台编辑~~ ✅（/admin「参数配置」tab）
8. ~~后台密码登录 + 模型管理（手动/定时清理）~~ ✅（/admin 三 tab）

**详细交接见 `docs\工作交接.md` 与 `docs\部署清单.md`。**

## 7. 本地环境当前状态（2026-08-28 更新）

- GenServer 已改为**密码登录**（adminKey 默认 `onebot888`），后台 `/admin` 三 tab：UG 配置 / 参数配置 / 模型管理
- `_start_all.bat` 一键启动（停旧→编译→启动 GenServer+worker→health 自检）；网页底部信息栏有状态圆球（绿=就绪/橙=等worker/红=故障）
- 配置以 **D 盘**为准（W 盘旧 TeamCenter 映射已废弃）
- **待真母模**：`catalog-masters\KC\KC_master.prt` 目前是仿真圆柱占位母模
- 母模：`catalog-masters\KC\KC_master.prt` 目前是"STEP 导入版"（实体数=0 的废品），真母模待用户提供/重建
- 测试夹具：`C:\Users\ruigu\AppData\Local\Temp\nds3dtest\`（playwright、gensrv* 测试目录）
