## 任务:迁移旧 CRUD 页面到新版 page-table + page-dialog-form 方案 ### 输入 用户会提供一个旧 CRUD 页面的文件路径列表和对照表信息。 --- ### 迁移规则(必须严格遵守) #### 1. 组件方案 - 使用 `` + `` 替代旧版 `` + `` + `` - 使用 `useTableColumns()` 生成列定义(不再手动分配 idx) - 使用 `useTableButtons()` 生成工具栏按钮和行内按钮(不再分开写 buttonList / tableButtonList) - 使用 `i18nMixin(prefix)` 注入 `key()` 和 `ckey()` 方法 - 参考文档:[表格组件使用说明.md](file:///d:/code/mes/mes-ui/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 节](file:///d:/code/mes/mes-ui/docs/表格组件使用说明.md#13-特殊弹出框组件规范),严格遵循: | 规则 | 说明 | |------|------| | 目录位置 | `src/views/{模块}/{功能}/components/{英文PascalCase}/index.vue` | | 文件夹命名 | 英文 PascalCase,描述功能(如 `PermDrawer`、`ImportDialog`) | | 组件通信 | 父→子 `props`(含 `.sync`),子→父 `$emit('saved')`,禁止 `$parent` / `$refs` | | 主页面数据 | 只存 `visible` Boolean + 业务对象,其余状态在子组件内部 | ##### 第四步:完整案例 参考角色权限分配抽屉的完整迁移: - 旧代码:`D:\code\company\SCTMES_MES_V5\vue-app\src\views\system_settings\user_management\role\components\PageMain\index.vue`(`dialogVisibleGive` + `el-tree`) - 新代码:[`src/views/system-administration/user-management/role/components/PermDrawer/index.vue`](file:///d:/code/mes/mes-ui/src/views/system-administration/user-management/role/components/PermDrawer/index.vue) - 主页面引用:[`src/views/system-administration/user-management/role/index.vue`](file:///d:/code/mes/mes-ui/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](file:///d:/code/mes/mes-ui/docs/国际化规则.md) #### 3. 文件夹命名(重要) - 文件夹名称遵循 [后台Webman界面截图对照表](file:///d:/code/mes/mes-ui/后台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界面截图对照表](file:///d:/code/mes/mes-ui/后台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**:`` 传 columns/data/loading/toolbarButtons/rowButtons/pagination + `` 传 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](file:///d:/code/mes/mes-ui/docs/表格组件使用说明.md#场景-8折叠式搜索区搜索条件过多时),使用 `searchExpanded` + `v-show` 实现折叠式搜索区,需额外添加 i18n key:`expand`(展开更多/Expand)、`collapse`(收起/Collapse) #### 6.1 依赖安装 当迁移涉及新的第三方库时: 1. **包管理器**:本项目使用 **pnpm**,安装命令为 `pnpm add ` 2. **安装前检查**:先在 `package.json` 中确认依赖是否已存在,避免重复安装 3. **版本兼容**:确保安装的包支持 Vue 2.x(本项目为 Vue 2.7) 4. **参考标准**:[表格组件使用说明.md - 第 11 节](file:///d:/code/mes/mes-ui/docs/表格组件使用说明.md#11-依赖安装规范) --- ### 输出要求 - 创建完整的页面文件、路由模块、API 文件 - 在 `zh-chs.json` 和 `en.json` 中添加对应 i18n key(中文和英文同步) - 完成后提醒用户验证 JSON 合法性 - 如涉及对照表中已有映射的 key 前缀变更,自动纠正为新的 key 前缀