271 lines
7.1 KiB
JavaScript
271 lines
7.1 KiB
JavaScript
/**
|
||
* AI角色主动推送消息工具模块
|
||
*
|
||
* 功能说明:
|
||
* 1. 跟进消息:发送给已聊过天但一段时间没互动的用户
|
||
* 2. 打招呼消息:发送给还没有和任何角色聊过天的新用户
|
||
*/
|
||
|
||
const api = require('./api')
|
||
const config = require('../config/index')
|
||
|
||
// 上次检查时间(避免频繁请求)
|
||
let lastCheckTime = 0
|
||
// 检查间隔(毫秒)- 默认5分钟
|
||
const CHECK_INTERVAL = 5 * 60 * 1000
|
||
|
||
/**
|
||
* 获取待接收的主动推送消息
|
||
* @returns {Promise<Array>} 消息列表
|
||
*/
|
||
async function getPendingMessages() {
|
||
try {
|
||
const token = wx.getStorageSync(config.STORAGE_KEYS.TOKEN)
|
||
if (!token) {
|
||
console.log('[proactiveMessage] 未登录,跳过获取推送消息')
|
||
return []
|
||
}
|
||
|
||
console.log('[proactiveMessage] 开始获取待推送消息...')
|
||
const res = await api.proactiveMessage.getPending()
|
||
console.log('[proactiveMessage] API响应:', JSON.stringify(res))
|
||
|
||
if (res.success && res.data) {
|
||
console.log('[proactiveMessage] 获取到消息数量:', res.data.length)
|
||
return res.data || []
|
||
}
|
||
return []
|
||
} catch (error) {
|
||
console.error('[proactiveMessage] 获取推送消息失败:', error)
|
||
return []
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 检查并处理推送消息
|
||
* 在首页 onShow 或定时调用
|
||
* @param {object} options - 配置选项
|
||
* @param {boolean} options.force - 是否强制检查(忽略时间间隔)
|
||
* @param {function} options.onNewMessages - 收到新消息时的回调
|
||
* @returns {Promise<Array>} 消息列表
|
||
*/
|
||
async function checkAndShowMessages(options = {}) {
|
||
const { force = false, onNewMessages } = options
|
||
|
||
// 检查登录状态
|
||
const app = getApp()
|
||
if (!app || !app.globalData || !app.globalData.isLoggedIn) {
|
||
console.log('[proactiveMessage] 未登录,跳过检查')
|
||
return []
|
||
}
|
||
|
||
// 检查时间间隔(避免频繁请求)
|
||
const now = Date.now()
|
||
if (!force && lastCheckTime && (now - lastCheckTime < CHECK_INTERVAL)) {
|
||
console.log('[proactiveMessage] 距离上次检查不足5分钟,跳过。上次:', lastCheckTime, '现在:', now)
|
||
return []
|
||
}
|
||
|
||
console.log('[proactiveMessage] 开始检查推送消息,force:', force)
|
||
lastCheckTime = now
|
||
|
||
const messages = await getPendingMessages()
|
||
|
||
if (messages.length > 0) {
|
||
console.log('[proactiveMessage] 收到推送消息:', messages.length, '条')
|
||
console.log('[proactiveMessage] 消息详情:', JSON.stringify(messages))
|
||
|
||
// 更新会话列表的未读状态
|
||
messages.forEach(msg => {
|
||
updateConversationUnread(msg)
|
||
})
|
||
|
||
// 触发回调
|
||
if (typeof onNewMessages === 'function') {
|
||
onNewMessages(messages)
|
||
}
|
||
} else {
|
||
console.log('[proactiveMessage] 没有待推送消息')
|
||
}
|
||
|
||
return messages
|
||
}
|
||
|
||
/**
|
||
* 更新会话列表未读状态
|
||
* @param {object} msg - 推送消息对象
|
||
*/
|
||
function updateConversationUnread(msg) {
|
||
// 获取当前会话列表缓存
|
||
const cacheKey = 'proactive_messages_cache'
|
||
let cache = wx.getStorageSync(cacheKey) || {}
|
||
|
||
// 记录消息,避免重复处理
|
||
const msgKey = `${msg.character_id}_${msg.sent_at}`
|
||
if (cache[msgKey]) {
|
||
return // 已处理过
|
||
}
|
||
|
||
cache[msgKey] = {
|
||
character_id: msg.character_id,
|
||
character_name: msg.character_name,
|
||
content: msg.content,
|
||
message_type: msg.message_type,
|
||
sent_at: msg.sent_at,
|
||
processed_at: new Date().toISOString()
|
||
}
|
||
|
||
// 清理过期缓存(保留最近24小时的记录)
|
||
const oneDayAgo = Date.now() - 24 * 60 * 60 * 1000
|
||
Object.keys(cache).forEach(key => {
|
||
const item = cache[key]
|
||
if (new Date(item.processed_at).getTime() < oneDayAgo) {
|
||
delete cache[key]
|
||
}
|
||
})
|
||
|
||
wx.setStorageSync(cacheKey, cache)
|
||
|
||
// 触发页面更新
|
||
triggerPageRefresh()
|
||
}
|
||
|
||
/**
|
||
* 触发页面刷新
|
||
* 通知当前页面刷新会话列表
|
||
*/
|
||
function triggerPageRefresh() {
|
||
const pages = getCurrentPages()
|
||
if (pages.length === 0) return
|
||
|
||
const currentPage = pages[pages.length - 1]
|
||
|
||
// 如果当前页面有刷新会话列表的方法,调用它
|
||
if (currentPage && typeof currentPage.loadConversations === 'function') {
|
||
currentPage.loadConversations()
|
||
}
|
||
|
||
// 如果当前页面有刷新未读数的方法,调用它
|
||
if (currentPage && typeof currentPage.loadUnreadCount === 'function') {
|
||
currentPage.loadUnreadCount()
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 获取角色的未处理推送消息
|
||
* @param {string} characterId - 角色ID
|
||
* @returns {object|null} 消息对象
|
||
*/
|
||
function getCharacterPendingMessage(characterId) {
|
||
const cacheKey = 'proactive_messages_cache'
|
||
const cache = wx.getStorageSync(cacheKey) || {}
|
||
|
||
// 查找该角色的最新消息
|
||
let latestMsg = null
|
||
Object.values(cache).forEach(msg => {
|
||
if (msg.character_id === characterId) {
|
||
if (!latestMsg || new Date(msg.sent_at) > new Date(latestMsg.sent_at)) {
|
||
latestMsg = msg
|
||
}
|
||
}
|
||
})
|
||
|
||
return latestMsg
|
||
}
|
||
|
||
/**
|
||
* 清除角色的推送消息缓存
|
||
* 用户进入聊天后调用
|
||
* @param {string} characterId - 角色ID
|
||
*/
|
||
function clearCharacterMessages(characterId) {
|
||
const cacheKey = 'proactive_messages_cache'
|
||
let cache = wx.getStorageSync(cacheKey) || {}
|
||
|
||
// 删除该角色的所有消息
|
||
Object.keys(cache).forEach(key => {
|
||
if (cache[key].character_id === characterId) {
|
||
delete cache[key]
|
||
}
|
||
})
|
||
|
||
wx.setStorageSync(cacheKey, cache)
|
||
}
|
||
|
||
/**
|
||
* 标记角色的推送消息为已读
|
||
* 调用后端API标记已读,同时清除本地缓存
|
||
* @param {string} characterId - 角色ID
|
||
*/
|
||
async function markAsRead(characterId) {
|
||
if (!characterId) {
|
||
console.log('[proactiveMessage] 没有角色ID,跳过标记已读')
|
||
return
|
||
}
|
||
|
||
// 先清除本地缓存
|
||
clearCharacterMessages(characterId)
|
||
|
||
// 调用后端API标记已读
|
||
try {
|
||
const res = await api.proactiveMessage.markAsRead({
|
||
character_id: characterId
|
||
})
|
||
console.log('[proactiveMessage] 标记已读结果:', JSON.stringify(res))
|
||
} catch (err) {
|
||
console.log('[proactiveMessage] 标记已读失败:', err)
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 按消息ID列表标记已读
|
||
* @param {Array<number>} messageIds - 消息ID列表
|
||
*/
|
||
async function markAsReadByIds(messageIds) {
|
||
if (!messageIds || messageIds.length === 0) {
|
||
return
|
||
}
|
||
|
||
try {
|
||
const res = await api.proactiveMessage.markAsRead({
|
||
message_ids: messageIds
|
||
})
|
||
console.log('[proactiveMessage] 按ID标记已读结果:', JSON.stringify(res))
|
||
} catch (err) {
|
||
console.log('[proactiveMessage] 按ID标记已读失败:', err)
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 启动定时检查
|
||
* @param {number} interval - 检查间隔(毫秒),默认5分钟
|
||
* @returns {number} 定时器ID
|
||
*/
|
||
function startPeriodicCheck(interval = CHECK_INTERVAL) {
|
||
return setInterval(() => {
|
||
checkAndShowMessages()
|
||
}, interval)
|
||
}
|
||
|
||
/**
|
||
* 停止定时检查
|
||
* @param {number} timerId - 定时器ID
|
||
*/
|
||
function stopPeriodicCheck(timerId) {
|
||
if (timerId) {
|
||
clearInterval(timerId)
|
||
}
|
||
}
|
||
|
||
module.exports = {
|
||
getPendingMessages,
|
||
checkAndShowMessages,
|
||
getCharacterPendingMessage,
|
||
clearCharacterMessages,
|
||
markAsRead,
|
||
markAsReadByIds,
|
||
startPeriodicCheck,
|
||
stopPeriodicCheck,
|
||
CHECK_INTERVAL
|
||
}
|