增加私信后端和标签上传

Change-Id: I4d5fbb6a634649359eef53091f07912c6099caeb
diff --git a/react-ui/src/pages/Message/data.d.ts b/react-ui/src/pages/Message/data.d.ts
index 2a537ea..dfe4771 100644
--- a/react-ui/src/pages/Message/data.d.ts
+++ b/react-ui/src/pages/Message/data.d.ts
@@ -11,7 +11,7 @@
 // 聊天对象接口
 export interface ChatContact {
     userId: number;
-    userName: string;
+    nickName: string;
     avatar?: string;
     lastMessage: string;
     lastMessageTime: Date;
@@ -41,7 +41,7 @@
 // 用户信息接口
 export interface UserInfo {
     userId: number;
-    userName: string;
+    nickName: string;
     avatar?: string;
 }
 
diff --git a/react-ui/src/pages/Message/index.tsx b/react-ui/src/pages/Message/index.tsx
index b07630a..04f9881 100644
--- a/react-ui/src/pages/Message/index.tsx
+++ b/react-ui/src/pages/Message/index.tsx
@@ -137,7 +137,8 @@
     // 获取用户名
     const getUserName = (userId: number) => {
         const contact = chatContacts.find(c => c.userId === userId);
-        return contact?.userName || `用户${userId}`;
+
+        return contact?.nickName || `用户${userId}`;
     };
 
     // 处理回车键发送
@@ -179,18 +180,18 @@
                                     className={selectedUserId === contact.userId ? 'selected' : ''}
                                 >
                                     <List.Item.Meta
-                                        avatar={
-                                            <Avatar size="large">
-                                                {contact.userName.charAt(0)}
-                                            </Avatar>
-                                        }
+                                        // avatar={
+                                        //     <Avatar size="large">
+                                        //         {contact.nickName.charAt(0)}
+                                        //     </Avatar>
+                                        // }
                                         title={
                                             <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
                                                 <span style={{
                                                     fontWeight: 'normal',
                                                     fontSize: '14px'
                                                 }}>
-                                                    {contact.userName}
+                                                    {contact.nickName}
                                                 </span>
                                                 <span style={{ fontSize: '12px', color: '#999' }}>
                                                     {formatTime(contact.lastMessageTime)}
diff --git a/react-ui/src/pages/Message/service.ts b/react-ui/src/pages/Message/service.ts
index 958290e..c5bc356 100644
--- a/react-ui/src/pages/Message/service.ts
+++ b/react-ui/src/pages/Message/service.ts
@@ -9,57 +9,40 @@
 
 // API 路径配置 - 可根据实际后端接口调整
 const API_CONFIG = {
-    CHAT_CONTACTS: '/api/system/message/contacts',  // 可改为: '/api/message/contacts' 或其他路径
-    CHAT_HISTORY: '/api/system/message/list',    // 可改为: '/api/message/history' 或其他路径
-    SEND_MESSAGE: '/api/system/message',       // 可改为: '/api/message/send' 或其他路径
-    USER_INFO: '/api/system/user',                  // 可改为: '/api/user' 或其他路径
+    CHAT_CONTACTS: '/api/system/user/message/chat/users',
+    CHAT_HISTORY: '/api/system/user/message/list',
+    SEND_MESSAGE: '/api/system/user/message',
+    USER_INFO: '/api/system/user'
 };
 
 /** 获取聊天对象列表 */
-export async function getChatContactList(params?: ChatContactListParams) {
+export async function getChatContactList() {
     // 默认数据
     const defaultData = [
         {
             userId: 2,
-            userName: '张三',
-            avatar: '',
-            lastMessage: '你好,请问有什么可以帮助你的吗?',
-            lastMessageTime: new Date(Date.now() - 1000 * 60 * 30),
-            unreadCount: 2
+            nickName: '张三'
         },
         {
             userId: 3,
-            userName: '李四',
-            avatar: '',
-            lastMessage: '关于最近的活动,我想了解更多细节。',
-            lastMessageTime: new Date(Date.now() - 1000 * 60 * 60 * 2),
-            unreadCount: 0
+            nickName: '李四'
         },
         {
             userId: 4,
-            userName: '王五',
-            avatar: '',
-            lastMessage: '好的,我知道了,谢谢!',
-            lastMessageTime: new Date(Date.now() - 1000 * 60 * 60 * 24),
-            unreadCount: 1
+            nickName: '王五'
         }
     ];
 
     try {
-        const queryString = params
-            ? `?${new URLSearchParams(params as Record<string, any>).toString()}`
-            : '';
-        const response = await request(`${API_CONFIG.CHAT_CONTACTS}${queryString}`, {
-            method: 'get',
+        const response = await request('/api/system/user/message/chat/users', {
+            method: 'get'
         });
 
-        // 如果接口返回空数据,使用默认数据
-        if (!response || response.length === 0) {
+        if (!response) {
             return defaultData;
         }
-        return response;
+        return response.data;
     } catch (error) {
-        // 接口报错时返回默认数据
         console.warn('获取聊天对象列表接口异常,使用默认数据:', error);
         return defaultData;
     }
@@ -96,23 +79,23 @@
         }
     ];
 
-    // try {
-    //     const queryString = `?${new URLSearchParams(params as Record<string, any>).toString()}`;
-    //     const response = await request(`${API_CONFIG.CHAT_HISTORY}${queryString}`, {
-    //         method: 'get',
-    //     });
-
-    //     // 如果接口返回空数据,使用默认数据
-    //     if (!response || response.length === 0) {
-    //         return defaultData;
-    //     }
-    //     return response;
-    // } catch (error) {
-    //     // 接口报错时返回默认数据
-    //     console.warn('获取聊天记录接口异常,使用默认数据:', error);
-    //     return defaultData;
-    // }
-    return defaultData;
+    try {
+        const response = await request(`${API_CONFIG.CHAT_HISTORY}`, {
+            method: 'get',
+            params: {
+                userId1: params.currentUserId,
+                userId2: params.userId
+            }
+        });
+        console.log(response);
+        if (!response || !response.data) {
+            return defaultData;
+        }
+        return response.data;
+    } catch (error) {
+        console.warn('获取聊天记录接口异常,使用默认数据:', error);
+        return defaultData;
+    }
 }
 
 /** 发送消息 */
@@ -134,7 +117,7 @@
     // 默认用户信息
     const defaultUserInfo = {
         userId,
-        userName: `用户${userId}`,
+        nickName: `用户${userId}`,
         avatar: ''
     };
 
@@ -143,10 +126,10 @@
             method: 'get',
         });
 
-        if (!response) {
+        if (!response || !response.data) {
             return defaultUserInfo;
         }
-        return response;
+        return response.data;
     } catch (error) {
         // 接口报错时返回默认用户信息
         console.warn(`获取用户${userId}信息接口异常,使用默认数据:`, error);
diff --git a/react-ui/src/pages/Torrent/index.tsx b/react-ui/src/pages/Torrent/index.tsx
index 30b7ef3..552a53c 100644
--- a/react-ui/src/pages/Torrent/index.tsx
+++ b/react-ui/src/pages/Torrent/index.tsx
@@ -45,6 +45,9 @@
   const [uploadFile, setUploadFile] = useState<File | null>(null); // State to store selected file
   const [uploadForm] = Form.useForm(); // Form for upload modal
   const [torrentTags, setTorrentTags] = useState<BtTorrentTag[]>([]); // 修改为数组类型来存储多个标签
+  const [tagModalVisible, setTagModalVisible] = useState(false);
+  const [currentTorrent, setCurrentTorrent] = useState<BtTorrent | null>(null);
+  const [tagForm] = Form.useForm();
 
   // Columns for the ProTable (the table displaying torrents)
   const columns: ProColumns<BtTorrent>[] = [
@@ -131,6 +134,11 @@
             message.error('下载失败');
           }
         }}>下载</Button>,
+        <Button key="tags" type="link" onClick={() => {
+          setCurrentTorrent(record);
+          handleGetTags(record.torrentId!);
+          setTagModalVisible(true);
+        }}>设置标签</Button>,
 
       ],
     },
