fix(reward):完善了悬赏功能,新增reward_id表

Change-Id: I1d9b93af1cd19e1d0c8ee69ba86f6c1460c883b0
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/reward/controller/RewardTasksController.java b/ruoyi-admin/src/main/java/com/ruoyi/reward/controller/RewardTasksController.java
index bae499a..5263309 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/reward/controller/RewardTasksController.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/reward/controller/RewardTasksController.java
@@ -1,9 +1,14 @@
 package com.ruoyi.reward.controller;
 
+import java.io.OutputStream;
+import java.nio.charset.StandardCharsets;
 import java.util.List;
+import java.util.ArrayList;
+import java.util.UUID;
 import jakarta.servlet.http.HttpServletResponse;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.transaction.annotation.Transactional;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.PutMapping;
@@ -12,18 +17,34 @@
 import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.multipart.MultipartFile;
 import com.ruoyi.common.annotation.Log;
 import com.ruoyi.common.core.controller.BaseController;
 import com.ruoyi.common.core.domain.AjaxResult;
 import com.ruoyi.common.enums.BusinessType;
 import com.ruoyi.reward.domain.RewardTasks;
 import com.ruoyi.reward.service.IRewardTasksService;
+import com.ruoyi.torrent.domain.BtTorrent;
+import com.ruoyi.torrent.domain.BtTorrentAnnounce;
+import com.ruoyi.torrent.domain.BtTorrentFile;
+import com.ruoyi.torrent.service.IBtTorrentService;
+import com.ruoyi.torrent.service.IBtTorrentFileService;
+import com.ruoyi.torrent.service.IBtTorrentAnnounceService;
+import com.ruoyi.torrent.util.TorrentFileUtil;
+import com.ruoyi.common.utils.SecurityUtils;
 import com.ruoyi.common.utils.poi.ExcelUtil;
 import com.ruoyi.common.core.page.TableDataInfo;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.JsonNode;
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.net.URL;
 
 /**
- * 【请填写功能名称】Controller
- * 
+ * 悬赏任务控制器
+ *
  * @author ruoyi
  * @date 2025-05-17
  */
@@ -34,8 +55,21 @@
     @Autowired
     private IRewardTasksService rewardTasksService;
 
+    @Autowired
+    private IBtTorrentService btTorrentService;
+
+    @Autowired
+    private IBtTorrentFileService btTorrentFileService;
+
+    @Autowired
+    private IBtTorrentAnnounceService btTorrentAnnounceService;
+
+    private static final String FLASK_URL = "http://49.233.215.144:5000/parse_torrent";
+    private static final String TORRENT_PATH = "torrents";
+    private static final String BOUNDARY = "----WebKitFormBoundary" + UUID.randomUUID().toString().replace("-", "");
+
     /**
-     * 查询【请填写功能名称】列表
+     * 查询悬赏任务列表
      */
     @PreAuthorize("@ss.hasPermi('system:tasks:list')")
     @GetMapping("/list")
@@ -47,20 +81,20 @@
     }
 
     /**
-     * 导出【请填写功能名称】列表
+     * 导出悬赏任务列表
      */
     @PreAuthorize("@ss.hasPermi('system:tasks:export')")
-    @Log(title = "【请填写功能名称】", businessType = BusinessType.EXPORT)
+    @Log(title = "悬赏任务", businessType = BusinessType.EXPORT)
     @PostMapping("/export")
     public void export(HttpServletResponse response, RewardTasks rewardTasks)
     {
         List<RewardTasks> list = rewardTasksService.selectRewardTasksList(rewardTasks);
         ExcelUtil<RewardTasks> util = new ExcelUtil<RewardTasks>(RewardTasks.class);
-        util.exportExcel(response, list, "【请填写功能名称】数据");
+        util.exportExcel(response, list, "悬赏任务数据");
     }
 
     /**
-     * 获取【请填写功能名称】详细信息
+     * 获取悬赏任务详细信息
      */
     @PreAuthorize("@ss.hasPermi('system:tasks:query')")
     @GetMapping(value = "/{rewardId}")
@@ -70,10 +104,10 @@
     }
 
     /**
-     * 新增【请填写功能名称】
+     * 新增悬赏任务
      */
     @PreAuthorize("@ss.hasPermi('system:tasks:add')")
