From 87d65d3b1cfc33673043595846a62c3eb6fdbbbc Mon Sep 17 00:00:00 2001 From: Soybean Date: Sun, 28 Jan 2024 23:38:44 +0800 Subject: [PATCH] feat(projects): page manage_menu --- src/constants/business.ts | 16 +- src/constants/common.ts | 8 + src/hooks/common/table.ts | 2 +- src/locales/langs/en-us.ts | 95 +++++-- src/locales/langs/zh-cn.ts | 95 +++++-- src/service/api/system-manage.ts | 8 + src/typings/api.d.ts | 109 ++++++-- src/typings/app.d.ts | 91 +++++-- src/views/manage/menu/index.vue | 255 +++++++++++++++++- .../menu/modules/menu-operate-drawer.vue | 113 ++++++++ src/views/manage/role/index.vue | 16 +- .../role/modules/role-operate-drawer.vue | 14 +- src/views/manage/role/modules/role-search.vue | 8 +- src/views/manage/user/index.vue | 16 +- .../user/modules/user-operate-drawer.vue | 16 +- src/views/manage/user/modules/user-search.vue | 6 +- 16 files changed, 739 insertions(+), 129 deletions(-) create mode 100644 src/constants/common.ts create mode 100644 src/views/manage/menu/modules/menu-operate-drawer.vue diff --git a/src/constants/business.ts b/src/constants/business.ts index 63b7a96fe..c404ee8f5 100644 --- a/src/constants/business.ts +++ b/src/constants/business.ts @@ -1,11 +1,11 @@ import { transformRecordToOption } from '@/utils/common'; -export const roleStatusRecord: Record = { - '1': 'page.manage.role.status.enable', - '2': 'page.manage.role.status.disable' +export const enableStatusRecord: Record = { + '1': 'page.manage.common.status.enable', + '2': 'page.manage.common.status.disable' }; -export const roleStatusOptions = transformRecordToOption(roleStatusRecord); +export const enableStatusOptions = transformRecordToOption(enableStatusRecord); export const userGenderRecord: Record = { '1': 'page.manage.user.gender.male', @@ -14,9 +14,9 @@ export const userGenderRecord: Record = { - '1': 'page.manage.user.status.enable', - '2': 'page.manage.user.status.disable' +export const menuTypeRecord: Record = { + '1': 'page.manage.menu.type.directory', + '2': 'page.manage.menu.type.menu' }; -export const userStatusOptions = transformRecordToOption(userStatusRecord); +export const menuTypeOptions = transformRecordToOption(menuTypeRecord); diff --git a/src/constants/common.ts b/src/constants/common.ts new file mode 100644 index 000000000..2d5e05e3f --- /dev/null +++ b/src/constants/common.ts @@ -0,0 +1,8 @@ +import { transformRecordToOption } from '@/utils/common'; + +export const yesOrNoRecord: Record = { + Y: 'common.yesOrNo.yes', + N: 'common.yesOrNo.no' +}; + +export const yesOrNoOptions = transformRecordToOption(yesOrNoRecord); diff --git a/src/hooks/common/table.ts b/src/hooks/common/table.ts index cafe2804e..6bb500ad4 100644 --- a/src/hooks/common/table.ts +++ b/src/hooks/common/table.ts @@ -33,7 +33,7 @@ export type TableConfig[0]; + apiParams?: Parameters[0]; /** transform api response to table data */ transformer: Transformer>>; /** pagination */ diff --git a/src/locales/langs/en-us.ts b/src/locales/langs/en-us.ts index 306a9ee6f..b4d9abbbc 100644 --- a/src/locales/langs/en-us.ts +++ b/src/locales/langs/en-us.ts @@ -30,7 +30,11 @@ const local: App.I18n.Schema = { tip: 'Tip', update: 'Update', updateSuccess: 'Update Success', - userCenter: 'User Center' + userCenter: 'User Center', + yesOrNo: { + yes: 'Yes', + no: 'No' + } }, theme: { themeSchema: { @@ -253,27 +257,36 @@ const local: App.I18n.Schema = { } }, manage: { + common: { + status: { + enable: 'Enable', + disable: 'Disable' + } + }, role: { title: 'Role List', + roleName: 'Role Name', + roleCode: 'Role Code', + roleStatus: 'Role Status', + roleDesc: 'Role Description', form: { roleName: 'Please enter role name', roleCode: 'Please enter role code', roleStatus: 'Please select role status', roleDesc: 'Please enter role description' }, - roleName: 'Role Name', - roleCode: 'Role Code', - roleStatus: 'Role Status', - roleDesc: 'Role Description', addRole: 'Add Role', - editRole: 'Edit Role', - status: { - enable: 'Enable', - disable: 'Disable' - } + editRole: 'Edit Role' }, user: { title: 'User List', + userName: 'User Name', + userGender: 'Gender', + nickName: 'Nick Name', + userPhone: 'Phone Number', + userEmail: 'Email', + userStatus: 'User Status', + userRole: 'User Role', form: { userName: 'Please enter user name', userGender: 'Please select gender', @@ -283,22 +296,64 @@ const local: App.I18n.Schema = { userStatus: 'Please select user status', userRole: 'Please select user role' }, - userName: 'User Name', - userGender: 'Gender', - nickName: 'Nick Name', - userPhone: 'Phone Number', - userEmail: 'Email', - userStatus: 'User Status', - userRole: 'User Role', addUser: 'Add User', editUser: 'Edit User', gender: { male: 'Male', female: 'Female' + } + }, + menu: { + title: 'Menu List', + menuType: 'Menu Type', + menuName: 'Menu Name', + routeName: 'Route Name', + routePath: 'Route Path', + page: 'Page Component', + layout: 'Layout Component', + i18nKey: 'I18n Key', + icon: 'Icon', + localIcon: 'Local Icon', + order: 'Order', + keepAlive: 'Keep Alive', + href: 'Href', + hideInMenu: 'Hide In Menu', + activeMenu: 'Active Menu', + multiTab: 'Multi Tab', + fixedIndexInTab: 'Fixed Index In Tab', + button: 'Button', + buttonCode: 'Button Code', + buttonDesc: 'Button Desc', + menuStatus: 'Menu Status', + form: { + menuType: 'Please select menu type', + menuName: 'Please enter menu name', + routeName: 'Please enter route name', + routePath: 'Please enter route path', + page: 'Please select page component', + layout: 'Please select layout component', + i18nKey: 'Please enter i18n key', + icon: 'Please enter icon', + localIcon: 'Please select local icon', + order: 'Please enter order', + keepAlive: 'Please select whether to cache route', + href: 'Please enter href', + hideInMenu: 'Please select whether to hide menu', + activeMenu: 'Please enter the route name of the highlighted menu', + multiTab: 'Please select whether to support multiple tabs', + fixedInTab: 'Please select whether to fix in the tab', + fixedIndexInTab: 'Please enter the index fixed in the tab', + button: 'Please select whether it is a button', + buttonCode: 'Please enter button code', + buttonDesc: 'Please enter button description', + menuStatus: 'Please select menu status' }, - status: { - enable: 'Enable', - disable: 'Disable' + addMenu: 'Add Menu', + editMenu: 'Edit Menu', + addChildMenu: 'Add Child Menu', + type: { + directory: 'Directory', + menu: 'Menu' } } } diff --git a/src/locales/langs/zh-cn.ts b/src/locales/langs/zh-cn.ts index 64cb1314f..6eb2a101c 100644 --- a/src/locales/langs/zh-cn.ts +++ b/src/locales/langs/zh-cn.ts @@ -30,7 +30,11 @@ const local: App.I18n.Schema = { tip: '提示', update: '更新', updateSuccess: '更新成功', - userCenter: '个人中心' + userCenter: '个人中心', + yesOrNo: { + yes: '是', + no: '否' + } }, theme: { themeSchema: { @@ -253,27 +257,36 @@ const local: App.I18n.Schema = { } }, manage: { + common: { + status: { + enable: '启用', + disable: '禁用' + } + }, role: { title: '角色列表', + roleName: '角色名称', + roleCode: '角色编码', + roleStatus: '角色状态', + roleDesc: '角色描述', form: { roleName: '请输入角色名称', roleCode: '请输入角色编码', roleStatus: '请选择角色状态', roleDesc: '请输入角色描述' }, - roleName: '角色名称', - roleCode: '角色编码', - roleStatus: '角色状态', - roleDesc: '角色描述', addRole: '新增角色', - editRole: '编辑角色', - status: { - enable: '启用', - disable: '禁用' - } + editRole: '编辑角色' }, user: { title: '用户列表', + userName: '用户名', + userGender: '性别', + nickName: '昵称', + userPhone: '手机号', + userEmail: '邮箱', + userStatus: '用户状态', + userRole: '用户角色', form: { userName: '请输入用户名', userGender: '请选择性别', @@ -283,22 +296,64 @@ const local: App.I18n.Schema = { userStatus: '请选择用户状态', userRole: '请选择用户角色' }, - userName: '用户名', - userGender: '性别', - nickName: '昵称', - userPhone: '手机号', - userEmail: '邮箱', - userStatus: '用户状态', - userRole: '用户角色', addUser: '新增用户', editUser: '编辑用户', gender: { male: '男', female: '女' + } + }, + menu: { + title: '菜单列表', + menuType: '菜单类型', + menuName: '菜单名称', + routeName: '路由名称', + routePath: '路由路径', + page: '页面组件', + layout: '布局', + i18nKey: '国际化key', + icon: '图标', + localIcon: '本地图标', + order: '排序', + keepAlive: '缓存路由', + href: '外链', + hideInMenu: '隐藏菜单', + activeMenu: '高亮的菜单', + multiTab: '支持多页签', + fixedIndexInTab: '固定在页签中的序号', + button: '按钮', + buttonCode: '按钮编码', + buttonDesc: '按钮描述', + menuStatus: '菜单状态', + form: { + menuType: '请选择菜单类型', + menuName: '请输入菜单名称', + routeName: '请输入路由名称', + routePath: '请输入路由路径', + page: '请选择页面组件', + layout: '请选择布局组件', + i18nKey: '请输入国际化key', + icon: '请输入图标', + localIcon: '请选择本地图标', + order: '请输入排序', + keepAlive: '请选择是否缓存路由', + href: '请输入外链', + hideInMenu: '请选择是否隐藏菜单', + activeMenu: '请输入高亮的菜单的路由名称', + multiTab: '请选择是否支持多标签', + fixedInTab: '请选择是否固定在页签中', + fixedIndexInTab: '请输入固定在页签中的序号', + button: '请选择是否按钮', + buttonCode: '请输入按钮编码', + buttonDesc: '请输入按钮描述', + menuStatus: '请选择菜单状态' }, - status: { - enable: '启用', - disable: '禁用' + addMenu: '新增菜单', + editMenu: '编辑菜单', + addChildMenu: '新增子菜单', + type: { + directory: '目录', + menu: '菜单' } } } diff --git a/src/service/api/system-manage.ts b/src/service/api/system-manage.ts index 50fa32435..8a75bf391 100644 --- a/src/service/api/system-manage.ts +++ b/src/service/api/system-manage.ts @@ -29,3 +29,11 @@ export function fetchGetUserList(params?: Api.SystemManage.UserSearchParams) { params }); } + +/** get menu list */ +export function fetchGetMenuList() { + return request({ + url: '/systemManage/getMenuList', + method: 'get' + }); +} diff --git a/src/typings/api.d.ts b/src/typings/api.d.ts index 9e6c8c7a5..492f477e4 100644 --- a/src/typings/api.d.ts +++ b/src/typings/api.d.ts @@ -20,6 +20,14 @@ declare namespace Api { records: T[]; } + /** + * enable status + * + * - "1": enabled + * - "2": disabled + */ + type EnableStatus = '1' | '2'; + /** common record */ type CommonRecord> = { /** record id */ @@ -32,6 +40,8 @@ declare namespace Api { updateBy: string; /** record update time */ updateTime: string; + /** record status */ + status: EnableStatus | null; } & T; } @@ -79,14 +89,6 @@ declare namespace Api { namespace SystemManage { type CommonSearchParams = Pick; - /** - * role status - * - * - "1": enabled - * - "2": disabled - */ - type RoleStatus = '1' | '2'; - /** role */ type Role = Common.CommonRecord<{ /** role name */ @@ -95,13 +97,11 @@ declare namespace Api { roleCode: string; /** role description */ roleDesc: string; - /** role status */ - roleStatus: RoleStatus | null; }>; /** role search params */ type RoleSearchParams = CommonType.RecordNullable< - Pick & CommonSearchParams + Pick & CommonSearchParams >; /** role list */ @@ -118,14 +118,6 @@ declare namespace Api { */ type UserGender = '1' | '2'; - /** - * user status - * - * - "1": enabled - * - "2": disabled - */ - type UserStatus = '1' | '2'; - /** user */ type User = Common.CommonRecord<{ /** user name */ @@ -140,17 +132,90 @@ declare namespace Api { userEmail: string; /** user role code collection */ userRoles: string[]; - /** user status */ - userStatus: UserStatus | null; }>; /** user search params */ type UserSearchParams = CommonType.RecordNullable< - Pick & + Pick & CommonSearchParams >; /** user list */ type UserList = Common.PaginatingQueryRecord; + + /** + * menu type + * + * - "1": directory + * - "2": menu + */ + type MenuType = '1' | '2'; + + type MenuButton = { + /** + * button code + * + * it can be used to control the button permission + */ + code: string; + /** button description */ + desc: string; + }; + + /** + * icon type + * + * - "1": iconify icon + * - "2": local icon + */ + type IconType = '1' | '2'; + + type Menu = Common.CommonRecord<{ + /** menu type */ + menuType: MenuType; + /** menu name */ + menuName: string; + /** route name */ + routeName: string; + /** route path */ + routePath: string; + /** component */ + component?: string; + /** + * i18n key + * + * it is for internationalization + */ + i18nKey?: App.I18n.I18nKey; + /** iconify icon name or local icon name */ + icon: string; + /** icon type */ + iconType: IconType; + /** menu order */ + order: number; + /** whether to cache the route */ + keepAlive?: boolean; + /** outer link */ + href?: string; + /** whether to hide the route in the menu */ + hideInMenu?: boolean; + /** + * The menu key will be activated when entering the route + * + * The route is not in the menu + * + * @example + * the route is "user_detail", if it is set to "user_list", the menu "user_list" will be activated + */ + activeMenu?: import('@elegant-router/types').LastLevelRouteKey; + /** By default, the same route path will use one tab, if set to true, it will use multiple tabs */ + multiTab?: boolean; + /** If set, the route will be fixed in tabs, and the value is the order of fixed tabs */ + fixedIndexInTab?: number; + /** menu buttons */ + buttons?: MenuButton[]; + /** children menu */ + children?: Menu[]; + }>; } } diff --git a/src/typings/app.d.ts b/src/typings/app.d.ts index 95bc1516e..ea1249d7b 100644 --- a/src/typings/app.d.ts +++ b/src/typings/app.d.ts @@ -277,6 +277,10 @@ declare namespace App { update: string; updateSuccess: string; userCenter: string; + yesOrNo: { + yes: string; + no: string; + }; }; theme: { themeSchema: { title: string } & Record; @@ -440,27 +444,36 @@ declare namespace App { }; }; manage: { + common: { + status: { + enable: string; + disable: string; + }; + }; role: { title: string; + roleName: string; + roleCode: string; + roleStatus: string; + roleDesc: string; form: { roleName: string; roleCode: string; roleStatus: string; roleDesc: string; }; - roleName: string; - roleCode: string; - roleStatus: string; - roleDesc: string; addRole: string; editRole: string; - status: { - enable: string; - disable: string; - }; }; user: { title: string; + userName: string; + userGender: string; + nickName: string; + userPhone: string; + userEmail: string; + userStatus: string; + userRole: string; form: { userName: string; userGender: string; @@ -470,22 +483,64 @@ declare namespace App { userStatus: string; userRole: string; }; - userName: string; - userGender: string; - nickName: string; - userPhone: string; - userEmail: string; - userStatus: string; - userRole: string; addUser: string; editUser: string; gender: { male: string; female: string; }; - status: { - enable: string; - disable: string; + }; + menu: { + title: string; + menuType: string; + menuName: string; + routeName: string; + routePath: string; + page: string; + layout: string; + i18nKey: string; + icon: string; + localIcon: string; + order: string; + keepAlive: string; + href: string; + hideInMenu: string; + activeMenu: string; + multiTab: string; + fixedIndexInTab: string; + button: string; + buttonCode: string; + buttonDesc: string; + menuStatus: string; + form: { + menuType: string; + menuName: string; + routeName: string; + routePath: string; + page: string; + layout: string; + i18nKey: string; + icon: string; + localIcon: string; + order: string; + keepAlive: string; + href: string; + hideInMenu: string; + activeMenu: string; + multiTab: string; + fixedInTab: string; + fixedIndexInTab: string; + button: string; + buttonCode: string; + buttonDesc: string; + menuStatus: string; + }; + addMenu: string; + editMenu: string; + addChildMenu: string; + type: { + directory: string; + menu: string; }; }; }; diff --git a/src/views/manage/menu/index.vue b/src/views/manage/menu/index.vue index 5db0cc3eb..14ad45df9 100644 --- a/src/views/manage/menu/index.vue +++ b/src/views/manage/menu/index.vue @@ -1,7 +1,258 @@ - + diff --git a/src/views/manage/menu/modules/menu-operate-drawer.vue b/src/views/manage/menu/modules/menu-operate-drawer.vue new file mode 100644 index 000000000..9eeb5fe85 --- /dev/null +++ b/src/views/manage/menu/modules/menu-operate-drawer.vue @@ -0,0 +1,113 @@ + + + + + diff --git a/src/views/manage/role/index.vue b/src/views/manage/role/index.vue index da66e6a8a..316d3e6f6 100644 --- a/src/views/manage/role/index.vue +++ b/src/views/manage/role/index.vue @@ -6,7 +6,7 @@ import { fetchGetRoleList } from '@/service/api'; import { useAppStore } from '@/store/modules/app'; import { useTable } from '@/hooks/common/table'; import { $t } from '@/locales'; -import { roleStatusRecord } from '@/constants/business'; +import { enableStatusRecord } from '@/constants/business'; import RoleOperateDrawer, { type OperateType } from './modules/role-operate-drawer.vue'; import RoleSearch from './modules/role-search.vue'; @@ -24,9 +24,9 @@ const { columns, filteredColumns, data, loading, pagination, getData, searchPara size: 10, // if you want to use the searchParams in Form, you need to define the following properties, and the value is null // the value can not be undefined, otherwise the property in Form will not be reactive + status: null, roleName: null, - roleCode: null, - roleStatus: null + roleCode: null }, transformer: res => { const { records = [], current = 1, size = 10, total = 0 } = res.data || {}; @@ -69,23 +69,23 @@ const { columns, filteredColumns, data, loading, pagination, getData, searchPara minWidth: 120 }, { - key: 'roleStatus', + key: 'status', title: $t('page.manage.role.roleStatus'), align: 'center', width: 100, render: row => { - if (row.roleStatus === null) { + if (row.status === null) { return null; } - const tagMap: Record = { + const tagMap: Record = { 1: 'success', 2: 'warning' }; - const label = $t(roleStatusRecord[row.roleStatus]); + const label = $t(enableStatusRecord[row.status]); - return {label}; + return {label}; } }, { diff --git a/src/views/manage/role/modules/role-operate-drawer.vue b/src/views/manage/role/modules/role-operate-drawer.vue index a12594713..a2b00ad97 100644 --- a/src/views/manage/role/modules/role-operate-drawer.vue +++ b/src/views/manage/role/modules/role-operate-drawer.vue @@ -2,7 +2,7 @@ import { computed, reactive, watch } from 'vue'; import { useFormRules, useNaiveForm } from '@/hooks/common/form'; import { $t } from '@/locales'; -import { roleStatusOptions } from '@/constants/business'; +import { enableStatusOptions } from '@/constants/business'; defineOptions({ name: 'RoleOperateDrawer' @@ -46,7 +46,7 @@ const title = computed(() => { return titles[props.operateType]; }); -type Model = Pick; +type Model = Pick; const model: Model = reactive(createDefaultModel()); @@ -55,7 +55,7 @@ function createDefaultModel(): Model { roleName: '', roleCode: '', roleDesc: '', - roleStatus: null + status: null }; } @@ -64,7 +64,7 @@ type RuleKey = Exclude; const rules: Record = { roleName: defaultRequiredRule, roleCode: defaultRequiredRule, - roleStatus: defaultRequiredRule + status: defaultRequiredRule }; function handleUpdateModelWhenEdit() { @@ -108,9 +108,9 @@ watch(visible, () => { - - - + + + diff --git a/src/views/manage/role/modules/role-search.vue b/src/views/manage/role/modules/role-search.vue index e173b24de..cf6233212 100644 --- a/src/views/manage/role/modules/role-search.vue +++ b/src/views/manage/role/modules/role-search.vue @@ -1,6 +1,6 @@