|
@@ -1,18 +1,17 @@
|
|
|
-import { fetchProductList } from '@/services/product';
|
|
|
|
|
|
|
+import { BindRolesDrawer } from '@/pages/Admin/_shared/BindRolesDrawer';
|
|
|
|
|
+import { UserPermDrawer } from '@/pages/Admin/_shared/UserPermDrawer';
|
|
|
|
|
+import { useUserProductRoles } from '@/pages/Admin/_shared/useUserProductRoles';
|
|
|
import { fetchUpdateUserStatus, fetchUserList } from '@/services/user';
|
|
import { fetchUpdateUserStatus, fetchUserList } from '@/services/user';
|
|
|
import { ActionType, PageContainer, ProColumns, ProTable } from '@ant-design/pro-components';
|
|
import { ActionType, PageContainer, ProColumns, ProTable } from '@ant-design/pro-components';
|
|
|
import { useIntl } from '@umijs/max';
|
|
import { useIntl } from '@umijs/max';
|
|
|
-import { Button, Popconfirm, Select, Tag, message } from 'antd';
|
|
|
|
|
-import { useEffect, useRef, useState } from 'react';
|
|
|
|
|
-import { BindRolesDrawer } from './components/BindRolesDrawer';
|
|
|
|
|
|
|
+import { Button, Popconfirm, Tag, message } from 'antd';
|
|
|
|
|
+import { useMemo, useRef, useState } from 'react';
|
|
|
import { UserForm } from './components/Form';
|
|
import { UserForm } from './components/Form';
|
|
|
-import { UserPermDrawer } from './components/UserPermDrawer';
|
|
|
|
|
|
|
|
|
|
export default function UserPage() {
|
|
export default function UserPage() {
|
|
|
const intl = useIntl();
|
|
const intl = useIntl();
|
|
|
const actionRef = useRef<ActionType>();
|
|
const actionRef = useRef<ActionType>();
|
|
|
- const [products, setProducts] = useState<API.ProductItem[]>([]);
|
|
|
|
|
- const [productCode, setProductCode] = useState<string | undefined>();
|
|
|
|
|
|
|
+ const [pageUsers, setPageUsers] = useState<API.UserItem[]>([]);
|
|
|
const [rolesDrawer, setRolesDrawer] = useState<{ open: boolean; userId: number }>({
|
|
const [rolesDrawer, setRolesDrawer] = useState<{ open: boolean; userId: number }>({
|
|
|
open: false,
|
|
open: false,
|
|
|
userId: 0,
|
|
userId: 0,
|
|
@@ -21,10 +20,10 @@ export default function UserPage() {
|
|
|
open: false,
|
|
open: false,
|
|
|
userId: 0,
|
|
userId: 0,
|
|
|
});
|
|
});
|
|
|
|
|
+ const [refreshKey, setRefreshKey] = useState(0);
|
|
|
|
|
|
|
|
- useEffect(() => {
|
|
|
|
|
- fetchProductList({ pageSize: 999 }).then((res) => setProducts(res.data ?? []));
|
|
|
|
|
- }, []);
|
|
|
|
|
|
|
+ const userIds = useMemo(() => pageUsers.map((u) => u.id), [pageUsers]);
|
|
|
|
|
+ const { userProductInfo } = useUserProductRoles(userIds, refreshKey);
|
|
|
|
|
|
|
|
const handleToggleStatus = async (r: API.UserItem) => {
|
|
const handleToggleStatus = async (r: API.UserItem) => {
|
|
|
await fetchUpdateUserStatus({ id: r.id, status: r.status === 1 ? 0 : 1 });
|
|
await fetchUpdateUserStatus({ id: r.id, status: r.status === 1 ? 0 : 1 });
|
|
@@ -33,77 +32,108 @@ export default function UserPage() {
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
const columns: ProColumns<API.UserItem>[] = [
|
|
const columns: ProColumns<API.UserItem>[] = [
|
|
|
- { title: '用户名', dataIndex: 'username' },
|
|
|
|
|
- { title: '昵称', dataIndex: 'nickname' },
|
|
|
|
|
|
|
+ { title: '用户名', dataIndex: 'username', width: 200 },
|
|
|
|
|
+ { title: '昵称', dataIndex: 'nickname', width: 200 },
|
|
|
{
|
|
{
|
|
|
title: '状态',
|
|
title: '状态',
|
|
|
dataIndex: 'status',
|
|
dataIndex: 'status',
|
|
|
|
|
+ width: 80,
|
|
|
render: (_, r) => (
|
|
render: (_, r) => (
|
|
|
<Tag color={r.status === 1 ? 'success' : 'default'}>{r.status === 1 ? '启用' : '禁用'}</Tag>
|
|
<Tag color={r.status === 1 ? 'success' : 'default'}>{r.status === 1 ? '启用' : '禁用'}</Tag>
|
|
|
),
|
|
),
|
|
|
},
|
|
},
|
|
|
- { title: '创建时间', dataIndex: 'createTime', valueType: 'dateTime' },
|
|
|
|
|
|
|
+ {
|
|
|
|
|
+ title: '产品角色',
|
|
|
|
|
+ key: 'productRoles',
|
|
|
|
|
+ render: (_, r) => {
|
|
|
|
|
+ const info = userProductInfo.get(r.id) ?? [];
|
|
|
|
|
+ if (info.length === 0) return <span className="text-gray-400 text-xs">无</span>;
|
|
|
|
|
+ return (
|
|
|
|
|
+ <div className="flex flex-col gap-1">
|
|
|
|
|
+ {info.map((p) => (
|
|
|
|
|
+ <div
|
|
|
|
|
+ key={p.productName}
|
|
|
|
|
+ className="flex flex-row gap-1 rounded border border-dashed border-gray-400 bg-gray-50 px-2 py-2"
|
|
|
|
|
+ >
|
|
|
|
|
+ <Tag color="blue" className="mr-0 self-center">
|
|
|
|
|
+ {p.productName}
|
|
|
|
|
+ </Tag>
|
|
|
|
|
+ <Tag
|
|
|
|
|
+ color={p.memberType === 'ADMIN' ? 'red' : 'green'}
|
|
|
|
|
+ className="mr-0 self-center"
|
|
|
|
|
+ >
|
|
|
|
|
+ {p.memberType === 'ADMIN' ? '管理员' : '开发者'}
|
|
|
|
|
+ </Tag>
|
|
|
|
|
+ <div className="flex flex-row flex-wrap gap-1 items-center">
|
|
|
|
|
+ {p.roleNames.length > 0 ? (
|
|
|
|
|
+ p.roleNames.map((name) => (
|
|
|
|
|
+ <Tag key={name} className="mr-0">
|
|
|
|
|
+ {name}
|
|
|
|
|
+ </Tag>
|
|
|
|
|
+ ))
|
|
|
|
|
+ ) : (
|
|
|
|
|
+ <span className="text-gray-400 text-xs whitespace-nowrap">无角色</span>
|
|
|
|
|
+ )}
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ ))}
|
|
|
|
|
+ </div>
|
|
|
|
|
+ );
|
|
|
|
|
+ },
|
|
|
|
|
+ },
|
|
|
|
|
+ { title: '创建时间', dataIndex: 'createTime', valueType: 'dateTime', width: 180 },
|
|
|
{
|
|
{
|
|
|
title: '操作',
|
|
title: '操作',
|
|
|
valueType: 'option',
|
|
valueType: 'option',
|
|
|
- render: (_, r) =>
|
|
|
|
|
- [
|
|
|
|
|
- <UserForm
|
|
|
|
|
- key="edit"
|
|
|
|
|
- mode="edit"
|
|
|
|
|
- initialValues={r}
|
|
|
|
|
- trigger={<a>编辑</a>}
|
|
|
|
|
- onSuccess={() => actionRef.current?.reload()}
|
|
|
|
|
- />,
|
|
|
|
|
- <UserForm
|
|
|
|
|
- key="copy"
|
|
|
|
|
- mode="copy"
|
|
|
|
|
- initialValues={r}
|
|
|
|
|
- trigger={<a>复制</a>}
|
|
|
|
|
- onSuccess={() => actionRef.current?.reload()}
|
|
|
|
|
- />,
|
|
|
|
|
- productCode ? (
|
|
|
|
|
- <a key="roles" onClick={() => setRolesDrawer({ open: true, userId: r.id })}>
|
|
|
|
|
- 分配角色
|
|
|
|
|
- </a>
|
|
|
|
|
- ) : null,
|
|
|
|
|
- productCode ? (
|
|
|
|
|
- <a key="perms" onClick={() => setPermDrawer({ open: true, userId: r.id })}>
|
|
|
|
|
- 设置权限
|
|
|
|
|
- </a>
|
|
|
|
|
- ) : null,
|
|
|
|
|
- <Popconfirm
|
|
|
|
|
- key="status"
|
|
|
|
|
- title={r.status === 1 ? '确认冻结?' : '确认解冻?'}
|
|
|
|
|
- onConfirm={() => handleToggleStatus(r)}
|
|
|
|
|
- >
|
|
|
|
|
- <a className={r.status === 1 ? 'text-red-500' : ''}>
|
|
|
|
|
- {r.status === 1 ? '冻结' : '解冻'}
|
|
|
|
|
- </a>
|
|
|
|
|
- </Popconfirm>,
|
|
|
|
|
- ].filter(Boolean),
|
|
|
|
|
|
|
+ width: 260,
|
|
|
|
|
+ render: (_, r) => [
|
|
|
|
|
+ <UserForm
|
|
|
|
|
+ key="edit"
|
|
|
|
|
+ mode="edit"
|
|
|
|
|
+ initialValues={r}
|
|
|
|
|
+ trigger={<a>编辑</a>}
|
|
|
|
|
+ onSuccess={() => actionRef.current?.reload()}
|
|
|
|
|
+ />,
|
|
|
|
|
+ <UserForm
|
|
|
|
|
+ key="copy"
|
|
|
|
|
+ mode="copy"
|
|
|
|
|
+ initialValues={r}
|
|
|
|
|
+ trigger={<a>复制</a>}
|
|
|
|
|
+ onSuccess={() => actionRef.current?.reload()}
|
|
|
|
|
+ />,
|
|
|
|
|
+ <a key="roles" onClick={() => setRolesDrawer({ open: true, userId: r.id })}>
|
|
|
|
|
+ 分配角色
|
|
|
|
|
+ </a>,
|
|
|
|
|
+ <a key="perms" onClick={() => setPermDrawer({ open: true, userId: r.id })}>
|
|
|
|
|
+ 设置权限
|
|
|
|
|
+ </a>,
|
|
|
|
|
+ <Popconfirm
|
|
|
|
|
+ key="status"
|
|
|
|
|
+ title={r.status === 1 ? '确认冻结?' : '确认解冻?'}
|
|
|
|
|
+ onConfirm={() => handleToggleStatus(r)}
|
|
|
|
|
+ >
|
|
|
|
|
+ <a className={r.status === 1 ? 'text-red-500' : ''}>{r.status === 1 ? '冻结' : '解冻'}</a>
|
|
|
|
|
+ </Popconfirm>,
|
|
|
|
|
+ ],
|
|
|
},
|
|
},
|
|
|
];
|
|
];
|
|
|
|
|
|
|
|
return (
|
|
return (
|
|
|
<PageContainer title={intl.formatMessage({ id: 'admin.user.title' })}>
|
|
<PageContainer title={intl.formatMessage({ id: 'admin.user.title' })}>
|
|
|
- <div className="mb-3 flex items-center gap-2">
|
|
|
|
|
- <span className="text-sm text-gray-500">当前产品:</span>
|
|
|
|
|
- <Select
|
|
|
|
|
- allowClear
|
|
|
|
|
- placeholder="选择产品(用于角色/权限操作)"
|
|
|
|
|
- options={products.map((p) => ({ label: p.name, value: p.code }))}
|
|
|
|
|
- value={productCode}
|
|
|
|
|
- onChange={setProductCode}
|
|
|
|
|
- className="w-64"
|
|
|
|
|
- />
|
|
|
|
|
- </div>
|
|
|
|
|
<ProTable<API.UserItem>
|
|
<ProTable<API.UserItem>
|
|
|
actionRef={actionRef}
|
|
actionRef={actionRef}
|
|
|
columns={columns}
|
|
columns={columns}
|
|
|
rowKey="id"
|
|
rowKey="id"
|
|
|
search={false}
|
|
search={false}
|
|
|
request={fetchUserList}
|
|
request={fetchUserList}
|
|
|
|
|
+ onDataSourceChange={setPageUsers}
|
|
|
|
|
+ scroll={{ x: 1220 }}
|
|
|
|
|
+ tableLayout="fixed"
|
|
|
|
|
+ pagination={{
|
|
|
|
|
+ defaultPageSize: 20,
|
|
|
|
|
+ pageSizeOptions: [10, 20, 50, 100],
|
|
|
|
|
+ showSizeChanger: true,
|
|
|
|
|
+ }}
|
|
|
toolBarRender={() => [
|
|
toolBarRender={() => [
|
|
|
<UserForm
|
|
<UserForm
|
|
|
key="create"
|
|
key="create"
|
|
@@ -113,20 +143,15 @@ export default function UserPage() {
|
|
|
/>,
|
|
/>,
|
|
|
]}
|
|
]}
|
|
|
/>
|
|
/>
|
|
|
- {productCode && (
|
|
|
|
|
- <>
|
|
|
|
|
- <BindRolesDrawer
|
|
|
|
|
- {...rolesDrawer}
|
|
|
|
|
- productCode={productCode}
|
|
|
|
|
- onClose={() => setRolesDrawer((p) => ({ ...p, open: false }))}
|
|
|
|
|
- />
|
|
|
|
|
- <UserPermDrawer
|
|
|
|
|
- {...permDrawer}
|
|
|
|
|
- productCode={productCode}
|
|
|
|
|
- onClose={() => setPermDrawer((p) => ({ ...p, open: false }))}
|
|
|
|
|
- />
|
|
|
|
|
- </>
|
|
|
|
|
- )}
|
|
|
|
|
|
|
+ <BindRolesDrawer
|
|
|
|
|
+ {...rolesDrawer}
|
|
|
|
|
+ onClose={() => setRolesDrawer((p) => ({ ...p, open: false }))}
|
|
|
|
|
+ onSuccess={() => setRefreshKey((k) => k + 1)}
|
|
|
|
|
+ />
|
|
|
|
|
+ <UserPermDrawer
|
|
|
|
|
+ {...permDrawer}
|
|
|
|
|
+ onClose={() => setPermDrawer((p) => ({ ...p, open: false }))}
|
|
|
|
|
+ />
|
|
|
</PageContainer>
|
|
</PageContainer>
|
|
|
);
|
|
);
|
|
|
}
|
|
}
|