@@ -330,25 +338,7 @@
                 <Button icon={<UploadOutlined />}>选择 .torrent 文件</Button>
               </Upload>
             </Form.Item>
-            <Form.Item
-              name="description"
-              label="介绍"
-              rules={[{ required: true, message: '请输入种子介绍' }]}
-            >
-              <Input.TextArea rows={4} placeholder="请输入种子文件的详细介绍" />
-            </Form.Item>
-            <Form.Item
-              name="tags"
-              label="标签"
-              rules={[{ required: true, message: '请输入标签' }]}
-            >
-              <Select
-                mode="tags"
-                style={{ width: '100%' }}
-                placeholder="请输入标签,按回车键确认"
-                tokenSeparators={[',']}
-              />
-            </Form.Item>
+
           </Form>
         </Modal>
 
@@ -449,6 +439,54 @@
             </>
           )}
         </Drawer>
+
+        {/* 设置标签的Modal */}
+        <Modal
+          title="设置标签"
+          open={tagModalVisible}
+          onCancel={() => {
+            setTagModalVisible(false);
+            tagForm.resetFields();
+          }}
+          onOk={async () => {
+            try {
+              const values = await tagForm.validateFields();
+              if (currentTorrent?.torrentId && values.tags) {
+                // 添加新标签
+                for (const tag of values.tags) {
+                  await addBtTorrentTag({
+                    torrentId: currentTorrent.torrentId,
+                    tag: tag
+                  });
+                }
+                message.success('标签设置成功');
+                setTagModalVisible(false);
+                tagForm.resetFields();
+                // 刷新标签列表
+                if (currentTorrent.torrentId === current?.torrentId) {
+                  handleGetTags(currentTorrent.torrentId);
+                }
+              }
+            } catch (error) {
+              message.error('设置标签失败');
+            }
+          }}
+        >
+          <Form form={tagForm} layout="vertical">
+            <Form.Item
+              name="tags"
+              label="标签"
+              rules={[{ required: true, message: '请输入标签' }]}
+            >
+              <Select
+                mode="tags"
+                style={{ width: '100%' }}
+                placeholder="请输入标签,按回车键确认"
+                tokenSeparators={[',']}
+              />
+            </Form.Item>
+          </Form>
+        </Modal>
       </Card>
     </Content>
   );
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysUserMessageController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysUserMessageController.java
index d6b030c..922fa7c 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysUserMessageController.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysUserMessageController.java
@@ -23,6 +23,14 @@
 
     @GetMapping("/list")
     public AjaxResult list(@RequestParam Long userId1, @RequestParam Long userId2) {
+        System.out.println(AjaxResult.success(messageService.getMessageList(userId1, userId2)));
         return AjaxResult.success(messageService.getMessageList(userId1, userId2));
     }
