feat: 完成 Tracker 项目与 Torrent 种子模块的前后端接口与页面开发

- 实现 Tracker 项目、任务、任务日志、项目用户关联等模块的接口封装与 ProTable 页面
- 实现 Torrent 种子主表、文件列表、Tracker 服务器、标签模块的前后端接口封装
- 支持新增、编辑、删除、详情查看等完整 CRUD 功能
- 页面基于 Ant Design Pro,支持分页、筛选、Drawer + Modal 表单展示

Change-Id: If8ead64a0bf6c177545f1c3c348ee09cad221a85
diff --git a/ruoyi-admin/src/main/resources/mapper/system/BtTorrentMapper.xml b/ruoyi-admin/src/main/resources/mapper/system/BtTorrentMapper.xml
new file mode 100644
index 0000000..afb29d7
--- /dev/null
+++ b/ruoyi-admin/src/main/resources/mapper/system/BtTorrentMapper.xml
@@ -0,0 +1,101 @@
+<?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">
+<mapper namespace="com.ruoyi.torrent.mapper.BtTorrentMapper">
+    
+    <resultMap type="BtTorrent" id="BtTorrentResult">
+        <result property="torrentId"    column="torrent_id"    />
+        <result property="infoHash"    column="info_hash"    />
+        <result property="name"    column="name"    />
+        <result property="length"    column="length"    />
+        <result property="pieceLength"    column="piece_length"    />
+        <result property="piecesCount"    column="pieces_count"    />
+        <result property="createdBy"    column="created_by"    />
+        <result property="torrentCreateTime"    column="torrent_create_time"    />
+        <result property="uploaderId"    column="uploader_id"    />
+        <result property="uploadTime"    column="upload_time"    />
+        <result property="filePath"    column="file_path"    />
+    </resultMap>
+
+    <sql id="selectBtTorrentVo">
+        select torrent_id, info_hash, name, length, piece_length, pieces_count, created_by, torrent_create_time, uploader_id, upload_time, file_path from bt_torrent
+    </sql>
+
+    <select id="selectBtTorrentList" parameterType="BtTorrent" resultMap="BtTorrentResult">
+        <include refid="selectBtTorrentVo"/>
+        <where>  
+            <if test="infoHash != null  and infoHash != ''"> and info_hash = #{infoHash}</if>
+            <if test="name != null  and name != ''"> and name like concat('%', #{name}, '%')</if>
+            <if test="length != null "> and length = #{length}</if>
+            <if test="pieceLength != null "> and piece_length = #{pieceLength}</if>
+            <if test="piecesCount != null "> and pieces_count = #{piecesCount}</if>
+            <if test="createdBy != null  and createdBy != ''"> and created_by = #{createdBy}</if>
+            <if test="torrentCreateTime != null "> and torrent_create_time = #{torrentCreateTime}</if>
+            <if test="uploaderId != null "> and uploader_id = #{uploaderId}</if>
+            <if test="uploadTime != null "> and upload_time = #{uploadTime}</if>
+            <if test="filePath != null  and filePath != ''"> and file_path = #{filePath}</if>
+        </where>
+    </select>
+    
+    <select id="selectBtTorrentByTorrentId" parameterType="Long" resultMap="BtTorrentResult">
+        <include refid="selectBtTorrentVo"/>
+        where torrent_id = #{torrentId}
+    </select>
+
+    <insert id="insertBtTorrent" parameterType="BtTorrent" useGeneratedKeys="true" keyProperty="torrentId">
+        insert into bt_torrent
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="infoHash != null and infoHash != ''">info_hash,</if>
+            <if test="name != null and name != ''">name,</if>
+            <if test="length != null">length,</if>
+            <if test="pieceLength != null">piece_length,</if>
+            <if test="piecesCount != null">pieces_count,</if>
+            <if test="createdBy != null">created_by,</if>
+            <if test="torrentCreateTime != null">torrent_create_time,</if>
+            <if test="uploaderId != null">uploader_id,</if>
+            <if test="uploadTime != null">upload_time,</if>
+            <if test="filePath != null">file_path,</if>
+         </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="infoHash != null and infoHash != ''">#{infoHash},</if>
+            <if test="name != null and name != ''">#{name},</if>
+            <if test="length != null">#{length},</if>
+            <if test="pieceLength != null">#{pieceLength},</if>
+            <if test="piecesCount != null">#{piecesCount},</if>
+            <if test="createdBy != null">#{createdBy},</if>
+            <if test="torrentCreateTime != null">#{torrentCreateTime},</if>
+            <if test="uploaderId != null">#{uploaderId},</if>
+            <if test="uploadTime != null">#{uploadTime},</if>
+            <if test="filePath != null">#{filePath},</if>
+         </trim>
+    </insert>
+
+    <update id="updateBtTorrent" parameterType="BtTorrent">
+        update bt_torrent
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="infoHash != null and infoHash != ''">info_hash = #{infoHash},</if>
+            <if test="name != null and name != ''">name = #{name},</if>
+            <if test="length != null">length = #{length},</if>
+            <if test="pieceLength != null">piece_length = #{pieceLength},</if>
+            <if test="piecesCount != null">pieces_count = #{piecesCount},</if>
+            <if test="createdBy != null">created_by = #{createdBy},</if>
+            <if test="torrentCreateTime != null">torrent_create_time = #{torrentCreateTime},</if>
+            <if test="uploaderId != null">uploader_id = #{uploaderId},</if>
+            <if test="uploadTime != null">upload_time = #{uploadTime},</if>
+            <if test="filePath != null">file_path = #{filePath},</if>
+        </trim>
+        where torrent_id = #{torrentId}
+    </update>
+
+    <delete id="deleteBtTorrentByTorrentId" parameterType="Long">
+        delete from bt_torrent where torrent_id = #{torrentId}
+    </delete>
+
+    <delete id="deleteBtTorrentByTorrentIds" parameterType="String">
+        delete from bt_torrent where torrent_id in 
+        <foreach item="torrentId" collection="array" open="(" separator="," close=")">
+            #{torrentId}
+        </foreach>
+    </delete>
+</mapper>
\ No newline at end of file