diff --git a/packages/base/src/locale/en-US/dmsUserCenter.ts b/packages/base/src/locale/en-US/dmsUserCenter.ts
index 87c969a9a1..aea92c56c6 100644
--- a/packages/base/src/locale/en-US/dmsUserCenter.ts
+++ b/packages/base/src/locale/en-US/dmsUserCenter.ts
@@ -28,7 +28,10 @@ export default {
opPermissions: 'Platform management permissions',
isDisabled: 'Disabled',
disabledTips:
- 'When the user is disabled, the user will not be able to log in'
+ 'When the user is disabled, the user will not be able to log in',
+ globalManagementLockedTips:
+ 'Only the built-in admin can grant or revoke the System Administrator permission',
+ manageTargetForbidden: 'You are not allowed to manage this user'
},
createUser: {
createSuccessTips: 'Add user "{{name}}" successfully'
diff --git a/packages/base/src/locale/zh-CN/dmsUserCenter.ts b/packages/base/src/locale/zh-CN/dmsUserCenter.ts
index 8c0d4a4473..dcc92ed288 100644
--- a/packages/base/src/locale/zh-CN/dmsUserCenter.ts
+++ b/packages/base/src/locale/zh-CN/dmsUserCenter.ts
@@ -25,7 +25,9 @@ export default {
userGroups: '所属用户组',
opPermissions: '平台管理权限',
isDisabled: '是否禁用',
- disabledTips: '当用户被禁用,该用户将无法登录'
+ disabledTips: '当用户被禁用,该用户将无法登录',
+ globalManagementLockedTips: '仅内置管理员可授予或收回「系统管理员」权限',
+ manageTargetForbidden: '无权管理该用户'
},
createUser: {
createSuccessTips: '添加用户 "{{name}}" 成功'
diff --git a/packages/base/src/page/Nav/SideMenu/UserMenu/Modal/VersionModal/test/__snapshots__/BasicVersionModal.test.tsx.snap b/packages/base/src/page/Nav/SideMenu/UserMenu/Modal/VersionModal/test/__snapshots__/BasicVersionModal.test.tsx.snap
index 8e6e5a31e5..3168ec2d4c 100644
--- a/packages/base/src/page/Nav/SideMenu/UserMenu/Modal/VersionModal/test/__snapshots__/BasicVersionModal.test.tsx.snap
+++ b/packages/base/src/page/Nav/SideMenu/UserMenu/Modal/VersionModal/test/__snapshots__/BasicVersionModal.test.tsx.snap
@@ -110,7 +110,7 @@ exports[`base/Nav/SideMenu/UserMenu/BasicVersionModal render snap when open is t
class="ant-typography css-dev-only-do-not-override-txh9fw"
>
UI:
- dev-zjrc-sql-audit-report-summary f4fab7b02
+ dev-zjrc-user-system-admin f4fab7b02
UI:
- dev-zjrc-sql-audit-report-summary f4fab7b02
+ dev-zjrc-user-system-admin f4fab7b02
UI:
- dev-zjrc-sql-audit-report-summary f4fab7b02
+ dev-zjrc-user-system-admin f4fab7b02
UI:
- dev-zjrc-sql-audit-report-summary f4fab7b02
+ dev-zjrc-user-system-admin f4fab7b02
UI:
- dev-zjrc-sql-audit-report-summary f4fab7b02
+ dev-zjrc-user-system-admin f4fab7b02
UI:
- dev-zjrc-sql-audit-report-summary f4fab7b02
+ dev-zjrc-user-system-admin f4fab7b02
{
return {
@@ -23,6 +24,7 @@ describe('base/UserCenter/Modal/AddUser', () => {
let addUserSpy: jest.SpyInstance;
beforeEach(() => {
jest.useFakeTimers();
+ mockUseCurrentUser({ username: 'admin', uid: '700200' });
addUserSpy = userCenter.addUser();
opPermissionListSpy = userCenter.getOpPermissionsList();
diff --git a/packages/base/src/page/UserCenter/Modal/User/AddUser/index.tsx b/packages/base/src/page/UserCenter/Modal/User/AddUser/index.tsx
index 6986d20adc..66aefe7549 100644
--- a/packages/base/src/page/UserCenter/Modal/User/AddUser/index.tsx
+++ b/packages/base/src/page/UserCenter/Modal/User/AddUser/index.tsx
@@ -1,4 +1,4 @@
-import { useCallback } from 'react';
+import { useCallback, useMemo } from 'react';
import { useBoolean } from 'ahooks';
import { Form, message, Space } from 'antd';
import { useTranslation } from 'react-i18next';
@@ -6,13 +6,15 @@ import { useDispatch, useSelector } from 'react-redux';
import { ModalName } from '../../../../../data/ModalName';
import { IReduxState } from '../../../../../store';
import { updateUserManageModalStatus } from '../../../../../store/userCenter';
-import { ResponseCode } from '@actiontech/shared/lib/enum';
+import { OpPermissionTypeUid, ResponseCode } from '@actiontech/shared/lib/enum';
import EmitterKey from '../../../../../data/EmitterKey';
import UserForm from '../UserForm';
import { IUserFormFields } from '../UserForm/index.type';
import EventEmitter from '../../../../../utils/EventEmitter';
import { BasicDrawer, BasicButton } from '@actiontech/shared';
import User from '@actiontech/shared/lib/api/base/service/User';
+import { useCurrentUser } from '@actiontech/shared/lib/global';
+import { canEditGlobalManagement } from '../../../utils/systemAdminBoundary';
const AddUser = () => {
const [form] = Form.useForm
();
@@ -27,6 +29,12 @@ const AddUser = () => {
(state) => !!state.userCenter.modalStatus[ModalName.DMS_Add_User]
);
+ const { username, uid } = useCurrentUser();
+ const allowEditGlobalManagement = useMemo(
+ () => canEditGlobalManagement({ name: username, uid }),
+ [username, uid]
+ );
+
const [messageApi, contextHolder] = message.useMessage();
const onClose = useCallback(() => {
@@ -41,6 +49,16 @@ const AddUser = () => {
const addUser = useCallback(async () => {
const values = await form.validateFields();
+ const opPermissionUids = values.opPermissionUids ?? [];
+ if (
+ !allowEditGlobalManagement &&
+ opPermissionUids.includes(OpPermissionTypeUid.global_management)
+ ) {
+ messageApi.error(
+ t('dmsUserCenter.user.userForm.globalManagementLockedTips')
+ );
+ return;
+ }
setTrue();
User.AddUser({
user: {
@@ -49,7 +67,7 @@ const AddUser = () => {
email: values.email ?? '',
phone: values.phone ?? '',
wxid: values.wxid ?? '',
- op_permission_uids: values.opPermissionUids ?? []
+ op_permission_uids: opPermissionUids
}
})
.then((res) => {
@@ -66,7 +84,15 @@ const AddUser = () => {
.finally(() => {
setFalse();
});
- }, [onClose, form, setFalse, setTrue, t, messageApi]);
+ }, [
+ allowEditGlobalManagement,
+ onClose,
+ form,
+ setFalse,
+ setTrue,
+ t,
+ messageApi
+ ]);
return (
{
}
>
{contextHolder}
-
+
);
};
diff --git a/packages/base/src/page/UserCenter/Modal/User/UpdateUser/index.test.tsx b/packages/base/src/page/UserCenter/Modal/User/UpdateUser/index.test.tsx
index d62df9904c..97652d196a 100644
--- a/packages/base/src/page/UserCenter/Modal/User/UpdateUser/index.test.tsx
+++ b/packages/base/src/page/UserCenter/Modal/User/UpdateUser/index.test.tsx
@@ -8,6 +8,7 @@ import { useDispatch, useSelector } from 'react-redux';
import { ModalName } from '../../../../../data/ModalName';
import EmitterKey from '../../../../../data/EmitterKey';
import { queryBySelector } from '@actiontech/shared/lib/testUtil/customQuery';
+import { mockUseCurrentUser } from '@actiontech/shared/lib/testUtil/mockHook/mockUseCurrentUser';
jest.mock('react-redux', () => ({
...jest.requireActual('react-redux'),
@@ -22,6 +23,8 @@ describe('base/UserCenter/Modal/UpdateUser', () => {
const mockUserData = userList[0];
beforeEach(() => {
jest.useFakeTimers();
+ // UpdateUser 经 useCurrentUser 读当前操作者;需内置 admin 才能编辑系统管理员边界
+ mockUseCurrentUser({ username: 'admin', uid: '700200' });
updateUserSpy = userCenter.updateUser();
opPermissionListSpy = userCenter.getOpPermissionsList();
diff --git a/packages/base/src/page/UserCenter/Modal/User/UpdateUser/index.tsx b/packages/base/src/page/UserCenter/Modal/User/UpdateUser/index.tsx
index 447c09796d..a38976c5c9 100644
--- a/packages/base/src/page/UserCenter/Modal/User/UpdateUser/index.tsx
+++ b/packages/base/src/page/UserCenter/Modal/User/UpdateUser/index.tsx
@@ -1,4 +1,4 @@
-import { useEffect, useCallback } from 'react';
+import { useEffect, useCallback, useMemo } from 'react';
import { Form, message, Space } from 'antd';
import { useTranslation } from 'react-i18next';
import { useDispatch, useSelector } from 'react-redux';
@@ -9,7 +9,7 @@ import UserForm from '../UserForm';
import { IUserFormFields } from '../UserForm/index.type';
import { ModalName } from '../../../../../data/ModalName';
import { updateUserManageModalStatus } from '../../../../../store/userCenter';
-import { ResponseCode } from '@actiontech/shared/lib/enum';
+import { OpPermissionTypeUid, ResponseCode } from '@actiontech/shared/lib/enum';
import EventEmitter from '../../../../../utils/EventEmitter';
import {
IListUser,
@@ -19,6 +19,11 @@ import User from '@actiontech/shared/lib/api/base/service/User';
import { ListUserStatEnum } from '@actiontech/shared/lib/api/base/service/common.enum';
import { BasicDrawer, BasicButton } from '@actiontech/shared';
import { SystemRole } from '@actiontech/shared/lib/enum';
+import { useCurrentUser } from '@actiontech/shared/lib/global';
+import {
+ canEditGlobalManagement,
+ canManageTarget
+} from '../../../utils/systemAdminBoundary';
const UpdateUser = () => {
const [form] = Form.useForm();
@@ -37,6 +42,16 @@ const UpdateUser = () => {
(state) => state.userCenter.selectUser
);
+ const { username, uid } = useCurrentUser();
+ const currentOperator = useMemo(
+ () => ({ name: username, uid }),
+ [username, uid]
+ );
+ const allowEditGlobalManagement = useMemo(
+ () => canEditGlobalManagement(currentOperator),
+ [currentOperator]
+ );
+
const [messageApi, contextHolder] = message.useMessage();
const onClose = useCallback(() => {
@@ -52,12 +67,32 @@ const UpdateUser = () => {
const updateUser = async () => {
const values = await form.validateFields();
+ if (!canManageTarget(currentOperator, currentUser)) {
+ messageApi.error(t('dmsUserCenter.user.userForm.manageTargetForbidden'));
+ return;
+ }
+
+ const nextOpUids = values.opPermissionUids ?? [];
+ const prevHadGlobal =
+ currentUser?.op_permissions?.some(
+ (p) => p.uid === OpPermissionTypeUid.global_management
+ ) ?? false;
+ const nextHasGlobal = nextOpUids.includes(
+ OpPermissionTypeUid.global_management
+ );
+ if (!allowEditGlobalManagement && prevHadGlobal !== nextHasGlobal) {
+ messageApi.error(
+ t('dmsUserCenter.user.userForm.globalManagementLockedTips')
+ );
+ return;
+ }
+
const userParams: IUpdateUser = {
password: values.passwordConfirm,
email: values.email ?? '',
phone: values.phone ?? '',
wxid: values.wxid ?? '',
- op_permission_uids: values.opPermissionUids ?? [],
+ op_permission_uids: nextOpUids,
is_disabled: values.username !== 'admin' ? !!values.isDisabled : false
};
setTrue();
@@ -124,6 +159,7 @@ const UpdateUser = () => {
visible={visible}
isUpdate={true}
isAdmin={currentUser?.name === SystemRole.admin}
+ canEditGlobalManagement={allowEditGlobalManagement}
/>
);
diff --git a/packages/base/src/page/UserCenter/Modal/User/UserForm/index.tsx b/packages/base/src/page/UserCenter/Modal/User/UserForm/index.tsx
index 1e457aaf7a..d20ceeb290 100644
--- a/packages/base/src/page/UserCenter/Modal/User/UserForm/index.tsx
+++ b/packages/base/src/page/UserCenter/Modal/User/UserForm/index.tsx
@@ -1,7 +1,7 @@
import { IUserFormProps } from './index.type';
import { Form, Switch } from 'antd';
import { BasicInput, BasicSelect } from '@actiontech/shared';
-import React, { useEffect } from 'react';
+import React, { useEffect, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { Rule } from 'antd/es/form';
import { nameRule, phoneRule } from '@actiontech/shared/lib/utils/FormRule';
@@ -9,9 +9,11 @@ import EmptyBox from '@actiontech/shared/lib/components/EmptyBox';
import { BasicToolTips } from '@actiontech/shared';
import useOpPermission from '../../../../../hooks/useOpPermission';
import { ListOpPermissionsFilterByTargetEnum } from '@actiontech/shared/lib/api/base/service/OpPermission/index.enum';
+import { OpPermissionTypeUid } from '@actiontech/shared/lib/enum';
const UserForm: React.FC = (props) => {
const { t } = useTranslation();
+ const canEditGlobalManagement = props.canEditGlobalManagement !== false;
const {
loading: getOpPermissionListLoading,
@@ -19,6 +21,18 @@ const UserForm: React.FC = (props) => {
updateOpPermissionList
} = useOpPermission();
+ const permissionOptions = useMemo(() => {
+ if (canEditGlobalManagement) {
+ return opPermissionOptions;
+ }
+ return opPermissionOptions.map((opt) => {
+ if (opt.value === OpPermissionTypeUid.global_management) {
+ return { ...opt, disabled: true };
+ }
+ return opt;
+ });
+ }, [canEditGlobalManagement, opPermissionOptions]);
+
const userNameRules = (): Rule[] => {
const baseRules = [
{
@@ -164,7 +178,21 @@ const UserForm: React.FC = (props) => {
+ {t('dmsUserCenter.user.userForm.opPermissions')}
+
+ )
+ }
>
= (props) => {
placeholder={t('common.form.placeholder.select', {
name: t('dmsUserCenter.user.userForm.opPermissions')
})}
- options={opPermissionOptions}
+ options={permissionOptions}
optionFilterProp="label"
/>
diff --git a/packages/base/src/page/UserCenter/Modal/User/UserForm/index.type.ts b/packages/base/src/page/UserCenter/Modal/User/UserForm/index.type.ts
index 89b5b67a0a..d67c1a601f 100644
--- a/packages/base/src/page/UserCenter/Modal/User/UserForm/index.type.ts
+++ b/packages/base/src/page/UserCenter/Modal/User/UserForm/index.type.ts
@@ -16,5 +16,8 @@ export interface IUserFormProps {
form: FormInstance;
visible: boolean;
isUpdate?: boolean;
+ /** 目标用户是否为 admin(控制禁用开关展示;勿与「当前操作者是否内置」混淆) */
isAdmin?: boolean;
+ /** 当前操作者是否可授予/收回「系统管理员」;false 时锁定 700017 选项 */
+ canEditGlobalManagement?: boolean;
}
diff --git a/packages/base/src/page/UserCenter/__tests__/__snapshots__/index.test.tsx.snap b/packages/base/src/page/UserCenter/__tests__/__snapshots__/index.test.tsx.snap
index 05c7174356..5c5a3a6a3b 100644
--- a/packages/base/src/page/UserCenter/__tests__/__snapshots__/index.test.tsx.snap
+++ b/packages/base/src/page/UserCenter/__tests__/__snapshots__/index.test.tsx.snap
@@ -650,16 +650,7 @@ exports[`base/UserCenter should render user list when it first entered the user
-
-
- 管 理
-
-
-
+ />
@@ -1483,16 +1474,7 @@ exports[`base/UserCenter switch to operate permission list 1`] = `
-
-
- 管 理
-
-
-
+ />
@@ -2614,16 +2596,7 @@ exports[`base/UserCenter switch to role list 1`] = `
-
-
- 管 理
-
-
-
+ />
diff --git a/packages/base/src/page/UserCenter/components/UserList/List.tsx b/packages/base/src/page/UserCenter/components/UserList/List.tsx
index fde1364b72..0b2d43c873 100644
--- a/packages/base/src/page/UserCenter/components/UserList/List.tsx
+++ b/packages/base/src/page/UserCenter/components/UserList/List.tsx
@@ -13,6 +13,7 @@ import { ResponseCode } from '@actiontech/shared/lib/enum';
import { IListUser } from '@actiontech/shared/lib/api/base/service/common';
import { IListUsersParams } from '@actiontech/shared/lib/api/base/service/User/index.d';
import User from '@actiontech/shared/lib/api/base/service/User';
+import { useCurrentUser } from '@actiontech/shared/lib/global';
import { UserCenterListEnum } from '../../index.enum';
import {
updateSelectUser,
@@ -32,6 +33,8 @@ const UserList: React.FC<{ activePage: UserCenterListEnum }> = ({
const dispatch = useDispatch();
+ const { username, uid } = useCurrentUser();
+
const { requestErrorMessage, handleTableRequestError } =
useTableRequestError();
@@ -97,9 +100,14 @@ const UserList: React.FC<{ activePage: UserCenterListEnum }> = ({
[refresh, t, messageApi]
);
+ const currentOperator = useMemo(
+ () => ({ name: username, uid }),
+ [username, uid]
+ );
+
const actions = useMemo(() => {
- return UserListActions(onEditUser, onDeleteUser);
- }, [onEditUser, onDeleteUser]);
+ return UserListActions(onEditUser, onDeleteUser, currentOperator);
+ }, [onEditUser, onDeleteUser, currentOperator]);
useEffect(() => {
const { unsubscribe } = EventEmitter.subscribe(
diff --git a/packages/base/src/page/UserCenter/components/UserList/__tests__/UserList.test.tsx b/packages/base/src/page/UserCenter/components/UserList/__tests__/UserList.test.tsx
index 9ae1558a28..da2bda6be3 100644
--- a/packages/base/src/page/UserCenter/components/UserList/__tests__/UserList.test.tsx
+++ b/packages/base/src/page/UserCenter/components/UserList/__tests__/UserList.test.tsx
@@ -17,6 +17,7 @@ import { ModalName } from '../../../../../data/ModalName';
import EventEmitter from '../../../../../utils/EventEmitter';
import EmitterKey from '../../../../../data/EmitterKey';
import { UserCenterListEnum } from '../../../index.enum';
+import { mockUseCurrentUser } from '@actiontech/shared/lib/testUtil/mockHook/mockUseCurrentUser';
jest.mock('react-redux', () => {
return {
@@ -30,6 +31,8 @@ describe('base/UserCenter/UserList', () => {
const dispatchSpy = jest.fn();
beforeEach(() => {
jest.useFakeTimers();
+ // 内置 admin:可管理列表内含 admin 在内的全部用户行
+ mockUseCurrentUser({ username: 'admin', uid: '700200' });
userListSpy = userCenter.getUserList();
(useDispatch as jest.Mock).mockImplementation(() => dispatchSpy);
});
@@ -64,7 +67,8 @@ describe('base/UserCenter/UserList', () => {
expect(screen.getByText('test')).toBeInTheDocument();
expect(screen.getByText('test666')).toBeInTheDocument();
expect(screen.getAllByText('dms')).toHaveLength(3);
- expect(screen.getAllByText('删 除')).toHaveLength(2);
+ // 内置 admin 操作者:可管理/删除含 admin 在内的全部行(canManageTarget)
+ expect(screen.getAllByText('删 除')).toHaveLength(3);
expect(screen.getAllByText('管 理')).toHaveLength(3);
});
diff --git a/packages/base/src/page/UserCenter/components/UserList/__tests__/__snapshots__/UserList.test.tsx.snap b/packages/base/src/page/UserCenter/components/UserList/__tests__/__snapshots__/UserList.test.tsx.snap
index 95bb555b23..342fb2ce62 100644
--- a/packages/base/src/page/UserCenter/components/UserList/__tests__/__snapshots__/UserList.test.tsx.snap
+++ b/packages/base/src/page/UserCenter/components/UserList/__tests__/__snapshots__/UserList.test.tsx.snap
@@ -495,7 +495,16 @@ exports[`base/UserCenter/UserList render user table 1`] = `
+ >
+
+
+ 删 除
+
+
+
diff --git a/packages/base/src/page/UserCenter/components/UserList/column.tsx b/packages/base/src/page/UserCenter/components/UserList/column.tsx
index 9b6f3737bb..34578169ae 100644
--- a/packages/base/src/page/UserCenter/components/UserList/column.tsx
+++ b/packages/base/src/page/UserCenter/components/UserList/column.tsx
@@ -7,8 +7,11 @@ import { ListUserStatEnum } from '@actiontech/shared/lib/api/base/service/common
import { orderBy } from 'lodash';
import { t } from '../../../../locale';
import { TableColumnWithIconStyleWrapper } from '@actiontech/shared/lib/styleWrapper/element';
-import { SystemRole } from '@actiontech/shared/lib/enum';
import { CheckHexagonOutlined, CloseHexagonOutlined } from '@actiontech/icons';
+import {
+ canManageTarget,
+ UserIdentityLike
+} from '../../utils/systemAdminBoundary';
export const UserListColumns: () => ActiontechTableColumn = () => [
{
@@ -65,8 +68,12 @@ export const UserListColumns: () => ActiontechTableColumn = () => [
export const UserListActions = (
onEditUser: (record?: IListUser) => void,
- onDeleteUser: (record?: IListUser) => void
+ onDeleteUser: (record?: IListUser) => void,
+ currentOperator?: UserIdentityLike | null
): ActiontechTableActionMeta[] => {
+ const canOperate = (record?: IListUser) =>
+ canManageTarget(currentOperator, record);
+
return [
{
text: t('common.manage'),
@@ -77,7 +84,8 @@ export const UserListActions = (
onEditUser(record);
}
};
- }
+ },
+ permissions: (record) => canOperate(record)
},
{
text: t('common.delete'),
@@ -95,9 +103,7 @@ export const UserListActions = (
}
};
},
- permissions: (record) => {
- return record?.name !== SystemRole.admin;
- }
+ permissions: (record) => canOperate(record)
}
];
};
diff --git a/packages/base/src/page/UserCenter/utils/systemAdminBoundary.ts b/packages/base/src/page/UserCenter/utils/systemAdminBoundary.ts
new file mode 100644
index 0000000000..65740de8ab
--- /dev/null
+++ b/packages/base/src/page/UserCenter/utils/systemAdminBoundary.ts
@@ -0,0 +1,46 @@
+import { OpPermissionTypeUid } from '@actiontech/shared/lib/enum';
+
+export type UserIdentityLike = {
+ name?: string;
+ username?: string;
+ uid?: string;
+ op_permissions?: Array<{ uid?: string } | null> | null;
+};
+
+const BUILTIN_ADMIN_NAMES = new Set(['admin', 'sys']);
+const BUILTIN_ADMIN_UIDS = new Set(['700200', '700201']);
+
+/** 内置 admin / sys(对齐后端 IsUserDMSAdmin);禁止用 isAdmin 推断 */
+export const isBuiltInAdminUser = (user?: UserIdentityLike | null): boolean => {
+ const name = user?.name ?? user?.username ?? '';
+ const uid = user?.uid ?? '';
+ return BUILTIN_ADMIN_NAMES.has(name) || BUILTIN_ADMIN_UIDS.has(uid);
+};
+
+/** 目标用户是否持有系统管理员(700017);看 op_permissions,不用 is_admin */
+export const isSystemAdminUser = (user?: UserIdentityLike | null): boolean => {
+ return (
+ user?.op_permissions?.some(
+ (p) => p?.uid === OpPermissionTypeUid.global_management
+ ) ?? false
+ );
+};
+
+/** 当前操作者能否管理目标用户(管理/删除) */
+export const canManageTarget = (
+ current?: UserIdentityLike | null,
+ target?: UserIdentityLike | null
+): boolean => {
+ if (isBuiltInAdminUser(current)) {
+ return true;
+ }
+ if (!target) {
+ return false;
+ }
+ return !isBuiltInAdminUser(target) && !isSystemAdminUser(target);
+};
+
+/** 当前操作者能否授予/收回「系统管理员」 */
+export const canEditGlobalManagement = (
+ current?: UserIdentityLike | null
+): boolean => isBuiltInAdminUser(current);
diff --git a/packages/base/src/scripts/version.ts b/packages/base/src/scripts/version.ts
index f78628f567..2cd6dda306 100644
--- a/packages/base/src/scripts/version.ts
+++ b/packages/base/src/scripts/version.ts
@@ -1 +1 @@
-export const UI_VERSION = 'dev-zjrc-sql-audit-report-summary f4fab7b02';
+export const UI_VERSION = 'dev-zjrc-user-system-admin f4fab7b02';
diff --git a/packages/shared/lib/enum/index.ts b/packages/shared/lib/enum/index.ts
index 1e56f3c9df..7378fe724e 100644
--- a/packages/shared/lib/enum/index.ts
+++ b/packages/shared/lib/enum/index.ts
@@ -62,7 +62,8 @@ export enum OpPermissionTypeUid {
'view_others_workflow' = '700007', // 查看其他工单权限 700007
'view_other_audit_plan' = '700008', // 查看其他扫描任务权限 700008
'save_audit_plan' = '700009', // 创建扫描任务权限;拥有该权限的用户可以创建/更新扫描任务 700009
- 'sql_query' = '700010' //SQL查询;SQL查询权限 700010
+ 'sql_query' = '700010', //SQL查询;SQL查询权限 700010
+ 'global_management' = '700017' // 系统管理员;可进行系统配置、用户管理等,权限低于内置 admin 700017
}
export enum CompanyNoticeDisplayStatusEnum {