miniprogramme/utils/message-search-manager.js

485 lines
13 KiB
JavaScript
Raw Normal View History

2025-09-12 16:08:17 +08:00
// 消息搜索管理器 - 微信小程序专用
// 处理消息搜索、历史记录管理、本地缓存等
const apiClient = require('./api-client.js');
/**
* 消息搜索管理器
* 功能
* 1. 全局消息搜索
* 2. 会话内搜索
* 3. 搜索结果高亮
* 4. 搜索历史管理
* 5. 本地缓存优化
* 6. 分页加载
*/
class MessageSearchManager {
constructor() {
this.isInitialized = false;
// 搜索配置
this.searchConfig = {
// 最小搜索关键词长度
minKeywordLength: 1,
// 搜索结果每页数量
pageSize: 20,
// 最大搜索历史数量
maxSearchHistory: 50,
// 本地缓存过期时间(毫秒)
cacheExpireTime: 30 * 60 * 1000, // 30分钟
// 搜索防抖延迟(毫秒)
debounceDelay: 300,
// 支持的搜索类型
searchTypes: ['text', 'image', 'file', 'all']
};
// 搜索缓存
this.searchCache = new Map();
// 搜索历史
this.searchHistory = [];
// 当前搜索状态
this.currentSearch = {
keyword: '',
type: 'all',
conversationId: null,
page: 1,
hasMore: true,
loading: false,
results: []
};
// 防抖定时器
this.debounceTimer = null;
this.init();
}
// 初始化搜索管理器
async init() {
if (this.isInitialized) return;
console.log('🔍 初始化消息搜索管理器...');
try {
// 加载搜索历史
await this.loadSearchHistory();
// 清理过期缓存
this.cleanupExpiredCache();
this.isInitialized = true;
console.log('✅ 消息搜索管理器初始化完成');
} catch (error) {
console.error('❌ 消息搜索管理器初始化失败:', error);
}
}
// 全局搜索消息
async searchMessages(keyword, options = {}) {
try {
// 验证搜索关键词
if (!this.validateKeyword(keyword)) {
return { success: false, error: '搜索关键词无效' };
}
console.log('🔍 搜索消息:', keyword);
// 设置搜索参数
const searchParams = {
keyword: keyword.trim(),
type: options.type || 'all',
conversationId: options.conversationId || null,
page: options.page || 1,
pageSize: options.pageSize || this.searchConfig.pageSize
};
// 检查缓存
const cacheKey = this.generateCacheKey(searchParams);
const cachedResult = this.getFromCache(cacheKey);
if (cachedResult) {
console.log('🔍 使用缓存搜索结果');
return cachedResult;
}
// 更新搜索状态
this.updateSearchState(searchParams);
// 执行搜索
const result = await this.performSearch(searchParams);
// 缓存结果
if (result.success) {
this.saveToCache(cacheKey, result);
// 添加到搜索历史
this.addToSearchHistory(keyword);
}
return result;
} catch (error) {
console.error('❌ 搜索消息失败:', error);
return { success: false, error: error.message };
}
}
// 会话内搜索
async searchInConversation(conversationId, keyword, options = {}) {
return await this.searchMessages(keyword, {
...options,
conversationId: conversationId
});
}
// 防抖搜索
searchWithDebounce(keyword, options = {}, callback) {
// 清除之前的定时器
if (this.debounceTimer) {
clearTimeout(this.debounceTimer);
}
// 设置新的定时器
this.debounceTimer = setTimeout(async () => {
try {
const result = await this.searchMessages(keyword, options);
if (callback) {
callback(result);
}
} catch (error) {
console.error('❌ 防抖搜索失败:', error);
if (callback) {
callback({ success: false, error: error.message });
}
}
}, this.searchConfig.debounceDelay);
}
// 执行搜索
async performSearch(searchParams) {
try {
this.currentSearch.loading = true;
// 构建搜索请求
const requestData = {
keyword: searchParams.keyword,
messageType: searchParams.type === 'all' ? null : this.getMessageTypeCode(searchParams.type),
page: searchParams.page,
pageSize: searchParams.pageSize
};
// 如果指定了会话ID则进行会话内搜索
if (searchParams.conversationId) {
requestData.conversationId = searchParams.conversationId;
}
// 调用搜索API按统一客户端签名
const response = await apiClient.post('/api/v1/messages/search', requestData);
if (response && (response.code === 0 || response.code === 200 || response.success)) {
const searchResult = {
success: true,
data: {
messages: response.data?.messages || [],
total: response.data?.total || 0,
page: searchParams.page,
pageSize: searchParams.pageSize,
hasMore: response.data?.hasMore || false,
keyword: searchParams.keyword,
searchTime: Date.now()
}
};
// 处理搜索结果
searchResult.data.messages = this.processSearchResults(
searchResult.data.messages,
searchParams.keyword
);
console.log(`🔍 搜索完成,找到 ${searchResult.data.total} 条消息`);
return searchResult;
} else {
const msg = response?.message || response?.error || '搜索失败';
throw new Error(msg);
}
} catch (error) {
console.error('❌ 执行搜索失败:', error);
return { success: false, error: error.message };
} finally {
this.currentSearch.loading = false;
}
}
// 处理搜索结果
processSearchResults(messages, keyword) {
return messages.map(message => {
// 添加高亮信息
const highlightedContent = this.highlightKeyword(message.content, keyword);
return {
...message,
highlightedContent: highlightedContent,
searchKeyword: keyword,
// 添加消息摘要(用于显示上下文)
summary: this.generateMessageSummary(message.content, keyword)
};
});
}
// 关键词高亮
highlightKeyword(content, keyword) {
if (!content || !keyword) return content;
try {
// 转义特殊字符
const escapedKeyword = keyword.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
const regex = new RegExp(`(${escapedKeyword})`, 'gi');
return content.replace(regex, '<mark class="search-highlight">$1</mark>');
} catch (error) {
console.error('❌ 关键词高亮失败:', error);
return content;
}
}
// 生成消息摘要
generateMessageSummary(content, keyword, maxLength = 100) {
if (!content || !keyword) return content;
try {
const keywordIndex = content.toLowerCase().indexOf(keyword.toLowerCase());
if (keywordIndex === -1) return content.substring(0, maxLength);
// 计算摘要范围
const start = Math.max(0, keywordIndex - 30);
const end = Math.min(content.length, keywordIndex + keyword.length + 30);
let summary = content.substring(start, end);
// 添加省略号
if (start > 0) summary = '...' + summary;
if (end < content.length) summary = summary + '...';
return summary;
} catch (error) {
console.error('❌ 生成消息摘要失败:', error);
return content.substring(0, maxLength);
}
}
// 加载更多搜索结果
async loadMoreResults() {
if (!this.currentSearch.hasMore || this.currentSearch.loading) {
return { success: false, error: '没有更多结果' };
}
const nextPage = this.currentSearch.page + 1;
const result = await this.searchMessages(this.currentSearch.keyword, {
type: this.currentSearch.type,
conversationId: this.currentSearch.conversationId,
page: nextPage
});
if (result.success) {
// 合并结果
this.currentSearch.results = [...this.currentSearch.results, ...result.data.messages];
this.currentSearch.page = nextPage;
this.currentSearch.hasMore = result.data.hasMore;
}
return result;
}
// 清除搜索结果
clearSearchResults() {
this.currentSearch = {
keyword: '',
type: 'all',
conversationId: null,
page: 1,
hasMore: true,
loading: false,
results: []
};
}
// 验证搜索关键词
validateKeyword(keyword) {
if (!keyword || typeof keyword !== 'string') {
return false;
}
const trimmedKeyword = keyword.trim();
return trimmedKeyword.length >= this.searchConfig.minKeywordLength;
}
// 获取消息类型代码
getMessageTypeCode(type) {
const typeMap = {
'text': 0,
'image': 1,
'voice': 2,
'video': 3,
'file': 4
};
return typeMap[type] || null;
}
// 更新搜索状态
updateSearchState(searchParams) {
this.currentSearch = {
keyword: searchParams.keyword,
type: searchParams.type,
conversationId: searchParams.conversationId,
page: searchParams.page,
hasMore: true,
loading: true,
results: []
};
}
// 生成缓存键
generateCacheKey(searchParams) {
return `search_${searchParams.keyword}_${searchParams.type}_${searchParams.conversationId || 'global'}_${searchParams.page}`;
}
// 从缓存获取
getFromCache(cacheKey) {
const cached = this.searchCache.get(cacheKey);
if (cached && (Date.now() - cached.timestamp) < this.searchConfig.cacheExpireTime) {
return cached.data;
}
return null;
}
// 保存到缓存
saveToCache(cacheKey, data) {
this.searchCache.set(cacheKey, {
data: data,
timestamp: Date.now()
});
// 限制缓存大小
if (this.searchCache.size > 100) {
const firstKey = this.searchCache.keys().next().value;
this.searchCache.delete(firstKey);
}
}
// 清理过期缓存
cleanupExpiredCache() {
const now = Date.now();
for (const [key, value] of this.searchCache) {
if (now - value.timestamp > this.searchConfig.cacheExpireTime) {
this.searchCache.delete(key);
}
}
}
// 添加到搜索历史
addToSearchHistory(keyword) {
const trimmedKeyword = keyword.trim();
if (!trimmedKeyword) return;
// 移除重复项
this.searchHistory = this.searchHistory.filter(item => item !== trimmedKeyword);
// 添加到开头
this.searchHistory.unshift(trimmedKeyword);
// 限制历史数量
if (this.searchHistory.length > this.searchConfig.maxSearchHistory) {
this.searchHistory = this.searchHistory.slice(0, this.searchConfig.maxSearchHistory);
}
// 保存到本地存储
this.saveSearchHistory();
}
// 获取搜索历史
getSearchHistory() {
return [...this.searchHistory];
}
// 清除搜索历史
clearSearchHistory() {
this.searchHistory = [];
this.saveSearchHistory();
}
// 删除搜索历史项
removeSearchHistoryItem(keyword) {
this.searchHistory = this.searchHistory.filter(item => item !== keyword);
this.saveSearchHistory();
}
// 加载搜索历史
async loadSearchHistory() {
try {
const history = wx.getStorageSync('messageSearchHistory') || [];
this.searchHistory = history;
} catch (error) {
console.error('❌ 加载搜索历史失败:', error);
}
}
// 保存搜索历史
async saveSearchHistory() {
try {
wx.setStorageSync('messageSearchHistory', this.searchHistory);
} catch (error) {
console.error('❌ 保存搜索历史失败:', error);
}
}
// 获取搜索建议
getSearchSuggestions(keyword) {
if (!keyword) return this.searchHistory.slice(0, 10);
const lowerKeyword = keyword.toLowerCase();
return this.searchHistory
.filter(item => item.toLowerCase().includes(lowerKeyword))
.slice(0, 10);
}
// 获取当前搜索状态
getCurrentSearchState() {
return { ...this.currentSearch };
}
// 获取搜索统计
getSearchStats() {
return {
historyCount: this.searchHistory.length,
cacheSize: this.searchCache.size,
currentKeyword: this.currentSearch.keyword,
isLoading: this.currentSearch.loading,
hasResults: this.currentSearch.results.length > 0
};
}
// 重置搜索管理器
reset() {
this.searchCache.clear();
this.clearSearchResults();
this.clearSearchHistory();
}
}
// 创建全局实例
const messageSearchManager = new MessageSearchManager();
module.exports = messageSearchManager;