blob: bb058aee248c9e04c8003a59c002e4aa7f45b848 [file] [log] [blame]
86133ec55c542025-04-21 11:51:32 +08001import React, { useRef, useState } from 'react';
861332d0a1792025-04-21 20:45:00 +08002import { PlusOutlined, EditOutlined, DeleteOutlined, EyeOutlined, UploadOutlined } from '@ant-design/icons';
86133ec55c542025-04-21 11:51:32 +08003import {
4 Button,
5 Modal,
6 message,
7 Drawer,
8 Form,
9 Input,
10 InputNumber,
11 DatePicker,
12 Card,
13 Layout,
861332d0a1792025-04-21 20:45:00 +080014 Upload,
15 UploadProps,
86133ec55c542025-04-21 11:51:32 +080016} from 'antd';
861332d0a1792025-04-21 20:45:00 +080017import { ProTable, ActionType, ProColumns, ProDescriptions, ProDescriptionsItemProps } from '@ant-design/pro-components';
86133ec55c542025-04-21 11:51:32 +080018import type { BtTorrent } from './data';
19import {
20 listBtTorrent,
21 getBtTorrent,
22 addBtTorrent,
23 updateBtTorrent,
24 removeBtTorrent,
861332d0a1792025-04-21 20:45:00 +080025 uploadTorrent, // Function to handle torrent upload
86133ec55c542025-04-21 11:51:32 +080026} from './service';
27
28const { Content } = Layout;
29
30const BtTorrentPage: React.FC = () => {
31 const actionRef = useRef<ActionType>();
32 const [form] = Form.useForm();
33 const [modalVisible, setModalVisible] = useState(false);
34 const [drawerVisible, setDrawerVisible] = useState(false);
35 const [current, setCurrent] = useState<Partial<BtTorrent>>({});
861332d0a1792025-04-21 20:45:00 +080036 const [uploadModalVisible, setUploadModalVisible] = useState(false); // State for upload modal
37 const [uploadFile, setUploadFile] = useState<File | null>(null); // State to store selected file
86133ec55c542025-04-21 11:51:32 +080038
861332d0a1792025-04-21 20:45:00 +080039 // Columns for the ProTable (the table displaying torrents)
86133ec55c542025-04-21 11:51:32 +080040 const columns: ProColumns<BtTorrent>[] = [
41 {
42 title: '种子ID',
43 dataIndex: 'torrentId',
44 hideInForm: true,
45 render: (dom, entity) => (
46 <a
47 onClick={async () => {
48 const res = await getBtTorrent(entity.torrentId!);
49 setCurrent(res);
50 setDrawerVisible(true);
51 }}
52 >
53 {dom}
54 </a>
55 ),
56 },
57 { title: '名称', dataIndex: 'name' },
58 { title: 'infoHash', dataIndex: 'infoHash' },
59 { title: '大小 (bytes)', dataIndex: 'length', valueType: 'digit' },
60 { title: '分片大小', dataIndex: 'pieceLength', valueType: 'digit' },
61 { title: '片段数', dataIndex: 'piecesCount', valueType: 'digit' },
62 { title: '创建工具', dataIndex: 'createdBy', hideInSearch: true },
63 { title: '上传时间', dataIndex: 'uploadTime', valueType: 'dateTime', hideInSearch: true },
64 {
65 title: '操作',
66 valueType: 'option',
67 render: (_, record) => [
68 <Button key="view" type="link" icon={<EyeOutlined />} onClick={() => {
69 setCurrent(record);
70 setDrawerVisible(true);
71 }}>查看</Button>,
72 <Button key="edit" type="link" icon={<EditOutlined />} onClick={() => {
73 setCurrent(record);
74 form.setFieldsValue(record);
75 setModalVisible(true);
76 }}>编辑</Button>,
77 <Button key="delete" type="link" icon={<DeleteOutlined />} danger onClick={() => {
78 Modal.confirm({
79 title: '删除确认',
80 content: '确定删除该种子?',
81 onOk: async () => {
82 await removeBtTorrent([record.torrentId!]);
83 message.success('删除成功');
84 actionRef.current?.reload();
85 },
86 });
87 }}>删除</Button>,
88 ],
89 },
90 ];
91
861332d0a1792025-04-21 20:45:00 +080092 // Handle the submit for adding or updating a torrent
86133ec55c542025-04-21 11:51:32 +080093 const handleSubmit = async () => {
94 const values = await form.validateFields();
861332d0a1792025-04-21 20:45:00 +080095 try {
96 if (current?.torrentId) {
97 await updateBtTorrent({ ...current, ...values });
98 message.success('更新成功');
99 } else {
100 await addBtTorrent(values as BtTorrent);
101 message.success('新增成功');
102 }
103 setModalVisible(false);
104 form.resetFields();
105 actionRef.current?.reload();
106 } catch (error) {
107 message.error('操作失败');
86133ec55c542025-04-21 11:51:32 +0800108 }
861332d0a1792025-04-21 20:45:00 +0800109 };
110
111 // Handle file upload
112 const handleFileUpload = async (file: File) => {
113 try {
114 if (!file) {
115 throw new Error('请选择一个文件');
116 }
117
118 // Call the uploadTorrent function to upload the file
119 await uploadTorrent(file);
120
121 // Show a success message
122 message.success('文件上传成功');
123
124 // Close the upload modal
125 setUploadModalVisible(false);
126
127 // Optionally reload the table or perform other actions (e.g., refresh list)
128 actionRef.current?.reload();
129
130 } catch (error) {
131 message.error(error.message || '文件上传失败');
132 }
86133ec55c542025-04-21 11:51:32 +0800133 };
134
135 return (
136 <Content>
137 <Card bordered={false}>
138 <ProTable<BtTorrent>
139 headerTitle="种子列表"
140 actionRef={actionRef}
141 rowKey="torrentId"
142 search={{ labelWidth: 100 }}
143 toolBarRender={() => [
144 <Button
145 key="add"
146 type="primary"
147 icon={<PlusOutlined />}
148 onClick={() => {
149 form.resetFields();
150 setCurrent({});
151 setModalVisible(true);
152 }}
153 >
154 新增
155 </Button>,
861332d0a1792025-04-21 20:45:00 +0800156 <Button
157 key="upload"
158 type="primary"
159 icon={<UploadOutlined />}
160 onClick={() => setUploadModalVisible(true)} // Show the upload modal
161 >
162 上传种子文件
163 </Button>
86133ec55c542025-04-21 11:51:32 +0800164 ]}
165 request={async (params) => {
166 const res = await listBtTorrent(params);
167 return { data: res.rows || res.data || [], success: true };
168 }}
169 columns={columns}
170 />
171
172 {/* 编辑/新增弹窗 */}
173 <Modal
174 title={current?.torrentId ? '编辑种子' : '新增种子'}
175 open={modalVisible}
176 onOk={handleSubmit}
177 onCancel={() => setModalVisible(false)}
178 destroyOnClose
179 >
180 <Form form={form} layout="vertical">
181 <Form.Item name="name" label="名称" rules={[{ required: true }]}>
182 <Input />
183 </Form.Item>
184 <Form.Item name="infoHash" label="infoHash" rules={[{ required: true }]}>
185 <Input />
186 </Form.Item>
187 <Form.Item name="length" label="总大小 (bytes)" rules={[{ required: true }]}>
188 <InputNumber style={{ width: '100%' }} />
189 </Form.Item>
190 <Form.Item name="pieceLength" label="分片大小" rules={[{ required: true }]}>
191 <InputNumber style={{ width: '100%' }} />
192 </Form.Item>
193 <Form.Item name="piecesCount" label="片段数">
194 <InputNumber style={{ width: '100%' }} />
195 </Form.Item>
196 <Form.Item name="createdBy" label="创建工具">
197 <Input />
198 </Form.Item>
199 </Form>
200 </Modal>
201
861332d0a1792025-04-21 20:45:00 +0800202 {/* 上传种子文件的Modal */}
203 <Modal
204 title="上传种子文件"
205 visible={uploadModalVisible}
206 onCancel={() => setUploadModalVisible(false)}
207 footer={null}
208 >
209 <Upload
210 customRequest={({ file, onSuccess, onError }) => {
211 setUploadFile(file);
212 handleFileUpload(file);
213 onSuccess?.();
214 }}
215 showUploadList={false}
216 accept=".torrent"
217 >
218 <Button icon={<UploadOutlined />}>点击上传 .torrent 文件</Button>
219 </Upload>
220 </Modal>
221
86133ec55c542025-04-21 11:51:32 +0800222 {/* 详情抽屉 */}
223 <Drawer
224 width={500}
225 open={drawerVisible}
226 onClose={() => setDrawerVisible(false)}
227 title="种子详情"
228 >
229 {current && (
230 <ProDescriptions<BtTorrent>
231 column={1}
232 title={current.name}
233 request={async () => ({ data: current })}
234 columns={columns as ProDescriptionsItemProps<BtTorrent>[]}
235 />
236 )}
237 </Drawer>
238 </Card>
239 </Content>
240 );
241};
242
243export default BtTorrentPage;