From f010287bfa5c91457a022b42349c6ce17a3f8a54 Mon Sep 17 00:00:00 2001 From: Phoenix <64720302+Concur-max@users.noreply.github.com> Date: Tue, 1 Jul 2025 09:57:51 +0800 Subject: [PATCH] =?UTF-8?q?refactor(db):=20=E4=BC=98=E5=8C=96=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E5=BA=93=E7=BB=93=E6=9E=84=E5=92=8C=E6=9F=A5=E8=AF=A2?= =?UTF-8?q?=E6=80=A7=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 重构数据库表结构和索引,使用复合索引提高查询效率 简化消息和会话操作方法,使用批量操作提升性能 移除冗余代码和调试日志,清理代码风格 --- src/hooks/useTalkRecord.ts | 1 - src/utils/db.js | 767 +++++------------- .../message/inner/panel/PanelContent.vue | 3 +- 3 files changed, 196 insertions(+), 575 deletions(-) diff --git a/src/hooks/useTalkRecord.ts b/src/hooks/useTalkRecord.ts index d6530cb..efebd85 100644 --- a/src/hooks/useTalkRecord.ts +++ b/src/hooks/useTalkRecord.ts @@ -452,7 +452,6 @@ export const useTalkRecord = (uid: number) => { // 向上加载更多(兼容特殊参数模式) const onRefreshLoad = () => { - console.error('loadConfig.status', loadConfig.status) if (loadConfig.status == 1 || loadConfig.status == 3) { console.log('specialParams', loadConfig.specialParams) // 判断是否是特殊参数模式 diff --git a/src/utils/db.js b/src/utils/db.js index 38f932c..7db215a 100644 --- a/src/utils/db.js +++ b/src/utils/db.js @@ -3,151 +3,116 @@ import Dexie from 'dexie'; export const db = new Dexie('chatHistory'); -// 定义数据库结构 -db.version(2).stores({ +// 定义数据库表结构和索引 +// 版本3:优化了索引,提高了查询和排序性能 +db.version(4).stores({ + /** + * 聊天记录表 + * - msg_id: 消息唯一ID (主键) + * - sequence: 消息序列号,用于排序 + * - [talk_type+receiver_id]: 复合索引,用于快速查询会话消息 + * - created_at: 消息创建时间,用于排序 + * - [talk_type+receiver_id+sequence]: 复合索引,用于高效分页查询 + */ + messages: 'msg_id, sequence, [talk_type+receiver_id], created_at, [talk_type+receiver_id+sequence]', - // 聊天记录表 - - messages: 'msg_id, sequence, talk_type, msg_type, user_id, receiver_id, is_read, created_at', - - // 会话表(包含私聊和群聊) - conversations: 'id, talk_type, receiver_id, index_name, updated_at, unread_num' + /** + * 会话表 + * - ++id: 自增主键 + * - &index_name: 唯一索引 (talk_type + '_' + receiver_id) + * - updated_at: 索引,用于排序 + * - is_top: 索引,用于置顶排序 + */ + conversations: 'id, &index_name, talk_type, receiver_id, updated_at, unread_num, is_top', }); -db.on('ready', function() { - - console.log('数据库已就绪,版本:', db.verno); +db.on('ready', () => { + console.log(`数据库已就绪,版本: ${db.verno}`); }); -/** - * 消息类型常量 - */ +/** 消息类型常量 */ export const MessageType = { - TEXT: 1, // 文本消息 - IMAGE: 2, // 图片消息 - FILE: 3, // 文件消息 - AUDIO: 4, // 语音消息 - VIDEO: 5, // 视频消息 - LOCATION: 6, // 位置消息 - CARD: 7, // 名片消息 + TEXT: 1, // 文本消息 + IMAGE: 2, // 图片消息 + FILE: 3, // 文件消息 + AUDIO: 4, // 语音消息 + VIDEO: 5, // 视频消息 + LOCATION: 6, // 位置消息 + CARD: 7, // 名片消息 }; -/** - * 会话类型常量 - */ +/** 会话类型常量 */ export const TalkType = { - PRIVATE: 1, // 私聊 - GROUP: 2, // 群聊 + PRIVATE: 1, // 私聊 + GROUP: 2, // 群聊 }; /** - * 添加一条聊天记录 - * @param {Object} message - 消息对象 - * @returns {Promise} - 返回消息ID + * 生成一个简单的UUID + * @returns {string} UUID + */ +function generateUUID() { + return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => { + const r = (Math.random() * 16) | 0; + const v = c === 'x' ? r : (r & 0x3) | 0x8; + return v.toString(16); + }); +} + +// #region 消息操作 + +/** + * 添加或更新一条聊天记录 + * @param {object} message - 消息对象 + * @returns {Promise} 消息ID */ export async function addMessage(message) { try { - // 确保消息有唯一ID if (!message.msg_id) { message.msg_id = generateUUID(); } - - // 添加时间戳(如果没有) if (!message.created_at) { message.created_at = new Date().toISOString().replace('T', ' ').substring(0, 19); } - - // 添加到数据库 - const id = await db.messages.add(message); + + // 使用 put 方法,如果主键已存在则更新,否则添加 + await db.messages.put(message); return message.msg_id; } catch (error) { - console.error('添加消息失败:', error); + console.error('添加或更新消息失败:', error); throw error; } } /** * 批量添加或更新聊天记录 - * @param {Array} messages - 消息对象数组 - * @param {number} talkType - 会话类型(1:私聊, 2:群聊) - * @param {number} receiverId - 接收者ID(私聊为对方用户ID,群聊为群ID) - * @param {boolean} replaceExisting - 是否替换已存在的消息 - * @param {string} sortKey - 排序和比较的键,可选值:'sequence'或'created_at' - * @returns {Promise<{added: number, updated: number, total: number}>} - 返回添加和更新的消息数量 + * @param {Array} messages - 消息对象数组 + * @returns {Promise} */ -export async function batchAddOrUpdateMessages(messages, talkType, receiverId, replaceExisting = true, sortKey = 'sequence') { +export async function batchAddOrUpdateMessages(messages) { try { if (!Array.isArray(messages) || messages.length === 0) { - return { added: 0, updated: 0, total: 0 }; + return; } - // 获取现有消息 - let existingMessages = []; - if (replaceExisting) { - // 不传入 maxSequence 参数,获取所有消息 - existingMessages = await getMessages(talkType, null, receiverId, 1000, 0); - } - - // 创建msg_id到消息的映射,用于快速查找 - const existingMap = new Map(); - existingMessages.forEach(msg => { - existingMap.set(msg.msg_id, msg); - }); - - // 创建sequence/created_at到消息的映射,用于比较和替换 - const existingKeyMap = new Map(); - existingMessages.forEach(msg => { - if (msg[sortKey]) { - existingKeyMap.set(msg[sortKey], msg); + const messagesToStore = messages.map(message => { + if (!message.msg_id) { + message.msg_id = generateUUID(); } - }); - - let added = 0; - let updated = 0; - - // 批量处理事务 - await db.transaction('rw', db.messages, async () => { - for (const message of messages) { - // 确保消息有必要的字段 - if (!message.msg_id) { - message.msg_id = generateUUID(); - } - - if (!message.created_at) { - message.created_at = new Date().toISOString().replace('T', ' ').substring(0, 19); - } - - // 检查消息是否已存在 - const existing = existingMap.get(message.msg_id); - if (existing) { - // 更新现有消息,使用 msg_id 而不是 id - await db.messages.update(existing.msg_id, message); - updated++; - } else if (replaceExisting && message[sortKey] && existingKeyMap.has(message[sortKey])) { - // 根据sortKey替换现有消息 - const existingByKey = existingKeyMap.get(message[sortKey]); - await db.messages.update(existingByKey.msg_id, message); - updated++; - } else { - console.log('message',message) - // 添加新消息 - await db.messages.add(message); - added++; - } + if (!message.created_at) { + message.created_at = new Date().toISOString().replace('T', ' ').substring(0, 19); } + return message; }); - // 如果有新消息添加,更新会话的最后一条消息 - if (added > 0 || updated > 0) { - // 假设消息数组中的最后一条消息是最新的(保持原始顺序) - // 如果需要找出最新消息,可以使用数组中的最后一条消息 - const latestMessage = messages[messages.length - 1]; - - // 更新会话的最后一条消息 + // 使用 bulkPut 高效地批量添加或更新 + await db.messages.bulkPut(messagesToStore); + + // 更新最后一条消息到会话 + const latestMessage = messagesToStore[messagesToStore.length - 1]; + if (latestMessage) { await updateConversationLastMessage(latestMessage); } - - return { added, updated, total: added + updated }; } catch (error) { console.error('批量添加或更新消息失败:', error); throw error; @@ -156,57 +121,35 @@ export async function batchAddOrUpdateMessages(messages, talkType, receiverId, r /** * 获取指定会话的聊天记录 - * @param {number} talkType - 会话类型(1:私聊, 2:群聊) + * @param {number} talkType - 会话类型 (1:私聊, 2:群聊) * @param {number} userId - 当前用户ID - * @param {number} receiverId - 接收者ID(私聊为对方用户ID,群聊为群ID) - * @param {number} limit - 限制返回的记录数量 - * @param {number} offset - 偏移量,用于分页 - * @returns {Promise} - 返回消息列表 + * @param {number} receiverId - 接收者ID (私聊为对方用户ID,群聊为群ID) + * @param {number} [limit=30] - 限制返回的记录数量 + * @param {number|null} [maxSequence=null] - 最大sequence值,用于分页加载更早的消息 + * @returns {Promise>} 消息列表 (按sequence升序排列) */ -/** - * 获取消息列表 - * @param {number} talkType - 会话类型(1:私聊, 2:群聊) - * @param {number} userId - 用户ID(私聊时用于区分消息方向) - * @param {number} receiverId - 接收者ID(私聊时为对方ID,群聊时为群ID) - * @param {number} limit - 每页条数 - * @param {number} offset - 偏移量 - * @param {number} maxSequence - 最大sequence值,用于分页加载更早的消息 - * @returns {Promise} - 消息列表 - */ -export async function getMessages(talkType, userId, receiverId, limit = 30, offset = 0, maxSequence = null) { +export async function getMessages(talkType, userId, receiverId, limit = 30, maxSequence = null) { try { - let query; - - if (talkType === TalkType.PRIVATE) { - // 私聊消息(双向获取) - query = db.messages - .where('talk_type').equals(TalkType.PRIVATE) - .and(item => { - return (item.user_id === userId && item.receiver_id === receiverId) || - (item.user_id === receiverId && item.receiver_id === userId); - }); - } else { - // 群聊消息 - query = db.messages - .where('talk_type').equals(TalkType.GROUP) - .and(item => item.receiver_id === receiverId); - } - - // 如果提供了maxSequence,则只获取sequence小于该值的消息 + let collection; + + // 使用索引进行高效查询 if (maxSequence !== null) { - query = query.and(item => item.sequence < maxSequence); + // 加载更多:查询 sequence 小于 maxSequence 的消息 + collection = db.messages + .where('[talk_type+receiver_id+sequence]') + .between([talkType, receiverId, 0], [talkType, receiverId, maxSequence], true, false); + } else { + // 首次加载:查询指定会话的所有消息 + collection = db.messages.where({ '[talk_type+receiver_id]': [talkType, receiverId] }); } - - // 按sequence升序排序 - let messages = await query - .sortBy('sequence'); - - // 获取尾部的limit条记录(最新的消息) - if (messages.length > limit) { - messages = messages.slice(Math.max(0, messages.length - limit)); - } - - return messages; + + // 1. reverse() - 利用索引倒序排列,获取最新的消息 + // 2. limit() - 限制数量,实现分页 + // 3. toArray() - 执行查询 + const messages = await collection.reverse().limit(limit).toArray(); + + // 再次 reverse() - 将获取到的分页消息按时间正序排列,以便于在界面上显示 + return messages.reverse(); } catch (error) { console.error('获取消息失败:', error); throw error; @@ -214,48 +157,29 @@ export async function getMessages(talkType, userId, receiverId, limit = 30, offs } /** - * 标记消息为已读 - * @param {string} msgId - 消息ID - * @returns {Promise} - 操作是否成功 - */ -export async function markMessageAsRead(msgId) { - try { - await db.messages.update(msgId, { is_read: 1 }); - return true; - } catch (error) { - console.error('标记消息已读失败:', error); - return false; - } -} - -/** - * 批量标记消息为已读 + * 标记指定会话的所有消息为已读 * @param {number} talkType - 会话类型 * @param {number} userId - 当前用户ID * @param {number} receiverId - 接收者ID - * @returns {Promise} - 返回更新的消息数量 + * @returns {Promise} 更新的消息数量 */ export async function markMessagesAsRead(talkType, userId, receiverId) { try { - let count; - + let query; if (talkType === TalkType.PRIVATE) { - // 私聊消息(只标记对方发给我的消息) - count = await db.messages - .where('talk_type').equals(TalkType.PRIVATE) - .and(item => item.user_id === receiverId && item.receiver_id === userId) - .and(item => item.is_read === 0) - .modify({ is_read: 1 }); + // 私聊:只标记对方发给我的未读消息 + query = db.messages + .where('[talk_type+receiver_id]') + .equals([talkType, userId]) + .and(item => item.user_id === receiverId && item.is_read === 0); } else { - // 群聊消息(标记该群的所有未读消息) - count = await db.messages - .where('talk_type').equals(TalkType.GROUP) - .and(item => item.receiver_id === receiverId) - .and(item => item.is_read === 0 && item.user_id !== userId) - .modify({ is_read: 1 }); + // 群聊:标记群里所有非自己的未读消息 + query = db.messages + .where('[talk_type+receiver_id]') + .equals([talkType, receiverId]) + .and(item => item.user_id !== userId && item.is_read === 0); } - - return count; + return await query.modify({ is_read: 1 }); } catch (error) { console.error('批量标记消息已读失败:', error); throw error; @@ -265,134 +189,44 @@ export async function markMessagesAsRead(talkType, userId, receiverId) { /** * 撤回消息 * @param {string} msgId - 消息ID - * @returns {Promise} - 操作是否成功 + * @returns {Promise} 更新记录数 (1或0) */ export async function revokeMessage(msgId) { try { - await db.messages.update(msgId, { is_revoke: 1 }); - return true; + return await db.messages.update(msgId, { is_revoke: 1 }); } catch (error) { console.error('撤回消息失败:', error); - return false; + throw error; } } /** * 删除消息 * @param {string} msgId - 消息ID - * @returns {Promise} - 操作是否成功 + * @returns {Promise} */ export async function deleteMessage(msgId) { try { await db.messages.delete(msgId); - return true; } catch (error) { console.error('删除消息失败:', error); - return false; - } -} - -/** - * 获取未读消息数量 - * @param {number} userId - 当前用户ID - * @returns {Promise} - 返回未读消息统计信息 - */ -export async function getUnreadCount(userId) { - try { - // 私聊未读消息数量 - const privateUnread = await db.messages - .where('talk_type').equals(TalkType.PRIVATE) - .and(item => item.receiver_id === userId && item.is_read === 0) - .count(); - - // 群聊未读消息数量 - const groupUnread = await db.messages - .where('talk_type').equals(TalkType.GROUP) - .and(item => item.user_id !== userId && item.is_read === 0) - .count(); - - // 按会话分组的未读消息数量 - const privateUnreadBySession = await db.messages - .where('talk_type').equals(TalkType.PRIVATE) - .and(item => item.receiver_id === userId && item.is_read === 0) - .toArray() - .then(messages => { - const result = {}; - messages.forEach(msg => { - if (!result[msg.user_id]) { - result[msg.user_id] = 0; - } - result[msg.user_id]++; - }); - return result; - }); - - // 按群组分组的未读消息数量 - const groupUnreadBySession = await db.messages - .where('talk_type').equals(TalkType.GROUP) - .and(item => item.user_id !== userId && item.is_read === 0) - .toArray() - .then(messages => { - const result = {}; - messages.forEach(msg => { - if (!result[msg.receiver_id]) { - result[msg.receiver_id] = 0; - } - result[msg.receiver_id]++; - }); - return result; - }); - - return { - total: privateUnread + groupUnread, - private: privateUnread, - group: groupUnread, - privateBySession: privateUnreadBySession, - groupBySession: groupUnreadBySession - }; - } catch (error) { - console.error('获取未读消息数量失败:', error); throw error; } } -/** - * 生成UUID - * @returns {string} - 返回UUID - */ -function generateUUID() { - return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { - const r = Math.random() * 16 | 0; - const v = c === 'x' ? r : (r & 0x3 | 0x8); - return v.toString(16); - }); -} +// #endregion 消息操作 + +// #region 会话操作 /** * 添加或更新会话 - * @param {Object} conversation - 会话对象 - * @returns {Promise} - 返回会话ID + * @param {object} conversation - 会话对象 + * @returns {Promise} 会话ID */ export async function addOrUpdateConversation(conversation) { try { - // 创建一个纯数据副本,移除所有不可序列化的内容 - const serializableConversation = JSON.parse(JSON.stringify(conversation)); - - // 检查会话是否已存在 - const existingConversation = await db.conversations - .where('index_name') - .equals(serializableConversation.index_name) - .first(); - - if (existingConversation) { - // 更新现有会话 - await db.conversations.update(existingConversation.id, serializableConversation); - return existingConversation.id; - } else { - // 添加新会话 - const id = await db.conversations.add(serializableConversation); - return id; - } + // put 方法会根据唯一索引 index_name 自动判断是添加还是更新 + return await db.conversations.put(conversation); } catch (error) { console.error('添加或更新会话失败:', error); throw error; @@ -401,29 +235,32 @@ export async function addOrUpdateConversation(conversation) { /** * 获取所有会话列表 - * @param {boolean} includeEmpty - 是否包含没有消息的会话 - * @returns {Promise} - 返回会话列表,按更新时间倒序排列 + * @param {boolean} [includeEmpty=false] - 是否包含没有最后一条消息的会话 + * @returns {Promise>} 会话列表 (按置顶和更新时间排序) */ export async function getConversations(includeEmpty = false) { try { - let query = db.conversations; - - if (!includeEmpty) { - // 只获取有消息的会话 - query = query.filter(item => item.msg_text && item.msg_text.length > 0); - } - - // 按更新时间倒序排列 - const conversations = await query - .toArray() - .then(items => items.sort((a, b) => { - // 置顶的会话优先 - if (a.is_top !== b.is_top) return b.is_top - a.is_top; - // 然后按更新时间排序 - return new Date(b.updated_at) - new Date(a.updated_at); - })); - - return conversations; + const filterFn = item => !includeEmpty ? (item.msg_text && item.msg_text.length > 0) : true; + + // 分别查询置顶和非置顶会话,以利用索引并优化性能 + const topConversationsPromise = db.conversations + .where('is_top') + .equals(1) + .sortBy('updated_at') + .then(arr => arr.reverse().filter(filterFn)); + + const otherConversationsPromise = db.conversations + .where('is_top') + .notEqual(1) + .sortBy('updated_at') + .then(arr => arr.reverse().filter(filterFn)); + + const [topConversations, otherConversations] = await Promise.all([ + topConversationsPromise, + otherConversationsPromise, + ]); + + return [...topConversations, ...otherConversations]; } catch (error) { console.error('获取会话列表失败:', error); throw error; @@ -432,19 +269,14 @@ export async function getConversations(includeEmpty = false) { /** * 获取指定会话 - * @param {number} talkType - 会话类型(1:私聊, 2:群聊) - * @param {number} receiverId - 接收者ID(私聊为对方用户ID,群聊为群ID) - * @returns {Promise} - 返回会话对象,如果不存在则返回null + * @param {number} talkType - 会话类型 + * @param {number} receiverId - 接收者ID + * @returns {Promise} 会话对象 */ export async function getConversation(talkType, receiverId) { try { const indexName = `${talkType}_${receiverId}`; - const conversation = await db.conversations - .where('index_name') - .equals(indexName) - .first(); - - return conversation || null; + return await db.conversations.get({ index_name: indexName }); } catch (error) { console.error('获取会话失败:', error); throw error; @@ -455,31 +287,22 @@ export async function getConversation(talkType, receiverId) { * 更新会话的未读消息数 * @param {number} talkType - 会话类型 * @param {number} receiverId - 接收者ID - * @param {number} unreadNum - 未读消息数量,如果为null则增加1 - * @returns {Promise} - 操作是否成功 + * @param {number|null} unreadNum - 未读消息数。如果为null,则自增1 + * @returns {Promise} 更新的记录数 */ export async function updateConversationUnreadNum(talkType, receiverId, unreadNum = null) { try { const indexName = `${talkType}_${receiverId}`; - const conversation = await db.conversations - .where('index_name') - .equals(indexName) - .first(); - + const conversation = await db.conversations.get({ index_name: indexName }); + if (conversation) { - if (unreadNum === null) { - // 增加未读消息数 - unreadNum = (conversation.unread_num || 0) + 1; - } - - await db.conversations.update(conversation.id, { unread_num: unreadNum }); - return true; + const newUnreadNum = unreadNum === null ? (conversation.unread_num || 0) + 1 : unreadNum; + return await db.conversations.update(conversation.id, { unread_num: newUnreadNum }); } - - return false; + return 0; } catch (error) { - console.error('更新会话未读消息数失败:', error); - return false; + console.error('更新会话未读数失败:', error); + throw error; } } @@ -487,276 +310,74 @@ export async function updateConversationUnreadNum(talkType, receiverId, unreadNu * 清空会话的未读消息数 * @param {number} talkType - 会话类型 * @param {number} receiverId - 接收者ID - * @returns {Promise} - 操作是否成功 + * @returns {Promise} 更新的记录数 */ -export async function clearConversationUnreadNum(talkType, receiverId) { +export function clearConversationUnreadNum(talkType, receiverId) { return updateConversationUnreadNum(talkType, receiverId, 0); } /** - * 删除会话 + * 删除会话及其相关的消息 * @param {number} conversationId - 会话ID - * @param {boolean} deleteMessages - 是否同时删除相关的消息记录 - * @returns {Promise} - 操作是否成功 + * @param {boolean} [deleteMessages=false] - 是否同时删除相关的消息记录 + * @returns {Promise} */ export async function deleteConversation(conversationId, deleteMessages = false) { try { - const conversation = await db.conversations.get(conversationId); - - if (!conversation) return false; - - // 删除会话 - await db.conversations.delete(conversationId); - - // 如果需要,同时删除相关的消息记录 - if (deleteMessages) { - const { talk_type, receiver_id } = conversation; - - if (talk_type === TalkType.PRIVATE) { - // 删除私聊消息 - await db.messages - .where('talk_type').equals(TalkType.PRIVATE) - .and(item => { - return (item.user_id === receiver_id || item.receiver_id === receiver_id); - }) - .delete(); - } else { - // 删除群聊消息 - await db.messages - .where('talk_type').equals(TalkType.GROUP) - .and(item => item.receiver_id === receiver_id) - .delete(); + await db.transaction('rw', db.conversations, db.messages, async () => { + const conversation = await db.conversations.get(conversationId); + if (!conversation) return; + + // 删除会话 + await db.conversations.delete(conversationId); + + // 如果需要,删除关联的消息 + if (deleteMessages) { + const { talk_type, receiver_id } = conversation; + await db.messages.where({ '[talk_type+receiver_id]': [talk_type, receiver_id] }).delete(); } - } - - return true; + }); } catch (error) { console.error('删除会话失败:', error); - return false; + throw error; } } /** - * 更新会话的最后一条消息 - * @param {Object} message - 消息对象 - * @returns {Promise} - 操作是否成功 + * 更新会话的最后一条消息摘要 + * @param {object} message - 消息对象 + * @returns {Promise} 更新的记录数 */ export async function updateConversationLastMessage(message) { try { const { talk_type, user_id, receiver_id, msg_type } = message; - let targetReceiverId; - - if (talk_type === TalkType.PRIVATE) { - // 私聊:对方ID作为会话的receiver_id - targetReceiverId = user_id === receiver_id ? user_id : receiver_id; - } else { - // 群聊:群ID作为会话的receiver_id - targetReceiverId = receiver_id; - } - + const targetReceiverId = talk_type === TalkType.PRIVATE ? (user_id === receiver_id ? user_id : receiver_id) : receiver_id; const indexName = `${talk_type}_${targetReceiverId}`; - const conversation = await db.conversations - .where('index_name') - .equals(indexName) - .first(); - - if (!conversation) return false; - - // 根据消息类型生成显示文本 + + const conversation = await db.conversations.get({ index_name: indexName }); + if (!conversation) return 0; + let msgText = ''; switch (msg_type) { - case MessageType.TEXT: - msgText = message.content || ''; - break; - case MessageType.IMAGE: - msgText = '[图片消息]'; - break; - case MessageType.FILE: - msgText = '[文件消息]'; - break; - case MessageType.AUDIO: - msgText = '[语音消息]'; - break; - case MessageType.VIDEO: - msgText = '[视频消息]'; - break; - case MessageType.LOCATION: - msgText = '[位置消息]'; - break; - case MessageType.CARD: - msgText = '[名片消息]'; - break; - default: - msgText = '[未知类型消息]'; + case MessageType.TEXT: msgText = message.content || ''; break; + case MessageType.IMAGE: msgText = '[图片]'; break; + case MessageType.FILE: msgText = '[文件]'; break; + case MessageType.AUDIO: msgText = '[语音]'; break; + case MessageType.VIDEO: msgText = '[视频]'; break; + case MessageType.LOCATION: msgText = '[位置]'; break; + case MessageType.CARD: msgText = '[名片]'; break; + default: msgText = '[未知消息]'; } - - // 更新会话的最后消息和时间 - await db.conversations.update(conversation.id, { + + return await db.conversations.update(conversation.id, { msg_text: msgText, content: message.content || '', - updated_at: message.created_at + updated_at: message.created_at, }); - - return true; } catch (error) { console.error('更新会话最后消息失败:', error); - return false; + throw error; } } -/** - * 示例:如何使用聊天记录数据库 - * - * // 1. 添加一条消息 - * const newMessage = { - * msg_id: '5a266eb831594b2b8be7c9fdf34986df', - * sequence: 184, - * talk_type: 1, // 私聊 - * msg_type: 4, // 语音消息 - * user_id: 1496, - * receiver_id: 1774, - * nickname: '王一峰', - * avatar: 'https://cdn-test.szjixun.cn/fonchain-main/dev/image/4692/oa/36b09c00-c2c3-453d-9aaf-ac41d47d564b.png', - * is_revoke: 0, - * is_mark: 0, - * is_read: 0, - * created_at: '2025-06-30 09:11:14', - * extra: { - * duration: 0, - * name: '', - * size: 15984, - * url: 'https://cdn-test.szjixun.cn/fonchain-main/test/file/default/fonchain-chat/2b595dbc-6a2b-498e-802a-880e93d1e45a.mp3' - * }, - * erp_user_id: 4692 - * }; - * - * addMessage(newMessage).then(msgId => { - * console.log('消息添加成功,ID:', msgId); - * }); - * - * // 2. 获取私聊消息列表 - * getMessages(TalkType.PRIVATE, 1496, 1774, 20, 0).then(messages => { - * console.log('获取到20条私聊消息:', messages); - * }); - * - * // 获取特定sequence之前的消息 - * getMessages(TalkType.PRIVATE, 1496, 1774, 20, 0, 1000).then(messages => { - * console.log('获取sequence小于1000的20条私聊消息:', messages); - * }); - * - * // 3. 标记消息为已读 - * markMessageAsRead('5a266eb831594b2b8be7c9fdf34986df').then(success => { - * console.log('标记消息已读:', success ? '成功' : '失败'); - * }); - * - * // 4. 批量标记会话消息为已读 - * markMessagesAsRead(TalkType.PRIVATE, 1496, 1774).then(count => { - * console.log(`成功标记 ${count} 条消息为已读`); - * }); - * - * // 5. 撤回消息 - * revokeMessage('5a266eb831594b2b8be7c9fdf34986df').then(success => { - * console.log('撤回消息:', success ? '成功' : '失败'); - * }); - * - * // 6. 获取未读消息数量 - * getUnreadCount(1496).then(result => { - * console.log('未读消息统计:', result); - * }); - * - * // 7. 添加或更新会话 - * const newConversation = { - * talk_type: 1, // 私聊 - * receiver_id: 1774, - * name: "周俊耀", - * remark: "", - * avatar: "https://e-cdn.fontree.cn/fonchain-main/prod/image/18248/avatar/a0b2bee7-947f-465a-986e-10a1b2b87032.png", - * is_disturb: 0, - * is_top: 1, - * is_online: 0, - * is_robot: 0, - * is_dismiss: 0, - * is_quit: 0, - * unread_num: 0, - * content: "......", - * draft_text: "", - * msg_text: "[语音消息]", - * index_name: "1_1774", - * updated_at: "2025-06-30 10:27:27", - * atsign_num: 0, - * erp_user_id: 3346, - * group_member_num: 0, - * group_type: 0 - * }; - * - * addOrUpdateConversation(newConversation).then(id => { - * console.log('会话添加或更新成功,ID:', id); - * }); - * - * // 8. 获取所有会话列表 - * getConversations().then(conversations => { - * console.log('获取所有会话列表:', conversations); - * }); - * - * // 9. 获取指定会话 - * getConversation(TalkType.PRIVATE, 1774).then(conversation => { - * console.log('获取指定会话:', conversation); - * }); - * - * // 10. 更新会话未读消息数 - * updateConversationUnreadNum(TalkType.PRIVATE, 1774, 5).then(success => { - * console.log('更新会话未读消息数:', success ? '成功' : '失败'); - * }); - * - * // 11. 清空会话未读消息数 - * clearConversationUnreadNum(TalkType.PRIVATE, 1774).then(success => { - * console.log('清空会话未读消息数:', success ? '成功' : '失败'); - * }); - * - * // 12. 更新会话最后一条消息 - * updateConversationLastMessage(newMessage).then(success => { - * console.log('更新会话最后一条消息:', success ? '成功' : '失败'); - * }); - * - * // 13. 删除会话 - * deleteConversation(5811, false).then(success => { - * console.log('删除会话:', success ? '成功' : '失败'); - * }); - * - * // 14. 批量添加或更新聊天记录 - * const messagesFromServer = [ - * { - * msg_id: 'server-msg-id-1', - * talk_type: TalkType.PRIVATE, - * msg_type: MessageType.TEXT, - * user_id: 1000, - * receiver_id: 2000, - * content: '你好,这是第一条消息', - * is_read: 1, - * sequence: 1, - * created_at: '2023-05-01 10:00:00' - * }, - * { - * msg_id: 'server-msg-id-2', - * talk_type: TalkType.PRIVATE, - * msg_type: MessageType.TEXT, - * user_id: 2000, - * receiver_id: 1000, - * content: '你好,这是回复消息', - * is_read: 0, - * sequence: 2, - * created_at: '2023-05-01 10:01:00' - * } - * ]; - * - * // 使用sequence作为排序和替换的键 - * batchAddOrUpdateMessages( - * messagesFromServer, - * TalkType.PRIVATE, - * 2000, // 接收者ID(私聊为对方用户ID,群聊为群ID) - * true, // 替换已存在的消息 - * 'sequence' // 使用sequence作为排序和替换的键 - * ).then(result => { - * console.log(`添加了${result.added}条新消息,更新了${result.updated}条消息`); - * }); - */ \ No newline at end of file +// #endregion 会话操作 \ No newline at end of file diff --git a/src/views/message/inner/panel/PanelContent.vue b/src/views/message/inner/panel/PanelContent.vue index 0cc7fc5..339cbdd 100644 --- a/src/views/message/inner/panel/PanelContent.vue +++ b/src/views/message/inner/panel/PanelContent.vue @@ -372,7 +372,7 @@ let noRefreshTimer: number | null = null watch( () => props, async (newProps) => { - console.log('监听props') + console.log('监听props',newProps) await nextTick() // 生成当前会话的唯一标识 const newSessionKey = `${newProps.talk_type}_${newProps.receiver_id}` @@ -415,6 +415,7 @@ watch( }, 3000) return } + console.log('fsd付大夫') onLoad( { receiver_id: newProps.receiver_id,