const BaseHandler = require('./baseHandler'); const ConfigManager = require('../services/configManager'); const command = require('../core/command'); const config = require('../infrastructure/config'); const chatManager = require('../../job/managers/chatManager'); const db = require('../../dbProxy'); /** * 自动沟通处理器 * 负责自动回复 HR 消息。auto_chat 是任务,其下按指令执行:获取列表 → 获取详情 →(若需回复)发送消息 */ class ChatHandler extends BaseHandler { /** * 处理自动沟通任务 * @param {object} task - 任务对象 * @returns {Promise} 执行结果 */ async handle(task) { return await this.execute(task, async () => { return await this.doChat(task); }, { checkAuth: true, checkOnline: true, recordDeviceMetrics: true }); } /** * 执行沟通逻辑:先下发「获取列表」指令,再对每个会话下发「获取详情」→(若需回复)「发送消息」指令 */ async doChat(task) { const { sn_code, taskParams } = task; const platform = taskParams.platform || 'boss'; console.log(`[自动沟通] 开始 - 设备: ${sn_code}`); const accountConfig = await this.getAccountConfig(sn_code, ['platform_type', 'chat_strategy']); if (!accountConfig) { return { chatCount: 0, message: '未找到账户配置' }; } const chatStrategy = ConfigManager.parseChatStrategy(accountConfig.chat_strategy); const timeRange = ConfigManager.getTimeRange(chatStrategy); if (timeRange) { const timeRangeValidator = require('../services/timeRangeValidator'); const timeCheck = timeRangeValidator.checkTimeRange(timeRange); if (!timeCheck.allowed) { return { chatCount: 0, message: timeCheck.reason }; } } const platform_type = platform || accountConfig.platform_type || 'boss'; const page_count = chatStrategy.page_count || 3; // 1. 下发「获取列表」指令 const list_command = { command_type: 'get_chat_list', command_name: '获取聊天列表', command_params: { platform: platform_type, pageCount: page_count }, priority: config.getTaskPriority('auto_chat') || 6 }; const list_exec = await command.executeCommands(task.id, [list_command], this.mqttClient); const list_result = list_exec?.results?.[0]?.result; const friend_list = Array.isArray(list_result?.friendList) ? list_result.friendList : []; if (friend_list.length === 0) { console.log(`[自动沟通] 完成 - 设备: ${sn_code},无会话`); return { chatCount: 0, message: '没有可沟通的会话', detail: { total_contacts: 0 } }; } this._syncFriendListToChatRecords(sn_code, platform_type, friend_list); let replied_count = 0; const details = []; for (const friend of friend_list) { if (!friend.friendId) continue; const item = await this._processOneFriend(task, friend, sn_code, platform_type); details.push(item); if (item.replied) replied_count++; } console.log(`[自动沟通] 完成 - 设备: ${sn_code},会话 ${friend_list.length},回复 ${replied_count}`); return { chatCount: replied_count, message: '自动沟通完成', detail: { total_contacts: friend_list.length, replied_count, details } }; } /** 将会话列表同步到 chat_records,内部 catch 仅打日志 */ async _syncFriendListToChatRecords(sn_code, platform_type, friend_list) { try { const chatRecordsModel = db.getModel('chat_records'); for (const friend of friend_list) { const friend_id = friend.friendId; if (friend_id == null) continue; const encryptId = friend.encryptFriendId || ''; const existing = await chatRecordsModel.findOne({ where: { sn_code, platform: platform_type, encryptFriendId: encryptId } }); const baseData = { sn_code, platform: platform_type, friendId: friend_id, encryptFriendId: encryptId, name: friend.name || '', updateTime: friend.updateTime != null ? friend.updateTime : null, brandName: friend.brandName || '', jobName: friend.jobName || '', jobCity: friend.jobCity || '', positionName: friend.positionName || '', bossTitle: friend.bossTitle || '', friendSource: friend.friendSource != null ? friend.friendSource : 0, jobTypeDesc: friend.jobTypeDesc || '', waterLevel: friend.waterLevel != null ? friend.waterLevel : 0 }; if (existing) await existing.update(baseData); else await chatRecordsModel.create(baseData); } console.log(`[自动沟通] 已同步 ${friend_list.length} 条会话到 chat_records`); } catch (e) { console.warn('[自动沟通] 同步聊天会话列表到 chat_records 失败:', e.message); } } /** * 落库 chat_message,入参为解析后格式 { variant, messages, data, job } * 有 messages 则每条一条记录;仅会话时 mid=0 存 { data, job } */ async _saveChatMessagesToDb(parsed, friend, sn_code, platform_type) { if (!parsed) return; const messages = Array.isArray(parsed.messages) ? parsed.messages : []; const has_session = parsed.data != null || parsed.job != null; if (messages.length === 0 && !has_session) return; try { const chatMessageModel = db.getModel('chat_message'); const friend_id = friend.friendId; const encrypt_id = friend.encryptFriendId || ''; const fetch_time = new Date(); const base = { sn_code, platform: platform_type, friendId: friend_id, encryptFriendId: encrypt_id, fetch_time }; if (messages.length > 0) { for (const msg of messages) { const mid = msg.mid != null ? msg.mid : 0; const existing = await chatMessageModel.findOne({ where: { sn_code, platform: platform_type, friendId: friend_id, mid } }); const row = { ...base, mid, message_data: msg }; if (existing) await existing.update(row); else await chatMessageModel.create(row); } } else { const boss_payload = { data: parsed.data || null, job: parsed.job || null }; const existing = await chatMessageModel.findOne({ where: { sn_code, platform: platform_type, friendId: friend_id, mid: 0 } }); const row = { ...base, mid: 0, message_data: boss_payload }; if (existing) await existing.update(row); else await chatMessageModel.create(row); } } catch (e) { console.warn('[自动沟通] 写入 chat_message 失败:', e.message); } } /** * 处理单个会话:获取详情 → 落库 → 判断是否回复 → 若需则发送消息 * @returns {{ friendId: number, replied: boolean, reason: string|null }} */ async _processOneFriend(task, friend, sn_code, platform_type) { const friend_id = friend.friendId; try { const detail_command = { command_type: 'get_chat_detail', command_name: '获取聊天详情', command_params: { platform: platform_type, friendId: friend_id }, priority: config.getTaskPriority('auto_chat') || 6 }; const detail_exec = await command.executeCommands(task.id, [detail_command], this.mqttClient); const result = detail_exec?.results?.[0]?.result; const parsed = chatManager.parseDetailResponse(result || {}); await this._saveChatMessagesToDb(parsed, friend, sn_code, platform_type); const decision = await chatManager.getReplyContentFromDetail(parsed || {}, { sn_code, platform: platform_type, friendId: friend_id, encryptFriendId: friend.encryptFriendId || '' }); if (decision.replied) { const action = decision.action || 'text'; const content = decision.reply_content || ''; const actionMessages = { send_resume: [{ type: 'send_resume', content }], exchange_wechat: [{ type: 'exchange_wechat', content }], exchange_phone: [{ type: 'exchange_phone', content }] }; const messages = actionMessages[action] || [{ type: 'text', content }]; const actionNames = { send_resume: '发送简历', exchange_wechat: '换微信', exchange_phone: '换电话' }; const send_command = { command_type: 'send_chat_message', command_name: actionNames[action] || '发送聊天消息', command_params: { platform: platform_type, friendId: friend_id, messages, chatType: 'reply' }, priority: config.getTaskPriority('auto_chat') || 6 }; await command.executeCommands(task.id, [send_command], this.mqttClient); } return { friendId: friend_id, replied: !!decision.replied, reason: decision.reason || null }; } catch (err) { return { friendId: friend_id, replied: false, reason: err.message || '处理失败' }; } } } module.exports = ChatHandler;