Chever John 0437aa04ed
feat: initial commit for muyu-portal
Umi-based frontend portal with TypeScript config.

Made-with: Cursor
2026-02-28 15:29:12 +08:00

121 lines
4.6 KiB
TypeScript

import { PlusOutlined } from '@ant-design/icons';
import { ActionType, ProColumns, ProTable, ModalForm, ProFormText, ProFormSelect } from '@ant-design/pro-components';
import { Button, message, Popconfirm, Switch } from 'antd';
import { useRef, useState } from 'react';
import { listUsers, createUser, updateUser, deleteUser, updateUserStatus, listRoles } from '@/services/api';
const UsersPage: React.FC = () => {
const actionRef = useRef<ActionType>();
const [createOpen, setCreateOpen] = useState(false);
const [editOpen, setEditOpen] = useState(false);
const [currentRow, setCurrentRow] = useState<any>(null);
const [roles, setRoles] = useState<any[]>([]);
const fetchRoles = async () => {
const res = await listRoles({ page: 1, pageSize: 100 });
if (res?.code === 0) {
setRoles(res.data?.list?.map((r: any) => ({ label: r.roleName, value: r.roleId })) || []);
}
};
const columns: ProColumns[] = [
{ title: '用户名', dataIndex: 'username' },
{ title: '真实姓名', dataIndex: 'realName' },
{ title: '手机号', dataIndex: 'phone', search: false },
{ title: '邮箱', dataIndex: 'email', search: false },
{ title: '角色', dataIndex: 'roleName', search: false },
{
title: '状态', dataIndex: 'status', search: false,
render: (_, record) => (
<Switch
checked={record.status === 1}
onChange={async (checked) => {
const res = await updateUserStatus(record.userId, checked ? 1 : 0);
if (res?.code === 0) { message.success('状态更新成功'); actionRef.current?.reload(); }
}}
/>
),
},
{ title: '最后登录', dataIndex: 'lastLoginTime', valueType: 'dateTime', search: false },
{
title: '操作', valueType: 'option',
render: (_, record) => [
<a key="edit" onClick={() => { setCurrentRow(record); setEditOpen(true); fetchRoles(); }}></a>,
<Popconfirm key="del" title="确认删除?" onConfirm={async () => {
const res = await deleteUser(record.userId);
if (res?.code === 0) { message.success('删除成功'); actionRef.current?.reload(); }
}}>
<a style={{ color: '#ff4d4f' }}></a>
</Popconfirm>,
],
},
];
return (
<>
<ProTable
headerTitle="用户管理"
actionRef={actionRef}
rowKey="userId"
columns={columns}
request={async (params) => {
const res = await listUsers({ page: params.current, pageSize: params.pageSize, username: params.username, realName: params.realName });
return { data: res?.data?.list || [], total: res?.data?.total || 0, success: res?.code === 0 };
}}
toolBarRender={() => [
<Button key="add" type="primary" icon={<PlusOutlined />} onClick={() => { setCreateOpen(true); fetchRoles(); }}>
</Button>,
]}
/>
<ModalForm
title="新增用户"
open={createOpen}
onOpenChange={setCreateOpen}
onFinish={async (values) => {
const res = await createUser(values);
if (res?.code === 0) {
message.success('创建成功');
actionRef.current?.reload();
return true;
}
message.error(res?.msg || '创建失败');
return false;
}}
>
<ProFormText name="username" label="用户名" rules={[{ required: true }]} />
<ProFormText.Password name="password" label="密码" rules={[{ required: true, min: 6, message: '密码至少6位' }]} />
<ProFormText name="realName" label="真实姓名" rules={[{ required: true }]} />
<ProFormText name="phone" label="手机号" />
<ProFormText name="email" label="邮箱" />
<ProFormSelect name="roleId" label="角色" options={roles} rules={[{ required: true }]} />
</ModalForm>
<ModalForm
title="编辑用户"
open={editOpen}
onOpenChange={setEditOpen}
initialValues={currentRow}
onFinish={async (values) => {
const res = await updateUser(currentRow.userId, values);
if (res?.code === 0) {
message.success('更新成功');
actionRef.current?.reload();
return true;
}
message.error(res?.msg || '更新失败');
return false;
}}
>
<ProFormText name="realName" label="真实姓名" />
<ProFormText name="phone" label="手机号" />
<ProFormText name="email" label="邮箱" />
<ProFormSelect name="roleId" label="角色" options={roles} />
</ModalForm>
</>
);
};
export default UsersPage;