1. 新增国际化规范文档 `i18n-rules.md`,详细说明项目国际化的规范、key 命名、使用方式等 2. 新增登录页面搬迁文档 `login-page-migration.md`,记录登录页搬迁的步骤、依赖和验证清单 3. 修复生产主数据路由文件中多余的尾随字符
442 lines
16 KiB
Markdown
442 lines
16 KiB
Markdown
# 登录页面搬迁文档
|
||
|
||
> **搬迁源**:`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
|
||
- <img class="page-login--logo" :src="`${$baseUrl}image/logo/sc_logo.png`">
|
||
+ <img class="page-login--logo" src="/image/logo/sc_logo.png">
|
||
```
|
||
|
||
> 新项目中 `$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`
|