mirror of
https://github.com/kuaifan/dootask.git
synced 2026-02-02 10:59:42 +00:00
feat: 优化打开会话事件接口,优化机器人webhook逻辑
- 新增 `open__event` 方法用于处理打开会话事件 - 移除旧的 `open__webhook` 方法 - 更新前端调用逻辑,使用新的事件接口 - 优化 webhook 事件推送逻辑,简化参数传递
This commit is contained in:
parent
130c8bf3b1
commit
4bfe33a37f
@ -448,6 +448,39 @@ class DialogController extends AbstractController
|
|||||||
return Base::retSuccess('success', $data);
|
return Base::retSuccess('success', $data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @api {get} api/dialog/open/event 打开会话事件
|
||||||
|
*
|
||||||
|
* @apiDescription 需要token身份
|
||||||
|
* @apiVersion 1.0.0
|
||||||
|
* @apiGroup dialog
|
||||||
|
* @apiName open__event
|
||||||
|
*
|
||||||
|
* @apiParam {Number} dialog_id 对话ID
|
||||||
|
*
|
||||||
|
* @apiSuccess {Number} ret 返回状态码(1正确、0错误)
|
||||||
|
* @apiSuccess {String} msg 返回信息(错误描述)
|
||||||
|
* @apiSuccess {Object} data 返回数据
|
||||||
|
*/
|
||||||
|
public function open__event()
|
||||||
|
{
|
||||||
|
$user = User::auth();
|
||||||
|
//
|
||||||
|
$dialog_id = intval(Request::input('dialog_id'));
|
||||||
|
//
|
||||||
|
$dialog = WebSocketDialog::checkDialog($dialog_id);
|
||||||
|
if (empty($dialog)) {
|
||||||
|
return Base::retError('打开会话失败');
|
||||||
|
}
|
||||||
|
//
|
||||||
|
Cache::remember("webhook_dialog_open_{$dialog->id}_{$user->userid}", Carbon::now()->addMinute(), function () use ($dialog, $user) {
|
||||||
|
$dialog->dispatchMemberWebhook(UserBot::WEBHOOK_EVENT_DIALOG_OPEN, $user->userid, $user->userid);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
//
|
||||||
|
return Base::retSuccess('success');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @api {get} api/dialog/msg/list 获取消息列表
|
* @api {get} api/dialog/msg/list 获取消息列表
|
||||||
*
|
*
|
||||||
@ -1258,9 +1291,6 @@ class DialogController extends AbstractController
|
|||||||
if ($model_name) {
|
if ($model_name) {
|
||||||
$msgData['model_name'] = $model_name;
|
$msgData['model_name'] = $model_name;
|
||||||
}
|
}
|
||||||
if (User::isBot($user->userid)) {
|
|
||||||
$msgData['force_webhook'] = true; // 强制使用webhook发送
|
|
||||||
}
|
|
||||||
$result = WebSocketDialogMsg::sendMsg($action, $dialog_id, 'text', $msgData, $user->userid, false, false, $silence, $key);
|
$result = WebSocketDialogMsg::sendMsg($action, $dialog_id, 'text', $msgData, $user->userid, false, false, $silence, $key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3688,61 +3718,4 @@ class DialogController extends AbstractController
|
|||||||
//
|
//
|
||||||
return Base::retSuccess('重命名成功', $session);
|
return Base::retSuccess('重命名成功', $session);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @api {get} api/dialog/open/webhook 打开机器人会话推送 webhook
|
|
||||||
*
|
|
||||||
* @apiDescription 需要token身份
|
|
||||||
* @apiVersion 1.0.0
|
|
||||||
* @apiGroup dialog
|
|
||||||
* @apiName open__webhook
|
|
||||||
*
|
|
||||||
* @apiParam {Number} dialog_id 对话ID
|
|
||||||
*
|
|
||||||
* @apiSuccess {Number} ret 返回状态码(1正确、0错误)
|
|
||||||
* @apiSuccess {String} msg 返回信息(错误描述)
|
|
||||||
* @apiSuccess {Object} data 返回数据
|
|
||||||
*/
|
|
||||||
public function open__webhook()
|
|
||||||
{
|
|
||||||
$user = User::auth();
|
|
||||||
//
|
|
||||||
$dialog_id = intval(Request::input('dialog_id'));
|
|
||||||
if (empty($dialog_id)) {
|
|
||||||
return Base::retError('错误的会话');
|
|
||||||
}
|
|
||||||
//
|
|
||||||
$dialog = WebSocketDialog::checkDialog($dialog_id);
|
|
||||||
if (empty($dialog)) {
|
|
||||||
return Base::retError('打开会话失败');
|
|
||||||
}
|
|
||||||
$data = WebSocketDialog::synthesizeData($dialog->id, $user->userid);
|
|
||||||
if ($data['bot'] == 1) {
|
|
||||||
$botTarget = User::whereUserid($data['dialog_user']['userid'])->whereBot(1)->first();
|
|
||||||
if ($botTarget) {
|
|
||||||
$userBot = UserBot::whereBotId($botTarget->userid)->first();
|
|
||||||
if ($userBot) {
|
|
||||||
// 每个机器人1分钟只触发一次 webhook
|
|
||||||
Cache::remember('webhook_dialog_open_' . $botTarget->userid, 60, function () use ($userBot, $dialog, $user) {
|
|
||||||
$userBot->dispatchWebhook(UserBot::WEBHOOK_EVENT_DIALOG_OPEN, [
|
|
||||||
'dialog_id' => $dialog->id,
|
|
||||||
'dialog_type' => $dialog->type,
|
|
||||||
'session_id' => $dialog->session_id,
|
|
||||||
'dialog_name' => $dialog->getGroupName(),
|
|
||||||
'user' => [
|
|
||||||
'userid' => $user->userid,
|
|
||||||
'email' => $user->email,
|
|
||||||
'nickname' => $user->nickname,
|
|
||||||
],
|
|
||||||
], 10, [
|
|
||||||
'dialog' => $dialog->id,
|
|
||||||
'operator' => $user->userid,
|
|
||||||
]);
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Base::retSuccess('success');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,7 +4,6 @@ namespace App\Models;
|
|||||||
|
|
||||||
use App\Module\Base;
|
use App\Module\Base;
|
||||||
use App\Module\Doo;
|
use App\Module\Doo;
|
||||||
use App\Module\Extranet;
|
|
||||||
use App\Module\Ihttp;
|
use App\Module\Ihttp;
|
||||||
use App\Module\Timer;
|
use App\Module\Timer;
|
||||||
use App\Tasks\JokeSoupTask;
|
use App\Tasks\JokeSoupTask;
|
||||||
@ -56,43 +55,6 @@ class UserBot extends AbstractModel
|
|||||||
'webhook_events' => 'array',
|
'webhook_events' => 'array',
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取可选的 webhook 事件
|
|
||||||
*
|
|
||||||
* @return string[]
|
|
||||||
*/
|
|
||||||
public static function webhookEventOptions(): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
self::WEBHOOK_EVENT_MESSAGE,
|
|
||||||
self::WEBHOOK_EVENT_DIALOG_OPEN,
|
|
||||||
self::WEBHOOK_EVENT_MEMBER_JOIN,
|
|
||||||
self::WEBHOOK_EVENT_MEMBER_LEAVE,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 标准化 webhook 事件配置
|
|
||||||
*
|
|
||||||
* @param mixed $events
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public static function normalizeWebhookEvents(mixed $events, bool $useFallback = true): array
|
|
||||||
{
|
|
||||||
if (is_string($events)) {
|
|
||||||
$events = Base::json2array($events);
|
|
||||||
}
|
|
||||||
if ($events === null) {
|
|
||||||
$events = [];
|
|
||||||
}
|
|
||||||
if (!is_array($events)) {
|
|
||||||
$events = [$events];
|
|
||||||
}
|
|
||||||
$events = array_filter(array_map('strval', $events));
|
|
||||||
$events = array_values(array_intersect($events, self::webhookEventOptions()));
|
|
||||||
return $events ?: ($useFallback ? [self::WEBHOOK_EVENT_MESSAGE] : []);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取 webhook 事件配置
|
* 获取 webhook 事件配置
|
||||||
*
|
*
|
||||||
@ -140,35 +102,27 @@ class UserBot extends AbstractModel
|
|||||||
* 发送 webhook
|
* 发送 webhook
|
||||||
*
|
*
|
||||||
* @param string $event
|
* @param string $event
|
||||||
* @param array $payload
|
* @param array $data
|
||||||
* @param int $timeout
|
* @param int $timeout
|
||||||
* @param array $context
|
|
||||||
* @return array|null
|
* @return array|null
|
||||||
*/
|
*/
|
||||||
public function dispatchWebhook(string $event, array $payload, int $timeout = 30, array $context = []): ?array
|
public function dispatchWebhook(string $event, array $data, int $timeout = 30): ?array
|
||||||
{
|
{
|
||||||
if (!$this->shouldDispatchWebhook($event)) {
|
if (!$this->shouldDispatchWebhook($event)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
$payload = array_merge([
|
|
||||||
'event' => $event,
|
|
||||||
'timestamp' => time(),
|
|
||||||
'bot_uid' => $this->bot_id,
|
|
||||||
'owner_uid' => $this->userid,
|
|
||||||
], $payload);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$result = Ihttp::ihttp_post($this->webhook_url, $payload, $timeout);
|
$data['event'] = $event;
|
||||||
|
$result = Ihttp::ihttp_post($this->webhook_url, $data, $timeout);
|
||||||
$this->increment('webhook_num');
|
$this->increment('webhook_num');
|
||||||
return $result;
|
return $result;
|
||||||
} catch (Throwable $th) {
|
} catch (Throwable $th) {
|
||||||
info(Base::array2json(array_merge($context, [
|
info(Base::array2json([
|
||||||
'bot_userid' => $this->bot_id,
|
|
||||||
'event' => $event,
|
|
||||||
'webhook_url' => $this->webhook_url,
|
'webhook_url' => $this->webhook_url,
|
||||||
|
'data' => $data,
|
||||||
'error' => $th->getMessage(),
|
'error' => $th->getMessage(),
|
||||||
])));
|
]));
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -607,4 +561,42 @@ class UserBot extends AbstractModel
|
|||||||
}
|
}
|
||||||
return Base::retSuccess("创建成功。", $data);
|
return Base::retSuccess("创建成功。", $data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取可选的 webhook 事件
|
||||||
|
*
|
||||||
|
* @return string[]
|
||||||
|
*/
|
||||||
|
public static function webhookEventOptions(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
self::WEBHOOK_EVENT_MESSAGE,
|
||||||
|
self::WEBHOOK_EVENT_DIALOG_OPEN,
|
||||||
|
self::WEBHOOK_EVENT_MEMBER_JOIN,
|
||||||
|
self::WEBHOOK_EVENT_MEMBER_LEAVE,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 标准化 webhook 事件配置
|
||||||
|
*
|
||||||
|
* @param mixed $events
|
||||||
|
* @param bool $useFallback
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public static function normalizeWebhookEvents(mixed $events, bool $useFallback = true): array
|
||||||
|
{
|
||||||
|
if (is_string($events)) {
|
||||||
|
$events = Base::json2array($events);
|
||||||
|
}
|
||||||
|
if ($events === null) {
|
||||||
|
$events = [];
|
||||||
|
}
|
||||||
|
if (!is_array($events)) {
|
||||||
|
$events = [$events];
|
||||||
|
}
|
||||||
|
$events = array_filter(array_map('strval', $events));
|
||||||
|
$events = array_values(array_intersect($events, self::webhookEventOptions()));
|
||||||
|
return $events ?: ($useFallback ? [self::WEBHOOK_EVENT_MESSAGE] : []);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -461,8 +461,7 @@ class WebSocketDialog extends AbstractModel
|
|||||||
*/
|
*/
|
||||||
public function joinGroup($userid, $inviter, $important = null)
|
public function joinGroup($userid, $inviter, $important = null)
|
||||||
{
|
{
|
||||||
$addedUserIds = [];
|
AbstractModel::transaction(function () use ($important, $inviter, $userid) {
|
||||||
AbstractModel::transaction(function () use ($important, $inviter, $userid, &$addedUserIds) {
|
|
||||||
foreach (is_array($userid) ? $userid : [$userid] as $value) {
|
foreach (is_array($userid) ? $userid : [$userid] as $value) {
|
||||||
if ($value > 0) {
|
if ($value > 0) {
|
||||||
$updateData = [
|
$updateData = [
|
||||||
@ -481,7 +480,6 @@ class WebSocketDialog extends AbstractModel
|
|||||||
]);
|
]);
|
||||||
}, $isInsert);
|
}, $isInsert);
|
||||||
if ($isInsert) {
|
if ($isInsert) {
|
||||||
$addedUserIds[] = $value;
|
|
||||||
WebSocketDialogMsg::sendMsg(null, $this->id, 'notice', [
|
WebSocketDialogMsg::sendMsg(null, $this->id, 'notice', [
|
||||||
'notice' => User::userid2nickname($value) . " 已加入群组"
|
'notice' => User::userid2nickname($value) . " 已加入群组"
|
||||||
], $inviter, true, true);
|
], $inviter, true, true);
|
||||||
@ -492,16 +490,6 @@ class WebSocketDialog extends AbstractModel
|
|||||||
$data = WebSocketDialog::generatePeople($this->id);
|
$data = WebSocketDialog::generatePeople($this->id);
|
||||||
$data['id'] = $this->id;
|
$data['id'] = $this->id;
|
||||||
$this->pushMsg("groupUpdate", $data);
|
$this->pushMsg("groupUpdate", $data);
|
||||||
if ($addedUserIds) {
|
|
||||||
$meta = ['action' => 'join'];
|
|
||||||
if ($inviter > 0) {
|
|
||||||
$actor = $this->getUserSnapshots([$inviter]);
|
|
||||||
if (!empty($actor)) {
|
|
||||||
$meta['actor'] = $actor[0];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$this->dispatchMemberWebhook(UserBot::WEBHOOK_EVENT_MEMBER_JOIN, $addedUserIds, $meta);
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -515,15 +503,14 @@ class WebSocketDialog extends AbstractModel
|
|||||||
public function exitGroup($userid, $type = 'exit', $checkDelete = true, $pushMsg = true)
|
public function exitGroup($userid, $type = 'exit', $checkDelete = true, $pushMsg = true)
|
||||||
{
|
{
|
||||||
$typeDesc = $type === 'remove' ? '移出' : '退出';
|
$typeDesc = $type === 'remove' ? '移出' : '退出';
|
||||||
$removedUserIds = [];
|
AbstractModel::transaction(function () use ($pushMsg, $checkDelete, $typeDesc, $type, $userid) {
|
||||||
AbstractModel::transaction(function () use ($pushMsg, $checkDelete, $typeDesc, $type, $userid, &$removedUserIds) {
|
|
||||||
$builder = WebSocketDialogUser::whereDialogId($this->id);
|
$builder = WebSocketDialogUser::whereDialogId($this->id);
|
||||||
if (is_array($userid)) {
|
if (is_array($userid)) {
|
||||||
$builder->whereIn('userid', $userid);
|
$builder->whereIn('userid', $userid);
|
||||||
} else {
|
} else {
|
||||||
$builder->whereUserid($userid);
|
$builder->whereUserid($userid);
|
||||||
}
|
}
|
||||||
$builder->chunkById(100, function($list) use ($pushMsg, $checkDelete, $typeDesc, $type, &$removedUserIds) {
|
$builder->chunkById(100, function($list) use ($pushMsg, $checkDelete, $typeDesc, $type) {
|
||||||
/** @var WebSocketDialogUser $item */
|
/** @var WebSocketDialogUser $item */
|
||||||
foreach ($list as $item) {
|
foreach ($list as $item) {
|
||||||
if ($checkDelete) {
|
if ($checkDelete) {
|
||||||
@ -543,8 +530,8 @@ class WebSocketDialog extends AbstractModel
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
|
$item->operator_id = User::userid();
|
||||||
$item->delete();
|
$item->delete();
|
||||||
$removedUserIds[] = $item->userid;
|
|
||||||
//
|
//
|
||||||
if ($pushMsg) {
|
if ($pushMsg) {
|
||||||
if ($type === 'remove') {
|
if ($type === 'remove') {
|
||||||
@ -563,58 +550,17 @@ class WebSocketDialog extends AbstractModel
|
|||||||
$data = WebSocketDialog::generatePeople($this->id);
|
$data = WebSocketDialog::generatePeople($this->id);
|
||||||
$data['id'] = $this->id;
|
$data['id'] = $this->id;
|
||||||
$this->pushMsg("groupUpdate", $data);
|
$this->pushMsg("groupUpdate", $data);
|
||||||
if ($removedUserIds) {
|
|
||||||
$meta = ['action' => $type];
|
|
||||||
$operatorId = User::userid();
|
|
||||||
if ($operatorId > 0) {
|
|
||||||
$actor = $this->getUserSnapshots([$operatorId]);
|
|
||||||
if (!empty($actor)) {
|
|
||||||
$meta['actor'] = $actor[0];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$this->dispatchMemberWebhook(UserBot::WEBHOOK_EVENT_MEMBER_LEAVE, $removedUserIds, $meta);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取用户快照
|
|
||||||
* @param array $userIds
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
protected function getUserSnapshots(array $userIds): array
|
|
||||||
{
|
|
||||||
$userIds = array_values(array_unique(array_filter($userIds)));
|
|
||||||
if (empty($userIds)) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
return User::whereIn('userid', $userIds)
|
|
||||||
->get(['userid', 'nickname', 'email', 'bot'])
|
|
||||||
->map(function (User $user) {
|
|
||||||
return [
|
|
||||||
'userid' => $user->userid,
|
|
||||||
'nickname' => $user->nickname,
|
|
||||||
'email' => $user->email,
|
|
||||||
'is_bot' => (bool)$user->bot,
|
|
||||||
];
|
|
||||||
})
|
|
||||||
->values()
|
|
||||||
->all();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 推送成员事件到机器人 webhook
|
* 推送成员事件到机器人 webhook
|
||||||
* @param string $event
|
* @param string $event
|
||||||
* @param array $memberIds
|
* @param int $memberId
|
||||||
* @param array $meta
|
* @param int $operatorId
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
protected function dispatchMemberWebhook(string $event, array $memberIds, array $meta = []): void
|
public function dispatchMemberWebhook(string $event, int $memberId, int $operatorId): void
|
||||||
{
|
{
|
||||||
$memberIds = array_values(array_unique(array_filter($memberIds)));
|
|
||||||
if (empty($memberIds)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$botIds = $this->dialogUser()->where('bot', 1)->pluck('userid')->toArray();
|
$botIds = $this->dialogUser()->where('bot', 1)->pluck('userid')->toArray();
|
||||||
if (empty($botIds)) {
|
if (empty($botIds)) {
|
||||||
return;
|
return;
|
||||||
@ -625,24 +571,20 @@ class WebSocketDialog extends AbstractModel
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$members = $this->getUserSnapshots($memberIds);
|
$member = User::find($memberId, ['userid', 'nickname', 'email', 'bot'])?->toArray();
|
||||||
if (empty($members)) {
|
$operator = $operatorId === $memberId ? $member : User::find($operatorId, ['userid', 'nickname', 'email', 'bot'])?->toArray();
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$payload = array_merge([
|
$payload = [
|
||||||
'dialog_id' => $this->id,
|
'dialog_id' => $this->id,
|
||||||
'dialog_type' => $this->type,
|
'dialog_type' => $this->type,
|
||||||
'group_type' => $this->group_type,
|
'group_type' => $this->group_type,
|
||||||
'dialog_name' => $this->getGroupName(),
|
'dialog_name' => $this->getGroupName(),
|
||||||
'members' => $members,
|
'member' => $member,
|
||||||
], array_filter($meta, fn ($value) => $value !== null));
|
'operator' => $operator,
|
||||||
|
];
|
||||||
|
|
||||||
foreach ($userBots as $userBot) {
|
foreach ($userBots as $userBot) {
|
||||||
$userBot->dispatchWebhook($event, $payload, 10, [
|
$userBot->dispatchWebhook($event, $payload, 10);
|
||||||
'dialog' => $this->id,
|
|
||||||
'event_members' => $memberIds,
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -3,6 +3,7 @@
|
|||||||
namespace App\Observers;
|
namespace App\Observers;
|
||||||
|
|
||||||
use App\Models\Deleted;
|
use App\Models\Deleted;
|
||||||
|
use App\Models\UserBot;
|
||||||
use App\Models\WebSocketDialogUser;
|
use App\Models\WebSocketDialogUser;
|
||||||
use App\Tasks\ZincSearchSyncTask;
|
use App\Tasks\ZincSearchSyncTask;
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
@ -31,6 +32,11 @@ class WebSocketDialogUserObserver extends AbstractObserver
|
|||||||
}
|
}
|
||||||
Deleted::forget('dialog', $webSocketDialogUser->dialog_id, $webSocketDialogUser->userid);
|
Deleted::forget('dialog', $webSocketDialogUser->dialog_id, $webSocketDialogUser->userid);
|
||||||
self::taskDeliver(new ZincSearchSyncTask('userSync', $webSocketDialogUser->toArray()));
|
self::taskDeliver(new ZincSearchSyncTask('userSync', $webSocketDialogUser->toArray()));
|
||||||
|
//
|
||||||
|
$dialog = $webSocketDialogUser->webSocketDialog;
|
||||||
|
if ($dialog) {
|
||||||
|
$dialog->dispatchMemberWebhook(UserBot::WEBHOOK_EVENT_MEMBER_JOIN, $webSocketDialogUser->userid, intval($webSocketDialogUser->inviter));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -54,6 +60,12 @@ class WebSocketDialogUserObserver extends AbstractObserver
|
|||||||
{
|
{
|
||||||
Deleted::record('dialog', $webSocketDialogUser->dialog_id, $webSocketDialogUser->userid);
|
Deleted::record('dialog', $webSocketDialogUser->dialog_id, $webSocketDialogUser->userid);
|
||||||
self::taskDeliver(new ZincSearchSyncTask('deleteUser', $webSocketDialogUser->toArray()));
|
self::taskDeliver(new ZincSearchSyncTask('deleteUser', $webSocketDialogUser->toArray()));
|
||||||
|
//
|
||||||
|
$dialog = $webSocketDialogUser->webSocketDialog;
|
||||||
|
if ($dialog) {
|
||||||
|
$operatorId = $webSocketDialogUser->operator_id ?? 0;
|
||||||
|
$dialog->dispatchMemberWebhook(UserBot::WEBHOOK_EVENT_MEMBER_LEAVE, $webSocketDialogUser->userid, intval($operatorId));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -75,11 +75,7 @@ class BotReceiveMsgTask extends AbstractTask
|
|||||||
$msg->readSuccess($botUser->userid);
|
$msg->readSuccess($botUser->userid);
|
||||||
|
|
||||||
// 判断消息是否是机器人发送的则不处理,避免循环
|
// 判断消息是否是机器人发送的则不处理,避免循环
|
||||||
if ((!$msg->user || $msg->user->bot)) {
|
if (!$msg->user || $msg->user->bot) {
|
||||||
$msgData = Base::json2array($msg->msg);
|
|
||||||
if (Base::val($msgData, 'force_webhook') && $msg->webSocketDialog) {
|
|
||||||
$this->handleWebhookRequest($msgData['text'], null, $msg, $msg->webSocketDialog, $botUser);
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -539,9 +535,6 @@ class BotReceiveMsgTask extends AbstractTask
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!$userBot && !preg_match("/^https?:\/\//", $webhookUrl)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
WebSocketDialogMsg::sendMsg(null, $msg->dialog_id, 'template', [
|
WebSocketDialogMsg::sendMsg(null, $msg->dialog_id, 'template', [
|
||||||
'type' => 'content',
|
'type' => 'content',
|
||||||
@ -549,8 +542,10 @@ class BotReceiveMsgTask extends AbstractTask
|
|||||||
], $botUser->userid, false, false, true); // todo 未能在任务end事件来发送任务
|
], $botUser->userid, false, false, true); // todo 未能在任务end事件来发送任务
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
//
|
|
||||||
|
// 基本请求数据
|
||||||
$data = [
|
$data = [
|
||||||
|
'event' => UserBot::WEBHOOK_EVENT_MESSAGE,
|
||||||
'text' => $sendText,
|
'text' => $sendText,
|
||||||
'reply_text' => $replyText,
|
'reply_text' => $replyText,
|
||||||
'token' => User::generateToken($botUser),
|
'token' => User::generateToken($botUser),
|
||||||
@ -561,8 +556,9 @@ class BotReceiveMsgTask extends AbstractTask
|
|||||||
'msg_uid' => $msg->userid,
|
'msg_uid' => $msg->userid,
|
||||||
'mention' => $this->mention ? 1 : 0,
|
'mention' => $this->mention ? 1 : 0,
|
||||||
'bot_uid' => $botUser->userid,
|
'bot_uid' => $botUser->userid,
|
||||||
|
'extras' => Base::array2json($extras),
|
||||||
'version' => Base::getVersion(),
|
'version' => Base::getVersion(),
|
||||||
'extras' => Base::array2json($extras)
|
'timestamp' => time(),
|
||||||
];
|
];
|
||||||
// 添加用户信息
|
// 添加用户信息
|
||||||
$userInfo = User::find($msg->userid);
|
$userInfo = User::find($msg->userid);
|
||||||
@ -579,19 +575,14 @@ class BotReceiveMsgTask extends AbstractTask
|
|||||||
|
|
||||||
$result = null;
|
$result = null;
|
||||||
if ($userBot) {
|
if ($userBot) {
|
||||||
$result = $userBot->dispatchWebhook(UserBot::WEBHOOK_EVENT_MESSAGE, $data, 30, [
|
$result = $userBot->dispatchWebhook(UserBot::WEBHOOK_EVENT_MESSAGE, $data);
|
||||||
'dialog' => $dialog->id,
|
|
||||||
'msg' => $msg->id,
|
|
||||||
]);
|
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
$result = Ihttp::ihttp_post($webhookUrl, $data, 30);
|
$result = Ihttp::ihttp_post($webhookUrl, $data, 30);
|
||||||
} catch (\Throwable $th) {
|
} catch (\Throwable $th) {
|
||||||
info(Base::array2json([
|
info(Base::array2json([
|
||||||
'bot_userid' => $botUser->userid,
|
|
||||||
'dialog' => $dialog->id,
|
|
||||||
'msg' => $msg->id,
|
|
||||||
'webhook_url' => $webhookUrl,
|
'webhook_url' => $webhookUrl,
|
||||||
|
'data' => $data,
|
||||||
'error' => $th->getMessage(),
|
'error' => $th->getMessage(),
|
||||||
]));
|
]));
|
||||||
}
|
}
|
||||||
@ -599,7 +590,7 @@ class BotReceiveMsgTask extends AbstractTask
|
|||||||
|
|
||||||
if ($result && isset($result['data'])) {
|
if ($result && isset($result['data'])) {
|
||||||
$responseData = Base::json2array($result['data']);
|
$responseData = Base::json2array($result['data']);
|
||||||
if (($responseData['code'] ?? 0) != 200 && !empty($responseData['message'])) {
|
if (($responseData['code'] ?? 0) === 200 && !empty($responseData['message'])) {
|
||||||
WebSocketDialogMsg::sendMsg(null, $msg->dialog_id, 'text', [
|
WebSocketDialogMsg::sendMsg(null, $msg->dialog_id, 'text', [
|
||||||
'text' => $responseData['message']
|
'text' => $responseData['message']
|
||||||
], $botUser->userid, false, false, true);
|
], $botUser->userid, false, false, true);
|
||||||
@ -722,7 +713,7 @@ class BotReceiveMsgTask extends AbstractTask
|
|||||||
</role_setting>
|
</role_setting>
|
||||||
EOF;
|
EOF;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 上下文信息(项目、任务、部门等)+ 操作指令
|
// 上下文信息(项目、任务、部门等)+ 操作指令
|
||||||
switch ($dialog->type) {
|
switch ($dialog->type) {
|
||||||
// 用户对话
|
// 用户对话
|
||||||
@ -757,7 +748,7 @@ class BotReceiveMsgTask extends AbstractTask
|
|||||||
项目状态:{$projectStatus}
|
项目状态:{$projectStatus}
|
||||||
</context_info>
|
</context_info>
|
||||||
EOF;
|
EOF;
|
||||||
|
|
||||||
$sections[] = <<<EOF
|
$sections[] = <<<EOF
|
||||||
<instructions>
|
<instructions>
|
||||||
如果你判断我想要或需要添加任务,请按照以下格式回复:
|
如果你判断我想要或需要添加任务,请按照以下格式回复:
|
||||||
@ -787,7 +778,7 @@ class BotReceiveMsgTask extends AbstractTask
|
|||||||
{$taskContext}
|
{$taskContext}
|
||||||
</context_info>
|
</context_info>
|
||||||
EOF;
|
EOF;
|
||||||
|
|
||||||
$sections[] = <<<EOF
|
$sections[] = <<<EOF
|
||||||
<instructions>
|
<instructions>
|
||||||
如果你判断我想要或需要添加子任务,请按照以下格式回复:
|
如果你判断我想要或需要添加子任务,请按照以下格式回复:
|
||||||
@ -822,7 +813,7 @@ class BotReceiveMsgTask extends AbstractTask
|
|||||||
EOF;
|
EOF;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 聊天历史
|
// 聊天历史
|
||||||
if ($dialog->type === 'group') {
|
if ($dialog->type === 'group') {
|
||||||
$chatHistory = $this->getRecentChatHistory($dialog, 15);
|
$chatHistory = $this->getRecentChatHistory($dialog, 15);
|
||||||
@ -836,7 +827,7 @@ class BotReceiveMsgTask extends AbstractTask
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更新系统提示词
|
// 更新系统提示词
|
||||||
if (!empty($sections)) {
|
if (!empty($sections)) {
|
||||||
$extras['system_message'] = implode("\n\n", $sections);
|
$extras['system_message'] = implode("\n\n", $sections);
|
||||||
|
|||||||
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import DialogMarkdown from "../../DialogMarkdown.vue";
|
import DialogMarkdown from "../../DialogMarkdown.vue";
|
||||||
|
import {languageName} from "../../../../../language";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {DialogMarkdown},
|
components: {DialogMarkdown},
|
||||||
@ -11,130 +12,357 @@ export default {
|
|||||||
msg: Object,
|
msg: Object,
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {};
|
return {
|
||||||
|
isChinese: /^zh/.test(languageName),
|
||||||
|
chineseTemplate: `
|
||||||
|
## API 使用说明
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 一、机器人主动发送消息
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>
|
||||||
|
<span style="font-size:1.25em;font-weight:bold;padding-left:8px">发送文本消息接口</span>
|
||||||
|
</summary>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
**功能说明**:开发者可以通过调用此API接口,让机器人主动向指定的对话(群组或私聊)发送文本消息。这是一个主动推送接口,适用于机器人需要定时通知、告警提醒等主动发送消息的场景。
|
||||||
|
|
||||||
|
#### 接口信息
|
||||||
|
|
||||||
|
| 属性 | 结果 |
|
||||||
|
|------|------|
|
||||||
|
| **请求方式** | POST |
|
||||||
|
| **接口地址** | \`{{sendApiUrl}}\` |
|
||||||
|
| **认证方式** | 通过请求头中的 version 和 token 进行认证 |
|
||||||
|
| **超时时间** | 30秒 |
|
||||||
|
|
||||||
|
#### 请求头
|
||||||
|
|
||||||
|
| 参数名 | 值 | 必填 | 说明 |
|
||||||
|
|--------|-----|------|------|
|
||||||
|
| \`version\` | \`{{version}}\` | √ | 系统版本号 |
|
||||||
|
| \`token\` | 机器人Token | √ | 机器人的访问令牌,可在机器人设置中获取 |
|
||||||
|
|
||||||
|
#### 请求参数
|
||||||
|
|
||||||
|
| 参数名 | 说明 | 类型 | 必填 | 示例值 |
|
||||||
|
|--------|------|------|------|--------|
|
||||||
|
| \`dialog_id\` | 对话ID | string | √ | |
|
||||||
|
| \`text\` | 消息内容 | string | √ | |
|
||||||
|
| \`text_type\` | 文本类型 | string | | html 或 md |
|
||||||
|
| \`key\` | 消息唯一标识 | string | | 留空则自动生成 |
|
||||||
|
| \`silence\` | 静默模式 | string | | yes 或 no |
|
||||||
|
| \`reply_id\` | 回复消息ID | string | | |
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 二、Webhook 事件推送
|
||||||
|
|
||||||
|
**功能说明**:当特定事件发生时,系统会自动向机器人配置的 Webhook 地址发送 POST 请求,推送事件数据。这是一个被动接收机制,适用于机器人需要响应用户消息、监听群组事件等场景。
|
||||||
|
|
||||||
|
**重要提示**:
|
||||||
|
- 请确保 Webhook 地址可正常访问,且能在超时时间内响应
|
||||||
|
- 建议对推送的数据进行签名验证,确保数据来源可信
|
||||||
|
- Webhook 接口应尽快返回响应(200 OK),复杂业务逻辑建议异步处理
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>
|
||||||
|
<span style="font-size:1.25em;font-weight:bold;padding-left:8px">接收消息事件(<code>message</code>)</span>
|
||||||
|
</summary>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
**触发时机**:当机器人在对话中收到新消息时(包括被@提及或私聊消息),系统会自动推送到配置的 Webhook 地址。
|
||||||
|
|
||||||
|
**超时时间**:30秒
|
||||||
|
|
||||||
|
**使用场景**:智能问答、关键词回复、消息记录、自动客服等
|
||||||
|
|
||||||
|
#### 推送参数
|
||||||
|
|
||||||
|
| 参数名 | 说明 | 类型 |
|
||||||
|
|--------|------|------|
|
||||||
|
| \`event\` | 事件类型,固定值 \`message\` | string |
|
||||||
|
| \`text\` | 消息的文本内容 | string |
|
||||||
|
| \`reply_text\` | 如果是回复消息,则包含被回复消息的文本内容 | string |
|
||||||
|
| \`token\` | 机器人Token | string |
|
||||||
|
| \`session_id\` | 会话ID {{sessionDesc}} | string |
|
||||||
|
| \`dialog_id\` | 对话ID | string |
|
||||||
|
| \`dialog_type\` | 对话类型 | string |
|
||||||
|
| \`msg_id\` | 消息ID | string |
|
||||||
|
| \`msg_uid\` | 消息发送人的用户ID | string |
|
||||||
|
| \`msg_user\` | 消息发送人的详细信息(昵称、头像等) | object |
|
||||||
|
| \`mention\` | 机器人是否被@提及 | boolean |
|
||||||
|
| \`bot_uid\` | 机器人ID | string |
|
||||||
|
| \`version\` | 系统版本 | string |
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>
|
||||||
|
<span style="font-size:1.25em;font-weight:bold;padding-left:8px">打开会话事件(<code>dialog_open</code>)</span>
|
||||||
|
</summary>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
**触发时机**:当用户打开与机器人的会话窗口时(首次打开或重新进入),系统会推送此事件。
|
||||||
|
|
||||||
|
**超时时间**:10秒
|
||||||
|
|
||||||
|
**使用场景**:欢迎语、菜单展示、会话初始化、用户行为统计等
|
||||||
|
|
||||||
|
#### 推送参数
|
||||||
|
|
||||||
|
| 参数名 | 说明 | 类型 |
|
||||||
|
|--------|------|------|
|
||||||
|
| \`event\` | 事件类型,固定值 \`dialog_open\` | string |
|
||||||
|
| \`dialog_id\` | 对话ID | number |
|
||||||
|
| \`dialog_type\` | 对话类型 | string |
|
||||||
|
| \`group_type\` | 群组类型(仅群组对话时有值) | string |
|
||||||
|
| \`dialog_name\` | 对话名称(群组名称或用户昵称) | string |
|
||||||
|
| \`member\` | 打开会话的成员信息 | object |
|
||||||
|
| \`operator\` | 操作人信息(通常与 member 相同) | object |
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>
|
||||||
|
<span style="font-size:1.25em;font-weight:bold;padding-left:8px">成员加入事件(<code>member_join</code>)</span>
|
||||||
|
</summary>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
**触发时机**:当新成员加入机器人所在的群组时,系统会推送此事件。
|
||||||
|
|
||||||
|
**超时时间**:10秒
|
||||||
|
|
||||||
|
**使用场景**:新成员欢迎语、群规则提醒、自动分配权限、成员统计等
|
||||||
|
|
||||||
|
#### 推送参数
|
||||||
|
|
||||||
|
| 参数名 | 说明 | 类型 |
|
||||||
|
|--------|------|------|
|
||||||
|
| \`event\` | 事件类型,固定值 \`member_join\` | string |
|
||||||
|
| \`dialog_id\` | 群组对话ID | number |
|
||||||
|
| \`dialog_type\` | 对话类型,此处固定为 \`group\` | string |
|
||||||
|
| \`group_type\` | 群组类型 | string |
|
||||||
|
| \`dialog_name\` | 群组名称 | string |
|
||||||
|
| \`member\` | 加入的成员信息(昵称、ID等) | object |
|
||||||
|
| \`operator\` | 操作人信息(邀请人,如果是自己加入则与 member 相同) | object |
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>
|
||||||
|
<span style="font-size:1.25em;font-weight:bold;padding-left:8px">成员退出事件(<code>member_leave</code>)</span>
|
||||||
|
</summary>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
**触发时机**:当成员退出或被移出机器人所在的群组时,系统会推送此事件。
|
||||||
|
|
||||||
|
**超时时间**:10秒
|
||||||
|
|
||||||
|
**使用场景**:成员变动记录、权限清理、离职提醒、成员统计等
|
||||||
|
|
||||||
|
#### 推送参数
|
||||||
|
|
||||||
|
| 参数名 | 说明 | 类型 |
|
||||||
|
|--------|------|------|
|
||||||
|
| \`event\` | 事件类型,固定值 \`member_leave\` | string |
|
||||||
|
| \`dialog_id\` | 群组对话ID | number |
|
||||||
|
| \`dialog_type\` | 对话类型,此处固定为 \`group\` | string |
|
||||||
|
| \`group_type\` | 群组类型 | string |
|
||||||
|
| \`dialog_name\` | 群组名称 | string |
|
||||||
|
| \`member\` | 退出的成员信息(昵称、ID等) | object |
|
||||||
|
| \`operator\` | 操作人信息(踢出者,如果是自己退出则与 member 相同) | object |
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**提示**:请妥善保管机器人 Token,确保 Webhook 接口稳定可用并及时响应。更多帮助请发送 <span class="mark-color mark-set">/help</span> 命令查看。
|
||||||
|
`,
|
||||||
|
englishTemplate: `
|
||||||
|
## API Documentation
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Bot Proactive Message Sending
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>
|
||||||
|
<span style="font-size:1.25em;font-weight:bold;padding-left:8px">Send Text Message API</span>
|
||||||
|
</summary>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
**Description**: Developers can call this API to allow the bot to proactively send text messages to specified conversations (groups or private chats). This is a proactive push interface, suitable for scenarios where the bot needs to send scheduled notifications, alerts, and other proactive messages.
|
||||||
|
|
||||||
|
#### API Information
|
||||||
|
|
||||||
|
| Property | Value |
|
||||||
|
|------|------|
|
||||||
|
| **Request Method** | POST |
|
||||||
|
| **API Endpoint** | \`{{sendApiUrl}}\` |
|
||||||
|
| **Authentication** | Authenticate via version and token in request headers |
|
||||||
|
| **Timeout** | 30 seconds |
|
||||||
|
|
||||||
|
#### Request Headers
|
||||||
|
|
||||||
|
| Parameter | Value | Required | Description |
|
||||||
|
|--------|-----|------|------|
|
||||||
|
| \`version\` | \`{{version}}\` | √ | System version number |
|
||||||
|
| \`token\` | Bot Token | √ | Bot access token, available in bot settings |
|
||||||
|
|
||||||
|
#### Request Parameters
|
||||||
|
|
||||||
|
| Parameter | Description | Type | Required | Example |
|
||||||
|
|--------|------|------|------|--------|
|
||||||
|
| \`dialog_id\` | Dialog ID | string | √ | |
|
||||||
|
| \`text\` | Message content | string | √ | |
|
||||||
|
| \`text_type\` | Text type | string | | html or md |
|
||||||
|
| \`key\` | Unique message identifier | string | | Auto-generated if left empty |
|
||||||
|
| \`silence\` | Silent mode | string | | yes or no |
|
||||||
|
| \`reply_id\` | Reply message ID | string | | |
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Webhook Event Push
|
||||||
|
|
||||||
|
**Description**: When specific events occur, the system will automatically send POST requests to the Webhook URL configured for the bot, pushing event data. This is a passive receiving mechanism, suitable for scenarios where the bot needs to respond to user messages, monitor group events, etc.
|
||||||
|
|
||||||
|
**Important Notes**:
|
||||||
|
- Ensure the Webhook URL is accessible and can respond within the timeout period
|
||||||
|
- Recommend verifying the signature of pushed data to ensure the source is trustworthy
|
||||||
|
- Webhook interface should return a response (200 OK) as quickly as possible; complex business logic should be handled asynchronously
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>
|
||||||
|
<span style="font-size:1.25em;font-weight:bold;padding-left:8px">Message Received Event (<code>message</code>)</span>
|
||||||
|
</summary>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
**Trigger Timing**: When the bot receives a new message in a conversation (including being @mentioned or private messages), the system will automatically push to the configured Webhook URL.
|
||||||
|
|
||||||
|
**Timeout**: 30 seconds
|
||||||
|
|
||||||
|
**Use Cases**: Intelligent Q&A, keyword replies, message logging, automatic customer service, etc.
|
||||||
|
|
||||||
|
#### Push Parameters
|
||||||
|
|
||||||
|
| Parameter | Description | Type |
|
||||||
|
|--------|------|------|
|
||||||
|
| \`event\` | Event type, fixed value \`message\` | string |
|
||||||
|
| \`text\` | Text content of the message | string |
|
||||||
|
| \`reply_text\` | If it's a reply message, contains the text content of the replied message | string |
|
||||||
|
| \`token\` | Bot Token | string |
|
||||||
|
| \`session_id\` | Session ID {{sessionDesc}} | string |
|
||||||
|
| \`dialog_id\` | Dialog ID | string |
|
||||||
|
| \`dialog_type\` | Dialog type | string |
|
||||||
|
| \`msg_id\` | Message ID | string |
|
||||||
|
| \`msg_uid\` | User ID of message sender | string |
|
||||||
|
| \`msg_user\` | Detailed information of message sender (nickname, avatar, etc.) | object |
|
||||||
|
| \`mention\` | Whether the bot was @mentioned | boolean |
|
||||||
|
| \`bot_uid\` | Bot ID | string |
|
||||||
|
| \`version\` | System version | string |
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>
|
||||||
|
<span style="font-size:1.25em;font-weight:bold;padding-left:8px">Dialog Open Event (<code>dialog_open</code>)</span>
|
||||||
|
</summary>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
**Trigger Timing**: When a user opens a conversation window with the bot (first time or re-entry), the system will push this event.
|
||||||
|
|
||||||
|
**Timeout**: 10 seconds
|
||||||
|
|
||||||
|
**Use Cases**: Welcome messages, menu display, session initialization, user behavior statistics, etc.
|
||||||
|
|
||||||
|
#### Push Parameters
|
||||||
|
|
||||||
|
| Parameter | Description | Type |
|
||||||
|
|--------|------|------|
|
||||||
|
| \`event\` | Event type, fixed value \`dialog_open\` | string |
|
||||||
|
| \`dialog_id\` | Dialog ID | number |
|
||||||
|
| \`dialog_type\` | Dialog type | string |
|
||||||
|
| \`group_type\` | Group type (only for group conversations) | string |
|
||||||
|
| \`dialog_name\` | Dialog name (group name or user nickname) | string |
|
||||||
|
| \`member\` | Information of member opening the session | object |
|
||||||
|
| \`operator\` | Operator information (usually same as member) | object |
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>
|
||||||
|
<span style="font-size:1.25em;font-weight:bold;padding-left:8px">Member Join Event (<code>member_join</code>)</span>
|
||||||
|
</summary>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
**Trigger Timing**: When a new member joins a group where the bot is present, the system will push this event.
|
||||||
|
|
||||||
|
**Timeout**: 10 seconds
|
||||||
|
|
||||||
|
**Use Cases**: New member welcome messages, group rules reminders, automatic permission assignment, member statistics, etc.
|
||||||
|
|
||||||
|
#### Push Parameters
|
||||||
|
|
||||||
|
| Parameter | Description | Type |
|
||||||
|
|--------|------|------|
|
||||||
|
| \`event\` | Event type, fixed value \`member_join\` | string |
|
||||||
|
| \`dialog_id\` | Group dialog ID | number |
|
||||||
|
| \`dialog_type\` | Dialog type, fixed as \`group\` | string |
|
||||||
|
| \`group_type\` | Group type | string |
|
||||||
|
| \`dialog_name\` | Group name | string |
|
||||||
|
| \`member\` | Information of joining member (nickname, ID, etc.) | object |
|
||||||
|
| \`operator\` | Operator information (inviter, same as member if self-joined) | object |
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>
|
||||||
|
<span style="font-size:1.25em;font-weight:bold;padding-left:8px">Member Leave Event (<code>member_leave</code>)</span>
|
||||||
|
</summary>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
**Trigger Timing**: When a member leaves or is removed from a group where the bot is present, the system will push this event.
|
||||||
|
|
||||||
|
**Timeout**: 10 seconds
|
||||||
|
|
||||||
|
**Use Cases**: Member change records, permission cleanup, departure reminders, member statistics, etc.
|
||||||
|
|
||||||
|
#### Push Parameters
|
||||||
|
|
||||||
|
| Parameter | Description | Type |
|
||||||
|
|--------|------|------|
|
||||||
|
| \`event\` | Event type, fixed value \`member_leave\` | string |
|
||||||
|
| \`dialog_id\` | Group dialog ID | number |
|
||||||
|
| \`dialog_type\` | Dialog type, fixed as \`group\` | string |
|
||||||
|
| \`group_type\` | Group type | string |
|
||||||
|
| \`dialog_name\` | Group name | string |
|
||||||
|
| \`member\` | Information of leaving member (nickname, ID, etc.) | object |
|
||||||
|
| \`operator\` | Operator information (remover, same as member if self-left) | object |
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Tip**: Please keep the bot Token secure, ensure the Webhook interface is stable and responds promptly. For more help, send the <span class="mark-color mark-set">/help</span> command.
|
||||||
|
`,
|
||||||
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
content() {
|
content() {
|
||||||
const sessionDesc = !/^(ai-|user-session-)/.test(this.msg.email) ? " <span style='color:#999;padding-left:4px;'>({{该机器人不支持}})</span>" : "";
|
const variables = {
|
||||||
return [
|
sendApiUrl: $A.apiUrl('dialog/msg/sendtext'),
|
||||||
"## {{API 使用说明}}",
|
version: this.msg.version,
|
||||||
"",
|
sessionDesc: !/^(ai-|user-session-)/.test(this.msg.email) ? ` <span style='color:#999;padding-left:4px;'>(${this.$L('该机器人不支持')})</span>` : ``,
|
||||||
"### 1. {{发送文本消息}}",
|
};
|
||||||
"",
|
const template = this.isChinese ? this.chineseTemplate : this.englishTemplate;
|
||||||
"{{开发者可以通过此接口调用机器人向指定对话发送文本消息。}}",
|
return template.replace(/\{\{([^}]+)\}\}/g, (_, v1) => variables[v1] || v1).trim();
|
||||||
"",
|
|
||||||
"#### {{接口信息}}",
|
|
||||||
"",
|
|
||||||
"| {{属性}} | {{结果}} |",
|
|
||||||
"|------|------|",
|
|
||||||
"| **{{请求方式}}** | POST |",
|
|
||||||
"| **{{接口地址}}** | `" + $A.apiUrl('dialog/msg/sendtext') + "` |",
|
|
||||||
"| **{{说明}}** | {{通过机器人向指定对话发送文本消息}} |",
|
|
||||||
"",
|
|
||||||
"#### {{请求头}}",
|
|
||||||
"",
|
|
||||||
"| {{参数名}} | {{值}} | {{必填}} |",
|
|
||||||
"|--------|-----|------|",
|
|
||||||
"| `version` | `" + this.msg.version + "` | √ |",
|
|
||||||
"| `token` | {{机器人Token}} | √ |",
|
|
||||||
"",
|
|
||||||
"#### {{请求参数}}",
|
|
||||||
"",
|
|
||||||
"| {{参数名}} | {{说明}} | {{类型}} | {{必填}} | {{示例值}} |",
|
|
||||||
"|--------|------|------|------|--------|",
|
|
||||||
"| `dialog_id` | {{对话ID}} | string | √ | |",
|
|
||||||
"| `text` | {{消息内容}} | string | √ | |",
|
|
||||||
"| `text_type` | {{文本类型}} | string | | {{html 或 md}} |",
|
|
||||||
"| `key` | {{搜索词}} | string | | {{留空自动生成}} |",
|
|
||||||
"| `silence` | {{静默模式}} | string | | {{yes 或 no}} |",
|
|
||||||
"| `reply_id` | {{回复指定消息ID}} | string | | |",
|
|
||||||
"",
|
|
||||||
"### 2. {{Webhook 消息推送}}",
|
|
||||||
"",
|
|
||||||
"{{机器人收到消息后会自动POST推送到配置的Webhook地址,请求超时为10秒。}}",
|
|
||||||
"",
|
|
||||||
"#### {{推送参数}}",
|
|
||||||
"",
|
|
||||||
"| {{参数名}} | {{说明}} | {{类型}} |",
|
|
||||||
"|--------|------|------|",
|
|
||||||
"| `text` | {{消息文本内容}} | string |",
|
|
||||||
"| `reply_text` | {{回复/引用的消息文本}} | string |",
|
|
||||||
"| `token` | {{机器人Token}} | string |",
|
|
||||||
"| `session_id` | {{会话ID}}" + sessionDesc + " | string |",
|
|
||||||
"| `dialog_id` | {{对话ID}} | string |",
|
|
||||||
"| `dialog_type` | {{对话类型}} | string |",
|
|
||||||
"| `msg_id` | {{消息ID}} | string |",
|
|
||||||
"| `msg_uid` | {{消息发送人ID}} | string |",
|
|
||||||
"| `msg_user` | {{消息发送人信息}} | object |",
|
|
||||||
"| `mention` | {{是否被@到}} | boolean |",
|
|
||||||
"| `bot_uid` | {{机器人ID}} | string |",
|
|
||||||
"| `version` | {{系统版本}} | string |",
|
|
||||||
"### 3. {{打开会话 消息推送}}",
|
|
||||||
"",
|
|
||||||
"{{打开机器人会话后会自动POST推送到配置的Webhook地址,请求超时为30秒。}}",
|
|
||||||
"",
|
|
||||||
"#### {{推送参数}}",
|
|
||||||
"",
|
|
||||||
"| {{参数名}} | {{说明}} | {{类型}} |",
|
|
||||||
"|--------|------|------|",
|
|
||||||
"| `event` | {{推送事件}} | string |",
|
|
||||||
"| `timestamp` | {{推送时间戳}} | string |",
|
|
||||||
"| `dialog_id` | {{对话ID}} | string |",
|
|
||||||
"| `dialog_type` | {{对话类型}} | string |",
|
|
||||||
"| `bot_uid` | {{机器人ID}} | string |",
|
|
||||||
"| `owner_uid` | {{机器人所属用户ID}} | string |",
|
|
||||||
"| `user` | {{机器人所属用户信息}} | object |",
|
|
||||||
"| `user.userid` | {{用户ID}} | string |",
|
|
||||||
"| `user.email` | {{用户邮箱}} | string |",
|
|
||||||
"| `user.nickname` | {{用户昵称}} | string |",
|
|
||||||
"### 4. {{成员加入 消息推送}}",
|
|
||||||
"",
|
|
||||||
"{{成员加入群组后会自动POST推送到配置的Webhook地址,请求超时为30秒。}}",
|
|
||||||
"",
|
|
||||||
"#### {{推送参数}}",
|
|
||||||
"",
|
|
||||||
"| {{参数名}} | {{说明}} | {{类型}} |",
|
|
||||||
"|--------|------|------|",
|
|
||||||
"| `event` | {{推送事件}} | string |",
|
|
||||||
"| `timestamp` | {{推送时间戳}} | string |",
|
|
||||||
"| `dialog_id` | {{对话ID}} | string |",
|
|
||||||
"| `dialog_type` | {{对话类型}} | string |",
|
|
||||||
"| `bot_uid` | {{机器人ID}} | string |",
|
|
||||||
"| `owner_uid` | {{机器人所属用户ID}} | string |",
|
|
||||||
"| `user` | {{机器人所属用户信息}} | object |",
|
|
||||||
"| `user.userid` | {{用户ID}} | string |",
|
|
||||||
"| `user.email` | {{用户邮箱}} | string |",
|
|
||||||
"| `user.nickname` | {{用户昵称}} | string |",
|
|
||||||
"### 5. {{成员退出 消息推送}}",
|
|
||||||
"",
|
|
||||||
"{{成员退出群组后会自动POST推送到配置的Webhook地址,请求超时为30秒。}}",
|
|
||||||
"",
|
|
||||||
"#### {{推送参数}}",
|
|
||||||
"",
|
|
||||||
"| {{参数名}} | {{说明}} | {{类型}} |",
|
|
||||||
"|--------|------|------|",
|
|
||||||
"| `event` | {{推送事件}} | string |",
|
|
||||||
"| `timestamp` | {{推送时间戳}} | string |",
|
|
||||||
"| `dialog_id` | {{对话ID}} | string |",
|
|
||||||
"| `dialog_type` | {{对话类型}} | string |",
|
|
||||||
"| `dialog_name` | {{对话名称}} | string |",
|
|
||||||
"| `group_type` | {{群组类型}} | string |",
|
|
||||||
"| `bot_uid` | {{机器人ID}} | string |",
|
|
||||||
"| `owner_uid` | {{机器人所属用户ID}} | string |",
|
|
||||||
"| `action` | {{动作}} | string |",
|
|
||||||
"| `actor` | {{操作人信息}} | object |",
|
|
||||||
"| `actor.userid` | {{用户ID}} | string |",
|
|
||||||
"| `actor.email` | {{用户邮箱}} | string |",
|
|
||||||
"| `actor.nickname` | {{用户昵称}} | string |",
|
|
||||||
"| `actor.is_bot` | {{是否机器人}} | boolean |",
|
|
||||||
"| `members` | {{成员信息}} | array |",
|
|
||||||
"| `members.userid` | {{用户ID}} | string |",
|
|
||||||
"| `members.email` | {{用户邮箱}} | string |",
|
|
||||||
"| `members.nickname` | {{用户昵称}} | string |",
|
|
||||||
"| `members.is_bot` | {{是否机器人}} | boolean |",
|
|
||||||
].map(item => item.replace(/\{\{([^}]+)\}\}/g, (_, v1) => this.$L(v1))).join("\n");
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {},
|
methods: {},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -1241,8 +1241,7 @@ export default {
|
|||||||
this.getDialogBase(dialog_id)
|
this.getDialogBase(dialog_id)
|
||||||
this.generateUnreadData(old_id)
|
this.generateUnreadData(old_id)
|
||||||
//
|
//
|
||||||
this.$store.dispatch('openDialogWebhook', dialog_id)
|
this.$store.dispatch('openDialogEvent', dialog_id)
|
||||||
//
|
|
||||||
this.$store.dispatch('closeDialog', {id: old_id})
|
this.$store.dispatch('closeDialog', {id: old_id})
|
||||||
//
|
//
|
||||||
window.localStorage.removeItem('__cache:vote__')
|
window.localStorage.removeItem('__cache:vote__')
|
||||||
|
|||||||
54
resources/assets/js/store/actions.js
vendored
54
resources/assets/js/store/actions.js
vendored
@ -3514,35 +3514,6 @@ export default {
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
|
||||||
* 打开会话(打开机器人会话推送 webhook)
|
|
||||||
* @param state
|
|
||||||
* @param dispatch
|
|
||||||
* @param dialogId
|
|
||||||
* @returns {Promise<unknown>}
|
|
||||||
*/
|
|
||||||
openDialogWebhook({state, dispatch}, dialogId) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
const dialog = state.cacheDialogs.find(item => {
|
|
||||||
if (item.type !== 'user') {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return item.id === dialogId
|
|
||||||
});
|
|
||||||
if (dialog && dialog.bot === 1) {
|
|
||||||
dispatch("call", {
|
|
||||||
url: 'dialog/open/webhook',
|
|
||||||
data: {
|
|
||||||
dialog_id: dialogId,
|
|
||||||
},
|
|
||||||
}).catch(e => {
|
|
||||||
console.warn(e);
|
|
||||||
reject(e);
|
|
||||||
})
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 打开会话(通过会员ID打开个人会话)
|
* 打开会话(通过会员ID打开个人会话)
|
||||||
* @param state
|
* @param state
|
||||||
@ -3576,6 +3547,31 @@ export default {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 打开会话事件
|
||||||
|
* @param state
|
||||||
|
* @param dispatch
|
||||||
|
* @param dialogId
|
||||||
|
* @returns {Promise<unknown>}
|
||||||
|
*/
|
||||||
|
openDialogEvent({state, dispatch}, dialogId) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
if (!dialogId) {
|
||||||
|
reject({msg: 'Parameter error'});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
dispatch("call", {
|
||||||
|
url: 'dialog/open/event',
|
||||||
|
data: {
|
||||||
|
dialog_id: dialogId,
|
||||||
|
},
|
||||||
|
}).catch(e => {
|
||||||
|
console.warn(e);
|
||||||
|
reject(e);
|
||||||
|
})
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 打开会话(客户端新窗口)
|
* 打开会话(客户端新窗口)
|
||||||
* @param state
|
* @param state
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user