| import React, { useRef, useState } from 'react'; |
| import { PlusOutlined, EditOutlined, DeleteOutlined, EyeOutlined, UploadOutlined } from '@ant-design/icons'; |
| import { |
| Button, |
| Modal, |
| message, |
| Drawer, |
| Form, |
| Input, |
| InputNumber, |
| DatePicker, |
| Card, |
| Layout, |
| Upload, |
| UploadProps, |
| } from 'antd'; |
| import { ProTable, ActionType, ProColumns, ProDescriptions, ProDescriptionsItemProps } from '@ant-design/pro-components'; |
| import type { BtTorrent } from './data'; |
| import { |
| listBtTorrent, |
| getBtTorrent, |
| addBtTorrent, |
| updateBtTorrent, |
| removeBtTorrent, |
| uploadTorrent, // Function to handle torrent upload |
| } from './service'; |
| |
| const { Content } = Layout; |
| |
| const BtTorrentPage: React.FC = () => { |
| const actionRef = useRef<ActionType>(); |
| const [form] = Form.useForm(); |
| const [modalVisible, setModalVisible] = useState(false); |
| const [drawerVisible, setDrawerVisible] = useState(false); |
| const [current, setCurrent] = useState<Partial<BtTorrent>>({}); |
| const [uploadModalVisible, setUploadModalVisible] = useState(false); // State for upload modal |
| const [uploadFile, setUploadFile] = useState<File | null>(null); // State to store selected file |
| |
| // Columns for the ProTable (the table displaying torrents) |
| const columns: ProColumns<BtTorrent>[] = [ |
| { |
| title: '种子ID', |
| dataIndex: 'torrentId', |
| hideInForm: true, |
| render: (dom, entity) => ( |
| <a |
| onClick={async () => { |
| const res = await getBtTorrent(entity.torrentId!); |
| setCurrent(res); |
| setDrawerVisible(true); |
| }} |
| > |
| {dom} |
| </a> |
| ), |
| }, |
| { title: '名称', dataIndex: 'name' }, |
| { title: 'infoHash', dataIndex: 'infoHash' }, |
| { title: '大小 (bytes)', dataIndex: 'length', valueType: 'digit' }, |
| { title: '分片大小', dataIndex: 'pieceLength', valueType: 'digit' }, |
| { title: '片段数', dataIndex: 'piecesCount', valueType: 'digit' }, |
| { title: '创建工具', dataIndex: 'createdBy', hideInSearch: true }, |
| { title: '上传时间', dataIndex: 'uploadTime', valueType: 'dateTime', hideInSearch: true }, |
| { |
| title: '操作', |
| valueType: 'option', |
| render: (_, record) => [ |
| <Button key="view" type="link" icon={<EyeOutlined />} onClick={() => { |
| setCurrent(record); |
| setDrawerVisible(true); |
| }}>查看</Button>, |
| <Button key="edit" type="link" icon={<EditOutlined />} onClick={() => { |
| setCurrent(record); |
| form.setFieldsValue(record); |
| setModalVisible(true); |
| }}>编辑</Button>, |
| <Button key="delete" type="link" icon={<DeleteOutlined />} danger onClick={() => { |
| Modal.confirm({ |
| title: '删除确认', |
| content: '确定删除该种子?', |
| onOk: async () => { |
| await removeBtTorrent([record.torrentId!]); |
| message.success('删除成功'); |
| actionRef.current?.reload(); |
| }, |
| }); |
| }}>删除</Button>, |
| ], |
| }, |
| ]; |
| |
| // Handle the submit for adding or updating a torrent |
| const handleSubmit = async () => { |
| const values = await form.validateFields(); |
| try { |
| if (current?.torrentId) { |
| await updateBtTorrent({ ...current, ...values }); |
| message.success('更新成功'); |
| } else { |
| await addBtTorrent(values as BtTorrent); |
| message.success('新增成功'); |
| } |
| setModalVisible(false); |
| form.resetFields(); |
| actionRef.current?.reload(); |
| } catch (error) { |
| message.error('操作失败'); |
| } |
| }; |
| |
| // Handle file upload |
| const handleFileUpload = async (file: File) => { |
| try { |
| if (!file) { |
| throw new Error('请选择一个文件'); |
| } |
| |
| // Call the uploadTorrent function to upload the file |
| await uploadTorrent(file); |
| |
| // Show a success message |
| message.success('文件上传成功'); |
| |
| // Close the upload modal |
| setUploadModalVisible(false); |
| |
| // Optionally reload the table or perform other actions (e.g., refresh list) |
| actionRef.current?.reload(); |
| |
| } catch (error) { |
| message.error(error.message || '文件上传失败'); |
| } |
| }; |
| |
| return ( |
| <Content> |
| <Card bordered={false}> |
| <ProTable<BtTorrent> |
| headerTitle="种子列表" |
| actionRef={actionRef} |
| rowKey="torrentId" |
| search={{ labelWidth: 100 }} |
| toolBarRender={() => [ |
| <Button |
| key="add" |
| type="primary" |
| icon={<PlusOutlined />} |
| onClick={() => { |
| form.resetFields(); |
| setCurrent({}); |
| setModalVisible(true); |
| }} |
| > |
| 新增 |
| </Button>, |
| <Button |
| key="upload" |
| type="primary" |
| icon={<UploadOutlined />} |
| onClick={() => setUploadModalVisible(true)} // Show the upload modal |
| > |
| 上传种子文件 |
| </Button> |
| ]} |
| request={async (params) => { |
| const res = await listBtTorrent(params); |
| return { data: res.rows || res.data || [], success: true }; |
| }} |
| columns={columns} |
| /> |
| |
| {/* 编辑/新增弹窗 */} |
| <Modal |
| title={current?.torrentId ? '编辑种子' : '新增种子'} |
| open={modalVisible} |
| onOk={handleSubmit} |
| onCancel={() => setModalVisible(false)} |
| destroyOnClose |
| > |
| <Form form={form} layout="vertical"> |
| <Form.Item name="name" label="名称" rules={[{ required: true }]}> |
| <Input /> |
| </Form.Item> |
| <Form.Item name="infoHash" label="infoHash" rules={[{ required: true }]}> |
| <Input /> |
| </Form.Item> |
| <Form.Item name="length" label="总大小 (bytes)" rules={[{ required: true }]}> |
| <InputNumber style={{ width: '100%' }} /> |
| </Form.Item> |
| <Form.Item name="pieceLength" label="分片大小" rules={[{ required: true }]}> |
| <InputNumber style={{ width: '100%' }} /> |
| </Form.Item> |
| <Form.Item name="piecesCount" label="片段数"> |
| <InputNumber style={{ width: '100%' }} /> |
| </Form.Item> |
| <Form.Item name="createdBy" label="创建工具"> |
| <Input /> |
| </Form.Item> |
| </Form> |
| </Modal> |
| |
| {/* 上传种子文件的Modal */} |
| <Modal |
| title="上传种子文件" |
| visible={uploadModalVisible} |
| onCancel={() => setUploadModalVisible(false)} |
| footer={null} |
| > |
| <Upload |
| customRequest={({ file, onSuccess, onError }) => { |
| setUploadFile(file); |
| handleFileUpload(file); |
| onSuccess?.(); |
| }} |
| showUploadList={false} |
| accept=".torrent" |
| > |
| <Button icon={<UploadOutlined />}>点击上传 .torrent 文件</Button> |
| </Upload> |
| </Modal> |
| |
| {/* 详情抽屉 */} |
| <Drawer |
| width={500} |
| open={drawerVisible} |
| onClose={() => setDrawerVisible(false)} |
| title="种子详情" |
| > |
| {current && ( |
| <ProDescriptions<BtTorrent> |
| column={1} |
| title={current.name} |
| request={async () => ({ data: current })} |
| columns={columns as ProDescriptionsItemProps<BtTorrent>[]} |
| /> |
| )} |
| </Drawer> |
| </Card> |
| </Content> |
| ); |
| }; |
| |
| export default BtTorrentPage; |