| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154 |
- import { PermTree } from '@/pages/Admin/_shared/PermTree';
- import { calcUserPermDelta } from '@/pages/Admin/_shared/PermTree/lib/permUtils';
- import { fetchMemberUserProducts } from '@/services/member';
- import { fetchPermList } from '@/services/perm';
- import { fetchRoleDetail } from '@/services/role';
- import { fetchGetUserPerms, fetchSetUserPerms, fetchUserDetail } from '@/services/user';
- import { Button, Drawer, Modal, Select, Spin, message } from 'antd';
- import { useEffect, useState } from 'react';
- interface UserPermDrawerProps {
- userId: number;
- open: boolean;
- onClose: () => void;
- }
- export const UserPermDrawer = ({ userId, open, onClose }: UserPermDrawerProps) => {
- const [products, setProducts] = useState<API.UserProductItem[]>([]);
- const [productCode, setProductCode] = useState<string | undefined>();
- const [loading, setLoading] = useState(false);
- const [saving, setSaving] = useState(false);
- const [allPerms, setAllPerms] = useState<API.PermItem[]>([]);
- const [checkedIds, setCheckedIds] = useState<number[]>([]);
- const [initialCheckedIds, setInitialCheckedIds] = useState<number[]>([]);
- const [roleInheritedIds, setRoleInheritedIds] = useState<number[]>([]);
- useEffect(() => {
- if (!open) return;
- setProductCode(undefined);
- setAllPerms([]);
- setCheckedIds([]);
- setInitialCheckedIds([]);
- setRoleInheritedIds([]);
- fetchMemberUserProducts({ userId }).then((res) => {
- const list = res.data?.list ?? [];
- setProducts(list);
- if (list.length > 0) setProductCode(list[0].productCode);
- });
- }, [open]);
- useEffect(() => {
- if (!open || !productCode) return;
- setLoading(true);
- const load = async () => {
- const [userRes, permRes, userPermsRes] = await Promise.all([
- fetchUserDetail({ id: userId }),
- fetchPermList({ productCode, pageSize: 9999 }),
- fetchGetUserPerms({ userId }),
- ]);
- const perms = permRes.data ?? [];
- setAllPerms(perms);
- const permIdSet = new Set(perms.map((p: API.PermItem) => p.id));
- const userPerms = userPermsRes.data?.perms ?? [];
- const allowIds = new Set(
- userPerms
- .filter((p) => p.effect === 'ALLOW')
- .map((p) => p.permId)
- .filter((id) => permIdSet.has(id)),
- );
- const denyIds = new Set(userPerms.filter((p) => p.effect === 'DENY').map((p) => p.permId));
- const roleIds = userRes.data?.roleIds ?? [];
- const roleDetails = await Promise.all(roleIds.map((id) => fetchRoleDetail({ id })));
- const inherited = new Set<number>();
- roleDetails.forEach((r) => (r.data?.permIds ?? []).forEach((id) => inherited.add(id)));
- setRoleInheritedIds([...inherited]);
- const effective = [...inherited, ...allowIds].filter((id) => !denyIds.has(id));
- setCheckedIds([...new Set(effective)]);
- setInitialCheckedIds([...new Set(effective)]);
- };
- load().finally(() => setLoading(false));
- }, [open, userId, productCode]);
- const isDirty =
- checkedIds.length !== initialCheckedIds.length ||
- checkedIds.some((id) => !initialCheckedIds.includes(id));
- const handleProductChange = (code: string) => {
- if (productCode && isDirty) {
- Modal.confirm({
- title: '未保存的修改',
- content: '当前产品的权限设置已修改但未保存,切换将丢失修改。确认切换?',
- okText: '确认切换',
- cancelText: '取消',
- onOk: () => setProductCode(code),
- });
- return;
- }
- setProductCode(code);
- };
- const handleSave = async () => {
- setSaving(true);
- try {
- const perms = calcUserPermDelta(checkedIds, roleInheritedIds);
- await fetchSetUserPerms({ userId, perms });
- message.success('保存成功');
- onClose();
- } finally {
- setSaving(false);
- }
- };
- return (
- <Drawer
- title="设置权限"
- open={open}
- onClose={onClose}
- width={560}
- footer={
- <div className="flex justify-end gap-2">
- <Button onClick={onClose}>取消</Button>
- <Button
- type="primary"
- loading={saving}
- onClick={handleSave}
- disabled={!productCode || !isDirty}
- >
- 确定
- </Button>
- </div>
- }
- >
- {products.length === 0 ? (
- <span className="text-gray-400 text-sm">用户不属于任何产品,无法设置权限</span>
- ) : (
- <>
- <div className="mb-4">
- <Select
- placeholder="请选择产品"
- options={products.map((p) => ({ label: p.productName, value: p.productCode }))}
- value={productCode}
- onChange={handleProductChange}
- className="w-full"
- />
- </div>
- {productCode && (
- <Spin spinning={loading}>
- <PermTree
- mode="edit"
- allPerms={allPerms}
- checkedPermIds={checkedIds}
- onChange={setCheckedIds}
- />
- </Spin>
- )}
- </>
- )}
- </Drawer>
- );
- };
|