diff --git a/.env.base b/.env.base index 8a8d91c..799b9e1 100644 --- a/.env.base +++ b/.env.base @@ -2,7 +2,7 @@ NODE_ENV=development # 接口前缀 -VITE_API_BASEPATH=base +VITE_API_BASE_PATH=base # 打包路径 VITE_BASE_PATH=/ diff --git a/.env.dev b/.env.dev index 6a641a3..b5b794e 100644 --- a/.env.dev +++ b/.env.dev @@ -2,7 +2,7 @@ NODE_ENV=production # 接口前缀 -VITE_API_BASEPATH=dev +VITE_API_BASE_PATH=dev # 打包路径 VITE_BASE_PATH=/dist-dev/ diff --git a/.env.gitee b/.env.gitee index c55b595..412f1c4 100644 --- a/.env.gitee +++ b/.env.gitee @@ -2,7 +2,7 @@ NODE_ENV=production # 接口前缀 -VITE_API_BASEPATH=pro +VITE_API_BASE_PATH=pro # 打包路径 VITE_BASE_PATH=/vue-element-plus-admin/ diff --git a/.env.pro b/.env.pro index 99a9480..d21f25c 100644 --- a/.env.pro +++ b/.env.pro @@ -2,7 +2,7 @@ NODE_ENV=production # 接口前缀 -VITE_API_BASEPATH=pro +VITE_API_BASE_PATH=pro # 打包路径 VITE_BASE_PATH=/ diff --git a/.env.test b/.env.test index 3f6ebe1..00d8f8a 100644 --- a/.env.test +++ b/.env.test @@ -2,7 +2,7 @@ NODE_ENV=production # 接口前缀 -VITE_API_BASEPATH=test +VITE_API_BASE_PATH=test # 打包路径 VITE_BASE_PATH=/dist-test/ diff --git a/.github/workflows/auto-merge.yml b/.github/workflows/auto-merge.yml index 33b6e00..5727846 100644 --- a/.github/workflows/auto-merge.yml +++ b/.github/workflows/auto-merge.yml @@ -24,6 +24,7 @@ jobs: - name: Automerge uses: 'pascalgn/automerge-action@v0.14.3' env: + BASE_BRANCHES: 'release' GITHUB_TOKEN: '${{ secrets.TOKEN }}' MERGE_LABELS: '' MERGE_FILTER_AUTHOR: 'kailong321200875' diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 609f607..4367b1c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,7 +1,7 @@ on: push: branches: - - master + - release name: Release diff --git a/.husky/commit-msg b/.husky/commit-msg old mode 100644 new mode 100755 diff --git a/.husky/pre-commit b/.husky/pre-commit old mode 100644 new mode 100755 diff --git a/mock/department/index.ts b/mock/department/index.ts new file mode 100644 index 0000000..34b5341 --- /dev/null +++ b/mock/department/index.ts @@ -0,0 +1,219 @@ +import config from '@/config/axios/config' +import { MockMethod } from 'vite-plugin-mock' +import { toAnyString } from '@/utils' +import Mock from 'mockjs' + +const { code } = config + +const departmentList: any = [] + +const citys = ['厦门总公司', '北京分公司', '上海分公司', '福州分公司', '深圳分公司', '杭州分公司'] + +for (let i = 0; i < 5; i++) { + departmentList.push({ + // 部门名称 + departmentName: citys[i], + id: toAnyString(), + createTime: '@datetime', + // 状态 + status: Mock.Random.integer(0, 1), + // 备注 + remark: '@cword(10, 15)', + children: [ + { + // 部门名称 + departmentName: '研发部', + createTime: '@datetime', + // 状态 + status: Mock.Random.integer(0, 1), + id: toAnyString(), + remark: '@cword(10, 15)' + }, + { + // 部门名称 + departmentName: '产品部', + createTime: '@datetime', + // 状态 + status: Mock.Random.integer(0, 1), + id: toAnyString(), + remark: '@cword(10, 15)' + }, + { + // 部门名称 + departmentName: '运营部', + createTime: '@datetime', + // 状态 + status: Mock.Random.integer(0, 1), + id: toAnyString(), + remark: '@cword(10, 15)' + }, + { + // 部门名称 + departmentName: '市场部', + createTime: '@datetime', + // 状态 + status: Mock.Random.integer(0, 1), + id: toAnyString(), + remark: '@cword(10, 15)' + }, + { + // 部门名称 + departmentName: '销售部', + createTime: '@datetime', + // 状态 + status: Mock.Random.integer(0, 1), + id: toAnyString(), + remark: '@cword(10, 15)' + }, + { + // 部门名称 + departmentName: '客服部', + createTime: '@datetime', + // 状态 + status: Mock.Random.integer(0, 1), + id: toAnyString(), + remark: '@cword(10, 15)' + } + ] + }) +} + +export default [ + // 列表接口 + { + url: '/department/list', + method: 'get', + response: () => { + return { + data: { + code: code, + data: { + list: departmentList + } + } + } + } + }, + { + url: '/department/table/list', + method: 'get', + response: () => { + return { + data: { + code: code, + data: { + list: departmentList, + total: 5 + } + } + } + } + }, + { + url: '/department/users', + method: 'get', + timeout: 1000, + response: ({ query }) => { + const { pageSize } = query + // 根据pageSize来创建数据 + const mockList: any = [] + for (let i = 0; i < pageSize; i++) { + mockList.push( + Mock.mock({ + // 用户名 + username: '@cname', + // 账号 + account: '@first', + // 邮箱 + email: '@EMAIL', + // 创建时间 + createTime: '@datetime', + // 角色 + role: '@first', + // 用户id + id: toAnyString() + }) + ) + } + return { + data: { + code: code, + data: { + total: 100, + list: mockList + } + } + } + } + }, + // 保存接口 + { + url: '/department/user/save', + method: 'post', + timeout: 1000, + response: () => { + return { + data: { + code: code, + data: 'success' + } + } + } + }, + // 删除接口 + { + url: '/department/user/delete', + method: 'post', + response: ({ body }) => { + const ids = body.ids + if (!ids) { + return { + code: '500', + message: '请选择需要删除的数据' + } + } else { + return { + data: { + code: code, + data: 'success' + } + } + } + } + }, + // 保存接口 + { + url: '/department/save', + method: 'post', + timeout: 1000, + response: () => { + return { + data: { + code: code, + data: 'success' + } + } + } + }, + // 删除接口 + { + url: '/department/delete', + method: 'post', + response: ({ body }) => { + const ids = body.ids + if (!ids) { + return { + code: '500', + message: '请选择需要删除的数据' + } + } else { + return { + data: { + code: code, + data: 'success' + } + } + } + } + } +] as MockMethod[] diff --git a/mock/menu/index.ts b/mock/menu/index.ts new file mode 100644 index 0000000..c2f0f61 --- /dev/null +++ b/mock/menu/index.ts @@ -0,0 +1,250 @@ +import config from '@/config/axios/config' +import { MockMethod } from 'vite-plugin-mock' +import Mock from 'mockjs' + +const { code } = config + +const timeout = 1000 + +export default [ + // 列表接口 + { + url: '/menu/list', + method: 'get', + timeout, + response: () => { + return { + data: { + code: code, + data: { + list: [ + { + path: '/dashboard', + component: '#', + redirect: '/dashboard/analysis', + name: 'Dashboard', + status: Mock.Random.integer(0, 1), + id: 1, + meta: { + title: '首页', + icon: 'ant-design:dashboard-filled', + alwaysShow: true + }, + children: [ + { + path: 'analysis', + component: 'views/Dashboard/Analysis', + name: 'Analysis', + status: Mock.Random.integer(0, 1), + id: 2, + meta: { + title: '分析页', + noCache: true + } + }, + { + path: 'workplace', + component: 'views/Dashboard/Workplace', + name: 'Workplace', + status: Mock.Random.integer(0, 1), + id: 3, + meta: { + title: '工作台', + noCache: true + } + } + ] + }, + { + path: '/external-link', + component: '#', + meta: { + title: '文档', + icon: 'clarity:document-solid' + }, + name: 'ExternalLink', + status: Mock.Random.integer(0, 1), + id: 4, + children: [ + { + path: 'https://element-plus-admin-doc.cn/', + name: 'DocumentLink', + status: Mock.Random.integer(0, 1), + id: 5, + meta: { + title: '文档' + } + } + ] + }, + { + path: '/level', + component: '#', + redirect: '/level/menu1/menu1-1/menu1-1-1', + name: 'Level', + status: Mock.Random.integer(0, 1), + id: 6, + meta: { + title: '菜单', + icon: 'carbon:skill-level-advanced' + }, + children: [ + { + path: 'menu1', + name: 'Menu1', + component: '##', + status: Mock.Random.integer(0, 1), + id: 7, + redirect: '/level/menu1/menu1-1/menu1-1-1', + meta: { + title: '菜单1' + }, + children: [ + { + path: 'menu1-1', + name: 'Menu11', + component: '##', + status: Mock.Random.integer(0, 1), + id: 8, + redirect: '/level/menu1/menu1-1/menu1-1-1', + meta: { + title: '菜单1-1', + alwaysShow: true + }, + children: [ + { + path: 'menu1-1-1', + name: 'Menu111', + component: 'views/Level/Menu111', + status: Mock.Random.integer(0, 1), + id: 9, + permission: ['edit', 'add', 'delete'], + meta: { + title: '菜单1-1-1' + } + } + ] + }, + { + path: 'menu1-2', + name: 'Menu12', + component: 'views/Level/Menu12', + status: Mock.Random.integer(0, 1), + id: 10, + permission: ['edit', 'add', 'delete'], + meta: { + title: '菜单1-2' + } + } + ] + }, + { + path: 'menu2', + name: 'Menu2Demo', + component: 'views/Level/Menu2', + status: Mock.Random.integer(0, 1), + id: 11, + permission: ['edit', 'add', 'delete'], + meta: { + title: '菜单2' + } + } + ] + }, + { + path: '/example', + component: '#', + redirect: '/example/example-dialog', + name: 'Example', + status: Mock.Random.integer(0, 1), + id: 12, + meta: { + title: '综合示例', + icon: 'ep:management', + alwaysShow: true + }, + children: [ + { + path: 'example-dialog', + component: 'views/Example/Dialog/ExampleDialog', + name: 'ExampleDialog', + status: Mock.Random.integer(0, 1), + id: 13, + permission: ['edit', 'add', 'delete'], + meta: { + title: '综合示例-弹窗', + permission: ['edit', 'add'] + } + }, + { + path: 'example-page', + component: 'views/Example/Page/ExamplePage', + name: 'ExamplePage', + status: Mock.Random.integer(0, 1), + id: 14, + permission: ['edit', 'add', 'delete'], + meta: { + title: '综合示例-页面', + permission: ['edit', 'add'] + } + }, + { + path: 'example-add', + component: 'views/Example/Page/ExampleAdd', + name: 'ExampleAdd', + status: Mock.Random.integer(0, 1), + id: 15, + permission: ['edit', 'add', 'delete'], + meta: { + title: '综合示例-新增', + noTagsView: true, + noCache: true, + hidden: true, + showMainRoute: true, + activeMenu: '/example/example-page', + permission: ['delete', 'add'] + } + }, + { + path: 'example-edit', + component: 'views/Example/Page/ExampleEdit', + name: 'ExampleEdit', + status: Mock.Random.integer(0, 1), + id: 16, + permission: ['edit', 'add', 'delete'], + meta: { + title: '综合示例-编辑', + noTagsView: true, + noCache: true, + hidden: true, + showMainRoute: true, + activeMenu: '/example/example-page', + permission: ['delete', 'add'] + } + }, + { + path: 'example-detail', + component: 'views/Example/Page/ExampleDetail', + name: 'ExampleDetail', + status: Mock.Random.integer(0, 1), + id: 17, + permission: ['edit', 'add', 'delete'], + meta: { + title: '综合示例-详情', + noTagsView: true, + noCache: true, + hidden: true, + showMainRoute: true, + activeMenu: '/example/example-page', + permission: ['delete', 'edit'] + } + } + ] + } + ] + } + } + } + } + } +] as MockMethod[] diff --git a/mock/role/index.ts b/mock/role/index.ts index 72022c6..3f93471 100644 --- a/mock/role/index.ts +++ b/mock/role/index.ts @@ -1,5 +1,7 @@ import config from '@/config/axios/config' import { MockMethod } from 'vite-plugin-mock' +import Mock from 'mockjs' +import { toAnyString } from '@/utils' const { code } = config @@ -105,14 +107,6 @@ const adminList = [ meta: { title: 'UseForm' } - }, - { - path: 'ref-form', - component: 'views/Components/Form/RefForm', - name: 'RefForm', - meta: { - title: 'RefForm' - } } ] }, @@ -143,13 +137,29 @@ const adminList = [ } }, { - path: 'ref-table', - component: 'views/Components/Table/RefTable', - name: 'RefTable', + path: 'tree-table', + component: 'views/Components/Table/TreeTable', + name: 'TreeTable', meta: { - title: 'RefTable' + title: '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' + // } + // } ] }, { @@ -259,14 +269,6 @@ const adminList = [ meta: { title: 'router.inputPassword' } - }, - { - path: 'sticky', - component: 'views/Components/Sticky', - name: 'Sticky', - meta: { - title: 'router.sticky' - } } ] }, @@ -290,13 +292,21 @@ const adminList = [ } }, { - path: 'useCrudSchemas', - component: 'views/hooks/useCrudSchemas', - name: 'UseCrudSchemas', + path: 'useOpenTab', + component: 'views/hooks/useOpenTab', + name: 'UseOpenTab', meta: { - title: 'useCrudSchemas' + title: 'useOpenTab' } } + // { + // path: 'useCrudSchemas', + // component: 'views/hooks/useCrudSchemas', + // name: 'UseCrudSchemas', + // meta: { + // title: 'useCrudSchemas' + // } + // } ] }, { @@ -462,6 +472,59 @@ const adminList = [ } } ] + }, + { + path: '/authorization', + component: '#', + redirect: '/authorization/user', + name: 'Authorization', + meta: { + title: 'router.authorization', + icon: 'eos-icons:role-binding', + alwaysShow: true + }, + children: [ + { + path: 'department', + component: 'views/Authorization/Department/Department', + name: 'Department', + meta: { + title: 'router.department' + } + }, + { + path: 'user', + component: 'views/Authorization/User/User', + name: 'User', + meta: { + title: 'router.user' + } + }, + { + path: 'menu', + component: 'views/Authorization/Menu/Menu', + name: 'Menu', + meta: { + title: 'router.menuManagement' + } + }, + { + path: 'role', + component: 'views/Authorization/Role/Role', + name: 'Role', + meta: { + title: 'router.role' + } + }, + { + path: 'test', + component: 'views/Authorization/Test/Test', + name: 'Test', + meta: { + title: 'router.permission' + } + } + ] } ] @@ -481,6 +544,8 @@ const testList: string[] = [ '/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', @@ -498,7 +563,8 @@ const testList: string[] = [ '/Components/Sticky', '/hooks', '/hooks/useWatermark', - '/hooks/useCrudSchemas', + '/hooks/useOpenTab', + // '/hooks/useCrudSchemas', '/level', '/level/menu1', '/level/menu1/menu1-1', @@ -511,12 +577,441 @@ const testList: string[] = [ '/example/example-add', '/example/example-edit', '/example/example-detail', + '/authorization', + '/authorization/department', + '/authorization/user', + '/authorization/role', + '/authorization/menu', + '/authorization/test', '/error', '/error/404-demo', '/error/403-demo', '/error/500-demo' ] +const List: any[] = [] + +const roleNames = ['超级管理员', '管理员', '普通用户', '游客'] +const menus = [ + [ + { + path: '/dashboard', + component: '#', + redirect: '/dashboard/analysis', + name: 'Dashboard', + status: Mock.Random.integer(0, 1), + id: 1, + meta: { + title: '首页', + icon: 'ant-design:dashboard-filled', + alwaysShow: true + }, + children: [ + { + path: 'analysis', + component: 'views/Dashboard/Analysis', + name: 'Analysis', + status: Mock.Random.integer(0, 1), + id: 2, + meta: { + title: '分析页', + noCache: true + } + }, + { + path: 'workplace', + component: 'views/Dashboard/Workplace', + name: 'Workplace', + status: Mock.Random.integer(0, 1), + id: 3, + meta: { + title: '工作台', + noCache: true + } + } + ] + }, + { + path: '/external-link', + component: '#', + meta: { + title: '文档', + icon: 'clarity:document-solid' + }, + name: 'ExternalLink', + status: Mock.Random.integer(0, 1), + id: 4, + children: [ + { + path: 'https://element-plus-admin-doc.cn/', + name: 'DocumentLink', + status: Mock.Random.integer(0, 1), + id: 5, + meta: { + title: '文档' + } + } + ] + }, + { + path: '/level', + component: '#', + redirect: '/level/menu1/menu1-1/menu1-1-1', + name: 'Level', + status: Mock.Random.integer(0, 1), + id: 6, + meta: { + title: '菜单', + icon: 'carbon:skill-level-advanced' + }, + children: [ + { + path: 'menu1', + name: 'Menu1', + component: '##', + status: Mock.Random.integer(0, 1), + id: 7, + redirect: '/level/menu1/menu1-1/menu1-1-1', + meta: { + title: '菜单1' + }, + children: [ + { + path: 'menu1-1', + name: 'Menu11', + component: '##', + status: Mock.Random.integer(0, 1), + id: 8, + redirect: '/level/menu1/menu1-1/menu1-1-1', + meta: { + title: '菜单1-1', + alwaysShow: true + }, + children: [ + { + path: 'menu1-1-1', + name: 'Menu111', + component: 'views/Level/Menu111', + status: Mock.Random.integer(0, 1), + id: 9, + permission: ['edit', 'add', 'delete'], + meta: { + title: '菜单1-1-1', + permission: ['edit', 'add', 'delete'] + } + } + ] + }, + { + path: 'menu1-2', + name: 'Menu12', + component: 'views/Level/Menu12', + status: Mock.Random.integer(0, 1), + id: 10, + permission: ['edit', 'add', 'delete'], + meta: { + title: '菜单1-2', + permission: ['edit', 'add', 'delete'] + } + } + ] + }, + { + path: 'menu2', + name: 'Menu2Demo', + component: 'views/Level/Menu2', + status: Mock.Random.integer(0, 1), + id: 11, + permission: ['edit', 'add', 'delete'], + meta: { + title: '菜单2', + permission: ['edit', 'add', 'delete'] + } + } + ] + }, + { + path: '/example', + component: '#', + redirect: '/example/example-dialog', + name: 'Example', + status: Mock.Random.integer(0, 1), + id: 12, + meta: { + title: '综合示例', + icon: 'ep:management', + alwaysShow: true + }, + children: [ + { + path: 'example-dialog', + component: 'views/Example/Dialog/ExampleDialog', + name: 'ExampleDialog', + status: Mock.Random.integer(0, 1), + id: 13, + permission: ['edit', 'add', 'delete'], + meta: { + title: '综合示例-弹窗', + permission: ['edit', 'add', 'delete'] + } + }, + { + path: 'example-page', + component: 'views/Example/Page/ExamplePage', + name: 'ExamplePage', + status: Mock.Random.integer(0, 1), + id: 14, + permission: ['edit', 'add', 'delete'], + meta: { + title: '综合示例-页面', + permission: ['edit', 'add', 'delete'] + } + }, + { + path: 'example-add', + component: 'views/Example/Page/ExampleAdd', + name: 'ExampleAdd', + status: Mock.Random.integer(0, 1), + id: 15, + permission: ['edit', 'add', 'delete'], + meta: { + title: '综合示例-新增', + noTagsView: true, + noCache: true, + hidden: true, + showMainRoute: true, + activeMenu: '/example/example-page', + permission: ['edit', 'add', 'delete'] + } + }, + { + path: 'example-edit', + component: 'views/Example/Page/ExampleEdit', + name: 'ExampleEdit', + status: Mock.Random.integer(0, 1), + id: 16, + permission: ['edit', 'add', 'delete'], + meta: { + title: '综合示例-编辑', + noTagsView: true, + noCache: true, + hidden: true, + showMainRoute: true, + activeMenu: '/example/example-page', + permission: ['edit', 'add', 'delete'] + } + }, + { + path: 'example-detail', + component: 'views/Example/Page/ExampleDetail', + name: 'ExampleDetail', + status: Mock.Random.integer(0, 1), + id: 17, + permission: ['edit', 'add', 'delete'], + meta: { + title: '综合示例-详情', + noTagsView: true, + noCache: true, + hidden: true, + showMainRoute: true, + activeMenu: '/example/example-page', + permission: ['edit', 'add', 'delete'] + } + } + ] + } + ], + [ + { + path: '/dashboard', + component: '#', + redirect: '/dashboard/analysis', + name: 'Dashboard', + status: Mock.Random.integer(0, 1), + id: 1, + meta: { + title: '首页', + icon: 'ant-design:dashboard-filled', + alwaysShow: true + }, + children: [ + { + path: 'analysis', + component: 'views/Dashboard/Analysis', + name: 'Analysis', + status: Mock.Random.integer(0, 1), + id: 2, + meta: { + title: '分析页', + noCache: true + } + }, + { + path: 'workplace', + component: 'views/Dashboard/Workplace', + name: 'Workplace', + status: Mock.Random.integer(0, 1), + id: 3, + meta: { + title: '工作台', + noCache: true + } + } + ] + } + ], + [ + { + path: '/external-link', + component: '#', + meta: { + title: '文档', + icon: 'clarity:document-solid' + }, + name: 'ExternalLink', + status: Mock.Random.integer(0, 1), + id: 4, + children: [ + { + path: 'https://element-plus-admin-doc.cn/', + name: 'DocumentLink', + status: Mock.Random.integer(0, 1), + id: 5, + meta: { + title: '文档' + } + } + ] + }, + { + path: '/level', + component: '#', + redirect: '/level/menu1/menu1-1/menu1-1-1', + name: 'Level', + status: Mock.Random.integer(0, 1), + id: 6, + meta: { + title: '菜单', + icon: 'carbon:skill-level-advanced' + }, + children: [ + { + path: 'menu1', + name: 'Menu1', + component: '##', + status: Mock.Random.integer(0, 1), + id: 7, + redirect: '/level/menu1/menu1-1/menu1-1-1', + meta: { + title: '菜单1' + }, + children: [ + { + path: 'menu1-1', + name: 'Menu11', + component: '##', + status: Mock.Random.integer(0, 1), + id: 8, + redirect: '/level/menu1/menu1-1/menu1-1-1', + meta: { + title: '菜单1-1', + alwaysShow: true + }, + children: [ + { + path: 'menu1-1-1', + name: 'Menu111', + component: 'views/Level/Menu111', + status: Mock.Random.integer(0, 1), + id: 9, + permission: ['edit', 'add', 'delete'], + meta: { + title: '菜单1-1-1', + permission: ['edit', 'add', 'delete'] + } + } + ] + }, + { + path: 'menu1-2', + name: 'Menu12', + component: 'views/Level/Menu12', + status: Mock.Random.integer(0, 1), + id: 10, + permission: ['edit', 'add', 'delete'], + meta: { + title: '菜单1-2', + permission: ['edit', 'add', 'delete'] + } + } + ] + }, + { + path: 'menu2', + name: 'Menu2Demo', + component: 'views/Level/Menu2', + status: Mock.Random.integer(0, 1), + id: 11, + permission: ['edit', 'add', 'delete'], + meta: { + title: '菜单2', + permission: ['edit', 'add', 'delete'] + } + } + ] + } + ], + [ + { + path: '/example', + component: '#', + redirect: '/example/example-dialog', + name: 'Example', + status: Mock.Random.integer(0, 1), + id: 12, + meta: { + title: '综合示例', + icon: 'ep:management', + alwaysShow: true + }, + children: [ + { + path: 'example-detail', + component: 'views/Example/Page/ExampleDetail', + name: 'ExampleDetail', + status: Mock.Random.integer(0, 1), + id: 17, + permission: ['edit', 'add', 'delete'], + meta: { + title: '综合示例-详情', + noTagsView: true, + noCache: true, + hidden: true, + showMainRoute: true, + activeMenu: '/example/example-page', + permission: ['edit', 'add', 'delete'] + } + } + ] + } + ] +] + +for (let i = 0; i < 4; i++) { + List.push( + Mock.mock({ + id: toAnyString(), + // timestamp: +Mock.Random.date('T'), + roleName: roleNames[i], + role: '@first', + status: Mock.Random.integer(0, 1), + createTime: '@datetime', + remark: '@cword(10, 15)', + menu: menus[i] + }) + ) +} + export default [ // 列表接口 { @@ -532,5 +1027,21 @@ export default [ } } } + }, + { + url: '/role/table', + method: 'get', + timeout, + response: () => { + return { + data: { + code: code, + data: { + list: List, + total: 4 + } + } + } + } } ] as MockMethod[] diff --git a/mock/table/index.ts b/mock/table/index.ts index ca8512d..04a3d78 100644 --- a/mock/table/index.ts +++ b/mock/table/index.ts @@ -12,7 +12,7 @@ const count = 100 const baseContent = '

