From 8a4511dc3642348fe1b50179ac2f66c2ca11b82c Mon Sep 17 00:00:00 2001
From: sheng <905537351@qq.com>
Date: Wed, 27 May 2026 14:38:53 +0800
Subject: [PATCH] docs: add i18n spec and login migration docs, fix router
trailing char
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
1. 新增国际化规范文档 `i18n-rules.md`,详细说明项目国际化的规范、key 命名、使用方式等
2. 新增登录页面搬迁文档 `login-page-migration.md`,记录登录页搬迁的步骤、依赖和验证清单
3. 修复生产主数据路由文件中多余的尾随字符
---
docs/i18n-rules.md | 445 +++++++++++++++++++
docs/login-page-migration.md | 441 ++++++++++++++++++
src/router/modules/production-master-data.js | 2 +-
3 files changed, 887 insertions(+), 1 deletion(-)
create mode 100644 docs/i18n-rules.md
create mode 100644 docs/login-page-migration.md
diff --git a/docs/i18n-rules.md b/docs/i18n-rules.md
new file mode 100644
index 00000000..f9ff1c86
--- /dev/null
+++ b/docs/i18n-rules.md
@@ -0,0 +1,445 @@
+# i18n 国际化规范文档
+
+> **版本**:v1.0
+> **适用项目**:`mes-ui`
+> **语言包文件**:`src/locales/zh-chs.json` / `src/locales/en.json` / `src/locales/zh-cht.json` / `src/locales/ja.json`
+> **配合使用**:`src/composables/useI18n.js`(`i18nMixin`)
+
+---
+
+## 目录
+
+1. [语言包文件规范](#1-语言包文件规范)
+2. [Key 命名规范(三层层级)](#2-key-命名规范三层层级)
+3. [公共 Key 规范(page.common)](#3-公共-key-规范pagecommon)
+4. [页面中如何使用(i18nMixin)](#4-页面中如何使用i18nmixin)
+5. [常见场景 Key 模板](#5-常见场景-key-模板)
+6. [旧项目 Key 迁移对照](#6-旧项目-key-迁移对照)
+7. [翻译格式规范](#7-翻译格式规范)
+8. [新增页面 Checklist](#8-新增页面-checklist)
+
+---
+
+## 1. 语言包文件规范
+
+### 1.1 文件清单
+
+| 文件 | 语言 | `_element` 值 |
+|------|------|--------------|
+| `src/locales/zh-chs.json` | 简体中文 | `"zh-CN"` |
+| `src/locales/zh-cht.json` | 繁体中文 | `"zh-TW"` |
+| `src/locales/en.json` | 英文 | `"en"` |
+| `src/locales/ja.json` | 日文 | `"ja"` |
+
+### 1.2 文件格式
+
+- **编码**:UTF-8
+- **格式**:标准 JSON(不允许尾逗号,不允许注释)
+- **顶层结构**:
+
+```json
+{
+ "_element": "zh-CN",
+ "_name": "简体中文",
+ "page": { ... }
+}
+```
+
+- `_element`:对应 `element-ui/lib/locale/lang/` 的语言包文件名
+- `_name`:语言切换下拉菜单中的显示名
+- `page`:所有业务翻译的根节点,之下按模块层级嵌套
+
+### 1.3 维护原则
+
+- 中文和英文文件**必须保持 key 结构完全一致**,不允许一边有 key 而另一边没有
+- 新增页面时**中英文同步添加**
+- 每次新增后用 `node -e "JSON.parse(require('fs').readFileSync('src/locales/zh-chs.json','utf8'))"` 验证 JSON 合法性
+
+---
+
+## 2. Key 命名规范(三层层级)
+
+### 2.1 核心规则
+
+```
+page.{一级模块英文} .{二级模块英文} .{三级模块英文} .{具体key}
+ └─ snake_case ─┘└─ snake_case ─┘└─ snake_case ─┘
+```
+
+**英文来源**:[后台Webman界面截图对照表](./后台Webman界面截图对照表.md) 中的英文列。
+
+**格式转换**:对照表英文 → 全小写 + 空格替换为下划线 + `&` 替换为下划线。
+
+### 2.2 对照表 → i18n Key 映射表
+
+| 对照表英文名 | snake_case(用于 i18n key) | kebab-case(用于目录名) |
+|-------------|---------------------------|------------------------|
+| System Administration | `system_administration` | `system-administration` |
+| Production Master Data | `production_master_data` | `production-master-data` |
+| Equipment Management | `equipment_management` | `equipment-management` |
+| Planning & Production | `planning_production` | `planning-production` |
+| Quality Management | `quality_management` | `quality-management` |
+| Data Platform | `data_platform` | `data-platform` |
+| Factory Model | `factory_model` | `factory-model` |
+| Process Model | `process_model` | `process-model` |
+| Product Management | `product_management` | `product-management` |
+| Material Model | `material_model` | `material-model` |
+| SPC Configuration | `spc_configuration` | `spc-configuration` |
+| Team Model | `team_model` | `team-model` |
+| User Management | `user_management` | `user-management` |
+| Menu Management | `menu_management` | `menu-management` |
+| System Utilities | `system_utilities` | `system-utilities` |
+| System Monitoring | `system_monitoring` | `system-monitoring` |
+| Batch Management | `batch_management` | `batch-management` |
+| Production Monitoring | `production_monitoring` | `production-monitoring` |
+| Process Control | `process_control` | `process-control` |
+| Inspection Management | `inspection_management` | `inspection-management` |
+| Traceability | `traceability` | `traceability` |
+| Production Reports | `production_reports` | `production-reports` |
+| Correlation Analysis | `correlation_analysis` | `correlation-analysis` |
+| Factory Area | `factory_area` | `factory-area` |
+| Production Line | `production_line` | `production-line` |
+
+> **完整映射表**见本文档末尾附录 A。
+
+### 2.3 完整示例
+
+以「生产配置 → 工厂模型 → 工厂区域」页面为例:
+
+```json
+{
+ "page": {
+ "production_master_data": {
+ "factory_model": {
+ "factory_area": {
+ "search": "查询",
+ "reset": "重置",
+ "code": "所区编码",
+ "name": "所区名称",
+ "add": "新 增",
+ "edit": "编 辑",
+ "delete": "删 除"
+ }
+ }
+ }
+ }
+}
+```
+
+对应的 `i18nMixin` 前缀:
+
+```js
+mixins: [i18nMixin('page.production_master_data.factory_model.factory_area')]
+```
+
+---
+
+## 3. 公共 Key 规范(page.common)
+
+### 3.1 什么应该放公共
+
+跨页面、跨模块重复出现的文案,提取到 `page.common` 下:
+
+```json
+{
+ "page": {
+ "common": {
+ "help": "帮 助",
+ "confirm": "确定",
+ "cancel": "取消",
+ "save": "保存",
+ "delete": "删除",
+ "edit": "编辑",
+ "add": "新增",
+ "search": "查询",
+ "reset": "重置",
+ "operation": "操作",
+ "tip": "提示",
+ "confirm_delete": "确定要执行该操作吗?",
+ "operation_success": "操作成功",
+ "no_data": "暂无数据",
+ "loading": "加载中..."
+ }
+ }
+}
+```
+
+### 3.2 已有公共 Key 清单
+
+| key | 中文 | 英文 | 用途 |
+|-----|------|------|------|
+| `page.common.help` | 帮 助 | Help | 表格工具栏右侧帮助按钮 |
+
+> 后续发现跨页面共用 key 时,持续往 `page.common` 中补充。
+
+### 3.3 如何使用
+
+```vue
+
+```
+
+`ckey('help')` → `'page.common.help'`,由 `i18nMixin` 自动注入。
+
+### 3.4 判断标准:该不该放 common?
+
+| 情况 | 放哪里 | 示例 |
+|------|--------|------|
+| 多个一级模块都出现 | `page.common` | 帮助、确定、取消 |
+| 只在本模块内出现 | 模块自己的 key | 所区编码、产线编码 |
+| 不确定 | 先放在模块内,等第二次出现时提取 | — |
+
+---
+
+## 4. 页面中如何使用(i18nMixin)
+
+### 4.1 页面 Script 部分
+
+```js
+import { i18nMixin } from '@/composables/useI18n'
+
+export default {
+ mixins: [i18nMixin('page.production_master_data.factory_model.factory_area')],
+ data () {
+ const t = this.$t.bind(this)
+ const k = (s) => t(this.key(s)) // 当前页面翻译
+ const ck = (s) => t(this.ckey(s)) // 公共翻译
+
+ return {
+ formCols: [
+ [{ label: k('code'), placeholder: k('enter_code') }]
+ ],
+ rules: {
+ code: [{ required: true, message: k('enter_code'), trigger: 'blur' }]
+ }
+ }
+ },
+ created () {
+ this.columns = useTableColumns([
+ { prop: 'code', label: this.key('code') }
+ ])
+ }
+}
+```
+
+### 4.2 页面 Template 部分
+
+```vue
+
+
+
+
+
+ {{ $t(key('search')) }}
+
+
+
+
+```
+
+### 4.3 data() 中翻译的时机说明
+
+`data()` 在 `created` 之前执行,此时 `this` 已经可用。因此:
+
+- **column label / formCols / rules.message**:在 `data()` 中或 `created()` 中 `this.key()` 都可以
+- **推荐在 `data()` 中用 `k()` 提前翻译**,避免子组件 `$t()` 的 webpack HMR 缓存问题
+
+---
+
+## 5. 常见场景 Key 模板
+
+### 5.1 标准 CRUD 页面(每个页面必有的 key)
+
+```json
+{
+ "search": "查询",
+ "reset": "重置",
+ "add": "新 增",
+ "edit": "编 辑",
+ "delete": "删 除",
+ "operation": "操作",
+ "add_title": "新增{模块名}",
+ "edit_title": "编辑{模块名}",
+ "operation_success": "操作成功",
+ "confirm_delete": "确定要执行该操作吗?",
+ "enter_xxx": "请输入{字段名}",
+ "select_xxx": "请选择{字段名}"
+}
+```
+
+### 5.2 列表页字段 Key
+
+```json
+{
+ "sort": "序号",
+ "code": "{实体}编码",
+ "name": "{实体}名称",
+ "remark": "备注"
+}
+```
+
+### 5.3 表单校验 Key
+
+```json
+{
+ "enter_code": "请输入{实体}编码",
+ "enter_name": "请输入{实体}名称",
+ "remark_length": "长度在 1 到 100 个字符",
+ "validation_fail": "校验失败"
+}
+```
+
+### 5.4 登录页 Key
+
+```json
+{
+ "username": "用户名",
+ "password": "密码",
+ "login": "登录",
+ "please_enter_username": "请输入用户名",
+ "please_enter_password": "请输入密码",
+ "form_validation_failed": "表单校验失败,请检查"
+}
+```
+
+---
+
+## 6. 旧项目 Key 迁移对照
+
+### 6.1 旧 Key 结构 vs 新 Key 结构
+
+旧项目 key 路径深且命名不统一:
+
+| 旧 key 前缀 | 新 key 前缀 |
+|-----------|-----------|
+| `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_monitoring.system.login` | `page.system_administration.system_monitoring.login` |
+| `page.production_configuration.factory_model.factory_area` | `page.production_master_data.factory_model.factory_area` |
+| `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.*` |
+| `page.warehouse.*` | `page.warehouse.*`(待确定对照表英文名) |
+
+### 6.2 搬迁时的操作步序
+
+1. 确定页面对应的对照表三级模块英文名
+2. 按 `page.{一级}.{二级}.{三级}` 组装新 key 前缀
+3. 在 `zh-chs.json` 中按三层嵌套创建节点
+4. 在 `en.json` 中创建相同结构
+5. 将旧 key 的翻译值复制到新 key 下
+6. 页面代码中 `i18nMixin` 参数改为新前缀
+7. 模板中 `$t('旧key')` 全部改为 `$t(key('新suffix'))`
+
+---
+
+## 7. 翻译格式规范
+
+### 7.1 中文规范
+
+| 场景 | 格式 | 示例 |
+|------|------|------|
+| 按钮文字 | 字间加空格(两字不加) | `"查询"`、`"新 增"`、`"批量删除"` |
+| 占位提示 | `请输入{名称}` | `"请输入所区编码"` |
+| 校验消息 | 完整句,不加句号 | `"长度在 1 到 100 个字符"` |
+| 提示弹框 | 加问号 | `"确定要执行该操作吗?"` |
+| 操作成功消息 | 不加"成功"后缀的冗余 | `"操作成功"`(而非"保存成功"、"编辑成功"各自定义) |
+
+### 7.2 英文规范
+
+| 场景 | 格式 | 示例 |
+|------|------|------|
+| 按钮文字 | 首字母大写 | `"Search"`、`"Add"`、`"Edit"` |
+| 占位提示 | `Please enter {name}` | `"Please enter area code"` |
+| 校验消息 | 完整句 | `"Length should be 1 to 100 characters"` |
+| 提示弹框 | 问句 | `"Are you sure to delete?"` |
+| 操作成功消息 | 过去式或名词 | `"Operation succeeded"` |
+
+### 7.3 占位符
+
+使用 `{name}` 格式,不使用 `%s` / `{0}`:
+
+```json
+"please_enter": "请输入{name}"
+```
+
+```js
+this.$t('please_enter', { name: '所区编码' })
+// → "请输入所区编码"
+```
+
+---
+
+## 8. 新增页面 Checklist
+
+新增一个 CRUD 页面时,按以下顺序操作:
+
+- [ ] 1. 在 [后台Webman界面截图对照表](./后台Webman界面截图对照表.md) 中找到该页面的三级英文名
+- [ ] 2. 确定 i18n key 前缀:`page.{一级snake_case}.{二级snake_case}.{三级snake_case}`
+- [ ] 3. 在 `zh-chs.json` 的对应节点下添加本页面全部 key
+- [ ] 4. 在 `en.json` 的相同节点下添加对应英文翻译
+- [ ] 5. 验证 JSON 合法性:`node -e "JSON.parse(require('fs').readFileSync('src/locales/zh-chs.json','utf8'))"`
+- [ ] 6. 页面中使用 `mixins: [i18nMixin('key前缀')]`
+- [ ] 7. 模板中用 `$t(key('xxx'))` 替代硬编码文字
+- [ ] 8. data() 中用 `k('xxx')` 提前翻译 formCols / rules
+- [ ] 9. 公共文案(帮助、确定、取消等)用 `ckey('xxx')` 引用
+- [ ] 10. `pnpm lint` 无报错
+
+---
+
+## 附录 A:对照表 → i18n Key 完整映射
+
+### 一级模块
+
+| 对照表英文 | snake_case(i18n) | kebab-case(目录) |
+|-----------|-------------------|-------------------|
+| System Administration | `system_administration` | `system-administration` |
+| Production Master Data | `production_master_data` | `production-master-data` |
+| Equipment Management | `equipment_management` | `equipment-management` |
+| Planning & Production | `planning_production` | `planning-production` |
+| Quality Management | `quality_management` | `quality-management` |
+| Data Platform | `data_platform` | `data-platform` |
+| Warehouse | `warehouse` | `warehouse` |
+| SCADA Management | `scada_management` | `scada-management` |
+
+### 生产配置 → 二级模块
+
+| 二级(对照表) | snake_case | 三级页面数 |
+|---------------|-----------|:--:|
+| Factory Model | `factory_model` | 2 |
+| Process Model | `process_model` | 3 |
+| Product Management | `product_management` | 2 |
+| Material Model | `material_model` | 4 |
+| SPC Configuration | `spc_configuration` | 1 |
+| Team Model | `team_model` | 3 |
+
+### 设备模型 → 二级模块
+
+| 二级(对照表) | snake_case |
+|---------------|-----------|
+| Equipment Category | `equipment_category` |
+| Equipment Management | `equipment_management` |
+| Inspection Management | `inspection_management` |
+| Maintenance Management | `maintenance_management` |
+| Repair Management | `repair_management` |
+| Consumables Management | `consumables_management` |
+
+### 系统设置 → 二级/三级
+
+| 二级(对照表) | snake_case | 三级 snake_case |
+|---------------|-----------|----------------|
+| User Management | `user_management` | `role` / `user` |
+| Menu Management | `menu_management` | `menu_configuration` |
+| System Utilities | `system_utilities` | `operation_logs` / `api_logs` |
+| System Monitoring | `system_monitoring` | `monitoring_configuration` |
+| Organization | `organization` | `production_team_manage` / `production_shift_management` / `production_shift_calender` |
+| OCR | `ocr` | `config` / `log` |
+
+---
+
+## 附录 B:当前已实施页面
+
+| 页面 | i18nMixin 前缀 | 语言包节点 |
+|------|---------------|----------|
+| 工厂区域 | `page.production_master_data.factory_model.factory_area` | `zh-chs.json` / `en.json` ✅ |
diff --git a/docs/login-page-migration.md b/docs/login-page-migration.md
new file mode 100644
index 00000000..289359d6
--- /dev/null
+++ b/docs/login-page-migration.md
@@ -0,0 +1,441 @@
+# 登录页面搬迁文档
+
+> **搬迁源**:`D:\code\company\SCTMES_MES_V5\vue-app`
+> **搬迁目标**:`d:\code\mes\mes-ui`
+> **状态**:⏳ 待审阅,审阅通过后执行搬迁
+
+---
+
+## 一、文件清单与依赖关系
+
+```
+登录页面 index.vue
+ │
+ ├── ① 页面自身
+ ├── ② 依赖的 Store 模块
+ ├── ③ 依赖的 API 文件
+ ├── ④ 依赖的静态资源(图片)
+ ├── ⑤ 依赖的 i18n 语言包
+ ├── ⑥ 依赖的 CSS 公共样式(% placeholder)
+ ├── ⑦ 依赖的工具库
+ └── ⑧ 路由中已有框架(无需搬迁本文件)
+```
+
+---
+
+## 二、需要搬迁的文件
+
+### 2.1 页面核心文件
+
+| 文件 | 旧路径 | 新目标路径 | 说明 |
+|------|--------|-----------|------|
+| 登录页面 | `src/views/system_settings/system_monitoring/system/login/index.vue` | **覆盖** `src/views/system/login/index.vue` | 新项目已有一个简易占位页面,需用旧项目的完整页面替换 |
+
+> 旧路径嵌套很深:`system_settings/system_monitoring/system/login/`。
+> 新项目按对照表命名为简化的 `system/login/`,保持一致的命名风格。
+
+---
+
+### 2.2 Store 模块(Vuex)
+
+| 文件 | 旧路径 | 新目标路径 | 说明 |
+|------|--------|-----------|------|
+| account | `src/store/modules/d2admin/modules/account.js` | `src/store/modules/d2admin/modules/account.js` | **核心**:含 `login` 和 `logout` action |
+| user | `src/store/modules/d2admin/modules/user.js` | `src/store/modules/d2admin/modules/user.js` | account.login 中调用 `d2admin/user/set`,**新项目已存在** |
+
+> `account.js` 的 `login` action 依赖链:
+> `login()` → `loginAdminUser()` API → 写 cookie(token/uuid) → `dispatch(d2admin/user/set)` → `dispatch(load)`
+> `load()` → 依次加载 user/theme/transition/page/menu/size/color
+
+**account.js 依赖的其它模块(新项目已存在,不需搬迁)**:
+
+| 模块 | 路径 | 状态 |
+|------|------|:--:|
+| user | `src/store/modules/d2admin/modules/user.js` | ✅ 已有 |
+| theme | `src/store/modules/d2admin/modules/theme.js` | ✅ 已有 |
+| transition | `src/store/modules/d2admin/modules/transition.js` | ✅ 已有 |
+| page | `src/store/modules/d2admin/modules/page.js` | ✅ 已有 |
+| menu | `src/store/modules/d2admin/modules/menu.js` | ✅ 已有 |
+| size | `src/store/modules/d2admin/modules/size.js` | ✅ 已有 |
+| color | `src/store/modules/d2admin/modules/color.js` | ✅ 已有 |
+| db | `src/store/modules/d2admin/modules/db.js` | ✅ 已有 |
+
+---
+
+### 2.3 API 文件
+
+| 文件 | 旧路径 | 新目标路径 | 说明 |
+|------|--------|-----------|------|
+| 登录/注销 API | `src/api/login.js` | `src/api/auth.js` | 含 `loginAdminUser()` 和 `logoutAdminUser()` |
+
+> 注意:旧项目 `login.js` 中 import 了 `@/plugin/axios/request`,这是旧项目的 axios 封装。
+> 新项目使用 `@/api/_service` 中的 `request`,搬迁时需替换 import 路径。
+
+---
+
+### 2.4 静态资源(图片)
+
+| 文件 | 旧路径 | 新目标路径 | 说明 |
+|------|--------|-----------|------|
+| 登录页 Logo | `public/image/logo/sc_logo.png` | `public/image/logo/sc_logo.png` | 登录表单上方的 Logo |
+
+> 旧项目 `public/image/logo/` 目录下共有 9 个文件,但登录页面只用 `sc_logo.png`。
+> 根据需要可按需搬其他 logo 文件。新项目原有 `src/views/system/login/image/logo@2x.png`,搬迁后可删除。
+
+---
+
+### 2.5 i18n 语言包
+
+**i18n key 前缀**:`page.system_settings.system_monitoring.system.login`
+
+| key | 中文 | 英文 |
+|-----|------|------|
+| `time_is_most_precious` | 时间是一切财富中最宝贵的财富 | Time is the most precious of all wealth |
+| `username` | 用户名 | Username |
+| `password` | 密码 | Password |
+| `login` | 登录 | Login |
+| `quick_select_user` | 快速选择用户 | Quick Select User |
+| `please_enter_username` | 请输入用户名 | Please enter username |
+| `please_enter_password` | 请输入密码 | Please enter password |
+| `please_enter_code` | 请输入验证码 | Please enter captcha |
+| `dev_version` | 开发版本 | Development Version |
+| `test_version` | 测试版本 | Test Version |
+| `form_validation_failed` | 表单校验失败,请检查 | Form validation failed |
+
+**搬迁操作**:
+
+1. 在 `src/locales/zh-chs.json` 的 `page.system.system_monitoring` 下新增:
+```json
+"login": {
+ "time_is_most_precious": "时间是一切财富中最宝贵的财富",
+ "username": "用户名",
+ "password": "密码",
+ "login": "登录",
+ "quick_select_user": "快速选择用户",
+ "please_enter_username": "请输入用户名",
+ "please_enter_password": "请输入密码",
+ "please_enter_code": "请输入验证码",
+ "dev_version": "开发版本",
+ "test_version": "测试版本",
+ "form_validation_failed": "表单校验失败,请检查"
+}
+```
+
+2. 在 `src/locales/en.json` 中对应添加英文翻译。
+
+---
+
+### 2.6 CSS 公共样式(依赖但不在页面内)
+
+页面中使用了 SCSS 的 `%placeholder` 选择器:
+
+| placeholder | 作用 | 定义位置 |
+|-------------|------|---------|
+| `%unable-select` | 禁止用户选中 + 鼠标变手形 | `src/assets/style/public.scss` |
+| `%full` | 绝对定位填满父元素 | `src/assets/style/public.scss` |
+| `%flex-center-col` | flex 垂直水平居中 | `src/assets/style/public.scss` |
+| `$color-text-normal` | 文字颜色变量 | `src/assets/style/unit/color.scss` |
+| `$color-primary` | 主色变量 | `src/assets/style/unit/color.scss` |
+| `$color-bg` | 背景色变量 | `src/assets/style/unit/color.scss` |
+
+> ✅ 这些在新项目中已存在(通过 `additionalData` 全局注入),不需要额外搬迁。
+
+---
+
+### 2.7 工具/插件依赖(新项目已有,不需搬迁)
+
+| 依赖 | 旧路径 | 新项目状态 |
+|------|--------|:--:|
+| `util.cookies` | `src/libs/util.cookies.js` → `src/libs/util.js` | ✅ 已有 |
+| `localeMixin` | `src/locales/mixin.js` | ✅ 已有 |
+| `dayjs` | npm 包 | ✅ 已有(`package.json` 中) |
+| `$baseUrl` | `Vue.prototype.$baseUrl = process.env.BASE_URL` | ✅ 已在 `plugin/d2admin/index.js` 注册 |
+| `vuex` `mapActions` | npm 包 | ✅ 已有 |
+
+---
+
+### 2.8 路由(新项目已配置,不需搬迁)
+
+旧路由:
+```js
+{
+ path: '/login',
+ name: 'login',
+ component: _import('system_settings/system_monitoring/system/login')
+}
+```
+
+新项目路由已在 `routes.js` 的 `frameOut` 中配置:
+```js
+{
+ path: '/login',
+ name: 'login',
+ component: _import('system/login')
+}
+```
+
+> ✅ 新路由已指向 `system/login`,对应的 `src/views/system/login/index.vue` 需要替换为旧页面内容。
+
+---
+
+## 三、搬迁执行步骤
+
+| 步骤 | 操作 | 文件 |
+|:--:|------|------|
+| 1 | 拷贝登录 API(替换 import 为 `@/api/_service`) | `src/api/login.js` → `src/api/auth.js` |
+| 2 | 拷贝 account Store(替换 API 引用路径) | `src/store/modules/d2admin/modules/account.js` |
+| 3 | 拷贝 Logo 图片 | `public/image/logo/sc_logo.png` |
+| 4 | 更新登录页面(替换 import 路径 + i18n key + logo 路径) | `src/views/system/login/index.vue` |
+| 5 | 添加 i18n 语言包 | `src/locales/zh-chs.json` / `en.json` |
+| 6 | 验证:`pnpm serve` 启动 → 访问 `/login` 测试登录流程 |
+
+---
+
+## 四、页面中需要修改的内容
+
+登录页面 `index.vue` 从旧项目拷贝后,需改以下几处:
+
+### 4.1 import 路径修正
+
+```diff
+- import { mapActions } from 'vuex'
+- import util from '@/libs/util'
+- import localeMixin from '@/locales/mixin.js'
++ // 这些在新项目中路径一致,无需修改
++ // util.cookies、localeMixin、mapActions 均同上
+```
+
+> 注意:旧页面 mixins 中引用了 `localeMixin`(切换语言),新项目中此 mixin 在 `src/locales/mixin.js` 已存在,不需动。
+
+### 4.2 Logo 图片路径
+
+```diff
+-
++
+```
+
+> 新项目中 `$baseUrl` 同样已注册,两种写法均可。建议用绝对路径 `/image/logo/sc_logo.png` 更直观。
+
+### 4.3 i18n key 修正
+
+旧页面使用的 key 前缀为 `page.system_settings.system_monitoring.system.login.xxx`,在新项目中统一简化为 `page.system.login.xxx`,或按新项目目录结构调整。
+
+建议调整为更简洁的 key:
+
+| 旧 key(太长) | 新 key(建议) |
+|---------------|---------------|
+| `page.system_settings.system_monitoring.system.login.username` | `page.system.login.username` |
+| `page.system_settings.system_monitoring.system.login.password` | `page.system.login.password` |
+
+---
+
+## 五、不涉及的依赖(记录说明)
+
+| 依赖 | 原因 |
+|------|------|
+| `@/libs/websocket.js` | 登录页面本身不 import websocket,但 `account.js` 的 `logout` action 中引用。新项目如不需 websocket,注释掉即可 |
+| `@/api/modules/sys.user.api.js` | 旧 `account.login` 只调 `login.js` API,不涉及此文件 |
+| `public/image/logo/` 其他 png | 登录页只用 `sc_logo.png`,其余 logo 按需搬迁 |
+
+---
+
+## 登录流程完整流程图
+
+### 正向流程:用户登录
+
+```mermaid
+sequenceDiagram
+ participant User as 用户
+ participant LoginPage as Login 页面
+ participant VUEX as Store account
+ participant API as 后端 POST /login
+ participant Cookie as Cookie
+ participant Router as router.beforeEach
+ participant Home as 首页
+
+ User->>LoginPage: 输入用户名密码,点击登录
+ LoginPage->>LoginPage: el-form.validate 校验表单
+ alt 校验失败
+ LoginPage-->>User: message.error 表单校验失败
+ else 校验通过
+ LoginPage->>VUEX: dispatch login { username, password }
+ VUEX->>API: loginAdminUser
+ alt 登录失败 401 或密码错误
+ API-->>VUEX: throw Error
+ VUEX->>VUEX: remove token 和 uuid
+ VUEX-->>LoginPage: Promise rejected
+ LoginPage-->>User: message.error
+ else 登录成功
+ API-->>VUEX: token 和 userInfo
+ VUEX->>Cookie: 写入 token / uuid 有效期365天
+ VUEX->>VUEX: localStorage.setItem user_id
+ VUEX->>VUEX: dispatch user/set
+ VUEX->>VUEX: dispatch load 加载持久化配置
+ Note over VUEX: load按序加载: user theme transition page menu size color sourceData
+ VUEX-->>LoginPage: Promise resolved
+ LoginPage->>Router: router.replace redirect or /
+ Router->>Router: beforeEach 检查 token
+ Router-->>Home: 鉴权通过,跳转目标页
+ end
+ end
+```
+
+### 反向流程:用户注销
+
+```mermaid
+sequenceDiagram
+ participant User as 用户
+ participant Header as 顶栏用户菜单
+ participant VUEX as Store account
+ participant API as 后端 POST /logout
+ participant Cookie as Cookie
+ participant WS as WebSocket
+ participant LoginPage as Login 页面
+
+ User->>Header: 点击注销
+ Header->>VUEX: dispatch logout { confirm: true }
+ VUEX->>User: confirm 确定要注销吗
+ alt 取消
+ User-->>VUEX: 取消
+ else 确认
+ VUEX->>VUEX: Loading 遮罩
+ VUEX->>WS: closeSock 断开 WebSocket
+ VUEX->>API: logoutAdminUser
+ API-->>VUEX: 服务端清除 session
+ VUEX->>VUEX: dispatch db/set 清空 sourceData
+ VUEX->>VUEX: dispatch user/set 清空用户信息
+ VUEX->>Cookie: remove token / uuid / set block true
+ VUEX->>VUEX: Loading 关闭
+ VUEX->>LoginPage: router.push { name: login }
+ LoginPage-->>User: 返回登录页面
+ end
+```
+
+### 路由守卫鉴权流程(分三种情况)
+
+#### 情况 A:无 Token → 跳转登录页
+
+```mermaid
+flowchart TD
+ A["用户访问 URL"] --> B{"路由需要 auth?"}
+ B -->|是| C["Cookie.get(token)"]
+ C -->|"token 为空"| D["重定向到 /login?redirect=原地址"]
+ D --> E["用户在登录页输入账号密码"]
+ E --> F["登录成功"]
+ F --> G["router.replace 回到目标页"]
+ G --> H["进入首页"]
+```
+
+#### 情况 B:有 Token → 恢复会话
+
+```mermaid
+flowchart TD
+ A["用户访问 URL,Cookie 中已有 token"] --> B{"路由需要 auth?"}
+ B -->|是| C["Cookie.get(token)"]
+ C -->|"token 有效"| D["next 放行"]
+ D --> E["框架渲染 header-aside 布局"]
+ E --> F["d2admin/page/isLoaded"]
+ F --> G["d2admin/size/isLoaded"]
+ G --> H["页面正常加载"]
+
+ style C fill:#f9f,stroke:#333
+ style D fill:#9f9,stroke:#333
+ style H fill:#9f9,stroke:#333
+```
+
+#### 情况 C:Token 有效但后端已过期 → API 层拦截
+
+```mermaid
+flowchart TD
+ A["页面加载后调用业务 API"] --> B["axios 请求携带 Authorization header"]
+ B --> C{"后端 code === 401?"}
+ C -->|否| D["正常返回数据"]
+ C -->|"是 401"| E["axios 响应拦截器 catch 401"]
+ E --> F["清除 Cookie(token / uuid)"]
+ F --> G["Message.error 请重新登录"]
+ G --> H["router.push /login"]
+
+ style C fill:#f96,stroke:#333
+ style H fill:#f96,stroke:#333
+```
+
+### 已有 Token 时的完整恢复时序
+
+```mermaid
+sequenceDiagram
+ participant User as 用户
+ participant Browser as 浏览器
+ participant Router as router.beforeEach
+ participant Cookie as Cookie
+ participant Store as Vuex Store
+ participant DB as Local DB lowdb
+ participant Layout as Layout
+ participant Page as 目标页面
+
+ User->>Browser: 打开网页
+ Browser->>Router: beforeEnter 触发
+ Router->>Store: dispatch page/isLoaded
+ Router->>Store: dispatch size/isLoaded
+ Router->>Cookie: get token
+ Cookie-->>Router: token = eyJ...
+ Router->>Router: next 放行
+ Router->>Layout: 渲染 header-aside
+ Layout->>Store: menu 加载侧边栏
+ Store->>DB: get sys.menu.asideCollapse
+ DB-->>Store: 上次展开收起状态
+ Layout->>Store: theme 加载主题
+ Store->>DB: get sys.theme.activeName
+ DB-->>Store: 上次选择的主题
+ Layout->>Store: page 加载多标签页
+ Store->>DB: get sys.page.opened
+ DB-->>Store: 上次打开的标签页列表
+ Layout->>Page: 目标页面渲染完成
+ Page-->>User: 首页正常显示,主题侧栏标签页全部恢复
+```
+
+### 对比:首次登录 vs 已有 Token
+
+| 维度 | 首次登录(无 Token) | 已有 Token 恢复 |
+|------|-------------------|----------------|
+| 入口 | `/login` 登录页 | 任意页面 URL |
+| 路由守卫 | 拦下 → 重定向 /login | 放行 |
+| 用户操作 | 输入用户名密码 | 无需操作 |
+| `account/login` | ✅ 触发 | ❌ 不触发 |
+| `account/load()` | ✅ 触发(写入 DB) | ❌ 不触发 |
+| `page/isLoaded` | 触发(首次无缓存) | 触发(从 DB 恢复) |
+| `size/isLoaded` | 触发 | 触发 |
+| 主题/侧栏/标签页 | 从登录后 load() 写入 | 从 lowdb 读取上次状态 |
+| Cookie | 新建 token / uuid | 复用已有 token |
+
+---
+
+### 整体状态流转
+
+```mermaid
+stateDiagram-v2
+ [*] --> 未登录: 首次访问
+ [*] --> 已登录: 已有 token,恢复会话
+ 未登录 --> 登录页面: 路由守卫拦下
+ 登录页面 --> 提交中: 输入账号密码,点击登录
+ 提交中 --> 登录成功: API 返回 token
+ 提交中 --> 登录失败: API 报错 / 401
+ 登录失败 --> 登录页面: 清除 cookie,允许重试
+ 登录成功 --> 已登录: 写入 cookie + load() 加载配置
+ 已登录 --> 已登录: 页面刷新(token 仍有效,Router + DB 恢复)
+ 已登录 --> 未登录: API 返回 401,被强制退出
+ 已登录 --> 注销中: 点击注销
+ 注销中 --> 已登录: 取消确认
+ 注销中 --> 未登录: 确认 → logout API → 清 cookie → 跳 /login
+```
+
+---
+
+## 六、搬迁后验证清单
+
+- [ ] `pnpm lint` 无报错
+- [ ] `pnpm serve` 启动成功
+- [ ] 访问 `http://localhost:8081/login` 能看到完整登录页面
+- [ ] 输入正确的用户名密码能登录并跳转首页
+- [ ] 中文/英文切换按钮文字正确
+- [ ] 登录失败有表单校验提示
+- [ ] 浏览器 Cookie 中有 `token` 和 `uuid`
diff --git a/src/router/modules/production-master-data.js b/src/router/modules/production-master-data.js
index 921a096d..e91fc9a1 100644
--- a/src/router/modules/production-master-data.js
+++ b/src/router/modules/production-master-data.js
@@ -14,5 +14,5 @@ export default {
meta: { ...meta, cache: true, title: '工厂区域' },
component: _import('production-master-data/factory-model/factory-area')
}
- ])('production_master_data-')
+ ])('production_master_data-')
}