请求接口更新,添加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-spread': 'error',
'prefer-template': 'error',
'eslint-comments/no-unlimited-disable': 'off',
'no-redeclare': 'off',
'@typescript-eslint/no-redeclare': 'error',

View File

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

View File

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

View File

@ -7,11 +7,14 @@ import { getRouterList } from '@/api/router'
//路由进入前拦截
//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) => {
progressStart()
document.title = langTitle(to.meta?.title) // i18 page title
const basicStore = useBasicStore()
if (to.path === '/500') {
return true
}
//1.判断token
if (basicStore.token) {
if (to.path === '/login') {
@ -36,7 +39,7 @@ router.beforeEach(async (to) => {
console.error(`route permission error${e}`)
basicStore.resetState()
progressClose()
return `/login?redirect=${to.path}`
return `/500?redirect=${to.path}`
}
} else {
return true

View File

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

View File

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

View File

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

View File

@ -1,6 +1,6 @@
import type { AxiosRequestConfig } from 'axios'
import axios from 'axios'
import { ElMessage, ElMessageBox } from 'element-plus'
import { ElMessage } from 'element-plus'
import { useBasicStore } from '@/store/basic'
//使用axios.create()创建一个axios请求实例
@ -31,6 +31,8 @@ service.interceptors.request.use(
//请求后拦截
service.interceptors.response.use(
(res) => {
const type = (res.headers['content-type'] as string) || ''
if (!type.startsWith('application/json')) return res.data
const { code } = res.data
const successCode = '0,200,20000'
const noAuthCode = '401,403'
@ -38,30 +40,39 @@ service.interceptors.response.use(
return res.data
} else {
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) => {
ElMessage.error({
message: err,
duration: 2 * 1000
})
const { response } = err
if (response?.status === 401) {
useBasicStore().resetStateAndToLogin()
} else {
const { msg } = response?.data ?? { msg: '未知异常' }
ElMessage.error({
message: msg || err,
duration: 2 * 1000
})
}
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->页面的配置
export default function request(config: AxiosRequestConfig) {
return service({
baseURL: import.meta.env.VITE_APP_BASE_URL,
//baseURL: import.meta.env.VITE_APP_BASE_URL,
baseURL: baseUrl,
timeout: 8000,
...config
})

View File

@ -42,8 +42,7 @@ export function isName(value) {
* @returns {boolean}
*/
export function isIP(ip) {
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])$/
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])$/
return reg.test(ip)
}
@ -53,8 +52,7 @@ export function isIP(ip) {
* @returns {boolean}
*/
export function isUrl(url) {
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.,?'\\+&%$#=~_-]+))*$/
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.,?'\\+&%$#=~_-]+))*$/
return reg.test(url)
}
@ -124,8 +122,7 @@ export function isObject(arg) {
* @returns {boolean}
*/
export function isPort(str) {
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])$/
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])$/
return reg.test(str)
}
@ -145,8 +142,7 @@ export function isPhone(str) {
* @returns {boolean}
*/
export function isIdCard(str) {
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]$/
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]$/
return reg.test(str)
}
@ -176,13 +172,7 @@ export function isChina(str) {
* @returns {boolean}
*/
export function isBlank(str) {
return (
str == null ||
false ||
str === '' ||
str.trim() === '' ||
str.toLocaleLowerCase().trim() === 'null'
)
return str == null || false || str === '' || str.trim() === '' || str.toLocaleLowerCase().trim() === 'null'
}
/**
@ -191,8 +181,7 @@ export function isBlank(str) {
* @returns {boolean}
*/
export function isTel(str) {
const reg =
/^(400|800)([0-9\\-]{7,10})|(([0-9]{4}|[0-9]{3})(-| )?)?([0-9]{7,8})((-| |转)*([0-9]{1,4}))?$/
const reg = /^(400|800)([0-9\\-]{7,10})|(([0-9]{4}|[0-9]{3})(-| )?)?([0-9]{7,8})((-| |转)*([0-9]{1,4}))?$/
return reg.test(str)
}
@ -210,14 +199,14 @@ export function isNum(str) {
* @param cid 18
* @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 arrValid = '1 0 X 9 8 7 6 5 4 3 2'.split(' ') //校检码
if (/^\d{17}\d|x$/i.test(cid)) {
let sum = 0
for (let i = 0; i < cid.length - 1; i++) {
// 对前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
@ -253,7 +242,7 @@ export class ElValidate {
validate.push({
required: true,
trigger: 'blur',
message: isString(canEmpty) ? canEmpty : '请输入文本',
message: isString(canEmpty) ? canEmpty : '请输入文本'
})
return validate
}
@ -268,11 +257,11 @@ export class ElValidate {
{
trigger: 'blur',
message: '请输入有效的手机号',
validator (rule, value, callback) {
validator(rule, value, callback) {
if (/^1[3456789]\d{9}$/g.test(value)) callback()
else callback(new Error('无效的手机号'))
},
},
}
}
])
}
@ -285,14 +274,14 @@ export class ElValidate {
{
trigger: 'blur',
message: '请输入有效的身份证号',
validator (rule, value, callback) {
validator(rule, value, callback) {
if (isIdentityNumber(value)) {
callback()
} else {
callback(new Error('无效的身份证号'))
}
},
},
}
}
])
}
@ -311,7 +300,7 @@ export class ElValidate {
{
trigger: 'change',
message: lint,
validator (rule, value, callback) {
validator(rule, value, callback) {
if (value.length < min) {
callback(new Error(`输入文本太短,最少长度为${min}`))
return
@ -321,8 +310,8 @@ export class ElValidate {
return
}
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>