版本更新:
1. 修复:移动端头像剪切功能 2. 修复:系统展示头像展示时从固定静态文件改为接口数据 3. 更新:升级PC端vue-element-plus-admin版本到1.9.2 4. 更新:文件上传接口 5. 更新:依赖库更新,使用python10版本 6. 新增:kinit-api 命令创建app目录
This commit is contained in:
parent
a7283b70f8
commit
1426e118f2
@ -42,7 +42,7 @@
|
||||
"mockjs": "^1.1.0",
|
||||
"moment": "^2.29.4",
|
||||
"nprogress": "^0.2.0",
|
||||
"pinia": "^2.0.29",
|
||||
"pinia": "2.0.29",
|
||||
"qrcode": "^1.5.1",
|
||||
"qs": "^6.11.0",
|
||||
"url": "^0.11.0",
|
||||
@ -96,7 +96,6 @@
|
||||
"stylelint-order": "^6.0.1",
|
||||
"terser": "^5.16.1",
|
||||
"typescript": "4.9.4",
|
||||
"unplugin-vue-define-options": "^1.1.4",
|
||||
"vite": "4.0.4",
|
||||
"vite-plugin-ejs": "^1.6.4",
|
||||
"vite-plugin-eslint": "^1.8.1",
|
||||
|
@ -50,7 +50,6 @@ watch(
|
||||
)
|
||||
|
||||
const dialogStyle = computed(() => {
|
||||
console.log(unref(dialogHeight))
|
||||
return {
|
||||
height: unref(dialogHeight)
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ import { useI18n } from '@/hooks/web/useI18n'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { useDesign } from '@/hooks/web/useDesign'
|
||||
import { useAuthStoreWithOut } from '@/store/modules/auth'
|
||||
import avatar from '@/assets/imgs/avatar.jpg'
|
||||
|
||||
const { getPrefixCls } = useDesign()
|
||||
|
||||
@ -46,7 +47,7 @@ const user = authStore.getUser
|
||||
<ElDropdown :class="prefixCls" trigger="click">
|
||||
<div class="flex items-center">
|
||||
<img
|
||||
src="@/assets/imgs/avatar.jpg"
|
||||
:src="user.avatar ? user.avatar : avatar"
|
||||
alt=""
|
||||
class="w-[calc(var(--logo-height)-25px)] rounded-[50%]"
|
||||
/>
|
||||
|
@ -3,6 +3,7 @@ const config: {
|
||||
unauthorized_code: number | string
|
||||
default_headers: AxiosHeaders
|
||||
request_timeout: number
|
||||
token: string
|
||||
} = {
|
||||
/**
|
||||
* 接口成功返回状态码
|
||||
@ -22,7 +23,13 @@ const config: {
|
||||
* 默认接口请求类型
|
||||
* 可选值:application/x-www-form-urlencoded multipart/form-data
|
||||
*/
|
||||
default_headers: 'application/json'
|
||||
default_headers: 'application/json',
|
||||
|
||||
/**
|
||||
* 存储Token字段
|
||||
* 关联 config/axios/service/service.interceptors
|
||||
*/
|
||||
token: 'Token'
|
||||
}
|
||||
|
||||
export { config }
|
||||
|
@ -1,15 +1,12 @@
|
||||
import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse, AxiosError } from 'axios'
|
||||
import axios, { AxiosInstance, InternalAxiosRequestConfig, AxiosResponse, AxiosError } from 'axios'
|
||||
import { useCache } from '@/hooks/web/useCache'
|
||||
import { useAppStore } from '@/store/modules/app'
|
||||
import { useAuthStore } from '@/store/modules/auth'
|
||||
import qs from 'qs'
|
||||
import { config } from './config'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { useAuthStore } from '@/store/modules/auth'
|
||||
|
||||
const { result_code, unauthorized_code, request_timeout } = config
|
||||
const { result_code, unauthorized_code, request_timeout, token } = config
|
||||
|
||||
const appStore = useAppStore()
|
||||
const authStore = useAuthStore()
|
||||
const { wsCache } = useCache()
|
||||
|
||||
// 创建axios实例
|
||||
@ -21,10 +18,10 @@ const service: AxiosInstance = axios.create({
|
||||
|
||||
// request拦截器
|
||||
service.interceptors.request.use(
|
||||
(config: AxiosRequestConfig) => {
|
||||
const token = wsCache.get(appStore.getToken)
|
||||
if (token !== '') {
|
||||
;(config.headers as any)['Authorization'] = token // 让每个请求携带自定义token 请根据实际情况自行修改
|
||||
(config: InternalAxiosRequestConfig) => {
|
||||
const _token = wsCache.get(token)
|
||||
if (_token !== '') {
|
||||
;(config.headers as any)['Authorization'] = _token // 让每个请求携带自定义token 请根据实际情况自行修改
|
||||
}
|
||||
if (
|
||||
config.method === 'post' &&
|
||||
@ -66,6 +63,7 @@ service.interceptors.response.use(
|
||||
} else if (response.data.code === unauthorized_code) {
|
||||
// 请重新登录
|
||||
ElMessage.error(response.data.message)
|
||||
const authStore = useAuthStore()
|
||||
authStore.logout()
|
||||
} else {
|
||||
ElMessage.error(response.data.message)
|
||||
@ -75,11 +73,11 @@ service.interceptors.response.use(
|
||||
console.log('err' + error)
|
||||
let { message } = error
|
||||
if (message == 'Network Error') {
|
||||
message = '后端接口连接异常'
|
||||
message = '系统接口连接异常'
|
||||
} else if (message.includes('timeout')) {
|
||||
message = '系统接口请求超时'
|
||||
} else if (message.includes('Request failed with status code')) {
|
||||
message = '系统接口' + message.substr(message.length - 3) + '异常'
|
||||
message = '系统接口状态码异常'
|
||||
}
|
||||
ElMessage.error(message)
|
||||
return Promise.reject(error)
|
||||
|
@ -3,16 +3,16 @@ import { useI18n } from '@/hooks/web/useI18n'
|
||||
import { useCache } from '@/hooks/web/useCache'
|
||||
import { intersection } from 'lodash-es'
|
||||
import { isArray } from '@/utils/is'
|
||||
import { useAppStoreWithOut } from '@/store/modules/app'
|
||||
import { useAuthStoreWithOut } from '@/store/modules/auth'
|
||||
|
||||
const { t } = useI18n()
|
||||
const { wsCache } = useCache()
|
||||
const appStore = useAppStoreWithOut()
|
||||
const authStore = useAuthStoreWithOut()
|
||||
|
||||
// 全部权限
|
||||
const all_permission = ['*.*.*']
|
||||
const hasPermission = (value: string | string[]): boolean => {
|
||||
const permissions = wsCache.get(appStore.getUserInfo).permissions as string[]
|
||||
const permissions = wsCache.get(authStore.getUserInfo).permissions as string[]
|
||||
if (!value) {
|
||||
throw new Error(t('permission.hasPermission'))
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
import router from './router'
|
||||
import { useAppStoreWithOut } from '@/store/modules/app'
|
||||
import { useCache } from '@/hooks/web/useCache'
|
||||
import type { RouteRecordRaw } from 'vue-router'
|
||||
import { useTitle } from '@/hooks/web/useTitle'
|
||||
@ -11,7 +10,6 @@ import { useAuthStoreWithOut } from '@/store/modules/auth'
|
||||
|
||||
const permissionStore = usePermissionStoreWithOut()
|
||||
|
||||
const appStore = useAppStoreWithOut()
|
||||
const authStore = useAuthStoreWithOut()
|
||||
|
||||
const { wsCache } = useCache()
|
||||
@ -25,14 +23,14 @@ const whiteList = ['/login', '/docs/privacy', '/docs/agreement'] // 不重定向
|
||||
router.beforeEach(async (to, from, next) => {
|
||||
start()
|
||||
loadStart()
|
||||
if (wsCache.get(appStore.getUserInfo)) {
|
||||
if (wsCache.get(authStore.getUserInfo)) {
|
||||
if (to.path === '/login') {
|
||||
next({ path: '/' })
|
||||
} else if (to.path === '/reset/password') {
|
||||
next()
|
||||
} else {
|
||||
if (!authStore.getIsUser) {
|
||||
await authStore.getUserInfo()
|
||||
await authStore.getUserInfoAction()
|
||||
}
|
||||
if (permissionStore.getIsAddRouters) {
|
||||
next()
|
||||
|
@ -27,7 +27,6 @@ interface AppState {
|
||||
pageLoading: boolean
|
||||
layout: LayoutType
|
||||
title: string
|
||||
userInfo: string
|
||||
isDark: boolean
|
||||
currentSize: ElementPlusSize
|
||||
sizeMap: ElementPlusSize[]
|
||||
@ -38,14 +37,11 @@ interface AppState {
|
||||
logoImage: string
|
||||
footerContent: string
|
||||
icpNumber: string
|
||||
token: string
|
||||
}
|
||||
|
||||
export const useAppStore = defineStore('app', {
|
||||
state: (): AppState => {
|
||||
return {
|
||||
userInfo: 'userInfo', // 登录信息存储字段-建议每个项目换一个字段,避免与其他项目冲突
|
||||
token: 'Token', // 存储Token字段
|
||||
sizeMap: ['default', 'large', 'small'],
|
||||
mobile: false, // 是否是移动端
|
||||
title: import.meta.env.VITE_APP_TITLE, // 标题
|
||||
@ -164,12 +160,6 @@ export const useAppStore = defineStore('app', {
|
||||
getTitle(): string {
|
||||
return this.title
|
||||
},
|
||||
getUserInfo(): string {
|
||||
return this.userInfo
|
||||
},
|
||||
getToken(): string {
|
||||
return this.token
|
||||
},
|
||||
getIsDark(): boolean {
|
||||
return this.isDark
|
||||
},
|
||||
|
@ -2,15 +2,15 @@ import { defineStore } from 'pinia'
|
||||
import { store } from '../index'
|
||||
import { UserLoginType } from '@/api/login/types'
|
||||
import { loginApi } from '@/api/login'
|
||||
import { useAppStore } from '@/store/modules/app'
|
||||
import { useCache } from '@/hooks/web/useCache'
|
||||
import { getCurrentUserInfo } from '@/api/vadmin/auth/user'
|
||||
import { resetRouter } from '@/router'
|
||||
import { config } from '@/config/axios/config'
|
||||
import { useTagsViewStore } from '@/store/modules/tagsView'
|
||||
|
||||
const appStore = useAppStore()
|
||||
const { token } = config
|
||||
|
||||
const { wsCache } = useCache()
|
||||
const tagsViewStore = useTagsViewStore()
|
||||
|
||||
export interface UserState {
|
||||
id?: number
|
||||
@ -24,6 +24,7 @@ export interface UserState {
|
||||
}
|
||||
|
||||
export interface AuthState {
|
||||
userInfo: string
|
||||
user: UserState
|
||||
isUser: boolean
|
||||
}
|
||||
@ -31,6 +32,7 @@ export interface AuthState {
|
||||
export const useAuthStore = defineStore('auth', {
|
||||
state: (): AuthState => {
|
||||
return {
|
||||
userInfo: 'userInfo', // 登录信息存储字段-建议每个项目换一个字段,避免与其他项目冲突
|
||||
user: {},
|
||||
isUser: false
|
||||
}
|
||||
@ -41,6 +43,9 @@ export const useAuthStore = defineStore('auth', {
|
||||
},
|
||||
getIsUser(): boolean {
|
||||
return this.isUser
|
||||
},
|
||||
getUserInfo(): string {
|
||||
return this.userInfo
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
@ -48,10 +53,9 @@ export const useAuthStore = defineStore('auth', {
|
||||
formData.platform = '0'
|
||||
const res = await loginApi(formData)
|
||||
if (res) {
|
||||
wsCache.set(appStore.getToken, `${res.data.token_type} ${res.data.access_token}`)
|
||||
wsCache.set(token, `${res.data.token_type} ${res.data.access_token}`)
|
||||
// 存储用户信息
|
||||
const auth = useAuthStore()
|
||||
await auth.getUserInfo()
|
||||
await this.getUserInfoAction()
|
||||
}
|
||||
return res
|
||||
},
|
||||
@ -59,6 +63,7 @@ export const useAuthStore = defineStore('auth', {
|
||||
wsCache.clear()
|
||||
this.user = {}
|
||||
this.isUser = false
|
||||
const tagsViewStore = useTagsViewStore()
|
||||
tagsViewStore.delAllViews()
|
||||
resetRouter()
|
||||
window.location.href = '/login'
|
||||
@ -68,11 +73,11 @@ export const useAuthStore = defineStore('auth', {
|
||||
this.user.name = data.name
|
||||
this.user.nickname = data.nickname
|
||||
this.user.telephone = data.telephone
|
||||
wsCache.set(appStore.getUserInfo, this.user)
|
||||
wsCache.set(this.userInfo, this.user)
|
||||
},
|
||||
async getUserInfo() {
|
||||
async getUserInfoAction() {
|
||||
const res = await getCurrentUserInfo()
|
||||
wsCache.set(appStore.getUserInfo, res.data)
|
||||
wsCache.set(this.userInfo, res.data)
|
||||
this.isUser = true
|
||||
this.user = res.data
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import { ref, reactive } from 'vue'
|
||||
import { CountTo } from '@/components/CountTo'
|
||||
import { formatTime } from '@/utils'
|
||||
import { Highlight } from '@/components/Highlight'
|
||||
import { useAuthStoreWithOut } from '@/store/modules/auth'
|
||||
import {
|
||||
getCountApi,
|
||||
getProjectApi,
|
||||
@ -21,7 +22,7 @@ import type {
|
||||
Shortcuts
|
||||
} from '@/api/dashboard/workplace/types'
|
||||
import { useCache } from '@/hooks/web/useCache'
|
||||
import { useAppStoreWithOut } from '@/store/modules/app'
|
||||
import avatar from '@/assets/imgs/avatar.jpg'
|
||||
|
||||
const { wsCache } = useCache()
|
||||
|
||||
@ -96,9 +97,9 @@ getAllApi()
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
const appStore = useAppStoreWithOut()
|
||||
const authStore = useAuthStoreWithOut()
|
||||
|
||||
const user = wsCache.get(appStore.getUserInfo)
|
||||
const user = wsCache.get(authStore.getUserInfo)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@ -109,7 +110,7 @@ const user = wsCache.get(appStore.getUserInfo)
|
||||
<ElCol :xl="12" :lg="12" :md="12" :sm="24" :xs="24">
|
||||
<div class="flex items-center">
|
||||
<img
|
||||
src="@/assets/imgs/avatar.jpg"
|
||||
:src="user.avatar ? user.avatar : avatar"
|
||||
alt=""
|
||||
class="w-70px h-70px rounded-[50%] mr-20px"
|
||||
/>
|
||||
|
@ -137,7 +137,7 @@ const signIn = async () => {
|
||||
// 重置密码
|
||||
push({ path: '/reset/password' })
|
||||
} else {
|
||||
// 是否使用动态路由
|
||||
// 获取动态路由
|
||||
getMenu()
|
||||
}
|
||||
} else {
|
||||
|
@ -10,6 +10,7 @@ import type { UploadProps } from 'element-plus'
|
||||
import { useCache } from '@/hooks/web/useCache'
|
||||
import { useAppStore } from '@/store/modules/app'
|
||||
import { propTypes } from '@/utils/propTypes'
|
||||
import { config } from '@/config/axios/config'
|
||||
|
||||
const props = defineProps({
|
||||
tabId: propTypes.number
|
||||
@ -79,8 +80,9 @@ const getData = async () => {
|
||||
const appStore = useAppStore()
|
||||
const { wsCache } = useCache()
|
||||
const loading = ref(false)
|
||||
const { token } = config
|
||||
|
||||
const token = wsCache.get(appStore.getToken)
|
||||
const _token = wsCache.get(token)
|
||||
|
||||
const save = async () => {
|
||||
const formRef = unref(elFormRef)
|
||||
@ -120,7 +122,7 @@ getData()
|
||||
:on-success="handleLogoUploadSuccess"
|
||||
accept="image/jpeg,image/gif,image/png"
|
||||
name="file"
|
||||
:headers="{ Authorization: token }"
|
||||
:headers="{ Authorization: _token }"
|
||||
>
|
||||
<img v-if="form.web_logo" :src="form.web_logo" class="logo-image" />
|
||||
<ElIcon v-else class="logo-image-uploader-icon"
|
||||
@ -139,7 +141,7 @@ getData()
|
||||
:on-success="handleICOUploadSuccess"
|
||||
accept="image/x-icon"
|
||||
name="file"
|
||||
:headers="{ Authorization: token }"
|
||||
:headers="{ Authorization: _token }"
|
||||
>
|
||||
<img v-if="form.web_ico" :src="form.web_ico" class="ico-image" />
|
||||
<ElIcon v-else class="ico-image-uploader-icon"
|
||||
|
@ -29,8 +29,7 @@
|
||||
"element-plus/global",
|
||||
"@types/intro.js",
|
||||
"@types/qrcode",
|
||||
"vite-plugin-svg-icons/client",
|
||||
"unplugin-vue-define-options/macros-global"
|
||||
"vite-plugin-svg-icons/client"
|
||||
],
|
||||
"typeRoots": ["./node_modules/@types/", "./types"]
|
||||
},
|
||||
|
@ -9,7 +9,6 @@ import EslintPlugin from 'vite-plugin-eslint'
|
||||
import PurgeIcons from 'vite-plugin-purge-icons'
|
||||
import VueI18nPlugin from "@intlify/unplugin-vue-i18n/vite"
|
||||
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'
|
||||
import DefineOptions from "unplugin-vue-define-options/vite"
|
||||
import { createStyleImportPlugin, ElementPlusResolve } from 'vite-plugin-style-import'
|
||||
import { ViteEjsPlugin } from "vite-plugin-ejs"
|
||||
|
||||
@ -60,18 +59,6 @@ export default ({ command, mode }: ConfigEnv): UserConfig => {
|
||||
svgoOptions: true
|
||||
}),
|
||||
PurgeIcons(),
|
||||
// viteMockServe({
|
||||
// ignore: /^\_/,
|
||||
// mockPath: 'mock',
|
||||
// localEnabled: !isBuild,
|
||||
// prodEnabled: isBuild,
|
||||
// injectCode: `
|
||||
// import { setupProdMockServer } from '../mock/_createProductionServer'
|
||||
|
||||
// setupProdMockServer()
|
||||
// `
|
||||
// }),
|
||||
DefineOptions(),
|
||||
ViteEjsPlugin({
|
||||
title: env.VITE_APP_TITLE
|
||||
})
|
||||
@ -102,7 +89,6 @@ export default ({ command, mode }: ConfigEnv): UserConfig => {
|
||||
minify: 'terser',
|
||||
outDir: env.VITE_OUT_DIR || 'dist',
|
||||
sourcemap: env.VITE_SOURCEMAP === 'true' ? 'inline' : false,
|
||||
// brotliSize: false,
|
||||
terserOptions: {
|
||||
compress: {
|
||||
drop_debugger: env.VITE_DROP_DEBUGGER === 'true',
|
||||
|
@ -11,13 +11,13 @@ from fastapi.security import OAuth2PasswordBearer
|
||||
"""
|
||||
系统版本
|
||||
"""
|
||||
VERSION = "1.4.3"
|
||||
VERSION = "1.5.0"
|
||||
|
||||
"""安全警告: 不要在生产中打开调试运行!"""
|
||||
DEBUG = True
|
||||
|
||||
"""是否开启演示功能:取消所有POST,DELETE,PUT操作权限"""
|
||||
DEMO = False
|
||||
DEMO = not DEBUG
|
||||
"""演示功能白名单"""
|
||||
DEMO_WHITE_LIST_PATH = [
|
||||
"/auth/login/",
|
||||
@ -105,7 +105,7 @@ EVENTS = [
|
||||
# 默认密码,"0" 默认为手机号后六位
|
||||
DEFAULT_PASSWORD = "0"
|
||||
# 是否开启保存登录日志
|
||||
LOGIN_LOG_RECORD = True
|
||||
LOGIN_LOG_RECORD = not DEBUG
|
||||
# 是否开启保存每次请求日志到本地
|
||||
REQUEST_LOG_RECORD = True
|
||||
# 是否开启每次操作日志记录到MongoDB数据库
|
||||
|
Loading…
x
Reference in New Issue
Block a user