feat: show login error message; add request timeout & network guard; silence NavigationDuplicated
CI/CD Deploy (Web) / 构建前端镜像并部署 (push) Successful in 29s

This commit is contained in:
张家训
2026-09-03 18:35:40 +08:00
parent 867647d2cd
commit 7d071218c2
4 changed files with 40 additions and 19 deletions
+17 -14
View File
@@ -8,6 +8,8 @@ import { TOKEN_KEY, EXPIRETIME_KEY } from '@/libs/util'
// import { Spin } from 'view-design'
const addErrorLog = errorInfo => {
// 网络错误/超时时 error.response 可能为 undefined,需兜底避免二次报错
if (!errorInfo || !errorInfo.request) return
const { statusText, status, request: { responseURL } } = errorInfo
let info = {
type: 'ajax',
@@ -15,7 +17,7 @@ const addErrorLog = errorInfo => {
mes: statusText,
url: responseURL
}
if (!responseURL.includes('save_error_logger')) store.dispatch('addErrorLog', info)
if (responseURL && !responseURL.includes('save_error_logger')) store.dispatch('addErrorLog', info)
}
class HttpRequest {
@@ -29,6 +31,8 @@ class HttpRequest {
headers: {
//
},
// 请求超时时间(毫秒),避免后端不可用时页面一直“卡住”无反馈
timeout: 30000,
/** transformRequest 允许在向服务器发送前,修改请求数据,只能用在 'PUT', 'POST' 和 'PATCH' 这几个请求方法后面数组中的函数必须返回一个字符串,或 ArrayBuffer,或 Stream**/
transformRequest: [function (data) {
// 对data进行任意转化处理
@@ -57,18 +61,12 @@ class HttpRequest {
}
this.queue[url] = true
// 根据项目需求添加请求拦截
//判断请求不是登陆接口的时候,字段是不是过期了,(根据业务逻辑做对应的处理)
//console.log("进入请求拦截器...")
//console.log(url)
if ((url.indexOf('login') < 0) && (config.url.indexOf('logout') )) {
// 判断请求不是登录/登出接口的时候,检查 token 是否过期(根据业务逻辑做对应的处理)
if ((url.indexOf('login') < 0) && (config.url.indexOf('logout') < 0)) {
let curTime = new Date().getTime()
let expireTime = store.state.user.expireTime // 获取token过期时间
//console.log(expireTime)
if (expireTime) {
let lessTime = eval(expireTime - curTime); // 后台返回的过期时间与现在的进行计算
//console.log(lessTime)
if (lessTime <= 0) {
Notice.warning({
title: '登录过期',
@@ -76,7 +74,6 @@ class HttpRequest {
})
Cookies.remove(TOKEN_KEY);
Cookies.remove(EXPIRETIME_KEY);
}
}
}
@@ -87,11 +84,17 @@ class HttpRequest {
})
// 响应拦截
instance.interceptors.response.use(res => {
// 根据项目需求添加响应拦截
//console.log("进入响应拦截器...")
//console.log(res.data.code )
let code = res.data.code
// 登录接口:业务失败(HTTP 200 + code!=200,如用户名或密码错误)
// 直接 reject,由登录页展示后端返回的 message,不触发全局登出逻辑
if (url.indexOf('/login') > -1) {
this.destroy(url)
const { data, status } = res
if (code && code !== 200) return Promise.reject(res.data)
return { data, status }
}
if (code === 415){
// 1、用户名或密码错误
Notice.warning({
+9
View File
@@ -11,6 +11,15 @@ import { getPermissionList } from '@/api/sys/sys-permission'
const {homeName} = config
Vue.use(Router)
// vue-router 对“重复导航到当前路由”会抛出 NavigationDuplicated(Promise rejection),
// 在关闭标签页、快速点击菜单等场景会向控制台报错,这里统一静默掉这种冗余导航
const originalPush = Router.prototype.push
Router.prototype.push = function push (location, onResolve, onReject) {
if (onResolve || onReject) return originalPush.call(this, location, onResolve, onReject)
return originalPush.call(this, location).catch(err => err)
}
const router = new Router({
routes,
mode: 'history'
+4 -3
View File
@@ -51,16 +51,17 @@ export default {
ip
}).then(res => {
let data = res.data
console.log("data:", data)
if (data.code === 200) {
let token = data.token
console.log("token:", token)
commit('setToken', token)
let curDate = new Date()
let expireTime = curDate.getTime() +24*60*60*1000 // 假设过期时间为后一天24*60*60*1000
commit('setExpireTime',expireTime)
resolve(data)
} else {
// 登录失败(如用户名或密码错误):把错误抛出给页面提示
reject(new Error(data.message || '登录失败,请稍后重试'))
}
resolve(data)
}).catch(err => {
reject(err)
})
+10 -2
View File
@@ -47,7 +47,8 @@
'getUserInfo'
]),
handleSubmit({username, password}) {
var ip = returnCitySN["cip"]
// returnCitySN 由 index.html 引用的第三方脚本定义,可能加载失败,需兜底
var ip = (typeof returnCitySN !== 'undefined' && returnCitySN) ? returnCitySN["cip"] : ''
this.$refs.loginForm.loading = true
this.handleLogin({username, password, ip}).then(res => {
setTimeout(() => {
@@ -56,7 +57,14 @@
name: this.$config.homeName
})
}, 400)
}).catch(err => {
// 登录失败 / 后端不可用 / 请求超时统一在此提示,并复位按钮 loading
this.$refs.loginForm.loading = false
let msg = (err && err.message) ? err.message : ''
if (!msg || msg.indexOf('Network Error') > -1 || msg.indexOf('timeout') > -1 || msg.indexOf('ECONNABORTED') > -1) {
msg = '网络异常或服务不可用,请稍后重试'
}
this.$Message.error(msg)
})
}
}