初步增加 web 界面
This commit is contained in:
@@ -0,0 +1,164 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import {
|
||||
Table, Button, Modal, Form, Input, Select, Tag, Popconfirm, message, Space,
|
||||
} from 'antd';
|
||||
import { PlusOutlined, EditOutlined, DeleteOutlined } from '@ant-design/icons';
|
||||
import { userApi, type UserInfo } from '../api/modules';
|
||||
|
||||
const ROLE_OPTIONS = [
|
||||
{ value: 'super_admin', label: '超级管理员' },
|
||||
{ value: 'operation', label: '运营' },
|
||||
{ value: 'support', label: '客服' },
|
||||
];
|
||||
|
||||
const ROLE_COLORS: Record<string, string> = {
|
||||
super_admin: 'red',
|
||||
operation: 'blue',
|
||||
support: 'green',
|
||||
};
|
||||
|
||||
export default function UsersPage() {
|
||||
const [users, setUsers] = useState<UserInfo[]>([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [modalOpen, setModalOpen] = useState(false);
|
||||
const [editing, setEditing] = useState<UserInfo | null>(null);
|
||||
const [form] = Form.useForm();
|
||||
|
||||
const loadUsers = async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const data = await userApi.list();
|
||||
setUsers(data);
|
||||
} catch (e: any) {
|
||||
message.error(e.message);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
loadUsers();
|
||||
}, []);
|
||||
|
||||
const handleCreate = () => {
|
||||
setEditing(null);
|
||||
form.resetFields();
|
||||
form.setFieldsValue({ role: 'support' });
|
||||
setModalOpen(true);
|
||||
};
|
||||
|
||||
const handleEdit = (user: UserInfo) => {
|
||||
setEditing(user);
|
||||
form.setFieldsValue({
|
||||
username: user.username,
|
||||
role: user.role,
|
||||
remark: user.remark,
|
||||
});
|
||||
setModalOpen(true);
|
||||
};
|
||||
|
||||
const handleSave = async () => {
|
||||
try {
|
||||
const values = await form.validateFields();
|
||||
if (editing) {
|
||||
const updateData: any = { role: values.role, remark: values.remark };
|
||||
if (values.password) updateData.password = values.password;
|
||||
await userApi.update(editing.id, updateData);
|
||||
message.success('已更新');
|
||||
} else {
|
||||
await userApi.create(values);
|
||||
message.success('已创建');
|
||||
}
|
||||
setModalOpen(false);
|
||||
loadUsers();
|
||||
} catch (e: any) {
|
||||
message.error(e.message);
|
||||
}
|
||||
};
|
||||
|
||||
const handleDelete = async (id: number) => {
|
||||
try {
|
||||
await userApi.delete(id);
|
||||
message.success('已删除');
|
||||
loadUsers();
|
||||
} catch (e: any) {
|
||||
message.error(e.message);
|
||||
}
|
||||
};
|
||||
|
||||
const columns = [
|
||||
{ title: 'ID', dataIndex: 'id', width: 60 },
|
||||
{ title: '用户名', dataIndex: 'username' },
|
||||
{
|
||||
title: '角色',
|
||||
dataIndex: 'role',
|
||||
render: (role: string) => {
|
||||
const label = ROLE_OPTIONS.find((r) => r.value === role)?.label || role;
|
||||
return <Tag color={ROLE_COLORS[role] || 'default'}>{label}</Tag>;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
dataIndex: 'is_active',
|
||||
render: (active: boolean) => active ? <Tag color="green">启用</Tag> : <Tag>禁用</Tag>,
|
||||
},
|
||||
{ title: '备注', dataIndex: 'remark' },
|
||||
{
|
||||
title: '操作',
|
||||
width: 160,
|
||||
render: (_: any, record: UserInfo) => (
|
||||
<Space>
|
||||
<Button size="small" icon={<EditOutlined />} onClick={() => handleEdit(record)}>编辑</Button>
|
||||
{record.role !== 'super_admin' && (
|
||||
<Popconfirm title="确认删除?" onConfirm={() => handleDelete(record.id)}>
|
||||
<Button danger size="small" icon={<DeleteOutlined />}>删除</Button>
|
||||
</Popconfirm>
|
||||
)}
|
||||
</Space>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div style={{ marginBottom: 16, display: 'flex', justifyContent: 'space-between' }}>
|
||||
<h2>用户管理</h2>
|
||||
<Button type="primary" icon={<PlusOutlined />} onClick={handleCreate}>新建用户</Button>
|
||||
</div>
|
||||
<Table
|
||||
columns={columns}
|
||||
dataSource={users}
|
||||
rowKey="id"
|
||||
loading={loading}
|
||||
size="small"
|
||||
pagination={{ pageSize: 20 }}
|
||||
/>
|
||||
<Modal
|
||||
title={editing ? '编辑用户' : '新建用户'}
|
||||
open={modalOpen}
|
||||
onCancel={() => setModalOpen(false)}
|
||||
onOk={handleSave}
|
||||
okText="保存"
|
||||
>
|
||||
<Form form={form} layout="vertical">
|
||||
<Form.Item name="username" label="用户名" rules={[{ required: true, message: '请输入用户名' }]}>
|
||||
<Input disabled={!!editing} />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
name="password"
|
||||
label={editing ? '新密码(留空不修改)' : '密码'}
|
||||
rules={editing ? [] : [{ required: true, message: '请输入密码' }]}
|
||||
>
|
||||
<Input.Password />
|
||||
</Form.Item>
|
||||
<Form.Item name="role" label="角色" rules={[{ required: true }]}>
|
||||
<Select options={ROLE_OPTIONS} />
|
||||
</Form.Item>
|
||||
<Form.Item name="remark" label="备注">
|
||||
<Input />
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</Modal>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user