Merge "接悬赏显示优化"
diff --git a/react-ui/src/pages/Reward/index.tsx b/react-ui/src/pages/Reward/index.tsx
index 42a9bac..ee9611a 100644
--- a/react-ui/src/pages/Reward/index.tsx
+++ b/react-ui/src/pages/Reward/index.tsx
@@ -1,5 +1,5 @@
-import { ExclamationCircleOutlined, PlusOutlined, DeleteOutlined, UploadOutlined, TrophyOutlined } from '@ant-design/icons';
-import { Button, message, Modal, Switch, Upload, Form } from 'antd';
+import { ExclamationCircleOutlined, PlusOutlined, DeleteOutlined, UploadOutlined, TrophyOutlined, CheckCircleOutlined, CloseCircleOutlined, DownloadOutlined } from '@ant-design/icons';
+import { Button, message, Modal, Switch, Upload, Form, Tag } from 'antd';
 import React, { useRef, useState, useEffect } from 'react';
 import { FormattedMessage, useIntl } from 'umi';
 import { FooterToolbar, PageContainer } from '@ant-design/pro-layout';
@@ -7,7 +7,7 @@
 import ProTable from '@ant-design/pro-table';
 import type { FormInstance } from 'antd';
 import type { UploadFile } from 'antd/es/upload/interface';
-import { getRewardList, removeReward, updateReward, addReward } from './service';
+import { getRewardList, removeReward, updateReward, addReward, getTorrentID, submitReward } from './service';
 import UpdateForm from './components/UpdateForm';
 import { getDictValueEnum } from '@/services/system/dict';
 import DictTag from '@/components/DictTag';
@@ -15,7 +15,7 @@
 import { RewardItem, RewardListParams } from './data';
 import { BtTorrent } from '../Torrent/data';
 import { uploadTorrent } from '../Torrent/service';
-
+import { downloadTorrent } from '../Torrent/service';
 /**
  * 删除节点
  *
@@ -73,11 +73,29 @@
 };
 
 /**
- * 处理接悬赏提交
+ * 下载已提交的种子文件
  * @param rewardId 悬赏ID
- * @param fileList 上传的文件列表
  */
+const handleDownloadSubmitted = async (rewardId: number) => {
+    const hide = message.loading('正在下载...');
 
+    try {
+        const torrentID = await getTorrentID(rewardId);
+        // 这里需要调用下载接口,假设接口为 downloadRewardFile
+        const blob = await downloadTorrent(torrentID.torrentId);
+        const url = window.URL.createObjectURL(blob);
+        const link = document.createElement('a');
+        link.href = url;
+        link.download = `${blob.name}.torrent`;
+        document.body.appendChild(link);
+        link.click();
+        document.body.removeChild(link);
+        window.URL.revokeObjectURL(url);
+        message.success('下载成功');
+    } catch (error: any) {
+        message.error('下载失败');
+    }
+};
 
 const RewardTableList: React.FC = () => {
     const formTableRef = useRef<FormInstance>();
@@ -107,8 +125,6 @@
         });
     }, []);
 
