调整数据授权管理的前端优化
parent
aa632ec6ec
commit
09098a180c
|
|
@ -1,5 +1,6 @@
|
|||
.user-data-scope-page {
|
||||
min-height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.user-data-scope-overview {
|
||||
|
|
@ -38,7 +39,45 @@
|
|||
}
|
||||
|
||||
.user-data-scope-table-card {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
overflow: hidden;
|
||||
|
||||
.ant-card-body {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
.user-data-scope-table {
|
||||
min-height: 0;
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
|
||||
.ant-spin-nested-loading,
|
||||
.ant-spin-container {
|
||||
min-height: 0;
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.ant-table {
|
||||
min-height: 0;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.ant-table-container {
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.ant-table-pagination {
|
||||
flex-shrink: 0;
|
||||
margin: 12px 16px !important;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 991px) {
|
||||
|
|
|
|||
|
|
@ -4,10 +4,10 @@ import dayjs from "dayjs";
|
|||
import { useCallback, useEffect, useMemo, useState } from "react";
|
||||
import { DeleteOutlined, EditOutlined, PlusOutlined, SearchOutlined, TeamOutlined } from "@ant-design/icons";
|
||||
import PageHeader from "@/components/shared/PageHeader";
|
||||
import { deleteUserDataScopeGrant, listTenants, listUserDataScopeGrants, listUserDataScopeUsers, saveUserDataScopeAssignment } from "@/api";
|
||||
import { deleteUserDataScopeGrant, fetchUsersByRoleId, listRoles, listTenants, listUserDataScopeGrants, listUserDataScopeUsers, saveUserDataScopeAssignment } from "@/api";
|
||||
import { usePermission } from "@/hooks/usePermission";
|
||||
import { getStandardPagination } from "@/utils/pagination";
|
||||
import type { SysTenant, UserDataScopeGrant, UserDataScopeUser } from "@/types";
|
||||
import type { SysRole, SysTenant, UserDataScopeGrant, UserDataScopeUser } from "@/types";
|
||||
import "./index.less";
|
||||
|
||||
const { Text } = Typography;
|
||||
|
|
@ -141,7 +141,9 @@ export default function UserDataScopePage() {
|
|||
const [form] = Form.useForm();
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [saving, setSaving] = useState(false);
|
||||
const [roleUserLoading, setRoleUserLoading] = useState(false);
|
||||
const [users, setUsers] = useState<UserDataScopeUser[]>([]);
|
||||
const [roles, setRoles] = useState<SysRole[]>([]);
|
||||
const [grants, setGrants] = useState<UserDataScopeGrant[]>([]);
|
||||
const [tenants, setTenants] = useState<SysTenant[]>([]);
|
||||
const [drawerOpen, setDrawerOpen] = useState(false);
|
||||
|
|
@ -170,6 +172,15 @@ export default function UserDataScopePage() {
|
|||
setUsers(list || []);
|
||||
}, [selectedTenantId]);
|
||||
|
||||
const loadRoles = useCallback(async () => {
|
||||
if (!selectedTenantId) {
|
||||
setRoles([]);
|
||||
return;
|
||||
}
|
||||
const list = await listRoles(selectedTenantId);
|
||||
setRoles(list || []);
|
||||
}, [selectedTenantId]);
|
||||
|
||||
const loadGrants = useCallback(async () => {
|
||||
if (!selectedTenantId) {
|
||||
setGrants([]);
|
||||
|
|
@ -182,11 +193,11 @@ export default function UserDataScopePage() {
|
|||
const loadPageData = useCallback(async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
await Promise.all([loadTenants(), loadUsers(), loadGrants()]);
|
||||
await Promise.all([loadTenants(), loadUsers(), loadRoles(), loadGrants()]);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, [loadTenants, loadUsers, loadGrants]);
|
||||
}, [loadTenants, loadUsers, loadRoles, loadGrants]);
|
||||
|
||||
useEffect(() => {
|
||||
loadPageData();
|
||||
|
|
@ -244,12 +255,28 @@ export default function UserDataScopePage() {
|
|||
[selectedDrawerViewerId, userOptions]
|
||||
);
|
||||
|
||||
const roleOptions = useMemo(() => roles.map((role) => {
|
||||
const label = role.roleName || role.roleCode || String(role.roleId);
|
||||
return {
|
||||
label: (
|
||||
<Space direction="vertical" size={0}>
|
||||
<span>{label}</span>
|
||||
{role.roleCode && role.roleCode !== label && <Text type="secondary" style={{ fontSize: 12 }}>{role.roleCode}</Text>}
|
||||
</Space>
|
||||
),
|
||||
displayLabel: label,
|
||||
value: role.roleId,
|
||||
searchText: `${role.roleName || ""} ${role.roleCode || ""}`
|
||||
};
|
||||
}), [roles]);
|
||||
|
||||
const openCreate = () => {
|
||||
setEditingGrantGroup(null);
|
||||
form.resetFields();
|
||||
form.setFieldsValue({
|
||||
resourceTypes: ["OPPORTUNITY"],
|
||||
enabled: true,
|
||||
roleIds: [],
|
||||
ownerUserIds: []
|
||||
});
|
||||
setDrawerOpen(true);
|
||||
|
|
@ -261,6 +288,7 @@ export default function UserDataScopePage() {
|
|||
form.setFieldsValue({
|
||||
viewerUserId: record.viewerUserId,
|
||||
resourceTypes: record.resourceTypes,
|
||||
roleIds: [],
|
||||
ownerUserIds: record.ownerUsers.map((owner) => owner.userId),
|
||||
enabled: record.enabled,
|
||||
expireAt: record.expireAt ? dayjs(record.expireAt) : undefined,
|
||||
|
|
@ -274,6 +302,27 @@ export default function UserDataScopePage() {
|
|||
setEditingGrantGroup(null);
|
||||
};
|
||||
|
||||
const handleRoleSelectChange = async (roleIds: number[]) => {
|
||||
form.setFieldValue("roleIds", roleIds);
|
||||
if (!roleIds.length) {
|
||||
return;
|
||||
}
|
||||
const selectedViewerUserId = form.getFieldValue("viewerUserId");
|
||||
const selectedOwnerIds = new Set<number>(form.getFieldValue("ownerUserIds") || []);
|
||||
setRoleUserLoading(true);
|
||||
try {
|
||||
const roleUsers = await Promise.all(roleIds.map((roleId) => fetchUsersByRoleId(roleId)));
|
||||
roleUsers.flat().forEach((user) => {
|
||||
if (user?.userId && user.userId !== selectedViewerUserId) {
|
||||
selectedOwnerIds.add(user.userId);
|
||||
}
|
||||
});
|
||||
form.setFieldValue("ownerUserIds", Array.from(selectedOwnerIds));
|
||||
} finally {
|
||||
setRoleUserLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleSave = async () => {
|
||||
if (!selectedTenantId) {
|
||||
message.warning("请先选择租户");
|
||||
|
|
@ -469,12 +518,13 @@ export default function UserDataScopePage() {
|
|||
|
||||
<Card className="app-page__content-card user-data-scope-table-card" styles={{ body: { padding: 0 } }}>
|
||||
<Table
|
||||
className="user-data-scope-table"
|
||||
rowKey="id"
|
||||
loading={loading}
|
||||
columns={columns}
|
||||
dataSource={pagedGrantGroups}
|
||||
size="middle"
|
||||
scroll={{ y: "calc(100vh - 390px)", x: 980 }}
|
||||
scroll={{ y: "max(260px, calc(100vh - 470px))", x: 980 }}
|
||||
pagination={getStandardPagination(
|
||||
filteredGrantGroups.length,
|
||||
query.current,
|
||||
|
|
@ -506,6 +556,20 @@ export default function UserDataScopePage() {
|
|||
<Form.Item label="资源范围" name="resourceTypes" rules={[{ required: true, message: "请选择资源范围" }]}>
|
||||
<Select mode="multiple" allowClear options={resourceOptions} maxTagCount="responsive" />
|
||||
</Form.Item>
|
||||
<Form.Item label="按角色添加" name="roleIds">
|
||||
<Select
|
||||
mode="multiple"
|
||||
showSearch
|
||||
allowClear
|
||||
placeholder="选择角色后自动加入该角色下人员"
|
||||
options={roleOptions}
|
||||
loading={roleUserLoading}
|
||||
optionFilterProp="searchText"
|
||||
optionLabelProp="displayLabel"
|
||||
maxTagCount="responsive"
|
||||
onChange={handleRoleSelectChange}
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item label="可见人员" name="ownerUserIds" rules={[{ required: true, message: "请选择可见人员" }]}>
|
||||
<Select
|
||||
mode="multiple"
|
||||
|
|
|
|||
Loading…
Reference in New Issue