feat: 实现前端管理后台(React + Vite + Ant Design + Zustand)

This commit is contained in:
2026-06-29 17:46:41 +06:00
parent da06866360
commit c714ea95ac
21 changed files with 1193 additions and 0 deletions
+162
View File
@@ -0,0 +1,162 @@
import { useEffect, useState } from 'react';
import {
Table,
Button,
Space,
Modal,
Form,
Input,
message,
Tag,
Popconfirm,
} from 'antd';
import { PlusOutlined } from '@ant-design/icons';
import {
listAccounts,
createAccount,
deleteAccount,
switchAccount,
Account,
AccountInput,
} from '../api/accounts';
export default function AccountsPage() {
const [accounts, setAccounts] = useState<Account[]>([]);
const [loading, setLoading] = useState(false);
const [modalOpen, setModalOpen] = useState(false);
const [form] = Form.useForm();
const fetchAccounts = async () => {
setLoading(true);
try {
const data = await listAccounts();
setAccounts(data);
} finally {
setLoading(false);
}
};
useEffect(() => {
fetchAccounts();
}, []);
const handleSubmit = async (values: AccountInput) => {
try {
await createAccount(values);
message.success('账号添加成功');
setModalOpen(false);
form.resetFields();
fetchAccounts();
} catch (error) {
message.error('添加失败');
}
};
const handleDelete = async (id: string) => {
try {
await deleteAccount(id);
message.success('已删除');
fetchAccounts();
} catch (error) {
message.error('删除失败');
}
};
const handleSwitch = async (id: string) => {
try {
await switchAccount(id);
message.success('已切换当前账号');
fetchAccounts();
} catch (error) {
message.error('切换失败');
}
};
const columns = [
{ title: '名称', dataIndex: 'name' },
{ title: 'AccessKey ID', dataIndex: 'accessKeyId', ellipsis: true },
{ title: 'Region', dataIndex: 'region' },
{
title: '状态',
dataIndex: 'isActive',
render: (isActive: number) =>
isActive ? <Tag color="green">使</Tag> : <Tag></Tag>,
},
{
title: '操作',
key: 'action',
render: (_: unknown, record: Account) => (
<Space>
{!record.isActive && (
<Button type="link" onClick={() => handleSwitch(record.id)}>
</Button>
)}
<Popconfirm title="确认删除?" onConfirm={() => handleDelete(record.id)}>
<Button type="link" danger>
</Button>
</Popconfirm>
</Space>
),
},
];
return (
<div>
<div style={{ marginBottom: 16 }}>
<Button type="primary" icon={<PlusOutlined />} onClick={() => setModalOpen(true)}>
</Button>
</div>
<Table rowKey="id" columns={columns} dataSource={accounts} loading={loading} />
<Modal
title="添加阿里云 VOD 账号"
open={modalOpen}
onCancel={() => setModalOpen(false)}
footer={null}
>
<Form form={form} layout="vertical" onFinish={handleSubmit}>
<Form.Item
label="名称"
name="name"
rules={[{ required: true, message: '请输入名称' }]}
>
<Input placeholder="用于区分不同账号" />
</Form.Item>
<Form.Item
label="AccessKey ID"
name="accessKeyId"
rules={[{ required: true, message: '请输入 AccessKey ID' }]}
>
<Input />
</Form.Item>
<Form.Item
label="AccessKey Secret"
name="accessKeySecret"
rules={[{ required: true, message: '请输入 AccessKey Secret' }]}
>
<Input.Password />
</Form.Item>
<Form.Item
label="Region"
name="region"
rules={[{ required: true, message: '请输入 Region' }]}
>
<Input placeholder="如 cn-shanghai" />
</Form.Item>
<Form.Item label="Endpoint(可选)" name="endpoint">
<Input placeholder="默认 vod.{region}.aliyuncs.com" />
</Form.Item>
<Form.Item>
<Button type="primary" htmlType="submit" block>
</Button>
</Form.Item>
</Form>
</Modal>
</div>
);
}