+
+    // 新增获取与当前用户聊过天的用户ID和昵称的接口
+    @GetMapping("/chat/users")
+    public AjaxResult getChatUsers() {
+        Long currentUserId = getUserId();
+        return AjaxResult.success(messageService.getChatUsers(currentUserId));
+    }
 }
\ No newline at end of file
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserMessageMapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserMessageMapper.java
index 6e2fc1d..edadbb8 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserMessageMapper.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserMessageMapper.java
@@ -2,8 +2,10 @@
 
 import com.ruoyi.system.domain.SysUserMessage;
 import java.util.List;
+import java.util.Map;
 
 public interface SysUserMessageMapper {
     int insertMessage(SysUserMessage message);
     List<SysUserMessage> selectMessageListByUserIds(Long userId1, Long userId2);
+    List<Map<String, Object>> selectChatUserIds(Long userId);
 }
\ No newline at end of file
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserMessageService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserMessageService.java
index 1bcc9f5..8501c99 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserMessageService.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserMessageService.java
@@ -2,8 +2,10 @@
 
 import com.ruoyi.system.domain.SysUserMessage;
 import java.util.List;
+import java.util.Map;
 
 public interface ISysUserMessageService {
     int sendMessage(SysUserMessage message);
     List<SysUserMessage> getMessageList(Long userId1, Long userId2);
+    List<Map<String, Object>> getChatUsers(Long userId);
 }
\ No newline at end of file
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserMessageServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserMessageServiceImpl.java
index 94c9e6e..fea1472 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserMessageServiceImpl.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserMessageServiceImpl.java
@@ -2,15 +2,22 @@
 
 import com.ruoyi.system.domain.SysUserMessage;
 import com.ruoyi.system.mapper.SysUserMessageMapper;
+import com.ruoyi.system.mapper.SysUserMapper;
 import com.ruoyi.system.service.ISysUserMessageService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 @Service
 public class SysUserMessageServiceImpl implements ISysUserMessageService {
     @Autowired
     private SysUserMessageMapper messageMapper;
+    @Autowired
+    private SysUserMapper userMapper; // 新增:用于查询用户昵称
 
     @Override
     public int sendMessage(SysUserMessage message) {
@@ -21,4 +28,11 @@
     public List<SysUserMessage> getMessageList(Long userId1, Long userId2) {
         return messageMapper.selectMessageListByUserIds(userId1, userId2);
     }
+
+
+    @Override
+    public List<Map<String, Object>> getChatUsers(Long userId) {
+        List<Map<String, Object>> chatUsers = messageMapper.selectChatUserIds(userId);
+        return chatUsers != null ? chatUsers : new ArrayList<>();
+    }
 }
\ No newline at end of file
diff --git a/ruoyi-system/src/main/resources/mapper/system/SysUserMessageMapper.xml b/ruoyi-system/src/main/resources/mapper/system/SysUserMessageMapper.xml
index 79fe8b7..73e55fc 100644
--- a/ruoyi-system/src/main/resources/mapper/system/SysUserMessageMapper.xml
+++ b/ruoyi-system/src/main/resources/mapper/system/SysUserMessageMapper.xml
@@ -22,4 +22,21 @@
             and del_flag = '0'
         order by create_time asc
     </select>
+
+    <select id="selectChatUserIds" parameterType="java.lang.Long" resultType="map">
+        SELECT DISTINCT
+            CASE
+                WHEN m.sender_id = #{userId} THEN m.receiver_id
+                ELSE m.sender_id
+                END AS userId,
+            u.nick_name AS nickName
+        FROM sys_user_message m
+                 INNER JOIN sys_user u
+                            ON (m.sender_id = #{userId} AND m.receiver_id = u.user_id)
+                                OR (m.receiver_id = #{userId} AND m.sender_id = u.user_id)
+        WHERE (m.sender_id = #{userId} OR m.receiver_id = #{userId})
+          AND m.del_flag = '0'
+          AND u.del_flag = '0'
+        ORDER BY u.nick_name
+    </select>
 </mapper>
\ No newline at end of file