-    @Log(title = "【请填写功能名称】", businessType = BusinessType.INSERT)
+    @Log(title = "悬赏任务", businessType = BusinessType.INSERT)
     @PostMapping
     public AjaxResult add(@RequestBody RewardTasks rewardTasks)
     {
@@ -81,10 +115,10 @@
     }
 
     /**
-     * 修改【请填写功能名称】
+     * 修改悬赏任务
      */
     @PreAuthorize("@ss.hasPermi('system:tasks:edit')")
-    @Log(title = "【请填写功能名称】", businessType = BusinessType.UPDATE)
+    @Log(title = "悬赏任务", businessType = BusinessType.UPDATE)
     @PutMapping
     public AjaxResult edit(@RequestBody RewardTasks rewardTasks)
     {
@@ -92,13 +126,154 @@
     }
 
     /**
-     * 删除【请填写功能名称】
+     * 删除悬赏任务
      */
     @PreAuthorize("@ss.hasPermi('system:tasks:remove')")
-    @Log(title = "【请填写功能名称】", businessType = BusinessType.DELETE)
-	@DeleteMapping("/{rewardIds}")
+    @Log(title = "悬赏任务", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{rewardIds}")
     public AjaxResult remove(@PathVariable Long[] rewardIds)
     {
         return toAjax(rewardTasksService.deleteRewardTasksByRewardIds(rewardIds));
     }
-}
+
+    /**
+     * 根据悬赏ID获取Torrent ID
+     */
+    @PreAuthorize("@ss.hasPermi('system:tasks:query')")
+    @GetMapping("/bt/{rewardId}")
+    public AjaxResult getRewardBt(@PathVariable("rewardId") Integer rewardId)
+    {
+        Integer rewardBt = rewardTasksService.selectRewardBtByRewardId(rewardId);
+        if (rewardBt == null) {
+            return error("未找到对应的 torrent ID");
+        }
+        return success(rewardBt);
+    }
+
+    /**
+     * 上传种子文件并关联悬赏任务
+     */
+    @PreAuthorize("@ss.hasPermi('system:tasks:edit')")
+    @Log(title = "悬赏任务种子上传", businessType = BusinessType.INSERT)
+    @PostMapping("/uploadTorrent")
+    @Transactional
+    public AjaxResult uploadTorrent(@RequestParam("file") MultipartFile file, @RequestParam("reward_id") Integer rewardId)
+    {
+        try {
+            // 验证文件类型
+            if (!file.getOriginalFilename().endsWith(".torrent")) {
+                return AjaxResult.error("仅支持 .torrent 文件");
+            }
+
+            // 验证 reward_id
+            RewardTasks task = rewardTasksService.selectRewardTasksByRewardId(rewardId.longValue());
+            if (task == null) {
+                return AjaxResult.error("无效的悬赏任务ID");
+            }
+            if (!"2".equals(task.getStatus())) {
+                return AjaxResult.error("悬赏任务未完成,无法上传种子文件");
+            }
+            if (!task.getAccepterId().equals(SecurityUtils.getUserId())) {
+                return AjaxResult.error("只有任务接受者可以上传种子文件");
+            }
+
+            // 检查是否已关联 torrent
+            Integer existingBt = rewardTasksService.selectRewardBtByRewardId(rewardId);
+            if (existingBt != null) {
+                return AjaxResult.error("该悬赏任务已关联种子文件");
+            }
+
+            // 调用 Flask 服务解析种子文件
+            HttpURLConnection connection = (HttpURLConnection) new URL(FLASK_URL).openConnection();
+            connection.setRequestMethod("POST");
+            connection.setDoOutput(true);
+            connection.setConnectTimeout(5000);
+            connection.setReadTimeout(5000);
+            connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + BOUNDARY);
+
+            // 写入文件数据
+            try (OutputStream outputStream = connection.getOutputStream()) {
+                outputStream.write(("--" + BOUNDARY + "\r\n").getBytes(StandardCharsets.UTF_8));
+                outputStream.write(("Content-Disposition: form-data; name=\"torrent\"; filename=\"" + file.getOriginalFilename() + "\"\r\n").getBytes(StandardCharsets.UTF_8));
+                outputStream.write(("Content-Type: application/octet-stream\r\n\r\n").getBytes(StandardCharsets.UTF_8));
+                file.getInputStream().transferTo(outputStream);
+                outputStream.write("\r\n".getBytes(StandardCharsets.UTF_8));
+                outputStream.write(("--" + BOUNDARY + "--\r\n").getBytes(StandardCharsets.UTF_8));
+
+                // 处理 Flask 响应
+                int responseCode = connection.getResponseCode();
+                if (responseCode != 200) {
+                    return AjaxResult.error("与Flask服务通信失败,响应码: " + responseCode);
+                }
+
+                // 保存文件到服务器
+                String filePath = TORRENT_PATH + "/" + SecurityUtils.getUserId() + "/" + file.getOriginalFilename();
+                if (filePath.contains("..")) {
+                    return AjaxResult.error("无效的文件路径");
+                }
+                TorrentFileUtil.uploadFile(file, filePath);
+
+                // 解析响应并存储到数据库
+                String responseBody = new String(connection.getInputStream().readAllBytes(), StandardCharsets.UTF_8);
+                Long torrentId = parseTorrentData(responseBody, filePath);
+
+                // 插入 reward_bt 记录
+                rewardTasksService.insertRewardBt(rewardId, torrentId.intValue());
+
+                return AjaxResult.success("种子文件上传并处理成功,torrent_id: " + torrentId);
+            }
+        } catch (IOException e) {
+            logger.error("文件上传或与Flask服务通信失败: {}", e.getMessage());
+            return AjaxResult.error("文件上传或与Flask服务通信失败: " + e.getMessage());
+        }
+    }
+
+    /**
+     * 解析种子数据并存储到数据库
+     */
+    private Long parseTorrentData(String responseData, String filePath)
+    {
+        try {
+            ObjectMapper objectMapper = new ObjectMapper();
+            JsonNode jsonNode = objectMapper.readTree(responseData);
+            JsonNode btTorrentNode = jsonNode.get("btTorrent");
+            JsonNode btTorrentAnnounceNode = jsonNode.get("btTorrentAnnounce");
+            JsonNode btTorrentFilesNode = jsonNode.get("btTorrentFiles");
+
+            // 存储 bt_torrent
+            BtTorrent btTorrent = objectMapper.readValue(btTorrentNode.toString(), BtTorrent.class);
+            btTorrent.setCreatedBy(SecurityUtils.getUsername());
+            btTorrent.setUploaderId(SecurityUtils.getUserId());
+            btTorrent.setFilePath(filePath);
+            btTorrentService.insertBtTorrent(btTorrent);
+            Long torrentId = btTorrent.getTorrentId();
+
+            // 存储 bt_torrent_file
+            List<BtTorrentFile> btTorrentFiles = objectMapper.readValue(
+                    btTorrentFilesNode.toString(),
+                    new TypeReference<List<BtTorrentFile>>() {});
+            btTorrentFiles.forEach(btFile -> {
+                btFile.setTorrentId(torrentId);
+                btTorrentFileService.insertBtTorrentFile(btFile);
+            });
+
+            // 存储 bt_torrent_announce
+            List<BtTorrentAnnounce> btTorrentAnnounceList = new ArrayList<>();
+            if (btTorrentAnnounceNode.isArray()) {
+                for (JsonNode announceNode : btTorrentAnnounceNode) {
+                    BtTorrentAnnounce announce = objectMapper.readValue(announceNode.toString(), BtTorrentAnnounce.class);
+                    btTorrentAnnounceList.add(announce);
+                }
+            }
+            btTorrentAnnounceList.forEach(btTorrentAnnounce -> {
+                btTorrentAnnounce.setTorrentId(torrentId);
+                btTorrentAnnounceService.insertBtTorrentAnnounce(btTorrentAnnounce);
+            });
+
+            return torrentId;
+        } catch (Exception e) {
+            logger.error("解析种子数据失败: {}", e.getMessage());
+            throw new RuntimeException("解析种子数据失败: " + e.getMessage());
+        }
+    }
+}
\ No newline at end of file
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/reward/domain/RewardTasks.java b/ruoyi-admin/src/main/java/com/ruoyi/reward/domain/RewardTasks.java
index 50e5c8f..4186f13 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/reward/domain/RewardTasks.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/reward/domain/RewardTasks.java
@@ -7,8 +7,8 @@
 import com.ruoyi.common.core.domain.BaseEntity;
 
 /**
- * 【请填写功能名称】对象 reward_tasks
- * 
+ * 悬赏任务对象 reward_tasks
+ *
  * @author ruoyi
  * @date 2025-05-17
  */
