diff --git a/frontend/src/api/modules/setting/user.ts b/frontend/src/api/modules/setting/user.ts index b969e26296..afb5037e87 100644 --- a/frontend/src/api/modules/setting/user.ts +++ b/frontend/src/api/modules/setting/user.ts @@ -20,6 +20,7 @@ import type { SystemRole, ImportResult, BatchAddUserGroupParams, + ResetUserPasswordParams, } from '@/models/setting/user'; import type { CommonList, TableQueryParams } from '@/models/common'; @@ -55,12 +56,12 @@ export function importUserInfo(data: ImportUserParams) { // 获取系统用户组 export function getSystemRoles() { - return MSR.get({ url: GetSystemRoleUrl }); + return MSR.get({ url: GetSystemRoleUrl }); } // 重置用户密码 -export function resetUserPassword(userIds: string[]) { - return MSR.post({ url: ResetPasswordUrl, data: userIds }); +export function resetUserPassword(data: ResetUserPasswordParams) { + return MSR.post({ url: ResetPasswordUrl, data }); } // 批量添加用户到多个用户组 diff --git a/frontend/src/api/requrls/setting/user.ts b/frontend/src/api/requrls/setting/user.ts index dfecba0c63..8eebb37402 100644 --- a/frontend/src/api/requrls/setting/user.ts +++ b/frontend/src/api/requrls/setting/user.ts @@ -15,4 +15,4 @@ export const GetSystemRoleUrl = '/system/user/get/global/system/role'; // 重置用户密码 export const ResetPasswordUrl = '/system/user/reset/password'; // 批量添加用户到多个用户组 -export const BatchAddUserGroupUrl = '/user/role/relation/global/add/batch'; +export const BatchAddUserGroupUrl = '/system/user/add/batch/user-role'; diff --git a/frontend/src/components/pure/ms-button/index.vue b/frontend/src/components/pure/ms-button/index.vue index e90fd3ea7a..230f1cb802 100644 --- a/frontend/src/components/pure/ms-button/index.vue +++ b/frontend/src/components/pure/ms-button/index.vue @@ -23,7 +23,7 @@ diff --git a/frontend/src/components/pure/ms-tags-input/locale/en-US.ts b/frontend/src/components/pure/ms-tags-input/locale/en-US.ts new file mode 100644 index 0000000000..d89331d68e --- /dev/null +++ b/frontend/src/components/pure/ms-tags-input/locale/en-US.ts @@ -0,0 +1,3 @@ +export default { + 'ms.tagsInput.tagsDuplicateText': 'Same label already exists', +}; diff --git a/frontend/src/components/pure/ms-tags-input/locale/zh-CN.ts b/frontend/src/components/pure/ms-tags-input/locale/zh-CN.ts new file mode 100644 index 0000000000..f35d390eb6 --- /dev/null +++ b/frontend/src/components/pure/ms-tags-input/locale/zh-CN.ts @@ -0,0 +1,3 @@ +export default { + 'ms.tagsInput.tagsDuplicateText': '已存在相同的标签', +}; diff --git a/frontend/src/config/pathMap.ts b/frontend/src/config/pathMap.ts index be793aa442..1a11788aca 100644 --- a/frontend/src/config/pathMap.ts +++ b/frontend/src/config/pathMap.ts @@ -1,5 +1,4 @@ import { RouteEnum } from '@/enums/routeEnum'; -import { TreeNode, mapTree } from '@/utils'; export const MENU_LEVEL = ['SYSTEM', 'ORGANIZATION', 'PROJECT'] as const; // 菜单级别 @@ -8,8 +7,9 @@ export const MENU_LEVEL = ['SYSTEM', 'ORGANIZATION', 'PROJECT'] as const; // 菜 * key 是与后台商定的映射 key * locale 是国际化的 key * route 是路由的 name + * routeQuery 是路由的固定参数集合,与routeParamKeys互斥,用于跳转同一个路由但不同 tab 时或其他需要固定参数的情况 * permission 是权限的 key 集合 - * level 是菜单级别 + * level 是菜单级别,用于筛选不同级别的路由/tab * children 是子路由/tab集合 */ export const pathMap = [ @@ -28,9 +28,9 @@ export const pathMap = [ level: MENU_LEVEL[0], children: [ { - key: 'SETTING_SYSTEM_USER', // 系统设置-系统-用户 + key: 'SETTING_SYSTEM_USER_SINGLE', // 系统设置-系统-用户 locale: 'menu.settings.system.user', - route: RouteEnum.SETTING_SYSTEM_USER, + route: RouteEnum.SETTING_SYSTEM_USER_SINGLE, permission: [], level: MENU_LEVEL[0], }, @@ -56,21 +56,30 @@ export const pathMap = [ level: MENU_LEVEL[0], children: [ { - key: 'SETTING_SYSTEM_PARAMETER', // 系统设置-系统-系统参数-基础设置 + key: 'SETTING_SYSTEM_PARAMETER_BASE_CONFIG', // 系统设置-系统-系统参数-基础设置 locale: 'system.config.baseConfig', route: RouteEnum.SETTING_SYSTEM_PARAMETER, + permission: [], level: MENU_LEVEL[0], }, { key: 'SETTING_SYSTEM_PARAMETER_PAGE_CONFIG', // 系统设置-系统-系统参数-界面设置 locale: 'system.config.pageConfig', route: RouteEnum.SETTING_SYSTEM_PARAMETER, + permission: [], + routeQuery: { + tab: 'pageConfig', + }, level: MENU_LEVEL[0], }, { key: 'SETTING_SYSTEM_PARAMETER_AUTH_CONFIG', // 系统设置-系统-系统参数-认证设置 locale: 'system.config.authConfig', route: RouteEnum.SETTING_SYSTEM_PARAMETER, + permission: [], + routeQuery: { + tab: 'authConfig', + }, level: MENU_LEVEL[0], }, ], @@ -136,40 +145,6 @@ export const pathMap = [ route: RouteEnum.PROJECT_MANAGEMENT, permission: [], level: MENU_LEVEL[2], - children: [ - { - key: 'PROJECT_MANAGEMENT_LOG', // 项目管理-日志 - locale: 'menu.projectManagement.log', - route: RouteEnum.PROJECT_MANAGEMENT_LOG, - permission: [], - level: MENU_LEVEL[2], - }, - ], + children: [], }, ]; - -/** - * 根据菜单级别过滤映射树 - * @param level 菜单级别 - * @param customNodeFn 自定义过滤函数 - * @returns 过滤后的映射树 - */ -export const getPathMapByLevel = ( - level: (typeof MENU_LEVEL)[number], - customNodeFn: (node: TreeNode) => TreeNode | null = (node) => node -) => { - return mapTree(pathMap, (e) => { - let isValid = true; // 默认是系统级别 - if (level === MENU_LEVEL[1]) { - // 组织级别只展示组织、项目 - isValid = e.level !== MENU_LEVEL[0]; - } else if (level === MENU_LEVEL[2]) { - // 项目级别只展示项目 - isValid = e.level !== MENU_LEVEL[0] && e.level !== MENU_LEVEL[1]; - } - if (isValid) { - return typeof customNodeFn === 'function' ? customNodeFn(e) : e; - } - return null; - }); -}; diff --git a/frontend/src/enums/routeEnum.ts b/frontend/src/enums/routeEnum.ts index 14d82e716f..8cfbe2314b 100644 --- a/frontend/src/enums/routeEnum.ts +++ b/frontend/src/enums/routeEnum.ts @@ -35,7 +35,7 @@ export enum WorkbenchRouteEnum { export enum SettingRouteEnum { SETTING = 'setting', SETTING_SYSTEM = 'settingSystem', - SETTING_SYSTEM_USER = 'settingSystemUser', + SETTING_SYSTEM_USER_SINGLE = 'settingSystemUser', SETTING_SYSTEM_USER_GROUP = 'settingSystemUserGroup', SETTING_SYSTEM_ORGANIZATION = 'settingSystemOrganization', SETTING_SYSTEM_PARAMETER = 'settingSystemParameter', diff --git a/frontend/src/hooks/usePathMap.ts b/frontend/src/hooks/usePathMap.ts new file mode 100644 index 0000000000..91eef06805 --- /dev/null +++ b/frontend/src/hooks/usePathMap.ts @@ -0,0 +1,55 @@ +import { useRouter } from 'vue-router'; +import { MENU_LEVEL, pathMap } from '@/config/pathMap'; +import { TreeNode, findNodeByKey, mapTree } from '@/utils'; +import { RouteEnum } from '@/enums/routeEnum'; + +export default function usePathMap() { + const router = useRouter(); + /** + * 根据菜单级别过滤映射树 + * @param level 菜单级别 + * @param customNodeFn 自定义过滤函数 + * @returns 过滤后的映射树 + */ + const getPathMapByLevel = ( + level: (typeof MENU_LEVEL)[number], + customNodeFn: (node: TreeNode) => TreeNode | null = (node) => node + ) => { + return mapTree(pathMap, (e) => { + let isValid = true; // 默认是系统级别 + if (level === MENU_LEVEL[1]) { + // 组织级别只展示组织、项目 + isValid = e.level !== MENU_LEVEL[0]; + } else if (level === MENU_LEVEL[2]) { + // 项目级别只展示项目 + isValid = e.level !== MENU_LEVEL[0] && e.level !== MENU_LEVEL[1]; + } + if (isValid) { + return typeof customNodeFn === 'function' ? customNodeFn(e) : e; + } + return null; + }); + }; + + /** + * 根据路由的 key 进行路由跳转,自动携带配置的 routeQuery 和 传入的routeQuery + * @param key + */ + const jumpRouteByMapKey = (key: typeof RouteEnum, routeQuery?: Record) => { + const pathNode = findNodeByKey(pathMap, key as unknown as string); + if (pathNode) { + router.push({ + name: pathNode?.route, + query: { + ...routeQuery, + ...pathNode?.routeQuery, + }, + }); + } + }; + + return { + getPathMapByLevel, + jumpRouteByMapKey, + }; +} diff --git a/frontend/src/models/common.ts b/frontend/src/models/common.ts index d24c9638a3..bbef7c2a5b 100644 --- a/frontend/src/models/common.ts +++ b/frontend/src/models/common.ts @@ -29,3 +29,10 @@ export interface CommonList { current: number; list: T[]; } + +export interface BatchApiParams { + selectIds: string[]; // 已选 ID 集合,当 selectAll 为 false 时接口会使用该字段 + excludeIds?: string[]; // 需要忽略的用户 id 集合,当selectAll为 true 时接口会使用该字段 + selectAll: boolean; // 是否跨页全选,即选择当前筛选条件下的全部表格数据 + condition: Record; // 当前表格查询的筛选条件 +} diff --git a/frontend/src/models/setting/log.ts b/frontend/src/models/setting/log.ts index 0b575692ac..e518a5c224 100644 --- a/frontend/src/models/setting/log.ts +++ b/frontend/src/models/setting/log.ts @@ -1,3 +1,5 @@ +import type { RouteEnum } from '@/enums/routeEnum'; + export interface OptionsItem { id: string; name: string; @@ -16,7 +18,7 @@ export interface LogItem { projectName: string; organizationId: string; organizationName: string; - module: string; // 操作对象 + module: typeof RouteEnum; // 操作对象 type: string; // 操作类型 content: string; // 操作名称 createTime: number; diff --git a/frontend/src/models/setting/user.ts b/frontend/src/models/setting/user.ts index 2dbff6266e..2564de5fd4 100644 --- a/frontend/src/models/setting/user.ts +++ b/frontend/src/models/setting/user.ts @@ -1,3 +1,5 @@ +import type { BatchApiParams } from '@/models/common'; + // 用户所属用户组模型 export interface UserRoleListItem { id: string; @@ -71,8 +73,7 @@ export interface CreateUserParams { userInfoList: SimpleUserInfo[]; userRoleIdList: string[]; } -export interface UpdateUserStatusParams { - userIdList: string[]; +export interface UpdateUserStatusParams extends BatchApiParams { enable: boolean; } @@ -80,9 +81,8 @@ export interface ImportUserParams { fileList: (File | undefined)[]; } -export interface DeleteUserParams { - userIdList: string[]; -} +export type DeleteUserParams = BatchApiParams; +export type ResetUserPasswordParams = BatchApiParams; export interface SystemRole { id: string; @@ -97,7 +97,6 @@ export interface ImportResult { errorMessages: Record; } -export interface BatchAddUserGroupParams { - userIds: string[]; // 用户 id 集合 +export interface BatchAddUserGroupParams extends BatchApiParams { roleIds: string[]; // 用户组 id 集合 } diff --git a/frontend/src/router/routes/modules/setting.ts b/frontend/src/router/routes/modules/setting.ts index 6c741c237a..42295fa369 100644 --- a/frontend/src/router/routes/modules/setting.ts +++ b/frontend/src/router/routes/modules/setting.ts @@ -26,7 +26,7 @@ const Setting: AppRouteRecordRaw = { children: [ { path: 'user', - name: SettingRouteEnum.SETTING_SYSTEM_USER, + name: SettingRouteEnum.SETTING_SYSTEM_USER_SINGLE, component: () => import('@/views/setting/system/user/index.vue'), meta: { locale: 'menu.settings.system.user', diff --git a/frontend/src/utils/index.ts b/frontend/src/utils/index.ts index ca220b10db..8608823652 100644 --- a/frontend/src/utils/index.ts +++ b/frontend/src/utils/index.ts @@ -206,3 +206,28 @@ export function mapTree( }) .filter(Boolean); } + +/** + * 根据属性 key 查找树形数组中匹配的某个节点 + * @param trees 属性数组 + * @param targetKey 需要匹配的属性值 + * @param customKey 默认为 key,可自定义需要匹配的属性名 + * @returns 匹配的节点/null + */ +export function findNodeByKey(trees: TreeNode[], targetKey: string, customKey = 'key'): TreeNode | null { + for (let i = 0; i < trees.length; i++) { + const node = trees[i]; + if (node[customKey] === targetKey) { + return node; // 如果当前节点的 key 与目标 key 匹配,则返回当前节点 + } + + if (Array.isArray(node.children) && node.children.length > 0) { + const _node = findNodeByKey(node.children, targetKey); // 递归在子节点中查找 + if (_node) { + return _node; // 如果在子节点中找到了匹配的节点,则返回该节点 + } + } + } + + return null; // 如果在整个树形数组中都没有找到匹配的节点,则返回 null +} diff --git a/frontend/src/views/setting/system/config/components/authConfig.vue b/frontend/src/views/setting/system/config/components/authConfig.vue index b5a88e29c8..eecff0662c 100644 --- a/frontend/src/views/setting/system/config/components/authConfig.vue +++ b/frontend/src/views/setting/system/config/components/authConfig.vue @@ -8,7 +8,7 @@