重构后端服务架构并优化前端错误处理

This commit is contained in:
ylweng
2025-09-05 01:18:40 +08:00
parent 86322c6f50
commit 5853953f79
20 changed files with 608 additions and 772 deletions

View File

@@ -3,9 +3,9 @@
<!-- 侧边栏 -->
<el-aside :width="isCollapse ? '64px' : '240px'" class="layout-aside">
<div class="logo-container">
<img v-if="!isCollapse" src="/logo.png" alt="Logo" class="logo" />
<img v-if="!isCollapse" src="/logo.svg" alt="Logo" class="logo" />
<span v-if="!isCollapse" class="logo-text">NiuMall</span>
<img v-else src="/logo.png" alt="Logo" class="logo-mini" />
<img v-else src="/logo.svg" alt="Logo" class="logo-mini" />
</div>
<el-menu

View File

@@ -29,10 +29,14 @@ export const useUserStore = defineStore('user', () => {
localStorage.setItem('token', access_token)
localStorage.setItem('userInfo', JSON.stringify(user))
ElMessage.success('登录成功')
ElMessage.success({
message: '登录成功',
grouping: true,
duration: 3000
})
return Promise.resolve()
} catch (error: any) {
ElMessage.error(error.message || '登录失败')
// 错误信息已在request拦截器中统一处理
return Promise.reject(error)
}
}
@@ -57,8 +61,13 @@ export const useUserStore = defineStore('user', () => {
const logoutAction = async () => {
try {
await logout()
} catch (error) {
console.error('登出接口调用失败:', error)
ElMessage.success({
message: '已退出登录',
grouping: true,
duration: 3000
})
} catch (error: any) {
// 错误信息已在request拦截器中统一处理
} finally {
// 清除状态和本地存储
token.value = ''

View File

@@ -3,6 +3,19 @@ import type { AxiosResponse, AxiosError } from 'axios'
import { ElMessage } from 'element-plus'
import { useUserStore } from '@/stores/user'
// 错误代码映射表
const ERROR_CODES: Record<string, string> = {
'AUTH_INVALID_CREDENTIALS': '用户名或密码错误',
'AUTH_ACCOUNT_LOCKED': '账户已被锁定,请联系管理员',
'AUTH_ACCOUNT_DISABLED': '账户已被禁用',
'AUTH_TOKEN_EXPIRED': '登录已过期,请重新登录',
'AUTH_INVALID_TOKEN': '无效的登录凭证',
'NETWORK_ERROR': '网络错误,请检查网络连接',
'TIMEOUT_ERROR': '请求超时,请稍后重试',
'SERVER_ERROR': '服务器内部错误',
'UNKNOWN_ERROR': '未知错误,请联系管理员'
}
// 创建axios实例
const request = axios.create({
baseURL: import.meta.env.VITE_API_BASE_URL || 'http://localhost:3000/api',
@@ -36,8 +49,14 @@ request.interceptors.response.use(
// 检查业务状态码
if (data.success === false) {
ElMessage.error(data.message || '请求失败')
return Promise.reject(new Error(data.message || '请求失败'))
const errorCode = data.code || 'UNKNOWN_ERROR'
const errorMsg = ERROR_CODES[errorCode] || data.message || '请求失败'
ElMessage.error({
message: errorMsg,
grouping: true,
duration: 5000
})
return Promise.reject(new Error(errorMsg))
}
return data
@@ -47,30 +66,61 @@ request.interceptors.response.use(
const { response } = error
if (response) {
const errorCode = (response.data as any)?.code
const errorMsg = errorCode ? ERROR_CODES[errorCode] : undefined
switch (response.status) {
case 401:
ElMessage.error('未授权,请重新登录')
ElMessage.error({
message: errorMsg || '未授权,请重新登录',
grouping: true,
duration: 5000
})
// 清除登录状态并跳转到登录页
const userStore = useUserStore()
userStore.logoutAction()
window.location.href = '/login'
break
case 403:
ElMessage.error('访问被拒绝,权限不足')
ElMessage.error({
message: errorMsg || '访问被拒绝,权限不足',
grouping: true,
duration: 5000
})
break
case 404:
ElMessage.error('请求的资源不存在')
ElMessage.error({
message: errorMsg || '请求的资源不存在',
grouping: true,
duration: 5000
})
break
case 500:
ElMessage.error('服务器内部错误')
ElMessage.error({
message: errorMsg || '服务器内部错误',
grouping: true,
duration: 5000
})
break
default:
ElMessage.error(`请求失败: ${response.status}`)
ElMessage.error({
message: errorMsg || `请求失败: ${response.status}`,
grouping: true,
duration: 5000
})
}
} else if (error.code === 'ECONNABORTED') {
ElMessage.error('请求超时,请稍后重试')
ElMessage.error({
message: '请求超时,请稍后重试',
grouping: true,
duration: 5000
})
} else {
ElMessage.error('网络错误,请检查网络连接')
ElMessage.error({
message: '网络错误,请检查网络连接',
grouping: true,
duration: 5000
})
}
return Promise.reject(error)

View File

@@ -3,7 +3,7 @@
<div class="login-box">
<div class="login-header">
<div class="logo">
<img src="/logo.png" alt="Logo" class="logo-img" />
<img src="/logo.svg" alt="Logo" class="logo-img" />
<h1 class="title">活牛采购智能数字化系统</h1>
</div>
<p class="subtitle">管理后台</p>