@@ -16,110 +16,116 @@
 {
     private static final long serialVersionUID = 1L;
 
-    /** $column.columnComment */
+    /** 悬赏任务ID */
     private Long rewardId;
 
-    /** $column.columnComment */
-    @Excel(name = "${comment}", readConverterExp = "$column.readConverterExp()")
+    /** 任务标题 */
+    @Excel(name = "任务标题")
     private String title;
 
-    /** $column.columnComment */
-    @Excel(name = "${comment}", readConverterExp = "$column.readConverterExp()")
+    /** 任务描述 */
+    @Excel(name = "任务描述")
     private String description;
 
-    /** $column.columnComment */
-    @Excel(name = "${comment}", readConverterExp = "$column.readConverterExp()")
+    /** 奖励金额 */
+    @Excel(name = "奖励金额")
     private BigDecimal amount;
 
-    /** $column.columnComment */
-    @Excel(name = "${comment}", readConverterExp = "$column.readConverterExp()")
+    /** 任务状态 (0开放 1已接受 2已完成) */
+    @Excel(name = "任务状态", readConverterExp = "0=开放,1=已接受,2=已完成")
     private String status;
 
-    /** $column.columnComment */
-    @Excel(name = "${comment}", readConverterExp = "$column.readConverterExp()")
+    /** 发布者ID */
+    @Excel(name = "发布者ID")
     private Long publisherId;
 
-    /** $column.columnComment */
-    @Excel(name = "${comment}", readConverterExp = "$column.readConverterExp()")
+    /** 接受者ID */
+    @Excel(name = "接受者ID")
     private Long accepterId;
 
-    public void setRewardId(Long rewardId) 
+    public void setRewardId(Long rewardId)
     {
         this.rewardId = rewardId;
     }
 
-    public Long getRewardId() 
+    public Long getRewardId()
     {
         return rewardId;
     }
-    public void setTitle(String title) 
+
+    public void setTitle(String title)
     {
         this.title = title;
     }
 
-    public String getTitle() 
+    public String getTitle()
     {
         return title;
     }
-    public void setDescription(String description) 
+
+    public void setDescription(String description)
     {
         this.description = description;
     }
 
-    public String getDescription() 
+    public String getDescription()
     {
         return description;
     }
-    public void setAmount(BigDecimal amount) 
+
+    public void setAmount(BigDecimal amount)
     {
         this.amount = amount;
     }
 
-    public BigDecimal getAmount() 
+    public BigDecimal getAmount()
     {
         return amount;
     }
-    public void setStatus(String status) 
+
+    public void setStatus(String status)
     {
         this.status = status;
     }
 
-    public String getStatus() 
+    public String getStatus()
     {
         return status;
     }
-    public void setPublisherId(Long publisherId) 
+
+    public void setPublisherId(Long publisherId)
     {
         this.publisherId = publisherId;
     }
 
-    public Long getPublisherId() 
+    public Long getPublisherId()
     {
         return publisherId;
     }
-    public void setAccepterId(Long accepterId) 
+
+    public void setAccepterId(Long accepterId)
     {
         this.accepterId = accepterId;
     }
 
-    public Long getAccepterId() 
+    public Long getAccepterId()
     {
         return accepterId;
     }
 
     @Override
     public String toString() {
-        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
-            .append("rewardId", getRewardId())
-            .append("title", getTitle())
-            .append("description", getDescription())
-            .append("amount", getAmount())
-            .append("status", getStatus())
-            .append("publisherId", getPublisherId())
-            .append("accepterId", getAccepterId())
-            .append("createTime", getCreateTime())
-            .append("updateTime", getUpdateTime())
-            .append("remark", getRemark())
-            .toString();
+        return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
+                .append("rewardId", getRewardId())
+                .append("title", getTitle())
+                .append("description", getDescription())
+                .append("amount", getAmount())
+                .append("status", getStatus())
+                .append("publisherId", getPublisherId())
+                .append("accepterId", getAccepterId())
+                .append("createTime", getCreateTime())
+                .append("updateTime", getUpdateTime())
+                .append("remark", getRemark())
+                .toString();
     }
-}
+}
\ No newline at end of file
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/reward/mapper/RewardTasksMapper.java b/ruoyi-admin/src/main/java/com/ruoyi/reward/mapper/RewardTasksMapper.java
index 92520b8..4ba8b5a 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/reward/mapper/RewardTasksMapper.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/reward/mapper/RewardTasksMapper.java
@@ -2,60 +2,79 @@
 
 import java.util.List;
 import com.ruoyi.reward.domain.RewardTasks;
