uniapp 集成腾讯云 IM 消息搜索功能
UniApp 集成腾讯云 IM 消息搜索功能实战指南
一、功能实现原理
腾讯云 IM 通过 消息漫游 + 服务端搜索接口 实现消息检索,核心机制如下:
- 数据存储:消息默认存储7天(可扩展至30天)
- 索引构建:基于消息内容自动建立倒排索引
- 检索接口:提供关键词匹配、时间范围、发送者等多维度查询
- 结果排序:按消息时间戳倒序排列
二、核心实现步骤
1. 初始化搜索模块
// services/search.js
import { initIM } from './im'const tim = initIM()// 配置搜索参数
const SEARCH_CONFIG = {MAX_KEYWORD_LENGTH: 30, // 最大关键词长度DEFAULT_PAGE_SIZE: 20, // 默认分页大小MAX_HISTORY_DAYS: 7 // 最大历史查询天数
}// 创建搜索实例
export function createSearchEngine(options) {return {conversationID: options.conversationID,keyword: '',timeRange: {startTime: Date.now() - 7 * 24 * 3600 * 1000,endTime: Date.now()},page: 1,pageSize: SEARCH_CONFIG.DEFAULT_PAGE_SIZE}
}
2. 执行消息搜索
export async function executeSearch(engine) {const tim = initIM()try {const res = await tim.getMessageList({conversationID: engine.conversationID,keyword: engine.keyword,nextSeq: engine.page === 1 ? 0 : engine.nextSeq,count: engine.pageSize})return {messages: res.data.messageList || [],hasNext: res.data.isCompleted === 0,nextSeq: res.data.nextSeq}} catch (error) {console.error('搜索失败:', error)throw new Error('消息搜索失败,请检查网络')}
}
3. 搜索结果渲染
<template><view class="search-results"><scroll-view scroll-y@scrolltolower="loadMore"><view v-for="(msg, index) in results":key="msg.clientMsgID"class="search-item"><view class="highlight-text">{{ msg.payload.text.replace(new RegExp(engine.keyword, 'gi'), (match) => `<mark>${match}</mark>`) }}</view><view class="meta-info">{{ formatTime(msg.time) }} - {{ msg.from }}</view></view><view v-if="loading" class="loading-tip">加载中...</view><view v-if="!hasNext" class="end-tip">没有更多结果了</view></scroll-view></view>
</template><script>
export default {data() {return {engine: createSearchEngine({conversationID: 'current_conv_id'}),results: [],loading: false,hasNext: true}},methods: {async loadMore() {if (this.loading || !this.hasNext) returnthis.loading = trueconst res = await executeSearch(this.engine)this.results = [...this.results, ...res.messages]this.hasNext = res.hasNextthis.loading = false}}
}
</script>
三、关键问题处理
1. 性能优化策略
// 防抖搜索(输入框场景)
let searchDebounce = nullexport function debouncedSearch(engine, callback) {clearTimeout(searchDebounce)searchDebounce = setTimeout(async () => {engine.page = 1const res = await executeSearch(engine)callback(res.messages, res.hasNext)}, 300) // 300ms防抖
}
2. 复杂查询构建
// 高级查询构造器
export function buildAdvancedQuery(options) {const tim = initIM()return {conversationID: options.convID,keyword: options.keyword || '',filter: {fromAccount: options.from || [],timeRange: options.timeRange || {startTime: Date.now() - 7 * 24 * 3600 * 1000,endTime: Date.now()}},pageIndex: options.page || 1,pageSize: options.pageSize || 20}
}// 使用示例
const query = buildAdvancedQuery({convID: 'group123',from: 'userA',timeRange: {startTime: new Date(2023, 0, 1).getTime(),endTime: new Date(2023, 1, 1).getTime()}
})
3. 敏感词过滤
// 集成腾讯云内容安全
export async function checkSensitiveWords(text) {const res = await axios.post('https://cms.tencentcloudapi.com/', {Action: 'TextModeration',Content: text,// 其他必要参数...})return res.data.Suggestion === 'Pass'
}// 搜索前校验
export async function validateSearchKeyword(keyword) {if (await checkSensitiveWords(keyword)) {return keyword}throw new Error('包含敏感词汇')
}
四、高级功能扩展
1. 语音消息转文本搜索
// 集成语音识别服务
export async function transcribeAudioMessage(fileKey) {const res = await axios.post('https://asr.tencentcloudapi.com/', {Action: 'SentenceRecognition',ProjectId: 0,SubServiceType: 2,EngSerViceType: '16k_zh',SourceType: 1,Url: fileKey})return res.data.Result
}// 修改搜索逻辑
async function searchAudioMessages(engine) {const { messages } = await executeSearch(engine)const transcriptions = await Promise.all(messages.filter(msg => msg.type === 'TIMAudioElem').map(async msg => ({...msg,transcription: await transcribeAudioMessage(msg.payload.fileKey)})))return transcriptions
}
2. 搜索结果聚合
// 按发送者聚合结果
function groupBySender(messages) {return messages.reduce((acc, msg) => {if (!acc[msg.from]) acc[msg.from] = []acc[msg.from].push(msg)return acc}, {})
}// 按日期聚合
function groupByDate(messages) {return messages.reduce((acc, msg) => {const dateKey = dayjs(msg.time).format('YYYY-MM-DD')if (!acc[dateKey]) acc[dateKey] = []acc[dateKey].push(msg)return acc}, {})
}
3. 搜索历史管理
// 本地存储搜索历史
export function saveSearchHistory(keyword) {const history = uni.getStorageSync('search_history') || []const newHistory = [...new Set([keyword, ...history.slice(0, 49)])]uni.setStorageSync('search_history', newHistory)
}// 清除历史记录
export function clearSearchHistory() {uni.removeStorageSync('search_history')
}
五、常见问题排查
-
Q: 搜索结果不完整
A: 检查时间范围设置,确保endTime > startTime,且在有效期内(默认7天) -
Q: 特殊字符搜索异常
A: 对关键词进行URL编码处理:encodeURIComponent(keyword)
-
Q: 群聊消息搜索失败
A: 确认群类型是否为Private(私有群),Public群需群主操作 -
Q: 消息内容高亮失效
A: 确保使用v-html指令渲染,并做好XSS防护:v-html="highlightedText"
六、性能优化建议
- 对超过1000条的会话禁用全局搜索
- 实现搜索结果虚拟滚动(仅渲染可视区域)
- 对高频关键词建立本地缓存(使用
uni.setStorage
) - 使用Web Worker处理复杂文本分析
- 限制最大并发搜索数为3