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;
diff --git a/react-ui/src/pages/Tracker/data.d.ts b/react-ui/src/pages/Tracker/data.d.ts
new file mode 100644
index 0000000..be71092
--- /dev/null
+++ b/react-ui/src/pages/Tracker/data.d.ts
@@ -0,0 +1,71 @@
+// data.d.ts
+
+/** 项目表 */
+export interface TrackerProject {
+  /** 项目ID */
+  projectId: number;
+  /** 项目名称 */
+  projectName: string;
+  /** 项目描述 */
+  description: string;
+  /** 项目状态(active: 激活, inactive: 不活跃) */
+  status: 'active' | 'inactive';
+  /** 创建者 */
+  createBy: string;
+  /** 创建时间 */
+  createTime: Date | null;
+  /** 更新者 */
+  updateBy: string;
+  /** 更新时间 */
+  updateTime: Date | null;
+}
+
+/** 项目与用户关联表 */
+export interface TrackerProjectUser {
+  /** 项目ID */
+  projectId: number;
+  /** 用户ID */
+  userId: number;
+  /** 角色(管理员、成员等) */
+  role: string;
+  /** 加入时间 */
+  createTime: Date;
+}
+
+/** 任务表 */
+export interface TrackerTask {
+  /** 任务ID */
+  taskId: number;
+  /** 所属项目ID */
+  projectId: number;
+  /** 任务名称 */
+  taskName: string;
+  /** 任务描述 */
+  description: string;
+  /** 分配给的用户ID */
+  assignedTo: number;
+  /** 任务状态(open: 待办, in_progress: 进行中, closed: 完成) */
+  status: 'open' | 'in_progress' | 'closed';
+  /** 任务优先级(low, medium, high) */
+  priority: 'low' | 'medium' | 'high';
+  /** 创建时间 */
+  createTime: Date | null;
+  /** 更新时间 */
+  updateTime: Date | null;
+}
+
+/** 任务日志表 */
+export interface TrackerTaskLog {
+  /** 日志ID */
+  logId: number;
+  /** 任务ID */
+  taskId: number;
+  /** 操作用户ID */
+  userId: number;
+  /** 操作类型(创建、更新、删除) */
+  action: '创建' | '更新' | '删除';
+  /** 操作描述 */
+  description: string;
+  /** 创建时间 */
+  createTime: Date | null;
+}
diff --git a/react-ui/src/pages/Tracker/service.ts b/react-ui/src/pages/Tracker/service.ts
new file mode 100644
index 0000000..c550cf4
--- /dev/null
+++ b/react-ui/src/pages/Tracker/service.ts
@@ -0,0 +1,199 @@
+import { request } from '@umijs/max';
+import type {
+  TrackerProject,
+  TrackerProjectUser,
+  TrackerTask,
+  TrackerTaskLog,
+} from '@/pages/Tracker/data';
+
+// ================================
+// 项目接口
+// ================================
+
+/** 查询项目分页列表 */
+export async function listTrackerProject(params?: TrackerProject) {
+  const queryString = params
+    ? `?${new URLSearchParams(params as Record<string, any>).toString()}`
+    : '';
+  return request(`/api/tracker/project/list${queryString}`, {
+    data: params,
+    method: 'get',
+    headers: {
+      'Content-Type': 'application/json;charset=UTF-8',
+    },
+  });
+}
+
+/** 获取单个项目详情 */
+export async function getTrackerProject(projectId: number) {
+  return request<TrackerProject>(`/api/tracker/project/${projectId}`, {
+    method: 'get',
+  });
+}
+
+/** 新增项目 */
+export async function addTrackerProject(data: TrackerProject) {
+  return request('/api/tracker/project', {
+    data,
+    method: 'post',
+  });
+}
+
+/** 更新项目 */
+export async function updateTrackerProject(data: TrackerProject) {
+  return request('/api/tracker/project', {
+    data,
+    method: 'put',
+  });
+}
+
+/** 删除项目(支持批量,传入 ID 数组) */
+export async function removeTrackerProject(projectIds: number[]) {
+  return request(`/api/tracker/project/${projectIds.join(',')}`, {
+    method: 'delete',
+  });
+}
+
+// ================================
+// 项目与用户关联接口
+// ================================
+
+/** 查询项目-用户关联分页列表 */
+export async function listTrackerProjectUser(params?: TrackerProjectUser) {
+  const queryString = params
+    ? `?${new URLSearchParams(params as Record<string, any>).toString()}`
+    : '';
+  return request(`/api/tracker/user/list${queryString}`, {
+    data: params,
+    method: 'get',
+    headers: {
+      'Content-Type': 'application/json;charset=UTF-8',
+    },
+  });
+}
+
+/** 获取单个项目-用户关联详情 */
+export async function getTrackerProjectUser(projectId: number) {
+  return request<TrackerProjectUser>(`/api/tracker/user/${projectId}`, {
+    method: 'get',
+  });
+}
+
+/** 新增项目-用户关联 */
+export async function addTrackerProjectUser(data: TrackerProjectUser) {
+  return request('/api/tracker/user', {
+    data,
+    method: 'post',
+  });
+}
+
+/** 更新项目-用户关联 */
+export async function updateTrackerProjectUser(data: TrackerProjectUser) {
+  return request('/api/tracker/user', {
+    data,
+    method: 'put',
+  });
+}
+
+/** 删除项目-用户关联(支持批量,传入项目 ID 数组) */
+export async function removeTrackerProjectUser(projectIds: number[]) {
+  return request(`/api/tracker/user/${projectIds.join(',')}`, {
+    method: 'delete',
+  });
+}
+
+// ================================
+// 任务接口
+// ================================
+
+/** 查询任务分页列表 */
+export async function listTrackerTask(params?: TrackerTask) {
+  const queryString = params
+    ? `?${new URLSearchParams(params as Record<string, any>).toString()}`
+    : '';
+  return request(`/api/tracker/task/list${queryString}`, {
+    data: params,
+    method: 'get',
+    headers: {
+      'Content-Type': 'application/json;charset=UTF-8',
+    },
+  });
+}
+
+/** 获取单个任务详情 */
+export async function getTrackerTask(taskId: number) {
+  return request<TrackerTask>(`/api/tracker/task/${taskId}`, {
+    method: 'get',
+  });
+}
+
+/** 新增任务 */
+export async function addTrackerTask(data: TrackerTask) {
+  return request('/api/tracker/task', {
+    data,
+    method: 'post',
+  });
+}
+
+/** 更新任务 */
+export async function updateTrackerTask(data: TrackerTask) {
+  return request('/api/tracker/task', {
+    data,
+    method: 'put',
+  });
+}
+
+/** 删除任务(支持批量,传入任务 ID 数组) */
+export async function removeTrackerTask(taskIds: number[]) {
+  return request(`/api/tracker/task/${taskIds.join(',')}`, {
+    method: 'delete',
+  });
+}
+
+// ================================
+// 任务日志接口
+// ================================
+
+/** 查询任务日志分页列表 */
+export async function listTrackerTaskLog(params?: TrackerTaskLog) {
+  const queryString = params
+    ? `?${new URLSearchParams(params as Record<string, any>).toString()}`
+    : '';
+  return request(`/api/tracker/log/list${queryString}`, {
+    data: params,
+    method: 'get',
+    headers: {
+      'Content-Type': 'application/json;charset=UTF-8',
+    },
+  });
+}
+
+/** 获取单个任务日志详情 */
+export async function getTrackerTaskLog(logId: number) {
+  return request<TrackerTaskLog>(`/api/tracker/log/${logId}`, {
+    method: 'get',
+  });
+}
+
+/** 新增任务日志 */
+export async function addTrackerTaskLog(data: TrackerTaskLog) {
+  return request('/api/tracker/log', {
+    data,
+    method: 'post',
+  });
+}
+
+/** 更新任务日志 */
+export async function updateTrackerTaskLog(data: TrackerTaskLog) {
+  return request('/api/tracker/log', {
+    data,
+    method: 'put',
+  });
+}
+
+/** 删除任务日志(支持批量,传入日志 ID 数组) */
+export async function removeTrackerTaskLog(logIds: number[]) {
+  return request(`/api/tracker/log/${logIds.join(',')}`, {
+    method: 'delete',
+  });
+}