-    // 修复后的接悬赏相关代码
-
     /**
      * 处理接悬赏提交
      * @param rewardId 悬赏ID  
@@ -118,7 +134,7 @@
         const hide = message.loading('正在提交悬赏...');
         try {
             // 直接传递File对象给uploadTorrent函数
-            const resp = await uploadTorrent(file);
+            const resp = await submitReward(file);
 
             hide();
             if (resp.code === 200) {
@@ -173,7 +189,7 @@
         }
     };
 
-    // 文件上传前的检查(保持不变,但添加更详细的验证)
+    // 文件上传前的检查
     const beforeUpload = (file: File) => {
         console.log('上传前检查文件:', file.name, file.type, file.size);
 
@@ -199,7 +215,7 @@
         return false; // 阻止自动上传,我们手动处理
     };
 
-    // 处理文件列表变化(简化逻辑)
+    // 处理文件列表变化
     const handleFileChange = ({ fileList: newFileList }: { fileList: UploadFile[] }) => {
         // 只保留最后一个文件
         const latestFileList = newFileList.slice(-1);
@@ -239,15 +255,45 @@
                 </span>
             ),
         },
-        // {
-        //     title: '悬赏状态',
-        //     dataIndex: 'status',
-        //     valueType: 'select',
-        //     valueEnum: statusOptions,
-        //     render: (_, record) => {
-        //         return (<DictTag enums={statusOptions} value={record.status} />);
-        //     },
-        // },
+        {
+            title: '完成状态',
+            dataIndex: 'status',
+            valueType: 'select',
+            valueEnum: {
+                '0': { text: '进行中', status: 'Processing' },
+                '1': { text: '已完成', status: 'Success' },
+                '2': { text: '已取消', status: 'Error' },
+            },
+            render: (_, record) => {
+                const status = record.status;
+                let color = 'default';
+                let icon = <CloseCircleOutlined />;
+                let text = '进行中';
+
+                if (status === '1') {
+                    color = 'success';
+                    icon = <CheckCircleOutlined />;
+                    text = '已完成';
+                } else if (status === '2') {
+                    color = 'error';
+                    icon = <CloseCircleOutlined />;
+                    text = '已取消';
+                } else {
+                    color = 'processing';
+                    icon = <TrophyOutlined />;
+                    text = '进行中';
+                }
+
+                return (
+                    <Tag
+                        color={color}
+                        icon={icon}
+                    >
+                        {text}
+                    </Tag>
+                );
+            },
+        },
         {
             title: '发布时间',
             dataIndex: 'createTime',
@@ -273,75 +319,100 @@
         {
             title: <FormattedMessage id="pages.searchTable.titleOption" defaultMessage="操作" />,
             dataIndex: 'option',
-            width: '300px',
+            width: '350px',
             valueType: 'option',
-            render: (_, record) => [
-                <Button
-                    type="link"
-                    size="small"
-                    key="view"
-                    onClick={() => {
-                        setModalVisible(true);
-                        setCurrentRow(record);
-                        // 设置只读模式
-                        setReadOnly(true);
-                    }}
-                >
-                    查看
-                </Button>,
-                <Button
-                    type="link"
-                    size="small"
-                    key="accept"
-                    style={{ color: '#52c41a' }}
-                    icon={<TrophyOutlined />}
-                    onClick={() => {
-                        setCurrentAcceptReward(record);
-                        setAcceptModalVisible(true);
-                        setFileList([]);
-                    }}
-                >
-                    接悬赏
-                </Button>,
-                <Button
-                    type="link"
-                    size="small"
-                    key="edit"
-                    hidden={!access.hasPerms('reward:reward:edit')}
-                    onClick={() => {
-                        setModalVisible(true);
-                        setCurrentRow(record);
-                        setReadOnly(false);
-                    }}
-                >
-                    编辑
-                </Button>,
-                <Button
-                    type="link"
-                    size="small"
-                    danger
-                    key="batchRemove"
-                    hidden={!access.hasPerms('reward:reward:remove')}
-                    onClick={async () => {
-                        Modal.confirm({
-                            title: '删除',
-                            content: '确定删除该项吗?',
-                            okText: '确认',
-                            cancelText: '取消',
-                            onOk: async () => {
-                                const success = await handleRemove([record]);
-                                if (success) {
-                                    if (actionRef.current) {
-                                        actionRef.current.reload();
+            render: (_, record) => {
+                // 根据status判断:0进行中 1已完成 2已取消
+                const status = record.status;
+                const isCompleted = status === '1'; // 已完成
+                const isInProgress = status === '0'; // 进行中
+                const isCancelled = status === '2'; // 已取消
+
+                return [
+                    <Button
+                        type="link"
+                        size="small"
+                        key="view"
+                        onClick={() => {
+                            setModalVisible(true);
+                            setCurrentRow(record);
+                            setReadOnly(true);
+                        }}
+                    >
+                        查看
+                    </Button>,
+                    // 只有进行中的悬赏才显示"接悬赏"按钮
+                    isInProgress && (
+                        <Button
+                            type="link"
+                            size="small"
+                            key="accept"
+                            style={{ color: '#52c41a' }}
+                            icon={<TrophyOutlined />}
+                            onClick={() => {
+                                setCurrentAcceptReward(record);
+                                setAcceptModalVisible(true);
+                                setFileList([]);
+                            }}
+                        >
+                            接悬赏
+                        </Button>
+                    ),
+                    // 只有已完成的悬赏才显示"下载"按钮
+                    isCompleted && (
+                        <Button
+                            type="link"
+                            size="small"
+                            key="download"
+                            style={{ color: '#1890ff' }}
+                            icon={<DownloadOutlined />}
+                            onClick={() => {
+                                handleDownloadSubmitted(record.rewardId);
+                            }}
+                        >
+                            下载
+                        </Button>
+                    ),
+                    <Button
+                        type="link"
+                        size="small"
+                        key="edit"
+                        hidden={!access.hasPerms('reward:reward:edit')}
+                        onClick={() => {
+                            setModalVisible(true);
+                            setCurrentRow(record);
+                            setReadOnly(false);
+                        }}
+                    >
+                        编辑
+                    </Button>,
+                    <Button
+                        type="link"
+                        size="small"
+                        danger
+                        key="batchRemove"
+                        hidden={!access.hasPerms('reward:reward:remove')}
+                        onClick={async () => {
+                            Modal.confirm({
+                                title: '删除',
+                                content: '确定删除该项吗?',
+                                okText: '确认',
+                                cancelText: '取消',
+                                onOk: async () => {
+                                    const success = await handleRemove([record]);
+                                    if (success) {
+                                        if (actionRef.current) {
+                                            actionRef.current.reload();
+                                        }
                                     }
-                                }
-                            },
-                        });
-                    }}
-                >
-                    删除
-                </Button>,
-            ],
+                                },
+                            });
+                        }}
+                    >
+                        删除
+                    </Button>,
+                ].filter(Boolean) // 过滤掉 false 值
+            },
         },
     ];
 
diff --git a/react-ui/src/pages/Reward/service.ts b/react-ui/src/pages/Reward/service.ts
index 390f43d..f226bae 100644
--- a/react-ui/src/pages/Reward/service.ts
+++ b/react-ui/src/pages/Reward/service.ts
@@ -9,6 +9,13 @@
     BtTorrentAnnounce,
     BtTorrentTag,
 } from '@/pages/Torrent/data';
+
+
+export async function getTorrentID(rewardId: number): Promise<{ torrentId: number }> {
+    return request(`/api/reward/bt/${rewardId}`, {
+        method: 'GET'
+    });
+}
 /** 获取悬赏任务列表 */
 export async function getRewardList(params?: RewardListParams) {
     const queryString = params
@@ -59,4 +66,17 @@
         method: 'post',
         data,
     });
+}
+
+export async function submitReward(file: File) {
+    const formData = new FormData();
+    formData.append('file', file);
+
+    return request('/api/rward/uploadTorrent', {
+        method: 'POST',
+        data: formData,
+        headers: {
+            'Content-Type': 'multipart/form-data',
+        },
+    });
 }
\ No newline at end of file