From 15fb60b186655f15b6db32fb9b60fadbca66ac52 Mon Sep 17 00:00:00 2001 From: wenqing Date: Thu, 31 Aug 2023 18:26:09 +0800 Subject: [PATCH] feat: role management --- components.d.ts | 4 + src/App.vue | 13 +- src/api/role/index.interface.ts | 22 +++ src/api/role/index.ts | 53 ++++++ src/assets/icons/role.svg | 1 + src/assets/icons/user.svg | 1 + src/assets/logo.svg | 1 - src/constants/index.ts | 7 + src/permission.ts | 2 +- src/plugins/i18n.ts | 10 +- src/router/staticRoutes/labRoutes.ts | 18 ++ src/stores/app.ts | 16 +- src/styles/utils.scss | 19 ++ src/styles/variables.module.scss | 0 src/utils/imageToDataUrl.ts | 30 ---- src/utils/index.ts | 8 +- src/views/system/resource/index.vue | 8 +- src/views/system/role/DataAuthTable.vue | 198 +++++++++++++++++++++ src/views/system/role/RoleEditor.vue | 224 ++++++++++++++++++++++++ src/views/system/role/index.vue | 147 ++++++++++++++++ src/views/system/user/index.vue | 9 + 21 files changed, 743 insertions(+), 48 deletions(-) create mode 100644 src/api/role/index.interface.ts create mode 100644 src/api/role/index.ts create mode 100644 src/assets/icons/role.svg create mode 100644 src/assets/icons/user.svg delete mode 100644 src/assets/logo.svg delete mode 100644 src/styles/variables.module.scss delete mode 100644 src/utils/imageToDataUrl.ts create mode 100644 src/views/system/role/DataAuthTable.vue create mode 100644 src/views/system/role/RoleEditor.vue create mode 100644 src/views/system/role/index.vue create mode 100644 src/views/system/user/index.vue diff --git a/components.d.ts b/components.d.ts index d38bc06..934157c 100644 --- a/components.d.ts +++ b/components.d.ts @@ -14,8 +14,10 @@ declare module 'vue' { ElButton: typeof import('element-plus/es')['ElButton'] ElCard: typeof import('element-plus/es')['ElCard'] ElCascader: typeof import('element-plus/es')['ElCascader'] + ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider'] ElContainer: typeof import('element-plus/es')['ElContainer'] ElDialog: typeof import('element-plus/es')['ElDialog'] + ElDrawer: typeof import('element-plus/es')['ElDrawer'] ElDropdown: typeof import('element-plus/es')['ElDropdown'] ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem'] ElDropdownMenu: typeof import('element-plus/es')['ElDropdownMenu'] @@ -31,12 +33,14 @@ declare module 'vue' { ElMenuItem: typeof import('element-plus/es')['ElMenuItem'] ElMenuItemGroup: typeof import('element-plus/es')['ElMenuItemGroup'] ElOption: typeof import('element-plus/es')['ElOption'] + ElPagination: typeof import('element-plus/es')['ElPagination'] ElScrollbar: typeof import('element-plus/es')['ElScrollbar'] ElSelect: typeof import('element-plus/es')['ElSelect'] ElSubmenu: typeof import('element-plus/es')['ElSubmenu'] ElSubMenu: typeof import('element-plus/es')['ElSubMenu'] ElTable: typeof import('element-plus/es')['ElTable'] ElTableColumn: typeof import('element-plus/es')['ElTableColumn'] + ElTree: typeof import('element-plus/es')['ElTree'] HelloWorld: typeof import('./src/components/HelloWorld.vue')['default'] Logicflow: typeof import('./src/components/Logicflow/index.vue')['default'] LogicFlow: typeof import('./src/components/LogicFlow/index.vue')['default'] diff --git a/src/App.vue b/src/App.vue index 7c2aa3f..4f00534 100644 --- a/src/App.vue +++ b/src/App.vue @@ -1,3 +1,14 @@ + + diff --git a/src/api/role/index.interface.ts b/src/api/role/index.interface.ts new file mode 100644 index 0000000..61066d3 --- /dev/null +++ b/src/api/role/index.interface.ts @@ -0,0 +1,22 @@ +export interface IRoleInfo { + description: string + id: number + name: string + order: number + permissions: number[] + resources: number[] + type: 0 | 1 +} + +export interface IGetRolesParams { + page: number + page_size: number + name: string + type: 0 | 1 | '' +} + +export interface IDataAuthInfo { + group_name: string + id: number + name: string +} diff --git a/src/api/role/index.ts b/src/api/role/index.ts new file mode 100644 index 0000000..3bb25d0 --- /dev/null +++ b/src/api/role/index.ts @@ -0,0 +1,53 @@ +import request from '@/utils/request' +import type { IRoleInfo, IGetRolesParams, IDataAuthInfo } from './index.interface' + +// 获取所有角色 +export const getRoles = (params: IGetRolesParams) => { + return request<{ data: IRoleInfo[]; total: number }>({ + url: '/roles', + method: 'get', + params + }) +} + +// 删除角色 +export const deleteRole = (id: number) => { + return request({ + url: `/roles/${id}`, + method: 'delete' + }) +} + +// 获取单个角色详情 +export const getRoleById = (id: number) => { + return request({ + url: `/roles/${id}`, + method: 'get' + }) +} + +// 修改角色 +export const updateRole = (id: number, data: Omit) => { + return request({ + url: `/roles/${id}`, + method: 'put', + data + }) +} + +// 新增角色 +export const addRole = (data: Omit) => { + return request({ + url: '/roles', + method: 'post', + data + }) +} + +// 获取所有数据权限 +export const getPermissions = () => { + return request({ + url: '/permission', + method: 'get' + }) +} diff --git a/src/assets/icons/role.svg b/src/assets/icons/role.svg new file mode 100644 index 0000000..694a4dc --- /dev/null +++ b/src/assets/icons/role.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/icons/user.svg b/src/assets/icons/user.svg new file mode 100644 index 0000000..ff22bee --- /dev/null +++ b/src/assets/icons/user.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/logo.svg b/src/assets/logo.svg deleted file mode 100644 index 7565660..0000000 --- a/src/assets/logo.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/constants/index.ts b/src/constants/index.ts index 6e84c64..e214e3b 100644 --- a/src/constants/index.ts +++ b/src/constants/index.ts @@ -5,7 +5,14 @@ export const resource_type = [ { label: '页面级', value: 3 } ] +/** 是否 */ export const bool_options = [ { label: '否', value: 0 }, { label: '是', value: 1 } ] + +/** 角色类型 */ +export const role_types = [ + { label: '用户', value: 0 }, + { label: '脚本', value: 1 } +] diff --git a/src/permission.ts b/src/permission.ts index 7500383..867fd5a 100644 --- a/src/permission.ts +++ b/src/permission.ts @@ -63,6 +63,6 @@ export const initPermissionGuard = (router: Router) => { // finish progress bar tricklingProgress.done() // set page title - document.title = to.meta?.title || '' + document.title = to.meta.title ? `${settings.title} | ${to.meta.title}` : settings.title }) } diff --git a/src/plugins/i18n.ts b/src/plugins/i18n.ts index a162403..32ea5e1 100644 --- a/src/plugins/i18n.ts +++ b/src/plugins/i18n.ts @@ -4,18 +4,12 @@ import { useAppStore } from '@/stores/app' import enLocale from '@/locales/en' import zhLocale from '@/locales/zh' -// element-plus国际化 -import enLocaleElementPlus from 'element-plus/dist/locale/en.mjs' -import zhLocaleElementPlus from 'element-plus/dist/locale/zh-cn.mjs' - export const localesConfigs = { en: { - ...enLocale, - ...enLocaleElementPlus + ...enLocale }, zh: { - ...zhLocale, - ...zhLocaleElementPlus + ...zhLocale } } diff --git a/src/router/staticRoutes/labRoutes.ts b/src/router/staticRoutes/labRoutes.ts index d381aca..887b55d 100644 --- a/src/router/staticRoutes/labRoutes.ts +++ b/src/router/staticRoutes/labRoutes.ts @@ -140,6 +140,24 @@ export const labRoutes: IRouteRecord[] = [ title: '资源管理', icon: 'resource-config' } + }, + { + path: 'role', + name: 'SystemRole', + component: () => import('@/views/system/role/index.vue'), + meta: { + title: '角色管理', + icon: 'role' + } + }, + { + path: 'user', + name: 'SystemUser', + component: () => import('@/views/system/user/index.vue'), + meta: { + title: '用户管理', + icon: 'user' + } } ] } diff --git a/src/stores/app.ts b/src/stores/app.ts index 21698a8..28ba40e 100644 --- a/src/stores/app.ts +++ b/src/stores/app.ts @@ -1,7 +1,16 @@ import { defineStore } from 'pinia' -import { ref } from 'vue' +import { computed, ref } from 'vue' import type { LocaleType } from '@/plugins/i18n' +// element-plus国际化 +import enLocaleElementPlus from 'element-plus/dist/locale/en.mjs' +import zhLocaleElementPlus from 'element-plus/dist/locale/zh-cn.mjs' + +export const elmentPlusLocales: Record = { + zh: zhLocaleElementPlus, + en: enLocaleElementPlus +} + export const useAppStore = defineStore( 'app', () => { @@ -19,11 +28,14 @@ export const useAppStore = defineStore( language.value = lang } + const elementPlusLocale = computed(() => elmentPlusLocales[language.value]) + return { sidebar, ToggleSideBar, language, - setLanguage + setLanguage, + elementPlusLocale } }, { diff --git a/src/styles/utils.scss b/src/styles/utils.scss index 4f6c662..0ac5398 100644 --- a/src/styles/utils.scss +++ b/src/styles/utils.scss @@ -2,4 +2,23 @@ .view-container { padding: 14px; +} + +.color { + &--primary { + color: var(--el-color-primary); + } + + &--danger { + color: var(--el-color-danger); + } + + &--warning { + color: var(--el-color-warning); + } + + &--info { + color: var(--el-color-info); + } + } \ No newline at end of file diff --git a/src/styles/variables.module.scss b/src/styles/variables.module.scss deleted file mode 100644 index e69de29..0000000 diff --git a/src/utils/imageToDataUrl.ts b/src/utils/imageToDataUrl.ts deleted file mode 100644 index 72a1986..0000000 --- a/src/utils/imageToDataUrl.ts +++ /dev/null @@ -1,30 +0,0 @@ -const imageToDataURL = function (src: string) { - return new Promise((resolve, reject) => { - const canvas = document.createElement('canvas') - const context = canvas.getContext('2d') as CanvasRenderingContext2D - - const img = new Image() - img.setAttribute('crossOrigin', 'Anonymous') - img.src = src - img.onload = () => { - canvas.width = img.width - canvas.height = img.height - context.clearRect(0, 0, img.width, img.height) - context.drawImage(img, 0, 0) - - resolve(canvas.toDataURL()) - } - - img.onerror = (err) => { - reject(err) - } - }) -} - -const imageToDataURLBatch = async function (srcs: string[]) { - const allTask = srcs.map((v) => imageToDataURL(v)) - - return await Promise.all(allTask) -} - -export { imageToDataURL, imageToDataURLBatch } diff --git a/src/utils/index.ts b/src/utils/index.ts index 2df59da..d73d8fe 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -1,4 +1,10 @@ -import isEmpty from 'lodash/isEmpty' +/** 验证对象或数组是否为空 */ +export const isEmpty = (obj: Object & Array) => { + if (['{}', '[]', 'null', undefined].includes(JSON.stringify(obj))) { + return true + } + return false +} /** * 筛选请求参数 diff --git a/src/views/system/resource/index.vue b/src/views/system/resource/index.vue index 9c614da..e580866 100644 --- a/src/views/system/resource/index.vue +++ b/src/views/system/resource/index.vue @@ -102,6 +102,7 @@ import { paramsVerify } from '@/utils' import { filterResourceTypeLabel, filterBoolToText } from '@/filters' import ResourceEditor from './ResourceEditor.vue' import { ElMessageBox, ElMessage } from 'element-plus' +import { usePermissionStore } from '@/stores/permission' defineOptions({ name: 'SystemResource' @@ -129,12 +130,11 @@ const getTableData = async () => { } } +const PermissionStore = usePermissionStore() + const allResources = ref([]) const cacheAllResources = async () => { - const { status, data } = await getAllResource() - if (status === 200) { - allResources.value = data - } + allResources.value = await PermissionStore.allResources({ force: true }) } const handleQuery = () => { diff --git a/src/views/system/role/DataAuthTable.vue b/src/views/system/role/DataAuthTable.vue new file mode 100644 index 0000000..bd8784c --- /dev/null +++ b/src/views/system/role/DataAuthTable.vue @@ -0,0 +1,198 @@ + + + diff --git a/src/views/system/role/RoleEditor.vue b/src/views/system/role/RoleEditor.vue new file mode 100644 index 0000000..1eedcd3 --- /dev/null +++ b/src/views/system/role/RoleEditor.vue @@ -0,0 +1,224 @@ + + + + + diff --git a/src/views/system/role/index.vue b/src/views/system/role/index.vue new file mode 100644 index 0000000..cfb31f4 --- /dev/null +++ b/src/views/system/role/index.vue @@ -0,0 +1,147 @@ + + + diff --git a/src/views/system/user/index.vue b/src/views/system/user/index.vue new file mode 100644 index 0000000..0b6d56e --- /dev/null +++ b/src/views/system/user/index.vue @@ -0,0 +1,9 @@ + + +