+import org.apache.ibatis.annotations.Mapper;
 
 /**
- * 【请填写功能名称】Mapper接口
- * 
+ * 悬赏任务Mapper接口
+ *
  * @author ruoyi
  * @date 2025-05-17
  */
-public interface RewardTasksMapper 
+@Mapper
+public interface RewardTasksMapper
 {
     /**
-     * 查询【请填写功能名称】
-     * 
-     * @param rewardId 【请填写功能名称】主键
-     * @return 【请填写功能名称】
+     * 查询悬赏任务
+     *
+     * @param rewardId 悬赏任务主键
+     * @return 悬赏任务
      */
     public RewardTasks selectRewardTasksByRewardId(Long rewardId);
 
     /**
-     * 查询【请填写功能名称】列表
-     * 
-     * @param rewardTasks 【请填写功能名称】
-     * @return 【请填写功能名称】集合
+     * 查询悬赏任务列表
+     *
+     * @param rewardTasks 悬赏任务
+     * @return 悬赏任务集合
      */
     public List<RewardTasks> selectRewardTasksList(RewardTasks rewardTasks);
 
     /**
-     * 新增【请填写功能名称】
-     * 
-     * @param rewardTasks 【请填写功能名称】
+     * 新增悬赏任务
+     *
+     * @param rewardTasks 悬赏任务
      * @return 结果
      */
     public int insertRewardTasks(RewardTasks rewardTasks);
 
     /**
-     * 修改【请填写功能名称】
-     * 
-     * @param rewardTasks 【请填写功能名称】
+     * 修改悬赏任务
+     *
+     * @param rewardTasks 悬赏任务
      * @return 结果
      */
     public int updateRewardTasks(RewardTasks rewardTasks);
 
     /**
-     * 删除【请填写功能名称】
-     * 
-     * @param rewardId 【请填写功能名称】主键
+     * 删除悬赏任务
+     *
+     * @param rewardId 悬赏任务主键
      * @return 结果
      */
     public int deleteRewardTasksByRewardId(Long rewardId);
 
     /**
-     * 批量删除【请填写功能名称】
-     * 
+     * 批量删除悬赏任务
+     *
      * @param rewardIds 需要删除的数据主键集合
      * @return 结果
      */
     public int deleteRewardTasksByRewardIds(Long[] rewardIds);
-}
+
+    /**
+     * 根据悬赏ID查询悬赏BT
+     *
+     * @param rewardId 悬赏任务ID
+     * @return 悬赏BT的torrent_id
+     */
+    public Integer selectRewardBtByRewardId(Integer rewardId);
+
+    /**
+     * 新增悬赏BT
+     *
+     * @param rewardId 悬赏任务ID
+     * @param rewardBt Torrent ID
+     * @return 结果
+     */
+    public int insertRewardBt(Integer rewardId, Integer rewardBt);
+}
\ No newline at end of file
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/reward/service/IRewardTasksService.java b/ruoyi-admin/src/main/java/com/ruoyi/reward/service/IRewardTasksService.java
index 5b8bd13..7ed6d59 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/reward/service/IRewardTasksService.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/reward/service/IRewardTasksService.java
@@ -4,58 +4,75 @@
 import com.ruoyi.reward.domain.RewardTasks;
 
 /**
- * 【请填写功能名称】Service接口
- * 
+ * 悬赏任务Service接口
+ *
  * @author ruoyi
  * @date 2025-05-17
  */
