Merge branch 'master' into release

This commit is contained in:
kailong321200875 2023-12-26 11:05:20 +08:00
commit 098bcba4bd
38 changed files with 710 additions and 450 deletions

View File

@ -1,5 +1,5 @@
# 环境 # 环境
NODE_ENV=development VITE_NODE_ENV=development
# 接口前缀 # 接口前缀
VITE_API_BASE_PATH= VITE_API_BASE_PATH=
@ -9,3 +9,9 @@ VITE_BASE_PATH=/
# 标题 # 标题
VITE_APP_TITLE=ElementAdmin VITE_APP_TITLE=ElementAdmin
# 是否全量引入element-plus样式
VITE_USE_ALL_ELEMENT_PLUS_STYLE=true
# 是否开启mock
VITE_USE_MOCK=true

View File

@ -1,5 +1,5 @@
# 环境 # 环境
NODE_ENV=production VITE_NODE_ENV=production
# 接口前缀 # 接口前缀
VITE_API_BASE_PATH= VITE_API_BASE_PATH=
@ -21,3 +21,15 @@ VITE_OUT_DIR=dist-dev
# 标题 # 标题
VITE_APP_TITLE=ElementAdmin VITE_APP_TITLE=ElementAdmin
# 是否包分析
VITE_USE_BUNDLE_ANALYZER=false
# 是否全量引入element-plus样式
VITE_USE_ALL_ELEMENT_PLUS_STYLE=false
# 是否开启mock
VITE_USE_MOCK=true
# 是否切割css
VITE_USE_CSS_SPLIT=false

View File

@ -1,5 +1,5 @@
# 环境 # 环境
NODE_ENV=production VITE_NODE_ENV=production
# 接口前缀 # 接口前缀
VITE_API_BASE_PATH= VITE_API_BASE_PATH=
@ -21,3 +21,15 @@ VITE_OUT_DIR=dist-pro
# 标题 # 标题
VITE_APP_TITLE=ElementAdmin VITE_APP_TITLE=ElementAdmin
# 是否包分析
VITE_USE_BUNDLE_ANALYZER=false
# 是否全量引入element-plus样式
VITE_USE_ALL_ELEMENT_PLUS_STYLE=false
# 是否开启mock
VITE_USE_MOCK=true
# 是否切割css
VITE_USE_CSS_SPLIT=false

View File

@ -1,5 +1,5 @@
# 环境 # 环境
NODE_ENV=production VITE_NODE_ENV=production
# 接口前缀 # 接口前缀
VITE_API_BASE_PATH= VITE_API_BASE_PATH=
@ -21,3 +21,15 @@ VITE_OUT_DIR=dist-pro
# 标题 # 标题
VITE_APP_TITLE=ElementAdmin VITE_APP_TITLE=ElementAdmin
# 是否包分析
VITE_USE_BUNDLE_ANALYZER=true
# 是否全量引入element-plus样式
VITE_USE_ALL_ELEMENT_PLUS_STYLE=false
# 是否开启mock
VITE_USE_MOCK=true
# 是否切割css
VITE_USE_CSS_SPLIT=false

View File

@ -1,5 +1,5 @@
# 环境 # 环境
NODE_ENV=production VITE_NODE_ENV=production
# 接口前缀 # 接口前缀
VITE_API_BASE_PATH= VITE_API_BASE_PATH=
@ -21,3 +21,15 @@ VITE_OUT_DIR=dist-test
# 标题 # 标题
VITE_APP_TITLE=ElementAdmin VITE_APP_TITLE=ElementAdmin
# 是否包分析
VITE_USE_BUNDLE_ANALYZER=false
# 是否全量引入element-plus样式
VITE_USE_ALL_ELEMENT_PLUS_STYLE=false
# 是否开启mock
VITE_USE_MOCK=true
# 是否切割css
VITE_USE_CSS_SPLIT=false

2
.gitignore vendored
View File

@ -6,3 +6,5 @@ dist-ssr
/dist* /dist*
*-lock.* *-lock.*
pnpm-debug pnpm-debug
stats.html

View File

@ -3,7 +3,6 @@
/dist* /dist*
/public/* /public/*
/docs/* /docs/*
/vite.config.ts
/src/types/env.d.ts /src/types/env.d.ts
/docs/**/* /docs/**/*
/plop/**/* /plop/**/*

View File

