# 开发提示词：NX 按需生成服务（A 版：轻量自建队列 + run_journal）

> 交付对象：Claude Code。实现前请先通读本提示词 + 项目根 `项目总览.md` + `docs\维护手册.md` + `开发提示词-参数化选型引擎.md`（一期，本服务的前置依赖）。
> 实施命令以用户说"开工"为准；本文档只定义"做什么、边界在哪、怎么验收"。
> 部署红线：本服务属于云部署范畴，**服务器上线动作需用户另行明确指令**，开发与本地联调不在此列。

## 1. 背景与目标

一期（参数化选型引擎）上线后，选型面板可生成**非标准档位组合**（型号编码+参数行），但无对应 STEP。用户已决策：**不做批量预生成**；生成**按需触发**，输出**留存到服务器输出目录、不删除**，同组合再次请求直接复用（磁盘增长 = 实际请求过的唯一组合数，天然有界）。

**目标（A 版）**：搭建**按需生成服务**——用户在网页/桌面对非标组合点击【在线生成数模】，服务器现场用 NX 无界面模式生成，**输出到服务器输出目录并留存复用**。请求支持**单个与批量**两种形态，导出支持**多格式**：

- 标准档位：继续走纯静态文件路径，**不经过服务**（现有架构不动）
- 非标档位：下载按钮从"置灰"升级为【在线生成数模】→ 请求 → 队列 → NX 生成 → 输出目录 → 下载
- **单个生成**：结果行单组合 → 一个任务 → 一个型号的全格式文件
- **批量生成**：购物车打包时清单含非标条目 → 一次性提交全部非标组合 → 一个批量任务（单 worker 单会话顺序处理）→ 全部完成后打包下载
- **输出目录**：`output\<系列>\<型号编码>\`，每次生成写入全部格式文件；**已存在则该组合直接命中复用，不重复生成、不删除**
- **多格式导出**（每型号一套）：STEP(AP214) + Parasolid(.x_t) + IGES + STL；JT / 3D PDF 列为可选升级
- 不做：Teamcenter Dispatcher（B 版，跑顺后再评估）、主动预生成入库、账号体系

## 2. 前置依赖与边界

**前置依赖 = 一期参数化选型引擎已上线**（本服务消费一期产出）：
- meta.json 规则包（参数域/规则/型号编码模板）→ 服务端**二次校验**请求参数的依据
- 非标组合的概念与 UI 徽标、统一文案基础
- 注意衔接：一期验收标准里"非标下载置灰"是**过渡态**，本服务上线后按钮升级为【在线生成数模】，两端一致

**做**：GenServer（HttpListener 轻量后端）+ 文件队列 + 常驻 NX worker（循环 journal）+ 两端接入 + 输出目录留存复用 + 限流/日志 + 母模工作目录规范
**不做（v1 明确排除）**：TC 检出与版本追溯（升级项）、Part Families 标准化（升级项）、Dispatcher（B 版）、主动预生成入库、用户账号/支付；标准档位多格式化（升级项：维护端批量导出时顺手出多格式）
**购物车联动（v1 含）**：清单含非标条目时，打包流程先走批量生成、成功后正常打包（不再跳过）；非标型号打包为型号子文件夹多格式结构

## 3. 系统架构

```
网页/桌面  ──HTTP──▶ GenServer(HttpListener, net48)
   非标组合+签名            │
                    参数二次校验(同一份规则JSON)
                            │
             检索输出目录(命中即返回, 不生成)──▶ output\<系列>\<型号>\
                            │ 未命中
                     文件任务队列(jobs\ 目录, 容量上限)
                            │
        ┌───────────────────┼──────────────┐
   NX worker 1      NX worker 2   ...  NX worker N   ← 常驻进程, 每进程1席位
   认领前再检索 → 拷母模副本 → 设表达式 → 更新 → 导多格式 → 写输出目录
                            │
                    结果轮询API(任务号) ──▶ 下载(全格式zip / 批量打包)