-public interface IRewardTasksService 
+public interface IRewardTasksService
 {
     /**
-     * 查询【请填写功能名称】
-     * 
-     * @param rewardId 【请填写功能名称】主键
-     * @return 【请填写功能名称】
+     * 查询悬赏任务
+     *
+     * @param rewardId 悬赏任务主键
+     * @return 悬赏任务
      */
     public RewardTasks selectRewardTasksByRewardId(Long rewardId);
 
     /**
-     * 查询【请填写功能名称】列表
-     * 
-     * @param rewardTasks 【请填写功能名称】
-     * @return 【请填写功能名称】集合
+     * 查询悬赏任务列表
+     *
+     * @param rewardTasks 悬赏任务
+     * @return 悬赏任务集合
      */
     public List<RewardTasks> selectRewardTasksList(RewardTasks rewardTasks);
 
     /**
-     * 新增【请填写功能名称】
-     * 
-     * @param rewardTasks 【请填写功能名称】
+     * 新增悬赏任务
+     *
+     * @param rewardTasks 悬赏任务
      * @return 结果
      */
     public int insertRewardTasks(RewardTasks rewardTasks);
 
     /**
-     * 修改【请填写功能名称】
-     * 
-     * @param rewardTasks 【请填写功能名称】
+     * 修改悬赏任务
+     *
+     * @param rewardTasks 悬赏任务
      * @return 结果
      */
     public int updateRewardTasks(RewardTasks rewardTasks);
 
     /**
-     * 批量删除【请填写功能名称】
-     * 
-     * @param rewardIds 需要删除的【请填写功能名称】主键集合
+     * 批量删除悬赏任务
+     *
+     * @param rewardIds 需要删除的悬赏任务主键集合
      * @return 结果
      */
     public int deleteRewardTasksByRewardIds(Long[] rewardIds);
 
     /**
-     * 删除【请填写功能名称】信息
-     * 
-     * @param rewardId 【请填写功能名称】主键
+     * 删除悬赏任务信息
+     *
+     * @param rewardId 悬赏任务主键
      * @return 结果
      */
     public int deleteRewardTasksByRewardId(Long rewardId);
-}
+
+    /**
+     * 根据悬赏ID查询悬赏BT
+     *
+     * @param rewardId 悬赏任务ID
+     * @return 悬赏BT的torrent_id
+     */
+    public Integer selectRewardBtByRewardId(Integer rewardId);
+
+    /**
+     * 新增悬赏BT
+     *
+     * @param rewardId 悬赏任务ID
+     * @param rewardBt Torrent ID
+     * @return 结果
+     */
+    public int insertRewardBt(Integer rewardId, Integer rewardBt);
+}
\ No newline at end of file
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/reward/service/impl/RewardTasksServiceImpl.java b/ruoyi-admin/src/main/java/com/ruoyi/reward/service/impl/RewardTasksServiceImpl.java
index b80f3f3..9c38580 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/reward/service/impl/RewardTasksServiceImpl.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/reward/service/impl/RewardTasksServiceImpl.java
@@ -1,30 +1,31 @@
 package com.ruoyi.reward.service.impl;
 
 import java.util.List;
