Files
chatroom/app/Services/WechatBot/WechatNotificationService.php
lkddi fa5e37f003 feat: 增加发送微信群内自定义公告功能,并优化离线防抖与自我播报过滤机制
- 后台微信机器人增加群内独立公告的分发推送模块
- 聊天室系统引入3秒离线延迟(防抖)防重复播报
- 优化聊天界面消息拉取过滤自身的欢迎或离场广播
- 管理员登录时的烟花特效同步至用户当前的前端显示
2026-04-02 16:07:40 +08:00

254 lines
7.0 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
/**
* 文件功能:微信消息发送核心业务逻辑服务
*
* @author ChatRoom Laravel
*
* @version 1.0.0
*/
namespace App\Services\WechatBot;
use App\Jobs\SendWechatBotMessage;
use App\Models\SysParam;
use App\Models\User;
use Illuminate\Support\Facades\Redis;
class WechatNotificationService
{
protected array $config = [];
protected bool $globalEnabled = false;
public function __construct()
{
$param = SysParam::where('alias', 'wechat_bot_config')->first();
if ($param && ! empty($param->body)) {
$this->config = json_decode($param->body, true) ?? [];
}
}
/**
* 检查当前时间是否在全局配置的允许推送免打扰时间窗口内
*/
protected function isWithinNotificationWindow(): bool
{
$startTime = $this->config['global_notify']['start_time'] ?? '';
$endTime = $this->config['global_notify']['end_time'] ?? '';
// 如果没有配置起止时间,默认全天放行
if (! $startTime || ! $endTime) {
return true;
}
$nowTime = date('H:i');
if ($startTime < $endTime) {
return $nowTime >= $startTime && $nowTime <= $endTime;
} else {
// 跨天逻辑,如 22:00 -> 08:00
return $nowTime >= $startTime || $nowTime <= $endTime;
}
}
/**
* 管理员上线群通知
*/
public function notifyAdminOnline(User $user): void
{
if (! $this->isWithinNotificationWindow()) {
return;
}
if (empty($this->config['group_notify']['toggle_admin_online'])) {
return;
}
$groupWxid = $this->config['group_notify']['target_wxid'] ?? '';
if (! $groupWxid) {
return;
}
// 判断是否真的是管理员(这里假设大于等于某等级,比如 15
$adminLevel = (int) Sysparam::getValue('level_kick', '15');
if ($user->user_level < $adminLevel) {
return;
}
$message = "👑 【管理员上线】\n"
."管理员 [{$user->username}] 刚刚登录了系统。";
SendWechatBotMessage::dispatch($groupWxid, $message);
}
/**
* 百家乐开奖群通知
*/
public function notifyBaccaratResult(string $historyText): void
{
if (! $this->isWithinNotificationWindow()) {
return;
}
if (empty($this->config['group_notify']['toggle_baccarat_result'])) {
return;
}
$groupWxid = $this->config['group_notify']['target_wxid'] ?? '';
if (! $groupWxid) {
return;
}
SendWechatBotMessage::dispatch($groupWxid, $historyText);
}
/**
* 彩票开奖群通知
*/
public function notifyLotteryResult(string $historyText): void
{
if (! $this->isWithinNotificationWindow()) {
return;
}
if (empty($this->config['group_notify']['toggle_lottery_result'])) {
return;
}
$groupWxid = $this->config['group_notify']['target_wxid'] ?? '';
if (! $groupWxid) {
return;
}
SendWechatBotMessage::dispatch($groupWxid, $historyText);
}
/**
* 发送自定义群内公告
*
* @throws \Exception
*/
public function sendCustomGroupAnnouncement(string $message): void
{
$groupWxid = $this->config['group_notify']['target_wxid'] ?? '';
if (! $groupWxid) {
throw new \Exception('未配置目标微信群 Wxid无法发送公告消息');
}
SendWechatBotMessage::dispatch($groupWxid, $message);
}
/**
* 好友上线私聊通知(带冷却)
*/
public function notifyFriendsOnline(User $user): void
{
if (! $this->isWithinNotificationWindow()) {
return;
}
if (empty($this->config['personal_notify']['toggle_friend_online'])) {
return;
}
$cacheKey = "wechat_notify_cd:friend_online:{$user->id}";
if (Redis::exists($cacheKey)) {
return;
}
// 假定有好友关系模型 Friends (视具体业务而定,目前先预留或者查询好友)
$friends = $this->getUserFriends($user->id);
foreach ($friends as $friend) {
if ($friend->wxid) {
$message = "👋 【好友上线】\n您的好友 [{$user->username}] 刚刚上线了!";
SendWechatBotMessage::dispatch($friend->wxid, $message);
}
}
// 冷却 30 分钟
Redis::setex($cacheKey, 1800, 1);
}
/**
* 夫妻上线私聊通知(带冷却)
*/
public function notifySpouseOnline(User $user): void
{
if (! $this->isWithinNotificationWindow()) {
return;
}
if (empty($this->config['personal_notify']['toggle_spouse_online'])) {
return;
}
$cacheKey = "wechat_notify_cd:spouse_online:{$user->id}";
if (Redis::exists($cacheKey)) {
return;
}
// 获取伴侣
$spouse = $this->getUserSpouse($user);
if ($spouse && $spouse->wxid) {
$message = "❤️ 【伴侣上线】\n您的伴侣 [{$user->username}] 刚刚上线了!";
SendWechatBotMessage::dispatch($spouse->wxid, $message);
// 冷却 30 分钟
Redis::setex($cacheKey, 1800, 1);
}
}
/**
* 等级变动私聊通知
*/
public function notifyLevelChange(User $user, int $oldLevel, int $newLevel): void
{
if (! $this->isWithinNotificationWindow()) {
return;
}
if (empty($this->config['personal_notify']['toggle_level_change'])) {
return;
}
if (! $user->wxid || $newLevel <= $oldLevel) {
return;
}
$message = "✨ 【等级提升】\n"
."恭喜您!您的聊天室等级已从 LV{$oldLevel} 提升至 LV{$newLevel}";
SendWechatBotMessage::dispatch($user->wxid, $message);
}
// ---------------------------------------------------------
// Helper Methods (Mocking the real data retrieval methods)
// ---------------------------------------------------------
protected function getUserFriends(int $userId)
{
// 假定有好友表
if (\Illuminate\Support\Facades\Schema::hasTable('friends')) {
return \Illuminate\Support\Facades\DB::table('friends')
->join('users', 'users.id', '=', 'friends.friend_id')
->where('friends.user_id', $userId)
->whereNotNull('users.wxid')
->select('users.*')
->get();
}
return collect([]);
}
protected function getUserSpouse(User $user)
{
// 如果有配偶字段
$mateName = $user->peiou ?? null;
if ($mateName && $mateName !== '无' && $mateName !== '') {
return User::where('username', $mateName)->whereNotNull('wxid')->first();
}
return null;
}
}