mirror of
https://github.com/zclzone/vue-naive-admin.git
synced 2025-12-28 12:10:20 +08:00
Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
100b91a118 | ||
|
|
26b71f0ec6 | ||
|
|
92e7ada37b | ||
|
|
2d879d0592 | ||
|
|
8806a6cb43 | ||
|
|
85a04fd06d | ||
|
|
4a5b8dd005 | ||
|
|
2f7da255e5 | ||
|
|
6664ae8f7b |
@@ -11,7 +11,27 @@
|
||||
"primaryColor": "#316C72FF",
|
||||
"primaryColorHover": "#316C72E3",
|
||||
"primaryColorPressed": "#2B4C59FF",
|
||||
"primaryColorSuppl": "#316C7263"
|
||||
"primaryColorSuppl": "#316C72E3",
|
||||
|
||||
"infoColor": "#2080F0FF",
|
||||
"infoColorHover": "#4098FCFF",
|
||||
"infoColorPressed": "#1060C9FF",
|
||||
"infoColorSuppl": "#4098FCFF",
|
||||
|
||||
"successColor": "#18A058FF",
|
||||
"successColorHover": "#36AD6AFF",
|
||||
"successColorPressed": "#0C7A43FF",
|
||||
"successColorSuppl": "#36AD6AFF",
|
||||
|
||||
"warningColor": "#F0A020FF",
|
||||
"warningColorHover": "#FCB040FF",
|
||||
"warningColorPressed": "#C97C10FF",
|
||||
"warningColorSuppl": "#FCB040FF",
|
||||
|
||||
"errorColor": "#D03050FF",
|
||||
"errorColorHover": "#DE576DFF",
|
||||
"errorColorPressed": "#AB1F3FFF",
|
||||
"errorColorSuppl": "#DE576DFF"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import request from '@/utils/http'
|
||||
import { request } from '@/utils'
|
||||
|
||||
export default {
|
||||
getUser: () => request.get('/user'),
|
||||
|
||||
@@ -18,7 +18,7 @@ import { defineComponent, h } from 'vue'
|
||||
import { useLoadingBar, useDialog, useMessage, useNotification } from 'naive-ui'
|
||||
import { useCssVar } from '@vueuse/core'
|
||||
import { kebabCase } from 'lodash-es'
|
||||
import { setupMessage, setupDialog } from '@/utils/common/naiveTools'
|
||||
import { setupMessage, setupDialog } from '@/utils'
|
||||
import { naiveThemeOverrides } from '~/settings'
|
||||
|
||||
function setupCssVar() {
|
||||
|
||||
@@ -38,16 +38,16 @@ const wrapper = ref(null)
|
||||
const isOverflow = ref(false)
|
||||
|
||||
const refreshIsOverflow = debounce(() => {
|
||||
const wrapperWidth = wrapper.value.offsetWidth
|
||||
const contentWidth = content.value.offsetWidth
|
||||
const wrapperWidth = wrapper.value?.offsetWidth
|
||||
const contentWidth = content.value?.offsetWidth
|
||||
isOverflow.value = contentWidth > wrapperWidth
|
||||
resetTranslateX(wrapperWidth, contentWidth)
|
||||
}, 200)
|
||||
|
||||
function handleMouseWheel(e) {
|
||||
const { wheelDelta } = e
|
||||
const wrapperWidth = wrapper.value.offsetWidth
|
||||
const contentWidth = content.value.offsetWidth
|
||||
const wrapperWidth = wrapper.value?.offsetWidth
|
||||
const contentWidth = content.value?.offsetWidth
|
||||
/**
|
||||
* @wheelDelta 平行滚动的值 >0: 右移 <0: 左移
|
||||
* @translateX 内容translateX的值
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup>
|
||||
import { renderIcon, renderCustomIcon } from '@/utils/icon'
|
||||
import { renderIcon, renderCustomIcon } from '@/utils'
|
||||
|
||||
const props = defineProps({
|
||||
icon: {
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { isNullOrWhitespace } from '@/utils/is'
|
||||
import { isNullOrWhitespace } from '@/utils'
|
||||
|
||||
defineProps({
|
||||
label: {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { isNullOrWhitespace } from '@/utils/is'
|
||||
import { isNullOrWhitespace } from '@/utils'
|
||||
|
||||
const ACTIONS = {
|
||||
view: '查看',
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
<template>
|
||||
<router-view v-slot="{ Component, route }">
|
||||
<KeepAlive :include="keepAliveRouteNames">
|
||||
<component :is="Component" v-if="appStore.reloadFlag" :key="route.meta?.key || route.fullPath" />
|
||||
<component :is="Component" v-if="appStore.reloadFlag" :key="appStore.aliveKeys[route.name] || route.fullPath" />
|
||||
</KeepAlive>
|
||||
</router-view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { useAppStore } from '@/store/modules/app'
|
||||
import { useAppStore } from '@/store'
|
||||
import { useRouter } from 'vue-router'
|
||||
const appStore = useAppStore()
|
||||
const router = useRouter()
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { renderCustomIcon, renderIcon } from '@/utils/icon'
|
||||
import { renderCustomIcon, renderIcon } from '@/utils'
|
||||
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { useAppStore } from '@/store/modules/app'
|
||||
import { useAppStore } from '@/store'
|
||||
|
||||
const appStore = useAppStore()
|
||||
</script>
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { useUserStore } from '@/store/modules/user'
|
||||
import { renderIcon } from '@/utils/icon'
|
||||
import { useUserStore } from '@/store'
|
||||
import { renderIcon } from '@/utils'
|
||||
|
||||
const userStore = useUserStore()
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { useAppStore } from '@/store/modules/app'
|
||||
import { useAppStore } from '@/store'
|
||||
const title = import.meta.env.VITE_TITLE
|
||||
|
||||
const appStore = useAppStore()
|
||||
|
||||
@@ -12,11 +12,8 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { usePermissionStore } from '@/store/modules/permission'
|
||||
|
||||
import { isExternal } from '@/utils/is'
|
||||
import { useAppStore } from '@/store/modules/app'
|
||||
import { renderCustomIcon, renderIcon } from '@/utils/icon'
|
||||
import { usePermissionStore, useAppStore } from '@/store'
|
||||
import { renderCustomIcon, renderIcon, isExternal } from '@/utils'
|
||||
|
||||
const router = useRouter()
|
||||
const curRoute = useRoute()
|
||||
|
||||
@@ -11,9 +11,9 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { useTagsStore } from '@/store/modules/tags'
|
||||
import { renderIcon } from '@/utils/icon'
|
||||
import { useAppStore } from '@/store/modules/app'
|
||||
import { useTagsStore, useAppStore } from '@/store'
|
||||
import { renderIcon } from '@/utils'
|
||||
import { useLocalStorage } from '@vueuse/core'
|
||||
|
||||
const props = defineProps({
|
||||
show: {
|
||||
@@ -79,7 +79,7 @@ const actionMap = new Map([
|
||||
() => {
|
||||
if (route.meta?.keepAlive) {
|
||||
// 重置keepAlive
|
||||
route.meta.key = +new Date()
|
||||
appStore.setAliveKeys(route.name, +new Date())
|
||||
}
|
||||
appStore.reloadPage()
|
||||
},
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
|
||||
<script setup>
|
||||
import ContextMenu from './ContextMenu.vue'
|
||||
import { useTagsStore } from '@/store/modules/tags'
|
||||
import { useTagsStore } from '@/store'
|
||||
import ScrollX from '@/components/common/ScrollX.vue'
|
||||
|
||||
const route = useRoute()
|
||||
|
||||
@@ -30,7 +30,7 @@ import AppHeader from './components/header/index.vue'
|
||||
import SideBar from './components/sidebar/index.vue'
|
||||
import AppMain from './components/AppMain.vue'
|
||||
import AppTags from './components/tags/index.vue'
|
||||
import { useAppStore } from '@/store/modules/app'
|
||||
import { useAppStore } from '@/store'
|
||||
import { header, tags } from '~/settings'
|
||||
|
||||
const appStore = useAppStore()
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/** 重置样式 */
|
||||
import '@/styles/reset.css'
|
||||
import '@/styles/index.scss'
|
||||
import 'uno.css'
|
||||
import '@/styles/global.scss'
|
||||
import 'virtual:svg-icons-register'
|
||||
|
||||
import { createApp } from 'vue'
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { getToken, refreshAccessToken } from '@/utils/token'
|
||||
import { isNullOrWhitespace } from '@/utils/is'
|
||||
import { getToken, refreshAccessToken, isNullOrWhitespace } from '@/utils'
|
||||
|
||||
const WHITE_LIST = ['/login', '/404']
|
||||
export function createPermissionGuard(router) {
|
||||
|
||||
@@ -1,24 +1,30 @@
|
||||
import { createRouter, createWebHistory, createWebHashHistory } from 'vue-router'
|
||||
import { setupRouterGuard } from './guard'
|
||||
import { basicRoutes as routes, EMPTY_ROUTE, NOT_FOUND_ROUTE } from './routes'
|
||||
import { getToken } from '@/utils/token'
|
||||
import { isNullOrWhitespace } from '@/utils/is'
|
||||
import { useUserStore } from '@/store/modules/user'
|
||||
import { usePermissionStore } from '@/store/modules/permission'
|
||||
import { basicRoutes, EMPTY_ROUTE, NOT_FOUND_ROUTE } from './routes'
|
||||
import { getToken, isNullOrWhitespace } from '@/utils'
|
||||
import { useUserStore, usePermissionStore } from '@/store'
|
||||
|
||||
const isHash = import.meta.env.VITE_USE_HASH === 'true'
|
||||
export const router = createRouter({
|
||||
history: isHash ? createWebHashHistory('/') : createWebHistory('/'),
|
||||
routes,
|
||||
routes: basicRoutes,
|
||||
scrollBehavior: () => ({ left: 0, top: 0 }),
|
||||
})
|
||||
|
||||
export async function resetRouter() {
|
||||
router.getRoutes().forEach((route) => {
|
||||
const { name } = route
|
||||
router.hasRoute(name) && router.removeRoute(name)
|
||||
})
|
||||
export async function setupRouter(app) {
|
||||
await addDynamicRoutes()
|
||||
setupRouterGuard(router)
|
||||
app.use(router)
|
||||
}
|
||||
|
||||
export async function resetRouter() {
|
||||
const basicRouteNames = getRouteNames(basicRoutes)
|
||||
router.getRoutes().forEach((route) => {
|
||||
const name = route.name
|
||||
if (!basicRouteNames.includes(name)) {
|
||||
router.removeRoute(name)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export async function addDynamicRoutes() {
|
||||
@@ -46,8 +52,14 @@ export async function addDynamicRoutes() {
|
||||
}
|
||||
}
|
||||
|
||||
export async function setupRouter(app) {
|
||||
await addDynamicRoutes()
|
||||
setupRouterGuard(router)
|
||||
app.use(router)
|
||||
export function getRouteNames(routes) {
|
||||
return routes.map((route) => getRouteName(route)).flat(1)
|
||||
}
|
||||
|
||||
function getRouteName(route) {
|
||||
const names = [route.name]
|
||||
if (route.children && route.children.length) {
|
||||
names.push(...route.children.map((item) => getRouteName(item)).flat(1))
|
||||
}
|
||||
return names
|
||||
}
|
||||
|
||||
@@ -3,3 +3,5 @@ import { createPinia } from 'pinia'
|
||||
export function setupStore(app) {
|
||||
app.use(createPinia())
|
||||
}
|
||||
|
||||
export * from './modules'
|
||||
|
||||
@@ -5,6 +5,8 @@ export const useAppStore = defineStore('app', {
|
||||
return {
|
||||
reloadFlag: true,
|
||||
collapsed: false,
|
||||
/** keepAlive路由的key,重新赋值可重置keepAlive */
|
||||
aliveKeys: {},
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
@@ -25,5 +27,8 @@ export const useAppStore = defineStore('app', {
|
||||
setCollapsed(collapsed) {
|
||||
this.collapsed = collapsed
|
||||
},
|
||||
setAliveKeys(key, val) {
|
||||
this.aliveKeys[key] = val
|
||||
},
|
||||
},
|
||||
})
|
||||
4
src/store/modules/index.js
Normal file
4
src/store/modules/index.js
Normal file
@@ -0,0 +1,4 @@
|
||||
export * from './app'
|
||||
export * from './permission'
|
||||
export * from './tags'
|
||||
export * from './user'
|
||||
@@ -53,5 +53,8 @@ export const usePermissionStore = defineStore('permission', {
|
||||
this.accessRoutes = accessRoutes
|
||||
return accessRoutes
|
||||
},
|
||||
resetPermission() {
|
||||
this.$reset()
|
||||
},
|
||||
},
|
||||
})
|
||||
@@ -1,4 +1,4 @@
|
||||
import { sStorage } from '@/utils/cache'
|
||||
import { sStorage } from '@/utils'
|
||||
|
||||
export const activeTag = sStorage.get('activeTag')
|
||||
export const tags = sStorage.get('tags')
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import { activeTag, tags, WITHOUT_TAG_PATHS } from './helpers'
|
||||
import { router } from '@/router'
|
||||
import { sStorage } from '@/utils/cache'
|
||||
import { sStorage } from '@/utils'
|
||||
|
||||
export const useTagsStore = defineStore('tag', {
|
||||
state() {
|
||||
@@ -57,5 +57,9 @@ export const useTagsStore = defineStore('tag', {
|
||||
router.push(filterTags[filterTags.length - 1].path)
|
||||
}
|
||||
},
|
||||
resetTags() {
|
||||
this.setTags([])
|
||||
this.setActiveTag('')
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import { removeToken } from '@/utils/token'
|
||||
import { toLogin } from '@/utils/auth'
|
||||
import { resetRouter } from '@/router'
|
||||
import { useTagsStore, usePermissionStore } from '@/store'
|
||||
import { removeToken, toLogin } from '@/utils'
|
||||
import api from '@/api'
|
||||
|
||||
export const useUserStore = defineStore('user', {
|
||||
@@ -35,8 +36,13 @@ export const useUserStore = defineStore('user', {
|
||||
}
|
||||
},
|
||||
async logout() {
|
||||
const { resetTags } = useTagsStore()
|
||||
const { resetPermission } = usePermissionStore()
|
||||
removeToken()
|
||||
this.userInfo = {}
|
||||
resetTags()
|
||||
resetPermission()
|
||||
resetRouter()
|
||||
this.$reset()
|
||||
toLogin()
|
||||
},
|
||||
setUserInfo(userInfo = {}) {
|
||||
@@ -1,14 +1,16 @@
|
||||
html {
|
||||
font-size: 4px; // * 1rem = 4px 方便unocss计算:在unocss中 1字体单位 = 0.25rem,相当于 1等份 = 1px
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
background-color: #f2f2f2;
|
||||
font-family: 'Encode Sans Condensed', sans-serif;
|
||||
}
|
||||
|
||||
html {
|
||||
font-size: 4px; // * 1rem = 4px 方便unocss计算:在unocss中 1字体单位 = 0.25rem,相当于 1等份 = 1px
|
||||
}
|
||||
|
||||
body {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
#app {
|
||||
@@ -16,7 +18,7 @@ body {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/* router view transition fade-slide */
|
||||
/* transition fade-slide */
|
||||
.fade-slide-leave-active,
|
||||
.fade-slide-enter-active {
|
||||
transition: all 0.3s;
|
||||
@@ -32,7 +34,6 @@ body {
|
||||
transform: translateX(30px);
|
||||
}
|
||||
|
||||
/* 自定义滚动条样式 */
|
||||
/* 自定义滚动条样式 */
|
||||
.cus-scroll {
|
||||
overflow: auto;
|
||||
@@ -12,7 +12,7 @@ html {
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
color: #333;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
a:hover,
|
||||
@@ -33,8 +33,3 @@ textarea {
|
||||
border: none;
|
||||
resize: none;
|
||||
}
|
||||
|
||||
body {
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
import { router } from '@/router'
|
||||
|
||||
export function toLogin() {
|
||||
router.replace({
|
||||
path: '/login',
|
||||
query: { ...router.currentRoute.value.query, redirect: router.currentRoute.value.path },
|
||||
})
|
||||
}
|
||||
|
||||
export function toFourZeroFour() {
|
||||
router.replace({
|
||||
path: '/404',
|
||||
})
|
||||
}
|
||||
16
src/utils/auth/auth.js
Normal file
16
src/utils/auth/auth.js
Normal file
@@ -0,0 +1,16 @@
|
||||
import { router } from '@/router'
|
||||
|
||||
export function toLogin() {
|
||||
const currentRoute = unref(router.currentRoute)
|
||||
const needRedirect = !currentRoute.meta.requireAuth && !['/404', '/login'].includes(router.currentRoute.value.path)
|
||||
router.replace({
|
||||
path: '/login',
|
||||
query: needRedirect ? { ...currentRoute.query, redirect: currentRoute.path } : {},
|
||||
})
|
||||
}
|
||||
|
||||
export function toFourZeroFour() {
|
||||
router.replace({
|
||||
path: '/404',
|
||||
})
|
||||
}
|
||||
2
src/utils/auth/index.js
Normal file
2
src/utils/auth/index.js
Normal file
@@ -0,0 +1,2 @@
|
||||
export * from './auth'
|
||||
export * from './token'
|
||||
@@ -1,4 +1,4 @@
|
||||
import { lStorage } from './cache'
|
||||
import { lStorage } from '@/utils'
|
||||
import api from '@/api'
|
||||
|
||||
const TOKEN_CODE = 'access_token'
|
||||
76
src/utils/common/common.js
Normal file
76
src/utils/common/common.js
Normal file
@@ -0,0 +1,76 @@
|
||||
import dayjs from 'dayjs'
|
||||
|
||||
/**
|
||||
* @desc 格式化时间
|
||||
* @param {(Object|string|number)} time
|
||||
* @param {string} format
|
||||
* @returns {string | null}
|
||||
*/
|
||||
export function formatDateTime(time = undefined, format = 'YYYY-MM-DD HH:mm:ss') {
|
||||
return dayjs(time).format(format)
|
||||
}
|
||||
|
||||
export function formatDate(date = undefined, format = 'YYYY-MM-DD') {
|
||||
return formatDateTime(date, format)
|
||||
}
|
||||
|
||||
/**
|
||||
* @desc 函数节流
|
||||
* @param {Function} fn
|
||||
* @param {Number} wait
|
||||
* @returns {Function}
|
||||
*/
|
||||
export function throttle(fn, wait) {
|
||||
var context, args
|
||||
var previous = 0
|
||||
|
||||
return function () {
|
||||
var now = +new Date()
|
||||
context = this
|
||||
args = arguments
|
||||
if (now - previous > wait) {
|
||||
fn.apply(context, args)
|
||||
previous = now
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @desc 函数防抖
|
||||
* @param {Function} func
|
||||
* @param {number} wait
|
||||
* @param {boolean} immediate
|
||||
* @return {*}
|
||||
*/
|
||||
export function debounce(method, wait, immediate) {
|
||||
let timeout
|
||||
return function (...args) {
|
||||
let context = this
|
||||
if (timeout) {
|
||||
clearTimeout(timeout)
|
||||
}
|
||||
// 立即执行需要两个条件,一是immediate为true,二是timeout未被赋值或被置为null
|
||||
if (immediate) {
|
||||
/**
|
||||
* 如果定时器不存在,则立即执行,并设置一个定时器,wait毫秒后将定时器置为null
|
||||
* 这样确保立即执行后wait毫秒内不会被再次触发
|
||||
*/
|
||||
let callNow = !timeout
|
||||
timeout = setTimeout(() => {
|
||||
timeout = null
|
||||
}, wait)
|
||||
if (callNow) {
|
||||
method.apply(context, args)
|
||||
}
|
||||
} else {
|
||||
// 如果immediate为false,则函数wait毫秒后执行
|
||||
timeout = setTimeout(() => {
|
||||
/**
|
||||
* args是一个类数组对象,所以使用fn.apply
|
||||
* 也可写作method.call(context, ...args)
|
||||
*/
|
||||
method.apply(context, args)
|
||||
}, wait)
|
||||
}
|
||||
}
|
||||
}
|
||||
4
src/utils/common/index.js
Normal file
4
src/utils/common/index.js
Normal file
@@ -0,0 +1,4 @@
|
||||
export * from './common'
|
||||
export * from './is'
|
||||
export * from './icon'
|
||||
export * from './naiveTools'
|
||||
@@ -1,4 +1,4 @@
|
||||
import { isNullOrUndef } from '@/utils/is'
|
||||
import { isNullOrUndef } from '@/utils'
|
||||
|
||||
export function setupMessage(NMessage) {
|
||||
let loadingMessage = null
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
import { useUserStore } from '@/store/modules/user'
|
||||
import { isNullOrUndef } from '@/utils/is'
|
||||
import { removeToken } from '@/utils/token'
|
||||
import { toLogin } from '@/utils/auth'
|
||||
import { useUserStore } from '@/store'
|
||||
|
||||
export function addBaseParams(params) {
|
||||
if (!params.userId) {
|
||||
@@ -9,35 +6,27 @@ export function addBaseParams(params) {
|
||||
}
|
||||
}
|
||||
|
||||
export function resolveResError(error = {}) {
|
||||
let { code, message } = error
|
||||
if (isNullOrUndef(code)) {
|
||||
// 未知错误
|
||||
code = -1
|
||||
message = message ?? '接口未知异常!'
|
||||
} else {
|
||||
switch (code) {
|
||||
case 400:
|
||||
message = message ?? '请求参数错误'
|
||||
break
|
||||
case 401:
|
||||
message = message ?? '登录已过期'
|
||||
removeToken()
|
||||
toLogin()
|
||||
break
|
||||
case 403:
|
||||
message = message ?? '没有权限'
|
||||
break
|
||||
case 404:
|
||||
message = message ?? '资源或接口不存在'
|
||||
break
|
||||
case 500:
|
||||
message = message ?? '服务器异常'
|
||||
break
|
||||
default:
|
||||
message = message ?? '操作异常!'
|
||||
break
|
||||
}
|
||||
export function resolveResError(code, message) {
|
||||
switch (code) {
|
||||
case 400:
|
||||
message = message ?? '请求参数错误'
|
||||
break
|
||||
case 401:
|
||||
message = message ?? '登录已过期'
|
||||
useUserStore().logout()
|
||||
break
|
||||
case 403:
|
||||
message = message ?? '没有权限'
|
||||
break
|
||||
case 404:
|
||||
message = message ?? '资源或接口不存在'
|
||||
break
|
||||
case 500:
|
||||
message = message ?? '服务器异常'
|
||||
break
|
||||
default:
|
||||
message = message ?? `【${code}】: 未知异常!`
|
||||
break
|
||||
}
|
||||
return { code, message }
|
||||
return message
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import axios from 'axios'
|
||||
import { repReject, repResolve, reqReject, reqResolve } from './interceptors'
|
||||
import { resReject, resResolve, reqReject, reqResolve } from './interceptors'
|
||||
|
||||
export function createAxios(options = {}) {
|
||||
const defaultOptions = {
|
||||
@@ -10,10 +10,10 @@ export function createAxios(options = {}) {
|
||||
...options,
|
||||
})
|
||||
service.interceptors.request.use(reqResolve, reqReject)
|
||||
service.interceptors.response.use(repResolve, repReject)
|
||||
service.interceptors.response.use(resResolve, resReject)
|
||||
return service
|
||||
}
|
||||
|
||||
export default createAxios({
|
||||
export const request = createAxios({
|
||||
baseURL: import.meta.env.VITE_BASE_API,
|
||||
})
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { getToken } from '@/utils/token'
|
||||
import { toLogin } from '@/utils/auth'
|
||||
import { getToken } from '@/utils'
|
||||
import { resolveResError } from './helpers'
|
||||
|
||||
export function reqResolve(config) {
|
||||
@@ -10,9 +9,7 @@ export function reqResolve(config) {
|
||||
|
||||
const token = getToken()
|
||||
if (!token) {
|
||||
// * 未登录或者token过期的情况下,跳转登录页重新登录
|
||||
toLogin()
|
||||
return Promise.reject({ code: '-1', message: '未登录' })
|
||||
return Promise.reject({ code: 401, message: '登录已过期,请重新登录!' })
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -28,19 +25,34 @@ export function reqReject(error) {
|
||||
return Promise.reject(error)
|
||||
}
|
||||
|
||||
export function repResolve(response) {
|
||||
const { noNeedTip } = response.config
|
||||
if (response.data?.code !== 0) {
|
||||
const { code, message } = resolveResError(response?.data)
|
||||
!noNeedTip && $message.error(message)
|
||||
return Promise.reject({ code, message, error: response?.data })
|
||||
export function resResolve(response) {
|
||||
// TODO: 处理不同的 response.headers
|
||||
const { data, status, config, statusText } = response
|
||||
if (data?.code !== 0) {
|
||||
const code = data?.code ?? status
|
||||
|
||||
/** 根据code处理对应的操作,并返回处理后的message */
|
||||
const message = resolveResError(code, data?.message ?? statusText)
|
||||
|
||||
/** 需要错误提醒 */
|
||||
!config.noNeedTip && $message.error(message)
|
||||
return Promise.reject({ code, message, error: data || response })
|
||||
}
|
||||
return Promise.resolve(response?.data)
|
||||
return Promise.resolve(data)
|
||||
}
|
||||
|
||||
export function repReject(error) {
|
||||
const { noNeedTip } = error.response?.config || error.config
|
||||
const { code, message } = resolveResError(error.response?.data)
|
||||
!noNeedTip && $message.error(message)
|
||||
return Promise.reject({ code, message, error })
|
||||
export function resReject(error) {
|
||||
if (!error || !error.response) {
|
||||
const code = error?.code
|
||||
/** 根据code处理对应的操作,并返回处理后的message */
|
||||
const message = resolveResError(code, error.message)
|
||||
$message?.error(message)
|
||||
return Promise.reject({ code, message, error })
|
||||
}
|
||||
const { data, status, config } = error.response
|
||||
const code = data?.code ?? status
|
||||
const message = resolveResError(code, data?.message ?? error.message)
|
||||
/** 需要错误提醒 */
|
||||
!config?.noNeedTip && $message.error(message)
|
||||
return Promise.reject({ code, message, error: error.response?.data || error.response })
|
||||
}
|
||||
|
||||
@@ -1,76 +1,4 @@
|
||||
import dayjs from 'dayjs'
|
||||
|
||||
/**
|
||||
* @desc 格式化时间
|
||||
* @param {(Object|string|number)} time
|
||||
* @param {string} format
|
||||
* @returns {string | null}
|
||||
*/
|
||||
export function formatDateTime(time = undefined, format = 'YYYY-MM-DD HH:mm:ss') {
|
||||
return dayjs(time).format(format)
|
||||
}
|
||||
|
||||
export function formatDate(date = undefined, format = 'YYYY-MM-DD') {
|
||||
return formatDateTime(date, format)
|
||||
}
|
||||
|
||||
/**
|
||||
* @desc 函数节流
|
||||
* @param {Function} fn
|
||||
* @param {Number} wait
|
||||
* @returns {Function}
|
||||
*/
|
||||
export function throttle(fn, wait) {
|
||||
var context, args
|
||||
var previous = 0
|
||||
|
||||
return function () {
|
||||
var now = +new Date()
|
||||
context = this
|
||||
args = arguments
|
||||
if (now - previous > wait) {
|
||||
fn.apply(context, args)
|
||||
previous = now
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @desc 函数防抖
|
||||
* @param {Function} func
|
||||
* @param {number} wait
|
||||
* @param {boolean} immediate
|
||||
* @return {*}
|
||||
*/
|
||||
export function debounce(method, wait, immediate) {
|
||||
let timeout
|
||||
return function (...args) {
|
||||
let context = this
|
||||
if (timeout) {
|
||||
clearTimeout(timeout)
|
||||
}
|
||||
// 立即执行需要两个条件,一是immediate为true,二是timeout未被赋值或被置为null
|
||||
if (immediate) {
|
||||
/**
|
||||
* 如果定时器不存在,则立即执行,并设置一个定时器,wait毫秒后将定时器置为null
|
||||
* 这样确保立即执行后wait毫秒内不会被再次触发
|
||||
*/
|
||||
let callNow = !timeout
|
||||
timeout = setTimeout(() => {
|
||||
timeout = null
|
||||
}, wait)
|
||||
if (callNow) {
|
||||
method.apply(context, args)
|
||||
}
|
||||
} else {
|
||||
// 如果immediate为false,则函数wait毫秒后执行
|
||||
timeout = setTimeout(() => {
|
||||
/**
|
||||
* args是一个类数组对象,所以使用fn.apply
|
||||
* 也可写作method.call(context, ...args)
|
||||
*/
|
||||
method.apply(context, args)
|
||||
}, wait)
|
||||
}
|
||||
}
|
||||
}
|
||||
export * from './common'
|
||||
export * from './storage'
|
||||
export * from './http'
|
||||
export * from './auth'
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { isNullOrUndef } from '@/utils/is'
|
||||
import { isNullOrUndef } from '@/utils'
|
||||
|
||||
class Storage {
|
||||
constructor(option) {
|
||||
@@ -10,8 +10,8 @@
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<div f-c-c mt-20 w-350 rounded-10 b-1 bc-ccc>
|
||||
<div flex w-360 flex-wrap justify-around p-10>
|
||||
<div f-c-c flex-col mt-20 w-350>
|
||||
<div flex flex-wrap justify-around p-10 rounded-10 b-1 bc-ccc>
|
||||
<div w-50 h-50 b-1 rounded-5 f-c-c p-10 m-20>
|
||||
<span w-6 h-6 rounded-3 bg-black></span>
|
||||
</div>
|
||||
@@ -34,12 +34,12 @@
|
||||
<span w-6 h-6 rounded-3 bg-black></span>
|
||||
</div>
|
||||
</div>
|
||||
<div w-50 h-50 b-1 rounded-5 f-c-c flex-col p-10 m-20>
|
||||
<div w-50 h-50 b-1 rounded-5 flex-col justify-between items-center p-10 m-20>
|
||||
<div flex w-full justify-between>
|
||||
<span w-6 h-6 rounded-3 bg-black></span>
|
||||
<span w-6 h-6 rounded-3 bg-black></span>
|
||||
</div>
|
||||
<span w-6 h-6 rounded-3 bg-black></span>
|
||||
<div w-6 h-6 rounded-3 bg-black></div>
|
||||
<div flex w-full justify-between>
|
||||
<span w-6 h-6 rounded-3 bg-black></span>
|
||||
<span w-6 h-6 rounded-3 bg-black></span>
|
||||
@@ -60,7 +60,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<h2 font-normal text-14 mt-10 color-gray>Flex 骰子</h2>
|
||||
</div>
|
||||
<h2 font-normal text-14 text-center w-350 mt-10 color-gray>Flex 骰子</h2>
|
||||
</CommonPage>
|
||||
</template>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import request from '@/utils/http'
|
||||
import { request } from '@/utils'
|
||||
|
||||
export default {
|
||||
getPosts: (params = {}) => request.get('posts', { params }),
|
||||
|
||||
@@ -82,11 +82,9 @@
|
||||
|
||||
<script setup>
|
||||
import { NButton, NSwitch } from 'naive-ui'
|
||||
import { formatDateTime } from '@/utils'
|
||||
import { renderIcon } from '@/utils/icon'
|
||||
import { formatDateTime, renderIcon, isNullOrUndef } from '@/utils'
|
||||
import { useCRUD } from '@/composables'
|
||||
import api from './api'
|
||||
import { isNullOrUndef } from '@/utils/is'
|
||||
|
||||
defineOptions({ name: 'CrudTable' })
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import request from '@/utils/http'
|
||||
import { request } from '@/utils'
|
||||
|
||||
export default {
|
||||
login: (data) => request.post('/auth/login', data, { noNeedToken: true }),
|
||||
|
||||
@@ -46,8 +46,7 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { lStorage } from '@/utils/cache'
|
||||
import { setToken } from '@/utils/token'
|
||||
import { lStorage, setToken } from '@/utils'
|
||||
import { useStorage } from '@vueuse/core'
|
||||
import bgImg from '@/assets/images/login_bg.webp'
|
||||
import api from './api'
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { useUserStore } from '@/store/modules/user'
|
||||
import { useUserStore } from '@/store'
|
||||
|
||||
const userStore = useUserStore()
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user