-import com.ruoyi.common.utils.DateUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import com.ruoyi.common.utils.DateUtils;
 import com.ruoyi.reward.mapper.RewardTasksMapper;
 import com.ruoyi.reward.domain.RewardTasks;
 import com.ruoyi.reward.service.IRewardTasksService;
 
 /**
- * 【请填写功能名称】Service业务层处理
- * 
+ * 悬赏任务Service业务层处理
+ *
  * @author ruoyi
  * @date 2025-05-17
  */
 @Service
-public class RewardTasksServiceImpl implements IRewardTasksService 
+public class RewardTasksServiceImpl implements IRewardTasksService
 {
     @Autowired
     private RewardTasksMapper rewardTasksMapper;
 
     /**
-     * 查询【请填写功能名称】
-     * 
-     * @param rewardId 【请填写功能名称】主键
-     * @return 【请填写功能名称】
+     * 查询悬赏任务
+     *
+     * @param rewardId 悬赏任务主键
+     * @return 悬赏任务
      */
     @Override
     public RewardTasks selectRewardTasksByRewardId(Long rewardId)
@@ -33,10 +34,10 @@
     }
 
     /**
-     * 查询【请填写功能名称】列表
-     * 
-     * @param rewardTasks 【请填写功能名称】
-     * @return 【请填写功能名称】
+     * 查询悬赏任务列表
+     *
+     * @param rewardTasks 悬赏任务
+     * @return 悬赏任务
      */
     @Override
     public List<RewardTasks> selectRewardTasksList(RewardTasks rewardTasks)
@@ -45,12 +46,13 @@
     }
 
     /**
-     * 新增【请填写功能名称】
-     * 
-     * @param rewardTasks 【请填写功能名称】
+     * 新增悬赏任务
+     *
+     * @param rewardTasks 悬赏任务
      * @return 结果
      */
     @Override
