## 任务：迁移旧 CRUD 页面到新版 page-table + page-dialog-form 方案

### 输入
用户会提供一个旧 CRUD 页面的文件路径列表和对照表信息。

---

### 迁移规则（必须严格遵守）

#### 1. 组件方案
- 使用 `<page-table>` + `<page-dialog-form>` 替代旧版 `<sct-base-table>` + `<sct-base-dialog>` + `<SctBaseForm>`
- 使用 `useTableColumns()` 生成列定义（不再手动分配 idx）
- 使用 `useTableButtons()` 生成工具栏按钮和行内按钮（不再分开写 buttonList / tableButtonList）
- 使用 `i18nMixin(prefix)` 注入 `key()` 和 `ckey()` 方法
- 参考文档：[表格组件使用说明.md](/docs/表格组件使用说明.md)
- 参考示例：`src/views/production-master-data/factory-model/factory-area/index.vue`

#### 1.1 特殊弹出框组件迁移（重要）

当旧页面中存在**超出 `page-dialog-form` 能力的弹出框**时（权限分配树、批量导入、关联选择器、详情查看、多步骤向导等），必须遵循以下流程：

##### 第一步：分析旧代码
- **仔细阅读旧项目的弹出框代码**，理解其数据结构、交互逻辑、API 调用
- 关注旧代码的数据来源路径（如 `row.menu_admin` 直接从列表获取、还是额外调 API）
- 记录旧的参数名、method 名，确保迁移时不遗漏

##### 第二步：提出优化方案
迁移时**不能简单照搬旧代码**，必须结合新版能力提出优化：

| 旧写法 | 优化方向 |
|--------|---------|
| `el-dialog` 内联在页面中 | 抽离为独立组件 → `components/` |
| `sct-base-dialog` + 内联表单 | 独立组件 + `el-drawer`（抽屉式体验更佳） |
| 额外调 API 获取数据（如行数据已包含） | 直接从 `row.xxx` 取值，减少请求 |
| `setTimeout` 硬编码延迟 | 提出来讨论，结合 `v-if` + `$nextTick` 优化 |
| `$parent` / `$refs` 跨组件通信 | 改为 `props` + `$emit` |

示例：角色权限分配迁移优化方案

```
旧方案                          优化方案
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
el-dialog 内联 42 行代码    →  独立 PermDrawer 组件（components/PermDrawer/index.vue）
getRoleMenu API 额外请求    →  直接从 row.menu_admin JSON.parse 获取（列表自带）
setTimeout 1000ms 关闭      →  保留（树渲染需要等待），但抽取到子组件内部
索引页 data 6 个 perm 字段  →  仅 2 个（permVisible + permRole）
```

