BirdNETM | b0f7153 | 2025-05-26 17:37:33 +0800 | [diff] [blame] | 1 | import React, { useRef, useState, useEffect } from 'react'; |
| 2 | import { PlusOutlined, EditOutlined, DeleteOutlined, EyeOutlined, UploadOutlined, DownloadOutlined, CommentOutlined } from '@ant-design/icons'; |
86133 | ec55c54 | 2025-04-21 11:51:32 +0800 | [diff] [blame] | 3 | import { |
| 4 | Button, |
| 5 | Modal, |
| 6 | message, |
| 7 | Drawer, |
| 8 | Form, |
| 9 | Input, |
| 10 | InputNumber, |
| 11 | DatePicker, |
| 12 | Card, |
| 13 | Layout, |
86133 | 2d0a179 | 2025-04-21 20:45:00 +0800 | [diff] [blame] | 14 | Upload, |
| 15 | UploadProps, |
BirdNETM | b0f7153 | 2025-05-26 17:37:33 +0800 | [diff] [blame] | 16 | Select, |
| 17 | Tag, // 导入Tag组件用于显示标签 |
86133 | ec55c54 | 2025-04-21 11:51:32 +0800 | [diff] [blame] | 18 | } from 'antd'; |
86133 | 2d0a179 | 2025-04-21 20:45:00 +0800 | [diff] [blame] | 19 | import { ProTable, ActionType, ProColumns, ProDescriptions, ProDescriptionsItemProps } from '@ant-design/pro-components'; |
BirdNETM | b0f7153 | 2025-05-26 17:37:33 +0800 | [diff] [blame] | 20 | import { useNavigate } from 'react-router-dom'; |
| 21 | import type { BtTorrent, BtTorrentTag } from './data'; |
86133 | ec55c54 | 2025-04-21 11:51:32 +0800 | [diff] [blame] | 22 | import { |
| 23 | listBtTorrent, |
| 24 | getBtTorrent, |
| 25 | addBtTorrent, |
| 26 | updateBtTorrent, |
| 27 | removeBtTorrent, |
BirdNETM | b0f7153 | 2025-05-26 17:37:33 +0800 | [diff] [blame] | 28 | uploadTorrent, |
| 29 | downloadTorrent, |
| 30 | addBtTorrentTag, |
| 31 | listBtTorrentTags, |
| 32 | getBtTorrentTag |
86133 | ec55c54 | 2025-04-21 11:51:32 +0800 | [diff] [blame] | 33 | } from './service'; |
| 34 | |
| 35 | const { Content } = Layout; |
| 36 | |
| 37 | const BtTorrentPage: React.FC = () => { |
BirdNETM | b0f7153 | 2025-05-26 17:37:33 +0800 | [diff] [blame] | 38 | const navigate = useNavigate(); |
86133 | ec55c54 | 2025-04-21 11:51:32 +0800 | [diff] [blame] | 39 | const actionRef = useRef<ActionType>(); |
| 40 | const [form] = Form.useForm(); |
| 41 | const [modalVisible, setModalVisible] = useState(false); |
| 42 | const [drawerVisible, setDrawerVisible] = useState(false); |
| 43 | const [current, setCurrent] = useState<Partial<BtTorrent>>({}); |
86133 | 2d0a179 | 2025-04-21 20:45:00 +0800 | [diff] [blame] | 44 | const [uploadModalVisible, setUploadModalVisible] = useState(false); // State for upload modal |
| 45 | const [uploadFile, setUploadFile] = useState<File | null>(null); // State to store selected file |
BirdNETM | b0f7153 | 2025-05-26 17:37:33 +0800 | [diff] [blame] | 46 | const [uploadForm] = Form.useForm(); // Form for upload modal |
| 47 | const [torrentTags, setTorrentTags] = useState<BtTorrentTag[]>([]); // 修改为数组类型来存储多个标签 |
BirdNETM | 2b78925 | 2025-06-03 18:08:04 +0800 | [diff] [blame] | 48 | const [tagModalVisible, setTagModalVisible] = useState(false); |
| 49 | const [currentTorrent, setCurrentTorrent] = useState<BtTorrent | null>(null); |
| 50 | const [tagForm] = Form.useForm(); |
86133 | ec55c54 | 2025-04-21 11:51:32 +0800 | [diff] [blame] | 51 | |
86133 | 2d0a179 | 2025-04-21 20:45:00 +0800 | [diff] [blame] | 52 | // Columns for the ProTable (the table displaying torrents) |
86133 | ec55c54 | 2025-04-21 11:51:32 +0800 | [diff] [blame] | 53 | const columns: ProColumns<BtTorrent>[] = [ |
| 54 | { |
| 55 | title: '种子ID', |
| 56 | dataIndex: 'torrentId', |
86133 | ec55c54 | 2025-04-21 11:51:32 +0800 | [diff] [blame] | 57 | render: (dom, entity) => ( |
| 58 | <a |
| 59 | onClick={async () => { |
BirdNETM | b0f7153 | 2025-05-26 17:37:33 +0800 | [diff] [blame] | 60 | try { |
| 61 | // 获取详细信息 |
| 62 | const res = await getBtTorrent(entity.torrentId!); |
| 63 | console.log('获取的种子详情:', res); // 调试用 |
| 64 | |
| 65 | // 确保res是对象类型并且包含数据 |
| 66 | if (res && typeof res === 'object') { |
| 67 | // 如果API返回了data包装,则提取data |
| 68 | const torrentData = res.data ? res.data : res; |
| 69 | setCurrent(torrentData); |
| 70 | |
| 71 | // 先设置当前种子,然后获取标签 |
| 72 | await handleGetTags(entity.torrentId!); |
| 73 | setDrawerVisible(true); |
| 74 | } else { |
| 75 | message.error('获取种子详情格式错误'); |
| 76 | } |
| 77 | } catch (error) { |
| 78 | console.error('获取种子详情出错:', error); |
| 79 | message.error('获取种子详情失败'); |
| 80 | } |
86133 | ec55c54 | 2025-04-21 11:51:32 +0800 | [diff] [blame] | 81 | }} |
| 82 | > |
| 83 | {dom} |
| 84 | </a> |
| 85 | ), |
| 86 | }, |
| 87 | { title: '名称', dataIndex: 'name' }, |
BirdNETM | b0f7153 | 2025-05-26 17:37:33 +0800 | [diff] [blame] | 88 | // { title: 'infoHash', dataIndex: 'infoHash' }, |
86133 | ec55c54 | 2025-04-21 11:51:32 +0800 | [diff] [blame] | 89 | { title: '大小 (bytes)', dataIndex: 'length', valueType: 'digit' }, |
BirdNETM | b0f7153 | 2025-05-26 17:37:33 +0800 | [diff] [blame] | 90 | // { title: '分片大小', dataIndex: 'pieceLength', valueType: 'digit' }, |
| 91 | // { title: '片段数', dataIndex: 'piecesCount', valueType: 'digit' }, |
| 92 | { title: '创建人', dataIndex: 'createdBy', hideInSearch: true }, |
86133 | ec55c54 | 2025-04-21 11:51:32 +0800 | [diff] [blame] | 93 | { title: '上传时间', dataIndex: 'uploadTime', valueType: 'dateTime', hideInSearch: true }, |
| 94 | { |
| 95 | title: '操作', |
| 96 | valueType: 'option', |
| 97 | render: (_, record) => [ |
BirdNETM | b0f7153 | 2025-05-26 17:37:33 +0800 | [diff] [blame] | 98 | <Button key="view" type="link" icon={<EyeOutlined />} onClick={async () => { |
| 99 | try { |
| 100 | // 获取详细信息 |
| 101 | const res = await getBtTorrent(record.torrentId!); |
| 102 | console.log('获取的种子详情:', res); // 调试用 |
| 103 | |
| 104 | // 确保res是对象类型并且包含数据 |
| 105 | if (res && typeof res === 'object') { |
| 106 | // 如果API返回了data包装,则提取data |
| 107 | const torrentData = res.data ? res.data : res; |
| 108 | setCurrent(torrentData); |
| 109 | |
| 110 | // 获取标签 |
| 111 | await handleGetTags(record.torrentId!); |
| 112 | setDrawerVisible(true); |
| 113 | } else { |
| 114 | message.error('获取种子详情格式错误'); |
| 115 | } |
| 116 | } catch (error) { |
| 117 | console.error('获取种子详情出错:', error); |
| 118 | message.error('获取详情失败'); |
| 119 | } |
86133 | ec55c54 | 2025-04-21 11:51:32 +0800 | [diff] [blame] | 120 | }}>查看</Button>, |
BirdNETM | b0f7153 | 2025-05-26 17:37:33 +0800 | [diff] [blame] | 121 | <Button key="download" type="link" icon={<DownloadOutlined />} onClick={async () => { |
| 122 | try { |
| 123 | const blob = await downloadTorrent(record.torrentId!); |
| 124 | const url = window.URL.createObjectURL(blob); |
| 125 | const link = document.createElement('a'); |
| 126 | link.href = url; |
86133 | a611b01 | 2025-06-07 22:11:57 +0800 | [diff] [blame] | 127 | link.download = `${record.name}`; |
BirdNETM | b0f7153 | 2025-05-26 17:37:33 +0800 | [diff] [blame] | 128 | document.body.appendChild(link); |
| 129 | link.click(); |
| 130 | document.body.removeChild(link); |
| 131 | window.URL.revokeObjectURL(url); |
| 132 | message.success('下载成功'); |
| 133 | } catch (error: any) { |
| 134 | message.error('下载失败'); |
| 135 | } |
| 136 | }}>下载</Button>, |
BirdNETM | 2b78925 | 2025-06-03 18:08:04 +0800 | [diff] [blame] | 137 | <Button key="tags" type="link" onClick={() => { |
| 138 | setCurrentTorrent(record); |
| 139 | handleGetTags(record.torrentId!); |
| 140 | setTagModalVisible(true); |
| 141 | }}>设置标签</Button>, |
BirdNETM | b0f7153 | 2025-05-26 17:37:33 +0800 | [diff] [blame] | 142 | |
86133 | ec55c54 | 2025-04-21 11:51:32 +0800 | [diff] [blame] | 143 | ], |
| 144 | }, |
| 145 | ]; |
| 146 | |
86133 | 2d0a179 | 2025-04-21 20:45:00 +0800 | [diff] [blame] | 147 | // Handle the submit for adding or updating a torrent |
86133 | ec55c54 | 2025-04-21 11:51:32 +0800 | [diff] [blame] | 148 | const handleSubmit = async () => { |
| 149 | const values = await form.validateFields(); |
86133 | 2d0a179 | 2025-04-21 20:45:00 +0800 | [diff] [blame] | 150 | try { |
| 151 | if (current?.torrentId) { |
| 152 | await updateBtTorrent({ ...current, ...values }); |
| 153 | message.success('更新成功'); |
| 154 | } else { |
| 155 | await addBtTorrent(values as BtTorrent); |
| 156 | message.success('新增成功'); |
| 157 | } |
| 158 | setModalVisible(false); |
| 159 | form.resetFields(); |
| 160 | actionRef.current?.reload(); |
| 161 | } catch (error) { |
| 162 | message.error('操作失败'); |
86133 | ec55c54 | 2025-04-21 11:51:32 +0800 | [diff] [blame] | 163 | } |
86133 | 2d0a179 | 2025-04-21 20:45:00 +0800 | [diff] [blame] | 164 | }; |
| 165 | |
| 166 | // Handle file upload |
| 167 | const handleFileUpload = async (file: File) => { |
| 168 | try { |
| 169 | if (!file) { |
| 170 | throw new Error('请选择一个文件'); |
| 171 | } |
| 172 | |
BirdNETM | b0f7153 | 2025-05-26 17:37:33 +0800 | [diff] [blame] | 173 | const values = await uploadForm.validateFields(); |
| 174 | console.log(file); |
| 175 | // Call the uploadTorrent function to upload the file with additional info |
86133 | 2d0a179 | 2025-04-21 20:45:00 +0800 | [diff] [blame] | 176 | await uploadTorrent(file); |
| 177 | |
| 178 | // Show a success message |
| 179 | message.success('文件上传成功'); |
| 180 | |
BirdNETM | b0f7153 | 2025-05-26 17:37:33 +0800 | [diff] [blame] | 181 | // Close the upload modal and reset form |
86133 | 2d0a179 | 2025-04-21 20:45:00 +0800 | [diff] [blame] | 182 | setUploadModalVisible(false); |
BirdNETM | b0f7153 | 2025-05-26 17:37:33 +0800 | [diff] [blame] | 183 | uploadForm.resetFields(); |
86133 | 2d0a179 | 2025-04-21 20:45:00 +0800 | [diff] [blame] | 184 | |
BirdNETM | b0f7153 | 2025-05-26 17:37:33 +0800 | [diff] [blame] | 185 | // Reload the table |
86133 | 2d0a179 | 2025-04-21 20:45:00 +0800 | [diff] [blame] | 186 | actionRef.current?.reload(); |
| 187 | |
| 188 | } catch (error) { |
| 189 | message.error(error.message || '文件上传失败'); |
| 190 | } |
86133 | ec55c54 | 2025-04-21 11:51:32 +0800 | [diff] [blame] | 191 | }; |
| 192 | |
BirdNETM | b0f7153 | 2025-05-26 17:37:33 +0800 | [diff] [blame] | 193 | // 修改获取标签的函数,处理API特定的响应格式 |
| 194 | const handleGetTags = async (id: number) => { |
| 195 | try { |
| 196 | // 根据API的响应格式,获取rows数组中的标签 |
| 197 | const response = await listBtTorrentTags({ torrentId: id }); |
| 198 | console.log('API标签响应:', response); |
| 199 | |
| 200 | // 检查响应格式并提取rows数组 |
| 201 | if (response && response.rows && Array.isArray(response.rows)) { |
| 202 | setTorrentTags(response.rows); |
| 203 | console.log('设置标签:', response.rows); |
| 204 | } else { |
| 205 | console.log('未找到标签或格式不符'); |
| 206 | setTorrentTags([]); |
| 207 | } |
| 208 | } catch (error) { |
| 209 | console.error('获取标签失败:', error); |
| 210 | message.error('获取标签失败'); |
| 211 | setTorrentTags([]); |
| 212 | } |
| 213 | }; |
| 214 | |
| 215 | useEffect(() => { |
| 216 | if (current?.torrentId) { |
| 217 | handleGetTags(current.torrentId); |
| 218 | } else { |
| 219 | setTorrentTags([]); // 清空标签当没有选中种子时 |
| 220 | } |
| 221 | }, [current]); |
| 222 | |
| 223 | // 渲染标签列表的函数 |
| 224 | const renderTags = () => { |
| 225 | if (!torrentTags || torrentTags.length === 0) { |
| 226 | return <span style={{ color: '#999' }}>暂无标签</span>; |
| 227 | } |
| 228 | |
| 229 | // 定义一些可能的标签颜色 |
| 230 | const tagColors = ['blue', 'green', 'cyan', 'purple', 'magenta', 'orange', 'gold', 'lime']; |
| 231 | |
| 232 | return ( |
| 233 | <div style={{ display: 'flex', flexWrap: 'wrap', gap: '8px' }}> |
| 234 | {torrentTags.map((tag, index) => { |
| 235 | // 根据索引轮换颜色 |
| 236 | const colorIndex = index % tagColors.length; |
| 237 | return ( |
| 238 | <Tag |
| 239 | key={tag.id || tag.torrentId || index} |
| 240 | color={tagColors[colorIndex]} |
| 241 | style={{ margin: '0 4px 4px 0', padding: '2px 8px' }} |
| 242 | > |
| 243 | {tag.tag} |
| 244 | </Tag> |
| 245 | ); |
| 246 | })} |
| 247 | </div> |
| 248 | ); |
| 249 | }; |
| 250 | |
86133 | ec55c54 | 2025-04-21 11:51:32 +0800 | [diff] [blame] | 251 | return ( |
| 252 | <Content> |
| 253 | <Card bordered={false}> |
| 254 | <ProTable<BtTorrent> |
| 255 | headerTitle="种子列表" |
| 256 | actionRef={actionRef} |
| 257 | rowKey="torrentId" |
| 258 | search={{ labelWidth: 100 }} |
| 259 | toolBarRender={() => [ |
| 260 | <Button |
86133 | 2d0a179 | 2025-04-21 20:45:00 +0800 | [diff] [blame] | 261 | key="upload" |
| 262 | type="primary" |
| 263 | icon={<UploadOutlined />} |
BirdNETM | b0f7153 | 2025-05-26 17:37:33 +0800 | [diff] [blame] | 264 | onClick={() => setUploadModalVisible(true)} |
86133 | 2d0a179 | 2025-04-21 20:45:00 +0800 | [diff] [blame] | 265 | > |
| 266 | 上传种子文件 |
| 267 | </Button> |
86133 | ec55c54 | 2025-04-21 11:51:32 +0800 | [diff] [blame] | 268 | ]} |
| 269 | request={async (params) => { |
| 270 | const res = await listBtTorrent(params); |
| 271 | return { data: res.rows || res.data || [], success: true }; |
| 272 | }} |
| 273 | columns={columns} |
| 274 | /> |
| 275 | |
| 276 | {/* 编辑/新增弹窗 */} |
| 277 | <Modal |
| 278 | title={current?.torrentId ? '编辑种子' : '新增种子'} |
| 279 | open={modalVisible} |
| 280 | onOk={handleSubmit} |
| 281 | onCancel={() => setModalVisible(false)} |
| 282 | destroyOnClose |
| 283 | > |
| 284 | <Form form={form} layout="vertical"> |
| 285 | <Form.Item name="name" label="名称" rules={[{ required: true }]}> |
| 286 | <Input /> |
| 287 | </Form.Item> |
| 288 | <Form.Item name="infoHash" label="infoHash" rules={[{ required: true }]}> |
| 289 | <Input /> |
| 290 | </Form.Item> |
| 291 | <Form.Item name="length" label="总大小 (bytes)" rules={[{ required: true }]}> |
| 292 | <InputNumber style={{ width: '100%' }} /> |
| 293 | </Form.Item> |
| 294 | <Form.Item name="pieceLength" label="分片大小" rules={[{ required: true }]}> |
| 295 | <InputNumber style={{ width: '100%' }} /> |
| 296 | </Form.Item> |
| 297 | <Form.Item name="piecesCount" label="片段数"> |
| 298 | <InputNumber style={{ width: '100%' }} /> |
| 299 | </Form.Item> |
| 300 | <Form.Item name="createdBy" label="创建工具"> |
| 301 | <Input /> |
| 302 | </Form.Item> |
| 303 | </Form> |
| 304 | </Modal> |
| 305 | |
86133 | 2d0a179 | 2025-04-21 20:45:00 +0800 | [diff] [blame] | 306 | {/* 上传种子文件的Modal */} |
| 307 | <Modal |
| 308 | title="上传种子文件" |
BirdNETM | b0f7153 | 2025-05-26 17:37:33 +0800 | [diff] [blame] | 309 | open={uploadModalVisible} |
| 310 | onCancel={() => { |
| 311 | setUploadModalVisible(false); |
| 312 | uploadForm.resetFields(); |
| 313 | }} |
| 314 | onOk={() => { |
| 315 | if (uploadFile) { |
| 316 | handleFileUpload(uploadFile); |
| 317 | } else { |
| 318 | message.error('请选择文件'); |
| 319 | } |
| 320 | }} |
86133 | 2d0a179 | 2025-04-21 20:45:00 +0800 | [diff] [blame] | 321 | > |
BirdNETM | b0f7153 | 2025-05-26 17:37:33 +0800 | [diff] [blame] | 322 | <Form form={uploadForm} layout="vertical"> |
| 323 | <Form.Item |
| 324 | name="file" |
| 325 | label="种子文件" |
| 326 | rules={[{ required: true, message: '请选择种子文件' }]} |
| 327 | > |
| 328 | <Upload |
| 329 | customRequest={({ file, onSuccess }) => { |
| 330 | setUploadFile(file as File); |
| 331 | onSuccess?.(); |
| 332 | }} |
| 333 | showUploadList={true} |
| 334 | maxCount={1} |
| 335 | accept=".torrent" |
| 336 | onRemove={() => setUploadFile(null)} |
| 337 | > |
| 338 | <Button icon={<UploadOutlined />}>选择 .torrent 文件</Button> |
| 339 | </Upload> |
| 340 | </Form.Item> |
BirdNETM | 2b78925 | 2025-06-03 18:08:04 +0800 | [diff] [blame] | 341 | |
BirdNETM | b0f7153 | 2025-05-26 17:37:33 +0800 | [diff] [blame] | 342 | </Form> |
86133 | 2d0a179 | 2025-04-21 20:45:00 +0800 | [diff] [blame] | 343 | </Modal> |
| 344 | |
86133 | ec55c54 | 2025-04-21 11:51:32 +0800 | [diff] [blame] | 345 | {/* 详情抽屉 */} |
| 346 | <Drawer |
BirdNETM | b0f7153 | 2025-05-26 17:37:33 +0800 | [diff] [blame] | 347 | width={600} |
86133 | ec55c54 | 2025-04-21 11:51:32 +0800 | [diff] [blame] | 348 | open={drawerVisible} |
| 349 | onClose={() => setDrawerVisible(false)} |
| 350 | title="种子详情" |
BirdNETM | b0f7153 | 2025-05-26 17:37:33 +0800 | [diff] [blame] | 351 | extra={ |
| 352 | <Button |
| 353 | type="primary" |
| 354 | icon={<CommentOutlined />} |
| 355 | onClick={() => navigate(`/torrent/comments/${current.torrentId}`)} |
| 356 | > |
| 357 | 查看评论 |
| 358 | </Button> |
| 359 | } |
86133 | ec55c54 | 2025-04-21 11:51:32 +0800 | [diff] [blame] | 360 | > |
| 361 | {current && ( |
BirdNETM | b0f7153 | 2025-05-26 17:37:33 +0800 | [diff] [blame] | 362 | <> |
| 363 | {/* 不要使用request属性,直接使用dataSource */} |
| 364 | <ProDescriptions<BtTorrent> |
| 365 | column={1} |
| 366 | title={current.name} |
| 367 | dataSource={current} |
| 368 | columns={[ |
| 369 | { |
| 370 | title: '种子ID', |
| 371 | dataIndex: 'torrentId', |
| 372 | valueType: 'text' |
| 373 | }, |
| 374 | { |
| 375 | title: '名称', |
| 376 | dataIndex: 'name', |
| 377 | valueType: 'text' |
| 378 | }, |
| 379 | { |
| 380 | title: 'infoHash', |
| 381 | dataIndex: 'infoHash', |
| 382 | valueType: 'text', |
| 383 | copyable: true |
| 384 | }, |
| 385 | { |
| 386 | title: '大小 (bytes)', |
| 387 | dataIndex: 'length', |
| 388 | valueType: 'digit', |
| 389 | |
| 390 | }, |
| 391 | { |
| 392 | title: '分片大小', |
| 393 | dataIndex: 'pieceLength', |
| 394 | valueType: 'digit' |
| 395 | }, |
| 396 | { |
| 397 | title: '片段数', |
| 398 | dataIndex: 'piecesCount', |
| 399 | valueType: 'digit' |
| 400 | }, |
| 401 | { |
| 402 | title: '创建人', |
| 403 | dataIndex: 'createdBy', |
| 404 | valueType: 'text' |
| 405 | }, |
| 406 | { |
| 407 | title: '上传时间', |
| 408 | dataIndex: 'uploadTime', |
| 409 | valueType: 'dateTime' |
| 410 | }, |
| 411 | { |
| 412 | title: '标签', |
| 413 | dataIndex: 'tags', |
| 414 | render: () => renderTags() |
| 415 | } |
| 416 | ] as ProDescriptionsItemProps<BtTorrent>[]} |
| 417 | /> |
| 418 | |
| 419 | {/* 如果需要显示额外信息,可以在这里添加 */} |
| 420 | {current.description && ( |
| 421 | <div style={{ marginTop: 16 }}> |
| 422 | <h3>介绍</h3> |
| 423 | <p>{current.description}</p> |
| 424 | </div> |
| 425 | )} |
| 426 | |
| 427 | {/* 添加调试信息 - 开发时使用,生产环境可以移除 */} |
| 428 | {/* <div style={{ marginTop: 20, background: '#f5f5f5', padding: 10, borderRadius: 4 }}> |
| 429 | <h4>调试信息:</h4> |
| 430 | <p>当前种子ID: {current.torrentId}</p> |
| 431 | <p>标签数量: {torrentTags?.length || 0}</p> |
| 432 | <details> |
| 433 | <summary>查看完整数据</summary> |
| 434 | <pre style={{ maxHeight: 200, overflow: 'auto' }}>{JSON.stringify(current, null, 2)}</pre> |
| 435 | <h5>标签数据:</h5> |
| 436 | <pre style={{ maxHeight: 200, overflow: 'auto' }}>{JSON.stringify(torrentTags, null, 2)}</pre> |
| 437 | </details> |
| 438 | </div> */} |
| 439 | </> |
86133 | ec55c54 | 2025-04-21 11:51:32 +0800 | [diff] [blame] | 440 | )} |
| 441 | </Drawer> |
BirdNETM | 2b78925 | 2025-06-03 18:08:04 +0800 | [diff] [blame] | 442 | |
| 443 | {/* 设置标签的Modal */} |
| 444 | <Modal |
| 445 | title="设置标签" |
| 446 | open={tagModalVisible} |
| 447 | onCancel={() => { |
| 448 | setTagModalVisible(false); |
| 449 | tagForm.resetFields(); |
| 450 | }} |
| 451 | onOk={async () => { |
| 452 | try { |
| 453 | const values = await tagForm.validateFields(); |
| 454 | if (currentTorrent?.torrentId && values.tags) { |
| 455 | // 添加新标签 |
| 456 | for (const tag of values.tags) { |
| 457 | await addBtTorrentTag({ |
| 458 | torrentId: currentTorrent.torrentId, |
| 459 | tag: tag |
| 460 | }); |
| 461 | } |
| 462 | message.success('标签设置成功'); |
| 463 | setTagModalVisible(false); |
| 464 | tagForm.resetFields(); |
| 465 | // 刷新标签列表 |
| 466 | if (currentTorrent.torrentId === current?.torrentId) { |
| 467 | handleGetTags(currentTorrent.torrentId); |
| 468 | } |
| 469 | } |
| 470 | } catch (error) { |
| 471 | message.error('设置标签失败'); |
| 472 | } |
| 473 | }} |
| 474 | > |
| 475 | <Form form={tagForm} layout="vertical"> |
| 476 | <Form.Item |
| 477 | name="tags" |
| 478 | label="标签" |
| 479 | rules={[{ required: true, message: '请输入标签' }]} |
| 480 | > |
| 481 | <Select |
| 482 | mode="tags" |
| 483 | style={{ width: '100%' }} |
| 484 | placeholder="请输入标签,按回车键确认" |
| 485 | tokenSeparators={[',']} |
| 486 | /> |
| 487 | </Form.Item> |
| 488 | </Form> |
| 489 | </Modal> |
86133 | ec55c54 | 2025-04-21 11:51:32 +0800 | [diff] [blame] | 490 | </Card> |
| 491 | </Content> |
| 492 | ); |
| 493 | }; |
| 494 | |
86133 | a611b01 | 2025-06-07 22:11:57 +0800 | [diff] [blame] | 495 | export default BtTorrentPage; |