+    @Transactional
     public int insertRewardTasks(RewardTasks rewardTasks)
     {
         rewardTasks.setCreateTime(DateUtils.getNowDate());
@@ -58,12 +60,13 @@
     }
 
     /**
-     * 修改【请填写功能名称】
-     * 
-     * @param rewardTasks 【请填写功能名称】
+     * 修改悬赏任务
+     *
+     * @param rewardTasks 悬赏任务
      * @return 结果
      */
     @Override
+    @Transactional
     public int updateRewardTasks(RewardTasks rewardTasks)
     {
         rewardTasks.setUpdateTime(DateUtils.getNowDate());
@@ -71,26 +74,54 @@
     }
 
     /**
-     * 批量删除【请填写功能名称】
-     * 
-     * @param rewardIds 需要删除的【请填写功能名称】主键
+     * 批量删除悬赏任务
+     *
+     * @param rewardIds 需要删除的悬赏任务主键
      * @return 结果
      */
     @Override
+    @Transactional
     public int deleteRewardTasksByRewardIds(Long[] rewardIds)
     {
         return rewardTasksMapper.deleteRewardTasksByRewardIds(rewardIds);
     }
 
     /**
-     * 删除【请填写功能名称】信息
-     * 
-     * @param rewardId 【请填写功能名称】主键
+     * 删除悬赏任务信息
+     *
+     * @param rewardId 悬赏任务主键
      * @return 结果
      */
     @Override
+    @Transactional
     public int deleteRewardTasksByRewardId(Long rewardId)
     {
         return rewardTasksMapper.deleteRewardTasksByRewardId(rewardId);
     }
-}
+
+    /**
+     * 根据悬赏ID查询悬赏BT
+     *
+     * @param rewardId 悬赏任务ID
+     * @return 悬赏BT的torrent_id
+     */
+    @Override
+    public Integer selectRewardBtByRewardId(Integer rewardId)
+    {
+        return rewardTasksMapper.selectRewardBtByRewardId(rewardId);
+    }
+
+    /**
+     * 新增悬赏BT
+     *
+     * @param rewardId 悬赏任务ID
+     * @param rewardBt Torrent ID
+     * @return 结果
+     */
+    @Override
+    @Transactional
+    public int insertRewardBt(Integer rewardId, Integer rewardBt)
+    {
+        return rewardTasksMapper.insertRewardBt(rewardId, rewardBt);
+    }
+}
\ No newline at end of file
diff --git a/ruoyi-admin/src/main/resources/mapper/system/RewardTasksMapper.xml b/ruoyi-admin/src/main/resources/mapper/system/RewardTasksMapper.xml
index bae8185..4019473 100644
--- a/ruoyi-admin/src/main/resources/mapper/system/RewardTasksMapper.xml
+++ b/ruoyi-admin/src/main/resources/mapper/system/RewardTasksMapper.xml
@@ -1,45 +1,47 @@
 <?xml version="1.0" encoding="UTF-8" ?>
 <!DOCTYPE mapper
-PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
-"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 <mapper namespace="com.ruoyi.reward.mapper.RewardTasksMapper">
-    
+
     <resultMap type="RewardTasks" id="RewardTasksResult">
-        <result property="rewardId"    column="reward_id"    />
-        <result property="title"    column="title"    />
-        <result property="description"    column="description"    />
-        <result property="amount"    column="amount"    />
-        <result property="status"    column="status"    />
-        <result property="publisherId"    column="publisher_id"    />
-        <result property="accepterId"    column="accepter_id"    />
-        <result property="createTime"    column="create_time"    />
-        <result property="updateTime"    column="update_time"    />
-        <result property="remark"    column="remark"    />
+        <result property="rewardId" column="reward_id" />
+        <result property="title" column="title" />
+        <result property="description" column="description" />
+        <result property="amount" column="amount" />
+        <result property="status" column="status" />
+        <result property="publisherId" column="publisher_id" />
+        <result property="accepterId" column="accepter_id" />
+        <result property="createTime" column="create_time" />
+        <result property="updateTime" column="update_time" />
+        <result property="remark" column="remark" />
     </resultMap>
 
     <sql id="selectRewardTasksVo">
