请求接口更新,添加500页面,修复初始状态下服务器连接失败造成直接退出登录的问题,修复ESLint问题。

This commit is contained in:
洛洛希雅Lolosia 2023-06-06 08:46:30 +08:00
parent bb55eaedad
commit cd59783e90
10 changed files with 294 additions and 48 deletions

View File

@ -74,6 +74,7 @@ module.exports = defineConfig({
'prefer-rest-params': 'error', 'prefer-rest-params': 'error',
'prefer-spread': 'error', 'prefer-spread': 'error',
'prefer-template': 'error', 'prefer-template': 'error',
'eslint-comments/no-unlimited-disable': 'off',
'no-redeclare': 'off', 'no-redeclare': 'off',
'@typescript-eslint/no-redeclare': 'error', '@typescript-eslint/no-redeclare': 'error',

View File

@ -1,3 +1,4 @@
/* eslint-disable */
import { markRaw, nextTick, ref } from 'vue' import { markRaw, nextTick, ref } from 'vue'
import { mount } from '@vue/test-utils' import { mount } from '@vue/test-utils'
import { describe, expect, it, test } from 'vitest' import { describe, expect, it, test } from 'vitest'

View File

@ -1,7 +1,6 @@
import NProgress from 'nprogress' import NProgress from 'nprogress'
import type { RouteRawConfig, RouterTypes, rawConfig } from '~/basic' import type { RouteRawConfig, RouterTypes, rawConfig } from '~/basic'
import type { RouteRecordName } from 'vue-router' import type { RouteRecordName } from 'vue-router'
import { RouterView } from 'vue-router'
/** /**
* *
* @param:menuList * @param:menuList
@ -17,7 +16,6 @@ import router, { asyncRoutes, constantRoutes } from '@/router'
import 'nprogress/nprogress.css' import 'nprogress/nprogress.css'
import { useBasicStore } from '@/store/basic' import { useBasicStore } from '@/store/basic'
import { isArray } from 'xe-utils' import { isArray } from 'xe-utils'
import settings from '@/settings'
const buttonCodes: Array<Number> = [] //按钮权限 const buttonCodes: Array<Number> = [] //按钮权限
interface menuRow { interface menuRow {

View File

@ -7,11 +7,14 @@ import { getRouterList } from '@/api/router'
//路由进入前拦截 //路由进入前拦截
//to:将要进入的页面 vue-router4.0 不推荐使用next() //to:将要进入的页面 vue-router4.0 不推荐使用next()
const whiteList = ['/login', '/404', '/401'] // no redirect whitelist const whiteList = ['/login', '/404', '/401', '/500'] // no redirect whitelist
router.beforeEach(async (to) => { router.beforeEach(async (to) => {
progressStart() progressStart()
document.title = langTitle(to.meta?.title) // i18 page title document.title = langTitle(to.meta?.title) // i18 page title
const basicStore = useBasicStore() const basicStore = useBasicStore()
if (to.path === '/500') {
return true
}
//1.判断token //1.判断token
if (basicStore.token) { if (basicStore.token) {
if (to.path === '/login') { if (to.path === '/login') {
@ -36,7 +39,7 @@ router.beforeEach(async (to) => {
console.error(`route permission error${e}`) console.error(`route permission error${e}`)
basicStore.resetState() basicStore.resetState()
progressClose() progressClose()
return `/login?redirect=${to.path}` return `/500?redirect=${to.path}`
} }
} else { } else {
return true return true

View File

@ -19,6 +19,11 @@ export const constantRoutes: RouterTypes = [
component: () => import('@/views/error-page/401.vue'), component: () => import('@/views/error-page/401.vue'),
hidden: true hidden: true
}, },
{
path: '/500',
component: () => import('@/views/error-page/500.vue'),
hidden: true
},
{ {
path: '/', path: '/',
component: Layout, component: Layout,

View File

@ -13,7 +13,7 @@ export function mobilePhone(str) {
/* /*
* num四个 * num四个
* */ * */
export function toSplitNumFor(num, numToSpace) { export function toSplitNumFor(num) {
return num.replace(/(.{4})/g, '$1 ') return num.replace(/(.{4})/g, '$1 ')
} }
// 匹配银行卡号 // 匹配银行卡号

View File

@ -46,6 +46,7 @@ service.interceptors.response.use(
} }
}, },
(error) => { (error) => {
// eslint-disable-next-line no-console
console.log(`err${error}`) // for debug console.log(`err${error}`) // for debug
ElMessage({ ElMessage({
message: error.ElMessage, message: error.ElMessage,

View File

@ -1,6 +1,6 @@
import type { AxiosRequestConfig } from 'axios' import type { AxiosRequestConfig } from 'axios'
import axios from 'axios' import axios from 'axios'
import { ElMessage, ElMessageBox } from 'element-plus' import { ElMessage } from 'element-plus'
import { useBasicStore } from '@/store/basic' import { useBasicStore } from '@/store/basic'
//使用axios.create()创建一个axios请求实例 //使用axios.create()创建一个axios请求实例
@ -31,6 +31,8 @@ service.interceptors.request.use(
//请求后拦截 //请求后拦截
service.interceptors.response.use( service.interceptors.response.use(
(res) => { (res) => {
const type = (res.headers['content-type'] as string) || ''
if (!type.startsWith('application/json')) return res.data
const { code } = res.data const { code } = res.data
const successCode = '0,200,20000' const successCode = '0,200,20000'
const noAuthCode = '401,403' const noAuthCode = '401,403'
@ -38,30 +40,39 @@ service.interceptors.response.use(
return res.data return res.data
} else { } else {
if (noAuthCode.includes(code) && !location.href.includes('/login')) { if (noAuthCode.includes(code) && !location.href.includes('/login')) {
ElMessageBox.confirm('请重新登录', {
confirmButtonText: '重新登录',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
useBasicStore().resetStateAndToLogin() useBasicStore().resetStateAndToLogin()
})
} }
return Promise.reject(res.data) return Promise.reject(new Error(res.data?.msg ?? '未知异常'))
} }
}, },
//响应报错 //响应报错
(err) => { (err) => {
const { response } = err
if (response?.status === 401) {
useBasicStore().resetStateAndToLogin()
} else {
const { msg } = response?.data ?? { msg: '未知异常' }
ElMessage.error({ ElMessage.error({
message: err, message: msg || err,
duration: 2 * 1000 duration: 2 * 1000
}) })
}
return Promise.reject(err) return Promise.reject(err)
} }
) )
export const baseUrl: string = (() => {
let port = import.meta.env.VITE_APP_BASE_URL
if (/:\d{1,5}/.test(port)) port = port.match(/(?<port>:\d{1,5})/)?.groups?.port ?? ''
else port = `:${location.port}`
return `${location.protocol}//${location.hostname}${port}`
})()
//导出service实例给页面调用 , config->页面的配置 //导出service实例给页面调用 , config->页面的配置
export default function request(config: AxiosRequestConfig) { export default function request(config: AxiosRequestConfig) {
return service({ return service({
baseURL: import.meta.env.VITE_APP_BASE_URL, //baseURL: import.meta.env.VITE_APP_BASE_URL,
baseURL: baseUrl,
timeout: 8000, timeout: 8000,
...config ...config
}) })

View File

@ -42,8 +42,7 @@ export function isName(value) {
* @returns {boolean} * @returns {boolean}
*/ */
export function isIP(ip) { export function isIP(ip) {
const reg = const reg = /^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])$/
/^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])$/
return reg.test(ip) return reg.test(ip)
} }
@ -53,8 +52,7 @@ export function isIP(ip) {
* @returns {boolean} * @returns {boolean}
*/ */
export function isUrl(url) { export function isUrl(url) {
const reg = const reg = /^(https?|ftp):\/\/([a-zA-Z0-9.-]+(:[a-zA-Z0-9.&%$-]+)*@)*((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}|([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2}))(:[0-9]+)*(\/($|[a-zA-Z0-9.,?'\\+&%$#=~_-]+))*$/
/^(https?|ftp):\/\/([a-zA-Z0-9.-]+(:[a-zA-Z0-9.&%$-]+)*@)*((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}|([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2}))(:[0-9]+)*(\/($|[a-zA-Z0-9.,?'\\+&%$#=~_-]+))*$/
return reg.test(url) return reg.test(url)
} }
@ -124,8 +122,7 @@ export function isObject(arg) {
* @returns {boolean} * @returns {boolean}
*/ */
export function isPort(str) { export function isPort(str) {
const reg = const reg = /^([0-9]|[1-9]\d|[1-9]\d{2}|[1-9]\d{3}|[1-5]\d{4}|6[0-4]\d{3}|65[0-4]\d{2}|655[0-2]\d|6553[0-5])$/
/^([0-9]|[1-9]\d|[1-9]\d{2}|[1-9]\d{3}|[1-5]\d{4}|6[0-4]\d{3}|65[0-4]\d{2}|655[0-2]\d|6553[0-5])$/
return reg.test(str) return reg.test(str)
} }
@ -145,8 +142,7 @@ export function isPhone(str) {
* @returns {boolean} * @returns {boolean}
*/ */
export function isIdCard(str) { export function isIdCard(str) {
const reg = const reg = /^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/
/^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/
return reg.test(str) return reg.test(str)
} }
@ -176,13 +172,7 @@ export function isChina(str) {
* @returns {boolean} * @returns {boolean}
*/ */
export function isBlank(str) { export function isBlank(str) {
return ( return str == null || false || str === '' || str.trim() === '' || str.toLocaleLowerCase().trim() === 'null'
str == null ||
false ||
str === '' ||
str.trim() === '' ||
str.toLocaleLowerCase().trim() === 'null'
)
} }
/** /**
@ -191,8 +181,7 @@ export function isBlank(str) {
* @returns {boolean} * @returns {boolean}
*/ */
export function isTel(str) { export function isTel(str) {
const reg = const reg = /^(400|800)([0-9\\-]{7,10})|(([0-9]{4}|[0-9]{3})(-| )?)?([0-9]{7,8})((-| |转)*([0-9]{1,4}))?$/
/^(400|800)([0-9\\-]{7,10})|(([0-9]{4}|[0-9]{3})(-| )?)?([0-9]{7,8})((-| |转)*([0-9]{1,4}))?$/
return reg.test(str) return reg.test(str)
} }
@ -210,14 +199,14 @@ export function isNum(str) {
* @param cid 18 * @param cid 18
* @return Boolean * @return Boolean
**/ **/
export function isIdentityNumber(cid) { export function isIdentityNumber(cid: string) {
const arrExp = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2] //加权因子 const arrExp = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2] //加权因子
const arrValid = '1 0 X 9 8 7 6 5 4 3 2'.split(' ') //校检码 const arrValid = '1 0 X 9 8 7 6 5 4 3 2'.split(' ') //校检码
if (/^\d{17}\d|x$/i.test(cid)) { if (/^\d{17}\d|x$/i.test(cid)) {
let sum = 0 let sum = 0
for (let i = 0; i < cid.length - 1; i++) { for (let i = 0; i < cid.length - 1; i++) {
// 对前17位数字与权值乘积求和 // 对前17位数字与权值乘积求和
sum += Number.parseInt(cid.substr(i, 1), 10) * arrExp[i] sum += Number.parseInt(cid.slice(i, i + 1), 10) * arrExp[i]
} }
// 计算模(固定算法) // 计算模(固定算法)
const idx = sum % 11 const idx = sum % 11
@ -253,7 +242,7 @@ export class ElValidate {
validate.push({ validate.push({
required: true, required: true,
trigger: 'blur', trigger: 'blur',
message: isString(canEmpty) ? canEmpty : '请输入文本', message: isString(canEmpty) ? canEmpty : '请输入文本'
}) })
return validate return validate
} }
@ -268,11 +257,11 @@ export class ElValidate {
{ {
trigger: 'blur', trigger: 'blur',
message: '请输入有效的手机号', message: '请输入有效的手机号',
validator (rule, value, callback) { validator(rule, value, callback) {
if (/^1[3456789]\d{9}$/g.test(value)) callback() if (/^1[3456789]\d{9}$/g.test(value)) callback()
else callback(new Error('无效的手机号')) else callback(new Error('无效的手机号'))
}, }
}, }
]) ])
} }
@ -285,14 +274,14 @@ export class ElValidate {
{ {
trigger: 'blur', trigger: 'blur',
message: '请输入有效的身份证号', message: '请输入有效的身份证号',
validator (rule, value, callback) { validator(rule, value, callback) {
if (isIdentityNumber(value)) { if (isIdentityNumber(value)) {
callback() callback()
} else { } else {
callback(new Error('无效的身份证号')) callback(new Error('无效的身份证号'))
} }
}, }
}, }
]) ])
} }
@ -311,7 +300,7 @@ export class ElValidate {
{ {
trigger: 'change', trigger: 'change',
message: lint, message: lint,
validator (rule, value, callback) { validator(rule, value, callback) {
if (value.length < min) { if (value.length < min) {
callback(new Error(`输入文本太短,最少长度为${min}`)) callback(new Error(`输入文本太短,最少长度为${min}`))
return return
@ -321,8 +310,8 @@ export class ElValidate {
return return
} }
callback() callback()
}, }
}, }
]) ])
} }

View File

@ -0,0 +1,237 @@
<template>
<div class="wscn-http404-container">
<div class="wscn-http404">
<div class="pic-404">
<img class="pic-404__parent" src="@/assets/404_images/404.png" alt="404" />
<img class="pic-404__child left" src="@/assets/404_images/404_cloud.png" alt="404" />
<img class="pic-404__child mid" src="@/assets/404_images/404_cloud.png" alt="404" />
<img class="pic-404__child right" src="@/assets/404_images/404_cloud.png" alt="404" />
</div>
<div class="bullshit">
<div class="bullshit__oops">OOPS!</div>
<div class="bullshit__info">
All rights reserved
<a style="color: #20a0ff" href="https://wallstreetcn.com" target="_blank">wallstreetcn</a>
</div>
<div class="bullshit__headline">服务器内部异常请稍候重试</div>
<div class="bullshit__info">
或询问管理员服务器后台是否正常运行
</div>
<router-link :to="target" class="bullshit__return-home">重试</router-link>
</div>
</div>
</div>
</template>
<script setup>
const target = computed(() => useRoute().query.redirect || "/dashboard");
</script>
<style lang="scss" scoped>
.wscn-http404-container {
transform: translate(-50%, -50%);
position: absolute;
top: 40%;
left: 50%;
}
.wscn-http404 {
position: relative;
width: 1200px;
padding: 0 50px;
overflow: hidden;
.pic-404 {
position: relative;
float: left;
width: 600px;
overflow: hidden;
&__parent {
width: 100%;
}
&__child {
position: absolute;
&.left {
width: 80px;
top: 17px;
left: 220px;
opacity: 0;
animation-name: cloudLeft;
animation-duration: 2s;
animation-timing-function: linear;
animation-fill-mode: forwards;
animation-delay: 1s;
}
&.mid {
width: 46px;
top: 10px;
left: 420px;
opacity: 0;
animation-name: cloudMid;
animation-duration: 2s;
animation-timing-function: linear;
animation-fill-mode: forwards;
animation-delay: 1.2s;
}
&.right {
width: 62px;
top: 100px;
left: 500px;
opacity: 0;
animation-name: cloudRight;
animation-duration: 2s;
animation-timing-function: linear;
animation-fill-mode: forwards;
animation-delay: 1s;
}
@keyframes cloudLeft {
0% {
top: 17px;
left: 220px;
opacity: 0;
}
20% {
top: 33px;
left: 188px;
opacity: 1;
}
80% {
top: 81px;
left: 92px;
opacity: 1;
}
100% {
top: 97px;
left: 60px;
opacity: 0;
}
}
@keyframes cloudMid {
0% {
top: 10px;
left: 420px;
opacity: 0;
}
20% {
top: 40px;
left: 360px;
opacity: 1;
}
70% {
top: 130px;
left: 180px;
opacity: 1;
}
100% {
top: 160px;
left: 120px;
opacity: 0;
}
}
@keyframes cloudRight {
0% {
top: 100px;
left: 500px;
opacity: 0;
}
20% {
top: 120px;
left: 460px;
opacity: 1;
}
80% {
top: 180px;
left: 340px;
opacity: 1;
}
100% {
top: 200px;
left: 300px;
opacity: 0;
}
}
}
}
.bullshit {
position: relative;
float: left;
width: 300px;
padding: 30px 0;
overflow: hidden;
&__oops {
font-size: 32px;
font-weight: bold;
line-height: 40px;
color: #1482f0;
opacity: 0;
margin-bottom: 20px;
animation-name: slideUp;
animation-duration: 0.5s;
animation-fill-mode: forwards;
}
&__headline {
font-size: 20px;
line-height: 24px;
color: #222;
font-weight: bold;
opacity: 0;
margin-bottom: 10px;
animation-name: slideUp;
animation-duration: 0.5s;
animation-delay: 0.1s;
animation-fill-mode: forwards;
}
&__info {
font-size: 13px;
line-height: 21px;
color: grey;
opacity: 0;
margin-bottom: 30px;
animation-name: slideUp;
animation-duration: 0.5s;
animation-delay: 0.2s;
animation-fill-mode: forwards;
}
&__return-home {
display: block;
float: left;
width: 110px;
height: 36px;
background: #1482f0;
border-radius: 100px;
text-align: center;
color: #ffffff;
opacity: 0;
font-size: 14px;
line-height: 36px;
cursor: pointer;
animation-name: slideUp;
animation-duration: 0.5s;
animation-delay: 0.3s;
animation-fill-mode: forwards;
}
@keyframes slideUp {
0% {
transform: translateY(60px);
opacity: 0;
}
100% {
transform: translateY(0);
opacity: 1;
}
}
}
}
</style>