代码提交

This commit is contained in:
wong
2025-11-04 17:48:51 +08:00
parent a4060fec1b
commit adc22c7d19
11 changed files with 1444 additions and 38 deletions

View File

@@ -1537,4 +1537,500 @@ class Adapter implements WeChatServiceInterface
} while ($affected > 0);
}
/**
* 处理自动问候功能
* 根据不同的触发类型检查并发送问候消息
*/
public function handleAutoGreetings()
{
try {
// 获取所有启用的问候规则
$rules = Db::name('kf_auto_greetings')
->where(['status' => 1, 'isDel' => 0])
->order('level asc, id asc')
->select();
if (empty($rules)) {
return;
}
foreach ($rules as $rule) {
$trigger = $rule['trigger'];
$condition = json_decode($rule['condition'], true);
switch ($trigger) {
case 1: // 新好友
$this->handleNewFriendGreeting($rule);
break;
case 2: // 首次发消息
$this->handleFirstMessageGreeting($rule);
break;
case 3: // 时间触发
$this->handleTimeTriggerGreeting($rule, $condition);
break;
case 4: // 关键词触发
$this->handleKeywordTriggerGreeting($rule, $condition);
break;
case 5: // 生日触发
$this->handleBirthdayTriggerGreeting($rule, $condition);
break;
case 6: // 自定义
$this->handleCustomTriggerGreeting($rule, $condition);
break;
}
}
} catch (\Exception $e) {
Log::error('自动问候处理失败:' . $e->getMessage());
}
}
/**
* 处理新好友触发
*/
private function handleNewFriendGreeting($rule)
{
// 获取最近24小时内添加的好友避免重复处理
$last24h = time() - 24 * 3600;
// 查询该用户/公司最近24小时内新添加的好友
// 通过 s2_wechat_account -> s2_company_account 关联获取 companyId
$friends = Db::table('s2_wechat_friend')
->alias('wf')
->join(['s2_wechat_account' => 'wa'], 'wf.wechatAccountId = wa.id')
->join(['s2_company_account' => 'ca'], 'wa.deviceAccountId = ca.id')
->where([
['wf.isPassed', '=', 1],
['wf.isDeleted', '=', 0],
['wf.passTime', '>=', $last24h],
['ca.departmentId', '=', $rule['companyId']],
])
->field('wf.id, wf.wechatAccountId')
->select();
foreach ($friends as $friend) {
// 检查是否已经发送过问候
$exists = Db::name('kf_auto_greetings_record')
->where([
'autoId' => $rule['id'],
'friendIdOrGroupId' => $friend['id'],
'wechatAccountId' => $friend['wechatAccountId'],
])
->find();
if (!$exists) {
$this->sendGreetingMessage($rule, $friend['wechatAccountId'], $friend['id'], 0);
}
}
}
/**
* 处理首次发消息触发
*/
private function handleFirstMessageGreeting($rule)
{
// 获取最近1小时内收到的消息
$last1h = time() - 3600;
// 查询消息表,找出首次发消息的好友
// 通过 s2_wechat_account -> s2_company_account 关联获取 companyId
$messages = Db::table('s2_wechat_message')
->alias('wm')
->join(['s2_wechat_account' => 'wa'], 'wm.wechatAccountId = wa.id')
->join(['s2_company_account' => 'ca'], 'wa.deviceAccountId = ca.id')
->where([
['wm.isSend', '=', 0], // 接收的消息
['wm.wechatChatroomId', '=', 0], // 个人消息
['wm.createTime', '>=', $last1h],
['ca.departmentId', '=', $rule['companyId']],
])
->group('wm.wechatFriendId, wm.wechatAccountId')
->field('wm.wechatFriendId, wm.wechatAccountId, MIN(wm.createTime) as firstMsgTime')
->select();
foreach ($messages as $msg) {
// 检查该好友是否之前发送过消息
$previousMsg = Db::table('s2_wechat_message')
->where([
'wechatFriendId' => $msg['wechatFriendId'],
'wechatAccountId' => $msg['wechatAccountId'],
'isSend' => 0,
])
->where('createTime', '<', $msg['firstMsgTime'])
->find();
// 如果是首次发消息,且没有发送过问候
if (!$previousMsg) {
$exists = Db::name('kf_auto_greetings_record')
->where([
'autoId' => $rule['id'],
'friendIdOrGroupId' => $msg['wechatFriendId'],
'wechatAccountId' => $msg['wechatAccountId'],
])
->find();
if (!$exists) {
$this->sendGreetingMessage($rule, $msg['wechatAccountId'], $msg['wechatFriendId'], 0);
}
}
}
}
/**
* 处理时间触发
*/
private function handleTimeTriggerGreeting($rule, $condition)
{
if (empty($condition) || !isset($condition['type'])) {
return;
}
$now = time();
$currentTime = date('H:i', $now);
$currentDate = date('m-d', $now);
$currentDateTime = date('m-d H:i', $now);
$currentWeekday = date('w', $now); // 0=周日, 1=周一, ..., 6=周六
$shouldTrigger = false;
switch ($condition['type']) {
case 'daily_time': // 每天固定时间
if ($currentTime === $condition['value']) {
$shouldTrigger = true;
}
break;
case 'yearly_datetime': // 每年固定日期时间
if ($currentDateTime === $condition['value']) {
$shouldTrigger = true;
}
break;
case 'fixed_range': // 固定时间段
if (is_array($condition['value']) && count($condition['value']) === 2) {
$startTime = strtotime('2000-01-01 ' . $condition['value'][0]);
$endTime = strtotime('2000-01-01 ' . $condition['value'][1]);
$currentTimeStamp = strtotime('2000-01-01 ' . $currentTime);
if ($currentTimeStamp >= $startTime && $currentTimeStamp <= $endTime) {
$shouldTrigger = true;
}
}
break;
case 'workday': // 工作日
// 周一到周五1-5
if ($currentWeekday >= 1 && $currentWeekday <= 5 && $currentTime === $condition['value']) {
$shouldTrigger = true;
}
break;
}
if ($shouldTrigger) {
// 获取该用户/公司的所有好友
// 通过 s2_wechat_account -> s2_company_account 关联获取 companyId
$friends = Db::table('s2_wechat_friend')
->alias('wf')
->join(['s2_wechat_account' => 'wa'], 'wf.wechatAccountId = wa.id')
->join(['s2_company_account' => 'ca'], 'wa.deviceAccountId = ca.id')
->where([
['wf.isPassed', '=', 1],
['wf.isDeleted', '=', 0],
['ca.departmentId', '=', $rule['companyId']],
])
->field('wf.id, wf.wechatAccountId')
->select();
foreach ($friends as $friend) {
// 检查今天是否已经发送过
$todayStart = strtotime(date('Y-m-d 00:00:00'));
$exists = Db::name('kf_auto_greetings_record')
->where([
'autoId' => $rule['id'],
'friendIdOrGroupId' => $friend['id'],
'wechatAccountId' => $friend['wechatAccountId'],
])
->where('createTime', '>=', $todayStart)
->find();
if (!$exists) {
$this->sendGreetingMessage($rule, $friend['wechatAccountId'], $friend['id'], 0);
}
}
}
}
/**
* 处理关键词触发
*/
private function handleKeywordTriggerGreeting($rule, $condition)
{
if (empty($condition) || empty($condition['keywords'])) {
return;
}
$keywords = $condition['keywords'];
$matchType = $condition['match_type'] ?? 'fuzzy';
// 获取最近1小时内收到的消息
$last1h = time() - 3600;
// 通过 s2_wechat_account -> s2_company_account 关联获取 companyId
$messages = Db::table('s2_wechat_message')
->alias('wm')
->join(['s2_wechat_account' => 'wa'], 'wm.wechatAccountId = wa.id')
->join(['s2_company_account' => 'ca'], 'wa.deviceAccountId = ca.id')
->where([
['wm.isSend', '=', 0], // 接收的消息
['wm.wechatChatroomId', '=', 0], // 个人消息
['wm.msgType', '=', 1], // 文本消息
['wm.createTime', '>=', $last1h],
['ca.departmentId', '=', $rule['companyId']],
])
->field('wm.*')
->select();
foreach ($messages as $msg) {
$content = $msg['content'] ?? '';
// 检查关键词匹配
$matched = false;
foreach ($keywords as $keyword) {
if ($matchType === 'exact') {
// 精准匹配
if ($content === $keyword) {
$matched = true;
break;
}
} else {
// 模糊匹配
if (strpos($content, $keyword) !== false) {
$matched = true;
break;
}
}
}
if ($matched) {
// 检查是否已经发送过问候同一好友同一规则1小时内只发送一次
$last1h = time() - 3600;
$exists = Db::name('kf_auto_greetings_record')
->where([
'autoId' => $rule['id'],
'friendIdOrGroupId' => $msg['wechatFriendId'],
'wechatAccountId' => $msg['wechatAccountId'],
])
->where('createTime', '>=', $last1h)
->find();
if (!$exists) {
$this->sendGreetingMessage($rule, $msg['wechatAccountId'], $msg['wechatFriendId'], 0);
}
}
}
}
/**
* 处理生日触发
*/
private function handleBirthdayTriggerGreeting($rule, $condition)
{
if (empty($condition)) {
return;
}
// 解析condition格式
// 支持格式:
// 1. {'month': 10, 'day': 10} - 当天任何时间都可以触发
// 2. {'month': 10, 'day': 10, 'time': '09:00'} - 当天指定时间触发
// 3. {'month': 10, 'day': 10, 'time_range': ['09:00', '10:00']} - 当天时间范围内触发
// 兼容旧格式:['10-10'] 或 '10-10'(仅支持 MM-DD 格式,不包含年份)
$birthdayMonth = null;
$birthdayDay = null;
$birthdayTime = null;
$timeRange = null;
if (is_array($condition)) {
// 新格式:对象格式 {'month': 10, 'day': 10}
if (isset($condition['month']) && isset($condition['day'])) {
$birthdayMonth = (int)$condition['month'];
$birthdayDay = (int)$condition['day'];
$birthdayTime = $condition['time'] ?? null;
$timeRange = $condition['time_range'] ?? null;
}
// 兼容旧格式:['10-10'] 或 ['10-10 09:00'](仅支持 MM-DD 格式)
elseif (isset($condition[0])) {
$dateStr = $condition[0];
// 只接受月日格式:'10-10' 或 '10-10 09:00'
if (preg_match('/^(\d{1,2})-(\d{1,2})(?:\s+(\d{2}:\d{2}))?$/', $dateStr, $matches)) {
$birthdayMonth = (int)$matches[1];
$birthdayDay = (int)$matches[2];
if (isset($matches[3])) {
$birthdayTime = $matches[3];
}
}
}
} elseif (is_string($condition)) {
// 字符串格式:只接受 '10-10' 或 '10-10 09:00'MM-DD 格式,不包含年份)
if (preg_match('/^(\d{1,2})-(\d{1,2})(?:\s+(\d{2}:\d{2}))?$/', $condition, $matches)) {
$birthdayMonth = (int)$matches[1];
$birthdayDay = (int)$matches[2];
if (isset($matches[3])) {
$birthdayTime = $matches[3];
}
}
}
if ($birthdayMonth === null || $birthdayDay === null || $birthdayMonth < 1 || $birthdayMonth > 12 || $birthdayDay < 1 || $birthdayDay > 31) {
return;
}
$todayMonth = (int)date('m');
$todayDay = (int)date('d');
// 检查今天是否是生日(只匹配月日,不匹配年份)
if ($todayMonth !== $birthdayMonth || $todayDay !== $birthdayDay) {
return;
}
// 如果配置了时间,检查当前时间是否匹配
$now = time();
$currentTime = date('H:i', $now);
if ($birthdayTime !== null) {
// 指定了具体时间检查是否在指定时间允许1分钟误差避免定时任务执行时间不精确
$birthdayTimestamp = strtotime('2000-01-01 ' . $birthdayTime);
$currentTimestamp = strtotime('2000-01-01 ' . $currentTime);
$diff = abs($currentTimestamp - $birthdayTimestamp);
// 如果时间差超过2分钟不触发允许1分钟误差
if ($diff > 120) {
return;
}
} elseif ($timeRange !== null && is_array($timeRange) && count($timeRange) === 2) {
// 指定了时间范围,检查当前时间是否在范围内
$startTime = strtotime('2000-01-01 ' . $timeRange[0]);
$endTime = strtotime('2000-01-01 ' . $timeRange[1]);
$currentTimestamp = strtotime('2000-01-01 ' . $currentTime);
if ($currentTimestamp < $startTime || $currentTimestamp > $endTime) {
return;
}
}
// 如果没有配置时间或时间范围,则当天任何时间都可以触发
// 获取该用户/公司的所有好友
// 通过 s2_wechat_account -> s2_company_account 关联获取 companyId
$friends = Db::table('s2_wechat_friend')
->alias('wf')
->join(['s2_wechat_account' => 'wa'], 'wf.wechatAccountId = wa.id')
->join(['s2_company_account' => 'ca'], 'wa.deviceAccountId = ca.id')
->where([
['wf.isPassed', '=', 1],
['wf.isDeleted', '=', 0],
['ca.departmentId', '=', $rule['companyId']],
])
->field('wf.id, wf.wechatAccountId')
->select();
foreach ($friends as $friend) {
// 检查今天是否已经发送过
$todayStart = strtotime(date('Y-m-d 00:00:00'));
$exists = Db::name('kf_auto_greetings_record')
->where([
'autoId' => $rule['id'],
'friendIdOrGroupId' => $friend['id'],
'wechatAccountId' => $friend['wechatAccountId'],
])
->where('createTime', '>=', $todayStart)
->find();
if (!$exists) {
$this->sendGreetingMessage($rule, $friend['wechatAccountId'], $friend['id'], 0);
}
}
}
/**
* 处理自定义触发
*/
private function handleCustomTriggerGreeting($rule, $condition)
{
// 自定义类型需要根据具体业务需求实现
// 这里提供一个基础框架,可根据实际需求扩展
// 暂时不实现,留待后续扩展
}
/**
* 发送问候消息
* @param array $rule 问候规则
* @param int $wechatAccountId 微信账号ID
* @param int $friendId 好友ID
* @param int $groupId 群ID0表示个人消息
*/
private function sendGreetingMessage($rule, $wechatAccountId, $friendId, $groupId = 0)
{
try {
$content = $rule['content'];
// 创建记录
$recordId = Db::name('kf_auto_greetings_record')->insertGetId([
'autoId' => $rule['id'],
'userId' => $rule['userId'],
'companyId' => $rule['companyId'],
'wechatAccountId' => $wechatAccountId,
'friendIdOrGroupId' => $friendId,
'isSend' => 0,
'sendTime' => 0,
'receiveTime' => 0,
'createTime' => time(),
]);
// 发送消息(文本消息)
$username = Env::get('api.username', '');
$password = Env::get('api.password', '');
$toAccountId = '';
if (!empty($username) || !empty($password)) {
$toAccountId = Db::name('users')->where('account', $username)->value('s2_accountId');
}
$wsController = new WebSocketController(['userName' => $username, 'password' => $password, 'accountId' => $toAccountId]);
$sendTime = time();
$result = $wsController->sendPersonal([
'wechatFriendId' => $friendId,
'wechatAccountId' => $wechatAccountId,
'msgType' => 1, // 文本消息
'content' => $content,
]);
$isSend = 0;
$receiveTime = 0;
// 解析返回结果
$resultData = json_decode($result, true);
if (!empty($resultData) && $resultData['code'] == 200) {
$isSend = 1;
$receiveTime = time(); // 简化处理,实际应该从返回结果中获取
}
// 更新记录
Db::name('kf_auto_greetings_record')
->where('id', $recordId)
->update([
'isSend' => $isSend,
'sendTime' => $sendTime,
'receiveTime' => $receiveTime,
]);
// 更新规则使用次数
Db::name('kf_auto_greetings')
->where('id', $rule['id'])
->setInc('usageCount');
} catch (\Exception $e) {
Log::error('发送问候消息失败:' . $e->getMessage() . '规则ID' . $rule['id']);
}
}
}