20) { // 每个机器人每分钟最多发送20条消息到群里,如果超过20条,会限流10分钟。 Log::critical(trans('notification.error', ['channel' => trans('admin.system.notification.channel.dingtalk'), 'reason' => trans('notification.ding_bot_limit')])); return false; } $message = $notification->toCustom($notifiable); $url = 'https://oapi.dingtalk.com/robot/send?'; $query['access_token'] = sysConfig('dingTalk_access_token'); if (sysConfig('dingTalk_secret') !== null) { $timestamp = time() * 1000; $query['timestamp'] = $timestamp; $query['sign'] = $this->sign($timestamp); } $url .= http_build_query($query); if (isset($message['button'])) { // 独立跳转ActionCard类型 $body = [ 'msgtype' => 'actionCard', 'actionCard' => [ 'title' => $message['title'], 'text' => $message['markdown'], 'btnOrientation' => 1, 'btns' => [ [ 'title' => trans('common.status.reject'), 'actionURL' => $message['button'][0], ], [ 'title' => trans('common.confirm'), 'actionURL' => $message['button'][1], ], ], ], ]; } elseif (isset($message['url_type'])) { // 文本卡片 $msgId = Str::uuid(); // 生成对公消息查询URL $body = [ 'msgtype' => 'link', 'link' => [ 'title' => $message['title'], 'text' => trans('notification.details_btn'), 'messageUrl' => route('message.show', ['type' => $message['url_type'], $msgId]), ], ]; } else { // 文本消息 $body = [ 'msgtype' => 'text', 'text' => [ 'content' => $message['content'], ], ]; } $response = Http::timeout(15)->withBody(json_encode($body, JSON_UNESCAPED_UNICODE), 'application/json;charset=utf-8')->post($url); // 发送成功 if ($response->ok()) { $ret = $response->json(); if (! $ret['errcode'] && $ret['errmsg'] === 'ok') { Helpers::addNotificationLog($message['title'], $message['content'] ?? var_export($message['body'], true), 10, 1, null, $msgId ?? null); return $ret; } // 发送失败 Helpers::addNotificationLog($message['title'], $message['content'] ?? var_export($message['body'], true), 10, -1, $ret ? $ret['errmsg'] : trans('common.status.unknown')); return false; } // 发送错误 Log::critical(trans('notification.error', ['channel' => trans('admin.system.notification.channel.dingtalk'), 'reason' => var_export($response, true)])); return false; } private function sign(int $timestamp): string // 加签 { // https://open.dingtalk.com/document/robots/customize-robot-security-settings return base64_encode(hash_hmac('sha256', $timestamp."\n".sysConfig('dingTalk_secret'), sysConfig('dingTalk_secret'), true)); } }