-        select reward_id, title, description, amount, status, publisher_id, accepter_id, create_time, update_time, remark from reward_tasks
+        SELECT reward_id, title, description, amount, status, publisher_id, accepter_id, create_time, update_time, remark
+        FROM reward_tasks
+        ORDER BY create_time DESC
     </sql>
 
     <select id="selectRewardTasksList" parameterType="RewardTasks" resultMap="RewardTasksResult">
         <include refid="selectRewardTasksVo"/>
-        <where>  
-            <if test="title != null  and title != ''"> and title = #{title}</if>
-            <if test="description != null  and description != ''"> and description = #{description}</if>
-            <if test="amount != null "> and amount = #{amount}</if>
-            <if test="status != null  and status != ''"> and status = #{status}</if>
-            <if test="publisherId != null "> and publisher_id = #{publisherId}</if>
-            <if test="accepterId != null "> and accepter_id = #{accepterId}</if>
+        <where>
+            <if test="title != null and title != ''"> AND title = #{title}</if>
+            <if test="description != null and description != ''"> AND description = #{description}</if>
+            <if test="amount != null"> AND amount = #{amount}</if>
+            <if test="status != null and status != ''"> AND status = #{status}</if>
+            <if test="publisherId != null"> AND publisher_id = #{publisherId}</if>
+            <if test="accepterId != null"> AND accepter_id = #{accepterId}</if>
         </where>
     </select>
-    
+
     <select id="selectRewardTasksByRewardId" parameterType="Long" resultMap="RewardTasksResult">
         <include refid="selectRewardTasksVo"/>
-        where reward_id = #{rewardId}
+        WHERE reward_id = #{rewardId}
     </select>
 
     <insert id="insertRewardTasks" parameterType="RewardTasks" useGeneratedKeys="true" keyProperty="rewardId">
-        insert into reward_tasks
+        INSERT INTO reward_tasks
         <trim prefix="(" suffix=")" suffixOverrides=",">
             <if test="title != null and title != ''">title,</if>
             <if test="description != null and description != ''">description,</if>
@@ -50,8 +52,8 @@
             <if test="createTime != null">create_time,</if>
             <if test="updateTime != null">update_time,</if>
             <if test="remark != null">remark,</if>
-         </trim>
-        <trim prefix="values (" suffix=")" suffixOverrides=",">
+        </trim>
+        <trim prefix="VALUES (" suffix=")" suffixOverrides=",">
             <if test="title != null and title != ''">#{title},</if>
             <if test="description != null and description != ''">#{description},</if>
             <if test="amount != null">#{amount},</if>
@@ -61,11 +63,11 @@
             <if test="createTime != null">#{createTime},</if>
             <if test="updateTime != null">#{updateTime},</if>
             <if test="remark != null">#{remark},</if>
-         </trim>
+        </trim>
     </insert>
 
     <update id="updateRewardTasks" parameterType="RewardTasks">
-        update reward_tasks
+        UPDATE reward_tasks
         <trim prefix="SET" suffixOverrides=",">
             <if test="title != null and title != ''">title = #{title},</if>
             <if test="description != null and description != ''">description = #{description},</if>
@@ -77,17 +79,26 @@
             <if test="updateTime != null">update_time = #{updateTime},</if>
             <if test="remark != null">remark = #{remark},</if>
         </trim>
-        where reward_id = #{rewardId}
+        WHERE reward_id = #{rewardId}
     </update>
 
     <delete id="deleteRewardTasksByRewardId" parameterType="Long">
-        delete from reward_tasks where reward_id = #{rewardId}
+        DELETE FROM reward_tasks WHERE reward_id = #{rewardId}
     </delete>
 
-    <delete id="deleteRewardTasksByRewardIds" parameterType="String">
-        delete from reward_tasks where reward_id in 
+    <delete id="deleteRewardTasksByRewardIds" parameterType="Long">
+        DELETE FROM reward_tasks WHERE reward_id IN
         <foreach item="rewardId" collection="array" open="(" separator="," close=")">
             #{rewardId}
         </foreach>
     </delete>
+
+    <select id="selectRewardBtByRewardId" parameterType="Integer" resultType="Integer">
+        SELECT reward_bt FROM reward_bt WHERE reward_id = #{rewardId}
+    </select>
+
+    <insert id="insertRewardBt" parameterType="map">
+        INSERT INTO reward_bt (reward_id, reward_bt)
+        VALUES (#{rewardId}, #{rewardBt})
+    </insert>
 </mapper>
\ No newline at end of file