feat: 更新mini分支
This commit is contained in:
parent
a1e89b7c8a
commit
607b73a7b3
|
@ -2,7 +2,7 @@
|
||||||
NODE_ENV=development
|
NODE_ENV=development
|
||||||
|
|
||||||
# 接口前缀
|
# 接口前缀
|
||||||
VITE_API_BASE_PATH=base
|
VITE_API_BASE_PATH=
|
||||||
|
|
||||||
# 打包路径
|
# 打包路径
|
||||||
VITE_BASE_PATH=/
|
VITE_BASE_PATH=/
|
||||||
|
|
2
.env.dev
2
.env.dev
|
@ -2,7 +2,7 @@
|
||||||
NODE_ENV=production
|
NODE_ENV=production
|
||||||
|
|
||||||
# 接口前缀
|
# 接口前缀
|
||||||
VITE_API_BASE_PATH=dev
|
VITE_API_BASE_PATH=
|
||||||
|
|
||||||
# 打包路径
|
# 打包路径
|
||||||
VITE_BASE_PATH=/dist-dev/
|
VITE_BASE_PATH=/dist-dev/
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
NODE_ENV=production
|
NODE_ENV=production
|
||||||
|
|
||||||
# 接口前缀
|
# 接口前缀
|
||||||
VITE_API_BASE_PATH=pro
|
VITE_API_BASE_PATH=
|
||||||
|
|
||||||
# 打包路径
|
# 打包路径
|
||||||
VITE_BASE_PATH=/vue-element-plus-admin/
|
VITE_BASE_PATH=/vue-element-plus-admin/
|
||||||
|
|
2
.env.pro
2
.env.pro
|
@ -2,7 +2,7 @@
|
||||||
NODE_ENV=production
|
NODE_ENV=production
|
||||||
|
|
||||||
# 接口前缀
|
# 接口前缀
|
||||||
VITE_API_BASE_PATH=pro
|
VITE_API_BASE_PATH=
|
||||||
|
|
||||||
# 打包路径
|
# 打包路径
|
||||||
VITE_BASE_PATH=/
|
VITE_BASE_PATH=/
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { createProdMockServer } from 'vite-plugin-mock/es/createProdMockServer'
|
import { createProdMockServer } from 'vite-plugin-mock/es/createProdMockServer'
|
||||||
|
|
||||||
const modules = import.meta.glob('./**/*.ts', {
|
const modules = import.meta.glob('./**/*.mock.ts', {
|
||||||
import: 'default',
|
import: 'default',
|
||||||
eager: true
|
eager: true
|
||||||
})
|
})
|
||||||
|
|
|
@ -0,0 +1,91 @@
|
||||||
|
import { MockMethod } from 'vite-plugin-mock'
|
||||||
|
import { SUCCESS_CODE } from '@/constants'
|
||||||
|
|
||||||
|
const timeout = 1000
|
||||||
|
|
||||||
|
const adminList = [
|
||||||
|
{
|
||||||
|
path: '/level',
|
||||||
|
component: '#',
|
||||||
|
redirect: '/level/menu1/menu1-1/menu1-1-1',
|
||||||
|
name: 'Level',
|
||||||
|
meta: {
|
||||||
|
title: 'router.level',
|
||||||
|
icon: 'carbon:skill-level-advanced'
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: 'menu1',
|
||||||
|
name: 'Menu1',
|
||||||
|
component: '##',
|
||||||
|
redirect: '/level/menu1/menu1-1/menu1-1-1',
|
||||||
|
meta: {
|
||||||
|
title: 'router.menu1'
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: 'menu1-1',
|
||||||
|
name: 'Menu11',
|
||||||
|
component: '##',
|
||||||
|
redirect: '/level/menu1/menu1-1/menu1-1-1',
|
||||||
|
meta: {
|
||||||
|
title: 'router.menu11',
|
||||||
|
alwaysShow: true
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: 'menu1-1-1',
|
||||||
|
name: 'Menu111',
|
||||||
|
component: 'views/Level/Menu111',
|
||||||
|
meta: {
|
||||||
|
title: 'router.menu111'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'menu1-2',
|
||||||
|
name: 'Menu12',
|
||||||
|
component: 'views/Level/Menu12',
|
||||||
|
meta: {
|
||||||
|
title: 'router.menu12'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'menu2',
|
||||||
|
name: 'Menu2Demo',
|
||||||
|
component: 'views/Level/Menu2',
|
||||||
|
meta: {
|
||||||
|
title: 'router.menu2'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
const testList: string[] = [
|
||||||
|
'/level',
|
||||||
|
'/level/menu1',
|
||||||
|
'/level/menu1/menu1-1',
|
||||||
|
'/level/menu1/menu1-1/menu1-1-1',
|
||||||
|
'/level/menu1/menu1-2',
|
||||||
|
'/level/menu2'
|
||||||
|
]
|
||||||
|
|
||||||
|
export default [
|
||||||
|
// 列表接口
|
||||||
|
{
|
||||||
|
url: '/mock/role/list',
|
||||||
|
method: 'get',
|
||||||
|
timeout,
|
||||||
|
response: ({ query }) => {
|
||||||
|
const { roleName } = query
|
||||||
|
return {
|
||||||
|
code: SUCCESS_CODE,
|
||||||
|
data: roleName === 'admin' ? adminList : testList
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
] as MockMethod[]
|
|
@ -1,544 +0,0 @@
|
||||||
import config from '@/config/axios/config'
|
|
||||||
import { MockMethod } from 'vite-plugin-mock'
|
|
||||||
|
|
||||||
const { code } = config
|
|
||||||
|
|
||||||
const timeout = 1000
|
|
||||||
|
|
||||||
const adminList = [
|
|
||||||
{
|
|
||||||
path: '/dashboard',
|
|
||||||
component: '#',
|
|
||||||
redirect: '/dashboard/analysis',
|
|
||||||
name: 'Dashboard',
|
|
||||||
meta: {
|
|
||||||
title: 'router.dashboard',
|
|
||||||
icon: 'ant-design:dashboard-filled',
|
|
||||||
alwaysShow: true
|
|
||||||
},
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
path: 'analysis',
|
|
||||||
component: 'views/Dashboard/Analysis',
|
|
||||||
name: 'Analysis',
|
|
||||||
meta: {
|
|
||||||
title: 'router.analysis',
|
|
||||||
noCache: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'workplace',
|
|
||||||
component: 'views/Dashboard/Workplace',
|
|
||||||
name: 'Workplace',
|
|
||||||
meta: {
|
|
||||||
title: 'router.workplace',
|
|
||||||
noCache: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/external-link',
|
|
||||||
component: '#',
|
|
||||||
meta: {},
|
|
||||||
name: 'ExternalLink',
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
path: 'https://element-plus-admin-doc.cn/',
|
|
||||||
name: 'DocumentLink',
|
|
||||||
meta: {
|
|
||||||
title: 'router.document',
|
|
||||||
icon: 'clarity:document-solid'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/guide',
|
|
||||||
component: '#',
|
|
||||||
name: 'Guide',
|
|
||||||
meta: {},
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
path: 'index',
|
|
||||||
component: 'views/Guide/Guide',
|
|
||||||
name: 'GuideDemo',
|
|
||||||
meta: {
|
|
||||||
title: 'router.guide',
|
|
||||||
icon: 'cib:telegram-plane'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/components',
|
|
||||||
component: '#',
|
|
||||||
redirect: '/components/form/default-form',
|
|
||||||
name: 'ComponentsDemo',
|
|
||||||
meta: {
|
|
||||||
title: 'router.component',
|
|
||||||
icon: 'bx:bxs-component',
|
|
||||||
alwaysShow: true
|
|
||||||
},
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
path: 'form',
|
|
||||||
component: '##',
|
|
||||||
name: 'Form',
|
|
||||||
meta: {
|
|
||||||
title: 'router.form',
|
|
||||||
alwaysShow: true
|
|
||||||
},
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
path: 'default-form',
|
|
||||||
component: 'views/Components/Form/DefaultForm',
|
|
||||||
name: 'DefaultForm',
|
|
||||||
meta: {
|
|
||||||
title: 'router.defaultForm'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'use-form',
|
|
||||||
component: 'views/Components/Form/UseFormDemo',
|
|
||||||
name: 'UseForm',
|
|
||||||
meta: {
|
|
||||||
title: 'UseForm'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'table',
|
|
||||||
component: '##',
|
|
||||||
redirect: '/components/table/default-table',
|
|
||||||
name: 'TableDemo',
|
|
||||||
meta: {
|
|
||||||
title: 'router.table',
|
|
||||||
alwaysShow: true
|
|
||||||
},
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
path: 'default-table',
|
|
||||||
component: 'views/Components/Table/DefaultTable',
|
|
||||||
name: 'DefaultTable',
|
|
||||||
meta: {
|
|
||||||
title: 'router.defaultTable'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'use-table',
|
|
||||||
component: 'views/Components/Table/UseTableDemo',
|
|
||||||
name: 'UseTable',
|
|
||||||
meta: {
|
|
||||||
title: 'UseTable'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'tree-table',
|
|
||||||
component: 'views/Components/Table/TreeTable',
|
|
||||||
name: 'TreeTable',
|
|
||||||
meta: {
|
|
||||||
title: 'router.TreeTable'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'table-image-preview',
|
|
||||||
component: 'views/Components/Table/TableImagePreview',
|
|
||||||
name: 'TableImagePreview',
|
|
||||||
meta: {
|
|
||||||
title: 'router.PicturePreview'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'ref-table',
|
|
||||||
component: 'views/Components/Table/RefTable',
|
|
||||||
name: 'RefTable',
|
|
||||||
meta: {
|
|
||||||
title: 'RefTable'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'editor-demo',
|
|
||||||
component: '##',
|
|
||||||
redirect: '/components/editor-demo/editor',
|
|
||||||
name: 'EditorDemo',
|
|
||||||
meta: {
|
|
||||||
title: 'router.editor',
|
|
||||||
alwaysShow: true
|
|
||||||
},
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
path: 'editor',
|
|
||||||
component: 'views/Components/Editor/Editor',
|
|
||||||
name: 'Editor',
|
|
||||||
meta: {
|
|
||||||
title: 'router.richText'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'search',
|
|
||||||
component: 'views/Components/Search',
|
|
||||||
name: 'Search',
|
|
||||||
meta: {
|
|
||||||
title: 'router.search'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'descriptions',
|
|
||||||
component: 'views/Components/Descriptions',
|
|
||||||
name: 'Descriptions',
|
|
||||||
meta: {
|
|
||||||
title: 'router.descriptions'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'image-viewer',
|
|
||||||
component: 'views/Components/ImageViewer',
|
|
||||||
name: 'ImageViewer',
|
|
||||||
meta: {
|
|
||||||
title: 'router.imageViewer'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'dialog',
|
|
||||||
component: 'views/Components/Dialog',
|
|
||||||
name: 'Dialog',
|
|
||||||
meta: {
|
|
||||||
title: 'router.dialog'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'icon',
|
|
||||||
component: 'views/Components/Icon',
|
|
||||||
name: 'Icon',
|
|
||||||
meta: {
|
|
||||||
title: 'router.icon'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'echart',
|
|
||||||
component: 'views/Components/Echart',
|
|
||||||
name: 'Echart',
|
|
||||||
meta: {
|
|
||||||
title: 'router.echart'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'count-to',
|
|
||||||
component: 'views/Components/CountTo',
|
|
||||||
name: 'CountTo',
|
|
||||||
meta: {
|
|
||||||
title: 'router.countTo'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'qrcode',
|
|
||||||
component: 'views/Components/Qrcode',
|
|
||||||
name: 'Qrcode',
|
|
||||||
meta: {
|
|
||||||
title: 'router.qrcode'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'highlight',
|
|
||||||
component: 'views/Components/Highlight',
|
|
||||||
name: 'Highlight',
|
|
||||||
meta: {
|
|
||||||
title: 'router.highlight'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'infotip',
|
|
||||||
component: 'views/Components/Infotip',
|
|
||||||
name: 'Infotip',
|
|
||||||
meta: {
|
|
||||||
title: 'router.infotip'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'input-password',
|
|
||||||
component: 'views/Components/InputPassword',
|
|
||||||
name: 'InputPassword',
|
|
||||||
meta: {
|
|
||||||
title: 'router.inputPassword'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'sticky',
|
|
||||||
component: 'views/Components/Sticky',
|
|
||||||
name: 'Sticky',
|
|
||||||
meta: {
|
|
||||||
title: 'router.sticky'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/hooks',
|
|
||||||
component: '#',
|
|
||||||
redirect: '/hooks/useWatermark',
|
|
||||||
name: 'Hooks',
|
|
||||||
meta: {
|
|
||||||
title: 'hooks',
|
|
||||||
icon: 'ic:outline-webhook',
|
|
||||||
alwaysShow: true
|
|
||||||
},
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
path: 'useWatermark',
|
|
||||||
component: 'views/hooks/useWatermark',
|
|
||||||
name: 'UseWatermark',
|
|
||||||
meta: {
|
|
||||||
title: 'useWatermark'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'useCrudSchemas',
|
|
||||||
component: 'views/hooks/useCrudSchemas',
|
|
||||||
name: 'UseCrudSchemas',
|
|
||||||
meta: {
|
|
||||||
title: 'useCrudSchemas'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/level',
|
|
||||||
component: '#',
|
|
||||||
redirect: '/level/menu1/menu1-1/menu1-1-1',
|
|
||||||
name: 'Level',
|
|
||||||
meta: {
|
|
||||||
title: 'router.level',
|
|
||||||
icon: 'carbon:skill-level-advanced'
|
|
||||||
},
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
path: 'menu1',
|
|
||||||
name: 'Menu1',
|
|
||||||
component: '##',
|
|
||||||
redirect: '/level/menu1/menu1-1/menu1-1-1',
|
|
||||||
meta: {
|
|
||||||
title: 'router.menu1'
|
|
||||||
},
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
path: 'menu1-1',
|
|
||||||
name: 'Menu11',
|
|
||||||
component: '##',
|
|
||||||
redirect: '/level/menu1/menu1-1/menu1-1-1',
|
|
||||||
meta: {
|
|
||||||
title: 'router.menu11',
|
|
||||||
alwaysShow: true
|
|
||||||
},
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
path: 'menu1-1-1',
|
|
||||||
name: 'Menu111',
|
|
||||||
component: 'views/Level/Menu111',
|
|
||||||
meta: {
|
|
||||||
title: 'router.menu111'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'menu1-2',
|
|
||||||
name: 'Menu12',
|
|
||||||
component: 'views/Level/Menu12',
|
|
||||||
meta: {
|
|
||||||
title: 'router.menu12'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'menu2',
|
|
||||||
name: 'Menu2Demo',
|
|
||||||
component: 'views/Level/Menu2',
|
|
||||||
meta: {
|
|
||||||
title: 'router.menu2'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/example',
|
|
||||||
component: '#',
|
|
||||||
redirect: '/example/example-dialog',
|
|
||||||
name: 'Example',
|
|
||||||
meta: {
|
|
||||||
title: 'router.example',
|
|
||||||
icon: 'ep:management',
|
|
||||||
alwaysShow: true
|
|
||||||
},
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
path: 'example-dialog',
|
|
||||||
component: 'views/Example/Dialog/ExampleDialog',
|
|
||||||
name: 'ExampleDialog',
|
|
||||||
meta: {
|
|
||||||
title: 'router.exampleDialog'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'example-page',
|
|
||||||
component: 'views/Example/Page/ExamplePage',
|
|
||||||
name: 'ExamplePage',
|
|
||||||
meta: {
|
|
||||||
title: 'router.examplePage'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'example-add',
|
|
||||||
component: 'views/Example/Page/ExampleAdd',
|
|
||||||
name: 'ExampleAdd',
|
|
||||||
meta: {
|
|
||||||
title: 'router.exampleAdd',
|
|
||||||
noTagsView: true,
|
|
||||||
noCache: true,
|
|
||||||
hidden: true,
|
|
||||||
showMainRoute: true,
|
|
||||||
activeMenu: '/example/example-page'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'example-edit',
|
|
||||||
component: 'views/Example/Page/ExampleEdit',
|
|
||||||
name: 'ExampleEdit',
|
|
||||||
meta: {
|
|
||||||
title: 'router.exampleEdit',
|
|
||||||
noTagsView: true,
|
|
||||||
noCache: true,
|
|
||||||
hidden: true,
|
|
||||||
showMainRoute: true,
|
|
||||||
activeMenu: '/example/example-page'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'example-detail',
|
|
||||||
component: 'views/Example/Page/ExampleDetail',
|
|
||||||
name: 'ExampleDetail',
|
|
||||||
meta: {
|
|
||||||
title: 'router.exampleDetail',
|
|
||||||
noTagsView: true,
|
|
||||||
noCache: true,
|
|
||||||
hidden: true,
|
|
||||||
showMainRoute: true,
|
|
||||||
activeMenu: '/example/example-page'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/error',
|
|
||||||
component: '#',
|
|
||||||
redirect: '/error/404',
|
|
||||||
name: 'Error',
|
|
||||||
meta: {
|
|
||||||
title: 'router.errorPage',
|
|
||||||
icon: 'ci:error',
|
|
||||||
alwaysShow: true
|
|
||||||
},
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
path: '404-demo',
|
|
||||||
component: 'views/Error/404',
|
|
||||||
name: '404Demo',
|
|
||||||
meta: {
|
|
||||||
title: '404'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '403-demo',
|
|
||||||
component: 'views/Error/403',
|
|
||||||
name: '403Demo',
|
|
||||||
meta: {
|
|
||||||
title: '403'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '500-demo',
|
|
||||||
component: 'views/Error/500',
|
|
||||||
name: '500Demo',
|
|
||||||
meta: {
|
|
||||||
title: '500'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
const testList: string[] = [
|
|
||||||
'/dashboard',
|
|
||||||
'/dashboard/analysis',
|
|
||||||
'/dashboard/workplace',
|
|
||||||
'external-link',
|
|
||||||
'https://element-plus-admin-doc.cn/',
|
|
||||||
'/guide',
|
|
||||||
'/guide/index',
|
|
||||||
'/components',
|
|
||||||
'/components/form',
|
|
||||||
'/components/form/default-form',
|
|
||||||
'/components/form/use-form',
|
|
||||||
'/components/form/ref-form',
|
|
||||||
'/components/table',
|
|
||||||
'/components/table/default-table',
|
|
||||||
'/components/table/use-table',
|
|
||||||
'/components/table/tree-table',
|
|
||||||
'/components/table/table-image-preview',
|
|
||||||
'/components/table/ref-table',
|
|
||||||
'/components/editor-demo',
|
|
||||||
'/components/editor-demo/editor',
|
|
||||||
'/components/search',
|
|
||||||
'/components/descriptions',
|
|
||||||
'/components/image-viewer',
|
|
||||||
'/components/dialog',
|
|
||||||
'/components/icon',
|
|
||||||
'/components/echart',
|
|
||||||
'/components/count-to',
|
|
||||||
'/components/qrcode',
|
|
||||||
'/components/highlight',
|
|
||||||
'/components/infotip',
|
|
||||||
'/Components/InputPassword',
|
|
||||||
'/Components/Sticky',
|
|
||||||
'/hooks',
|
|
||||||
'/hooks/useWatermark',
|
|
||||||
'/hooks/useCrudSchemas',
|
|
||||||
'/level',
|
|
||||||
'/level/menu1',
|
|
||||||
'/level/menu1/menu1-1',
|
|
||||||
'/level/menu1/menu1-1/menu1-1-1',
|
|
||||||
'/level/menu1/menu1-2',
|
|
||||||
'/level/menu2',
|
|
||||||
'/example',
|
|
||||||
'/example/example-dialog',
|
|
||||||
'/example/example-page',
|
|
||||||
'/example/example-add',
|
|
||||||
'/example/example-edit',
|
|
||||||
'/example/example-detail',
|
|
||||||
'/error',
|
|
||||||
'/error/404-demo',
|
|
||||||
'/error/403-demo',
|
|
||||||
'/error/500-demo'
|
|
||||||
]
|
|
||||||
|
|
||||||
export default [
|
|
||||||
// 列表接口
|
|
||||||
{
|
|
||||||
url: '/role/list',
|
|
||||||
method: 'get',
|
|
||||||
timeout,
|
|
||||||
response: ({ query }) => {
|
|
||||||
const { roleName } = query
|
|
||||||
return {
|
|
||||||
code: code,
|
|
||||||
data: roleName === 'admin' ? adminList : testList
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
] as MockMethod[]
|
|
|
@ -1,7 +1,4 @@
|
||||||
import config from '@/config/axios/config'
|
import { SUCCESS_CODE } from '@/constants'
|
||||||
import { MockMethod } from 'vite-plugin-mock'
|
|
||||||
|
|
||||||
const { code } = config
|
|
||||||
|
|
||||||
const timeout = 1000
|
const timeout = 1000
|
||||||
|
|
||||||
|
@ -31,7 +28,7 @@ const List: {
|
||||||
export default [
|
export default [
|
||||||
// 列表接口
|
// 列表接口
|
||||||
{
|
{
|
||||||
url: '/user/list',
|
url: '/mock/user/list',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
response: ({ query }) => {
|
response: ({ query }) => {
|
||||||
const { username, pageIndex, pageSize } = query
|
const { username, pageIndex, pageSize } = query
|
||||||
|
@ -45,8 +42,8 @@ export default [
|
||||||
)
|
)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
code: SUCCESS_CODE,
|
||||||
data: {
|
data: {
|
||||||
code: code,
|
|
||||||
total: mockList.length,
|
total: mockList.length,
|
||||||
list: pageList
|
list: pageList
|
||||||
}
|
}
|
||||||
|
@ -55,7 +52,7 @@ export default [
|
||||||
},
|
},
|
||||||
// 登录接口
|
// 登录接口
|
||||||
{
|
{
|
||||||
url: '/user/login',
|
url: '/mock/user/login',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
timeout,
|
timeout,
|
||||||
response: ({ body }) => {
|
response: ({ body }) => {
|
||||||
|
@ -65,7 +62,7 @@ export default [
|
||||||
if (user.username === data.username && user.password === data.password) {
|
if (user.username === data.username && user.password === data.password) {
|
||||||
hasUser = true
|
hasUser = true
|
||||||
return {
|
return {
|
||||||
code: code,
|
code: SUCCESS_CODE,
|
||||||
data: user
|
data: user
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -80,14 +77,14 @@ export default [
|
||||||
},
|
},
|
||||||
// 退出接口
|
// 退出接口
|
||||||
{
|
{
|
||||||
url: '/user/loginOut',
|
url: '/mock/user/loginOut',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
timeout,
|
timeout,
|
||||||
response: () => {
|
response: () => {
|
||||||
return {
|
return {
|
||||||
code: code,
|
code: SUCCESS_CODE,
|
||||||
data: null
|
data: null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
] as MockMethod[]
|
]
|
93
package.json
93
package.json
|
@ -6,18 +6,18 @@
|
||||||
"private": false,
|
"private": false,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"i": "pnpm install",
|
"i": "pnpm install",
|
||||||
"dev": "vite --mode base",
|
"dev": "pnpm vite --mode base",
|
||||||
"ts:check": "vue-tsc --noEmit --skipLibCheck",
|
"ts:check": "pnpm vue-tsc --noEmit --skipLibCheck",
|
||||||
"build:pro": "vite build --mode pro",
|
"build:pro": "pnpm vite build --mode pro",
|
||||||
"build:gitee": "vite build --mode gitee",
|
"build:gitee": "pnpm vite build --mode gitee",
|
||||||
"build:dev": "vite build --mode dev",
|
"build:dev": "pnpm vite build --mode dev",
|
||||||
"build:test": "npm run ts:check && vite build --mode test",
|
"build:test": "pnpm run ts:check && vite build --mode test",
|
||||||
"serve:pro": "vite preview --mode pro",
|
"serve:pro": "pnpm vite preview --mode pro",
|
||||||
"serve:dev": "vite preview --mode dev",
|
"serve:dev": "pnpm vite preview --mode dev",
|
||||||
"serve:test": "vite preview --mode test",
|
"serve:test": "pnpm vite preview --mode test",
|
||||||
"npm:check": "npx npm-check-updates",
|
"npm:check": "pnpx npm-check-updates -u",
|
||||||
"clean": "npx rimraf node_modules",
|
"clean": "pnpx rimraf node_modules",
|
||||||
"clean:cache": "npx rimraf node_modules/.cache",
|
"clean:cache": "pnpx rimraf node_modules/.cache",
|
||||||
"lint:eslint": "eslint --fix --ext .js,.ts,.vue ./src",
|
"lint:eslint": "eslint --fix --ext .js,.ts,.vue ./src",
|
||||||
"lint:format": "prettier --write --loglevel warn \"src/**/*.{js,ts,json,tsx,css,less,vue,html,md}\"",
|
"lint:format": "prettier --write --loglevel warn \"src/**/*.{js,ts,json,tsx,css,less,vue,html,md}\"",
|
||||||
"lint:style": "stylelint --fix \"**/*.{vue,less,postcss,css,scss}\" --cache --cache-location node_modules/.cache/stylelint/",
|
"lint:style": "stylelint --fix \"**/*.{vue,less,postcss,css,scss}\" --cache --cache-location node_modules/.cache/stylelint/",
|
||||||
|
@ -26,90 +26,99 @@
|
||||||
"p": "plop"
|
"p": "plop"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@faker-js/faker": "^8.3.1",
|
||||||
"@iconify/iconify": "^3.1.1",
|
"@iconify/iconify": "^3.1.1",
|
||||||
"@iconify/vue": "^4.1.1",
|
"@iconify/vue": "^4.1.1",
|
||||||
"@vueuse/core": "^10.6.1",
|
"@vueuse/core": "^10.7.0",
|
||||||
"@wangeditor/editor": "^5.1.23",
|
"@wangeditor/editor": "^5.1.23",
|
||||||
"@wangeditor/editor-for-vue": "^5.1.10",
|
"@wangeditor/editor-for-vue": "^5.1.10",
|
||||||
"@zxcvbn-ts/core": "^3.0.4",
|
"@zxcvbn-ts/core": "^3.0.4",
|
||||||
"animate.css": "^4.1.1",
|
"animate.css": "^4.1.1",
|
||||||
"axios": "^1.6.2",
|
"axios": "^1.6.2",
|
||||||
|
"cropperjs": "^1.6.1",
|
||||||
"dayjs": "^1.11.10",
|
"dayjs": "^1.11.10",
|
||||||
|
"driver.js": "^1.3.1",
|
||||||
"echarts": "^5.4.3",
|
"echarts": "^5.4.3",
|
||||||
"echarts-wordcloud": "^2.1.0",
|
"echarts-wordcloud": "^2.1.0",
|
||||||
"element-plus": "^2.4.2",
|
"element-plus": "^2.4.3",
|
||||||
"lodash-es": "^4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
"mitt": "^3.0.1",
|
"mitt": "^3.0.1",
|
||||||
"mockjs": "^1.1.0",
|
|
||||||
"nprogress": "^0.2.0",
|
"nprogress": "^0.2.0",
|
||||||
"pinia": "^2.1.7",
|
"pinia": "^2.1.7",
|
||||||
"pinia-plugin-persist": "^1.0.0",
|
"pinia-plugin-persistedstate": "^3.2.0",
|
||||||
"qrcode": "^1.5.3",
|
"qrcode": "^1.5.3",
|
||||||
"qs": "^6.11.2",
|
"qs": "^6.11.2",
|
||||||
"sortablejs": "^1.15.0",
|
|
||||||
"url": "^0.11.3",
|
"url": "^0.11.3",
|
||||||
"vue": "3.3.8",
|
"vue": "3.3.10",
|
||||||
"vue-i18n": "9.7.0",
|
"vue-i18n": "9.8.0",
|
||||||
|
"vue-json-pretty": "^2.2.4",
|
||||||
"vue-router": "^4.2.5",
|
"vue-router": "^4.2.5",
|
||||||
"vue-types": "^5.1.1"
|
"vue-types": "^5.1.1",
|
||||||
|
"xgplayer": "^3.0.10"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@commitlint/cli": "^18.4.3",
|
"@commitlint/cli": "^18.4.3",
|
||||||
"@commitlint/config-conventional": "^18.4.3",
|
"@commitlint/config-conventional": "^18.4.3",
|
||||||
"@iconify/json": "^2.2.144",
|
"@iconify/json": "^2.2.153",
|
||||||
"@intlify/unplugin-vue-i18n": "^1.5.0",
|
"@intlify/unplugin-vue-i18n": "^1.5.0",
|
||||||
"@purge-icons/generated": "^0.10.0",
|
"@purge-icons/generated": "^0.10.0",
|
||||||
|
"@types/fs-extra": "^11.0.4",
|
||||||
|
"@types/inquirer": "^9.0.7",
|
||||||
"@types/lodash-es": "^4.17.12",
|
"@types/lodash-es": "^4.17.12",
|
||||||
"@types/node": "^20.9.4",
|
"@types/node": "^20.10.3",
|
||||||
"@types/nprogress": "^0.2.3",
|
"@types/nprogress": "^0.2.3",
|
||||||
"@types/qrcode": "^1.5.5",
|
"@types/qrcode": "^1.5.5",
|
||||||
"@types/qs": "^6.9.10",
|
"@types/qs": "^6.9.10",
|
||||||
"@types/sortablejs": "^1.15.7",
|
"@types/sortablejs": "^1.15.7",
|
||||||
"@typescript-eslint/eslint-plugin": "^6.12.0",
|
"@typescript-eslint/eslint-plugin": "^6.13.2",
|
||||||
"@typescript-eslint/parser": "^6.12.0",
|
"@typescript-eslint/parser": "^6.13.2",
|
||||||
"@unocss/transformer-variant-group": "^0.57.7",
|
"@unocss/transformer-variant-group": "^0.58.0",
|
||||||
"@vitejs/plugin-legacy": "^5.1.0",
|
"@vitejs/plugin-legacy": "^5.2.0",
|
||||||
"@vitejs/plugin-vue": "^4.5.0",
|
"@vitejs/plugin-vue": "^4.5.1",
|
||||||
"@vitejs/plugin-vue-jsx": "^3.1.0",
|
"@vitejs/plugin-vue-jsx": "^3.1.0",
|
||||||
"@vue-macros/volar": "^0.17.3",
|
|
||||||
"autoprefixer": "^10.4.16",
|
"autoprefixer": "^10.4.16",
|
||||||
|
"chalk": "^5.3.0",
|
||||||
"consola": "^3.2.3",
|
"consola": "^3.2.3",
|
||||||
"eslint": "^8.54.0",
|
"eslint": "^8.55.0",
|
||||||
"eslint-config-prettier": "^9.0.0",
|
"eslint-config-prettier": "^9.1.0",
|
||||||
"eslint-define-config": "^2.0.0",
|
"eslint-define-config": "^2.0.0",
|
||||||
"eslint-plugin-prettier": "^5.0.1",
|
"eslint-plugin-prettier": "^5.0.1",
|
||||||
"eslint-plugin-vue": "^9.18.1",
|
"eslint-plugin-vue": "^9.19.2",
|
||||||
|
"esno": "^4.0.0",
|
||||||
|
"fs-extra": "^11.2.0",
|
||||||
"husky": "^8.0.3",
|
"husky": "^8.0.3",
|
||||||
|
"inquirer": "^9.2.12",
|
||||||
"less": "^4.2.0",
|
"less": "^4.2.0",
|
||||||
"lint-staged": "^15.1.0",
|
"lint-staged": "^15.2.0",
|
||||||
"plop": "^4.0.0",
|
"plop": "^4.0.0",
|
||||||
"postcss": "^8.4.31",
|
"postcss": "^8.4.32",
|
||||||
"postcss-html": "^1.5.0",
|
"postcss-html": "^1.5.0",
|
||||||
"postcss-less": "^6.0.0",
|
"postcss-less": "^6.0.0",
|
||||||
"prettier": "^3.1.0",
|
"prettier": "^3.1.0",
|
||||||
"rimraf": "^5.0.5",
|
"rimraf": "^5.0.5",
|
||||||
"rollup": "^4.5.1",
|
"rollup": "^4.6.1",
|
||||||
"stylelint": "^15.11.0",
|
"stylelint": "^15.11.0",
|
||||||
"stylelint-config-html": "^1.1.0",
|
"stylelint-config-html": "^1.1.0",
|
||||||
"stylelint-config-recommended": "^13.0.0",
|
"stylelint-config-recommended": "^13.0.0",
|
||||||
"stylelint-config-standard": "^34.0.0",
|
"stylelint-config-standard": "^34.0.0",
|
||||||
"stylelint-order": "^6.0.3",
|
"stylelint-order": "^6.0.3",
|
||||||
"terser": "^5.24.0",
|
"terser": "^5.25.0",
|
||||||
"typescript": "5.3.2",
|
"typescript": "5.3.3",
|
||||||
"unocss": "^0.57.7",
|
"unocss": "^0.58.0",
|
||||||
"unplugin-vue-define-options": "^1.4.0",
|
"vite": "5.0.6",
|
||||||
"vite": "5.0.2",
|
|
||||||
"vite-plugin-ejs": "^1.7.0",
|
"vite-plugin-ejs": "^1.7.0",
|
||||||
"vite-plugin-eslint": "^1.8.1",
|
"vite-plugin-eslint": "^1.8.1",
|
||||||
"vite-plugin-mock": "2.9.6",
|
"vite-plugin-mock": "^2.9.6",
|
||||||
"vite-plugin-progress": "^0.0.7",
|
"vite-plugin-progress": "^0.0.7",
|
||||||
"vite-plugin-purge-icons": "^0.10.0",
|
"vite-plugin-purge-icons": "^0.10.0",
|
||||||
"vite-plugin-style-import": "2.0.0",
|
"vite-plugin-style-import": "2.0.0",
|
||||||
"vite-plugin-svg-icons": "^2.0.1",
|
"vite-plugin-svg-icons": "^2.0.1",
|
||||||
"vue-tsc": "^1.8.22"
|
"vue-tsc": "^1.8.25"
|
||||||
},
|
},
|
||||||
|
"packageManager": "pnpm@8.1.0",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 18.0.0 || >= 20.0.0"
|
"node": ">=18.0.0",
|
||||||
|
"pnpm": ">=8.1.0"
|
||||||
},
|
},
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
import request from '@/config/axios'
|
|
||||||
|
|
||||||
// 获取所有字典
|
|
||||||
export const getDictApi = () => {
|
|
||||||
return request.get({ url: '/dict/list' })
|
|
||||||
}
|
|
||||||
|
|
||||||
// 模拟获取某个字典
|
|
||||||
export const getDictOneApi = async () => {
|
|
||||||
return request.get({ url: '/dict/one' })
|
|
||||||
}
|
|
|
@ -1,23 +0,0 @@
|
||||||
import request from '@/config/axios'
|
|
||||||
import type {
|
|
||||||
AnalysisTotalTypes,
|
|
||||||
UserAccessSource,
|
|
||||||
WeeklyUserActivity,
|
|
||||||
MonthlySales
|
|
||||||
} from './types'
|
|
||||||
|
|
||||||
export const getCountApi = (): Promise<IResponse<AnalysisTotalTypes[]>> => {
|
|
||||||
return request.get({ url: '/analysis/total' })
|
|
||||||
}
|
|
||||||
|
|
||||||
export const getUserAccessSourceApi = (): Promise<IResponse<UserAccessSource[]>> => {
|
|
||||||
return request.get({ url: '/analysis/userAccessSource' })
|
|
||||||
}
|
|
||||||
|
|
||||||
export const getWeeklyUserActivityApi = (): Promise<IResponse<WeeklyUserActivity[]>> => {
|
|
||||||
return request.get({ url: '/analysis/weeklyUserActivity' })
|
|
||||||
}
|
|
||||||
|
|
||||||
export const getMonthlySalesApi = (): Promise<IResponse<MonthlySales[]>> => {
|
|
||||||
return request.get({ url: '/analysis/monthlySales' })
|
|
||||||
}
|
|
|
@ -1,22 +0,0 @@
|
||||||
export type AnalysisTotalTypes = {
|
|
||||||
users: number
|
|
||||||
messages: number
|
|
||||||
moneys: number
|
|
||||||
shoppings: number
|
|
||||||
}
|
|
||||||
|
|
||||||
export type UserAccessSource = {
|
|
||||||
value: number
|
|
||||||
name: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export type WeeklyUserActivity = {
|
|
||||||
value: number
|
|
||||||
name: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export type MonthlySales = {
|
|
||||||
name: string
|
|
||||||
estimate: number
|
|
||||||
actual: number
|
|
||||||
}
|
|
|
@ -1,22 +0,0 @@
|
||||||
import request from '@/config/axios'
|
|
||||||
import type { WorkplaceTotal, Project, Dynamic, Team, RadarData } from './types'
|
|
||||||
|
|
||||||
export const getCountApi = (): Promise<IResponse<WorkplaceTotal>> => {
|
|
||||||
return request.get({ url: '/workplace/total' })
|
|
||||||
}
|
|
||||||
|
|
||||||
export const getProjectApi = (): Promise<IResponse<Project>> => {
|
|
||||||
return request.get({ url: '/workplace/project' })
|
|
||||||
}
|
|
||||||
|
|
||||||
export const getDynamicApi = (): Promise<IResponse<Dynamic[]>> => {
|
|
||||||
return request.get({ url: '/workplace/dynamic' })
|
|
||||||
}
|
|
||||||
|
|
||||||
export const getTeamApi = (): Promise<IResponse<Team[]>> => {
|
|
||||||
return request.get({ url: '/workplace/team' })
|
|
||||||
}
|
|
||||||
|
|
||||||
export const getRadarApi = (): Promise<IResponse<RadarData[]>> => {
|
|
||||||
return request.get({ url: '/workplace/radar' })
|
|
||||||
}
|
|
|
@ -1,30 +0,0 @@
|
||||||
export type WorkplaceTotal = {
|
|
||||||
project: number
|
|
||||||
access: number
|
|
||||||
todo: number
|
|
||||||
}
|
|
||||||
|
|
||||||
export type Project = {
|
|
||||||
name: string
|
|
||||||
icon: string
|
|
||||||
message: string
|
|
||||||
personal: string
|
|
||||||
time: Date | number | string
|
|
||||||
}
|
|
||||||
|
|
||||||
export type Dynamic = {
|
|
||||||
keys: string[]
|
|
||||||
time: Date | number | string
|
|
||||||
}
|
|
||||||
|
|
||||||
export type Team = {
|
|
||||||
name: string
|
|
||||||
icon: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export type RadarData = {
|
|
||||||
personal: number
|
|
||||||
team: number
|
|
||||||
max: number
|
|
||||||
name: string
|
|
||||||
}
|
|
|
@ -1,30 +0,0 @@
|
||||||
import request from '@/config/axios'
|
|
||||||
import { DepartmentListResponse, DepartmentUserParams, DepartmentUserResponse } from './types'
|
|
||||||
|
|
||||||
export const getDepartmentApi = () => {
|
|
||||||
return request.get<DepartmentListResponse>({ url: '/department/list' })
|
|
||||||
}
|
|
||||||
|
|
||||||
export const getUserByIdApi = (params: DepartmentUserParams) => {
|
|
||||||
return request.get<DepartmentUserResponse>({ url: '/department/users', params })
|
|
||||||
}
|
|
||||||
|
|
||||||
export const deleteUserByIdApi = (ids: string[] | number[]) => {
|
|
||||||
return request.post({ url: '/department/user/delete', data: { ids } })
|
|
||||||
}
|
|
||||||
|
|
||||||
export const saveUserApi = (data: any) => {
|
|
||||||
return request.post({ url: '/department/user/save', data })
|
|
||||||
}
|
|
||||||
|
|
||||||
export const saveDepartmentApi = (data: any) => {
|
|
||||||
return request.post({ url: '/department/save', data })
|
|
||||||
}
|
|
||||||
|
|
||||||
export const deleteDepartmentApi = (ids: string[] | number[]) => {
|
|
||||||
return request.post({ url: '/department/delete', data: { ids } })
|
|
||||||
}
|
|
||||||
|
|
||||||
export const getDepartmentTableApi = (params: any) => {
|
|
||||||
return request.get({ url: '/department/table/list', params })
|
|
||||||
}
|
|
|
@ -1,32 +0,0 @@
|
||||||
export interface DepartmentItem {
|
|
||||||
id: string
|
|
||||||
departmentName: string
|
|
||||||
children?: DepartmentItem[]
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface DepartmentListResponse {
|
|
||||||
list: DepartmentItem[]
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface DepartmentUserParams {
|
|
||||||
pageSize: number
|
|
||||||
pageIndex: number
|
|
||||||
id: string
|
|
||||||
username?: string
|
|
||||||
account?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface DepartmentUserItem {
|
|
||||||
id: string
|
|
||||||
username: string
|
|
||||||
account: string
|
|
||||||
email: string
|
|
||||||
createTime: string
|
|
||||||
role: string
|
|
||||||
department: DepartmentItem
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface DepartmentUserResponse {
|
|
||||||
list: DepartmentUserItem[]
|
|
||||||
total: number
|
|
||||||
}
|
|
|
@ -1,4 +1,4 @@
|
||||||
import request from '@/config/axios'
|
import request from '@/axios'
|
||||||
import type { UserType } from './types'
|
import type { UserType } from './types'
|
||||||
|
|
||||||
interface RoleParams {
|
interface RoleParams {
|
||||||
|
@ -6,29 +6,19 @@ interface RoleParams {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const loginApi = (data: UserType): Promise<IResponse<UserType>> => {
|
export const loginApi = (data: UserType): Promise<IResponse<UserType>> => {
|
||||||
return request.post({ url: '/user/login', data })
|
return request.post({ url: '/mock/user/login', data })
|
||||||
}
|
}
|
||||||
|
|
||||||
export const loginOutApi = (): Promise<IResponse> => {
|
export const loginOutApi = (): Promise<IResponse> => {
|
||||||
return request.get({ url: '/user/loginOut' })
|
return request.get({ url: '/mock/user/loginOut' })
|
||||||
}
|
|
||||||
|
|
||||||
export const getUserListApi = ({ params }: AxiosConfig) => {
|
|
||||||
return request.get<{
|
|
||||||
code: string
|
|
||||||
data: {
|
|
||||||
list: UserType[]
|
|
||||||
total: number
|
|
||||||
}
|
|
||||||
}>({ url: '/user/list', params })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getAdminRoleApi = (
|
export const getAdminRoleApi = (
|
||||||
params: RoleParams
|
params: RoleParams
|
||||||
): Promise<IResponse<AppCustomRouteRecordRaw[]>> => {
|
): Promise<IResponse<AppCustomRouteRecordRaw[]>> => {
|
||||||
return request.get({ url: '/role/list', params })
|
return request.get({ url: '/mock/role/list', params })
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getTestRoleApi = (params: RoleParams): Promise<IResponse<string[]>> => {
|
export const getTestRoleApi = (params: RoleParams): Promise<IResponse<string[]>> => {
|
||||||
return request.get({ url: '/role/list', params })
|
return request.get({ url: '/mock/role/list2', params })
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
import request from '@/config/axios'
|
|
||||||
|
|
||||||
export const getMenuListApi = () => {
|
|
||||||
return request.get({ url: '/menu/list' })
|
|
||||||
}
|
|
|
@ -1,22 +0,0 @@
|
||||||
import request from '@/config/axios'
|
|
||||||
import type { TableData } from './types'
|
|
||||||
|
|
||||||
export const getTableListApi = (params: any) => {
|
|
||||||
return request.get({ url: '/example/list', params })
|
|
||||||
}
|
|
||||||
|
|
||||||
export const getTreeTableListApi = (params: any) => {
|
|
||||||
return request.get({ url: '/example/treeList', params })
|
|
||||||
}
|
|
||||||
|
|
||||||
export const saveTableApi = (data: Partial<TableData>): Promise<IResponse> => {
|
|
||||||
return request.post({ url: '/example/save', data })
|
|
||||||
}
|
|
||||||
|
|
||||||
export const getTableDetApi = (id: string): Promise<IResponse<TableData>> => {
|
|
||||||
return request.get({ url: '/example/detail', params: { id } })
|
|
||||||
}
|
|
||||||
|
|
||||||
export const delTableListApi = (ids: string[] | number[]): Promise<IResponse> => {
|
|
||||||
return request.post({ url: '/example/delete', data: { ids } })
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
export type TableData = {
|
|
||||||
id: string
|
|
||||||
author: string
|
|
||||||
title: string
|
|
||||||
content: string
|
|
||||||
importance: number
|
|
||||||
display_time: string
|
|
||||||
pageviews: number
|
|
||||||
}
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
import { AxiosResponse, InternalAxiosRequestConfig } from './types'
|
||||||
|
import { ElMessage } from 'element-plus'
|
||||||
|
import qs from 'qs'
|
||||||
|
import { SUCCESS_CODE } from '@/constants'
|
||||||
|
import { useUserStoreWithOut } from '@/store/modules/user'
|
||||||
|
|
||||||
|
const defaultRequestInterceptors = (config: InternalAxiosRequestConfig) => {
|
||||||
|
if (
|
||||||
|
config.method === 'post' &&
|
||||||
|
config.headers['Content-Type'] === 'application/x-www-form-urlencoded'
|
||||||
|
) {
|
||||||
|
config.data = qs.stringify(config.data)
|
||||||
|
}
|
||||||
|
if (config.method === 'get' && config.params) {
|
||||||
|
let url = config.url as string
|
||||||
|
url += '?'
|
||||||
|
const keys = Object.keys(config.params)
|
||||||
|
for (const key of keys) {
|
||||||
|
if (config.params[key] !== void 0 && config.params[key] !== null) {
|
||||||
|
url += `${key}=${encodeURIComponent(config.params[key])}&`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
url = url.substring(0, url.length - 1)
|
||||||
|
config.params = {}
|
||||||
|
config.url = url
|
||||||
|
}
|
||||||
|
return config
|
||||||
|
}
|
||||||
|
|
||||||
|
const defaultResponseInterceptors = (response: AxiosResponse) => {
|
||||||
|
if (response?.config?.responseType === 'blob') {
|
||||||
|
// 如果是文件流,直接过
|
||||||
|
return response
|
||||||
|
} else if (response.data.code === SUCCESS_CODE) {
|
||||||
|
return response.data
|
||||||
|
} else {
|
||||||
|
ElMessage.error(response?.data?.message)
|
||||||
|
if (response?.data?.code === 401) {
|
||||||
|
const userStore = useUserStoreWithOut()
|
||||||
|
userStore.logout()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { defaultResponseInterceptors, defaultRequestInterceptors }
|
|
@ -1,11 +1,10 @@
|
||||||
import service from './service'
|
import service from './service'
|
||||||
|
import { CONTENT_TYPE } from '@/constants'
|
||||||
import config from './config'
|
import { useUserStoreWithOut } from '@/store/modules/user'
|
||||||
|
|
||||||
const { defaultHeaders } = config
|
|
||||||
|
|
||||||
const request = (option: AxiosConfig) => {
|
const request = (option: AxiosConfig) => {
|
||||||
const { url, method, params, data, headersType, responseType } = option
|
const { url, method, params, data, headers, responseType } = option
|
||||||
|
const userStore = useUserStoreWithOut()
|
||||||
return service.request({
|
return service.request({
|
||||||
url: url,
|
url: url,
|
||||||
method,
|
method,
|
||||||
|
@ -13,7 +12,9 @@ const request = (option: AxiosConfig) => {
|
||||||
data,
|
data,
|
||||||
responseType: responseType,
|
responseType: responseType,
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': headersType || defaultHeaders
|
'Content-Type': CONTENT_TYPE,
|
||||||
|
[userStore.getTokenKey ?? 'Authorization']: userStore.getToken ?? '',
|
||||||
|
...headers
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
|
@ -1,18 +1,16 @@
|
||||||
import axios, { AxiosError } from 'axios'
|
import axios, { AxiosError } from 'axios'
|
||||||
import config, { defaultRequestInterceptors, defaultResponseInterceptors } from './config'
|
import { defaultRequestInterceptors, defaultResponseInterceptors } from './config'
|
||||||
|
|
||||||
import { AxiosInstance, InternalAxiosRequestConfig, RequestConfig, AxiosResponse } from './types'
|
import { AxiosInstance, InternalAxiosRequestConfig, RequestConfig, AxiosResponse } from './types'
|
||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage } from 'element-plus'
|
||||||
|
import { REQUEST_TIMEOUT } from '@/constants'
|
||||||
|
|
||||||
const { interceptors, baseUrl } = config
|
export const PATH_URL = import.meta.env.VITE_API_BASE_PATH
|
||||||
export const PATH_URL = baseUrl[import.meta.env.VITE_API_BASE_PATH]
|
|
||||||
|
|
||||||
const { requestInterceptors, responseInterceptors } = interceptors
|
|
||||||
|
|
||||||
const abortControllerMap: Map<string, AbortController> = new Map()
|
const abortControllerMap: Map<string, AbortController> = new Map()
|
||||||
|
|
||||||
const axiosInstance: AxiosInstance = axios.create({
|
const axiosInstance: AxiosInstance = axios.create({
|
||||||
...config,
|
timeout: REQUEST_TIMEOUT,
|
||||||
baseURL: PATH_URL
|
baseURL: PATH_URL
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -28,6 +26,7 @@ axiosInstance.interceptors.response.use(
|
||||||
(res: AxiosResponse) => {
|
(res: AxiosResponse) => {
|
||||||
const url = res.config.url || ''
|
const url = res.config.url || ''
|
||||||
abortControllerMap.delete(url)
|
abortControllerMap.delete(url)
|
||||||
|
// 这里不能做任何处理,否则后面的 interceptors 拿不到完整的上下文了
|
||||||
return res
|
return res
|
||||||
},
|
},
|
||||||
(error: AxiosError) => {
|
(error: AxiosError) => {
|
||||||
|
@ -37,8 +36,8 @@ axiosInstance.interceptors.response.use(
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
axiosInstance.interceptors.request.use(requestInterceptors || defaultRequestInterceptors)
|
axiosInstance.interceptors.request.use(defaultRequestInterceptors)
|
||||||
axiosInstance.interceptors.response.use(responseInterceptors || defaultResponseInterceptors)
|
axiosInstance.interceptors.response.use(defaultResponseInterceptors)
|
||||||
|
|
||||||
const service = {
|
const service = {
|
||||||
request: (config: RequestConfig) => {
|
request: (config: RequestConfig) => {
|
|
@ -15,18 +15,6 @@ interface RequestInterceptors<T> {
|
||||||
responseInterceptors?: (config: T) => T
|
responseInterceptors?: (config: T) => T
|
||||||
responseInterceptorsCatch?: (err: any) => any
|
responseInterceptorsCatch?: (err: any) => any
|
||||||
}
|
}
|
||||||
interface AxiosConfig<T = AxiosResponse> {
|
|
||||||
baseUrl: {
|
|
||||||
base: string
|
|
||||||
dev: string
|
|
||||||
pro: string
|
|
||||||
test: string
|
|
||||||
}
|
|
||||||
code: number
|
|
||||||
defaultHeaders: AxiosHeaders
|
|
||||||
timeout: number
|
|
||||||
interceptors: RequestInterceptors<T>
|
|
||||||
}
|
|
||||||
|
|
||||||
interface RequestConfig<T = AxiosResponse> extends AxiosRequestConfig {
|
interface RequestConfig<T = AxiosResponse> extends AxiosRequestConfig {
|
||||||
interceptors?: RequestInterceptors<T>
|
interceptors?: RequestInterceptors<T>
|
||||||
|
@ -36,7 +24,6 @@ export {
|
||||||
AxiosResponse,
|
AxiosResponse,
|
||||||
RequestInterceptors,
|
RequestInterceptors,
|
||||||
RequestConfig,
|
RequestConfig,
|
||||||
AxiosConfig,
|
|
||||||
AxiosInstance,
|
AxiosInstance,
|
||||||
InternalAxiosRequestConfig,
|
InternalAxiosRequestConfig,
|
||||||
AxiosRequestHeaders,
|
AxiosRequestHeaders,
|
|
@ -0,0 +1,3 @@
|
||||||
|
import BaseButton from './src/Button.vue'
|
||||||
|
|
||||||
|
export { BaseButton }
|
|
@ -0,0 +1,121 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { useDesign } from '@/hooks/web/useDesign'
|
||||||
|
import { ElButton, ComponentSize, ButtonType } from 'element-plus'
|
||||||
|
import { PropType, Component, computed, unref } from 'vue'
|
||||||
|
import { useAppStore } from '@/store/modules/app'
|
||||||
|
|
||||||
|
const appStore = useAppStore()
|
||||||
|
|
||||||
|
const getTheme = computed(() => appStore.getTheme)
|
||||||
|
|
||||||
|
const { getPrefixCls } = useDesign()
|
||||||
|
|
||||||
|
const prefixCls = getPrefixCls('button')
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
size: {
|
||||||
|
type: String as PropType<ComponentSize>,
|
||||||
|
default: undefined
|
||||||
|
},
|
||||||
|
type: {
|
||||||
|
type: String as PropType<ButtonType>,
|
||||||
|
default: 'default'
|
||||||
|
},
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
plain: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
text: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
bg: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
link: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
round: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
circle: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
loading: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
loadingIcon: {
|
||||||
|
type: [String, Object] as PropType<String | Component>,
|
||||||
|
default: undefined
|
||||||
|
},
|
||||||
|
icon: {
|
||||||
|
type: [String, Object] as PropType<String | Component>,
|
||||||
|
default: undefined
|
||||||
|
},
|
||||||
|
autofocus: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
nativeType: {
|
||||||
|
type: String as PropType<'button' | 'submit' | 'reset'>,
|
||||||
|
default: 'button'
|
||||||
|
},
|
||||||
|
autoInsertSpace: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
color: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
darker: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
tag: {
|
||||||
|
type: [String, Object] as PropType<String | Component>,
|
||||||
|
default: 'button'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const emits = defineEmits(['click'])
|
||||||
|
|
||||||
|
const color = computed(() => {
|
||||||
|
const { type } = props
|
||||||
|
if (type === 'primary') {
|
||||||
|
return unref(getTheme).elColorPrimary
|
||||||
|
}
|
||||||
|
return ''
|
||||||
|
})
|
||||||
|
|
||||||
|
const style = computed(() => {
|
||||||
|
const { type } = props
|
||||||
|
if (type === 'primary') {
|
||||||
|
return '--el-button-text-color: #fff; --el-button-hover-text-color: #fff'
|
||||||
|
}
|
||||||
|
return ''
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<ElButton
|
||||||
|
:class="`${prefixCls} color-#fff`"
|
||||||
|
v-bind="{ ...props }"
|
||||||
|
:color="color"
|
||||||
|
:style="style"
|
||||||
|
@click="() => emits('click')"
|
||||||
|
>
|
||||||
|
<slot></slot>
|
||||||
|
<slot name="icon"></slot>
|
||||||
|
<slot name="loading"></slot>
|
||||||
|
</ElButton>
|
||||||
|
</template>
|
|
@ -155,6 +155,7 @@ export default defineComponent({
|
||||||
.is-active {
|
.is-active {
|
||||||
& > .@{elNamespace}-sub-menu__title {
|
& > .@{elNamespace}-sub-menu__title {
|
||||||
color: var(--left-menu-text-active-color) !important;
|
color: var(--left-menu-text-active-color) !important;
|
||||||
|
// background-color: var(--left-menu-bg-color) !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -168,7 +169,6 @@ export default defineComponent({
|
||||||
}
|
}
|
||||||
|
|
||||||
// 设置选中时的高亮背景和高亮颜色
|
// 设置选中时的高亮背景和高亮颜色
|
||||||
.@{elNamespace}-sub-menu.is-active,
|
|
||||||
.@{elNamespace}-menu-item.is-active {
|
.@{elNamespace}-menu-item.is-active {
|
||||||
color: var(--left-menu-text-active-color) !important;
|
color: var(--left-menu-text-active-color) !important;
|
||||||
background-color: var(--left-menu-bg-active-color) !important;
|
background-color: var(--left-menu-bg-active-color) !important;
|
||||||
|
@ -235,7 +235,7 @@ export default defineComponent({
|
||||||
.@{elNamespace}-menu-item.is-active {
|
.@{elNamespace}-menu-item.is-active {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
&:after {
|
&::after {
|
||||||
display: none !important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -270,6 +270,7 @@ export default defineComponent({
|
||||||
.is-active {
|
.is-active {
|
||||||
& > .el-sub-menu__title {
|
& > .el-sub-menu__title {
|
||||||
color: var(--left-menu-text-active-color) !important;
|
color: var(--left-menu-text-active-color) !important;
|
||||||
|
// background-color: var(--left-menu-bg-color) !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,24 +1,24 @@
|
||||||
import { ElSubMenu, ElMenuItem } from 'element-plus'
|
import { ElSubMenu, ElMenuItem } from 'element-plus'
|
||||||
import type { RouteMeta } from 'vue-router'
|
|
||||||
import { hasOneShowingChild } from '../helper'
|
import { hasOneShowingChild } from '../helper'
|
||||||
import { isUrl } from '@/utils/is'
|
import { isUrl } from '@/utils/is'
|
||||||
import { useRenderMenuTitle } from './useRenderMenuTitle'
|
import { useRenderMenuTitle } from './useRenderMenuTitle'
|
||||||
import { useDesign } from '@/hooks/web/useDesign'
|
import { useDesign } from '@/hooks/web/useDesign'
|
||||||
import { pathResolve } from '@/utils/routerHelper'
|
import { pathResolve } from '@/utils/routerHelper'
|
||||||
|
|
||||||
|
const { renderMenuTitle } = useRenderMenuTitle()
|
||||||
|
|
||||||
export const useRenderMenuItem = (
|
export const useRenderMenuItem = (
|
||||||
// allRouters: AppRouteRecordRaw[] = [],
|
// allRouters: AppRouteRecordRaw[] = [],
|
||||||
menuMode: 'vertical' | 'horizontal'
|
menuMode: 'vertical' | 'horizontal'
|
||||||
) => {
|
) => {
|
||||||
const renderMenuItem = (routers: AppRouteRecordRaw[], parentPath = '/') => {
|
const renderMenuItem = (routers: AppRouteRecordRaw[], parentPath = '/') => {
|
||||||
return routers.map((v) => {
|
return routers
|
||||||
const meta = (v.meta ?? {}) as RouteMeta
|
.filter((v) => !v.meta?.hidden)
|
||||||
if (!meta.hidden) {
|
.map((v) => {
|
||||||
|
const meta = v.meta ?? {}
|
||||||
const { oneShowingChild, onlyOneChild } = hasOneShowingChild(v.children, v)
|
const { oneShowingChild, onlyOneChild } = hasOneShowingChild(v.children, v)
|
||||||
const fullPath = isUrl(v.path) ? v.path : pathResolve(parentPath, v.path) // getAllParentPath<AppRouteRecordRaw>(allRouters, v.path).join('/')
|
const fullPath = isUrl(v.path) ? v.path : pathResolve(parentPath, v.path) // getAllParentPath<AppRouteRecordRaw>(allRouters, v.path).join('/')
|
||||||
|
|
||||||
const { renderMenuTitle } = useRenderMenuTitle()
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
oneShowingChild &&
|
oneShowingChild &&
|
||||||
(!onlyOneChild?.children || onlyOneChild?.noShowingChildren) &&
|
(!onlyOneChild?.children || onlyOneChild?.noShowingChildren) &&
|
||||||
|
@ -49,8 +49,7 @@ export const useRenderMenuItem = (
|
||||||
</ElSubMenu>
|
</ElSubMenu>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -88,6 +88,9 @@ const newSchema = computed(() => {
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
},
|
||||||
|
label: () => {
|
||||||
|
return <span> </span>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -117,11 +120,14 @@ const setProps = (props: SearchProps = {}) => {
|
||||||
outsideProps.value = props
|
outsideProps.value = props
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const schemaRef = ref<FormSchema[]>([])
|
||||||
|
|
||||||
// 监听表单结构化数组,重新生成formModel
|
// 监听表单结构化数组,重新生成formModel
|
||||||
watch(
|
watch(
|
||||||
() => unref(newSchema),
|
() => unref(newSchema),
|
||||||
async (schema = []) => {
|
async (schema = []) => {
|
||||||
formModel.value = initModel(schema, unref(formModel))
|
formModel.value = initModel(schema, unref(formModel))
|
||||||
|
schemaRef.value = schema
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
immediate: true,
|
immediate: true,
|
||||||
|
@ -241,7 +247,7 @@ const onFormValidate = (prop: FormItemProp, isValid: boolean, message: string) =
|
||||||
hide-required-asterisk
|
hide-required-asterisk
|
||||||
:inline="getProps.inline"
|
:inline="getProps.inline"
|
||||||
:is-col="getProps.isCol"
|
:is-col="getProps.isCol"
|
||||||
:schema="newSchema"
|
:schema="schemaRef"
|
||||||
@register="formRegister"
|
@register="formRegister"
|
||||||
@validate="onFormValidate"
|
@validate="onFormValidate"
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ElDrawer, ElDivider, ElButton, ElMessage } from 'element-plus'
|
import { ElDrawer, ElDivider, ElMessage } from 'element-plus'
|
||||||
import { ref, unref, computed, watch } from 'vue'
|
import { ref, unref, computed, watch } from 'vue'
|
||||||
import { useI18n } from '@/hooks/web/useI18n'
|
import { useI18n } from '@/hooks/web/useI18n'
|
||||||
import { ThemeSwitch } from '@/components/ThemeSwitch'
|
import { ThemeSwitch } from '@/components/ThemeSwitch'
|
||||||
|
@ -14,7 +14,7 @@ import { useStorage } from '@/hooks/web/useStorage'
|
||||||
import { useClipboard } from '@vueuse/core'
|
import { useClipboard } from '@vueuse/core'
|
||||||
import { useDesign } from '@/hooks/web/useDesign'
|
import { useDesign } from '@/hooks/web/useDesign'
|
||||||
|
|
||||||
const { removeStorage } = useStorage()
|
const { clear: storageClear } = useStorage('localStorage')
|
||||||
|
|
||||||
const { getPrefixCls } = useDesign()
|
const { getPrefixCls } = useDesign()
|
||||||
|
|
||||||
|
@ -174,7 +174,8 @@ const copyConfig = async () => {
|
||||||
// 头部边框颜色
|
// 头部边框颜色
|
||||||
topToolBorderColor: '${appStore.getTheme.topToolBorderColor}'
|
topToolBorderColor: '${appStore.getTheme.topToolBorderColor}'
|
||||||
}
|
}
|
||||||
`
|
`,
|
||||||
|
legacy: true
|
||||||
})
|
})
|
||||||
if (!isSupported) {
|
if (!isSupported) {
|
||||||
ElMessage.error(t('setting.copyFailed'))
|
ElMessage.error(t('setting.copyFailed'))
|
||||||
|
@ -188,9 +189,7 @@ const copyConfig = async () => {
|
||||||
|
|
||||||
// 清空缓存
|
// 清空缓存
|
||||||
const clear = () => {
|
const clear = () => {
|
||||||
removeStorage('layout')
|
storageClear()
|
||||||
removeStorage('theme')
|
|
||||||
removeStorage('isDark')
|
|
||||||
window.location.reload()
|
window.location.reload()
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -278,12 +277,14 @@ const clear = () => {
|
||||||
|
|
||||||
<ElDivider />
|
<ElDivider />
|
||||||
<div>
|
<div>
|
||||||
<ElButton type="primary" class="w-full" @click="copyConfig">{{ t('setting.copy') }}</ElButton>
|
<BaseButton type="primary" class="w-full" @click="copyConfig">{{
|
||||||
|
t('setting.copy')
|
||||||
|
}}</BaseButton>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-5px">
|
<div class="mt-5px">
|
||||||
<ElButton type="danger" class="w-full" @click="clear">
|
<BaseButton type="danger" class="w-full" @click="clear">
|
||||||
{{ t('setting.clearAndReset') }}
|
{{ t('setting.clearAndReset') }}
|
||||||
</ElButton>
|
</BaseButton>
|
||||||
</div>
|
</div>
|
||||||
</ElDrawer>
|
</ElDrawer>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -108,13 +108,21 @@ const greyModeChange = (show: boolean) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 动态路由
|
// 动态路由
|
||||||
const dynamicRouter = ref(appStore.getDynamicRouter)
|
const dynamicRouter = ref(!!appStore.getDynamicRouter)
|
||||||
|
|
||||||
const dynamicRouterChange = (show: boolean) => {
|
const dynamicRouterChange = (show: boolean) => {
|
||||||
ElMessage.info(t('setting.reExperienced'))
|
ElMessage.info(t('setting.reExperienced'))
|
||||||
appStore.setDynamicRouter(show)
|
appStore.setDynamicRouter(show)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 服务端动态路由
|
||||||
|
const serverDynamicRouter = ref(appStore.getServerDynamicRouter)
|
||||||
|
|
||||||
|
const serverDynamicRouterChange = (show: boolean) => {
|
||||||
|
ElMessage.info(t('setting.reExperienced'))
|
||||||
|
appStore.setServerDynamicRouter(show)
|
||||||
|
}
|
||||||
|
|
||||||
// 固定菜单
|
// 固定菜单
|
||||||
const fixedMenu = ref(appStore.getFixedMenu)
|
const fixedMenu = ref(appStore.getFixedMenu)
|
||||||
|
|
||||||
|
@ -206,6 +214,11 @@ watch(
|
||||||
<ElSwitch v-model="dynamicRouter" @change="dynamicRouterChange" />
|
<ElSwitch v-model="dynamicRouter" @change="dynamicRouterChange" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="flex justify-between items-center">
|
||||||
|
<span class="text-14px">{{ t('setting.serverDynamicRouter') }}</span>
|
||||||
|
<ElSwitch v-model="serverDynamicRouter" @change="serverDynamicRouterChange" />
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="flex justify-between items-center">
|
<div class="flex justify-between items-center">
|
||||||
<span class="text-14px">{{ t('setting.fixedMenu') }}</span>
|
<span class="text-14px">{{ t('setting.fixedMenu') }}</span>
|
||||||
<ElSwitch v-model="fixedMenu" @change="fixedMenuChange" />
|
<ElSwitch v-model="fixedMenu" @change="fixedMenuChange" />
|
||||||
|
|
|
@ -67,7 +67,7 @@ const layout = computed(() => appStore.getLayout)
|
||||||
border: 2px solid #e5e7eb;
|
border: 2px solid #e5e7eb;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
|
|
||||||
&:before {
|
&::before {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
|
@ -79,14 +79,14 @@ const layout = computed(() => appStore.getLayout)
|
||||||
content: '';
|
content: '';
|
||||||
}
|
}
|
||||||
|
|
||||||
&:after {
|
&::after {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 25%;
|
height: 25%;
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
border-radius: 4px 4px 0 4px;
|
border-radius: 4px 4px 0;
|
||||||
content: '';
|
content: '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -95,7 +95,7 @@ const layout = computed(() => appStore.getLayout)
|
||||||
border: 2px solid #e5e7eb;
|
border: 2px solid #e5e7eb;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
|
|
||||||
&:before {
|
&::before {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
|
@ -107,7 +107,7 @@ const layout = computed(() => appStore.getLayout)
|
||||||
content: '';
|
content: '';
|
||||||
}
|
}
|
||||||
|
|
||||||
&:after {
|
&::after {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
|
@ -123,7 +123,7 @@ const layout = computed(() => appStore.getLayout)
|
||||||
border: 2px solid #e5e7eb;
|
border: 2px solid #e5e7eb;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
|
|
||||||
&:before {
|
&::before {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
|
@ -140,7 +140,7 @@ const layout = computed(() => appStore.getLayout)
|
||||||
border: 2px solid #e5e7eb;
|
border: 2px solid #e5e7eb;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
|
|
||||||
&:before {
|
&::before {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
|
@ -152,7 +152,7 @@ const layout = computed(() => appStore.getLayout)
|
||||||
content: '';
|
content: '';
|
||||||
}
|
}
|
||||||
|
|
||||||
&:after {
|
&::after {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
|
|
|
@ -5,7 +5,9 @@ import {
|
||||||
ElPagination,
|
ElPagination,
|
||||||
ComponentSize,
|
ComponentSize,
|
||||||
ElTooltipProps,
|
ElTooltipProps,
|
||||||
ElImage
|
ElImage,
|
||||||
|
ElEmpty,
|
||||||
|
ElCard
|
||||||
} from 'element-plus'
|
} from 'element-plus'
|
||||||
import { defineComponent, PropType, ref, computed, unref, watch, onMounted } from 'vue'
|
import { defineComponent, PropType, ref, computed, unref, watch, onMounted } from 'vue'
|
||||||
import { propTypes } from '@/utils/propTypes'
|
import { propTypes } from '@/utils/propTypes'
|
||||||
|
@ -15,8 +17,10 @@ import { set, get } from 'lodash-es'
|
||||||
import { CSSProperties } from 'vue'
|
import { CSSProperties } from 'vue'
|
||||||
import { getSlot } from '@/utils/tsxHelper'
|
import { getSlot } from '@/utils/tsxHelper'
|
||||||
import TableActions from './components/TableActions.vue'
|
import TableActions from './components/TableActions.vue'
|
||||||
// import Sortable from 'sortablejs'
|
import { isImgPath } from '@/utils/is'
|
||||||
// import { Icon } from '@/components/Icon'
|
import { createVideoViewer } from '@/components/VideoPlayer'
|
||||||
|
import { Icon } from '@/components/Icon'
|
||||||
|
import { BaseButton } from '@/components/Button'
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'Table',
|
name: 'Table',
|
||||||
|
@ -32,8 +36,6 @@ export default defineComponent({
|
||||||
type: Array as PropType<TableColumn[]>,
|
type: Array as PropType<TableColumn[]>,
|
||||||
default: () => []
|
default: () => []
|
||||||
},
|
},
|
||||||
// 展开行
|
|
||||||
// expand: propTypes.bool.def(false),
|
|
||||||
// 是否展示分页
|
// 是否展示分页
|
||||||
pagination: {
|
pagination: {
|
||||||
type: Object as PropType<Pagination>,
|
type: Object as PropType<Pagination>,
|
||||||
|
@ -62,7 +64,6 @@ export default defineComponent({
|
||||||
type: Array as PropType<string[]>,
|
type: Array as PropType<string[]>,
|
||||||
default: () => []
|
default: () => []
|
||||||
},
|
},
|
||||||
// sortable: propTypes.bool.def(false),
|
|
||||||
height: propTypes.oneOfType([Number, String]),
|
height: propTypes.oneOfType([Number, String]),
|
||||||
maxHeight: propTypes.oneOfType([Number, String]),
|
maxHeight: propTypes.oneOfType([Number, String]),
|
||||||
stripe: propTypes.bool.def(false),
|
stripe: propTypes.bool.def(false),
|
||||||
|
@ -186,9 +187,27 @@ export default defineComponent({
|
||||||
default: 'fixed'
|
default: 'fixed'
|
||||||
},
|
},
|
||||||
scrollbarAlwaysOn: propTypes.bool.def(false),
|
scrollbarAlwaysOn: propTypes.bool.def(false),
|
||||||
flexible: propTypes.bool.def(false)
|
flexible: propTypes.bool.def(false),
|
||||||
|
// 自定义内容
|
||||||
|
customContent: propTypes.bool.def(false),
|
||||||
|
cardBodyStyle: {
|
||||||
|
type: Object as PropType<CSSProperties>,
|
||||||
|
default: () => ({})
|
||||||
|
},
|
||||||
|
cardBodyClass: {
|
||||||
|
type: String as PropType<string>,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
cardWrapStyle: {
|
||||||
|
type: Object as PropType<CSSProperties>,
|
||||||
|
default: () => ({})
|
||||||
|
},
|
||||||
|
cardWrapClass: {
|
||||||
|
type: String as PropType<string>,
|
||||||
|
default: ''
|
||||||
|
}
|
||||||
},
|
},
|
||||||
emits: ['update:pageSize', 'update:currentPage', 'register', 'refresh', 'sortable-change'],
|
emits: ['update:pageSize', 'update:currentPage', 'register', 'refresh'],
|
||||||
setup(props, { attrs, emit, slots, expose }) {
|
setup(props, { attrs, emit, slots, expose }) {
|
||||||
const elTableRef = ref<ComponentRef<typeof ElTable>>()
|
const elTableRef = ref<ComponentRef<typeof ElTable>>()
|
||||||
|
|
||||||
|
@ -213,33 +232,6 @@ export default defineComponent({
|
||||||
return propsObj
|
return propsObj
|
||||||
})
|
})
|
||||||
|
|
||||||
// const sortableEl = ref()
|
|
||||||
// 初始化拖拽
|
|
||||||
// const initDropTable = () => {
|
|
||||||
// const el = unref(elTableRef)?.$el.querySelector('.el-table__body tbody')
|
|
||||||
// if (!el) return
|
|
||||||
// if (unref(sortableEl)) unref(sortableEl).destroy()
|
|
||||||
|
|
||||||
// sortableEl.value = Sortable.create(el, {
|
|
||||||
// handle: '.table-move',
|
|
||||||
// animation: 180,
|
|
||||||
// onEnd(e: any) {
|
|
||||||
// emit('sortable-change', e)
|
|
||||||
// }
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
|
|
||||||
// watch(
|
|
||||||
// () => getProps.value.sortable,
|
|
||||||
// async (v) => {
|
|
||||||
// await nextTick()
|
|
||||||
// v && initDropTable()
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// immediate: true
|
|
||||||
// }
|
|
||||||
// )
|
|
||||||
|
|
||||||
const setProps = (props: TableProps = {}) => {
|
const setProps = (props: TableProps = {}) => {
|
||||||
mergeProps.value = Object.assign(unref(mergeProps), props)
|
mergeProps.value = Object.assign(unref(mergeProps), props)
|
||||||
outsideProps.value = { ...props } as any
|
outsideProps.value = { ...props } as any
|
||||||
|
@ -260,7 +252,7 @@ export default defineComponent({
|
||||||
|
|
||||||
const addColumn = (column: TableColumn, index?: number) => {
|
const addColumn = (column: TableColumn, index?: number) => {
|
||||||
const { columns } = unref(getProps)
|
const { columns } = unref(getProps)
|
||||||
if (index) {
|
if (index !== void 0) {
|
||||||
columns.splice(index, 0, column)
|
columns.splice(index, 0, column)
|
||||||
} else {
|
} else {
|
||||||
columns.push(column)
|
columns.push(column)
|
||||||
|
@ -391,14 +383,28 @@ export default defineComponent({
|
||||||
const renderPreview = (url: string) => {
|
const renderPreview = (url: string) => {
|
||||||
return (
|
return (
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<ElImage
|
{isImgPath(url) ? (
|
||||||
src={url}
|
<ElImage
|
||||||
fit="cover"
|
src={url}
|
||||||
class="w-[100%] h-100px"
|
fit="cover"
|
||||||
lazy
|
class="w-[100%]"
|
||||||
preview-src-list={[url]}
|
lazy
|
||||||
preview-teleported
|
preview-src-list={[url]}
|
||||||
/>
|
preview-teleported
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<BaseButton
|
||||||
|
type="primary"
|
||||||
|
icon={<Icon icon="ep:video-play" />}
|
||||||
|
onClick={() => {
|
||||||
|
createVideoViewer({
|
||||||
|
url
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
预览
|
||||||
|
</BaseButton>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -438,6 +444,7 @@ export default defineComponent({
|
||||||
reserveSelection={reserveSelection}
|
reserveSelection={reserveSelection}
|
||||||
align={align}
|
align={align}
|
||||||
headerAlign={headerAlign}
|
headerAlign={headerAlign}
|
||||||
|
selectable={v.selectable}
|
||||||
width="50"
|
width="50"
|
||||||
></ElTableColumn>
|
></ElTableColumn>
|
||||||
)
|
)
|
||||||
|
@ -489,41 +496,68 @@ export default defineComponent({
|
||||||
return () => {
|
return () => {
|
||||||
const tableSlots = {}
|
const tableSlots = {}
|
||||||
if (getSlot(slots, 'empty')) {
|
if (getSlot(slots, 'empty')) {
|
||||||
tableSlots['empty'] = (...args: any[]) => getSlot(slots, 'empty', ...args)
|
tableSlots['empty'] = (...args: any[]) => getSlot(slots, 'empty', args)
|
||||||
}
|
}
|
||||||
if (getSlot(slots, 'append')) {
|
if (getSlot(slots, 'append')) {
|
||||||
tableSlots['append'] = (...args: any[]) => getSlot(slots, 'append', ...args)
|
tableSlots['append'] = (...args: any[]) => getSlot(slots, 'append', args)
|
||||||
}
|
}
|
||||||
|
|
||||||
// const { sortable } = unref(getProps)
|
|
||||||
|
|
||||||
// const sortableEl = sortable ? (
|
|
||||||
// <ElTableColumn
|
|
||||||
// className="table-move cursor-move"
|
|
||||||
// type="sortable"
|
|
||||||
// prop="sortable"
|
|
||||||
// width="60px"
|
|
||||||
// align="center"
|
|
||||||
// >
|
|
||||||
// <Icon icon="ant-design:drag-outlined" />
|
|
||||||
// </ElTableColumn>
|
|
||||||
// ) : null
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div v-loading={unref(getProps).loading}>
|
<div v-loading={unref(getProps).loading}>
|
||||||
{unref(getProps).showAction ? (
|
{unref(getProps).customContent ? (
|
||||||
<TableActions
|
<div class="flex flex-wrap">
|
||||||
columns={unref(getProps).columns}
|
{unref(getProps)?.data?.length ? (
|
||||||
onChangSize={changSize}
|
unref(getProps)?.data.map((item) => {
|
||||||
onRefresh={refresh}
|
const cardSlots = {
|
||||||
/>
|
default: () => {
|
||||||
) : null}
|
return getSlot(slots, 'content', item)
|
||||||
<ElTable ref={elTableRef} data={unref(getProps).data} {...unref(getBindValue)}>
|
}
|
||||||
{{
|
}
|
||||||
default: () => renderTableColumn(),
|
if (getSlot(slots, 'content-header')) {
|
||||||
...tableSlots
|
cardSlots['header'] = () => {
|
||||||
}}
|
return getSlot(slots, 'content-header', item)
|
||||||
</ElTable>
|
}
|
||||||
|
}
|
||||||
|
if (getSlot(slots, 'content-footer')) {
|
||||||
|
cardSlots['footer'] = () => {
|
||||||
|
return getSlot(slots, 'content-footer', item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<ElCard
|
||||||
|
shadow="hover"
|
||||||
|
class={unref(getProps).cardWrapClass}
|
||||||
|
style={unref(getProps).cardWrapStyle}
|
||||||
|
bodyClass={unref(getProps).cardBodyClass}
|
||||||
|
bodyStyle={unref(getProps).cardBodyStyle}
|
||||||
|
>
|
||||||
|
{cardSlots}
|
||||||
|
</ElCard>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
) : (
|
||||||
|
<div class="flex flex-1 justify-center">
|
||||||
|
<ElEmpty description="暂无数据" />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
{unref(getProps).showAction ? (
|
||||||
|
<TableActions
|
||||||
|
columns={unref(getProps).columns}
|
||||||
|
onChangSize={changSize}
|
||||||
|
onRefresh={refresh}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
|
<ElTable ref={elTableRef} data={unref(getProps).data} {...unref(getBindValue)}>
|
||||||
|
{{
|
||||||
|
default: () => renderTableColumn(),
|
||||||
|
...tableSlots
|
||||||
|
}}
|
||||||
|
</ElTable>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
{unref(getProps).pagination ? (
|
{unref(getProps).pagination ? (
|
||||||
<ElPagination
|
<ElPagination
|
||||||
v-model:pageSize={pageSizeRef.value}
|
v-model:pageSize={pageSizeRef.value}
|
||||||
|
|
|
@ -1,49 +1,27 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ElDropdown, ElDropdownMenu, ElDropdownItem, ElMessageBox } from 'element-plus'
|
import { ElDropdown, ElDropdownMenu, ElDropdownItem } from 'element-plus'
|
||||||
import { useI18n } from '@/hooks/web/useI18n'
|
import { useI18n } from '@/hooks/web/useI18n'
|
||||||
import { useStorage } from '@/hooks/web/useStorage'
|
|
||||||
import { resetRouter } from '@/router'
|
|
||||||
import { useRouter } from 'vue-router'
|
|
||||||
import { loginOutApi } from '@/api/login'
|
|
||||||
import { useDesign } from '@/hooks/web/useDesign'
|
import { useDesign } from '@/hooks/web/useDesign'
|
||||||
import { useTagsViewStore } from '@/store/modules/tagsView'
|
|
||||||
import LockDialog from './components/LockDialog.vue'
|
import LockDialog from './components/LockDialog.vue'
|
||||||
import { ref, computed } from 'vue'
|
import { ref, computed } from 'vue'
|
||||||
import LockPage from './components/LockPage.vue'
|
import LockPage from './components/LockPage.vue'
|
||||||
import { useLockStore } from '@/store/modules/lock'
|
import { useLockStore } from '@/store/modules/lock'
|
||||||
|
import { useUserStore } from '@/store/modules/user'
|
||||||
|
|
||||||
|
const userStore = useUserStore()
|
||||||
|
|
||||||
const lockStore = useLockStore()
|
const lockStore = useLockStore()
|
||||||
|
|
||||||
const getIsLock = computed(() => lockStore.getLockInfo?.isLock ?? false)
|
const getIsLock = computed(() => lockStore.getLockInfo?.isLock ?? false)
|
||||||
|
|
||||||
const tagsViewStore = useTagsViewStore()
|
|
||||||
|
|
||||||
const { getPrefixCls } = useDesign()
|
const { getPrefixCls } = useDesign()
|
||||||
|
|
||||||
const prefixCls = getPrefixCls('user-info')
|
const prefixCls = getPrefixCls('user-info')
|
||||||
|
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
|
|
||||||
const { clear } = useStorage()
|
|
||||||
|
|
||||||
const { replace } = useRouter()
|
|
||||||
|
|
||||||
const loginOut = () => {
|
const loginOut = () => {
|
||||||
ElMessageBox.confirm(t('common.loginOutMessage'), t('common.reminder'), {
|
userStore.logoutConfirm()
|
||||||
confirmButtonText: t('common.ok'),
|
|
||||||
cancelButtonText: t('common.cancel'),
|
|
||||||
type: 'warning'
|
|
||||||
})
|
|
||||||
.then(async () => {
|
|
||||||
const res = await loginOutApi().catch(() => {})
|
|
||||||
if (res) {
|
|
||||||
clear()
|
|
||||||
tagsViewStore.delAllViews()
|
|
||||||
resetRouter() // 重置静态路由表
|
|
||||||
replace('/login')
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(() => {})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const dialogVisible = ref<boolean>(false)
|
const dialogVisible = ref<boolean>(false)
|
||||||
|
@ -66,7 +44,9 @@ const toDocument = () => {
|
||||||
alt=""
|
alt=""
|
||||||
class="w-[calc(var(--logo-height)-25px)] rounded-[50%]"
|
class="w-[calc(var(--logo-height)-25px)] rounded-[50%]"
|
||||||
/>
|
/>
|
||||||
<span class="<lg:hidden text-14px pl-[5px] text-[var(--top-header-text-color)]">Archer</span>
|
<span class="<lg:hidden text-14px pl-[5px] text-[var(--top-header-text-color)]">{{
|
||||||
|
userStore.getUserInfo?.username
|
||||||
|
}}</span>
|
||||||
</div>
|
</div>
|
||||||
<template #dropdown>
|
<template #dropdown>
|
||||||
<ElDropdownMenu>
|
<ElDropdownMenu>
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
import { VNode, createVNode, render } from 'vue'
|
||||||
|
import VideoPlayer from './src/VideoPlayer.vue'
|
||||||
|
import { isClient } from '@/utils/is'
|
||||||
|
import { VideoPlayerViewer } from '@/components/VideoPlayerViewer'
|
||||||
|
import { toAnyString } from '@/utils'
|
||||||
|
|
||||||
|
export { VideoPlayer }
|
||||||
|
|
||||||
|
let instance: Nullable<VNode> = null
|
||||||
|
|
||||||
|
export function createVideoViewer(options: { url: string; poster?: string; show?: boolean }) {
|
||||||
|
if (!isClient) return
|
||||||
|
const { url, poster } = options
|
||||||
|
|
||||||
|
const propsData: Partial<{ url: string; poster?: string; show?: boolean; id?: string }> = {}
|
||||||
|
const container = document.createElement('div')
|
||||||
|
const id = toAnyString()
|
||||||
|
container.id = id
|
||||||
|
propsData.url = url
|
||||||
|
propsData.poster = poster
|
||||||
|
propsData.show = true
|
||||||
|
propsData.id = id
|
||||||
|
|
||||||
|
document.body.appendChild(container)
|
||||||
|
instance = createVNode(VideoPlayerViewer, propsData)
|
||||||
|
render(instance, container)
|
||||||
|
}
|
|
@ -0,0 +1,59 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import Player from 'xgplayer'
|
||||||
|
import { ref, unref, onMounted, watch, onBeforeUnmount, nextTick } from 'vue'
|
||||||
|
import 'xgplayer/dist/index.min.css'
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
url: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
poster: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const playerRef = ref<Player>()
|
||||||
|
|
||||||
|
const videoEl = ref<HTMLDivElement>()
|
||||||
|
|
||||||
|
const intiPlayer = () => {
|
||||||
|
if (!unref(videoEl)) return
|
||||||
|
new Player({
|
||||||
|
autoplay: false,
|
||||||
|
...props,
|
||||||
|
el: unref(videoEl)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
intiPlayer()
|
||||||
|
})
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props,
|
||||||
|
async (newProps) => {
|
||||||
|
await nextTick()
|
||||||
|
if (newProps) {
|
||||||
|
unref(playerRef)?.setConfig(newProps)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
deep: true
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
unref(playerRef)?.destroy()
|
||||||
|
})
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
playerExpose: () => unref(playerRef)
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div ref="videoEl"></div>
|
||||||
|
</template>
|
|
@ -0,0 +1,3 @@
|
||||||
|
import VideoPlayerViewer from './src/VideoPlayerViewer.vue'
|
||||||
|
|
||||||
|
export { VideoPlayerViewer }
|
|
@ -0,0 +1,49 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { VideoPlayer } from '@/components/VideoPlayer'
|
||||||
|
import { ElOverlay } from 'element-plus'
|
||||||
|
import { ref, nextTick } from 'vue'
|
||||||
|
import { Icon } from '@/components/Icon'
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
show: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
url: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
poster: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
id: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const visible = ref(props.show)
|
||||||
|
|
||||||
|
const close = async () => {
|
||||||
|
visible.value = false
|
||||||
|
await nextTick()
|
||||||
|
const wrap = document.getElementById(props.id)
|
||||||
|
if (!wrap) return
|
||||||
|
document.body.removeChild(wrap)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<ElOverlay v-show="visible" @click="close">
|
||||||
|
<div class="w-full h-full flex justify-center items-center relative" @click="close">
|
||||||
|
<div
|
||||||
|
class="w-44px h-44px color-[#fff] bg-[var(--el-text-color-regular)] rounded-full border-[#fff] flex justify-center items-center cursor-pointer absolute top-40px right-40px"
|
||||||
|
@click="close"
|
||||||
|
>
|
||||||
|
<Icon icon="ep:close" :size="24" />
|
||||||
|
</div>
|
||||||
|
<VideoPlayer :url="url" :poster="poster" />
|
||||||
|
</div>
|
||||||
|
</ElOverlay>
|
||||||
|
</template>
|
|
@ -1,6 +1,8 @@
|
||||||
import type { App } from 'vue'
|
import type { App } from 'vue'
|
||||||
import { Icon } from './Icon'
|
import { Icon } from './Icon'
|
||||||
|
import { BaseButton } from './Button'
|
||||||
|
|
||||||
export const setupGlobCom = (app: App<Element>): void => {
|
export const setupGlobCom = (app: App<Element>): void => {
|
||||||
app.component('Icon', Icon)
|
app.component('Icon', Icon)
|
||||||
|
app.component('BaseButton', BaseButton)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,99 +0,0 @@
|
||||||
import {
|
|
||||||
AxiosConfig,
|
|
||||||
AxiosResponse,
|
|
||||||
AxiosRequestHeaders,
|
|
||||||
InternalAxiosRequestConfig
|
|
||||||
} from './types'
|
|
||||||
import { ElMessage } from 'element-plus'
|
|
||||||
import qs from 'qs'
|
|
||||||
import { useStorage } from '@/hooks/web/useStorage'
|
|
||||||
|
|
||||||
const { clear } = useStorage()
|
|
||||||
|
|
||||||
const config: AxiosConfig = {
|
|
||||||
/**
|
|
||||||
* api请求基础路径
|
|
||||||
*/
|
|
||||||
baseUrl: {
|
|
||||||
// 开发环境接口前缀
|
|
||||||
base: '',
|
|
||||||
|
|
||||||
// 打包开发环境接口前缀
|
|
||||||
dev: '',
|
|
||||||
|
|
||||||
// 打包生产环境接口前缀
|
|
||||||
pro: '',
|
|
||||||
|
|
||||||
// 打包测试环境接口前缀
|
|
||||||
test: ''
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 接口成功返回状态码
|
|
||||||
*/
|
|
||||||
code: 0,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 接口请求超时时间
|
|
||||||
*/
|
|
||||||
timeout: 60000,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 默认接口请求类型
|
|
||||||
* 可选值:application/x-www-form-urlencoded multipart/form-data
|
|
||||||
*/
|
|
||||||
defaultHeaders: 'application/json',
|
|
||||||
|
|
||||||
interceptors: {
|
|
||||||
//请求拦截
|
|
||||||
// requestInterceptors: (config) => {
|
|
||||||
// return config
|
|
||||||
// },
|
|
||||||
// 响应拦截器
|
|
||||||
// responseInterceptors: (result: AxiosResponse) => {
|
|
||||||
// return result
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const defaultRequestInterceptors = (config: InternalAxiosRequestConfig) => {
|
|
||||||
if (
|
|
||||||
config.method === 'post' &&
|
|
||||||
(config.headers as AxiosRequestHeaders)['Content-Type'] === 'application/x-www-form-urlencoded'
|
|
||||||
) {
|
|
||||||
config.data = qs.stringify(config.data)
|
|
||||||
}
|
|
||||||
if (config.method === 'get' && config.params) {
|
|
||||||
let url = config.url as string
|
|
||||||
url += '?'
|
|
||||||
const keys = Object.keys(config.params)
|
|
||||||
for (const key of keys) {
|
|
||||||
if (config.params[key] !== void 0 && config.params[key] !== null) {
|
|
||||||
url += `${key}=${encodeURIComponent(config.params[key])}&`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
url = url.substring(0, url.length - 1)
|
|
||||||
config.params = {}
|
|
||||||
config.url = url
|
|
||||||
}
|
|
||||||
return config
|
|
||||||
}
|
|
||||||
|
|
||||||
const defaultResponseInterceptors = (response: AxiosResponse<any>) => {
|
|
||||||
if (response?.config?.responseType === 'blob') {
|
|
||||||
// 如果是文件流,直接过
|
|
||||||
return response
|
|
||||||
} else if (response.data.code === config.code) {
|
|
||||||
return response.data
|
|
||||||
} else {
|
|
||||||
ElMessage.error(response?.data?.message)
|
|
||||||
if (response?.data?.code === 401) {
|
|
||||||
// token过期
|
|
||||||
clear()
|
|
||||||
window.location.reload()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export { defaultResponseInterceptors, defaultRequestInterceptors }
|
|
||||||
export default config
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
/**
|
||||||
|
* 请求成功状态码
|
||||||
|
*/
|
||||||
|
export const SUCCESS_CODE = 0
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 请求contentType
|
||||||
|
*/
|
||||||
|
export const CONTENT_TYPE = 'application/json'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 请求超时时间
|
||||||
|
*/
|
||||||
|
export const REQUEST_TIMEOUT = 60000
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 不重定向白名单
|
||||||
|
*/
|
||||||
|
export const NO_REDIRECT_WHITE_LIST = ['/login']
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 不重置路由白名单
|
||||||
|
*/
|
||||||
|
export const NO_RESET_WHITE_LIST = ['Redirect', 'Login', 'NoFind', 'Root']
|
|
@ -91,7 +91,8 @@ export default {
|
||||||
tagsViewIcon: 'Tags view icon',
|
tagsViewIcon: 'Tags view icon',
|
||||||
dynamicRouter: 'Dynamic router',
|
dynamicRouter: 'Dynamic router',
|
||||||
reExperienced: 'Please exit the login experience again',
|
reExperienced: 'Please exit the login experience again',
|
||||||
fixedMenu: 'Fixed menu'
|
fixedMenu: 'Fixed menu',
|
||||||
|
serverDynamicRouter: 'Server dynamic router'
|
||||||
},
|
},
|
||||||
size: {
|
size: {
|
||||||
default: 'Default',
|
default: 'Default',
|
||||||
|
|
|
@ -91,7 +91,8 @@ export default {
|
||||||
tagsViewIcon: '标签页图标',
|
tagsViewIcon: '标签页图标',
|
||||||
dynamicRouter: '动态路由',
|
dynamicRouter: '动态路由',
|
||||||
reExperienced: '请重新退出登录体验',
|
reExperienced: '请重新退出登录体验',
|
||||||
fixedMenu: '固定菜单'
|
fixedMenu: '固定菜单',
|
||||||
|
serverDynamicRouter: '服务端动态路由'
|
||||||
},
|
},
|
||||||
size: {
|
size: {
|
||||||
default: '默认',
|
default: '默认',
|
||||||
|
|
|
@ -1,28 +1,24 @@
|
||||||
import router from './router'
|
import router from './router'
|
||||||
import { useAppStoreWithOut } from '@/store/modules/app'
|
import { useAppStoreWithOut } from '@/store/modules/app'
|
||||||
import { useStorage } from '@/hooks/web/useStorage'
|
|
||||||
import type { RouteRecordRaw } from 'vue-router'
|
import type { RouteRecordRaw } from 'vue-router'
|
||||||
import { useTitle } from '@/hooks/web/useTitle'
|
import { useTitle } from '@/hooks/web/useTitle'
|
||||||
import { useNProgress } from '@/hooks/web/useNProgress'
|
import { useNProgress } from '@/hooks/web/useNProgress'
|
||||||
import { usePermissionStoreWithOut } from '@/store/modules/permission'
|
import { usePermissionStoreWithOut } from '@/store/modules/permission'
|
||||||
import { usePageLoading } from '@/hooks/web/usePageLoading'
|
import { usePageLoading } from '@/hooks/web/usePageLoading'
|
||||||
|
import { NO_REDIRECT_WHITE_LIST } from '@/constants'
|
||||||
const permissionStore = usePermissionStoreWithOut()
|
import { useUserStoreWithOut } from '@/store/modules/user'
|
||||||
|
|
||||||
const appStore = useAppStoreWithOut()
|
|
||||||
|
|
||||||
const { getStorage } = useStorage()
|
|
||||||
|
|
||||||
const { start, done } = useNProgress()
|
const { start, done } = useNProgress()
|
||||||
|
|
||||||
const { loadStart, loadDone } = usePageLoading()
|
const { loadStart, loadDone } = usePageLoading()
|
||||||
|
|
||||||
const whiteList = ['/login'] // 不重定向白名单
|
|
||||||
|
|
||||||
router.beforeEach(async (to, from, next) => {
|
router.beforeEach(async (to, from, next) => {
|
||||||
start()
|
start()
|
||||||
loadStart()
|
loadStart()
|
||||||
if (getStorage(appStore.getUserInfo)) {
|
const permissionStore = usePermissionStoreWithOut()
|
||||||
|
const appStore = useAppStoreWithOut()
|
||||||
|
const userStore = useUserStoreWithOut()
|
||||||
|
if (userStore.getUserInfo) {
|
||||||
if (to.path === '/login') {
|
if (to.path === '/login') {
|
||||||
next({ path: '/' })
|
next({ path: '/' })
|
||||||
} else {
|
} else {
|
||||||
|
@ -32,16 +28,15 @@ router.beforeEach(async (to, from, next) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 开发者可根据实际情况进行修改
|
// 开发者可根据实际情况进行修改
|
||||||
const roleRouters = getStorage('roleRouters') || []
|
const roleRouters = userStore.getRoleRouters || []
|
||||||
const userInfo = getStorage(appStore.getUserInfo)
|
|
||||||
|
|
||||||
// 是否使用动态路由
|
// 是否使用动态路由
|
||||||
if (appStore.getDynamicRouter) {
|
if (appStore.getDynamicRouter) {
|
||||||
userInfo.role === 'admin'
|
appStore.serverDynamicRouter
|
||||||
? await permissionStore.generateRoutes('admin', roleRouters as AppCustomRouteRecordRaw[])
|
? await permissionStore.generateRoutes('server', roleRouters as AppCustomRouteRecordRaw[])
|
||||||
: await permissionStore.generateRoutes('test', roleRouters as string[])
|
: await permissionStore.generateRoutes('frontEnd', roleRouters as string[])
|
||||||
} else {
|
} else {
|
||||||
await permissionStore.generateRoutes('none')
|
await permissionStore.generateRoutes('static')
|
||||||
}
|
}
|
||||||
|
|
||||||
permissionStore.getAddRouters.forEach((route) => {
|
permissionStore.getAddRouters.forEach((route) => {
|
||||||
|
@ -54,7 +49,7 @@ router.beforeEach(async (to, from, next) => {
|
||||||
next(nextData)
|
next(nextData)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (whiteList.indexOf(to.path) !== -1) {
|
if (NO_REDIRECT_WHITE_LIST.indexOf(to.path) !== -1) {
|
||||||
next()
|
next()
|
||||||
} else {
|
} else {
|
||||||
next(`/login?redirect=${to.path}`) // 否则全部重定向到登录页
|
next(`/login?redirect=${to.path}`) // 否则全部重定向到登录页
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import type { App } from 'vue'
|
import type { App } from 'vue'
|
||||||
import { createPinia } from 'pinia'
|
import { createPinia } from 'pinia'
|
||||||
import piniaPersist from 'pinia-plugin-persist'
|
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
|
||||||
|
|
||||||
const store = createPinia()
|
const store = createPinia()
|
||||||
|
|
||||||
store.use(piniaPersist)
|
store.use(piniaPluginPersistedstate)
|
||||||
|
|
||||||
export const setupStore = (app: App<Element>) => {
|
export const setupStore = (app: App<Element>) => {
|
||||||
app.use(store)
|
app.use(store)
|
||||||
|
|
|
@ -2,9 +2,6 @@ import { defineStore } from 'pinia'
|
||||||
import { store } from '../index'
|
import { store } from '../index'
|
||||||
import { setCssVar, humpToUnderline } from '@/utils'
|
import { setCssVar, humpToUnderline } from '@/utils'
|
||||||
import { ElMessage, ComponentSize } from 'element-plus'
|
import { ElMessage, ComponentSize } from 'element-plus'
|
||||||
import { useStorage } from '@/hooks/web/useStorage'
|
|
||||||
|
|
||||||
const { getStorage, setStorage } = useStorage()
|
|
||||||
|
|
||||||
interface AppState {
|
interface AppState {
|
||||||
breadcrumb: boolean
|
breadcrumb: boolean
|
||||||
|
@ -21,10 +18,10 @@ interface AppState {
|
||||||
fixedHeader: boolean
|
fixedHeader: boolean
|
||||||
greyMode: boolean
|
greyMode: boolean
|
||||||
dynamicRouter: boolean
|
dynamicRouter: boolean
|
||||||
|
serverDynamicRouter: boolean
|
||||||
pageLoading: boolean
|
pageLoading: boolean
|
||||||
layout: LayoutType
|
layout: LayoutType
|
||||||
title: string
|
title: string
|
||||||
userInfo: string
|
|
||||||
isDark: boolean
|
isDark: boolean
|
||||||
currentSize: ComponentSize
|
currentSize: ComponentSize
|
||||||
sizeMap: ComponentSize[]
|
sizeMap: ComponentSize[]
|
||||||
|
@ -37,12 +34,10 @@ interface AppState {
|
||||||
export const useAppStore = defineStore('app', {
|
export const useAppStore = defineStore('app', {
|
||||||
state: (): AppState => {
|
state: (): AppState => {
|
||||||
return {
|
return {
|
||||||
userInfo: 'userInfo', // 登录信息存储字段-建议每个项目换一个字段,避免与其它项目冲突
|
|
||||||
sizeMap: ['default', 'large', 'small'],
|
sizeMap: ['default', 'large', 'small'],
|
||||||
mobile: false, // 是否是移动端
|
mobile: false, // 是否是移动端
|
||||||
title: import.meta.env.VITE_APP_TITLE, // 标题
|
title: import.meta.env.VITE_APP_TITLE, // 标题
|
||||||
pageLoading: false, // 路由跳转loading
|
pageLoading: false, // 路由跳转loading
|
||||||
|
|
||||||
breadcrumb: true, // 面包屑
|
breadcrumb: true, // 面包屑
|
||||||
breadcrumbIcon: true, // 面包屑图标
|
breadcrumbIcon: true, // 面包屑图标
|
||||||
collapse: false, // 折叠菜单
|
collapse: false, // 折叠菜单
|
||||||
|
@ -57,13 +52,14 @@ export const useAppStore = defineStore('app', {
|
||||||
fixedHeader: true, // 固定toolheader
|
fixedHeader: true, // 固定toolheader
|
||||||
footer: true, // 显示页脚
|
footer: true, // 显示页脚
|
||||||
greyMode: false, // 是否开始灰色模式,用于特殊悼念日
|
greyMode: false, // 是否开始灰色模式,用于特殊悼念日
|
||||||
dynamicRouter: getStorage('dynamicRouter') || false, // 是否动态路由
|
dynamicRouter: true, // 是否动态路由
|
||||||
fixedMenu: getStorage('fixedMenu') || false, // 是否固定菜单
|
serverDynamicRouter: true, // 是否服务端渲染动态路由
|
||||||
|
fixedMenu: false, // 是否固定菜单
|
||||||
|
|
||||||
layout: getStorage('layout') || 'classic', // layout布局
|
layout: 'classic', // layout布局
|
||||||
isDark: getStorage('isDark') || false, // 是否是暗黑模式
|
isDark: false, // 是否是暗黑模式
|
||||||
currentSize: getStorage('default') || 'default', // 组件尺寸
|
currentSize: 'default', // 组件尺寸
|
||||||
theme: getStorage('theme') || {
|
theme: {
|
||||||
// 主题色
|
// 主题色
|
||||||
elColorPrimary: '#409eff',
|
elColorPrimary: '#409eff',
|
||||||
// 左侧菜单边框颜色
|
// 左侧菜单边框颜色
|
||||||
|
@ -138,6 +134,9 @@ export const useAppStore = defineStore('app', {
|
||||||
getDynamicRouter(): boolean {
|
getDynamicRouter(): boolean {
|
||||||
return this.dynamicRouter
|
return this.dynamicRouter
|
||||||
},
|
},
|
||||||
|
getServerDynamicRouter(): boolean {
|
||||||
|
return this.serverDynamicRouter
|
||||||
|
},
|
||||||
getFixedMenu(): boolean {
|
getFixedMenu(): boolean {
|
||||||
return this.fixedMenu
|
return this.fixedMenu
|
||||||
},
|
},
|
||||||
|
@ -150,9 +149,6 @@ export const useAppStore = defineStore('app', {
|
||||||
getTitle(): string {
|
getTitle(): string {
|
||||||
return this.title
|
return this.title
|
||||||
},
|
},
|
||||||
getUserInfo(): string {
|
|
||||||
return this.userInfo
|
|
||||||
},
|
|
||||||
getIsDark(): boolean {
|
getIsDark(): boolean {
|
||||||
return this.isDark
|
return this.isDark
|
||||||
},
|
},
|
||||||
|
@ -213,11 +209,12 @@ export const useAppStore = defineStore('app', {
|
||||||
this.greyMode = greyMode
|
this.greyMode = greyMode
|
||||||
},
|
},
|
||||||
setDynamicRouter(dynamicRouter: boolean) {
|
setDynamicRouter(dynamicRouter: boolean) {
|
||||||
setStorage('dynamicRouter', dynamicRouter)
|
|
||||||
this.dynamicRouter = dynamicRouter
|
this.dynamicRouter = dynamicRouter
|
||||||
},
|
},
|
||||||
|
setServerDynamicRouter(serverDynamicRouter: boolean) {
|
||||||
|
this.serverDynamicRouter = serverDynamicRouter
|
||||||
|
},
|
||||||
setFixedMenu(fixedMenu: boolean) {
|
setFixedMenu(fixedMenu: boolean) {
|
||||||
setStorage('fixedMenu', fixedMenu)
|
|
||||||
this.fixedMenu = fixedMenu
|
this.fixedMenu = fixedMenu
|
||||||
},
|
},
|
||||||
setPageLoading(pageLoading: boolean) {
|
setPageLoading(pageLoading: boolean) {
|
||||||
|
@ -229,7 +226,6 @@ export const useAppStore = defineStore('app', {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.layout = layout
|
this.layout = layout
|
||||||
setStorage('layout', this.layout)
|
|
||||||
},
|
},
|
||||||
setTitle(title: string) {
|
setTitle(title: string) {
|
||||||
this.title = title
|
this.title = title
|
||||||
|
@ -243,18 +239,15 @@ export const useAppStore = defineStore('app', {
|
||||||
document.documentElement.classList.add('light')
|
document.documentElement.classList.add('light')
|
||||||
document.documentElement.classList.remove('dark')
|
document.documentElement.classList.remove('dark')
|
||||||
}
|
}
|
||||||
setStorage('isDark', this.isDark)
|
|
||||||
},
|
},
|
||||||
setCurrentSize(currentSize: ComponentSize) {
|
setCurrentSize(currentSize: ComponentSize) {
|
||||||
this.currentSize = currentSize
|
this.currentSize = currentSize
|
||||||
setStorage('currentSize', this.currentSize)
|
|
||||||
},
|
},
|
||||||
setMobile(mobile: boolean) {
|
setMobile(mobile: boolean) {
|
||||||
this.mobile = mobile
|
this.mobile = mobile
|
||||||
},
|
},
|
||||||
setTheme(theme: ThemeTypes) {
|
setTheme(theme: ThemeTypes) {
|
||||||
this.theme = Object.assign(this.theme, theme)
|
this.theme = Object.assign(this.theme, theme)
|
||||||
setStorage('theme', this.theme)
|
|
||||||
},
|
},
|
||||||
setCssVarTheme() {
|
setCssVarTheme() {
|
||||||
for (const key in this.theme) {
|
for (const key in this.theme) {
|
||||||
|
@ -264,7 +257,8 @@ export const useAppStore = defineStore('app', {
|
||||||
setFooter(footer: boolean) {
|
setFooter(footer: boolean) {
|
||||||
this.footer = footer
|
this.footer = footer
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
persist: true
|
||||||
})
|
})
|
||||||
|
|
||||||
export const useAppStoreWithOut = () => {
|
export const useAppStoreWithOut = () => {
|
||||||
|
|
|
@ -1,34 +0,0 @@
|
||||||
import { defineStore } from 'pinia'
|
|
||||||
import { store } from '../index'
|
|
||||||
|
|
||||||
export interface DictState {
|
|
||||||
isSetDict: boolean
|
|
||||||
dictObj: Recordable
|
|
||||||
}
|
|
||||||
|
|
||||||
export const useDictStore = defineStore('dict', {
|
|
||||||
state: (): DictState => ({
|
|
||||||
isSetDict: false,
|
|
||||||
dictObj: {}
|
|
||||||
}),
|
|
||||||
getters: {
|
|
||||||
getDictObj(): Recordable {
|
|
||||||
return this.dictObj
|
|
||||||
},
|
|
||||||
getIsSetDict(): boolean {
|
|
||||||
return this.isSetDict
|
|
||||||
}
|
|
||||||
},
|
|
||||||
actions: {
|
|
||||||
setDictObj(dictObj: Recordable) {
|
|
||||||
this.dictObj = dictObj
|
|
||||||
},
|
|
||||||
setIsSetDict(isSetDict: boolean) {
|
|
||||||
this.isSetDict = isSetDict
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
export const useDictStoreWithOut = () => {
|
|
||||||
return useDictStore(store)
|
|
||||||
}
|
|
|
@ -40,10 +40,7 @@ export const useLockStore = defineStore('lock', {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
persist: {
|
persist: true
|
||||||
enabled: true,
|
|
||||||
strategies: [{ key: 'lock', storage: localStorage }]
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
export const useLockStoreWithOut = () => {
|
export const useLockStoreWithOut = () => {
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
import { defineStore } from 'pinia'
|
import { defineStore } from 'pinia'
|
||||||
import { asyncRouterMap, constantRouterMap } from '@/router'
|
import { asyncRouterMap, constantRouterMap } from '@/router'
|
||||||
import { generateRoutesFn1, generateRoutesFn2, flatMultiLevelRoutes } from '@/utils/routerHelper'
|
import {
|
||||||
|
generateRoutesByFrontEnd,
|
||||||
|
generateRoutesByServer,
|
||||||
|
flatMultiLevelRoutes
|
||||||
|
} from '@/utils/routerHelper'
|
||||||
import { store } from '../index'
|
import { store } from '../index'
|
||||||
import { cloneDeep } from 'lodash-es'
|
import { cloneDeep } from 'lodash-es'
|
||||||
|
|
||||||
|
@ -34,17 +38,17 @@ export const usePermissionStore = defineStore('permission', {
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
generateRoutes(
|
generateRoutes(
|
||||||
type: 'admin' | 'test' | 'none',
|
type: 'server' | 'frontEnd' | 'static',
|
||||||
routers?: AppCustomRouteRecordRaw[] | string[]
|
routers?: AppCustomRouteRecordRaw[] | string[]
|
||||||
): Promise<unknown> {
|
): Promise<unknown> {
|
||||||
return new Promise<void>((resolve) => {
|
return new Promise<void>((resolve) => {
|
||||||
let routerMap: AppRouteRecordRaw[] = []
|
let routerMap: AppRouteRecordRaw[] = []
|
||||||
if (type === 'admin') {
|
if (type === 'server') {
|
||||||
// 模拟后端过滤菜单
|
// 模拟后端过滤菜单
|
||||||
routerMap = generateRoutesFn2(routers as AppCustomRouteRecordRaw[])
|
routerMap = generateRoutesByServer(routers as AppCustomRouteRecordRaw[])
|
||||||
} else if (type === 'test') {
|
} else if (type === 'frontEnd') {
|
||||||
// 模拟前端过滤菜单
|
// 模拟前端过滤菜单
|
||||||
routerMap = generateRoutesFn1(cloneDeep(asyncRouterMap), routers as string[])
|
routerMap = generateRoutesByFrontEnd(cloneDeep(asyncRouterMap), routers as string[])
|
||||||
} else {
|
} else {
|
||||||
// 直接读取静态路由表
|
// 直接读取静态路由表
|
||||||
routerMap = cloneDeep(asyncRouterMap)
|
routerMap = cloneDeep(asyncRouterMap)
|
||||||
|
@ -72,6 +76,9 @@ export const usePermissionStore = defineStore('permission', {
|
||||||
setMenuTabRouters(routers: AppRouteRecordRaw[]): void {
|
setMenuTabRouters(routers: AppRouteRecordRaw[]): void {
|
||||||
this.menuTabRouters = routers
|
this.menuTabRouters = routers
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
persist: {
|
||||||
|
paths: ['routers', 'addRouters', 'menuTabRouters']
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -4,16 +4,19 @@ import { getRawRoute } from '@/utils/routerHelper'
|
||||||
import { defineStore } from 'pinia'
|
import { defineStore } from 'pinia'
|
||||||
import { store } from '../index'
|
import { store } from '../index'
|
||||||
import { findIndex } from '@/utils'
|
import { findIndex } from '@/utils'
|
||||||
|
import { useUserStoreWithOut } from './user'
|
||||||
|
|
||||||
export interface TagsViewState {
|
export interface TagsViewState {
|
||||||
visitedViews: RouteLocationNormalizedLoaded[]
|
visitedViews: RouteLocationNormalizedLoaded[]
|
||||||
cachedViews: Set<string>
|
cachedViews: Set<string>
|
||||||
|
selectedTag?: RouteLocationNormalizedLoaded
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useTagsViewStore = defineStore('tagsView', {
|
export const useTagsViewStore = defineStore('tagsView', {
|
||||||
state: (): TagsViewState => ({
|
state: (): TagsViewState => ({
|
||||||
visitedViews: [],
|
visitedViews: [],
|
||||||
cachedViews: new Set()
|
cachedViews: new Set(),
|
||||||
|
selectedTag: undefined
|
||||||
}),
|
}),
|
||||||
getters: {
|
getters: {
|
||||||
getVisitedViews(): RouteLocationNormalizedLoaded[] {
|
getVisitedViews(): RouteLocationNormalizedLoaded[] {
|
||||||
|
@ -21,6 +24,9 @@ export const useTagsViewStore = defineStore('tagsView', {
|
||||||
},
|
},
|
||||||
getCachedViews(): string[] {
|
getCachedViews(): string[] {
|
||||||
return Array.from(this.cachedViews)
|
return Array.from(this.cachedViews)
|
||||||
|
},
|
||||||
|
getSelectedTag(): RouteLocationNormalizedLoaded | undefined {
|
||||||
|
return this.selectedTag
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
|
@ -44,7 +50,7 @@ export const useTagsViewStore = defineStore('tagsView', {
|
||||||
const cacheMap: Set<string> = new Set()
|
const cacheMap: Set<string> = new Set()
|
||||||
for (const v of this.visitedViews) {
|
for (const v of this.visitedViews) {
|
||||||
const item = getRawRoute(v)
|
const item = getRawRoute(v)
|
||||||
const needCache = !item.meta?.noCache
|
const needCache = !item?.meta?.noCache
|
||||||
if (!needCache) {
|
if (!needCache) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -84,8 +90,12 @@ export const useTagsViewStore = defineStore('tagsView', {
|
||||||
},
|
},
|
||||||
// 删除所有tag
|
// 删除所有tag
|
||||||
delAllVisitedViews() {
|
delAllVisitedViews() {
|
||||||
|
const userStore = useUserStoreWithOut()
|
||||||
|
|
||||||
// const affixTags = this.visitedViews.filter((tag) => tag.meta.affix)
|
// const affixTags = this.visitedViews.filter((tag) => tag.meta.affix)
|
||||||
this.visitedViews = []
|
this.visitedViews = userStore.getUserInfo
|
||||||
|
? this.visitedViews.filter((tag) => tag?.meta?.affix)
|
||||||
|
: []
|
||||||
},
|
},
|
||||||
// 删除其它
|
// 删除其它
|
||||||
delOthersViews(view: RouteLocationNormalizedLoaded) {
|
delOthersViews(view: RouteLocationNormalizedLoaded) {
|
||||||
|
@ -131,8 +141,21 @@ export const useTagsViewStore = defineStore('tagsView', {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
// 设置当前选中的tag
|
||||||
|
setSelectedTag(tag: RouteLocationNormalizedLoaded) {
|
||||||
|
this.selectedTag = tag
|
||||||
|
},
|
||||||
|
setTitle(title: string, path?: string) {
|
||||||
|
for (const v of this.visitedViews) {
|
||||||
|
if (v.path === (path ?? this.selectedTag?.path)) {
|
||||||
|
v.meta.title = title
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
persist: false
|
||||||
})
|
})
|
||||||
|
|
||||||
export const useTagsViewStoreWithOut = () => {
|
export const useTagsViewStoreWithOut = () => {
|
||||||
|
|
|
@ -0,0 +1,102 @@
|
||||||
|
import { defineStore } from 'pinia'
|
||||||
|
import { store } from '../index'
|
||||||
|
import { UserLoginType, UserType } from '@/api/login/types'
|
||||||
|
import { ElMessageBox } from 'element-plus'
|
||||||
|
import { useI18n } from '@/hooks/web/useI18n'
|
||||||
|
import { loginOutApi } from '@/api/login'
|
||||||
|
import { useTagsViewStore } from './tagsView'
|
||||||
|
import router from '@/router'
|
||||||
|
|
||||||
|
interface UserState {
|
||||||
|
userInfo?: UserType
|
||||||
|
tokenKey: string
|
||||||
|
token: string
|
||||||
|
roleRouters?: string[] | AppCustomRouteRecordRaw[]
|
||||||
|
rememberMe: boolean
|
||||||
|
loginInfo?: UserLoginType
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useUserStore = defineStore('user', {
|
||||||
|
state: (): UserState => {
|
||||||
|
return {
|
||||||
|
userInfo: undefined,
|
||||||
|
tokenKey: 'Authorization',
|
||||||
|
token: '',
|
||||||
|
roleRouters: undefined,
|
||||||
|
// 记住我
|
||||||
|
rememberMe: true,
|
||||||
|
loginInfo: undefined
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getters: {
|
||||||
|
getTokenKey(): string {
|
||||||
|
return this.tokenKey
|
||||||
|
},
|
||||||
|
getToken(): string {
|
||||||
|
return this.token
|
||||||
|
},
|
||||||
|
getUserInfo(): UserType | undefined {
|
||||||
|
return this.userInfo
|
||||||
|
},
|
||||||
|
getRoleRouters(): string[] | AppCustomRouteRecordRaw[] | undefined {
|
||||||
|
return this.roleRouters
|
||||||
|
},
|
||||||
|
getRememberMe(): boolean {
|
||||||
|
return this.rememberMe
|
||||||
|
},
|
||||||
|
getLoginInfo(): UserLoginType | undefined {
|
||||||
|
return this.loginInfo
|
||||||
|
}
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
setTokenKey(tokenKey: string) {
|
||||||
|
this.tokenKey = tokenKey
|
||||||
|
},
|
||||||
|
setToken(token: string) {
|
||||||
|
this.token = token
|
||||||
|
},
|
||||||
|
setUserInfo(userInfo?: UserType) {
|
||||||
|
this.userInfo = userInfo
|
||||||
|
},
|
||||||
|
setRoleRouters(roleRouters: string[] | AppCustomRouteRecordRaw[]) {
|
||||||
|
this.roleRouters = roleRouters
|
||||||
|
},
|
||||||
|
logoutConfirm() {
|
||||||
|
const { t } = useI18n()
|
||||||
|
ElMessageBox.confirm(t('common.loginOutMessage'), t('common.reminder'), {
|
||||||
|
confirmButtonText: t('common.ok'),
|
||||||
|
cancelButtonText: t('common.cancel'),
|
||||||
|
type: 'warning'
|
||||||
|
})
|
||||||
|
.then(async () => {
|
||||||
|
const res = await loginOutApi().catch(() => {})
|
||||||
|
if (res) {
|
||||||
|
this.reset()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(() => {})
|
||||||
|
},
|
||||||
|
reset() {
|
||||||
|
const tagsViewStore = useTagsViewStore()
|
||||||
|
tagsViewStore.delAllViews()
|
||||||
|
this.setToken('')
|
||||||
|
this.setUserInfo(undefined)
|
||||||
|
this.setRoleRouters([])
|
||||||
|
router.replace('/login')
|
||||||
|
},
|
||||||
|
logout() {
|
||||||
|
this.reset()
|
||||||
|
},
|
||||||
|
setRememberMe(rememberMe: boolean) {
|
||||||
|
this.rememberMe = rememberMe
|
||||||
|
},
|
||||||
|
setLoginInfo(loginInfo: UserLoginType | undefined) {
|
||||||
|
this.loginInfo = loginInfo
|
||||||
|
}
|
||||||
|
},
|
||||||
|
persist: true
|
||||||
|
})
|
||||||
|
|
||||||
|
export const useUserStoreWithOut = () => {
|
||||||
|
return useUserStore(store)
|
||||||
|
}
|
|
@ -3,7 +3,6 @@ import type {
|
||||||
Router,
|
Router,
|
||||||
RouteLocationNormalized,
|
RouteLocationNormalized,
|
||||||
RouteRecordNormalized,
|
RouteRecordNormalized,
|
||||||
RouteMeta,
|
|
||||||
RouteRecordRaw
|
RouteRecordRaw
|
||||||
} from 'vue-router'
|
} from 'vue-router'
|
||||||
import { isUrl } from '@/utils/is'
|
import { isUrl } from '@/utils/is'
|
||||||
|
@ -39,7 +38,7 @@ export const getRawRoute = (route: RouteLocationNormalized): RouteLocationNormal
|
||||||
}
|
}
|
||||||
|
|
||||||
// 前端控制路由生成
|
// 前端控制路由生成
|
||||||
export const generateRoutesFn1 = (
|
export const generateRoutesByFrontEnd = (
|
||||||
routes: AppRouteRecordRaw[],
|
routes: AppRouteRecordRaw[],
|
||||||
keys: string[],
|
keys: string[],
|
||||||
basePath = '/'
|
basePath = '/'
|
||||||
|
@ -47,7 +46,7 @@ export const generateRoutesFn1 = (
|
||||||
const res: AppRouteRecordRaw[] = []
|
const res: AppRouteRecordRaw[] = []
|
||||||
|
|
||||||
for (const route of routes) {
|
for (const route of routes) {
|
||||||
const meta = route.meta as RouteMeta
|
const meta = route.meta ?? {}
|
||||||
// skip some route
|
// skip some route
|
||||||
if (meta.hidden && !meta.canTo) {
|
if (meta.hidden && !meta.canTo) {
|
||||||
continue
|
continue
|
||||||
|
@ -70,7 +69,7 @@ export const generateRoutesFn1 = (
|
||||||
if (isUrl(item) && (onlyOneChild === item || route.path === item)) {
|
if (isUrl(item) && (onlyOneChild === item || route.path === item)) {
|
||||||
data = Object.assign({}, route)
|
data = Object.assign({}, route)
|
||||||
} else {
|
} else {
|
||||||
const routePath = onlyOneChild ?? pathResolve(basePath, route.path)
|
const routePath = (onlyOneChild ?? pathResolve(basePath, route.path)).trim()
|
||||||
if (routePath === item || meta.followRoute === item) {
|
if (routePath === item || meta.followRoute === item) {
|
||||||
data = Object.assign({}, route)
|
data = Object.assign({}, route)
|
||||||
}
|
}
|
||||||
|
@ -79,7 +78,11 @@ export const generateRoutesFn1 = (
|
||||||
|
|
||||||
// recursive child routes
|
// recursive child routes
|
||||||
if (route.children && data) {
|
if (route.children && data) {
|
||||||
data.children = generateRoutesFn1(route.children, keys, pathResolve(basePath, data.path))
|
data.children = generateRoutesByFrontEnd(
|
||||||
|
route.children,
|
||||||
|
keys,
|
||||||
|
pathResolve(basePath, data.path)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
if (data) {
|
if (data) {
|
||||||
res.push(data as AppRouteRecordRaw)
|
res.push(data as AppRouteRecordRaw)
|
||||||
|
@ -89,7 +92,7 @@ export const generateRoutesFn1 = (
|
||||||
}
|
}
|
||||||
|
|
||||||
// 后端控制路由生成
|
// 后端控制路由生成
|
||||||
export const generateRoutesFn2 = (routes: AppCustomRouteRecordRaw[]): AppRouteRecordRaw[] => {
|
export const generateRoutesByServer = (routes: AppCustomRouteRecordRaw[]): AppRouteRecordRaw[] => {
|
||||||
const res: AppRouteRecordRaw[] = []
|
const res: AppRouteRecordRaw[] = []
|
||||||
|
|
||||||
for (const route of routes) {
|
for (const route of routes) {
|
||||||
|
@ -112,7 +115,7 @@ export const generateRoutesFn2 = (routes: AppCustomRouteRecordRaw[]): AppRouteRe
|
||||||
}
|
}
|
||||||
// recursive child routes
|
// recursive child routes
|
||||||
if (route.children) {
|
if (route.children) {
|
||||||
data.children = generateRoutesFn2(route.children)
|
data.children = generateRoutesByServer(route.children)
|
||||||
}
|
}
|
||||||
res.push(data as AppRouteRecordRaw)
|
res.push(data as AppRouteRecordRaw)
|
||||||
}
|
}
|
||||||
|
@ -122,7 +125,7 @@ export const generateRoutesFn2 = (routes: AppCustomRouteRecordRaw[]): AppRouteRe
|
||||||
export const pathResolve = (parentPath: string, path: string) => {
|
export const pathResolve = (parentPath: string, path: string) => {
|
||||||
if (isUrl(path)) return path
|
if (isUrl(path)) return path
|
||||||
const childPath = path.startsWith('/') || !path ? path : `/${path}`
|
const childPath = path.startsWith('/') || !path ? path : `/${path}`
|
||||||
return `${parentPath}${childPath}`.replace(/\/\//g, '/')
|
return `${parentPath}${childPath}`.replace(/\/\//g, '/').trim()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 路由降级
|
// 路由降级
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
<script setup lang="tsx">
|
<script setup lang="tsx">
|
||||||
import { reactive, ref, watch } from 'vue'
|
import { reactive, ref, watch, onMounted, unref } from 'vue'
|
||||||
import { Form, FormSchema } from '@/components/Form'
|
import { Form, FormSchema } from '@/components/Form'
|
||||||
import { useI18n } from '@/hooks/web/useI18n'
|
import { useI18n } from '@/hooks/web/useI18n'
|
||||||
import { ElButton, ElCheckbox, ElLink } from 'element-plus'
|
import { ElCheckbox, ElLink } from 'element-plus'
|
||||||
import { useForm } from '@/hooks/web/useForm'
|
import { useForm } from '@/hooks/web/useForm'
|
||||||
import { loginApi, getTestRoleApi, getAdminRoleApi } from '@/api/login'
|
import { loginApi, getTestRoleApi, getAdminRoleApi } from '@/api/login'
|
||||||
import { useStorage } from '@/hooks/web/useStorage'
|
|
||||||
import { useAppStore } from '@/store/modules/app'
|
import { useAppStore } from '@/store/modules/app'
|
||||||
import { usePermissionStore } from '@/store/modules/permission'
|
import { usePermissionStore } from '@/store/modules/permission'
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
|
@ -13,6 +12,8 @@ import type { RouteLocationNormalizedLoaded, RouteRecordRaw } from 'vue-router'
|
||||||
import { UserType } from '@/api/login/types'
|
import { UserType } from '@/api/login/types'
|
||||||
import { useValidator } from '@/hooks/web/useValidator'
|
import { useValidator } from '@/hooks/web/useValidator'
|
||||||
import { Icon } from '@/components/Icon'
|
import { Icon } from '@/components/Icon'
|
||||||
|
import { useUserStore } from '@/store/modules/user'
|
||||||
|
import { BaseButton } from '@/components/Button'
|
||||||
|
|
||||||
const { required } = useValidator()
|
const { required } = useValidator()
|
||||||
|
|
||||||
|
@ -20,12 +21,12 @@ const emit = defineEmits(['to-register'])
|
||||||
|
|
||||||
const appStore = useAppStore()
|
const appStore = useAppStore()
|
||||||
|
|
||||||
|
const userStore = useUserStore()
|
||||||
|
|
||||||
const permissionStore = usePermissionStore()
|
const permissionStore = usePermissionStore()
|
||||||
|
|
||||||
const { currentRoute, addRoute, push } = useRouter()
|
const { currentRoute, addRoute, push } = useRouter()
|
||||||
|
|
||||||
const { setStorage } = useStorage()
|
|
||||||
|
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
|
|
||||||
const rules = {
|
const rules = {
|
||||||
|
@ -50,19 +51,19 @@ const schema = reactive<FormSchema[]>([
|
||||||
{
|
{
|
||||||
field: 'username',
|
field: 'username',
|
||||||
label: t('login.username'),
|
label: t('login.username'),
|
||||||
value: 'admin',
|
// value: 'admin',
|
||||||
component: 'Input',
|
component: 'Input',
|
||||||
colProps: {
|
colProps: {
|
||||||
span: 24
|
span: 24
|
||||||
},
|
},
|
||||||
componentProps: {
|
componentProps: {
|
||||||
placeholder: t('login.usernamePlaceholder')
|
placeholder: 'admin or test'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'password',
|
field: 'password',
|
||||||
label: t('login.password'),
|
label: t('login.password'),
|
||||||
value: 'admin',
|
// value: 'admin',
|
||||||
component: 'InputPassword',
|
component: 'InputPassword',
|
||||||
colProps: {
|
colProps: {
|
||||||
span: 24
|
span: 24
|
||||||
|
@ -71,7 +72,7 @@ const schema = reactive<FormSchema[]>([
|
||||||
style: {
|
style: {
|
||||||
width: '100%'
|
width: '100%'
|
||||||
},
|
},
|
||||||
placeholder: t('login.passwordPlaceholder')
|
placeholder: 'admin or test'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -107,14 +108,19 @@ const schema = reactive<FormSchema[]>([
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div class="w-[100%]">
|
<div class="w-[100%]">
|
||||||
<ElButton loading={loading.value} type="primary" class="w-[100%]" onClick={signIn}>
|
<BaseButton
|
||||||
|
loading={loading.value}
|
||||||
|
type="primary"
|
||||||
|
class="w-[100%]"
|
||||||
|
onClick={signIn}
|
||||||
|
>
|
||||||
{t('login.login')}
|
{t('login.login')}
|
||||||
</ElButton>
|
</BaseButton>
|
||||||
</div>
|
</div>
|
||||||
<div class="w-[100%] mt-15px">
|
<div class="w-[100%] mt-15px">
|
||||||
<ElButton class="w-[100%]" onClick={toRegister}>
|
<BaseButton class="w-[100%]" onClick={toRegister}>
|
||||||
{t('login.register')}
|
{t('login.register')}
|
||||||
</ElButton>
|
</BaseButton>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
@ -180,10 +186,21 @@ const schema = reactive<FormSchema[]>([
|
||||||
|
|
||||||
const iconSize = 30
|
const iconSize = 30
|
||||||
|
|
||||||
const remember = ref(false)
|
const remember = ref(userStore.getRememberMe)
|
||||||
|
|
||||||
|
const initLoginInfo = () => {
|
||||||
|
const loginInfo = userStore.getLoginInfo
|
||||||
|
if (loginInfo) {
|
||||||
|
const { username, password } = loginInfo
|
||||||
|
setValues({ username, password })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onMounted(() => {
|
||||||
|
initLoginInfo()
|
||||||
|
})
|
||||||
|
|
||||||
const { formRegister, formMethods } = useForm()
|
const { formRegister, formMethods } = useForm()
|
||||||
const { getFormData, getElFormExpose } = formMethods
|
const { getFormData, getElFormExpose, setValues } = formMethods
|
||||||
|
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
|
|
||||||
|
@ -205,13 +222,6 @@ watch(
|
||||||
|
|
||||||
// 登录
|
// 登录
|
||||||
const signIn = async () => {
|
const signIn = async () => {
|
||||||
await permissionStore.generateRoutes('none').catch(() => {})
|
|
||||||
permissionStore.getAddRouters.forEach((route) => {
|
|
||||||
addRoute(route as RouteRecordRaw) // 动态添加可访问路由表
|
|
||||||
})
|
|
||||||
permissionStore.setIsAddRouters(true)
|
|
||||||
push({ path: redirect.value || permissionStore.addRouters[0].path })
|
|
||||||
|
|
||||||
const formRef = await getElFormExpose()
|
const formRef = await getElFormExpose()
|
||||||
await formRef?.validate(async (isValid) => {
|
await formRef?.validate(async (isValid) => {
|
||||||
if (isValid) {
|
if (isValid) {
|
||||||
|
@ -222,12 +232,22 @@ const signIn = async () => {
|
||||||
const res = await loginApi(formData)
|
const res = await loginApi(formData)
|
||||||
|
|
||||||
if (res) {
|
if (res) {
|
||||||
setStorage(appStore.getUserInfo, res.data)
|
// 是否记住我
|
||||||
|
if (unref(remember)) {
|
||||||
|
userStore.setLoginInfo({
|
||||||
|
username: formData.username,
|
||||||
|
password: formData.password
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
userStore.setLoginInfo(undefined)
|
||||||
|
}
|
||||||
|
userStore.setRememberMe(unref(remember))
|
||||||
|
userStore.setUserInfo(res.data)
|
||||||
// 是否使用动态路由
|
// 是否使用动态路由
|
||||||
if (appStore.getDynamicRouter) {
|
if (appStore.getDynamicRouter) {
|
||||||
getRole()
|
getRole()
|
||||||
} else {
|
} else {
|
||||||
await permissionStore.generateRoutes('none').catch(() => {})
|
await permissionStore.generateRoutes('static').catch(() => {})
|
||||||
permissionStore.getAddRouters.forEach((route) => {
|
permissionStore.getAddRouters.forEach((route) => {
|
||||||
addRoute(route as RouteRecordRaw) // 动态添加可访问路由表
|
addRoute(route as RouteRecordRaw) // 动态添加可访问路由表
|
||||||
})
|
})
|
||||||
|
@ -248,17 +268,16 @@ const getRole = async () => {
|
||||||
const params = {
|
const params = {
|
||||||
roleName: formData.username
|
roleName: formData.username
|
||||||
}
|
}
|
||||||
// admin - 模拟后端过滤菜单
|
|
||||||
// test - 模拟前端过滤菜单
|
|
||||||
const res =
|
const res =
|
||||||
formData.username === 'admin' ? await getAdminRoleApi(params) : await getTestRoleApi(params)
|
appStore.getDynamicRouter && appStore.getServerDynamicRouter
|
||||||
|
? await getAdminRoleApi(params)
|
||||||
|
: await getTestRoleApi(params)
|
||||||
if (res) {
|
if (res) {
|
||||||
const routers = res.data || []
|
const routers = res.data || []
|
||||||
setStorage('roleRouters', routers)
|
userStore.setRoleRouters(routers)
|
||||||
|
appStore.getDynamicRouter && appStore.getServerDynamicRouter
|
||||||
formData.username === 'admin'
|
? await permissionStore.generateRoutes('server', routers).catch(() => {})
|
||||||
? await permissionStore.generateRoutes('admin', routers).catch(() => {})
|
: await permissionStore.generateRoutes('frontEnd', routers).catch(() => {})
|
||||||
: await permissionStore.generateRoutes('test', routers).catch(() => {})
|
|
||||||
|
|
||||||
permissionStore.getAddRouters.forEach((route) => {
|
permissionStore.getAddRouters.forEach((route) => {
|
||||||
addRoute(route as RouteRecordRaw) // 动态添加可访问路由表
|
addRoute(route as RouteRecordRaw) // 动态添加可访问路由表
|
||||||
|
|
|
@ -215,6 +215,8 @@ module.exports = {
|
||||||
extends: ['stylelint-config-recommended', 'stylelint-config-html'],
|
extends: ['stylelint-config-recommended', 'stylelint-config-html'],
|
||||||
rules: {
|
rules: {
|
||||||
'keyframes-name-pattern': null,
|
'keyframes-name-pattern': null,
|
||||||
|
'selector-class-pattern': null,
|
||||||
|
'no-duplicate-selectors': null,
|
||||||
'selector-pseudo-class-no-unknown': [
|
'selector-pseudo-class-no-unknown': [
|
||||||
true,
|
true,
|
||||||
{
|
{
|
||||||
|
|
|
@ -27,8 +27,8 @@
|
||||||
"@intlify/unplugin-vue-i18n/types",
|
"@intlify/unplugin-vue-i18n/types",
|
||||||
"vite/client",
|
"vite/client",
|
||||||
"element-plus/global",
|
"element-plus/global",
|
||||||
"vite-plugin-svg-icons/client",
|
"@types/qrcode",
|
||||||
"unplugin-vue-define-options/macros-global"
|
"vite-plugin-svg-icons/client"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"include": ["src", "types/**/*.d.ts", "mock/**/*.ts"]
|
"include": ["src", "types/**/*.d.ts", "mock/**/*.ts"]
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
declare module 'vue' {
|
declare module 'vue' {
|
||||||
export interface GlobalComponents {
|
export interface GlobalComponents {
|
||||||
Icon: typeof import('../components/Icon/src/Icon.vue')['default']
|
Icon: (typeof import('../components/Icon/src/Icon.vue'))['default']
|
||||||
|
BaseButton: (typeof import('../components/Button/src/Button.vue'))['default']
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import type { CSSProperties } from 'vue'
|
import type { CSSProperties } from 'vue'
|
||||||
|
import { RawAxiosRequestHeaders } from 'axios'
|
||||||
declare global {
|
declare global {
|
||||||
declare interface Fn<T = any> {
|
declare interface Fn<T = any> {
|
||||||
(...arg: T[]): T
|
(...arg: T[]): T
|
||||||
|
@ -25,7 +26,7 @@ declare global {
|
||||||
|
|
||||||
declare type LayoutType = 'classic' | 'topLeft' | 'top' | 'cutMenu'
|
declare type LayoutType = 'classic' | 'topLeft' | 'top' | 'cutMenu'
|
||||||
|
|
||||||
declare type AxiosHeaders =
|
declare type AxiosContentType =
|
||||||
| 'application/json'
|
| 'application/json'
|
||||||
| 'application/x-www-form-urlencoded'
|
| 'application/x-www-form-urlencoded'
|
||||||
| 'multipart/form-data'
|
| 'multipart/form-data'
|
||||||
|
@ -39,12 +40,12 @@ declare global {
|
||||||
data?: any
|
data?: any
|
||||||
url?: string
|
url?: string
|
||||||
method?: AxiosMethod
|
method?: AxiosMethod
|
||||||
headersType?: string
|
headers?: RawAxiosRequestHeaders
|
||||||
responseType?: AxiosResponseType
|
responseType?: AxiosResponseType
|
||||||
}
|
}
|
||||||
|
|
||||||
declare interface IResponse<T = any> {
|
declare interface IResponse<T = any> {
|
||||||
code: string
|
code: number
|
||||||
data: T extends any ? T : T & any
|
data: T extends any ? T : T & any
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,6 @@ import { viteMockServe } from 'vite-plugin-mock'
|
||||||
import PurgeIcons from 'vite-plugin-purge-icons'
|
import PurgeIcons from 'vite-plugin-purge-icons'
|
||||||
import VueI18nPlugin from "@intlify/unplugin-vue-i18n/vite"
|
import VueI18nPlugin from "@intlify/unplugin-vue-i18n/vite"
|
||||||
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'
|
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'
|
||||||
import DefineOptions from "unplugin-vue-define-options/vite"
|
|
||||||
import { createStyleImportPlugin, ElementPlusResolve } from 'vite-plugin-style-import'
|
import { createStyleImportPlugin, ElementPlusResolve } from 'vite-plugin-style-import'
|
||||||
import UnoCSS from 'unocss/vite'
|
import UnoCSS from 'unocss/vite'
|
||||||
|
|
||||||
|
@ -32,9 +31,13 @@ export default ({ command, mode }: ConfigEnv): UserConfig => {
|
||||||
return {
|
return {
|
||||||
base: env.VITE_BASE_PATH,
|
base: env.VITE_BASE_PATH,
|
||||||
plugins: [
|
plugins: [
|
||||||
Vue(),
|
Vue({
|
||||||
|
script: {
|
||||||
|
// 开启defineModel
|
||||||
|
defineModel: true
|
||||||
|
}
|
||||||
|
}),
|
||||||
VueJsx(),
|
VueJsx(),
|
||||||
// WindiCSS(),
|
|
||||||
progress(),
|
progress(),
|
||||||
createStyleImportPlugin({
|
createStyleImportPlugin({
|
||||||
resolves: [ElementPlusResolve()],
|
resolves: [ElementPlusResolve()],
|
||||||
|
@ -75,7 +78,6 @@ export default ({ command, mode }: ConfigEnv): UserConfig => {
|
||||||
setupProdMockServer()
|
setupProdMockServer()
|
||||||
`
|
`
|
||||||
}),
|
}),
|
||||||
DefineOptions(),
|
|
||||||
ViteEjsPlugin({
|
ViteEjsPlugin({
|
||||||
title: env.VITE_APP_TITLE
|
title: env.VITE_APP_TITLE
|
||||||
}),
|
}),
|
||||||
|
@ -142,11 +144,10 @@ export default ({ command, mode }: ConfigEnv): UserConfig => {
|
||||||
'@vueuse/core',
|
'@vueuse/core',
|
||||||
'axios',
|
'axios',
|
||||||
'qs',
|
'qs',
|
||||||
'echarts',
|
'@zxcvbn-ts/core',
|
||||||
'echarts-wordcloud',
|
'dayjs',
|
||||||
'@wangeditor/editor',
|
'xgplayer'
|
||||||
'@wangeditor/editor-for-vue'
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue