diff --git a/scaleph-ui-react/src/locales/zh-CN/pages/base.ts b/scaleph-ui-react/src/locales/zh-CN/pages/base.ts index 2ff2fae0e..a7bc0531b 100644 --- a/scaleph-ui-react/src/locales/zh-CN/pages/base.ts +++ b/scaleph-ui-react/src/locales/zh-CN/pages/base.ts @@ -14,6 +14,16 @@ export default { 'app.common.operate.label': '操作', 'app.common.operate.success': '操作成功', 'app.common.operate.new.label': '新增', + 'app.common.operate.new.roles': '分配角色', + 'app.common.operate.new.rolesUser': '角色分配用户', + 'app.common.operate.new.rolesWeb': '角色配置web资源', + 'app.common.operate.new.user': '配置用户', + 'app.common.operate.new.webs': '配置web资源', + 'app.common.operate.new.accreditUser': '已授权用户', + 'app.common.operate.new.accreditRoles': '已授权角色', + 'app.common.operate.new.notAccreditUser': '未授权用户', + 'app.common.operate.new.notAccreditRoles': '未授权角色', + 'app.common.operate.new.assets': '权限配置', 'app.common.operate.new.success': '新增成功', 'app.common.operate.new.failure': '新增失败', 'app.common.operate.new.directive': '没有?去创建', diff --git a/scaleph-ui-react/src/models/useMainSize.ts b/scaleph-ui-react/src/models/useMainSize.ts new file mode 100644 index 000000000..07436b494 --- /dev/null +++ b/scaleph-ui-react/src/models/useMainSize.ts @@ -0,0 +1,26 @@ +import { useLayoutEffect, useState } from "react"; +import { throttle } from "lodash"; + +export default (mainCl = ".ant-pro-basicLayout-content") => { + const [container, setContainer] = useState<{ height: number; width: number }>({ + width: 100, + height: 100 + }); + // const mainCl = '.ant-pro-basicLayout-content'; + useLayoutEffect(() => { + const handler = throttle(() => { + const rt = document.querySelector(mainCl)?.getBoundingClientRect(); + setContainer({ + height: rt?.height, + width: rt?.width + }); + }, 100); + handler(); + window.addEventListener("resize", handler, false); + return () => { + window.removeEventListener("resize", handler, false); + }; + }, []); + + return container; +}; diff --git a/scaleph-ui-react/src/pages/Admin/Resource/Web/components/TransferTable.tsx b/scaleph-ui-react/src/pages/Admin/Resource/Web/components/TransferTable.tsx new file mode 100644 index 000000000..2ae7fb9a3 --- /dev/null +++ b/scaleph-ui-react/src/pages/Admin/Resource/Web/components/TransferTable.tsx @@ -0,0 +1,56 @@ +import { Table, Transfer } from 'antd'; +import { difference } from 'lodash'; // 注意这里改为大写的Difference +import React from 'react'; + +// 定义组件的Props类型 +interface Props { + leftColumns: any[]; // 左侧表格列配置数组 + rightColumns: any[]; // 右侧表格列配置数组 + containerHeight: number; // 容器高度 +} + +// 使用React.FC声明函数组件,并传入Props类型 +const TableTransfer: React.FC = ({ leftColumns, rightColumns, ...restProps }) => ( + + {({ + direction, + filteredItems, + onItemSelectAll, + onItemSelect, + selectedKeys: listSelectedKeys, + disabled: listDisabled, + }) => { + const columns = direction === 'left' ? leftColumns : rightColumns; + // 表格行选择配置 + const rowSelection = { + onSelectAll(selected: boolean, selectedRows: any[]) { + const treeSelectedKeys = selectedRows.map(({ key }) => key); + const diffKeys = selected + ? difference(treeSelectedKeys, listSelectedKeys) + : difference(listSelectedKeys, treeSelectedKeys); + onItemSelectAll(diffKeys, selected); + }, + onSelect: ({ id }: { id: string }, selected: boolean) => { + onItemSelect(id, selected); + }, + selectedRowKeys: listSelectedKeys, + }; + + return ( + + ); + }} + +); +export default React.memo(TableTransfer); diff --git a/scaleph-ui-react/src/pages/Admin/Resource/Web/components/WebAssugnRoles.tsx b/scaleph-ui-react/src/pages/Admin/Resource/Web/components/WebAssugnRoles.tsx new file mode 100644 index 000000000..7550f0aef --- /dev/null +++ b/scaleph-ui-react/src/pages/Admin/Resource/Web/components/WebAssugnRoles.tsx @@ -0,0 +1,170 @@ +import mainHeight from '@/models/useMainSize'; +import { SecResourceWeb } from '@/services/admin/typings'; +import { AuthService } from '@/services/auth'; +import { Button, Card, Form, message, Modal, Space } from 'antd'; +import React, { useCallback, useEffect, useMemo, useState } from 'react'; +import { useIntl } from 'umi'; +import TableTransfer from './TransferTable'; + +// 定义组件 Props 类型 +interface ModalFormParentProps { + data: T; + visible: boolean; + onVisibleChange?: (visible: boolean) => void; + onCancel: () => void; + onOK?: (values: any) => void; +} + +const WebResourceForm: React.FC> = ({ + data, + visible, + onVisibleChange, + onCancel, +}) => { + const intl = useIntl(); + const [form] = Form.useForm(); + const containerInfo = mainHeight('.ant-layout-content'); + const [roleLists, setRoleLists] = useState([]); + + // 角色表格列配置 + const tableColumns = [ + { + dataIndex: 'name', + title: '角色名称', + width: 300, + }, + { + dataIndex: 'desc', + title: '描述', + width: 300, + }, + ]; + + // 角色类型定义 + interface Role { + id: string; + name: string; + resourceAuthorized: number; + checkOut?: number; + } + + // 合并数组 + function mergeArrays(array1: Role[], array2: Role[]): Role[] { + array1.forEach((obj, index) => { + obj.checkOut = 0; + }); + array2.forEach((obj, index) => { + obj.checkOut = 1; + }); + return [...array1, ...array2]; + } + + // 异步获取数据 + const fetchData = useCallback(async () => { + try { + const res1 = await AuthService.unauthorizedRoles({ resourceWebId: data?.id }); + const res2 = await AuthService.authorizedRoles({ resourceWebId: data?.id }); + if (res1?.records && res2?.records) { + const mergedArray = mergeArrays(res1.records, res2.records); + setRoleLists(mergedArray); + } + } catch (error) { + console.error(error); + } + }, [data]); + + useEffect(() => { + if (data) { + fetchData(); + } + }, [data, fetchData]); + + // 页面标题 + const returnTitle = useMemo(() => { + return ( + + {` ${intl.formatMessage({ id: `menu.${data?.name}` })}-资源分配详情`} + + ); + }, [data, intl]); + + // 获取选中角色的 id 数组 + const originTargetKeys = useMemo(() => { + return roleLists?.filter((item) => item.checkOut === 1).map((item) => item.id); + }, [roleLists]); + + // 过滤方法 + const handleFilter = useCallback((inputValue, item) => { + return item?.name.indexOf(inputValue) !== -1; + }, []); + + // 角色转移事件处理 + const handleChange = useCallback( + async (targetKeys, direction, moveKeys) => { + const roleIds = moveKeys.map((item: string | number) => +item); + const params = { + resourceWebId: data?.id, + roleIds: roleIds, + }; + if (direction === 'right') { + // 绑定角色资源 + await AuthService.resourceWebRoles(params).then((res) => { + if (res?.success) { + message.success(intl.formatMessage({ id: 'app.common.operate.edit.success' }), 2); + } + }); + } else { + // 删除绑定的角色资源 + await AuthService.resourceWebRolesDelete(params).then((res) => { + message.success(intl.formatMessage({ id: 'app.common.operate.edit.success' }), 2); + }); + } + fetchData(); + }, + [data, fetchData, intl], + ); + + return ( + + {intl.formatMessage({ id: 'app.common.operate.close.label' })} + , + ]} + > +
+ + record.id} + onChange={handleChange} + filterOption={handleFilter} + listStyle={{ + width: 500, + }} + leftColumns={tableColumns} + rightColumns={tableColumns} + /> + +
+
+ ); +}; + +export default WebResourceForm; diff --git a/scaleph-ui-react/src/pages/Admin/Resource/Web/index.tsx b/scaleph-ui-react/src/pages/Admin/Resource/Web/index.tsx index d50592fe2..f21ddd1e9 100644 --- a/scaleph-ui-react/src/pages/Admin/Resource/Web/index.tsx +++ b/scaleph-ui-react/src/pages/Admin/Resource/Web/index.tsx @@ -1,9 +1,10 @@ import { PRIVILEGE_CODE } from '@/constant'; +import WebAssugnRoles from '@/pages/Admin/Resource/Web/components/WebAssugnRoles'; import WebResourceForm from '@/pages/Admin/Resource/Web/components/WebResourceForm'; import { PrivilegeService } from '@/services/admin/privilege.service'; import { ResourceWebService } from '@/services/admin/resourceWeb.service'; import { SecResourceWeb } from '@/services/admin/typings'; -import { DeleteOutlined, EditOutlined, PlusOutlined } from '@ant-design/icons'; +import { DeleteOutlined, EditOutlined, FormOutlined, PlusOutlined } from '@ant-design/icons'; import { ActionType, ProColumns, ProFormInstance, ProTable } from '@ant-design/pro-components'; import { Button, message, Modal, Space, Tag, Tooltip } from 'antd'; import { isEmpty } from 'lodash'; @@ -21,6 +22,10 @@ const WebResourceWeb: React.FC = () => { parent: SecResourceWeb; data: SecResourceWeb; }>({ visiable: false, parent: {}, data: {} }); + const [webAssignRoles, setWebAssignRoles] = useState<{ + visiable: boolean; + data: SecResourceWeb; + }>({ visiable: false, parent: {}, data: {} }); const onExpand = (expanded: boolean, record: SecResourceWeb) => { if (expanded && record.children && isEmpty(record.children)) { @@ -44,6 +49,9 @@ const WebResourceWeb: React.FC = () => { { title: intl.formatMessage({ id: 'pages.admin.resource.web.name' }), dataIndex: 'name', + // render: (dom, entity) => { + // return intl.formatMessage({ id: `menu.${entity?.name}` }); + // }, }, { title: intl.formatMessage({ id: 'pages.admin.resource.web.path' }), @@ -91,12 +99,22 @@ const WebResourceWeb: React.FC = () => { title: intl.formatMessage({ id: 'app.common.operate.label' }), dataIndex: 'actions', align: 'center', - width: 120, + width: 160, fixed: 'right', valueType: 'option', render: (_, record) => ( <> + {access.canAccess(PRIVILEGE_CODE.datadevProjectEdit) && ( + + , + ]} + > +
+ + record.id} + onChange={handleChange} + filterOption={handleFilter} + listStyle={{ + width: 500, + }} + leftColumns={tableColumns} + rightColumns={tableColumns} + /> + +
+ + ); +}; + +export default WebResourceForm; diff --git a/scaleph-ui-react/src/pages/Admin/Role/index.tsx b/scaleph-ui-react/src/pages/Admin/Role/index.tsx index 5b34a7ab9..e1b98455d 100644 --- a/scaleph-ui-react/src/pages/Admin/Role/index.tsx +++ b/scaleph-ui-react/src/pages/Admin/Role/index.tsx @@ -1,13 +1,21 @@ -import {useAccess, useIntl} from "umi"; -import React, {useRef, useState} from "react"; -import {Button, message, Modal, Space, Tag, Tooltip} from "antd"; -import {DeleteOutlined, EditOutlined} from "@ant-design/icons"; -import {ActionType, ProColumns, ProFormInstance, ProFormSelect, ProTable} from "@ant-design/pro-components"; -import {DICT_TYPE, PRIVILEGE_CODE} from "@/constant"; -import {SecRole} from "@/services/admin/typings"; -import {RoleService} from "@/services/admin/role.service"; -import RoleForm from "@/pages/Admin/Role/components/RoleForm"; -import {DictDataService} from "@/services/admin/dictData.service"; +import { DICT_TYPE, PRIVILEGE_CODE } from '@/constant'; +import RoleForm from '@/pages/Admin/Role/components/RoleForm'; +import { DictDataService } from '@/services/admin/dictData.service'; +import { RoleService } from '@/services/admin/role.service'; +import { SecRole } from '@/services/admin/typings'; +import { DeleteOutlined, EditOutlined, FormOutlined, SelectOutlined } from '@ant-design/icons'; +import { + ActionType, + ProColumns, + ProFormInstance, + ProFormSelect, + ProTable, +} from '@ant-design/pro-components'; +import { Button, message, Modal, Space, Tag, Tooltip } from 'antd'; +import React, { useRef, useState } from 'react'; +import { useAccess, useIntl } from 'umi'; +import WebAssugnRoles from './components/WebAssugnRoles'; +import ResourceWebs from './components/ResourceWebs'; const RoleWeb: React.FC = () => { const intl = useIntl(); @@ -18,27 +26,37 @@ const RoleWeb: React.FC = () => { const [roleFormData, setRoleFormData] = useState<{ visiable: boolean; data: SecRole; - }>({visiable: false, data: {}}); + }>({ visiable: false, data: {} }); + + const [webAssignRoles, setWebAssignRoles] = useState<{ + visiable: boolean; + data: SecRole; + }>({ visiable: false, parent: {}, data: {} }); + + const [resourceWebs, setResourceWebs] = useState<{ + visiable: boolean; + data: SecRole; + }>({ visiable: false, parent: {}, data: {} }); const tableColumns: ProColumns[] = [ { - title: intl.formatMessage({id: 'pages.admin.role.name'}), + title: intl.formatMessage({ id: 'pages.admin.role.name' }), dataIndex: 'name', - width: 200 + width: 200, }, { - title: intl.formatMessage({id: 'pages.admin.role.code'}), + title: intl.formatMessage({ id: 'pages.admin.role.code' }), dataIndex: 'code', hideInSearch: true, - width: 200 + width: 200, }, { - title: intl.formatMessage({id: 'pages.admin.role.type'}), + title: intl.formatMessage({ id: 'pages.admin.role.type' }), dataIndex: 'type', render: (dom, entity) => { - return ({entity.type?.label}) + return {entity.type?.label}; }, - renderFormItem: (item, {defaultRender, ...rest}, form) => { + renderFormItem: (item, { defaultRender, ...rest }, form) => { return ( { /> ); }, - width: 200 + width: 200, }, { - title: intl.formatMessage({id: 'pages.admin.role.status'}), + title: intl.formatMessage({ id: 'pages.admin.role.status' }), dataIndex: 'status', render: (dom, entity) => { - return ({entity.status?.label}) + return {entity.status?.label}; }, - renderFormItem: (item, {defaultRender, ...rest}, form) => { + renderFormItem: (item, { defaultRender, ...rest }, form) => { return ( { /> ); }, - width: 200 + width: 200, }, { - title: intl.formatMessage({id: 'app.common.data.remark'}), + title: intl.formatMessage({ id: 'app.common.data.remark' }), dataIndex: 'remark', hideInSearch: true, width: 180, }, { - title: intl.formatMessage({id: 'app.common.data.createTime'}), + title: intl.formatMessage({ id: 'app.common.data.createTime' }), dataIndex: 'createTime', hideInSearch: true, width: 180, }, { - title: intl.formatMessage({id: 'app.common.data.updateTime'}), + title: intl.formatMessage({ id: 'app.common.data.updateTime' }), dataIndex: 'updateTime', hideInSearch: true, width: 180, }, { - title: intl.formatMessage({id: 'app.common.operate.label'}), + title: intl.formatMessage({ id: 'app.common.operate.label' }), dataIndex: 'actions', align: 'center', width: 120, @@ -94,34 +112,60 @@ const RoleWeb: React.FC = () => { render: (_, record) => ( <> + {access.canAccess(PRIVILEGE_CODE.datadevProjectEdit) && ( + + )} {access.canAccess(PRIVILEGE_CODE.roleDelete) && ( - + ), access.canAccess(PRIVILEGE_CODE.roleDelete) && ( @@ -170,15 +214,19 @@ const RoleWeb: React.FC = () => { disabled={selectedRows.length < 1} onClick={() => { Modal.confirm({ - title: intl.formatMessage({id: 'app.common.operate.delete.confirm.title'}), - content: intl.formatMessage({id: 'app.common.operate.delete.confirm.content'}), - okText: intl.formatMessage({id: 'app.common.operate.confirm.label'}), - okButtonProps: {danger: true}, - cancelText: intl.formatMessage({id: 'app.common.operate.cancel.label'}), + title: intl.formatMessage({ id: 'app.common.operate.delete.confirm.title' }), + content: intl.formatMessage({ + id: 'app.common.operate.delete.confirm.content', + }), + okText: intl.formatMessage({ id: 'app.common.operate.confirm.label' }), + okButtonProps: { danger: true }, + cancelText: intl.formatMessage({ id: 'app.common.operate.cancel.label' }), onOk() { RoleService.deleteBatch(selectedRows).then((d) => { if (d.success) { - message.success(intl.formatMessage({id: 'app.common.operate.delete.success'})); + message.success( + intl.formatMessage({ id: 'app.common.operate.delete.success' }), + ); actionRef.current?.reload(); } }); @@ -186,12 +234,12 @@ const RoleWeb: React.FC = () => { }); }} > - {intl.formatMessage({id: 'app.common.operate.delete.label'})} + {intl.formatMessage({ id: 'app.common.operate.delete.label' })} ), ], }} - pagination={{showQuickJumper: true, showSizeChanger: true, defaultPageSize: 10}} + pagination={{ showQuickJumper: true, showSizeChanger: true, defaultPageSize: 10 }} rowSelection={{ fixed: true, onChange: (selectedRowKeys, selectedRows, info) => setSelectedRows(selectedRows), @@ -202,17 +250,38 @@ const RoleWeb: React.FC = () => { {roleFormData.visiable && ( setRoleFormData({visiable: false, data: {}})} + onCancel={() => setRoleFormData({ visiable: false, data: {} })} onVisibleChange={(visiable) => { - setRoleFormData({visiable: visiable, data: {}}); + setRoleFormData({ visiable: visiable, data: {} }); actionRef.current?.reload(); }} data={roleFormData.data} /> )} + {webAssignRoles.visiable && ( + setWebAssignRoles({ visiable: false, data: {} })} + onVisibleChange={(visiable) => { + setWebAssignRoles({ visiable: visiable, data: {} }); + actionRef.current?.reload(); + }} + data={webAssignRoles.data} + /> + )} + {resourceWebs.visiable && ( + setResourceWebs({ visiable: false, data: {} })} + onVisibleChange={(visiable) => { + setResourceWebs({ visiable: visiable, data: {} }); + actionRef.current?.reload(); + }} + data={resourceWebs.data} + /> + )} ); - -} +}; export default RoleWeb; diff --git a/scaleph-ui-react/src/pages/Admin/User/components/UserRoles.tsx b/scaleph-ui-react/src/pages/Admin/User/components/UserRoles.tsx new file mode 100644 index 000000000..09f8369fb --- /dev/null +++ b/scaleph-ui-react/src/pages/Admin/User/components/UserRoles.tsx @@ -0,0 +1,172 @@ +import mainHeight from '@/models/useMainSize'; +import TableTransfer from '@/pages/Admin/Resource/Web/components/TransferTable'; +import { SecResourceWeb } from '@/services/admin/typings'; +import { AuthService } from '@/services/auth'; +import { Button, Card, Form, message, Modal, Space } from 'antd'; +import React, { useCallback, useEffect, useMemo, useState } from 'react'; +import { useIntl } from 'umi'; + +// 定义组件 Props 类型 +interface ModalFormParentProps { + data: T; + visible: boolean; + onVisibleChange?: (visible: boolean) => void; + onCancel: () => void; + onOK?: (values: any) => void; +} + +const WebResourceForm: React.FC> = ({ + data, + visible, + onVisibleChange, + onCancel, +}) => { + const intl = useIntl(); + const [form] = Form.useForm(); + const containerInfo = mainHeight('.ant-layout-content'); + const [roleLists, setRoleLists] = useState([]); + + // 角色表格列配置 + const tableColumns = [ + { + dataIndex: 'name', + title: '角色名称', + width: 300, + }, + { + dataIndex: 'status.label', + title: '角色状态', + width: 300, + render: (text: any, record: { status: { label: boolean | React.ReactChild | React.ReactFragment | React.ReactPortal | null | undefined; }; }) => ( + {record.status.label} + ), + }, + ]; + + // 角色类型定义 + interface Role { + id: string; + name: string; + resourceAuthorized: number; + checkOut?: number; + } + + // 合并数组 + function mergeArrays(array1: any, array2: any): any { + array1.forEach((obj: { checkOut: number; }, index: any) => { + obj.checkOut = 0; + }); + array2.forEach((obj: { checkOut: number; }, index: any) => { + obj.checkOut = 1; + }); + return [...array1, ...array2]; + } + // 异步获取数据 + const fetchData = useCallback(async () => { + try { + const res1 = await AuthService.requestUnauthorizedRoles({ userId: data?.id }); + const res2 = await AuthService.requestUserAuthorizedRoles({ userId: data?.id }); + if (res1 && res2) { + const mergedArray = mergeArrays(res1, res2); + setRoleLists(mergedArray); + } + } catch (error) { + console.error(error); + } + }, [data]); + + useEffect(() => { + if (data) { + fetchData(); + } + }, [data, fetchData]); + + // 页面标题 + const returnTitle = useMemo(() => { + return ( + + {` ${intl.formatMessage({ id: `menu.${data?.userName}` })}-${intl.formatMessage({ id: 'app.common.operate.new.roles' })}`} + + ); + }, [data, intl]); + + // 获取选中角色的 id 数组 + const originTargetKeys = useMemo(() => { + return roleLists?.filter((item) => item.checkOut === 1).map((item) => item.id); + }, [roleLists]); + + // 过滤方法 + const handleFilter = useCallback((inputValue, item) => { + return item?.name.indexOf(inputValue) !== -1; + }, []); + + // 角色转移事件处理 + const handleChange = useCallback( + async (targetKeys, direction, moveKeys) => { + const roleIds = moveKeys.map((item: string | number) => +item); + const params = { + userId: data?.id, + roleIds: roleIds, + }; + if (direction === 'right') { + // 批量为角色绑定用户 + await AuthService.requestUserRoles(params).then((res) => { + if (res?.success) { + message.success(intl.formatMessage({ id: 'app.common.operate.edit.success' }), 2); + } + }); + } else { + // 批量为角色解除用户绑定 + await AuthService.requestDeleteUserRoles(params).then((res) => { + message.success(intl.formatMessage({ id: 'app.common.operate.edit.success' }), 2); + }); + } + fetchData(); + }, + [data, fetchData, intl], + ); + + return ( + + {intl.formatMessage({ id: 'app.common.operate.close.label' })} + , + ]} + > +
+ + record.id} + onChange={handleChange} + filterOption={handleFilter} + listStyle={{ + width: 500, + }} + leftColumns={tableColumns} + rightColumns={tableColumns} + /> + +
+
+ ); +}; + +export default WebResourceForm; diff --git a/scaleph-ui-react/src/pages/Admin/User/index.tsx b/scaleph-ui-react/src/pages/Admin/User/index.tsx index 6dcb4247c..3166099e8 100644 --- a/scaleph-ui-react/src/pages/Admin/User/index.tsx +++ b/scaleph-ui-react/src/pages/Admin/User/index.tsx @@ -1,19 +1,20 @@ -import {useAccess, useIntl} from 'umi'; -import React, {useEffect, useRef, useState} from 'react'; -import {Button, Card, Col, Input, List, message, Modal, Row, Space, Tabs, Tag, Tooltip, Tree, Typography,} from 'antd'; -import {EditOutlined, RedoOutlined, StopOutlined, UserSwitchOutlined,} from '@ant-design/icons'; -import {ActionType, ProColumns, ProFormInstance, ProFormSelect, ProTable} from '@ant-design/pro-components'; -import {TreeNode} from '@/app.d'; -import {DICT_TYPE, PRIVILEGE_CODE} from '@/constant'; -import {DeptService} from '@/services/admin/dept.service'; -import {DictDataService} from '@/services/admin/dictData.service'; -import {RoleService} from '@/services/admin/role.service'; -import {SecDept, SecRole, SecUser} from '@/services/admin/typings'; -import {UserService} from '@/services/admin/user.service'; +import { useAccess, useIntl } from 'umi'; +import React, { useEffect, useRef, useState } from 'react'; +import { Button, Card, Col, Input, List, message, Modal, Row, Space, Tabs, Tag, Tooltip, Tree, Typography, } from 'antd'; +import { EditOutlined, RedoOutlined, StopOutlined, UserSwitchOutlined, FormOutlined } from '@ant-design/icons'; +import { ActionType, ProColumns, ProFormInstance, ProFormSelect, ProTable } from '@ant-design/pro-components'; +import { TreeNode } from '@/app.d'; +import { DICT_TYPE, PRIVILEGE_CODE } from '@/constant'; +import { DeptService } from '@/services/admin/dept.service'; +import { DictDataService } from '@/services/admin/dictData.service'; +import { RoleService } from '@/services/admin/role.service'; +import { SecDept, SecRole, SecUser } from '@/services/admin/typings'; +import { UserService } from '@/services/admin/user.service'; import DeptGrant from './components/DeptGrant'; import RoleForm from './components/RoleForm'; import RoleGrant from './components/RoleGrant'; import UserForm from './components/UserForm'; +import UserRoles from './components/UserRoles'; import styles from './index.less'; const User: React.FC = () => { @@ -47,15 +48,19 @@ const User: React.FC = () => { visible: false, data: {}, }); + const [webAssignRoles, setWebAssignRoles] = useState<{ + visiable: boolean; + data: SecRole; + }>({ visiable: false, parent: {}, data: {} }); const tableColumns: ProColumns[] = [ { - title: intl.formatMessage({id: 'pages.admin.user.type'}), + title: intl.formatMessage({ id: 'pages.admin.user.type' }), dataIndex: 'type', render: (dom, entity) => { return ({entity.type?.label}) }, - renderFormItem: (item, {defaultRender, ...rest}, form) => { + renderFormItem: (item, { defaultRender, ...rest }, form) => { return ( { width: 200 }, { - title: intl.formatMessage({id: 'pages.admin.user.userName'}), + title: intl.formatMessage({ id: 'pages.admin.user.userName' }), dataIndex: 'userName', }, { - title: intl.formatMessage({id: 'pages.admin.user.nickName'}), + title: intl.formatMessage({ id: 'pages.admin.user.nickName' }), dataIndex: 'nickName', }, { - title: intl.formatMessage({id: 'pages.admin.user.email'}), + title: intl.formatMessage({ id: 'pages.admin.user.email' }), dataIndex: 'email', hideInSearch: true }, { - title: intl.formatMessage({id: 'pages.admin.user.phone'}), + title: intl.formatMessage({ id: 'pages.admin.user.phone' }), dataIndex: 'phone', hideInSearch: true }, { - title: intl.formatMessage({id: 'pages.admin.user.gender'}), + title: intl.formatMessage({ id: 'pages.admin.user.gender' }), dataIndex: 'gender', hideInSearch: true, render: (text, record, index) => { @@ -93,12 +98,12 @@ const User: React.FC = () => { }, }, { - title: intl.formatMessage({id: 'pages.admin.user.status'}), + title: intl.formatMessage({ id: 'pages.admin.user.status' }), dataIndex: 'userStatus', render: (text, record, index) => { return ({record.status?.label}) }, - renderFormItem: (item, {defaultRender, ...rest}, form) => { + renderFormItem: (item, { defaultRender, ...rest }, form) => { return ( { } }, { - title: intl.formatMessage({id: 'app.common.operate.label'}), + title: intl.formatMessage({ id: 'app.common.operate.label' }), dataIndex: 'actions', align: 'center', width: 120, @@ -118,15 +123,26 @@ const User: React.FC = () => { render: (_, record) => ( <> + {access.canAccess(PRIVILEGE_CODE.datadevProjectEdit) && ( + + @@ -134,23 +150,23 @@ const User: React.FC = () => { {record.userStatus?.value?.substring(0, 1) != '9' && access.canAccess(PRIVILEGE_CODE.userDelete) && ( - + @@ -293,16 +309,16 @@ const User: React.FC = () => { )} {access.canAccess(PRIVILEGE_CODE.deptSelect) && ( - + { setDeptTreeList([...deptTreeList]); }} > - + {node.title} {node.showOpIcon && ( {access.canAccess(PRIVILEGE_CODE.deptGrant) && ( - + @@ -370,12 +386,12 @@ const User: React.FC = () => {
- headerTitle={intl.formatMessage({id: 'pages.admin.user'})} + headerTitle={intl.formatMessage({ id: 'pages.admin.user' })} search={{ labelWidth: 'auto', - span: {xs: 24, sm: 12, md: 8, lg: 6, xl: 6, xxl: 4}, + span: { xs: 24, sm: 12, md: 8, lg: 6, xl: 6, xxl: 4 }, }} - scroll={{x: 800}} + scroll={{ x: 800 }} rowKey="id" actionRef={actionRef} formRef={formRef} @@ -387,10 +403,10 @@ const User: React.FC = () => { key="new" type="primary" onClick={() => { - setUserFormData({visible: true, data: {}}); + setUserFormData({ visible: true, data: {} }); }} > - {intl.formatMessage({id: 'app.common.operate.new.label'})} + {intl.formatMessage({ id: 'app.common.operate.new.label' })} ), access.canAccess(PRIVILEGE_CODE.userDelete) && ( @@ -400,15 +416,15 @@ const User: React.FC = () => { disabled={selectedRows.length < 1} onClick={() => { Modal.confirm({ - title: intl.formatMessage({id: 'app.common.operate.forbid.confirm.title'}), - content: intl.formatMessage({id: 'app.common.operate.forbid.confirm.content'}), - okText: intl.formatMessage({id: 'app.common.operate.confirm.label'}), - okButtonProps: {danger: true}, - cancelText: intl.formatMessage({id: 'app.common.operate.cancel.label'}), + title: intl.formatMessage({ id: 'app.common.operate.forbid.confirm.title' }), + content: intl.formatMessage({ id: 'app.common.operate.forbid.confirm.content' }), + okText: intl.formatMessage({ id: 'app.common.operate.confirm.label' }), + okButtonProps: { danger: true }, + cancelText: intl.formatMessage({ id: 'app.common.operate.cancel.label' }), onOk() { UserService.deleteUserBatch(selectedRows).then((d) => { if (d.success) { - message.success(intl.formatMessage({id: 'app.common.operate.forbid.success'})); + message.success(intl.formatMessage({ id: 'app.common.operate.forbid.success' })); actionRef.current?.reload(); } }); @@ -416,7 +432,7 @@ const User: React.FC = () => { }); }} > - {intl.formatMessage({id: 'app.common.operate.forbid.label'})} + {intl.formatMessage({ id: 'app.common.operate.forbid.label' })} ), ], @@ -429,7 +445,7 @@ const User: React.FC = () => { roleId: selectRole, }); }} - pagination={{showQuickJumper: true, showSizeChanger: true, defaultPageSize: 10}} + pagination={{ showQuickJumper: true, showSizeChanger: true, defaultPageSize: 10 }} rowSelection={{ fixed: true, onChange(selectedRowKeys, selectedRows, info) { @@ -444,10 +460,10 @@ const User: React.FC = () => { { - setRoleFormData({visible: false, data: {}}); + setRoleFormData({ visible: false, data: {} }); }} onVisibleChange={(visible) => { - setRoleFormData({visible: visible, data: {}}); + setRoleFormData({ visible: visible, data: {} }); refreshRoles(); }} data={roleFormData.data} @@ -457,10 +473,10 @@ const User: React.FC = () => { { - setRoleGrantData({visible: false, data: {}}); + setRoleGrantData({ visible: false, data: {} }); }} onVisibleChange={(visible) => { - setRoleGrantData({visible: visible, data: {}}); + setRoleGrantData({ visible: visible, data: {} }); }} data={roleGrantData.data} > @@ -469,10 +485,10 @@ const User: React.FC = () => { { - setDeptGrantData({visible: false, data: {}}); + setDeptGrantData({ visible: false, data: {} }); }} onVisibleChange={(visible) => { - setDeptGrantData({visible: visible, data: {}}); + setDeptGrantData({ visible: visible, data: {} }); }} data={deptGrantData.data} /> @@ -481,15 +497,26 @@ const User: React.FC = () => { { - setUserFormData({visible: false, data: {}}); + setUserFormData({ visible: false, data: {} }); }} onVisibleChange={(visible) => { - setUserFormData({visible: visible, data: {}}); + setUserFormData({ visible: visible, data: {} }); actionRef.current?.reload(); }} data={userFormData.data} > ) : null} + {webAssignRoles.visiable && ( + setWebAssignRoles({ visiable: false, data: {} })} + onVisibleChange={(visiable) => { + setWebAssignRoles({ visiable: visiable, data: {} }); + actionRef.current?.reload(); + }} + data={webAssignRoles.data} + /> + )} ); }; diff --git a/scaleph-ui-react/src/services/auth.ts b/scaleph-ui-react/src/services/auth.ts index b8425839e..07d3ae4db 100644 --- a/scaleph-ui-react/src/services/auth.ts +++ b/scaleph-ui-react/src/services/auth.ts @@ -63,4 +63,112 @@ export const AuthService = { params: { token: token }, }); }, + + unauthorizedRoles: async (param: any) => { + return request>('/api/admin/authorize/resource-web/unauthorized-roles', { + method: 'GET', + params: param, + }); + }, + authorizedRoles: async (param: any) => { + return request>('/api/admin/authorize/resource-web/authorized-roles', { + method: 'GET', + params: param, + }); + }, + resourceWebRoles: async (param: any) => { + return request>('/api/admin/authorize/resource-web/roles', { + method: 'PUT', + data: param, + }); + }, + resourceWebRolesDelete: async (param: any) => { + return request>('/api/admin/authorize/resource-web/roles', { + method: 'DELETE', + data: param, + }); + }, + //查询角色绑定用户列表 + requestAuthorizedUsers: async (param: any) => { + return request>('/api/admin/authorize/role/authorized-users', { + method: 'GET', + params: param, + }); + }, + //查询角色未绑定用户列表 + requestUnauthorizedUsers: async (param: any) => { + return request>('/api/admin/authorize/role/unauthorized-users', { + method: 'GET', + params: param, + }); + }, + //批量为角色绑定用户 + rolesUser: async (param: any) => { + return request>('/api/admin/authorize/role/users', { + method: 'PUT', + data: param, + }); + }, + //批量为角色解除用户绑定 + deleteRolesUser: async (param: any) => { + return request>('/api/admin/authorize/role/users', { + method: 'DELETE', + data: param, + }); + }, + + //查询用户未绑定角色列表 + requestUnauthorizedRoles: async (param: any) => { + return request>('/api/admin/authorize/user/unauthorized-roles', { + method: 'GET', + params: param, + }); + }, + //查询角色绑定用户列表 + requestUserAuthorizedRoles: async (param: any) => { + return request>('/api/admin/authorize/user/authorized-roles', { + method: 'GET', + params: param, + }); + }, + + //批量为用户绑定角色 + requestUserRoles: async (param: any) => { + return request>('/api/admin/authorize/user/roles', { + method: 'PUT', + data: param, + }); + }, + + //批量为用户解除角色绑定 + requestDeleteUserRoles: async (param: any) => { + return request>('/api/admin/authorize/user/roles', { + method: 'DELETE', + data: param, + }); + }, + + //查询所有 资源-web 和指定角色绑定状态 + requestResourceWebs: async (param: any) => { + return request>('/api/admin/authorize/role/resource-webs', { + method: 'GET', + params: param, + }); + }, + + //批量为角色绑定 资源-web + requestRoleResourceWebs: async (param: any) => { + return request>('/api/admin/authorize/role/resource-webs', { + method: 'PUT', + data: param, + }); + }, + + //批量为角色解除 资源-web 绑定 + requestDeleteRoleResourceWebs: async (param: any) => { + return request>('/api/admin/authorize/role/resource-webs', { + method: 'DELETE', + data: param, + }); + }, }; diff --git a/scaleph-ui-react/src/typings.d.ts b/scaleph-ui-react/src/typings.d.ts index cb2b0295f..73f1ad1a6 100644 --- a/scaleph-ui-react/src/typings.d.ts +++ b/scaleph-ui-react/src/typings.d.ts @@ -22,3 +22,4 @@ declare module 'bizcharts-plugin-slider'; declare let ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION: 'site' | undefined; declare const REACT_APP_ENV: 'test' | 'dev' | 'pre' | 'dist' | false; +declare module 'monaco-editor/esm/vs/basic-languages/sql/sql';