import { http } from '@/utils/request' import type { ChatMessage } from '@/types' // 消息相关类型定义 export interface MessageResponse { id: string conversationId: string content: string type: string sender: string isRead: number aiReply?: string emotionAnalysis?: string messageOrder?: number createTime: string updateTime: string } export interface PageResult { records: T[] total: number size: number current: number pages: number } export interface MessagePageRequest { current: number size: number conversationId?: string type?: string sender?: string startTime?: string endTime?: string } export interface MessageSearchRequest { keyword: string limit: number conversationId?: string type?: string sender?: string startTime?: string endTime?: string } export interface MessageRecentRequest { limit: number conversationId?: string type?: string sender?: string } /** * 消息API服务 - 与web项目保持一致的接口 */ export const messageApi = { // 获取用户消息分页 getUserMessages: async (current: number = 1, size: number = 20) => { console.log('📨 调用getUserMessages API:', { current, size }) // backend-single: GET /message/page (后端根据token识别用户) const response = await http.get(`/message/page`, { params: { current, size } }) console.log('📨 getUserMessages API响应:', response) return response }, // 搜索用户消息 searchUserMessages: async (keyword: string, limit: number = 50) => { console.log('🔍 调用searchUserMessages API:', { keyword, limit }) // backend-single: POST /message/search const resp = await http.post(`/message/search`, { keyword, limit }) console.log('🔍 searchUserMessages API响应:', resp) // 统一返回数组,兼容控制器返回 PageResult 结构 const data: any = (resp as any).data || resp const records = data.records || data return Array.isArray(records) ? records : [] }, // 获取用户最近的聊天记录 - 返回数组,兼容后端 PageResult 结构 getRecentMessages: async (limit: number = 10) => { console.log('📝 调用getRecentMessages API:', { limit }) // backend-single: POST /message/recent const resp = await http.post(`/message/recent`, { limit }) console.log('📝 getRecentMessages API响应:', resp) const data: any = (resp as any).data || resp const records = data.records || data return Array.isArray(records) ? records : [] }, // 获取消息详情 getMessageById: async (id: string) => { console.log('📄 调用getMessageById API:', { id }) // backend-single: GET /message/detail?id=xxx const response = await http.get(`/message/detail`, { params: { id } }) console.log('📄 getMessageById API响应:', response) return response } } /** * 消息服务类 - 提供高级封装 */ class MessageService { /** * 获取用户消息分页 */ static async getUserMessages(current: number = 1, size: number = 20): Promise> { const response = await messageApi.getUserMessages(current, size) return response.data || response } /** * 搜索用户消息 */ static async searchUserMessages(request: MessageSearchRequest): Promise { const response = await messageApi.searchUserMessages(request.keyword, request.limit) return response.data || response } /** * 获取用户最近的聊天记录 */ static async getRecentMessages(request: MessageRecentRequest): Promise { console.log('📝 MessageService.getRecentMessages 调用:', request) const response = await messageApi.getRecentMessages(request.limit) console.log('📝 MessageService.getRecentMessages 响应:', response) // 处理响应数据结构 const messageList = response.data || response || [] return Array.isArray(messageList) ? messageList : [] } /** * 根据ID获取消息详情 */ static async getMessageById(id: string): Promise { const response = await messageApi.getMessageById(id) return response.data || response } /** * 转换消息格式为聊天消息格式 - 完整匹配后端字段 */ static convertToChatMessage(msg: MessageResponse): ChatMessage { console.log('🔄 转换消息格式:', msg) // 处理时间格式 - 后端返回 "2025-07-26 22:09:10" 格式 // 直接保持原始字符串格式,让前端UI层处理 let timestamp = msg.createTime console.log('🕐 保持原始时间格式:', msg.createTime) const chatMessage: ChatMessage = { id: msg.id, content: msg.content, type: msg.sender === 'user' ? 'user' : (msg.sender === 'ai' ? 'ai' : 'system'), timestamp: timestamp, conversationId: msg.conversationId, sessionId: msg.conversationId, // 别名,保持兼容性 status: 'sent', sender: msg.sender as 'user' | 'ai' | 'system', isRead: msg.isRead, role: msg.sender === 'user' ? 'user' : 'assistant', // 用于UI显示 messageOrder: msg.messageOrder // 消息顺序 - 用于确保消息展示顺序 } console.log('✅ 转换后的消息详情:', { 原始sender: msg.sender, 转换后role: chatMessage.role, 转换后type: chatMessage.type, 时间: msg.createTime + ' -> ' + timestamp, 消息顺序: msg.messageOrder }) console.log('✅ 转换后的消息:', chatMessage) return chatMessage } /** * 批量转换消息格式 */ static convertToChatMessages(messages: MessageResponse[]): ChatMessage[] { console.log('🔄 批量转换消息格式,数量:', messages.length) const chatMessages = messages.map(msg => this.convertToChatMessage(msg)) console.log('✅ 批量转换完成,结果:', chatMessages) return chatMessages } /** * 解析时间戳为毫秒数 - 统一处理各种时间格式 * 支持格式: * - "2025-07-26 22:09:10" (后端格式) * - "2025-07-26T22:09:10" (ISO格式) * - "2025-07-26T22:09:10.000Z" (ISO完整格式) * - Date对象 */ static parseTimestamp(timestamp: string | Date | number): number { if (typeof timestamp === 'number') { return timestamp } if (timestamp instanceof Date) { return timestamp.getTime() } if (typeof timestamp === 'string') { // 处理 "2025-07-26 22:09:10" 格式 if (timestamp.includes(' ') && !timestamp.includes('T')) { const isoString = timestamp.replace(' ', 'T') return new Date(isoString).getTime() } // 处理其他格式 return new Date(timestamp).getTime() } // 默认返回当前时间 return new Date().getTime() } /** * 对消息进行排序和去重 * 优先使用 messageOrder 排序,如果没有则使用时间戳排序 * 确保消息按顺序排列,相同顺序的消息保持原有顺序 */ static sortAndDeduplicateMessages(messages: ChatMessage[]): ChatMessage[] { console.log('🔄 开始排序和去重消息,原始数量:', messages.length) // 创建消息ID的Set用于去重 const seenIds = new Set() const uniqueMessages: ChatMessage[] = [] // 先去重 for (const msg of messages) { if (!seenIds.has(msg.id)) { seenIds.add(msg.id) uniqueMessages.push(msg) } else { console.warn('⚠️ 发现重复消息,ID:', msg.id) } } console.log('✅ 去重完成,去重后数量:', uniqueMessages.length) // 按消息顺序排序(优先使用 messageOrder,如果没有则使用时间戳) uniqueMessages.sort((a, b) => { // 优先使用 messageOrder 排序 if (a.messageOrder !== undefined && b.messageOrder !== undefined) { if (a.messageOrder !== b.messageOrder) { return a.messageOrder - b.messageOrder } } // 如果 messageOrder 相同或不存在,使用时间戳排序 const timeA = this.parseTimestamp(a.timestamp) const timeB = this.parseTimestamp(b.timestamp) if (timeA !== timeB) { return timeA - timeB } // 时间相同时,保持原有顺序(稳定排序) // 通过比较消息ID的字典序来保持一致性 return a.id.localeCompare(b.id) }) console.log('✅ 排序完成,排序后消息:', uniqueMessages.map(m => ({ id: m.id, type: m.type, order: m.messageOrder, time: m.timestamp, content: m.content.substring(0, 20) + '...' }))) return uniqueMessages } } export default MessageService