@ -50,7 +50,7 @@ Online examples do not apply to menu filtering by default, but directly use Stat
- [Es6+](http://es6.ruanyifeng.com/) - Familiar with es6 basic syntax - [Es6+](http://es6.ruanyifeng.com/) - Familiar with es6 basic syntax
- [Vue-Router-Next](https://next.router.vuejs.org/) - Familiar with the basic use of vue-router - [Vue-Router-Next](https://next.router.vuejs.org/) - Familiar with the basic use of vue-router
- [Element-Plus](https://element-plus.org/) - Familiar with the basic use of element-plus - [Element-Plus](https://element-plus.org/) - Familiar with the basic use of element-plus
- [Faker.js](https://github.com/faker-js/faker#readme) - Generate massive amounts of fake contextual data - [Mock.js](https://github.com/nuysoft/Mock) - mockjs basic syntax
## Install and use ## Install and use

View File

@ -50,7 +50,7 @@ vue-element-plus-admin 的定位是后台集成方案,不太适合当基础模
- [Es6+](http://es6.ruanyifeng.com/) - 熟悉 es6 基本语法 - [Es6+](http://es6.ruanyifeng.com/) - 熟悉 es6 基本语法
- [Vue-Router-Next](https://next.router.vuejs.org/) - 熟悉 vue-router 基本使用 - [Vue-Router-Next](https://next.router.vuejs.org/) - 熟悉 vue-router 基本使用
- [Element-Plus](https://element-plus.org/) - element-plus 基本使用 - [Element-Plus](https://element-plus.org/) - element-plus 基本使用
- [Faker.js](https://github.com/faker-js/faker#readme) - 生成大量伪造的上下文数据 - [Mock.js](https://github.com/nuysoft/Mock) - mockjs 基本语法
## 安装和使用 ## 安装和使用

View File

@ -1,5 +1,5 @@
import { toAnyString } from '@/utils' import { toAnyString } from '@/utils'
import { faker } from '@faker-js/faker' import Mock from 'mockjs'
import { SUCCESS_CODE } from '@/constants' import { SUCCESS_CODE } from '@/constants'
const departmentList: any = [] const departmentList: any = []
@ -11,64 +11,71 @@ for (let i = 0; i < 5; i++) {
// 部门名称 // 部门名称
departmentName: citys[i], departmentName: citys[i],
id: toAnyString(), id: toAnyString(),
createTime: faker.date.anytime(), createTime: '@datetime',
status: faker.number.int({ min: 0, max: 1 }), // 状态
status: Mock.Random.integer(0, 1),
// 备注 // 备注
remark: faker.lorem.sentence(), remark: '@cword(10, 15)',
children: [ children: [
{ {
// 部门名称 // 部门名称
departmentName: '研发部', departmentName: '研发部',
createTime: faker.date.anytime(),
// 状态
status: faker.number.int({ min: 0, max: 1 }),
id: toAnyString(), id: toAnyString(),
remark: faker.lorem.sentence() createTime: '@datetime',
// 状态
status: Mock.Random.integer(0, 1),
// 备注
remark: '@cword(10, 15)'
}, },
{ {
// 部门名称 // 部门名称
departmentName: '产品部', departmentName: '产品部',
createTime: faker.date.anytime(),
// 状态
status: faker.number.int({ min: 0, max: 1 }),
id: toAnyString(), id: toAnyString(),
remark: faker.lorem.sentence() createTime: '@datetime',
// 状态
status: Mock.Random.integer(0, 1),
// 备注
remark: '@cword(10, 15)'
}, },
{ {
// 部门名称 // 部门名称
departmentName: '运营部', departmentName: '运营部',
createTime: faker.date.anytime(),
// 状态
status: faker.number.int({ min: 0, max: 1 }),
id: toAnyString(), id: toAnyString(),
remark: faker.lorem.sentence() createTime: '@datetime',
// 状态
status: Mock.Random.integer(0, 1),
// 备注
remark: '@cword(10, 15)'
}, },
{ {
// 部门名称 // 部门名称
departmentName: '市场部', departmentName: '市场部',
createTime: faker.date.anytime(),
// 状态
status: faker.number.int({ min: 0, max: 1 }),
id: toAnyString(), id: toAnyString(),
remark: faker.lorem.sentence() createTime: '@datetime',
// 状态
status: Mock.Random.integer(0, 1),
// 备注
remark: '@cword(10, 15)'
}, },
{ {
// 部门名称 // 部门名称
departmentName: '销售部', departmentName: '销售部',
createTime: faker.date.anytime(),
// 状态
status: faker.number.int({ min: 0, max: 1 }),
id: toAnyString(), id: toAnyString(),
remark: faker.lorem.sentence() createTime: '@datetime',
// 状态
status: Mock.Random.integer(0, 1),
// 备注
remark: '@cword(10, 15)'
}, },
{ {
// 部门名称 // 部门名称
departmentName: '客服部', departmentName: '客服部',
createTime: faker.date.anytime(),
// 状态
status: faker.number.int({ min: 0, max: 1 }),
id: toAnyString(), id: toAnyString(),
remark: faker.lorem.sentence() createTime: '@datetime',
// 状态
status: Mock.Random.integer(0, 1),
// 备注
remark: '@cword(10, 15)'
} }
] ]
}) })
@ -110,18 +117,20 @@ export default [
// 根据pageSize来创建数据 // 根据pageSize来创建数据
const mockList: any = [] const mockList: any = []
for (let i = 0; i < pageSize; i++) { for (let i = 0; i < pageSize; i++) {
mockList.push({ mockList.push(
// 用户名 Mock.mock({
username: faker.person.firstName(), // 用户名
// 账号 username: '@cname',
account: faker.person.lastName(), // 账号
// 邮箱 account: '@first',
email: faker.internet.email(), // 邮箱
// 创建时间 email: '@EMAIL',
createTime: faker.date.anytime(), // 创建时间
// 用户id createTime: '@datetime',
id: toAnyString() // 用户id
}) id: toAnyString()
})
)
} }
return { return {
code: SUCCESS_CODE, code: SUCCESS_CODE,

View File

@ -1,4 +1,4 @@
import { faker } from '@faker-js/faker' import Mock from 'mockjs'
import { SUCCESS_CODE } from '@/constants' import { SUCCESS_CODE } from '@/constants'
const timeout = 1000 const timeout = 1000
@ -19,7 +19,7 @@ export default [
component: '#', component: '#',
redirect: '/dashboard/analysis', redirect: '/dashboard/analysis',
name: 'Dashboard', name: 'Dashboard',
status: faker.number.int({ min: 0, max: 1 }), status: Mock.Random.integer(0, 1),
id: 1, id: 1,
type: 0, type: 0,
parentId: undefined, parentId: undefined,
@ -34,7 +34,7 @@ export default [
path: 'analysis', path: 'analysis',
component: 'views/Dashboard/Analysis', component: 'views/Dashboard/Analysis',
name: 'Analysis', name: 'Analysis',
status: faker.number.int({ min: 0, max: 1 }), status: Mock.Random.integer(0, 1),
id: 2, id: 2,
type: 1, type: 1,
parentId: 1, parentId: 1,
@ -59,7 +59,7 @@ export default [
path: 'workplace', path: 'workplace',
component: 'views/Dashboard/Workplace', component: 'views/Dashboard/Workplace',
name: 'Workplace', name: 'Workplace',
status: faker.number.int({ min: 0, max: 1 }), status: Mock.Random.integer(0, 1),
id: 3, id: 3,
type: 1, type: 1,
parentId: 1, parentId: 1,
@ -93,7 +93,7 @@ export default [
icon: 'clarity:document-solid' icon: 'clarity:document-solid'
}, },
name: 'ExternalLink', name: 'ExternalLink',
status: faker.number.int({ min: 0, max: 1 }), status: Mock.Random.integer(0, 1),
id: 4, id: 4,
type: 0, type: 0,
parentId: undefined, parentId: undefined,
@ -102,7 +102,7 @@ export default [
{ {
path: 'https://element-plus-admin-doc.cn/', path: 'https://element-plus-admin-doc.cn/',
name: 'DocumentLink', name: 'DocumentLink',
status: faker.number.int({ min: 0, max: 1 }), status: Mock.Random.integer(0, 1),
id: 5, id: 5,
type: 1, type: 1,
parentId: 4, parentId: 4,
@ -118,7 +118,7 @@ export default [
component: '#', component: '#',
redirect: '/level/menu1/menu1-1/menu1-1-1', redirect: '/level/menu1/menu1-1/menu1-1-1',
name: 'Level', name: 'Level',
status: faker.number.int({ min: 0, max: 1 }), status: Mock.Random.integer(0, 1),
id: 6, id: 6,
type: 0, type: 0,
parentId: undefined, parentId: undefined,
@ -132,7 +132,7 @@ export default [
path: 'menu1', path: 'menu1',
name: 'Menu1', name: 'Menu1',
component: '##', component: '##',
status: faker.number.int({ min: 0, max: 1 }), status: Mock.Random.integer(0, 1),
id: 7, id: 7,
type: 0, type: 0,
parentId: 6, parentId: 6,
@ -146,7 +146,7 @@ export default [
path: 'menu1-1', path: 'menu1-1',
name: 'Menu11', name: 'Menu11',
component: '##', component: '##',
status: faker.number.int({ min: 0, max: 1 }), status: Mock.Random.integer(0, 1),
id: 8, id: 8,
type: 0, type: 0,
parentId: 7, parentId: 7,
@ -161,7 +161,7 @@ export default [
path: 'menu1-1-1', path: 'menu1-1-1',
name: 'Menu111', name: 'Menu111',
component: 'views/Level/Menu111', component: 'views/Level/Menu111',
status: faker.number.int({ min: 0, max: 1 }), status: Mock.Random.integer(0, 1),
id: 9, id: 9,
type: 1, type: 1,
parentId: 8, parentId: 8,
@ -176,7 +176,7 @@ export default [
path: 'menu1-2', path: 'menu1-2',
name: 'Menu12', name: 'Menu12',
component: 'views/Level/Menu12', component: 'views/Level/Menu12',
status: faker.number.int({ min: 0, max: 1 }), status: Mock.Random.integer(0, 1),
id: 10, id: 10,
type: 1, type: 1,
parentId: 7, parentId: 7,
@ -191,7 +191,7 @@ export default [
path: 'menu2', path: 'menu2',
name: 'Menu2Demo', name: 'Menu2Demo',
component: 'views/Level/Menu2', component: 'views/Level/Menu2',
status: faker.number.int({ min: 0, max: 1 }), status: Mock.Random.integer(0, 1),
id: 11, id: 11,
type: 1, type: 1,
parentId: 6, parentId: 6,
@ -207,7 +207,7 @@ export default [
component: '#', component: '#',
redirect: '/example/example-dialog', redirect: '/example/example-dialog',
name: 'Example', name: 'Example',
status: faker.number.int({ min: 0, max: 1 }), status: Mock.Random.integer(0, 1),
id: 12, id: 12,
type: 0, type: 0,
parentId: undefined, parentId: undefined,
@ -222,7 +222,7 @@ export default [
path: 'example-dialog', path: 'example-dialog',
component: 'views/Example/Dialog/ExampleDialog', component: 'views/Example/Dialog/ExampleDialog',
name: 'ExampleDialog', name: 'ExampleDialog',
status: faker.number.int({ min: 0, max: 1 }), status: Mock.Random.integer(0, 1),
id: 13, id: 13,
type: 1, type: 1,
parentId: 12, parentId: 12,
@ -253,7 +253,7 @@ export default [
path: 'example-page', path: 'example-page',
component: 'views/Example/Page/ExamplePage', component: 'views/Example/Page/ExamplePage',
name: 'ExamplePage', name: 'ExamplePage',
status: faker.number.int({ min: 0, max: 1 }), status: Mock.Random.integer(0, 1),
id: 14, id: 14,
type: 1, type: 1,
parentId: 12, parentId: 12,
@ -284,7 +284,7 @@ export default [
path: 'example-add', path: 'example-add',
component: 'views/Example/Page/ExampleAdd', component: 'views/Example/Page/ExampleAdd',
name: 'ExampleAdd', name: 'ExampleAdd',
status: faker.number.int({ min: 0, max: 1 }), status: Mock.Random.integer(0, 1),
id: 15, id: 15,
type: 1, type: 1,
parentId: 12, parentId: 12,
@ -302,7 +302,7 @@ export default [
path: 'example-edit', path: 'example-edit',
component: 'views/Example/Page/ExampleEdit', component: 'views/Example/Page/ExampleEdit',
name: 'ExampleEdit', name: 'ExampleEdit',
status: faker.number.int({ min: 0, max: 1 }), status: Mock.Random.integer(0, 1),
id: 16, id: 16,
type: 1, type: 1,
parentId: 12, parentId: 12,
@ -320,7 +320,7 @@ export default [
path: 'example-detail', path: 'example-detail',
component: 'views/Example/Page/ExampleDetail', component: 'views/Example/Page/ExampleDetail',
name: 'ExampleDetail', name: 'ExampleDetail',
status: faker.number.int({ min: 0, max: 1 }), status: Mock.Random.integer(0, 1),
id: 17, id: 17,
type: 1, type: 1,
parentId: 12, parentId: 12,

View File

@ -1,4 +1,4 @@
import { faker } from '@faker-js/faker' import Mock from 'mockjs'
import { SUCCESS_CODE } from '@/constants' import { SUCCESS_CODE } from '@/constants'
import { toAnyString } from '@/utils' import { toAnyString } from '@/utils'
@ -731,7 +731,7 @@ const menus = [
component: '#', component: '#',
redirect: '/dashboard/analysis', redirect: '/dashboard/analysis',
name: 'Dashboard', name: 'Dashboard',
status: faker.number.int({ min: 0, max: 1 }), status: Mock.Random.integer(0, 1),
id: 1, id: 1,
meta: { meta: {
title: '首页', title: '首页',
@ -743,7 +743,7 @@ const menus = [
path: 'analysis', path: 'analysis',
component: 'views/Dashboard/Analysis', component: 'views/Dashboard/Analysis',
name: 'Analysis', name: 'Analysis',
status: faker.number.int({ min: 0, max: 1 }), status: Mock.Random.integer(0, 1),
id: 2, id: 2,
meta: { meta: {
title: '分析页', title: '分析页',
@ -754,7 +754,7 @@ const menus = [
path: 'workplace', path: 'workplace',
component: 'views/Dashboard/Workplace', component: 'views/Dashboard/Workplace',
name: 'Workplace', name: 'Workplace',
status: faker.number.int({ min: 0, max: 1 }), status: Mock.Random.integer(0, 1),
id: 3, id: 3,
meta: { meta: {
title: '工作台', title: '工作台',
@ -771,13 +771,13 @@ const menus = [
icon: 'clarity:document-solid' icon: 'clarity:document-solid'
}, },
name: 'ExternalLink', name: 'ExternalLink',
status: faker.number.int({ min: 0, max: 1 }), status: Mock.Random.integer(0, 1),
id: 4, id: 4,
children: [ children: [
{ {
path: 'https://element-plus-admin-doc.cn/', path: 'https://element-plus-admin-doc.cn/',
name: 'DocumentLink', name: 'DocumentLink',
status: faker.number.int({ min: 0, max: 1 }), status: Mock.Random.integer(0, 1),
id: 5, id: 5,
meta: { meta: {
title: '文档' title: '文档'
@ -790,7 +790,7 @@ const menus = [
component: '#', component: '#',
redirect: '/level/menu1/menu1-1/menu1-1-1', redirect: '/level/menu1/menu1-1/menu1-1-1',
name: 'Level', name: 'Level',
status: faker.number.int({ min: 0, max: 1 }), status: Mock.Random.integer(0, 1),
id: 6, id: 6,
meta: { meta: {
title: '菜单', title: '菜单',
@ -801,7 +801,7 @@ const menus = [
path: 'menu1', path: 'menu1',
name: 'Menu1', name: 'Menu1',
component: '##', component: '##',
status: faker.number.int({ min: 0, max: 1 }), status: Mock.Random.integer(0, 1),
id: 7, id: 7,
redirect: '/level/menu1/menu1-1/menu1-1-1', redirect: '/level/menu1/menu1-1/menu1-1-1',
meta: { meta: {
@ -812,7 +812,7 @@ const menus = [
path: 'menu1-1', path: 'menu1-1',
name: 'Menu11', name: 'Menu11',
component: '##', component: '##',
status: faker.number.int({ min: 0, max: 1 }), status: Mock.Random.integer(0, 1),
id: 8, id: 8,
redirect: '/level/menu1/menu1-1/menu1-1-1', redirect: '/level/menu1/menu1-1/menu1-1-1',
meta: { meta: {
@ -824,7 +824,7 @@ const menus = [
path: 'menu1-1-1', path: 'menu1-1-1',
name: 'Menu111', name: 'Menu111',
component: 'views/Level/Menu111', component: 'views/Level/Menu111',
status: faker.number.int({ min: 0, max: 1 }), status: Mock.Random.integer(0, 1),
id: 9, id: 9,
permission: ['edit', 'add', 'delete'], permission: ['edit', 'add', 'delete'],
meta: { meta: {
@ -838,7 +838,7 @@ const menus = [
path: 'menu1-2', path: 'menu1-2',
name: 'Menu12', name: 'Menu12',
component: 'views/Level/Menu12', component: 'views/Level/Menu12',
status: faker.number.int({ min: 0, max: 1 }), status: Mock.Random.integer(0, 1),
id: 10, id: 10,
permission: ['edit', 'add', 'delete'], permission: ['edit', 'add', 'delete'],
meta: { meta: {
@ -852,7 +852,7 @@ const menus = [
path: 'menu2', path: 'menu2',
name: 'Menu2Demo', name: 'Menu2Demo',
component: 'views/Level/Menu2', component: 'views/Level/Menu2',
status: faker.number.int({ min: 0, max: 1 }), status: Mock.Random.integer(0, 1),
id: 11, id: 11,
permission: ['edit', 'add', 'delete'], permission: ['edit', 'add', 'delete'],
meta: { meta: {
@ -867,7 +867,7 @@ const menus = [
component: '#', component: '#',
redirect: '/example/example-dialog', redirect: '/example/example-dialog',
name: 'Example', name: 'Example',
status: faker.number.int({ min: 0, max: 1 }), status: Mock.Random.integer(0, 1),
id: 12, id: 12,
meta: { meta: {
title: '综合示例', title: '综合示例',
@ -879,7 +879,7 @@ const menus = [
path: 'example-dialog', path: 'example-dialog',
component: 'views/Example/Dialog/ExampleDialog', component: 'views/Example/Dialog/ExampleDialog',
name: 'ExampleDialog', name: 'ExampleDialog',
status: faker.number.int({ min: 0, max: 1 }), status: Mock.Random.integer(0, 1),
id: 13, id: 13,
permission: ['edit', 'add', 'delete'], permission: ['edit', 'add', 'delete'],
meta: { meta: {
@ -891,7 +891,7 @@ const menus = [
path: 'example-page', path: 'example-page',
component: 'views/Example/Page/ExamplePage', component: 'views/Example/Page/ExamplePage',
name: 'ExamplePage', name: 'ExamplePage',
status: faker.number.int({ min: 0, max: 1 }), status: Mock.Random.integer(0, 1),
id: 14, id: 14,
permission: ['edit', 'add', 'delete'], permission: ['edit', 'add', 'delete'],
meta: { meta: {
@ -903,7 +903,7 @@ const menus = [
path: 'example-add', path: 'example-add',
component: 'views/Example/Page/ExampleAdd', component: 'views/Example/Page/ExampleAdd',
name: 'ExampleAdd', name: 'ExampleAdd',
status: faker.number.int({ min: 0, max: 1 }), status: Mock.Random.integer(0, 1),
id: 15, id: 15,
permission: ['edit', 'add', 'delete'], permission: ['edit', 'add', 'delete'],
meta: { meta: {
@ -920,7 +920,7 @@ const menus = [
path: 'example-edit', path: 'example-edit',
component: 'views/Example/Page/ExampleEdit', component: 'views/Example/Page/ExampleEdit',
name: 'ExampleEdit', name: 'ExampleEdit',
status: faker.number.int({ min: 0, max: 1 }), status: Mock.Random.integer(0, 1),
id: 16, id: 16,
permission: ['edit', 'add', 'delete'], permission: ['edit', 'add', 'delete'],
meta: { meta: {
@ -937,7 +937,7 @@ const menus = [
path: 'example-detail', path: 'example-detail',
component: 'views/Example/Page/ExampleDetail', component: 'views/Example/Page/ExampleDetail',
name: 'ExampleDetail', name: 'ExampleDetail',
status: faker.number.int({ min: 0, max: 1 }), status: Mock.Random.integer(0, 1),
id: 17, id: 17,
permission: ['edit', 'add', 'delete'], permission: ['edit', 'add', 'delete'],
meta: { meta: {
@ -959,7 +959,7 @@ const menus = [
component: '#', component: '#',
redirect: '/dashboard/analysis', redirect: '/dashboard/analysis',
name: 'Dashboard', name: 'Dashboard',
status: faker.number.int({ min: 0, max: 1 }), status: Mock.Random.integer(0, 1),
id: 1, id: 1,
meta: { meta: {
title: '首页', title: '首页',
@ -971,7 +971,7 @@ const menus = [
path: 'analysis', path: 'analysis',
component: 'views/Dashboard/Analysis', component: 'views/Dashboard/Analysis',
name: 'Analysis', name: 'Analysis',
status: faker.number.int({ min: 0, max: 1 }), status: Mock.Random.integer(0, 1),
id: 2, id: 2,
meta: { meta: {
title: '分析页', title: '分析页',
@ -982,7 +982,7 @@ const menus = [
path: 'workplace', path: 'workplace',
component: 'views/Dashboard/Workplace', component: 'views/Dashboard/Workplace',
name: 'Workplace', name: 'Workplace',
status: faker.number.int({ min: 0, max: 1 }), status: Mock.Random.integer(0, 1),
id: 3, id: 3,
meta: { meta: {
title: '工作台', title: '工作台',
@ -1001,13 +1001,13 @@ const menus = [
icon: 'clarity:document-solid' icon: 'clarity:document-solid'
}, },
name: 'ExternalLink', name: 'ExternalLink',
status: faker.number.int({ min: 0, max: 1 }), status: Mock.Random.integer(0, 1),
id: 4, id: 4,
children: [ children: [
{ {
path: 'https://element-plus-admin-doc.cn/', path: 'https://element-plus-admin-doc.cn/',
name: 'DocumentLink', name: 'DocumentLink',
status: faker.number.int({ min: 0, max: 1 }), status: Mock.Random.integer(0, 1),
id: 5, id: 5,
meta: { meta: {
title: '文档' title: '文档'
@ -1020,7 +1020,7 @@ const menus = [
component: '#', component: '#',
redirect: '/level/menu1/menu1-1/menu1-1-1', redirect: '/level/menu1/menu1-1/menu1-1-1',
name: 'Level', name: 'Level',
status: faker.number.int({ min: 0, max: 1 }), status: Mock.Random.integer(0, 1),
id: 6, id: 6,
meta: { meta: {
title: '菜单', title: '菜单',
@ -1031,7 +1031,7 @@ const menus = [
path: 'menu1', path: 'menu1',
name: 'Menu1', name: 'Menu1',
component: '##', component: '##',
status: faker.number.int({ min: 0, max: 1 }), status: Mock.Random.integer(0, 1),
id: 7, id: 7,
redirect: '/level/menu1/menu1-1/menu1-1-1', redirect: '/level/menu1/menu1-1/menu1-1-1',
meta: { meta: {
@ -1042,7 +1042,7 @@ const menus = [
path: 'menu1-1', path: 'menu1-1',
name: 'Menu11', name: 'Menu11',
component: '##', component: '##',
status: faker.number.int({ min: 0, max: 1 }), status: Mock.Random.integer(0, 1),
id: 8, id: 8,
redirect: '/level/menu1/menu1-1/menu1-1-1', redirect: '/level/menu1/menu1-1/menu1-1-1',
meta: { meta: {
@ -1054,7 +1054,7 @@ const menus = [
path: 'menu1-1-1', path: 'menu1-1-1',
name: 'Menu111', name: 'Menu111',
component: 'views/Level/Menu111', component: 'views/Level/Menu111',
status: faker.number.int({ min: 0, max: 1 }), status: Mock.Random.integer(0, 1),
id: 9, id: 9,
permission: ['edit', 'add', 'delete'], permission: ['edit', 'add', 'delete'],
meta: { meta: {
@ -1068,7 +1068,7 @@ const menus = [
path: 'menu1-2', path: 'menu1-2',
name: 'Menu12', name: 'Menu12',
component: 'views/Level/Menu12', component: 'views/Level/Menu12',
status: faker.number.int({ min: 0, max: 1 }), status: Mock.Random.integer(0, 1),
id: 10, id: 10,
permission: ['edit', 'add', 'delete'], permission: ['edit', 'add', 'delete'],
meta: { meta: {
@ -1082,7 +1082,7 @@ const menus = [
path: 'menu2', path: 'menu2',
name: 'Menu2Demo', name: 'Menu2Demo',
component: 'views/Level/Menu2', component: 'views/Level/Menu2',
status: faker.number.int({ min: 0, max: 1 }), status: Mock.Random.integer(0, 1),
id: 11, id: 11,
permission: ['edit', 'add', 'delete'], permission: ['edit', 'add', 'delete'],
meta: { meta: {
@ -1099,7 +1099,7 @@ const menus = [
component: '#', component: '#',
redirect: '/example/example-dialog', redirect: '/example/example-dialog',
name: 'Example', name: 'Example',
status: faker.number.int({ min: 0, max: 1 }), status: Mock.Random.integer(0, 1),
id: 12, id: 12,
meta: { meta: {
title: '综合示例', title: '综合示例',
@ -1111,7 +1111,7 @@ const menus = [
path: 'example-detail', path: 'example-detail',
component: 'views/Example/Page/ExampleDetail', component: 'views/Example/Page/ExampleDetail',
name: 'ExampleDetail', name: 'ExampleDetail',
status: faker.number.int({ min: 0, max: 1 }), status: Mock.Random.integer(0, 1),
id: 17, id: 17,
permission: ['edit', 'add', 'delete'], permission: ['edit', 'add', 'delete'],
meta: { meta: {
@ -1130,16 +1130,18 @@ const menus = [
] ]
for (let i = 0; i < 4; i++) { for (let i = 0; i < 4; i++) {
List.push({ List.push(
id: toAnyString(), Mock.mock({
// timestamp: +Mock.Random.date('T'), id: toAnyString(),
roleName: roleNames[i], // timestamp: +Mock.Random.date('T'),
role: faker.lorem.sentence(1), roleName: roleNames[i],
status: faker.number.int({ min: 0, max: 1 }), role: '@first',
createTime: faker.date.anytime(), status: Mock.Random.integer(0, 1),
remark: faker.lorem.sentence(), createTime: '@datetime',
menu: menus[i] remark: '@cword(10, 15)',
}) menu: menus[i]
})
)
} }
export default [ export default [

View File

@ -1,4 +1,4 @@
import { faker } from '@faker-js/faker' import Mock from 'mockjs'
import { SUCCESS_CODE } from '@/constants' import { SUCCESS_CODE } from '@/constants'
import { toAnyString } from '@/utils' import { toAnyString } from '@/utils'
@ -36,144 +36,103 @@ interface TreeListProps {
let List: ListProps[] = [] let List: ListProps[] = []
for (let i = 0; i < count; i++) { for (let i = 0; i < count; i++) {
List.push({ List.push(
id: toAnyString(), Mock.mock({
// timestamp: +Mock.Random.date('T'), id: toAnyString(),
author: faker.person.firstName(), // timestamp: +Mock.Random.date('T'),
title: faker.lorem.sentence(), author: '@first',
content: baseContent, title: '@title(5, 10)',
importance: faker.number.int({ min: 1, max: 3 }), content: baseContent,
display_time: faker.date.anytime(), importance: '@integer(1, 3)',
pageviews: faker.number.int({ min: 300, max: 5000 }), display_time: '@datetime',
image_uri: faker.image.url({ pageviews: '@integer(100, 500)',
width: faker.number.int({ min: 200, max: 400 }), image_uri: Mock.Random.image('@integer(100, 500)x@integer(100, 500)'),
height: faker.number.int({ min: 200, max: 400 }) video_uri:
}), '//sf1-cdn-tos.huoshanstatic.com/obj/media-fe/xgplayer_doc_video/mp4/xgplayer-demo-720p.mp4'
video_uri: })
'//sf1-cdn-tos.huoshanstatic.com/obj/media-fe/xgplayer_doc_video/mp4/xgplayer-demo-720p.mp4' )
})
} }
const treeList: TreeListProps[] = [] const treeList: TreeListProps[] = []
for (let i = 0; i < count; i++) { for (let i = 0; i < count; i++) {
treeList.push({ treeList.push(
id: toAnyString(), Mock.mock({
// timestamp: +Mock.Random.date('T'), id: toAnyString(),
author: faker.person.firstName(), // timestamp: +Mock.Random.date('T'),
title: faker.lorem.sentence(), author: '@first',
content: baseContent, title: '@title(5, 10)',
importance: faker.number.int({ min: 1, max: 3 }), content: baseContent,
display_time: faker.date.anytime(), importance: '@integer(1, 3)',
pageviews: faker.number.int({ min: 300, max: 5000 }), display_time: '@datetime',
image_uri: faker.image.url({ pageviews: '@integer(300, 5000)',
width: faker.number.int({ min: 200, max: 400 }), children: [
height: faker.number.int({ min: 200, max: 400 }) {
}), id: toAnyString(),
video_uri: // timestamp: +Mock.Random.date('T'),
'//sf1-cdn-tos.huoshanstatic.com/obj/media-fe/xgplayer_doc_video/mp4/xgplayer-demo-720p.mp4', author: '@first',
children: [ title: '@title(5, 10)',
{ content: baseContent,
id: toAnyString(), importance: '@integer(1, 3)',
// timestamp: +Mock.Random.date('T'), display_time: '@datetime',
author: faker.person.firstName(), pageviews: '@integer(300, 5000)',
title: faker.lorem.sentence(), children: [
content: baseContent, {
importance: faker.number.int({ min: 1, max: 3 }), id: toAnyString(),
display_time: faker.date.anytime(), // timestamp: +Mock.Random.date('T'),
pageviews: faker.number.int({ min: 300, max: 5000 }), author: '@first',
image_uri: faker.image.url({ title: '@title(5, 10)',
width: faker.number.int({ min: 200, max: 400 }), content: baseContent,
height: faker.number.int({ min: 200, max: 400 }) importance: '@integer(1, 3)',
}), display_time: '@datetime',
video_uri: pageviews: '@integer(300, 5000)'
'//sf1-cdn-tos.huoshanstatic.com/obj/media-fe/xgplayer_doc_video/mp4/xgplayer-demo-720p.mp4', },
children: [ {
{ id: toAnyString(),
id: toAnyString(), // timestamp: +Mock.Random.date('T'),
// timestamp: +Mock.Random.date('T'), author: '@first',
author: faker.person.firstName(), title: '@title(5, 10)',
title: faker.lorem.sentence(), content: baseContent,
content: baseContent, importance: '@integer(1, 3)',
importance: faker.number.int({ min: 1, max: 3 }), display_time: '@datetime',
display_time: faker.date.anytime(), pageviews: '@integer(300, 5000)'
pageviews: faker.number.int({ min: 300, max: 5000 }), }
image_uri: faker.image.url({ ]
width: faker.number.int({ min: 200, max: 400 }), },
height: faker.number.int({ min: 200, max: 400 }) {
}), id: toAnyString(),
video_uri: // timestamp: +Mock.Random.date('T'),
'//sf1-cdn-tos.huoshanstatic.com/obj/media-fe/xgplayer_doc_video/mp4/xgplayer-demo-720p.mp4' author: '@first',
}, title: '@title(5, 10)',
{ content: baseContent,
id: toAnyString(), importance: '@integer(1, 3)',
// timestamp: +Mock.Random.date('T'), display_time: '@datetime',
author: faker.person.firstName(), pageviews: '@integer(300, 5000)'
title: faker.lorem.sentence(), },
content: baseContent, {
importance: faker.number.int({ min: 1, max: 3 }), id: toAnyString(),
display_time: faker.date.anytime(), // timestamp: +Mock.Random.date('T'),
pageviews: faker.number.int({ min: 300, max: 5000 }), author: '@first',
image_uri: faker.image.url({ title: '@title(5, 10)',
width: faker.number.int({ min: 200, max: 400 }), content: baseContent,
height: faker.number.int({ min: 200, max: 400 }) importance: '@integer(1, 3)',
}), display_time: '@datetime',
video_uri: pageviews: '@integer(300, 5000)'
'//sf1-cdn-tos.huoshanstatic.com/obj/media-fe/xgplayer_doc_video/mp4/xgplayer-demo-720p.mp4' },
} {
] id: toAnyString(),
}, // timestamp: +Mock.Random.date('T'),
{ author: '@first',
id: toAnyString(), title: '@title(5, 10)',
// timestamp: +Mock.Random.date('T'), content: baseContent,
author: faker.person.firstName(), importance: '@integer(1, 3)',
title: faker.lorem.sentence(), display_time: '@datetime',
content: baseContent, pageviews: '@integer(300, 5000)'
importance: faker.number.int({ min: 1, max: 3 }), }
display_time: faker.date.anytime(), ]
pageviews: faker.number.int({ min: 300, max: 5000 }), // image_uri
image_uri: faker.image.url({ })
width: faker.number.int({ min: 200, max: 400 }), )
height: faker.number.int({ min: 200, max: 400 })
}),
video_uri:
'//sf1-cdn-tos.huoshanstatic.com/obj/media-fe/xgplayer_doc_video/mp4/xgplayer-demo-720p.mp4'
},
{
id: toAnyString(),
// timestamp: +Mock.Random.date('T'),
author: faker.person.firstName(),
title: faker.lorem.sentence(),
content: baseContent,
importance: faker.number.int({ min: 1, max: 3 }),
display_time: faker.date.anytime(),
pageviews: faker.number.int({ min: 300, max: 5000 }),
image_uri: faker.image.url({
width: faker.number.int({ min: 200, max: 400 }),
height: faker.number.int({ min: 200, max: 400 })
}),
video_uri:
'//sf1-cdn-tos.huoshanstatic.com/obj/media-fe/xgplayer_doc_video/mp4/xgplayer-demo-720p.mp4'
},
{
id: toAnyString(),
// timestamp: +Mock.Random.date('T'),
author: faker.person.firstName(),
title: faker.lorem.sentence(),
content: baseContent,
importance: faker.number.int({ min: 1, max: 3 }),
display_time: faker.date.anytime(),
pageviews: faker.number.int({ min: 300, max: 5000 }),
image_uri: faker.image.url({
width: faker.number.int({ min: 200, max: 400 }),
height: faker.number.int({ min: 200, max: 400 })
}),
video_uri:
'//sf1-cdn-tos.huoshanstatic.com/obj/media-fe/xgplayer_doc_video/mp4/xgplayer-demo-720p.mp4'
}
]
// image_uri
})
} }
const cardList = [ const cardList = [

View File

@ -27,9 +27,7 @@
"icon": "esno ./scripts/icon.ts" "icon": "esno ./scripts/icon.ts"
}, },
"dependencies": { "dependencies": {
"@faker-js/faker": "^8.3.1",
"@iconify/iconify": "^3.1.1", "@iconify/iconify": "^3.1.1",
"@iconify/vue": "^4.1.1",
"@vueuse/core": "^10.7.0", "@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",
@ -41,49 +39,50 @@
"driver.js": "^1.3.1", "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.3", "element-plus": "^2.4.4",
"lodash-es": "^4.17.21", "lodash-es": "^4.17.21",
"mitt": "^3.0.1", "mitt": "^3.0.1",
"nprogress": "^0.2.0", "nprogress": "^0.2.0",
"pinia": "^2.1.7", "pinia": "^2.1.7",
"pinia-plugin-persistedstate": "^3.2.0", "pinia-plugin-persistedstate": "^3.2.1",
"qrcode": "^1.5.3", "qrcode": "^1.5.3",
"qs": "^6.11.2", "qs": "^6.11.2",
"url": "^0.11.3", "url": "^0.11.3",
"vue": "3.3.10", "vue": "3.3.13",
"vue-draggable-plus": "^0.3.2",
"vue-i18n": "9.8.0", "vue-i18n": "9.8.0",
"vue-json-pretty": "^2.2.4", "vue-json-pretty": "^2.3.0",
"vue-router": "^4.2.5", "vue-router": "^4.2.5",
"vue-types": "^5.1.1", "vue-types": "^5.1.1",
"xgplayer": "^3.0.10" "xgplayer": "^3.0.11"
}, },
"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.153", "@iconify/json": "^2.2.160",
"@intlify/unplugin-vue-i18n": "^1.5.0", "@intlify/unplugin-vue-i18n": "^2.0.0",
"@purge-icons/generated": "^0.10.0",
"@types/fs-extra": "^11.0.4", "@types/fs-extra": "^11.0.4",
"@types/inquirer": "^9.0.7", "@types/inquirer": "^9.0.7",
"@types/lodash-es": "^4.17.12", "@types/lodash-es": "^4.17.12",
"@types/node": "^20.10.3", "@types/mockjs": "^1.0.10",
"@types/node": "^20.10.5",
"@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.13.2", "@typescript-eslint/eslint-plugin": "^6.15.0",
"@typescript-eslint/parser": "^6.13.2", "@typescript-eslint/parser": "^6.15.0",
"@unocss/transformer-variant-group": "^0.58.0", "@unocss/transformer-variant-group": "^0.58.0",
"@vitejs/plugin-legacy": "^5.2.0", "@vitejs/plugin-legacy": "^5.2.0",
"@vitejs/plugin-vue": "^4.5.1", "@vitejs/plugin-vue": "^4.5.2",
"@vitejs/plugin-vue-jsx": "^3.1.0", "@vitejs/plugin-vue-jsx": "^3.1.0",
"autoprefixer": "^10.4.16", "autoprefixer": "^10.4.16",
"chalk": "^5.3.0", "chalk": "^5.3.0",
"consola": "^3.2.3", "consola": "^3.2.3",
"eslint": "^8.55.0", "eslint": "^8.56.0",
"eslint-config-prettier": "^9.1.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.1.0",
"eslint-plugin-vue": "^9.19.2", "eslint-plugin-vue": "^9.19.2",
"esno": "^4.0.0", "esno": "^4.0.0",
"fs-extra": "^11.2.0", "fs-extra": "^11.2.0",
@ -91,22 +90,24 @@
"inquirer": "^9.2.12", "inquirer": "^9.2.12",
"less": "^4.2.0", "less": "^4.2.0",
"lint-staged": "^15.2.0", "lint-staged": "^15.2.0",
"mockjs": "^1.1.0",
"plop": "^4.0.0", "plop": "^4.0.0",
"postcss": "^8.4.32", "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.1",
"rimraf": "^5.0.5", "rimraf": "^5.0.5",
"rollup": "^4.6.1", "rollup": "^4.9.1",
"stylelint": "^15.11.0", "rollup-plugin-visualizer": "^5.11.0",
"stylelint": "^16.0.2",
"stylelint-config-html": "^1.1.0", "stylelint-config-html": "^1.1.0",
"stylelint-config-recommended": "^13.0.0", "stylelint-config-recommended": "^14.0.0",
"stylelint-config-standard": "^34.0.0", "stylelint-config-standard": "^35.0.0",
"stylelint-order": "^6.0.3", "stylelint-order": "^6.0.4",
"terser": "^5.25.0", "terser": "^5.26.0",
"typescript": "5.3.3", "typescript": "5.3.3",
"unocss": "^0.58.0", "unocss": "^0.58.0",
"vite": "5.0.6", "vite": "5.0.10",
"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",

View File

@ -2,9 +2,9 @@
import { computed } from 'vue' import { computed } from 'vue'
import { useAppStore } from '@/store/modules/app' import { useAppStore } from '@/store/modules/app'
import { ConfigGlobal } from '@/components/ConfigGlobal' import { ConfigGlobal } from '@/components/ConfigGlobal'
import { isDark } from '@/utils/is'
import { useDesign } from '@/hooks/web/useDesign' import { useDesign } from '@/hooks/web/useDesign'
import { useStorage } from '@/hooks/web/useStorage' import { useDark } from '@vueuse/core'
import { ElNotification } from 'element-plus'
const { getPrefixCls } = useDesign() const { getPrefixCls } = useDesign()
@ -16,19 +16,20 @@ const currentSize = computed(() => appStore.getCurrentSize)
const greyMode = computed(() => appStore.getGreyMode) const greyMode = computed(() => appStore.getGreyMode)
const { getStorage } = useStorage() const isDark = useDark({
valueDark: 'dark',
valueLight: 'light'
})
// isDark.value = appStore.getIsDark
const setDefaultTheme = () => { ElNotification({
if (getStorage('isDark') !== null) { title: '提示',
appStore.setIsDark(getStorage('isDark')) type: 'warning',
return duration: 0,
} dangerouslyUseHTMLString: true,
const isDarkTheme = isDark() message:
appStore.setIsDark(isDarkTheme) '<div><p><strong>遇事不决,请先查阅常见问题,说不定你能找到相关解答</strong></p><p><a href="https://element-plus-admin-doc.cn/guide/fqa.html" target="_blank">链接地址</a></p></div>'
} })
setDefaultTheme()
</script> </script>
<template> <template>

View File

@ -1,4 +1,4 @@
import { AxiosResponse, AxiosRequestHeaders, InternalAxiosRequestConfig } from './types' import { AxiosResponse, InternalAxiosRequestConfig } from './types'
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
import qs from 'qs' import qs from 'qs'
import { SUCCESS_CODE } from '@/constants' import { SUCCESS_CODE } from '@/constants'
@ -7,7 +7,7 @@ import { useUserStoreWithOut } from '@/store/modules/user'
const defaultRequestInterceptors = (config: InternalAxiosRequestConfig) => { const defaultRequestInterceptors = (config: InternalAxiosRequestConfig) => {
if ( if (
config.method === 'post' && config.method === 'post' &&
(config.headers as AxiosRequestHeaders)['Content-Type'] === 'application/x-www-form-urlencoded' config.headers['Content-Type'] === 'application/x-www-form-urlencoded'
) { ) {
config.data = qs.stringify(config.data) config.data = qs.stringify(config.data)
} }

View File

@ -3,7 +3,6 @@ import { computed, unref } from 'vue'
import { ElIcon } from 'element-plus' import { ElIcon } from 'element-plus'
import { propTypes } from '@/utils/propTypes' import { propTypes } from '@/utils/propTypes'
import { useDesign } from '@/hooks/web/useDesign' import { useDesign } from '@/hooks/web/useDesign'
import { Icon } from '@iconify/vue'
const { getPrefixCls } = useDesign() const { getPrefixCls } = useDesign()
@ -40,20 +39,27 @@ const getIconifyStyle = computed(() => {
<use :xlink:href="symbolId" /> <use :xlink:href="symbolId" />
</svg> </svg>
<Icon v-else :icon="icon" :style="getIconifyStyle" /> <!-- <Icon v-else :icon="icon" :style="getIconifyStyle" /> -->
<div :class="`${icon} iconify`" :style="getIconifyStyle"></div>
</ElIcon> </ElIcon>
</template> </template>
<style lang="less" scoped> <style lang="less" scoped>
@prefix-cls: ~'@{namespace}-icon'; @prefix-cls: ~'@{namespace}-icon';
.@{prefix-cls}, .@{prefix-cls} {
.iconify { :deep(svg) {
&:hover { &:hover {
:deep(svg) {
// stylelint-disable-next-line // stylelint-disable-next-line
color: v-bind(hoverColor) !important; color: v-bind(hoverColor) !important;
} }
} }
} }
.iconify {
&:hover {
// stylelint-disable-next-line
color: v-bind(hoverColor) !important;
}
}
</style> </style>

View File

@ -12,9 +12,10 @@ export const useRenderMenuItem = (
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 ?? {} .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('/')
@ -48,8 +49,7 @@ export const useRenderMenuItem = (
</ElSubMenu> </ElSubMenu>
) )
} }
} })
})
} }
return { return {

View File

@ -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'))

View File

@ -275,6 +275,10 @@ export default defineComponent({
setProps({ size }) setProps({ size })
} }
const confirmSetColumn = (columns: TableColumn[]) => {
setProps({ columns })
}
expose({ expose({
setProps, setProps,
setColumn, setColumn,
@ -434,6 +438,7 @@ export default defineComponent({
align={v.align || align} align={v.align || align}
headerAlign={v.headerAlign || headerAlign} headerAlign={v.headerAlign || headerAlign}
label={v.label} label={v.label}
fixed={v.fixed}
width="65px" width="65px"
></ElTableColumn> ></ElTableColumn>
) )
@ -543,11 +548,12 @@ export default defineComponent({
</div> </div>
) : ( ) : (
<> <>
{unref(getProps).showAction ? ( {unref(getProps).showAction && !unref(getProps).customContent ? (
<TableActions <TableActions
columns={unref(getProps).columns} columns={unref(getProps).columns}
onChangSize={changSize} onChangSize={changSize}
onRefresh={refresh} onRefresh={refresh}
onConfirm={confirmSetColumn}
/> />
) : null} ) : null}
<ElTable ref={elTableRef} data={unref(getProps).data} {...unref(getBindValue)}> <ElTable ref={elTableRef} data={unref(getProps).data} {...unref(getBindValue)}>

View File

@ -0,0 +1,165 @@
<script setup lang="ts">
import {
ElDrawer,
ElCheckbox,
ElCheckboxGroup,
ElText,
ElRadioButton,
ElRadioGroup
} from 'element-plus'
import { TableColumn } from '../types'
import { PropType, ref, watch, unref } from 'vue'
import { cloneDeep } from 'lodash-es'
import { DEFAULT_FILTER_COLUMN } from '@/constants'
import { VueDraggable } from 'vue-draggable-plus'
const modelValue = defineModel<boolean>()
const props = defineProps({
columns: {
type: Array as PropType<TableColumn[]>,
default: () => []
}
})
const emit = defineEmits(['confirm'])
const oldColumns = ref<TableColumn[]>()
const settingColumns = ref<TableColumn[]>()
//
const hiddenColumns = ref<TableColumn[]>([])
const defaultCheckColumns = ref<string[]>([])
const checkColumns = ref<string[]>([])
const checkAll = ref(false)
const isIndeterminate = ref(true)
const handleCheckAllChange = (val: boolean) => {
checkColumns.value = val ? unref(defaultCheckColumns) : []
isIndeterminate.value = false
}
const handleCheckedColumnsChange = (value: string[]) => {
const checkedCount = value.length
checkAll.value = checkedCount === unref(defaultCheckColumns)?.length
isIndeterminate.value = checkedCount > 0 && checkedCount < unref(defaultCheckColumns)?.length
}
const confirm = () => {
const newColumns = cloneDeep(unref(settingColumns))?.map((item) => {
const fixed = unref(settingColumns)?.find((col) => col.field === item.field)?.fixed
item.hidden = !!!unref(checkColumns)?.includes(item.field)
item.fixed = fixed ? fixed : undefined
return item
})
emit('confirm', [...unref(hiddenColumns), ...(newColumns || [])])
modelValue.value = false
}
const restore = () => {
initColumns([...unref(hiddenColumns), ...(unref(oldColumns) || [])], true)
}
const initColumns = (columns: TableColumn[], isReStore = false) => {
const newColumns = columns?.filter((item) => {
if (!isReStore) {
item.fixed = item.fixed !== void 0 ? item.fixed : undefined
}
return (item.type && !DEFAULT_FILTER_COLUMN.includes(item.type)) || !item.type
})
if (!unref(oldColumns)) {
oldColumns.value = cloneDeep(newColumns)
}
settingColumns.value = cloneDeep(newColumns)
hiddenColumns.value = cloneDeep(
columns?.filter((item) => item.type && DEFAULT_FILTER_COLUMN.includes(item.type))
)
defaultCheckColumns.value = unref(settingColumns)?.map((item) => item.field) || []
checkColumns.value =
unref(settingColumns)
?.filter((item) => !item.hidden)
?.map((item) => item.field) || []
if (unref(checkColumns)?.length === unref(defaultCheckColumns)?.length) {
checkAll.value = true
isIndeterminate.value = false
}
}
watch(
() => props.columns,
(columns) => {
initColumns(columns)
},
{
immediate: true
}
)
</script>
<template>
<ElDrawer v-model="modelValue" title="列设置" size="350px">
<div>
<div class="flex items-center justify-between">
<div class="flex items-center justify-between">
<ElCheckbox
v-model="checkAll"
:indeterminate="isIndeterminate"
@change="handleCheckAllChange"
/>
<ElText class="ml-8px!">{{ checkColumns.length }} / {{ settingColumns?.length }}</ElText>
</div>
<ElText>固定 / 排序</ElText>
</div>
<div v-if="settingColumns?.length">
<VueDraggable
v-model="settingColumns"
target=".el-checkbox-group"
handle=".handle"
:animation="150"
>
<ElCheckboxGroup
ref="draggableWrap"
v-model="checkColumns"
@change="handleCheckedColumnsChange"
>
<div
v-for="item in settingColumns"
:key="item.field"
class="flex items-center justify-between mt-12px"
>
<ElCheckbox :label="item.field">
{{ item.label }}
</ElCheckbox>
<div class="flex items-center">
<ElRadioGroup size="small" v-model="item.fixed">
<ElRadioButton label="left">
<Icon icon="ep:arrow-left" />
</ElRadioButton>
<ElRadioButton :label="undefined">
<Icon icon="ep:close" />
</ElRadioButton>
<ElRadioButton label="right">
<Icon icon="ep:arrow-right" />
</ElRadioButton>
</ElRadioGroup>
<div class="ml-12px cursor-move handle"><Icon icon="ep:rank" /></div>
</div>
</div>
</ElCheckboxGroup>
</VueDraggable>
</div>
</div>
<template #footer>
<div>
<BaseButton @click="restore">还原</BaseButton>
<BaseButton type="primary" @click="confirm">确定</BaseButton>
</div>
</template>
</ElDrawer>
</template>

View File

@ -1,10 +1,11 @@
<script lang="tsx"> <script lang="tsx">
import { defineComponent, unref, computed, PropType } from 'vue' import { defineComponent, unref, computed, PropType, ref } from 'vue'
import { ElTooltip, ElDropdown, ElDropdownMenu, ElDropdownItem, ComponentSize } from 'element-plus' import { ElDropdown, ElDropdownMenu, ElDropdownItem, ComponentSize } from 'element-plus'
import { Icon } from '@/components/Icon' import { Icon } from '@/components/Icon'
import { useI18n } from '@/hooks/web/useI18n' import { useI18n } from '@/hooks/web/useI18n'
import { useAppStore } from '@/store/modules/app' import { useAppStore } from '@/store/modules/app'
import { TableColumn } from '../types' import { TableColumn } from '../types'
import ColumnSetting from './ColumnSetting.vue'
const appStore = useAppStore() const appStore = useAppStore()
const sizeMap = computed(() => appStore.sizeMap) const sizeMap = computed(() => appStore.sizeMap)
@ -13,14 +14,19 @@ const { t } = useI18n()
export default defineComponent({ export default defineComponent({
name: 'TableActions', name: 'TableActions',
components: {
ColumnSetting
},
props: { props: {
columns: { columns: {
type: Array as PropType<TableColumn[]>, type: Array as PropType<TableColumn[]>,
default: () => [] default: () => []
} }
}, },
emits: ['refresh', 'changSize'], emits: ['refresh', 'changSize', 'confirm'],
setup(_, { emit }) { setup(props, { emit }) {
const showSetting = ref(false)
const refresh = () => { const refresh = () => {
emit('refresh') emit('refresh')
} }
@ -29,54 +35,71 @@ export default defineComponent({
emit('changSize', size) emit('changSize', size)
} }
const confirm = (columns: TableColumn[]) => {
emit('confirm', columns)
}
const showColumnSetting = () => {
showSetting.value = true
}
return () => ( return () => (
<> <>
<div class="text-right h-28px flex items-center justify-end"> <div class="text-right h-28px flex items-center justify-end">
<ElTooltip content={t('common.refresh')} placement="top"> <div title="刷新" class="w-30px h-20px flex items-center justify-end" onClick={refresh}>
<span onClick={refresh}> <Icon
<Icon icon="ant-design:sync-outlined"
icon="ant-design:sync-outlined" class="cursor-pointer"
class="cursor-pointer" hover-color="var(--el-color-primary)"
hover-color="var(--el-color-primary)" />
/> </div>
</span>
</ElTooltip>
<ElTooltip content={t('common.size')} placement="top"> <ElDropdown trigger="click" onCommand={changSize}>
<ElDropdown trigger="click" onCommand={changSize}> {{
{{ default: () => {
default: () => { return (
return ( <div title="尺寸" class="w-30px h-20px flex items-center justify-end">
<span> <Icon
<Icon icon="ant-design:column-height-outlined"
icon="ant-design:column-height-outlined" class="cursor-pointer"
class="cursor-pointer mr-8px ml-8px" hover-color="var(--el-color-primary)"
hover-color="var(--el-color-primary)" />
/> </div>
</span> )
) },
}, dropdown: () => {
dropdown: () => { return (
return ( <ElDropdownMenu>
<ElDropdownMenu> {{
{{ default: () => {
default: () => { return unref(sizeMap).map((v) => {
return unref(sizeMap).map((v) => { return (
return ( <ElDropdownItem key={v} command={v}>
<ElDropdownItem key={v} command={v}> {t(`size.${v}`)}
{t(`size.${v}`)} </ElDropdownItem>
</ElDropdownItem> )
) })
}) }
} }}
}} </ElDropdownMenu>
</ElDropdownMenu> )
) }
} }}
}} </ElDropdown>
</ElDropdown>
</ElTooltip> <div
title="列设置"
class="w-30px h-20px flex items-center justify-end"
onClick={showColumnSetting}
>
<Icon
icon="ant-design:setting-outlined"
class="cursor-pointer"
hover-color="var(--el-color-primary)"
/>
</div>
</div> </div>
<ColumnSetting v-model={showSetting.value} columns={props.columns} onConfirm={confirm} />
</> </>
) )
} }

View File

@ -22,3 +22,8 @@ export const NO_REDIRECT_WHITE_LIST = ['/login']
* *
*/ */
export const NO_RESET_WHITE_LIST = ['Redirect', 'Login', 'NoFind', 'Root'] export const NO_RESET_WHITE_LIST = ['Redirect', 'Login', 'NoFind', 'Root']
/**
*
*/
export const DEFAULT_FILTER_COLUMN = ['expand', 'selection']

View File

@ -8,7 +8,7 @@ interface Option {
const emitter = mitt() const emitter = mitt()
export const useEmitt = (option?: Option) => { export const useEventBus = (option?: Option) => {
if (option) { if (option) {
emitter.on(option.name, option.callback) emitter.on(option.name, option.callback)
@ -18,6 +18,9 @@ export const useEmitt = (option?: Option) => {
} }
return { return {
emitter on: emitter.on,
off: emitter.off,
emit: emitter.emit,
all: emitter.all
} }
} }

View File

@ -48,7 +48,9 @@ export default {
lengthRange: 'The length should be between {min} and {max}', lengthRange: 'The length should be between {min} and {max}',
notSpace: 'Spaces are not allowed', notSpace: 'Spaces are not allowed',
notSpecialCharacters: 'Special characters are not allowed', notSpecialCharacters: 'Special characters are not allowed',
isEqual: 'The two are not equal' isEqual: 'The two are not equal',
// 列设置
setting: 'Setting'
}, },
lock: { lock: {
lockScreen: 'Lock screen', lockScreen: 'Lock screen',

View File

@ -48,7 +48,8 @@ export default {
lengthRange: '长度在 {min} 到 {max} 个字符', lengthRange: '长度在 {min} 到 {max} 个字符',
notSpace: '不能包含空格', notSpace: '不能包含空格',
notSpecialCharacters: '不能包含特殊字符', notSpecialCharacters: '不能包含特殊字符',
isEqual: '两次输入不一致' isEqual: '两次输入不一致',
setting: '设置'
}, },
lock: { lock: {
lockScreen: '锁定屏幕', lockScreen: '锁定屏幕',

View File

@ -12,6 +12,12 @@ export const setupElementPlus = (app: App<Element>) => {
app.use(plugin) app.use(plugin)
}) })
// 为了开发环境启动更快,一次性引入所有样式
if (import.meta.env.VITE_USE_ALL_ELEMENT_PLUS_STYLE === 'true') {
import('element-plus/dist/index.css')
return
}
components.forEach((component) => { components.forEach((component) => {
app.component(component.name!, component) app.component(component.name!, component)
}) })

View File

@ -1,3 +1 @@
import 'virtual:svg-icons-register' import 'virtual:svg-icons-register'
import '@purge-icons/generated'

View File

@ -59,41 +59,35 @@ const columns = reactive<TableColumn[]>([
type: 'index' type: 'index'
}, },
{ {
field: 'content', field: 'title',
label: t('tableDemo.header'), label: t('tableDemo.title')
children: [ },
{ {
field: 'title', field: 'author',
label: t('tableDemo.title') label: t('tableDemo.author')
}, },
{ {
field: 'author', field: 'display_time',
label: t('tableDemo.author') label: t('tableDemo.displayTime')
}, },
{ {
field: 'display_time', field: 'importance',
label: t('tableDemo.displayTime') label: t('tableDemo.importance'),
}, formatter: (_: Recordable, __: TableColumn, cellValue: number) => {
{ return (
field: 'importance', <ElTag type={cellValue === 1 ? 'success' : cellValue === 2 ? 'warning' : 'danger'}>
label: t('tableDemo.importance'), {cellValue === 1
formatter: (_: Recordable, __: TableColumn, cellValue: number) => { ? t('tableDemo.important')
return ( : cellValue === 2
<ElTag type={cellValue === 1 ? 'success' : cellValue === 2 ? 'warning' : 'danger'}> ? t('tableDemo.good')
{cellValue === 1 : t('tableDemo.commonly')}
? t('tableDemo.important') </ElTag>
: cellValue === 2 )
? t('tableDemo.good') }
: t('tableDemo.commonly')} },
</ElTag> {
) field: 'pageviews',
} label: t('tableDemo.pageviews')
},
{
field: 'pageviews',
label: t('tableDemo.pageviews')
}
]
}, },
{ {
field: 'action', field: 'action',

View File

@ -2,7 +2,7 @@
import { Waterfall } from '@/components/Waterfall' import { Waterfall } from '@/components/Waterfall'
import { ContentWrap } from '@/components/ContentWrap' import { ContentWrap } from '@/components/ContentWrap'
import { useI18n } from '@/hooks/web/useI18n' import { useI18n } from '@/hooks/web/useI18n'
import { faker } from '@faker-js/faker' import Mock from 'mockjs'
import { ref, unref } from 'vue' import { ref, unref } from 'vue'
import { toAnyString } from '@/utils' import { toAnyString } from '@/utils'
@ -12,17 +12,17 @@ const getList = () => {
const list: any = [] const list: any = []
for (let i = 0; i < 20; i++) { for (let i = 0; i < 20; i++) {
// 100, 500 // 100, 500
const height = faker.number.int({ min: 100, max: 500 }) const height = Mock.Random.integer(100, 500)
const width = faker.number.int({ min: 100, max: 500 }) const width = Mock.Random.integer(100, 500)
list.push({ list.push(
width, Mock.mock({
height,
id: toAnyString(),
image_uri: faker.image.url({
width, width,
height height,
id: toAnyString(),
// httphttps
image_uri: Mock.Random.image(`${width}x${height}`).replace('http://', 'https://')
}) })
}) )
} }
data.value = [...unref(data), ...list] data.value = [...unref(data), ...list]
if (unref(data).length >= 60) { if (unref(data).length >= 60) {

View File

@ -5,9 +5,9 @@ import { ref, unref } from 'vue'
import { useI18n } from '@/hooks/web/useI18n' import { useI18n } from '@/hooks/web/useI18n'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import { saveTableApi } from '@/api/table' import { saveTableApi } from '@/api/table'
import { useEmitt } from '@/hooks/event/useEmitt' import { useEventBus } from '@/hooks/event/useEventBus'
const { emitter } = useEmitt() const { emit } = useEventBus()
const { push, go } = useRouter() const { push, go } = useRouter()
@ -28,7 +28,7 @@ const save = async () => {
loading.value = false loading.value = false
}) })
if (res) { if (res) {
emitter.emit('getList', 'add') emit('getList', 'add')
push('/example/example-page') push('/example/example-page')
} }
} }
@ -43,10 +43,10 @@ const save = async () => {
<BaseButton @click="go(-1)"> <BaseButton @click="go(-1)">
{{ t('common.back') }} {{ t('common.back') }}
</BaseButton> </BaseButton>
<BaseButton type="primary" :loading="loading" @click="save"> <BaseButton type="primary" :loading="loading" @click="save"
{{ t('exampleDemo.save') }} >{{ t('exampleDemo.save') }}
</BaseButton> </BaseButton>
</template> </template>
</ContentDetailWrap> </ContentDetailWrap>
</template> </template>
@/hooks/event/useEmitt @/hooks/event/useEventBus

View File

@ -6,9 +6,9 @@ import { useI18n } from '@/hooks/web/useI18n'
import { useRouter, useRoute } from 'vue-router' import { useRouter, useRoute } from 'vue-router'
import { saveTableApi, getTableDetApi } from '@/api/table' import { saveTableApi, getTableDetApi } from '@/api/table'
import { TableData } from '@/api/table/types' import { TableData } from '@/api/table/types'
import { useEmitt } from '@/hooks/event/useEmitt' import { useEventBus } from '@/hooks/event/useEventBus'
const { emitter } = useEmitt() const { emit } = useEventBus()
const { push, go } = useRouter() const { push, go } = useRouter()
@ -42,7 +42,7 @@ const save = async () => {
loading.value = false loading.value = false
}) })
if (res) { if (res) {
emitter.emit('getList', 'editor') emit('getList', 'editor')
push('/example/example-page') push('/example/example-page')
} }
} }
@ -63,4 +63,4 @@ const save = async () => {
</template> </template>
</ContentDetailWrap> </ContentDetailWrap>
</template> </template>
@/hooks/event/useEmitt @/hooks/event/useEventBus

View File

@ -9,7 +9,7 @@ import { useTable } from '@/hooks/web/useTable'
import { TableData } from '@/api/table/types' import { TableData } from '@/api/table/types'
import { reactive, ref, unref } from 'vue' import { reactive, ref, unref } from 'vue'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import { useEmitt } from '@/hooks/event/useEmitt' import { useEventBus } from '@/hooks/event/useEventBus'
import { CrudSchema, useCrudSchemas } from '@/hooks/web/useCrudSchemas' import { CrudSchema, useCrudSchemas } from '@/hooks/web/useCrudSchemas'
import { BaseButton } from '@/components/Button' import { BaseButton } from '@/components/Button'
@ -50,7 +50,7 @@ const { getList, getElTableExpose, delList } = tableMethods
getList() getList()
useEmitt({ useEventBus({
name: 'getList', name: 'getList',
callback: (type: string) => { callback: (type: string) => {
if (type === 'add') { if (type === 'add') {
@ -294,4 +294,4 @@ const action = (row: TableData, type: string) => {
/> />
</ContentWrap> </ContentWrap>
</template> </template>
@/hooks/event/useEmitt @/hooks/event/useEventBus

View File

@ -20,12 +20,8 @@ module.exports = {
'function-no-unknown': null, 'function-no-unknown': null,
'no-empty-source': null, 'no-empty-source': null,
'named-grid-areas-no-invalid': null, 'named-grid-areas-no-invalid': null,
'unicode-bom': 'never',
'no-descending-specificity': null, 'no-descending-specificity': null,
'font-family-no-missing-generic-family-keyword': null, 'font-family-no-missing-generic-family-keyword': null,
'declaration-colon-space-after': 'always-single-line',
'declaration-colon-space-before': 'never',
'declaration-block-trailing-semicolon': null,
'rule-empty-line-before': [ 'rule-empty-line-before': [
'always', 'always',
{ {

View File

@ -1,8 +1,8 @@
declare module 'vue' { declare module 'vue' {
export interface GlobalComponents { export interface GlobalComponents {
Icon: (typeof import('../components/Icon/src/Icon.vue'))['default'] Icon: (typeof import('../src/components/Icon/index'))['Icon']
Permission: (typeof import('../components/Permission/src/Permission.vue'))['default'] Permission: (typeof import('../src/components/Permission/index'))['Permission']
BaseButton: (typeof import('../components/Button/src/Button.vue'))['default'] BaseButton: (typeof import('../src/components/Button/index'))['BaseButton']
} }
} }

4
types/global.d.ts vendored
View File

@ -1,5 +1,5 @@
import type { CSSProperties } from 'vue' import type { CSSProperties } from 'vue'
import { AxiosRequestHeaders } from 'axios' import { RawAxiosRequestHeaders } from 'axios'
declare global { declare global {
declare interface Fn<T = any> { declare interface Fn<T = any> {
(...arg: T[]): T (...arg: T[]): T
@ -40,7 +40,7 @@ declare global {
data?: any data?: any
url?: string url?: string
method?: AxiosMethod method?: AxiosMethod
headers?: AxiosRequestHeaders headers?: RawAxiosRequestHeaders
responseType?: AxiosResponseType responseType?: AxiosResponseType
} }

View File

@ -1,4 +1,4 @@
import { defineConfig, toEscapedSelector as e, presetUno } from 'unocss' import { defineConfig, toEscapedSelector as e, presetUno, presetIcons } from 'unocss'
import transformerVariantGroup from '@unocss/transformer-variant-group' import transformerVariantGroup from '@unocss/transformer-variant-group'
export default defineConfig({ export default defineConfig({
@ -111,6 +111,16 @@ ${selector}:after {
} }
] ]
], ],
presets: [presetUno({ dark: 'class', attributify: false })], presets: [
transformers: [transformerVariantGroup()] presetUno({ dark: 'class', attributify: false }),
presetIcons({
prefix: ''
})
],
transformers: [transformerVariantGroup()],
content: {
pipeline: {
include: [/\.(vue|svelte|[jt]sx|mdx?|astro|elm|php|phtml|html|ts)($|\?)/]
}
}
}) })

View File

@ -5,13 +5,14 @@ import Vue from '@vitejs/plugin-vue'
import VueJsx from '@vitejs/plugin-vue-jsx' import VueJsx from '@vitejs/plugin-vue-jsx'
import progress from 'vite-plugin-progress' import progress from 'vite-plugin-progress'
import EslintPlugin from 'vite-plugin-eslint' import EslintPlugin from 'vite-plugin-eslint'
import { ViteEjsPlugin } from "vite-plugin-ejs" import { ViteEjsPlugin } from 'vite-plugin-ejs'
import { viteMockServe } from 'vite-plugin-mock' 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 { 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'
import { visualizer } from 'rollup-plugin-visualizer'
// https://vitejs.dev/config/ // https://vitejs.dev/config/
const root = process.cwd() const root = process.cwd()
@ -24,7 +25,7 @@ export default ({ command, mode }: ConfigEnv): UserConfig => {
let env = {} as any let env = {} as any
const isBuild = command === 'build' const isBuild = command === 'build'
if (!isBuild) { if (!isBuild) {
env = loadEnv((process.argv[3] === '--mode' ? process.argv[4] : process.argv[3]), root) env = loadEnv(process.argv[3] === '--mode' ? process.argv[4] : process.argv[3], root)
} else { } else {
env = loadEnv(mode, root) env = loadEnv(mode, root)
} }
@ -39,19 +40,23 @@ export default ({ command, mode }: ConfigEnv): UserConfig => {
}), }),
VueJsx(), VueJsx(),
progress(), progress(),
createStyleImportPlugin({ env.VITE_USE_ALL_ELEMENT_PLUS_STYLE === 'false'
resolves: [ElementPlusResolve()], ? createStyleImportPlugin({
libs: [{ resolves: [ElementPlusResolve()],
libraryName: 'element-plus', libs: [
esModule: true, {
resolveStyle: (name) => { libraryName: 'element-plus',
if (name === 'click-outside') { esModule: true,
return '' resolveStyle: (name) => {
} if (name === 'click-outside') {
return `element-plus/es/components/${name.replace(/^el-/, '')}/style/css` return ''
} }
}] return `element-plus/es/components/${name.replace(/^el-/, '')}/style/css`
}), }
}
]
})
: undefined,
EslintPlugin({ EslintPlugin({
cache: false, cache: false,
include: ['src/**/*.vue', 'src/**/*.ts', 'src/**/*.tsx'] // 检查的文件 include: ['src/**/*.vue', 'src/**/*.ts', 'src/**/*.tsx'] // 检查的文件
@ -67,22 +72,23 @@ export default ({ command, mode }: ConfigEnv): UserConfig => {
svgoOptions: true svgoOptions: true
}), }),
PurgeIcons(), PurgeIcons(),
viteMockServe({ env.VITE_USE_MOCK === 'true'
ignore: /^\_/, ? viteMockServe({
mockPath: 'mock', ignore: /^\_/,
localEnabled: !isBuild, mockPath: 'mock',
prodEnabled: isBuild, localEnabled: !isBuild,
injectCode: ` prodEnabled: isBuild,
injectCode: `
import { setupProdMockServer } from '../mock/_createProductionServer' import { setupProdMockServer } from '../mock/_createProductionServer'
setupProdMockServer() setupProdMockServer()
` `
}), })
: undefined,
ViteEjsPlugin({ ViteEjsPlugin({
title: env.VITE_APP_TITLE title: env.VITE_APP_TITLE
}), }),
UnoCSS(), UnoCSS()
// sveltekit(),
], ],
css: { css: {
@ -106,17 +112,28 @@ export default ({ command, mode }: ConfigEnv): UserConfig => {
} }
] ]
}, },
esbuild: {
pure: env.VITE_DROP_CONSOLE === 'true' ? ['console.log'] : undefined,
drop: env.VITE_DROP_DEBUGGER === 'true' ? ['debugger'] : undefined
},
build: { build: {
minify: 'terser', target: 'es2015',
outDir: env.VITE_OUT_DIR || 'dist', outDir: env.VITE_OUT_DIR || 'dist',
sourcemap: env.VITE_SOURCEMAP === 'true' ? 'inline' : false, sourcemap: env.VITE_SOURCEMAP === 'true',
// brotliSize: false, // brotliSize: false,
terserOptions: { rollupOptions: {
compress: { plugins: env.VITE_USE_BUNDLE_ANALYZER === 'true' ? [visualizer()] : undefined,
drop_debugger: env.VITE_DROP_DEBUGGER === 'true', // 拆包
drop_console: env.VITE_DROP_CONSOLE === 'true' output: {
manualChunks: {
'vue-chunks': ['vue', 'vue-router', 'pinia', 'vue-i18n'],
'element-plus': ['element-plus'],
'wang-editor': ['@wangeditor/editor', '@wangeditor/editor-for-vue'],
echarts: ['echarts', 'echarts-wordcloud']
}
} }
} },
cssCodeSplit: !(env.VITE_USE_CSS_SPLIT === 'false')
}, },
server: { server: {
port: 4000, port: 4000,
@ -125,7 +142,7 @@ export default ({ command, mode }: ConfigEnv): UserConfig => {
'/api': { '/api': {
target: 'http://127.0.0.1:8000', target: 'http://127.0.0.1:8000',
changeOrigin: true, changeOrigin: true,
rewrite: path => path.replace(/^\/api/, '') rewrite: (path) => path.replace(/^\/api/, '')
} }
}, },
hmr: { hmr: {