'发送成功', 2 => '发送失败']; } public function getSendStatusTxtAttr($value, $data) { $value = $value ? $value : (isset($data['send_status']) ? $data['send_status'] : ''); $sendStatusList = $this->sendStatusList(); return isset($sendStatusList[$value]) ? $sendStatusList[$value] : ''; } public function readStatusList() { return [1 => '未读', 2 => '已读']; } public function getReadStatusTxtAttr($value, $data) { $value = $value ? $value : (isset($data['read_status']) ? $data['read_status'] : ''); $readStatusList = $this->readStatusList(); return isset($readStatusList[$value]) ? $readStatusList[$value] : ''; } public function channelList() { return Msgtype::channelList(); } public function getChannelTxtAttr($value, $data) { $value = $value ? $value : (isset($data['channel']) ? $data['channel'] : ''); $channelList = $this->channelList(); return isset($channelList[$value]) ? $channelList[$value] : ''; } static public function getUrlAttr($value, $data) { $msgType = Msgtype::where('type_code', $data['type_code'])->cache(true, 86400)->find(); $param = []; if (!empty($msgType->param_key1)) { $param[$msgType->param_key1] = $data['param1']; } if (!empty($msgType->param_key2)) { $param[$msgType->param_key2] = $data['param2']; } $url = ""; if (!empty($msgType->url_mp) || !empty($msgType->url_pc)) { $url = IsMobileAccess() ? $msgType->url_mp : $msgType->url_pc . '?'; $url .= http_build_query($param); } return $url; } public function msgtype() { return $this->belongsTo(Msgtype::class, 'type_code', 'type_code')->cache(true, 3600); } public function receiver() { return $this->belongsTo(User::class, 'receive_uid', 'user_id')->cache(true, 3600); } /** * @title: 通过邮件发送消息通知 * @desc: * @param {Int} {receiver_uid} {} {邮件接收用户ID} * @param {String} {subject} {} {邮件主题} * @param {String} {content} {} {邮件内容,可使用html代码} * @return {*} * @Author: Rock * @Date: 2021-05-26 17:07:43 * @LastEditTime: Do not edit * @throws \Exception */ static public function sendMail($receiver_uid, $subject = 'This is a test mail', $content = 'This is a test mail content') { $user = User::where('user_id', $receiver_uid)->find(); if (!empty($user->email)) { $email = new Email; $result = $email ->to($user->email) ->subject($subject) ->message($content) ->send(); if ($result) { return Result(1, "发送邮件成功"); } else { return Result(0, "发送邮件失败" . $email->getError()); } } else { return Result(0, "此用户未设置邮箱"); } } /** * @title: 使用腾讯发送短信 * @desc: * @param {*} $mobiles * @param {*} $data * @param {*} $tpl_id * @return {*} * @Author: Rock * @Date: 2022-03-12 17:25:15 * @LastEditTime: Do not edit */ static public function TxSmsSend($mobiles, $data, $tpl_id) { if (empty($mobiles)) { return Result(0, '手机号不能为空'); } $sms = new \tencent\Sms; $newMobiles = []; foreach ($mobiles as $mobile) { if (11 == strlen($mobile)) { $newMobiles[] = $mobile; } } $res = $sms->SendSms($newMobiles, $data, $tpl_id); if (isset($res['errmsg']) && $res['errmsg'] == 'OK') { return Result(1, "发送短信成功"); } else { $msg = isset($res['ErrorInfo']) ? $res['ErrorInfo'] : (isset($res['errmsg']) ? $res['errmsg'] : '短信接口错误'); return Result(0, "发送短信失败:" . $msg); } } /** * @title: 使用联通发送短信 * @desc: * @param {*} $phone * @param {*} $data * @param {*} $tpl_id * @return {*} * @Author: Rock * @Date: 2022-03-12 17:29:20 * @LastEditTime: Do not edit */ static public function UmsSmsSend($mobiles, $data, $tpl_id) { if (empty($mobiles)) { return Result(0, '手机号不能为空'); } $sms = new \ums\Sms; $tplInfo = SmsTpl::where('tpl_id', $tpl_id)->find(); if ($tplInfo) { $content = $tplInfo->content; // 将参数替换进模板内容 foreach ($data as $param) { $start = strpos($content, '{'); $end = strpos($content, '}'); if ($start !== false && $end !== false) { $sub = substr($content, $start, $end - $start + 1); $content = str_replace($sub, $param, $content); } } // 过滤不是手机的号码 $newMobiles = []; foreach ($mobiles as $mobile) { if (11 == strlen($mobile)) { $newMobiles[] = $mobile; } } $phone = implode(',', $newMobiles); $res = $sms->SendSms($phone, $content, $tpl_id); if (!empty($res['result']) && 0 == $res['result']) { return Result(1, "短信发送成功", $res); } else { WLog('ums_sms_send', "短信发送失败:" . json_encode($res)); return Result(0, $res['description'] ?? '短信发送失败', $res); } } else { WLog('ums_sms_send', "没有找到短信模板"); } } /** * @title: 通过短信发送消息通知 * @desc: * @param {string/array} {mobiles} {} {短信接收用户手机号} * @param {Array} {data} {} {需要填充到短信模板中的数据} * @param {Int} {tpl_id} {} {腾讯短信消息模板ID} * @return {*} * @Author: Rock * @Date: 2021-05-26 17:09:28 * @LastEditTime: Do not edit * @throws \Exception */ static public function sendSms($mobiles, array $data, string $tpl_id) { $provider = sysconfig('sms.provider'); if (!empty($mobiles)) { // 腾讯短信 if (1 == $provider) { return self::TxSmsSend($mobiles, $data, $tpl_id); } // 联通短信 elseif (2 == $provider) { return self::UmsSmsSend($mobiles, $data, $tpl_id); } } else { return Result(0, "此用户未绑定手机号"); } } /** * @title: 通过站内信发送消息通知 * @desc: * @param {Int} {receiver_uid} {} {消息接收用户ID} * @param {Array} {data} {} {消息数据包} * @return {*} * @Author: Rock * @Date: 2021-06-04 09:56:48 * @LastEditTime: Do not edit */ static public function sendWs($uids, $data) { $res = wssend($uids, 'notice', $data); if ($res) { return Result($res['code'], $res['msg']); } else { return Result(2, "发送失败"); } } /** * @title: 通过微信公众号发送消息通知 * @desc: 描述 * @param {mixed} {uids} {} {消息接收用户ID数组} * @param {array} {data} {} {消息数据包,这里接收和短信一样的参数方式,即索引数组,如:['张三','18','男']} * @return {*} * @author: Rock * @method: POST * @Date: 2023-04-06 17:48:17 */ static public function sendWx($uids,array $data,string $template_id) { if(is_string($uids)){ $udis = explode(',',$uids); }elseif(is_int($uids)){ $uids = [$uids]; } $openids = Wxauth::where('user_id','IN',$uids)->column('openid'); // 因为接收的是短信一样的参数,这里需要处理成公众号方式的参数$info $info = []; // 通过模板取出待填充数据的字段 $content = WxTpl::where('template_id',$template_id)->value('content'); preg_match_all('/{{([\w\W]*?).DATA}}/',$content,$matches); $keys = $matches[1]; foreach($keys as $index=>$key){ $info[$key] = $data[$index]??''; } foreach($openids as $openid){ $res = (new Wxmsg)->Send_Msg($openid,$template_id,$info); if($res['errcode'] && 0!=$res['errcode']){ WLog('Notice/SendWx',json_encode($res)); } } return Result(1,"发送成功",$res); } /** * @title: 单一通道发送消息通知 * @desc: * @param {string} {notice.uids} {} {用户ID或逗号分隔的多个用户ID} * @param {string} {notice.title} {} {消息通知标题} * @param {string} {notice.type_code} {} {消息类型代码} * @param {string} {notice.data} {} {短信模板填充数据} * @param {mixed} {notice.param1} {} {所属消息类型的第一个参数} * @param {mixed} {notice.param2} {} {所属消息类型的第二个参数} * @return {*} * @Author: Rock * @Date: 2021-05-26 18:50:12 * @LastEditTime: Do not edit * @throws \Exception */ static public function sendNotice($notice) { try { if (empty($notice['uids']) || empty($notice['title']) || empty($notice['type_code'])) { return res(2, "发送消息缺少参数"); } $uids = $notice['uids']; $title = $notice['title']; $data = !empty($notice['data']) ? $notice['data'] : []; $type_code = $notice['type_code']; $param1 = !empty($notice['param1']) ? $notice['param1'] : ''; $param2 = !empty($notice['param2']) ? $notice['param2'] : ''; $msgtype = Msgtype::where('type_code', $type_code)->find(); if (empty($msgtype)) { return res(2, "不存在的消息类型"); } $channel = $msgtype->channel; $pcHost = sysconfig('base.pc_host');//换为PC端访问基础地址 if (is_string($uids)) { $uids = explode(',', (string)$uids); } elseif (is_int($uids)) { $uids = [$uids]; } $mobiles = User::where('user_id', 'IN', $uids)->where('phone', '<>', '')->whereNotNull('phone')->column('phone'); $mobiles = array_filter($mobiles); $saveData = []; foreach ($channel as $channelItem) { $temp = [ 'title' => $msgtype->type_name . ":" . $title, 'type_code' => $type_code, 'channel' => $channelItem, 'param1' => $param1, 'param2' => $param2, 'send_at' => date('Y-m-d H:i:s'), 'read_status' => 1, ]; switch ($channelItem) { case 1://站内信 $temp['send_status'] = 1; $temp['msgtype'] = $msgtype->toArray(); $res = self::sendWs(implode(',', $uids), $temp); foreach ($uids as $uid) { $temp['receive_uid'] = $uid; unset($temp['msgtype']); $saveData[] = $temp; } break; case 2://短信 $res = self::sendSms($mobiles, $data, $msgtype->sms_tpl); foreach ($uids as $uid) { $temp['send_status'] = $res['code'] == 1 ? 1 : 2; $temp['receive_uid'] = $uid; $saveData[] = $temp; } break; case 3://邮件 $url = self::getUrlAttr('', $temp); $content = '' . $temp['title'] . ''; foreach ($uids as $uid) { $res = self::sendMail($uid, $temp['title'], $content); $temp['send_status'] = $res['code'] == 1 ? 1 : 2; $temp['receive_uid'] = $uid; $saveData[] = $temp; } self::create($temp); break; case 4://公众号 $res = self::sendWx($uids,$data,$msgtype->template_id); foreach($uids as $uid){ $temp['send_status'] = $res['code'] == 1?1:2; $temp['receive_uid'] = $uid; } $saveData[] = $temp; break; default: $res = ['code' => 1]; break; } } self::insertAll($saveData); return res(1, '发送成功'); } catch (Exception $e) { abort(2, $e->getMessage()); } } /** * @title: 获取消息未读数等 * @param $user_id {用户id} * @param $role_code {用户角色} * @param $ids {用户有权限的组织id} * @Author: wangkewei * @return mixed * @Date: 2022/2/28 18:47 */ public function MsgUnreadNum($user_id, $role_code, $ids) { $un_read_num = $this->where('receive_uid', $user_id) ->where('read_status', 1) ->where('channel', 1) ->count('notice_id'); return ['un_read_num' => $un_read_num]; } }