##### 第三步：按标准实现
参考 [表格组件使用说明.md 第 13 节](/docs/表格组件使用说明.md#13-特殊弹出框组件规范)，严格遵循：

| 规则 | 说明 |
|------|------|
| 目录位置 | `src/views/{模块}/{功能}/components/{英文PascalCase}/index.vue` |
| 文件夹命名 | 英文 PascalCase，描述功能（如 `PermDrawer`、`ImportDialog`） |
| 组件通信 | 父→子 `props`（含 `.sync`），子→父 `$emit('saved')`，禁止 `$parent` / `$refs` |
| 主页面数据 | 只存 `visible` Boolean + 业务对象，其余状态在子组件内部 |

##### 第四步：完整案例

参考角色权限分配抽屉的完整迁移：
- 旧代码：`/home/james/WEBMAN-VUE-APP-develop/src/views/system_settings/user_management/role/components/PageMain/index.vue`（`dialogVisibleGive` + `el-tree`）
- 新代码：[`/home/james/WEBMAN-VUE-APP-V2-develop/mes-ui-d2/src/views/system-administration/user-management/role/components/PermDrawer/index.vue`](/src/views/system-administration/user-management/role/components/PermDrawer/index.vue)
- 主页面引用：[`src/views/system-administration/user-management/role/index.vue`](/src/views/system-administration/user-management/role/index.vue#L79-L87)

---

#### 2. i18n 国际化（重要）
- 使用 `mixins: [i18nMixin('完整i18n前缀')]`，不要在每个页面手动定义 `T` 常量和 `tkey()` 方法
- `data()` 中用 `this.key('xxx')` 传完整 i18n key，**不要用 `k()` 提前翻译**（翻译由 page-table / page-dialog-form 内部处理，切换语言自动响应）
- 模板搜索区用 `$t(key('xxx'))`，公共 key 用 `$t(ckey('xxx'))`
- 语言包必须中英文同步添加（`zh-chs.json` + `en.json`）
- 参考文档：[国际化规则.md](/docs/国际化规则.md)

#### 3. 文件夹命名（重要）
- 文件夹名称遵循 [后台Webman界面截图对照表](/后台Webman界面截图对照表.md) 的 snake_case/kebab-case 命名
- 目录示例：`src/views/production-master-data/factory-model/factory-area/`
- 路由模块：`src/router/modules/production-master-data.js`
- API 文件：`src/api/production-master-data/factory-area.js`

#### 4. 路由 path 和 API BASE URL（重要 — 临时方案）
- **路由 path** 和 **API BASE URL** **暂时保留旧项目的命名**，因为后台数据库的路由表还未更新
- 示例：目录按对照表叫 `production-master-data`，但路由 path 保持旧值 `production_configuration`
  ```js
  // src/router/modules/production-master-data.js
  path: '/production_configuration',  // 旧值暂留
  ```
  ```js
  // src/api/production-master-data/factory-area.js
  const BASE = 'production_configuration/factory_model/factory_area/'  // 旧值暂留
  ```
- 后续统一修改路由后再批量替换

#### 4.1 API 参数名必须对齐旧项目（重要）
- **API 函数入参的 key 名称必须与旧项目保持一致**，不能自行发明参数名
- 例如：旧项目角色菜单接口参数是 `role_id`，不能写成 `id`
  ```js
  // ❌ 错误 — 自行发明参数名
  getRoleMenu({ id: this.roleId })
  // ✅ 正确 — 与旧项目参数名一致
  getRoleMenu({ role_id: this.roleId })
  ```
- **迁移 API 时必须仔细阅读旧项目接口代码**，逐个核对每个接口的入参 key 名称
- 如果后端报「xxx 不能为空」，首先检查参数 key 是否与旧项目一致

#### 5. 旧 key → 新 key 映射
如果用户提供的是旧页面代码，需要根据对照表做 key 映射。已知映射如下（持续补充）：

| 旧 key 前缀 | 新 key 前缀 |
|------------|------------|
| `page.production_configuration.factory_model.factory_area` | `page.production_master_data.factory_model.factory_area` |
| `page.system_settings.user_management.role` | `page.system_administration.user_management.role` |
| `page.system_settings.user_management.user` | `page.system_administration.user_management.user` |
| `page.system_settings.menu_configuration.menu` | `page.system_administration.menu_management.menu_configuration` |
| `page.system_settings.system_assistant.operate_log` | `page.system_administration.system_utilities.operation_logs` |
| `page.system_settings.system_assistant.api_log` | `page.system_administration.system_utilities.api_logs` |
| `page.system_settings.system_assistant.problem_help` | `page.system_administration.system_utilities.problem_help` |
| `page.system_settings.system_monitoring.system.login` | `page.system_administration.system_monitoring.login` |
| `page.production_configuration.matetial_model.*` | `page.production_master_data.material_model.*` |
| `page.planning_production.production_batch_management.batch` | `page.planning_production.batch_management.batch_list` |
| `page.data_middleground.basic_traceability.*` | `page.data_platform.traceability.*` |

#### 6. 处理流程（每迁移一个页面执行以下步骤）
1. **确定对照表位置**：从 [后台Webman界面截图对照表](/后台Webman界面截图对照表.md) 找到对应行的英文名，转换为 snake_case
2. **创建目录结构**：`src/views/{一级snake_case}/{二级snake_case}/{三级snake_case}/`
3. **创建 API 文件**：`src/api/{一级snake_case}/{二级snake_case}/{三级snake_case}.js`，BASE URL 暂用旧值
4. **添加路由模块**：`src/router/modules/{一级snake_case}.js`，path 暂用旧值
5. **编写页面代码**：使用 page-table + page-dialog-form 方案
6. **添加 i18n**：在 `zh-chs.json` 和 `en.json` 中添加对应 key
7. **验证 JSON 合法性**：`node -e "JSON.parse(require('fs').readFileSync('src/locales/zh-chs.json','utf8'))"`

---

### 页面模板（通用 CRUD 页面骨架）

参考 `src/views/production-master-data/factory-model/factory-area/index.vue` 的结构，核心模式：

- **Script**：`mixins: [i18nMixin('page.{一}.{二}.{三}')]` + `data()` 中用 `this.key('xxx')` 传 key
- **Template**：`<page-table>` 传 columns/data/loading/toolbarButtons/rowButtons/pagination + `<page-dialog-form>` 传 formCols/formData/rules/title
- **Buttons**：`useTableButtons({ toolbar: [...], row: [...] }, this.$permission)`
- **Columns**：`useTableColumns([...])`
- **Methods**：`fetchData / onSearch / onReset / onPageChange / openAdd / openEdit / onDialogSubmit / handleDelete`
- **i18n key 模板**（每个页面至少要有这些）：`search / reset / add / edit / delete / operation / add_title / edit_title / code / name / remark / enter_code / enter_name / remark_length / operation_success / confirm / cancel / tip / confirm_delete`
- **搜索条件过多时**参考 [表格组件使用说明.md - 场景 8](/docs/表格组件使用说明.md#场景-8折叠式搜索区搜索条件过多时)，使用 `searchExpanded` + `v-show` 实现折叠式搜索区，需额外添加 i18n key：`expand`（展开更多/Expand）、`collapse`（收起/Collapse）

#### 6.1 依赖安装

当迁移涉及新的第三方库时：

1. **包管理器**：本项目使用 **pnpm**，安装命令为 `pnpm add <package-name>`
2. **安装前检查**：先在 `package.json` 中确认依赖是否已存在，避免重复安装
3. **版本兼容**：确保安装的包支持 Vue 2.x（本项目为 Vue 2.7）
4. **参考标准**：[表格组件使用说明.md - 第 11 节](/docs/表格组件使用说明.md#11-依赖安装规范)

---

### 输出要求
- 创建完整的页面文件、路由模块、API 文件
- 在 `zh-chs.json` 和 `en.json` 中添加对应 i18n key（中文和英文同步）
- 完成后提醒用户验证 JSON 合法性
- 如涉及对照表中已有映射的 key 前缀变更，自动纠正为新的 key 前缀
