feat: 完成 Tracker 项目与 Torrent 种子模块的前后端接口与页面开发
- 实现 Tracker 项目、任务、任务日志、项目用户关联等模块的接口封装与 ProTable 页面
- 实现 Torrent 种子主表、文件列表、Tracker 服务器、标签模块的前后端接口封装
- 支持新增、编辑、删除、详情查看等完整 CRUD 功能
- 页面基于 Ant Design Pro,支持分页、筛选、Drawer + Modal 表单展示
Change-Id: If8ead64a0bf6c177545f1c3c348ee09cad221a85
diff --git a/react-ui/src/pages/Tracker/Projects/index.tsx b/react-ui/src/pages/Tracker/Projects/index.tsx
new file mode 100644
index 0000000..b5bf106
--- /dev/null
+++ b/react-ui/src/pages/Tracker/Projects/index.tsx
@@ -0,0 +1,203 @@
+import React, { useState, useRef, useEffect } from 'react';
+import { PlusOutlined, EditOutlined, DeleteOutlined, EyeOutlined } from '@ant-design/icons';
+import {
+ Button,
+ message,
+ Drawer,
+ Modal,
+ Form,
+ Input,
+ Select,
+ DatePicker,
+ Card,
+ Layout,
+} from 'antd';
+import type { FormInstance } from 'antd';
+import {
+ ProTable,
+ ActionType,
+ ProColumns,
+ FooterToolbar,
+ ProDescriptions,
+ ProDescriptionsItemProps,
+} from '@ant-design/pro-components';
+import type { TrackerProject } from '../data.d.ts';
+import {
+ listTrackerProject,
+ getTrackerProject,
+ addTrackerProject,
+ updateTrackerProject,
+ removeTrackerProject,
+} from '../service';
+
+const { Content } = Layout;
+
+const TrackerProjectPage: React.FC = () => {
+ const actionRef = useRef<ActionType>();
+ const [detailVisible, setDetailVisible] = useState(false);
+ const [editVisible, setEditVisible] = useState(false);
+ const [current, setCurrent] = useState<TrackerProject>();
+ const [form] = Form.useForm();
+
+ const columns: ProColumns<TrackerProject>[] = [
+ {
+ title: '项目ID',
+ dataIndex: 'projectId',
+ render: (_, row) => (
+ <a
+ onClick={async () => {
+ const res = await getTrackerProject(row.projectId!);
+ setCurrent(res.data);
+ setDetailVisible(true);
+ }}
+ >
+ {row.projectId}
+ </a>
+ ),
+ },
+ { title: '项目名称', dataIndex: 'projectName' },
+ { title: '描述', dataIndex: 'description', hideInSearch: true },
+ { title: '状态', dataIndex: 'status', valueEnum: { active: { text: '激活' }, inactive: { text: '不活跃' } } },
+ { title: '创建者', dataIndex: 'createBy', hideInSearch: true },
+ { title: '创建时间', dataIndex: 'createTime', hideInSearch: true },
+ { title: '更新时间', dataIndex: 'updateTime', hideInSearch: true },
+ {
+ title: '操作',
+ valueType: 'option',
+ render: (_, row) => [
+ <Button
+ key="view"
+ type="link"
+ icon={<EyeOutlined />}
+ onClick={async () => {
+ const res = await getTrackerProject(row.projectId!);
+ setCurrent(res.data);
+ setDetailVisible(true);
+ }}
+ >
+ 查看
+ </Button>,
+ <Button
+ key="edit"
+ type="link"
+ icon={<EditOutlined />}
+ onClick={() => {
+ setCurrent(row);
+ form.setFieldsValue(row);
+ setEditVisible(true);
+ }}
+ >
+ 编辑
+ </Button>,
+ <Button
+ key="delete"
+ type="link"
+ icon={<DeleteOutlined />}
+ danger
+ onClick={() => {
+ Modal.confirm({
+ title: '删除项目',
+ content: '确认删除该项目?',
+ onOk: async () => {
+ await removeTrackerProject([row.projectId!]);
+ message.success('删除成功');
+ actionRef.current?.reload();
+ },
+ });
+ }}
+ >
+ 删除
+ </Button>,
+ ],
+ },
+ ];
+
+ /** 新增或更新 */
+ const handleSubmit = async (values: any) => {
+ if (current?.projectId) {
+ await updateTrackerProject({ ...current, ...values });
+ message.success('更新成功');
+ } else {
+ await addTrackerProject(values);
+ message.success('新增成功');
+ }
+ setEditVisible(false);
+ actionRef.current?.reload();
+ };
+
+ return (
+ <Content>
+ <Card bordered={false}>
+ <ProTable<TrackerProject>
+ headerTitle="项目列表"
+ actionRef={actionRef}
+ rowKey="projectId"
+ search={{ labelWidth: 100 }}
+ toolBarRender={() => [
+ <Button
+ key="add"
+ type="primary"
+ icon={<PlusOutlined />}
+ onClick={() => {
+ form.resetFields();
+ setCurrent(undefined);
+ setEditVisible(true);
+ }}
+ >
+ 新增
+ </Button>,
+ ]}
+ request={async (params) => {
+ const res = await listTrackerProject(params);
+ return { data: res.rows, success: true, total: res.total };
+ }}
+ columns={columns}
+ />
+
+ {/* 详情 Drawer */}
+ <Drawer
+ width={500}
+ open={detailVisible}
+ onClose={() => setDetailVisible(false)}
+ >
+ {current && (
+ <ProDescriptions<TrackerProject>
+ column={1}
+ title="项目详情"
+ dataSource={current}
+ columns={columns as ProDescriptionsItemProps<TrackerProject>[]}
+ />
+ )}
+ </Drawer>
+
+ {/* 新增/编辑 Modal */}
+ <Modal
+ title={current?.projectId ? '编辑项目' : '新增项目'}
+ open={editVisible}
+ onCancel={() => setEditVisible(false)}
+ onOk={() => {
+ form.validateFields().then(handleSubmit);
+ }}
+ >
+ <Form form={form} layout="vertical">
+ <Form.Item name="projectName" label="项目名称" rules={[{ required: true }]}>
+ <Input />
+ </Form.Item>
+ <Form.Item name="description" label="描述">
+ <Input.TextArea />
+ </Form.Item>
+ <Form.Item name="status" label="状态" initialValue="active">
+ <Select>
+ <Select.Option value="active">激活</Select.Option>
+ <Select.Option value="inactive">不活跃</Select.Option>
+ </Select>
+ </Form.Item>
+ {/* TODO: 补充其他字段 */}
+ </Form>
+ </Modal>
+ </Card>
+ </Content>
+ );
+};
+
+export default TrackerProjectPage;