﻿P10-03 工作台：「一键准备」—— 一次生成带刀具/程序组/工序/刀路的副本并自动打开

## 背景（用户真实需求 2026-10-19 23:40）
用户希望"打开模型后点按钮建程序组、建刀具，再建工序匹配刀路，再生成刀路"。
架构限制：外挂用的是**另起的后台 NX 进程**，无法操作已打开的 NX 窗口
（文件锁 + 许可冲突），且用户明确要求独立外挂、不做 NX 插件。
因此按"反序但等价"实现：点一次按钮 → 后台一次做完 → 自动打开结果副本。

## 现状缺陷（必须先修，否则白做）
`app\NXAIStart.cs` 的 ② 建刀具 / ③ 建程序组 **没有传 --save-as**，
而 `tools\cam_build_local.py` 第 40 行明确"默认不保存"。
所以现在点了之后进程一退出，建好的刀具/程序组全部丢失，用户再打开零件什么也看不到。
这是用户实测"点了没用"的第二层原因。

## 要做的事

### 1) 新增「一键准备」按钮（放在功能按钮区，不影响已有 ①-⑦ 编号）
点击后按顺序执行，任一步失败即中止并明确报告（不许跳过继续）：

```
a. 前置检查：NX 进程是否在运行（Get-Process ugraf）
   - 在运行 → 提示「请先关闭 NX 再点此按钮（避免文件锁定与许可冲突）」并中止
   - 用户确认后也可强制继续（加 -AllowRunning 语义）
b. 前置检查：零件文件存在；facts 是否过期（复用 P10-01 的过期检测）
   - 过期 → 提示先「重新探测零件」
c. 后台 NX 执行（一次进程内做完，减少启停次数）：
   1. 建程序组 PROGRAM（名 NXAI_PROGRAM）
   2. 建刀具（名/直径取界面字段，默认 NXAI_D12 / 12）
   3. 建工序并生成刀路（复用 cam_create_op.py 已跑通的调用链）
   4. 另存副本：状态\artifacts\准备_<零件名>_<yyyyMMdd_HHmmss>.prt
d. 成功后：
   - 日志区打印副本全路径、文件大小、工序数、刀路行数
   - 自动用 NX 打开副本（Process.Start(<NX>\NXBIN\ugraf.exe, "副本路径")）
e. 失败时：日志区打印失败步骤 + 原始报错，不打开空洞的副本
```

### 2) 顺手修 ② ③ 的保存缺陷
- ② 建刀具 → 加 `--save-as 状态\artifacts\tool_<yyyyMMdd_HHmmss>.prt`
- ③ 建程序组 → 加 `--save-as 状态\artifacts\group_<yyyyMMdd_HHmmss>.prt`
- 日志里必须打印副本路径，否则用户不知道去哪找

### 3) 工序与刀具的匹配（用户明确要求"建工序，匹配相应的刀路"）
- 建工序时必须引用**本次刚建的刀具**（按名字查找 NCGroup 下的 Tool），
  不能新建一把临时刀
- 若找不到该刀具 → 报错「未找到刀具 <名>，请先建刀具」

## 验收（必须实测）
1. 用 `C:\Users\Administrator\Desktop\数控加工教程\7-17\7-17.prt` 实跑一次「一键准备」，
   贴出：rc、副本路径、副本大小、工序数、刀路行数
2. 证明副本真的含刀具/程序组：用后台 NX 重新打开该副本并枚举
   （刀 count、PROGRAM count、operation count），贴出实际数字
3. 证明 NX 在运行时按钮会拦截：开着 NX 点一次，贴出提示文案与日志
4. 门禁全绿：check_py_syntax 0 错误、run_eval 21/21、所有 tests\test_*.py 通过
5. 新增 .py 必须有 `P2-02 控制台编码护栏` 中文原文

## 约束
- 不改 `E:\Program Files\Siemens\NX*`、不改 cloud\、不改 core\license.py
- 不改 nx_post\ 下的后处理文件
- 不伪造结果：工序/刀路数量必须是真实枚举出来的
- 完成后写 `状态\P10-03.done.json`

## 修正（用户明确指出，2026-10-19 23:46）
上面第 1 步 c-2/c-3 写的是"建一把刀、建一条工序"，**这是错的**。
用户原话：「每个程序刀都不一样的啊」。刀具必须**从工序单逐行驱动**，不是固定默认值。

### 改为：工序单驱动的批量准备
1. 读最新工序单：优先 `状态\artifacts\plan_<最新>\process_plan.json`，
   没有就解析同目录 `工序单.md` 的第一张表（列：工序/刀具/φ/S/F/ap/ae）。
2. 对**每一行**：
   - 按该行刀具名与直径建刀具（D12→φ12，D8→φ8，E8.5→φ8.5，E11→φ11，
     名字与直径都取自该行，不写死）
   - 按该行工序类型建对应工序（铣/钻/攻牙/铣孔…，工序类型映射见 P10-02 的 op_matrix.json）
   - 该工序**必须引用刚建的那把刀**（按名字在 NCGroup 下查找并校验）
   - 调 GenerateToolPath 生成该工序刀路
   - 记录每行结果：刀具名、直径、工序、刀路行数、rc
3. 全部行处理完 → 另存副本 `状态\artifacts\准备_<零件名>_<时间>.prt` → 打开。
4. 日志区打印**逐行表格**：序号 / 刀具 / φ / 工序类型 / 刀路行数 / 结果。
   任何一行失败都要标红并汇总"共 N 行成功、M 行失败"，不许只报总数。

