// +---------------------------------------------------------------------- declare (strict_types=1); namespace app\jobs; use app\services\kefu\CozeServices; use crmeb\basic\BaseJobs; use crmeb\services\app\MiniProgramService; use crmeb\services\CacheService; use crmeb\traits\QueueTrait; use crmeb\utils\Queue; use think\facade\Env; use think\facade\Log; /** * 小程序原生客服消息 AI 回复任务 */ class MiniProgramKefuReplyJob extends BaseJobs { use QueueTrait; public static function dispatchAsync(string $openid, string $content, string $messageId = '') { if (sys_config('queue_open', 0) != 1 || Env::get('cache.driver', 'file') !== 'redis') { Log::error('小程序客服 Coze 回复未入队:请开启 Redis 缓存和队列,避免微信回调超时'); return false; } return Queue::instance()->job(__CLASS__)->do('doJob')->data($openid, $content, $messageId)->errorCount(1)->push(); } public function doJob(string $openid, string $content, string $messageId = ''): bool { if ($openid === '' || trim($content) === '') { return true; } $lockKey = $messageId ? 'mini_kefu_coze_' . $messageId : 'mini_kefu_coze_' . md5($openid . $content); if (CacheService::has($lockKey)) { return true; } CacheService::set($lockKey, 1, 3600); try { /** @var CozeServices $coze */ $coze = app()->make(CozeServices::class); $reply = $coze->chatText('mini_' . $openid, $content); if ($reply !== '') { $sendResult = MiniProgramService::staffTo($openid, $reply); if (($sendResult['errcode'] ?? 0) != 0) { Log::error('小程序客服 Coze 回复发送失败:' . json_encode($sendResult, JSON_UNESCAPED_UNICODE)); } } } catch (\Throwable $e) { Log::error('小程序客服 Coze 回复失败:' . $e->getMessage()); } return true; } }