```

**检索先行（每次生成前必做）**：GenServer 入队前按 `output\<系列>\<型号编码>\` 检索输出目录——**命中（目录存在且 exports 配置的全格式文件齐全）则直接返回已输出文件，不生成、不进队列**；worker 认领任务后**再查一次**（防并发窗口重复生成）；未命中才真正触发 NX。

**组件规格**：

1. **GenServer**：csc 编译的 net48 控制台程序，`HttpListener` 自托管（与桌面端 LocalViewerServer 同技术路线，无新运行时依赖）。接口：
   - `POST /gen` — 入参 {series, params, code} → 校验 → **检索输出目录（命中直接返回）** → 写队列 → 返回 {jobId}
   - `POST /gen-batch` — 批量：入参 {items: [{series, params, code}...]}（上限如 50 项）→ 逐项校验（任一非法整单拒绝）→ **逐项检索输出目录（命中项免生成）** → 未命中项写一个批量任务 → 返回 {jobId}；状态接口附带逐项进度 {done, total, failedItems}
   - `GET /status?job=<id>` — 返回 {state: queued|running|done|failed|timeout, filesUrl?, error?}
   - `GET /file?job=<id>&token=<一次性token>` — 下载该型号**全格式 zip**
   - `GET /health` — 存活探测
2. **文件任务队列**：`jobs\` 目录，每任务一个 `job_<id>.json`（单个任务或批量任务，含参数、母模路径、表达式映射快照）。**容量上限按任务计**（如 200），超限返回"队列繁忙"文案。任务状态持久在 job 文件里（崩溃可查）。
3. **NX worker（常驻，推荐）**：每个席位一个进程，`run_journal.exe worker_journal.vb <worker号>` 循环：轮询 `jobs\` → **认领前对该任务逐项检索输出目录（命中项跳过）** → 认领（原子改名/标记）→ 处理 → 写结果文件 → 继续。**进程守护**：GenServer 或计划任务检测 worker 心跳文件，死了自动重启。
   - **批量任务 = 单会话顺序处理**：同一 worker 会话内逐项"打开副本→设参→导出→关闭"，复用会话避免每项冷启动；同一系列的项共用一份母模副本（副本从不保存，只导多格式，可安全复用）；跨系列则各拷一份
   - v0 备选（更简单）：每任务直接 spawn run_journal 单发 journal——注意 NX 会话启动 ~30-60 秒/次，用户体验差，仅用于联调
4. **生成 journal 要点**：
   - 打开母模前**必须先拷贝母模到任务私有目录**再打开（NX 文件锁会排他，多 worker 并发打开同一 .prt 必冲突）
   - 按 masters.json 的表达式映射逐项设置表达式；**任一设置失败 → 任务失败并写明原因，禁止静默跳过**
   - **按 masters.json 的 exports 配置逐格式导出**：STEP(AP214)/Parasolid(.x_t)/IGES/STL（NX 均有对应导出 API），全部写入该型号输出子文件夹
   - 写入状态文件（journal 内 try-catch，不要只依赖 exit code）
5. **输出目录与残留清理**：生成结果写入 `output\<系列>\<型号编码>\` **留存不删除**；清理仅针对任务私有工作副本（母模拷贝等中间物，任务完成后删除，兜底 TTL 2 小时）；jobs 日志按天滚动。输出目录磁盘增长 = 实际请求过的唯一组合数，容量监控/归档属部署决策。
6. **安全**：API Key 校验（请求头）+ 每 Key 限流（如 10 次/分钟，超限返回统一文案）+ 参数全量规则校验（不信任客户端）+ 请求日志。v1 不需要账号体系。
7. **两端接入**：
   - 网页：静态站配置 `GEN_API` 基址（config.js，默认空 → 按钮维持一期置灰态，优雅降级）。非标组合显示【在线生成数模】→ 提交 → 轮询（间隔 3 秒，断线重连）→ 完成自动下载**全格式 zip**
   - **购物车批量打包联动**：打包时清单含非标条目 → 先提示"清单含 {n} 个非标档位"→【生成后打包】提交 /gen-batch → 逐项进度（{done}/{total}）→ 全部成功按原 zip 逻辑打包（非标为型号子文件夹多格式）；部分失败 → 成功项打包 + 失败清单提示可重试
   - 桌面：同按钮同文案同流程（联网探测：服务不可达按断网处理）；断网 → 置灰 + "需联网生成"提示。GenServer 地址由维护入口配置、随 .opc 发布
8. **母模工作目录（v1 文件型）**：服务器上 `catalog-masters\<系列>\<母模>.prt`，由维护人员从 Teamcenter 导出"已发布"母模同步至此（人工/robocopy）。TC 自动检出+版本写入 STEP 属性为升级项。

## 4. masters.json（服务器侧新文件，不进客户包）

```json
{
  "KC": {
    "masterPart": "KC_master.prt",
    "expressionMap": { "bore": "BORE", "stroke": "STROKE", "mount": "MOUNT_TYPE" },
    "exports": { "step": "214", "parasolid": true, "iges": true, "stl": true },
    "timeoutSec": 300
  }
}
```
- exports 支持全局默认 + 按系列覆盖；STL 精度沿用网格管线经验（0.5mm 量级，可配）
- **命中判定**：`output\<系列>\<型号编码>\` 目录存在且 exports 配置的全部格式文件齐全

- 表达式名由用户按 NX 母模实际命名确认；生成服务只认这张表
- 缺映射的参数（如影响不到几何的选项）可不列，生成照常

## 5. 验收标准（11 条，全部通过才可部署）

1. **端到端正确性（单个）**：网页非标组合（如 KC 系列 stroke=87）点【在线生成数模】→ 下载 zip → 在 NX 中打开 STEP 核对缸径/行程与请求一致（用户侧确认）
2. **批量生成端到端**：购物车含 3 个非标条目（跨系列）→ 一次提交 → 逐项进度 → 全部成功后打包 zip（标准档位 STEP + 非标型号子文件夹多格式）且各文件与请求参数一致；含 1 个非法项时整单拒绝
3. **部分失败可重试**：批量中 1 项生成失败 → 成功项正常打包、失败项明确列出并可单独重试
4. **检索先行与留存复用**：生成结果写入 `output\<系列>\<型号编码>\` 且不删除；同一组合第二次请求**不触发 NX**（观察无进程活动）直接返回已输出文件
5. **多格式完整**：每型号输出 STEP/Parasolid/IGES/STL 四格式，文件可各自打开验证
6. **双端一致**：桌面联网时与网页同按钮同文案同行为；断网置灰+提示（红线：两端 UI 无差异）
7. **服务端校验**：非法组合（越界/违背规则/不存在的系列）被拒绝，不进入队列，不触达 NX
8. **限流**：高频请求触发限流文案；日志可查
9. **并发与排队**：worker 数 = 席位上限，超出排队；队列满返回"队列繁忙"统一文案（按任务计）
10. **失败与重试**：生成失败/超时返回统一文案+可重试；worker 崩溃自动重启，任务不丢（重入队列）
11. **回归零影响**：标准档位全部不经服务、行为不变；一期验收项（对拍门禁/组合爆炸保护/31 项 selftest）全过

## 6. 陷阱清单（12 条）

1. **NX 母模文件锁**：多 worker 并发打开同一 .prt 会排他冲突——必须"拷贝副本再打开"（§3 组件 4）
2. **run_journal 启动开销**：每任务 spawn 一个 NX 会话 30~60 秒——v1 用常驻轮询 worker，别走每任务冷启动
3. **journal 错误捕获**：状态文件必须在 journal 内 try-catch 写入，exit code 不可靠
4. **表达式设置静默失败**：设参失败必须判失败并写明，否则交付错误几何
5. **中文路径**：服务器工作目录全部英文路径（NX 对中文路径敏感，项目已有教训）
6. **编码**：编辑含中文的 .cs/.vb/.ps1 后跑 `sample-data\tools\fix-bom.ps1`；journal 文件 BOM 手工恢复（fix-bom 不覆盖 .vb 的坑）
7. **任务幂等**：认领/完成必须原子操作（文件改名），防止双 worker 抢同一任务
8. **队列有界**：jobs 目录容量上限 + 状态表有界，防止磁盘/内存被刷爆
9. **下载 token 一次性**：/file 用一次性 token，防止链接外传；下载完成才清理
10. **网页轮询健壮性**：轮询断线重连、页面关闭不报错；生成中按钮防重复提交
11. **桌面联网探测**："服务不可达"与"断网"同文案处理，不弹错误框
12. **与一期验收衔接**：一期"非标置灰"验收项在本服务上线后升级——发布门禁脚本同步更新，别两头打架
13. **批量会话复用脏副本**：同系列共用的母模副本绝不能保存（journal 禁 Save）——误存一次，后续所有项都基于脏几何导出
14. **批量部分失败处理**：单项失败不得中止整批，记录 failedItems 继续；失败项可单独重试，状态文案一致
15. **输出目录并发写冲突**：同型号并发请求（两个用户同时生成同一组合）——按型号原子写（写临时名再改名落位），半成品文件绝不可被下载接口看到

## 7. 两端统一文案表（zh / en 同源，走 _lang.T/t 双语文案）

| 场景 | 中文 | English |
|---|---|---|
| 生成按钮 | 在线生成数模 | Generate 3D model online |
| 生成中 | 正在生成数模，预计 10–60 秒… | Generating — typically 10–60 s… |
| 排队中 | 生成队列繁忙，前面还有 {n} 个任务 | Queue busy — {n} task(s) ahead |
| 生成失败 | 生成失败，请重试或联系销售 | Generation failed — retry or contact sales |
| 生成超时 | 生成超时，请重试 | Generation timed out — retry |
| 断网/不可达 | 需联网生成，请连接网络后重试 | Internet required for generation |
| 参数无效 | 请求参数无效 | Invalid parameters |
| 限流 | 请求过于频繁，请稍后再试 | Too many requests — try again later |
| 多格式下载 | 下载全格式压缩包（STEP/Parasolid/IGES/STL） | Download all-format zip (STEP/Parasolid/IGES/STL) |
| 批量提示 | 清单含 {n} 个非标档位，将在线生成后打包 | {n} non-standard item(s) — will be generated before packaging |
| 批量生成按钮 | 生成后打包 | Generate & download zip |
| 批量进度 | 正在生成 {done}/{total}… | Generating {done}/{total}… |
| 批量部分失败 | {n} 项生成失败，其余已打包；失败项可重试 | {n} item(s) failed — the rest are packaged. Failed items can be retried. |

## 8. 成本与部署（决策要点，仅分析）

- **大头 = NX 授权席位**：每并发 worker 1 席位，公司现有 NX 可复用；席位少 → 队列深
- 服务器：Windows Server 一台（CPU/RAM 按席位数量配，每 NX 进程数 GB 内存）
- 部署位置（内网/公网反代）与公网域名/证书属上线决策，需用户另行指令
- 开发量：中小型功能（GenServer + journal + 两端接入），约购物车功能量级

## 9. 交付物

1. GenServer 源码与编译脚本（tools\build.ps1 增项）+ 启动/守护脚本
2. worker_journal.vb（常驻轮询生成）+ 单发 journal（联调用）
3. masters.json 模板 + KC 系列示例（表达式名由用户确认后填）
4. 网页端接入（config.js 基址 + 非标按钮/轮询/多格式 zip 下载 + 购物车批量生成打包联动，style.css 样式）+ 桌面端接入（联网探测/按钮/轮询/购物车联动，MainWindow）
5. 本地联调说明（docs\维护手册.md 增补章节）+ `项目总览.md` 回写进展
6. 升级路线备注：TC 检出与版本追溯、Part Families、Dispatcher（B 版）评估、JT/3D PDF 导出、标准档位多格式化
