消息推送
This commit is contained in:
@@ -0,0 +1,33 @@
|
|||||||
|
<?php
|
||||||
|
namespace app\common\controller;
|
||||||
|
|
||||||
|
use app\common\controller\BaseController;
|
||||||
|
use app\common\traits\crud\CrudControllerTrait;
|
||||||
|
use app\common\service\MessageNotificationsService;
|
||||||
|
|
||||||
|
class MessageNotificationsController extends BaseController
|
||||||
|
{
|
||||||
|
use CrudControllerTrait;
|
||||||
|
|
||||||
|
protected $service;
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->service = new MessageNotificationsService();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 列表页数据格式化
|
||||||
|
*
|
||||||
|
* @param array $data
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
// protected function indexFormat($data)
|
||||||
|
// {
|
||||||
|
// if (isset($data['created_at']))
|
||||||
|
// $data['created_at'] = date('Y-m-d H:i:s', $data['created_at']);
|
||||||
|
// if (isset($data['updated_at']))
|
||||||
|
// $data['updated_at'] = date('Y-m-d H:i:s', $data['updated_at']);
|
||||||
|
// return $data;
|
||||||
|
// }
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
<?php
|
||||||
|
namespace app\common\controller;
|
||||||
|
|
||||||
|
use app\common\controller\BaseController;
|
||||||
|
use app\common\traits\crud\CrudControllerTrait;
|
||||||
|
use app\common\service\MessageUserStatusService;
|
||||||
|
|
||||||
|
class MessageUserStatusController extends BaseController
|
||||||
|
{
|
||||||
|
use CrudControllerTrait;
|
||||||
|
|
||||||
|
protected $service;
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->service = new MessageUserStatusService();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 列表页数据格式化
|
||||||
|
*
|
||||||
|
* @param array $data
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
// protected function indexFormat($data)
|
||||||
|
// {
|
||||||
|
// if (isset($data['created_at']))
|
||||||
|
// $data['created_at'] = date('Y-m-d H:i:s', $data['created_at']);
|
||||||
|
// if (isset($data['updated_at']))
|
||||||
|
// $data['updated_at'] = date('Y-m-d H:i:s', $data['updated_at']);
|
||||||
|
// return $data;
|
||||||
|
// }
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace app\common\logic;
|
||||||
|
|
||||||
|
use app\common\traits\crud\CrudLogicTrait;
|
||||||
|
use app\common\model\MessageNotifications;
|
||||||
|
|
||||||
|
class MessageNotificationsLogic
|
||||||
|
{
|
||||||
|
use CrudLogicTrait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 指定当前要操作的模型
|
||||||
|
*/
|
||||||
|
protected string $modelClass = MessageNotifications::class;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace app\common\logic;
|
||||||
|
|
||||||
|
use app\common\traits\crud\CrudLogicTrait;
|
||||||
|
use app\common\model\MessageUserStatus;
|
||||||
|
|
||||||
|
class MessageUserStatusLogic
|
||||||
|
{
|
||||||
|
use CrudLogicTrait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 指定当前要操作的模型
|
||||||
|
*/
|
||||||
|
protected string $modelClass = MessageUserStatus::class;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace app\common\model;
|
||||||
|
|
||||||
|
use support\Model;
|
||||||
|
|
||||||
|
class MessageNotifications extends Model
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The connection name for the model.
|
||||||
|
*
|
||||||
|
* @var string|null
|
||||||
|
*/
|
||||||
|
protected $connection = 'mysql';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The table associated with the model.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $table = 'message_notifications';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The primary key associated with the table.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $primaryKey = 'id';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates if the model should be timestamped.
|
||||||
|
*
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
public $timestamps = true;
|
||||||
|
|
||||||
|
|
||||||
|
protected $dateFormat = 'U';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 允许自动填充模型字段
|
||||||
|
*/
|
||||||
|
protected $fillable = ['id', 'msg_no', 'sender_id', 'sender_type', 'recipient', 'title', 'content', 'scene', 'created_at'];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 不允许自动填充模型字段
|
||||||
|
*/
|
||||||
|
protected $guarded = [];
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace app\common\model;
|
||||||
|
|
||||||
|
use support\Model;
|
||||||
|
|
||||||
|
class MessageUserStatus extends Model
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The connection name for the model.
|
||||||
|
*
|
||||||
|
* @var string|null
|
||||||
|
*/
|
||||||
|
protected $connection = 'mysql';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The table associated with the model.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $table = 'message_user_status';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The primary key associated with the table.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $primaryKey = 'id';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates if the model should be timestamped.
|
||||||
|
*
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
public $timestamps = true;
|
||||||
|
|
||||||
|
|
||||||
|
protected $dateFormat = 'U';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 允许自动填充模型字段
|
||||||
|
*/
|
||||||
|
protected $fillable = ['id', 'msg_id', 'uid', 'status', 'read_at'];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 不允许自动填充模型字段
|
||||||
|
*/
|
||||||
|
protected $guarded = [];
|
||||||
|
}
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace app\common\service;
|
||||||
|
|
||||||
|
use app\common\validate\MessageNotificationsValidate;
|
||||||
|
use app\common\traits\crud\CrudServiceTrait;
|
||||||
|
use app\common\model\MessageNotifications;
|
||||||
|
use app\common\model\User;
|
||||||
|
use support\Db;
|
||||||
|
|
||||||
|
class MessageNotificationsService
|
||||||
|
{
|
||||||
|
|
||||||
|
use CrudServiceTrait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 指定当前要操作的模型
|
||||||
|
*/
|
||||||
|
protected string $modelClass = MessageNotifications::class;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证器
|
||||||
|
*/
|
||||||
|
protected $validator = MessageNotificationsValidate::class;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取验证器
|
||||||
|
*/
|
||||||
|
public function getValidator()
|
||||||
|
{
|
||||||
|
return new $this->validator;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建一条消息
|
||||||
|
*/
|
||||||
|
public function createMessage(array $data): int
|
||||||
|
{
|
||||||
|
$msgId = Db::table('message_notifications')->insertGetId([
|
||||||
|
'msg_no' => generateMsgId(),
|
||||||
|
'sender_id' => $data['sender_id'],
|
||||||
|
'sender_type' => $data['sender_type'],
|
||||||
|
'title' => $data['title'],
|
||||||
|
'content' => $data['content'],
|
||||||
|
'scene' => $data['scene'],
|
||||||
|
'recipient' => $data['recipient'],
|
||||||
|
'created_at' => time(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
return $msgId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量插入用户消息状态
|
||||||
|
*/
|
||||||
|
public function addUserStatus(int $msgId, array $uids)
|
||||||
|
{
|
||||||
|
$rows = [];
|
||||||
|
foreach ($uids as $uid) {
|
||||||
|
$rows[] = [
|
||||||
|
'msg_id' => $msgId,
|
||||||
|
'uid' => $uid,
|
||||||
|
'status' => 0,
|
||||||
|
'read_at' => null
|
||||||
|
];
|
||||||
|
}
|
||||||
|
if ($rows) {
|
||||||
|
Db::table('message_user_status')->insert($rows);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 标记消息已读
|
||||||
|
*/
|
||||||
|
public function markAsRead(array|string $msgIds, int $uid)
|
||||||
|
{
|
||||||
|
$query = Db::table('message_user_status')->where('uid', $uid);
|
||||||
|
if (is_array($msgIds)) {
|
||||||
|
$query->whereIn('msg_id', $msgIds);
|
||||||
|
}
|
||||||
|
return $query->update([
|
||||||
|
'status' => 1,
|
||||||
|
'read_at' => time()
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取所有用户ID
|
||||||
|
*/
|
||||||
|
public function getAllUserIds(): array
|
||||||
|
{
|
||||||
|
return User::where('status', 1)->pluck('id')->toArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace app\common\service;
|
||||||
|
|
||||||
|
use app\common\validate\MessageUserStatusValidate;
|
||||||
|
use app\common\traits\crud\CrudServiceTrait;
|
||||||
|
use app\common\model\MessageUserStatus;
|
||||||
|
|
||||||
|
class MessageUserStatusService
|
||||||
|
{
|
||||||
|
|
||||||
|
use CrudServiceTrait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 指定当前要操作的模型
|
||||||
|
*/
|
||||||
|
protected string $modelClass = MessageUserStatus::class;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证器
|
||||||
|
*/
|
||||||
|
protected $validator = MessageUserStatusValidate::class;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取验证器
|
||||||
|
*/
|
||||||
|
public function getValidator()
|
||||||
|
{
|
||||||
|
return new $this->validator;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,6 +4,7 @@ namespace app\common\utils;
|
|||||||
|
|
||||||
use GatewayWorker\Lib\Gateway;
|
use GatewayWorker\Lib\Gateway;
|
||||||
use app\common\utils\WsResponse;
|
use app\common\utils\WsResponse;
|
||||||
|
use app\common\service\MessageNotificationsService;
|
||||||
|
|
||||||
class WsEvents
|
class WsEvents
|
||||||
{
|
{
|
||||||
@@ -72,17 +73,17 @@ class WsEvents
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// // 连接是否满足条件
|
// 连接是否满足条件
|
||||||
// if ($payload['server']['HTTP_ORIGIN'] != 'https://wstool.js.org') {
|
if ($payload['server']['HTTP_ORIGIN'] != 'https://wstool.js.org') {
|
||||||
// flg('[x] [TOKEN认证] HTTP_ORIGIN不满足条件', false);
|
flg('[x] [TOKEN认证] HTTP_ORIGIN不满足条件', false);
|
||||||
// Gateway::sendToClient($client_id, WsResponse::error(
|
Gateway::sendToClient($client_id, WsResponse::error(
|
||||||
// 'system.auth',
|
'system.auth',
|
||||||
// 1001,
|
1001,
|
||||||
// '[x] [TOKEN认证] HTTP_ORIGIN不满足条件'
|
'[x] [TOKEN认证] HTTP_ORIGIN不满足条件'
|
||||||
// ));
|
));
|
||||||
// Gateway::closeClient($client_id);
|
Gateway::closeClient($client_id);
|
||||||
// return;
|
return;
|
||||||
// }
|
}
|
||||||
|
|
||||||
// 签名检查
|
// 签名检查
|
||||||
if (!isset($payload['get']['token'])) {
|
if (!isset($payload['get']['token'])) {
|
||||||
@@ -136,11 +137,6 @@ class WsEvents
|
|||||||
// ================= 消息通知事件 =================
|
// ================= 消息通知事件 =================
|
||||||
/**
|
/**
|
||||||
* 管理端主动推送通知
|
* 管理端主动推送通知
|
||||||
* data = [
|
|
||||||
* 'to_uids' => [uid1, uid2], // 可选,为空表示全员
|
|
||||||
* 'title' => '标题',
|
|
||||||
* 'content' => '内容',
|
|
||||||
* ]
|
|
||||||
*/
|
*/
|
||||||
public function notifyPush(?string $traceId)
|
public function notifyPush(?string $traceId)
|
||||||
{
|
{
|
||||||
@@ -158,7 +154,20 @@ class WsEvents
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$msgId = rand(1000, 9999); // 生成消息ID,可用数据库存储
|
// 写消息
|
||||||
|
$msgService = new MessageNotificationsService();
|
||||||
|
$msgId = $msgService->createMessage([
|
||||||
|
'sender_id' => $this->eventData['sender_id'] ?? 0,
|
||||||
|
'sender_type' => $this->eventData['sender_type'] ?? 'system',
|
||||||
|
'title' => $title,
|
||||||
|
'content' => $content,
|
||||||
|
'scene' => $this->eventData['scene'] ?? 0,
|
||||||
|
'recipient' => $this->eventData['to_uids'] ? implode(',', $this->eventData['to_uids']) : '',
|
||||||
|
]);
|
||||||
|
|
||||||
|
// 写用户状态
|
||||||
|
$uids = !empty($toUids) ? $toUids : $msgService->getAllUserIds();
|
||||||
|
$msgService->addUserStatus($msgId, $uids);
|
||||||
|
|
||||||
$payload = WsResponse::success('notify.push', [
|
$payload = WsResponse::success('notify.push', [
|
||||||
'msg_id' => $msgId,
|
'msg_id' => $msgId,
|
||||||
@@ -181,18 +190,18 @@ class WsEvents
|
|||||||
Gateway::sendToClient($this->clientId, WsResponse::success(
|
Gateway::sendToClient($this->clientId, WsResponse::success(
|
||||||
'notify.push.result',
|
'notify.push.result',
|
||||||
['msg_id' => $msgId],
|
['msg_id' => $msgId],
|
||||||
$traceId
|
$traceId,
|
||||||
|
'消息发送成功'
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 客户端标记通知已读
|
* 客户端标记通知已读
|
||||||
* data = ['msg_ids' => [1,2,3]]
|
|
||||||
*/
|
*/
|
||||||
public function notifyRead(?string $traceId)
|
public function notifyRead(?string $traceId)
|
||||||
{
|
{
|
||||||
$msgIds = $this->eventData['msg_ids'] ?? [];
|
$msgIds = $this->eventData['msg_ids'];
|
||||||
if (empty($msgIds)) {
|
if (!is_array($msgIds) && $msgIds !== 'all') {
|
||||||
Gateway::sendToClient($this->clientId, WsResponse::error(
|
Gateway::sendToClient($this->clientId, WsResponse::error(
|
||||||
'notify.read',
|
'notify.read',
|
||||||
400,
|
400,
|
||||||
@@ -201,6 +210,11 @@ class WsEvents
|
|||||||
));
|
));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 更新消息为已读
|
||||||
|
$msgService = new MessageNotificationsService();
|
||||||
|
$msgService->markAsRead($msgIds, Gateway::getUidByClientId($this->clientId));
|
||||||
|
|
||||||
Gateway::sendToClient($this->clientId, WsResponse::success(
|
Gateway::sendToClient($this->clientId, WsResponse::success(
|
||||||
'notify.read.result',
|
'notify.read.result',
|
||||||
['msg_ids' => $msgIds],
|
['msg_ids' => $msgIds],
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace app\common\validate;
|
||||||
|
|
||||||
|
use think\Validate;
|
||||||
|
|
||||||
|
class MessageNotificationsValidate extends Validate
|
||||||
|
{
|
||||||
|
// 规则
|
||||||
|
protected $rule = [
|
||||||
|
|
||||||
|
];
|
||||||
|
|
||||||
|
// 提示
|
||||||
|
protected $message = [
|
||||||
|
|
||||||
|
];
|
||||||
|
|
||||||
|
// 场景
|
||||||
|
protected $scene = [
|
||||||
|
'store' => [
|
||||||
|
|
||||||
|
],
|
||||||
|
|
||||||
|
'update' => [
|
||||||
|
|
||||||
|
]
|
||||||
|
];
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace app\common\validate;
|
||||||
|
|
||||||
|
use think\Validate;
|
||||||
|
|
||||||
|
class MessageUserStatusValidate extends Validate
|
||||||
|
{
|
||||||
|
// 规则
|
||||||
|
protected $rule = [
|
||||||
|
|
||||||
|
];
|
||||||
|
|
||||||
|
// 提示
|
||||||
|
protected $message = [
|
||||||
|
|
||||||
|
];
|
||||||
|
|
||||||
|
// 场景
|
||||||
|
protected $scene = [
|
||||||
|
'store' => [
|
||||||
|
|
||||||
|
],
|
||||||
|
|
||||||
|
'update' => [
|
||||||
|
|
||||||
|
]
|
||||||
|
];
|
||||||
|
}
|
||||||
@@ -77,25 +77,25 @@ class IndexController
|
|||||||
$options = [
|
$options = [
|
||||||
'controller' => [
|
'controller' => [
|
||||||
'module' => 'common',
|
'module' => 'common',
|
||||||
'name' => 'resources'
|
'name' => 'message_notifications'
|
||||||
],
|
],
|
||||||
'model' => [
|
'model' => [
|
||||||
'module' => 'common',
|
'module' => 'common',
|
||||||
'name' => 'resources'
|
'name' => 'message_notifications'
|
||||||
],
|
],
|
||||||
'service' => [
|
'service' => [
|
||||||
'module' => 'common',
|
'module' => 'common',
|
||||||
'name' => 'resources'
|
'name' => 'message_notifications'
|
||||||
],
|
],
|
||||||
'logic' => [
|
'logic' => [
|
||||||
'module' => 'common',
|
'module' => 'common',
|
||||||
'name' => 'resources'
|
'name' => 'message_notifications'
|
||||||
],
|
],
|
||||||
'validate' => [
|
'validate' => [
|
||||||
'module' => 'common',
|
'module' => 'common',
|
||||||
'name' => 'resources'
|
'name' => 'message_notifications'
|
||||||
],
|
],
|
||||||
'table' => 'resources'
|
'table' => 'message_notifications'
|
||||||
];
|
];
|
||||||
|
|
||||||
$result = (new Generate($options))->doGenerate();
|
$result = (new Generate($options))->doGenerate();
|
||||||
@@ -106,21 +106,11 @@ class IndexController
|
|||||||
public function test()
|
public function test()
|
||||||
{
|
{
|
||||||
|
|
||||||
// $data = [
|
$service = new \app\common\service\MessageNotificationsService();
|
||||||
// 'code' => 'GD20250703-1DC80',
|
$udis = $service->getAllUserIds();
|
||||||
// 'category' => '账号类问题',
|
|
||||||
// 'content' => '这是一条测试工单内容。'
|
|
||||||
// ];
|
|
||||||
// \app\common\utils\email\MailSend::send('mzl@hnxinyouhe.com', '【XYH】新的工单提醒', replaceTpl($data, 'work_order'));
|
|
||||||
|
|
||||||
// $options = [
|
var_dump($udis);
|
||||||
// 'corp_id' => 3,
|
|
||||||
// 'user_id' => 666
|
|
||||||
// ];
|
|
||||||
// \Webman\RedisQueue\Redis::send('perm-agt', $options);
|
|
||||||
|
|
||||||
$res = Cache::delete("user_resources_74_fdesk");
|
return json($udis);
|
||||||
|
|
||||||
return 22;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -284,3 +284,27 @@ if (!function_exists('normalizeRichText')) {
|
|||||||
return preg_replace('/\s+/u', ' ', $result);
|
return preg_replace('/\s+/u', ' ', $result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成消息编号(唯一业务标识)
|
||||||
|
* 格式:年月日时分秒 + 微秒 + 随机数
|
||||||
|
* 例如:20250820175530987654321
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
if (!function_exists('generateMsgId')) {
|
||||||
|
function generateMsgId(): string
|
||||||
|
{
|
||||||
|
// 时间部分(精确到微秒)
|
||||||
|
$time = microtime(true);
|
||||||
|
$micro = sprintf("%06d", ($time - floor($time)) * 1e6);
|
||||||
|
$date = date('YmdHis', (int)$time);
|
||||||
|
|
||||||
|
// 随机部分(3位)
|
||||||
|
$rand = mt_rand(100, 999);
|
||||||
|
|
||||||
|
// 拼接:日期时间 + 微秒 + 随机数
|
||||||
|
return $date . $micro . $rand;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user