### 界面那三个输入框的定位（改掉歧义）
- `刀具名 / 直径 / 程序组名` 只用于**单件手工操作**（②③ 单点按钮），
  不参与「一键准备」的批量流程。
- 「一键准备」按钮旁加一句说明：
  「刀具与工序来自当前工序单，不用手填」。
- 若没有工序单 → 提示"请先点 ① 出工序单"，不要用默认值硬造。

## 工序命名规范（用户定，2026-10-19 23:55，三张卡通用）
- 工序统一命名为 **A01、A02、A03 … A30**（两位数字，从 01 起按加工顺序递增）。
- 超过 30 道时继续 A31、A32…（两位不够就三位 A100，不截断、不重复）。
- 同一零件内**不许重名**；重新出单时按最新顺序重新编号。
- 命名与工序类型/刀具**解耦**：工序名只是编号，
  类型（面铣/钻孔/攻牙…）与刀具（D12/E8.5…）各自占列，不写进工序名。
- NX 里创建的工序名也用 A01…（Create 的 name 参数直接传它），
  不要用 NXAI_OP、roughing_1 这类临时名。
- 工序单表格「工序」列显示 A01…；工序类型放独立列（列名「类型」）。
- 「一键准备」按 A01…A30 顺序逐行建工序并生成刀路，日志逐行打印编号。

## 补充需求（用户实测反馈 2026-10-20 00:01）
「点完 ①出工序单 / ②建刀具 / ③建程序组 后，点击启动UG，不会自动加载这张模型，还需要手动点。」

### 修法：启动 UG 时必须带零件参数
- `app\NXAIStart.cs` 的「一键启动 UG」当前是 `Process.Start(exe)`，**不带参数**，
  所以 NX 打开的是空界面。改成 `Process.Start(exe, "\"" + <零件全路径> + "\"")`。
- 优先级（按序取第一个存在的）：
  1. 若「一键准备」刚生成了副本 → **打开那个副本**（带刀具/程序组/工序/刀路）
  2. 否则打开界面「零件」框里的文件（必须 File.Exists 为真）
  3. 都没有 → 弹提示「请先选择零件文件」，不要静默打开空 NX
- 日志区打印：`已启动 UG 并加载：<路径>`
- 若路径含空格或中文，**必须用引号包裹**（NX 路径常有 "Program Files"、中文目录）。

### 验收
- 点「一键启动 UG」，贴出日志与 NX 标题栏截图/描述，证明直接加载了指定零件
  （不是空白工作台，也不是上次打开的旧文件）。
- 用带中文和空格的路径实测一次（如 `C:\我的 工具\测试 零件.prt`），证明引号处理正确。

## 修正（用户选 C 方案，2026-10-20 00:05）
上面「补充需求」里写的"优先打开副本"改成**由用户勾选决定**：

### 界面
在「一键启动 UG」按钮右侧加一个复选框：
```
☐ 启动UG时打开最新产物
```
- 默认 **不勾** → 点「一键启动 UG」打开界面「零件」框里的原文件
- 勾上 → 打开 `状态\artifacts\` 下**最新的产物文件**（按修改时间取最新），
  优先取「一键准备」生成的 `准备_*.prt`，其次 `tool_*.prt` / `group_*.prt` / `gui_op_*.prt`
- 勾上但目录里没有任何产物 → 提示「还没有产物，先点 ②③ 或 一键准备」并中止，不打开空 NX
- 复选框状态记到 `config\ui.json`，下次启动保持

### 与「一键准备」的关系
- 「一键准备」成功后**仍然自动打开副本**（不看这个复选框）—— 那是主流程
- 复选框只影响「一键启动 UG」这个按钮

### 日志
- 不勾：`已启动 UG 并加载原零件：<路径>`
- 勾选：`已启动 UG 并加载最新产物：<路径>（<时间>）`

### 验收
1. 不勾选启动 → 贴出日志证明加载的是原零件（路径与零件框一致）
2. 勾选启动 → 贴出日志证明加载的是最新产物（路径在 artifacts 下且时间最新）
3. 勾选但无产物 → 贴出提示文案，证明没打开空 NX
4. 路径含中文与空格时引号正确（用 `C:\我的 工具\测试 零件.prt` 实测）

## 产物输出目录改为桌面（用户决定，2026-10-20 00:12）
现在副本存在 `D:\NX_AI\状态\artifacts\`，太深不好找。改为桌面：

### 规则
- 产物根目录：`<桌面>\NXAI产物\`
  必须用 `Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory)`
  取桌面路径，**不要硬编码** `C:\Users\Administrator\Desktop`
  （有人桌面被 OneDrive 重定向到 `C:\Users\x\OneDrive\桌面`）。
- 目录不存在就自动创建。
- 产物文件名保持：`准备_<零件名>_<yyyyMMdd_HHmmss>.prt`、`tool_*.prt`、
  `group_*.prt`、`gui_op_*.prt`。
- 工作台「打开产物目录」按钮 → 打开这个桌面目录（不是 状态\artifacts）。
- **中间文件仍留在 `D:\NX_AI\状态\artifacts\`**：
  日志、gui_log、plan_*、selftest 输出等，不要搬到桌面污染桌面。
- 启动 UG 的「打开最新产物」复选框，扫描范围 = 桌面 NXAI产物 目录。

### 验收
1. 实跑一次 ② 或 一键准备，贴出产物落在 `<桌面>\NXAI产物\` 的实际路径与大小
2. 贴出「打开产物目录」打开的是该目录（截图或进程命令行）
3. 证明没有硬编码 C:\Users\Administrator\Desktop（代码里搜不到该字面量）
4. 中间文件仍在 D:\NX_AI\状态\artifacts\（贴出目录内容对比）