I am testing data, I am testing data.

' -let List: { +interface ListProps { id: string author: string title: string @@ -20,7 +20,21 @@ let List: { importance: number display_time: string pageviews: number -}[] = [] + image_uri: string +} + +interface TreeListProps { + id: string + author: string + title: string + content: string + importance: number + display_time: string + pageviews: number + children: TreeListProps[] +} + +let List: ListProps[] = [] for (let i = 0; i < count; i++) { List.push( @@ -32,13 +46,120 @@ for (let i = 0; i < count; i++) { content: baseContent, importance: '@integer(1, 3)', display_time: '@datetime', - pageviews: '@integer(300, 5000)' + pageviews: '@integer(300, 5000)', + image_uri: Mock.Random.image('@integer(300, 5000)x@integer(300, 5000)') + }) + ) +} + +const treeList: TreeListProps[] = [] + +for (let i = 0; i < count; i++) { + treeList.push( + Mock.mock({ + id: toAnyString(), + // timestamp: +Mock.Random.date('T'), + author: '@first', + title: '@title(5, 10)', + content: baseContent, + importance: '@integer(1, 3)', + display_time: '@datetime', + pageviews: '@integer(300, 5000)', + children: [ + { + id: toAnyString(), + // timestamp: +Mock.Random.date('T'), + author: '@first', + title: '@title(5, 10)', + content: baseContent, + importance: '@integer(1, 3)', + display_time: '@datetime', + pageviews: '@integer(300, 5000)', + children: [ + { + id: toAnyString(), + // timestamp: +Mock.Random.date('T'), + author: '@first', + title: '@title(5, 10)', + content: baseContent, + importance: '@integer(1, 3)', + display_time: '@datetime', + pageviews: '@integer(300, 5000)' + }, + { + id: toAnyString(), + // timestamp: +Mock.Random.date('T'), + author: '@first', + title: '@title(5, 10)', + content: baseContent, + importance: '@integer(1, 3)', + display_time: '@datetime', + pageviews: '@integer(300, 5000)' + } + ] + }, + { + id: toAnyString(), + // timestamp: +Mock.Random.date('T'), + author: '@first', + title: '@title(5, 10)', + content: baseContent, + importance: '@integer(1, 3)', + display_time: '@datetime', + pageviews: '@integer(300, 5000)' + }, + { + id: toAnyString(), + // timestamp: +Mock.Random.date('T'), + author: '@first', + title: '@title(5, 10)', + content: baseContent, + importance: '@integer(1, 3)', + display_time: '@datetime', + pageviews: '@integer(300, 5000)' + }, + { + id: toAnyString(), + // timestamp: +Mock.Random.date('T'), + author: '@first', + title: '@title(5, 10)', + content: baseContent, + importance: '@integer(1, 3)', + display_time: '@datetime', + pageviews: '@integer(300, 5000)' + } + ] // image_uri }) ) } export default [ + // 树形列表接口 + { + url: '/example/treeList', + method: 'get', + timeout, + response: ({ query }) => { + const { title, pageIndex, pageSize } = query + const mockList = treeList.filter((item) => { + if (title && item.title.indexOf(title) < 0) return false + return true + }) + const pageList = mockList.filter( + (_, index) => index < pageSize * pageIndex && index >= pageSize * (pageIndex - 1) + ) + return { + data: { + code: code, + data: { + total: mockList.length, + list: pageList + } + } + } + } + }, // 列表接口 { url: '/example/list', diff --git a/package.json b/package.json index 23f74c8..bc28bcc 100644 --- a/package.json +++ b/package.json @@ -1,16 +1,16 @@ { "name": "vue-element-plus-admin", - "version": "1.9.9", + "version": "2.0。0", "description": "一套基于vue3、element-plus、typesScript、vite4的后台集成方案。", "author": "Archer <502431556@qq.com>", "private": false, "scripts": { "i": "pnpm install", "dev": "vite --mode base", - "ts:check": "vue-tsc --noEmit", + "ts:check": "vue-tsc --noEmit --skipLibCheck", "build:pro": "vite build --mode pro", "build:gitee": "vite build --mode gitee", - "build:dev": "npm run ts:check && vite build --mode dev", + "build:dev": "vite build --mode dev", "build:test": "npm run ts:check && vite build --mode test", "serve:pro": "vite preview --mode pro", "serve:dev": "vite preview --mode dev", @@ -26,88 +26,90 @@ "p": "plop" }, "dependencies": { - "@iconify/iconify": "^3.1.0", - "@vueuse/core": "^10.1.2", + "@iconify/iconify": "^3.1.1", + "@iconify/vue": "^4.1.1", + "@vueuse/core": "^10.2.1", "@wangeditor/editor": "^5.1.23", "@wangeditor/editor-for-vue": "^5.1.10", - "@zxcvbn-ts/core": "^3.0.0", + "@zxcvbn-ts/core": "^3.0.3", "animate.css": "^4.1.1", "axios": "^1.4.0", - "dayjs": "^1.11.7", - "echarts": "^5.4.2", + "dayjs": "^1.11.9", + "echarts": "^5.4.3", "echarts-wordcloud": "^2.1.0", - "element-plus": "2.3.4", + "element-plus": "^2.3.8", "intro.js": "^7.0.1", "lodash-es": "^4.17.21", - "mitt": "^3.0.0", + "mitt": "^3.0.1", "mockjs": "^1.1.0", "nprogress": "^0.2.0", - "pinia": "^2.0.36", + "pinia": "^2.1.4", "pinia-plugin-persist": "^1.0.0", "qrcode": "^1.5.3", - "qs": "^6.11.1", - "url": "^0.11.0", - "vue": "3.2.47", + "qs": "^6.11.2", + "sortablejs": "^1.15.0", + "url": "^0.11.1", + "vue": "3.3.4", "vue-i18n": "9.2.2", - "vue-router": "^4.1.6", - "vue-types": "^5.0.2", - "web-storage-cache": "^1.1.1" + "vue-router": "^4.2.4", + "vue-types": "^5.1.0" }, "devDependencies": { - "@commitlint/cli": "^17.6.3", - "@commitlint/config-conventional": "^17.6.3", - "@iconify/json": "^2.2.62", - "@intlify/unplugin-vue-i18n": "^0.10.0", + "@commitlint/cli": "^17.6.7", + "@commitlint/config-conventional": "^17.6.7", + "@iconify/json": "^2.2.92", + "@intlify/unplugin-vue-i18n": "^0.12.2", "@purge-icons/generated": "^0.9.0", "@types/intro.js": "^5.1.1", - "@types/lodash-es": "^4.17.7", - "@types/node": "^20.1.1", + "@types/lodash-es": "^4.17.8", + "@types/node": "^20.4.2", "@types/nprogress": "^0.2.0", - "@types/qrcode": "^1.5.0", + "@types/qrcode": "^1.5.1", "@types/qs": "^6.9.7", - "@typescript-eslint/eslint-plugin": "^5.59.5", - "@typescript-eslint/parser": "^5.59.5", - "@unocss/transformer-variant-group": "^0.51.12", - "@vitejs/plugin-legacy": "^4.0.3", - "@vitejs/plugin-vue": "^4.2.1", + "@types/sortablejs": "^1.15.1", + "@typescript-eslint/eslint-plugin": "^6.1.0", + "@typescript-eslint/parser": "^6.1.0", + "@unocss/transformer-variant-group": "^0.53.5", + "@vitejs/plugin-legacy": "^4.1.0", + "@vitejs/plugin-vue": "^4.2.3", "@vitejs/plugin-vue-jsx": "^3.0.1", - "@vue-macros/volar": "^0.9.8", + "@vue-macros/volar": "^0.12.2", "autoprefixer": "^10.4.14", - "consola": "^3.1.0", - "eslint": "^8.40.0", + "consola": "^3.2.3", + "eslint": "^8.45.0", "eslint-config-prettier": "^8.8.0", - "eslint-define-config": "^1.20.0", - "eslint-plugin-prettier": "^4.2.1", - "eslint-plugin-vue": "^9.11.1", + "eslint-define-config": "^1.21.0", + "eslint-plugin-prettier": "^5.0.0", + "eslint-plugin-vue": "^9.15.1", "husky": "^8.0.3", "less": "^4.1.3", - "lint-staged": "^13.2.2", + "lint-staged": "^13.2.3", "plop": "^3.1.2", - "postcss": "^8.4.23", + "postcss": "^8.4.26", "postcss-html": "^1.5.0", "postcss-less": "^6.0.0", - "prettier": "^2.8.8", - "rimraf": "^5.0.0", - "rollup": "^3.21.5", - "stylelint": "^15.6.1", + "prettier": "^3.0.0", + "rimraf": "^5.0.1", + "rollup": "^3.26.3", + "stylelint": "^15.10.1", "stylelint-config-html": "^1.1.0", "stylelint-config-prettier": "^9.0.5", - "stylelint-config-recommended": "^12.0.0", - "stylelint-config-standard": "^33.0.0", + "stylelint-config-recommended": "^13.0.0", + "stylelint-config-standard": "^34.0.0", "stylelint-order": "^6.0.3", - "terser": "^5.17.2", - "typescript": "5.0.4", - "unocss": "^0.51.12", - "unplugin-vue-define-options": "^1.3.5", - "vite": "4.3.5", + "terser": "^5.19.1", + "typescript": "5.1.6", + "unocss": "^0.53.5", + "unplugin-vue-define-options": "^1.3.11", + "vite": "4.4.4", "vite-plugin-ejs": "^1.6.4", "vite-plugin-eslint": "^1.8.1", - "vite-plugin-mock": "^3.0.0", + "vite-plugin-mock": "2.9.6", "vite-plugin-progress": "^0.0.7", "vite-plugin-purge-icons": "^0.9.2", "vite-plugin-style-import": "2.0.0", "vite-plugin-svg-icons": "^2.0.1", - "vue-tsc": "^1.6.4" + "vue-tsc": "^1.8.5" }, "engines": { "node": ">= 14.18.0" diff --git a/src/App.vue b/src/App.vue index 9a1beeb..c097654 100644 --- a/src/App.vue +++ b/src/App.vue @@ -4,7 +4,7 @@ import { useAppStore } from '@/store/modules/app' import { ConfigGlobal } from '@/components/ConfigGlobal' import { isDark } from '@/utils/is' import { useDesign } from '@/hooks/web/useDesign' -import { useCache } from '@/hooks/web/useCache' +import { useStorage } from '@/hooks/web/useStorage' const { getPrefixCls } = useDesign() @@ -16,12 +16,12 @@ const currentSize = computed(() => appStore.getCurrentSize) const greyMode = computed(() => appStore.getGreyMode) -const { wsCache } = useCache() +const { getStorage } = useStorage() // 根据浏览器当前主题设置系统主题色 const setDefaultTheme = () => { - if (wsCache.get('isDark') !== null) { - appStore.setIsDark(wsCache.get('isDark')) + if (getStorage('isDark') !== null) { + appStore.setIsDark(getStorage('isDark')) return } const isDarkTheme = isDark() diff --git a/src/api/common/index.ts b/src/api/common/index.ts index 3f78a52..07c0f13 100644 --- a/src/api/common/index.ts +++ b/src/api/common/index.ts @@ -1,11 +1,11 @@ import request from '@/config/axios' // 获取所有字典 -export const getDictApi = (): Promise => { +export const getDictApi = () => { return request.get({ url: '/dict/list' }) } // 模拟获取某个字典 -export const getDictOneApi = async (): Promise => { +export const getDictOneApi = async () => { return request.get({ url: '/dict/one' }) } diff --git a/src/api/department/index.ts b/src/api/department/index.ts new file mode 100644 index 0000000..b6ece1e --- /dev/null +++ b/src/api/department/index.ts @@ -0,0 +1,30 @@ +import request from '@/config/axios' +import { DepartmentListResponse, DepartmentUserParams, DepartmentUserResponse } from './types' + +export const getDepartmentApi = () => { + return request.get({ url: '/department/list' }) +} + +export const getUserByIdApi = (params: DepartmentUserParams) => { + return request.get({ 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 }) +} diff --git a/src/api/department/types.ts b/src/api/department/types.ts new file mode 100644 index 0000000..027a628 --- /dev/null +++ b/src/api/department/types.ts @@ -0,0 +1,32 @@ +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 +} diff --git a/src/api/menu/index.ts b/src/api/menu/index.ts new file mode 100644 index 0000000..a7c55a7 --- /dev/null +++ b/src/api/menu/index.ts @@ -0,0 +1,5 @@ +import request from '@/config/axios' + +export const getMenuListApi = () => { + return request.get({ url: '/menu/list' }) +} diff --git a/src/api/role/index.ts b/src/api/role/index.ts new file mode 100644 index 0000000..3e6d3f8 --- /dev/null +++ b/src/api/role/index.ts @@ -0,0 +1,5 @@ +import request from '@/config/axios' + +export const getRoleListApi = () => { + return request.get({ url: '/role/table' }) +} diff --git a/src/api/table/index.ts b/src/api/table/index.ts index bd4f0b9..c3b6d06 100644 --- a/src/api/table/index.ts +++ b/src/api/table/index.ts @@ -1,10 +1,14 @@ import request from '@/config/axios' import type { TableData } from './types' -export const getTableListApi = (params: any): Promise => { +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): Promise => { return request.post({ url: '/example/save', data }) } diff --git a/src/components/ConfigGlobal/index.ts b/src/components/ConfigGlobal/index.ts index dda2462..eaeb7d0 100644 --- a/src/components/ConfigGlobal/index.ts +++ b/src/components/ConfigGlobal/index.ts @@ -1,3 +1,5 @@ import ConfigGlobal from './src/ConfigGlobal.vue' +export type { ConfigGlobalTypes } from './src/types' + export { ConfigGlobal } diff --git a/src/components/ConfigGlobal/src/ConfigGlobal.vue b/src/components/ConfigGlobal/src/ConfigGlobal.vue index 0a55f15..5bd90cf 100644 --- a/src/components/ConfigGlobal/src/ConfigGlobal.vue +++ b/src/components/ConfigGlobal/src/ConfigGlobal.vue @@ -1,20 +1,19 @@ diff --git a/src/components/ContextMenu/index.ts b/src/components/ContextMenu/index.ts index 2a7c1f0..1b5442d 100644 --- a/src/components/ContextMenu/index.ts +++ b/src/components/ContextMenu/index.ts @@ -2,6 +2,8 @@ import ContextMenu from './src/ContextMenu.vue' import { ElDropdown } from 'element-plus' import type { RouteLocationNormalizedLoaded } from 'vue-router' +export type { ContextMenuSchema } from './src/types' + export interface ContextMenuExpose { elDropdownMenuRef: ComponentRef tagItem: RouteLocationNormalizedLoaded diff --git a/src/components/ContextMenu/src/ContextMenu.vue b/src/components/ContextMenu/src/ContextMenu.vue index 5e77307..9583037 100644 --- a/src/components/ContextMenu/src/ContextMenu.vue +++ b/src/components/ContextMenu/src/ContextMenu.vue @@ -4,7 +4,7 @@ import { PropType, ref } from 'vue' import { useI18n } from '@/hooks/web/useI18n' import { useDesign } from '@/hooks/web/useDesign' import type { RouteLocationNormalizedLoaded } from 'vue-router' -import { contextMenuSchema } from '../../../types/contextMenu' +import { ContextMenuSchema } from './types' const { getPrefixCls } = useDesign() const prefixCls = getPrefixCls('context-menu') @@ -15,7 +15,7 @@ const emit = defineEmits(['visibleChange']) const props = defineProps({ schema: { - type: Array as PropType, + type: Array as PropType, default: () => [] }, trigger: { @@ -28,7 +28,7 @@ const props = defineProps({ } }) -const command = (item: contextMenuSchema) => { +const command = (item: ContextMenuSchema) => { item.command && item.command(item) } diff --git a/src/components/ContextMenu/src/types/index.ts b/src/components/ContextMenu/src/types/index.ts new file mode 100644 index 0000000..b2be72b --- /dev/null +++ b/src/components/ContextMenu/src/types/index.ts @@ -0,0 +1,7 @@ +export interface ContextMenuSchema { + disabled?: boolean + divided?: boolean + icon?: string + label: string + command?: (item: ContextMenuSchema) => void +} diff --git a/src/components/Descriptions/index.ts b/src/components/Descriptions/index.ts index 91b0eb4..8f9a0f0 100644 --- a/src/components/Descriptions/index.ts +++ b/src/components/Descriptions/index.ts @@ -1,3 +1,5 @@ import Descriptions from './src/Descriptions.vue' +export type { DescriptionsSchema } from './src/types' + export { Descriptions } diff --git a/src/components/Descriptions/src/Descriptions.vue b/src/components/Descriptions/src/Descriptions.vue index d0fbf5d..20dcc71 100644 --- a/src/components/Descriptions/src/Descriptions.vue +++ b/src/components/Descriptions/src/Descriptions.vue @@ -1,134 +1,144 @@ - + const toggleClick = () => { + if (props.collapse) { + show.value = !unref(show) + } + } - + +
+ + {{ + extra: () => (slots['extra'] ? slots['extra']() : props.extra), + default: () => { + return props.schema.map((item) => { + return ( + + {{ + label: () => (item.slots?.label ? item.slots?.label(item) : item.label), + default: () => + item.slots?.default + ? item.slots?.default(props.data) + : get(props.data, item.field) + }} + + ) + }) + } + }} + +
+
+ + ) + } + } +}) + diff --git a/src/components/Editor/src/Editor.vue b/src/components/Editor/src/Editor.vue index 30e5689..b354db0 100644 --- a/src/components/Editor/src/Editor.vue +++ b/src/components/Editor/src/Editor.vue @@ -99,7 +99,6 @@ const handleChange = (editor: IDomEditor) => { // 组件销毁时,及时销毁编辑器 onBeforeUnmount(() => { const editor = unref(editorRef.value) - if (editor === null) return // 销毁,并移除 editor editor?.destroy() @@ -116,12 +115,12 @@ defineExpose({