1
This commit is contained in:
277
demo-project/_doc/登录功能修复说明.md
Normal file
277
demo-project/_doc/登录功能修复说明.md
Normal file
@@ -0,0 +1,277 @@
|
||||
# 登录功能修复说明
|
||||
|
||||
## 🔧 修复的问题
|
||||
|
||||
### 问题描述
|
||||
登录时出现错误:`Cannot read properties of undefined (reading 'message')`
|
||||
|
||||
### 根本原因
|
||||
登录接口返回的数据结构与代码中期望的不一致。
|
||||
|
||||
## 📊 数据结构分析
|
||||
|
||||
### 后端返回的数据结构
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "请求成功",
|
||||
"data": {
|
||||
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
|
||||
"user": {
|
||||
"id": 1,
|
||||
"name": "zc",
|
||||
"password": "d3df61764ee9a26091f714b88958caef",
|
||||
"roleId": 6,
|
||||
"create_time": "2022-10-24 05:45:40",
|
||||
"last_modify_time": "2025-09-12 06:48:54"
|
||||
},
|
||||
"authorityMenus": "[1,142,121,143,144,145,124,147,120,123,125,132,133,126,136,137,138,139,151,152,153,154,149,150,156,157,158,122,159,5,11,12,13,67,68,15]"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### HTTP 工具类的处理流程
|
||||
|
||||
1. **axios 响应拦截器**(`src/utils/http.js` 第 55-69 行)
|
||||
```javascript
|
||||
instance.interceptors.response.use(
|
||||
response => {
|
||||
if (response.status === 200) {
|
||||
if (response.data && response.data.code === 0) {
|
||||
return response // 返回整个 response 对象
|
||||
} else {
|
||||
// code 不为 0,拒绝
|
||||
return Promise.reject(response.data.message)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
```
|
||||
|
||||
2. **http.post 方法**(`src/utils/http.js` 第 176-191 行)
|
||||
```javascript
|
||||
async post(url, param, config) {
|
||||
let instance = this.getHttpInstance(config)
|
||||
let promise = new Promise((resolve, reject) => {
|
||||
instance.post(url, param).then(response => {
|
||||
resolve(response.data) // 返回 response.data
|
||||
})
|
||||
})
|
||||
return promise
|
||||
}
|
||||
```
|
||||
|
||||
3. **最终在 user.js 中得到的数据结构**
|
||||
```javascript
|
||||
let res = await userServerInstance.login(userFrom)
|
||||
// res 的结构是:
|
||||
// {
|
||||
// code: 0,
|
||||
// message: "请求成功",
|
||||
// data: { token, user, authorityMenus }
|
||||
// }
|
||||
```
|
||||
|
||||
## ✅ 修复方案
|
||||
|
||||
### 1. 修复 `src/store/user.js` 中的 `handleLogin` 方法
|
||||
|
||||
**修复前:**
|
||||
```javascript
|
||||
let res = await userServerInstance.login(userFrom)
|
||||
let token = res.data.token // ❌ 错误:res.data 是整个数据对象
|
||||
let user = res.data.user
|
||||
```
|
||||
|
||||
**修复后:**
|
||||
```javascript
|
||||
let res = await userServerInstance.login(userFrom)
|
||||
|
||||
// 检查返回数据结构
|
||||
if (res.code !== 0) {
|
||||
throw new Error(res.message || '登录失败')
|
||||
}
|
||||
|
||||
// 实际数据在 res.data 中
|
||||
let token = res.data.token // ✅ 正确
|
||||
let user = res.data.user // ✅ 正确
|
||||
let authorityMenus = res.data.authorityMenus // ✅ 正确
|
||||
```
|
||||
|
||||
### 2. 修复 `src/store/user.js` 中的 `setAuthorityMenus` 方法
|
||||
|
||||
**修复前:**
|
||||
```javascript
|
||||
let res = await userServerInstance.authorityMenus()
|
||||
let authorityMenus = res.data // ❌ 可能不正确
|
||||
```
|
||||
|
||||
**修复后:**
|
||||
```javascript
|
||||
let res = await userServerInstance.authorityMenus()
|
||||
|
||||
// res 的结构是 { code, message, data }
|
||||
if (res && res.code === 0 && res.data) {
|
||||
menus = res.data // ✅ 正确获取数据
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 增强错误处理
|
||||
|
||||
在 `src/views/login/login.vue` 中:
|
||||
|
||||
```javascript
|
||||
async handleSubmit({ userName, password }) {
|
||||
try {
|
||||
let userFrom = { name: userName, password: password }
|
||||
await this.handleLogin({
|
||||
userFrom,
|
||||
Main,
|
||||
ParentView,
|
||||
Page404
|
||||
})
|
||||
this.$Message.success('登录成功!')
|
||||
window.location.reload()
|
||||
} catch (error) {
|
||||
console.error('登录失败:', error)
|
||||
|
||||
// 处理不同类型的错误
|
||||
let errorMsg = '登录失败,请检查用户名和密码'
|
||||
|
||||
if (error) {
|
||||
if (typeof error === 'string') {
|
||||
errorMsg = error
|
||||
} else if (error.message) {
|
||||
errorMsg = error.message
|
||||
} else if (error.data && error.data.message) {
|
||||
errorMsg = error.data.message
|
||||
}
|
||||
}
|
||||
|
||||
this.$Message.error(errorMsg)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 🎯 登录流程
|
||||
|
||||
### 完整的登录流程
|
||||
|
||||
1. **用户输入用户名和密码**
|
||||
- 组件:`src/components/login-form/login-form.vue`
|
||||
- 触发事件:`on-success-valid`
|
||||
|
||||
2. **登录页面处理**
|
||||
- 组件:`src/views/login/login.vue`
|
||||
- 调用:`handleLogin` action
|
||||
|
||||
3. **Vuex Action 处理**
|
||||
- 文件:`src/store/user.js`
|
||||
- 方法:`handleLogin`
|
||||
- 步骤:
|
||||
1. 调用登录接口
|
||||
2. 保存 token 和用户名
|
||||
3. 处理权限菜单
|
||||
4. 生成路由
|
||||
|
||||
4. **HTTP 请求**
|
||||
- 文件:`src/api/system/userServer.js`
|
||||
- 接口:`POST /sys_user/login`
|
||||
- 参数:`{ name, password }`
|
||||
|
||||
5. **登录成功后**
|
||||
- 显示成功提示
|
||||
- 刷新页面
|
||||
- 自动跳转到首页
|
||||
|
||||
## 📝 测试步骤
|
||||
|
||||
### 1. 启动项目
|
||||
```bash
|
||||
cd demo-project
|
||||
npm run dev
|
||||
```
|
||||
|
||||
### 2. 打开浏览器
|
||||
访问:`http://localhost:8080`
|
||||
|
||||
### 3. 输入登录信息
|
||||
- 用户名:`zc`(或其他有效用户名)
|
||||
- 密码:对应的密码
|
||||
|
||||
### 4. 查看控制台日志
|
||||
应该能看到以下日志:
|
||||
```
|
||||
登录接口返回: { code: 0, message: "请求成功", data: {...} }
|
||||
处理权限菜单: [1,142,121,...]
|
||||
生成的主菜单: { path: '/', children: [...] }
|
||||
✅ Demo 项目启动成功!
|
||||
```
|
||||
|
||||
### 5. 验证登录成功
|
||||
- ✅ 显示"登录成功!"提示
|
||||
- ✅ 页面刷新
|
||||
- ✅ 跳转到系统首页
|
||||
- ✅ 显示用户名和菜单
|
||||
|
||||
## 🐛 调试技巧
|
||||
|
||||
### 查看登录请求
|
||||
1. 打开浏览器开发者工具(F12)
|
||||
2. 切换到 Network 标签
|
||||
3. 输入用户名密码,点击登录
|
||||
4. 查看 `/sys_user/login` 请求
|
||||
5. 检查 Response 数据结构
|
||||
|
||||
### 查看 Vuex 状态
|
||||
1. 安装 Vue DevTools 浏览器插件
|
||||
2. 打开 Vue DevTools
|
||||
3. 切换到 Vuex 标签
|
||||
4. 查看 `user` 模块的状态:
|
||||
- `token`:应该有值
|
||||
- `userName`:应该是登录的用户名
|
||||
- `authorityMenus`:应该是权限菜单数组
|
||||
|
||||
### 查看 localStorage
|
||||
1. 打开浏览器开发者工具(F12)
|
||||
2. 切换到 Application 标签
|
||||
3. 展开 Local Storage
|
||||
4. 查看存储的数据:
|
||||
- `demo_token`:token 值
|
||||
- `userName`:用户名
|
||||
- `authorityMenus`:权限菜单 JSON 字符串
|
||||
|
||||
## ⚠️ 注意事项
|
||||
|
||||
### 1. authorityMenus 的数据格式
|
||||
后端返回的 `authorityMenus` 是一个 **字符串**:
|
||||
```json
|
||||
"authorityMenus": "[1,142,121,143,...]"
|
||||
```
|
||||
|
||||
代码会自动解析这个字符串为数组。
|
||||
|
||||
### 2. 权限菜单的处理
|
||||
- 登录接口返回的 `authorityMenus` 是菜单 ID 数组
|
||||
- 需要根据这些 ID 从菜单配置中生成实际的路由
|
||||
- 使用 `uiTool.getRoutes()` 方法生成路由
|
||||
|
||||
### 3. Token 的使用
|
||||
- Token 保存在 Vuex store 和 localStorage 中
|
||||
- 每次 HTTP 请求都会自动带上 token(在请求头 `admin-token` 中)
|
||||
- Token 失效时会自动跳转到登录页
|
||||
|
||||
## 🎉 修复完成
|
||||
|
||||
现在登录功能应该可以正常工作了!
|
||||
|
||||
### 验证清单
|
||||
- ✅ 登录接口正确调用
|
||||
- ✅ Token 正确保存
|
||||
- ✅ 用户信息正确保存
|
||||
- ✅ 权限菜单正确处理
|
||||
- ✅ 登录成功后正确跳转
|
||||
- ✅ 错误处理完善
|
||||
|
||||
如果还有问题,请查看浏览器控制台的错误信息和网络请求详情。
|
||||
|
||||
Reference in New Issue
Block a user