企微短剧业务系统

ChatGroupService.php 57KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358
  1. <?php
  2. namespace App\Service\ChatGroup;
  3. use App\EsModel;
  4. use App\Log;
  5. use App\Models\AndroidBindCorp;
  6. use App\Models\AuthorizeCorp;
  7. use App\Models\ChatGroup;
  8. use App\Models\ChatGroupWelcomeTemplate;
  9. use App\Models\CustomerDetails;
  10. use App\Models\DjDepartment;
  11. use App\Models\DjUser;
  12. use App\Models\Es\ChatGroupMember;
  13. use App\Models\ForwardChatGroupRule;
  14. use App\Models\InviteChatGroupDetail;
  15. use App\Models\InviteChatGroupRule;
  16. use App\Models\Material;
  17. use App\Models\QrcodeChatGroup;
  18. use App\Models\System\AdminManageCorp;
  19. use App\Models\System\Users;
  20. use App\RedisModel;
  21. use App\Service\CircleMassMsgService;
  22. use App\Service\MassMsgService;
  23. use App\Service\MaterialService;
  24. use App\Support\EmailQueue;
  25. use App\Support\qyApi\QyCommon;
  26. use Illuminate\Support\Facades\DB;
  27. class ChatGroupService
  28. {
  29. CONST CREATE_GROUP_WAIT_RDS = 'Playlet::createChatGroupWaitRds';
  30. // 客户群事件回调处理
  31. public static function templateCallBack($msgStr)
  32. {
  33. try{
  34. $msgObj = simplexml_load_string($msgStr, 'SimpleXMLElement', LIBXML_NOCDATA);
  35. $changeType = trim($msgObj->ChangeType);
  36. $params['corpid'] = trim($msgObj->ToUserName);
  37. $params['chat_id'] = trim($msgObj->ChatId);
  38. $params['change_type'] = $changeType;
  39. if(empty($params['corpid']) || empty($params['chat_id']) || empty($params['change_type'])) {
  40. Log::logError('ChatGroupService.templateCallBack', [
  41. 'params' => $msgStr,
  42. 'err_msg' => '回调参数异常',
  43. ], 'interface');
  44. return false;
  45. }
  46. $params['update_detail'] = isset($msgObj->UpdateDetail) ? trim($msgObj->UpdateDetail) : null;
  47. $params['create_time'] = isset($msgObj->CreateTime) ? trim($msgObj->CreateTime) : null;
  48. $params['join_scene'] = isset($msgObj->JoinScene) ? trim($msgObj->JoinScene) : null;
  49. $params['quit_scene'] = isset($msgObj->QuitScene) ? trim($msgObj->QuitScene) : null;
  50. $params['mem_change_cnt'] = isset($msgObj->MemChangeCnt) ? trim($msgObj->MemChangeCnt) : null;
  51. $params['request_time'] = time()+5;
  52. $params['status'] = null;
  53. $params['mem_change_list'] = isset($msgObj->MemChangeList->Item) ? json_decode(json_encode($msgObj->MemChangeList->Item), true) : [];
  54. $params['last_mem_ver'] = isset($msgObj->LastMemVer) ? trim($msgObj->LastMemVer) : '';
  55. $params['cur_mem_ver'] = isset($msgObj->CurMemVer) ? trim($msgObj->CurMemVer) : '';
  56. Log::logInfo('群回调数据日志', [
  57. 'params' => $params,
  58. 'msg' => $msgStr
  59. ], 'ChatGroupCallback');
  60. switch($changeType) {
  61. case 'create': // 客户群创建
  62. $result = RedisModel::lPush(ChatGroup::CHAT_GROUP_DETAIL_RDS, json_encode($params));
  63. break;
  64. case 'update': // 客户群变更
  65. // 比对版本号
  66. $chatGroupInfo = ChatGroup::where('corpid', $params['corpid'])->where('chat_id', $params['chat_id'])->first();
  67. if(!empty($chatGroupInfo) && $chatGroupInfo->member_version == $params['last_mem_ver']) {
  68. switch($params['update_detail']) {
  69. case 'add_member': // 成员入群
  70. if($params['update_detail'] == 'add_member') {
  71. $res = RedisModel::lPush(QrcodeChatGroup::CHECK_CHAT_GROUP_USER_LIMIT_RDS, json_encode($params));
  72. if(!$res) {
  73. Log::logError('ChatGroupService.templateCallBack', [
  74. 'params' => $msgStr,
  75. 'err_msg' => '客户群回调事件入群活码队列处理失败',
  76. ], 'interface');
  77. }
  78. }
  79. # 获取新进群成员信息
  80. $customerList = CustomerDetails::suffix($params['corpid'])
  81. ->select('external_userid', 'name')->where('corpid', $params['corpid'])
  82. ->whereIn('external_userid', $params['mem_change_list'])->get();
  83. $userList = DjUser::select('user_id', 'name')->where('corpid', $params['corpid'])
  84. ->whereIn('user_id', $params['mem_change_list'])
  85. ->get();
  86. # 插入新进群成员信息到ES
  87. $groupData = [];
  88. foreach($params['mem_change_list'] as $item) {
  89. $userInfo = $customerList->where('external_userid', $item)->first();
  90. if(empty($userInfo)) {
  91. $userInfo = $userList->where('user_id', $item)->first();
  92. }
  93. $insertData = [];
  94. $insertData['corpid'] = $params['corpid'];
  95. $insertData['chat_id'] = $params['chat_id'];
  96. $insertData['status'] = 1;
  97. $insertData['user_id'] = $item;
  98. $insertData['type'] = '';
  99. $insertData['join_time'] = date('Y-m-d H:i:s', $params['create_time']);
  100. $insertData['update_time'] = date('Y-m-d H:i:s');
  101. $insertData['join_scene'] = $params['join_scene'];
  102. $insertData['invitor_user_id'] = null;
  103. $insertData['group_nickname'] = $userInfo->name ?? null;
  104. $insertData['name'] = $userInfo->name ?? null;
  105. $insertData['member_name'] = $userInfo->name ?? null;
  106. $insertData['state'] = null;
  107. // 数据格式处理
  108. $groupData['body'][] = [
  109. "index" => [
  110. "_index" => ChatGroupMember::TABLE,
  111. "_id" => $params['corpid'].'@@'.$params['chat_id'].'@@'.$item
  112. ]
  113. ];
  114. $groupData['body'][] = $insertData;
  115. }
  116. if(!empty($groupData)) {
  117. $res = EsModel::bulkDoc($groupData);
  118. Log::logInfo('新成员入群处理:', [
  119. 'groupData' => $groupData,
  120. 'msg' => $msgStr,
  121. 'res' => $res
  122. ], 'ChatGroupCallback');
  123. if (!isset($res['errors']) || ($res['errors'] != false)) {
  124. Log::logError('客户群回调处理过程成员信息入ES失败', [
  125. 'groupData' => $groupData,
  126. 'msg_str' => $msgStr,
  127. 'res' => $res,
  128. ], 'ChatGroupCallback');
  129. EmailQueue::rPush('客户群成员信息入ES异常', '获取客户群信息入ES异常:'.json_encode($res), ['xiaohua.hou@kuxuan-inc.com'], '客户群成员信息入ES异常');
  130. $result = false;
  131. } else {
  132. $result = true;
  133. }
  134. }
  135. break;
  136. case 'del_member': // 成员退群
  137. $result = ChatGroupMember::delMember(
  138. $params['corpid'], $params['chat_id'], $params['mem_change_list'], $params['create_time']
  139. );
  140. break;
  141. case 'change_owner': // 群主变更
  142. case 'change_name': // 群名变更
  143. case 'change_notice':
  144. $result = false;
  145. break;
  146. }
  147. if($result === true) {
  148. ChatGroup::where('corpid', $params['corpid'])->where('chat_id', $params['chat_id'])
  149. ->update(['member_version' => $params['cur_mem_ver']]);
  150. } else {
  151. RedisModel::lPush(ChatGroup::CHAT_GROUP_DETAIL_RDS, json_encode($params));
  152. }
  153. } else {
  154. $result = RedisModel::lPush(ChatGroup::CHAT_GROUP_DETAIL_RDS, json_encode($params));
  155. }
  156. break;
  157. case 'dismiss': // 客户群解散
  158. $result = ChatGroup::where('corpid', $params['corpid'])->where('chat_id', $params['chat_id'])
  159. ->update(['status' => 2, 'updated_at' => date('Y-m-d H:i:s')]);
  160. # 更新对应群的群成员状态
  161. ChatGroupMember::UpdateDismissChatGroupMemberStatus($params['corpid'], $params['chat_id']);
  162. break;
  163. default:
  164. Log::logError('ChatGroupService.templateCallBack', [
  165. 'params' => $msgStr,
  166. 'err_msg' => '事件类型不合法',
  167. ], 'interface');
  168. return false;
  169. }
  170. if(!$result) {
  171. Log::logError('ChatGroupService.templateCallBack', [
  172. 'params' => $msgStr,
  173. 'err_msg' => '客户群回调事件处理失败',
  174. ], 'interface');
  175. return false;
  176. }
  177. return true;
  178. } catch (\Exception $exception){
  179. Log::logError('ChatGroupService.templateCallBack', [
  180. 'params' => $msgStr,
  181. 'line' => $exception->getLine(),
  182. 'message' => $exception->getMessage(),
  183. ], 'interface');
  184. EmailQueue::rPush('客户群变更回调处理异常', json_encode([
  185. 'params' => $msgStr,
  186. 'line' => $exception->getLine(),
  187. 'trace' => $exception->getTraceAsString(),
  188. ], 256), ['xiaohua.hou@kuxuan-inc.com'], []);
  189. return false;
  190. }
  191. }
  192. public static function ownerList($corpid, $userName)
  193. {
  194. $ownerList = ChatGroup::where('corpid', $corpid)->where('status', 1)->pluck('owner')->toArray();
  195. if(empty($ownerList)) {
  196. return ['list' => [], 'count' => 0];
  197. }
  198. // 查询部门列表
  199. $departmentList = DjDepartment::selectRaw('department_id, name as department_name')
  200. ->where('enable', 1)
  201. ->where('corpid', $corpid)
  202. ->get()
  203. ->keyBy('department_id')
  204. ->toArray();
  205. $userList = DjUser::select(['user_id', 'name', 'open_user_id', 'avatar', 'department', 'status', 'is_active'])
  206. ->where('corpid', $corpid)
  207. ->where('enable', 1)
  208. ->where('name', 'like', '%' . $userName . '%')
  209. ->where('status', 1)
  210. ->whereIn('user_id', $ownerList)
  211. ->get()
  212. ->toArray();
  213. $departmentData = [];
  214. $userData = [];
  215. $total = 0;
  216. foreach ($userList as $user) {
  217. $departmentIdList = explode(',', $user['department']);
  218. foreach ($departmentIdList as $departmentId) {
  219. if (!isset($departmentData[$departmentId])) {
  220. $departmentData[$departmentId] = isset($departmentList[$departmentId]) ? $departmentList[$departmentId] : [];
  221. }
  222. $user['department_list'][] = isset($departmentList[$departmentId]['department_name']) ? $departmentList[$departmentId]['department_name'] : '';
  223. $departmentData[$departmentId]['user_list'][] = $user;
  224. if (!in_array($user['user_id'], $userData)) {
  225. $userData[] = $user['user_id'];
  226. $total += 1;
  227. }
  228. }
  229. }
  230. foreach($departmentData as $k=>$departmentInfo) {
  231. if(empty($departmentInfo['user_list'])) {
  232. unset($departmentData[$k]);
  233. }
  234. }
  235. return ['list' => array_values($departmentData), 'count' => $total];
  236. }
  237. /**
  238. * 获取账号下各企微的群主列表
  239. * */
  240. public static function ownerListOfCompany($userName, $sysGroupId)
  241. {
  242. try {
  243. # 获取公司账号下绑定的企微
  244. $corpIds = AdminManageCorp::where('sys_user_id', $sysGroupId)->where('is_delete', 0)->pluck('corpid');
  245. $accountList = AuthorizeCorp::select('corpid', 'corp_name')->where('enable', 1)
  246. ->whereIn('id', $corpIds)->get();
  247. if(empty($accountList)) return [];
  248. $corpidList = $accountList->pluck('corpid');
  249. $ownerList = ChatGroup::select('corpid', 'owner')->whereIn('corpid', $corpidList)->where('status', 1)
  250. ->groupBy(['corpid', 'owner'])
  251. ->get();
  252. $data = [];
  253. foreach ($accountList as $account) {
  254. $corpid = $account->corpid;
  255. $corpName = $account->corp_name;
  256. # 整理数据
  257. $userIdList = $ownerList->where('corpid', $corpid)->pluck('owner');
  258. $userList = DjUser::select(['user_id', 'name', 'avatar', 'status', 'is_active'])
  259. ->where('corpid', $corpid)->where('enable', 1)->where('status', 1)
  260. ->whereIn('user_id', $userIdList)
  261. ->get();
  262. $data[] = [
  263. 'corpid' => $corpid,
  264. 'corp_name' => $corpName,
  265. 'user_list' => $userList
  266. ];
  267. }
  268. } catch (\Exception $e) {
  269. Log::logError('获取账号下各企微的群主列表出现异常', [
  270. 'line' => $e->getLine(),
  271. 'msg' => $e->getTraceAsString()
  272. ], 'ownerListOfCompany');
  273. return [];
  274. }
  275. return $data;
  276. }
  277. public static function ownerIndex($corpid, $userName)
  278. {
  279. $ownerList = ChatGroup::where('corpid', $corpid)->where('status', 1)->pluck('owner')->toArray();
  280. if(empty($ownerList)) {
  281. return [];
  282. }
  283. $userList = DjUser::select(['user_id', 'name', 'avatar'])->where('corpid', $corpid)
  284. ->where('enable', 1)->where('name', 'like', '%' . $userName . '%')
  285. ->where('status', 1)->whereIn('user_id', $ownerList)
  286. ->get()->toArray();
  287. return $userList;
  288. }
  289. /*
  290. * 检索框群列表
  291. * */
  292. public static function chatGroupList($corpid, $keyword, $startTime, $endTime, $owner, $isActive)
  293. {
  294. $groupList = ChatGroup::select(['chat_id', 'name', 'notice', 'owner', 'create_time'])
  295. ->where('corpid', $corpid)
  296. ->where(function($query) use ($keyword, $owner, $startTime, $endTime) {
  297. if($keyword) $query->where('name', 'like', '%'.$keyword.'%');
  298. if($owner) $query->where('owner', $owner);
  299. if($startTime) $query->where('create_time', '>=', $startTime);
  300. if($endTime) $query->where('create_time', '<=', $endTime);
  301. })
  302. ->where('enable', 1)
  303. ->where('status', 1)
  304. ->get();
  305. # 提取群主
  306. $ownerIdList = $groupList->isNotEmpty() ? array_column($groupList->toArray(), 'owner') : [];
  307. $ownerData = null;
  308. if(!empty($ownerIdList)) {
  309. $ownerIdList = array_unique($ownerIdList);
  310. $ownerData = DjUser::select(['user_id', 'name'])
  311. ->where('corpid', $corpid)
  312. ->whereIn('user_id', $ownerIdList)
  313. ->where('status', 1)
  314. ->get();
  315. }
  316. foreach ($groupList as $key => $group) {
  317. $owner = $group->owner;
  318. $ownerInfo = !empty($ownerData) ? $ownerData->where('user_id', $owner)->first(): '';
  319. $group->owner_name = isset($ownerInfo->name) ? $ownerInfo->name : '';
  320. if($isActive && empty($group->owner_name)) {
  321. unset($groupList[$key]);
  322. }
  323. }
  324. return array_values($groupList->toArray());
  325. }
  326. /**
  327. * 配置邀请入群规则
  328. * */
  329. public static function setInviteRule($ruleId, $params)
  330. {
  331. try {
  332. # 详细配置信息入dj_invite_chat_group_detail表
  333. $configDetail = json_decode($params['invite_config'], true);
  334. if(empty($configDetail)) {return 4823;}
  335. $chatIdUsed = array_column($configDetail, 'chat_id');
  336. # 判断选定的客服或者群主是否已经绑定了设备信息
  337. $error = self::checkUserBindDevice($params, $chatIdUsed);
  338. if($error) return $error;
  339. if($ruleId) {
  340. $ruleInfo = InviteChatGroupRule::getInfo($ruleId);
  341. if(empty($ruleInfo)) {return 4821;}
  342. # 已经开启客户续拉配置的规则不允许再次编辑
  343. if(1 == $ruleInfo->continuously_attract_groups) {return 4818;}
  344. }
  345. # 选择了持续拉取客户入群(首次设置)
  346. if(1 == $params['continuously_attract_groups']) {
  347. if(empty($params['upper_limit'])) {return 4819;} // 单次创建群聊上限必填
  348. if($params['invite_type'] == 1) {return 4817;}// 仅支持定时邀请
  349. }
  350. # 选择了客户补拉,仅执行当前客服群聊以及定时邀请
  351. if(1 == $params['supplementary_invite']) {
  352. if($params['invite_type'] == 1) {return 4817;}// 仅支持定时邀请
  353. // if($params['owner_type'] == 2) {return 4816;}// 仅支持当前客服群聊
  354. }
  355. DB::beginTransaction();
  356. # 计算下次邀请入群的时间点
  357. $datetimeNow = date('Y-m-d H:i:s');
  358. if($params['invite_type'] == 2) { // 定时邀请
  359. $params['next_invite_time'] = CircleMassMsgService::getNextSendTime(1, $params['invite_time'], 0, $datetimeNow);
  360. if(1 == $params['supplementary_invite']) {
  361. $params['next_supplementary_invite_time'] = CircleMassMsgService::getNextSupplementaryInviteTime(
  362. 1, $params['supplementary_invite_time'], $params['supplementary_invite_cycle'], $datetimeNow);
  363. }
  364. } else {
  365. $params['next_invite_time'] = $datetimeNow;
  366. $params['next_supplementary_invite_time'] = $datetimeNow;
  367. }
  368. # 基础数据入dj_invite_chat_group_rule表
  369. $errno = InviteChatGroupRule::editRule($ruleId, $params);
  370. if($errno) {
  371. DB::rollback();
  372. return $errno;
  373. }
  374. # 禁用删除掉的配置
  375. InviteChatGroupDetail::whereNotIn('chat_id', $chatIdUsed)->where('rule_id', $ruleId)->update(['enable' => 0]);
  376. foreach ($configDetail as $index=>$config) {
  377. $chatId = $config['chat_id'] ?? null;
  378. if(!$chatId) continue;
  379. $status = $config['status'] ?? 1;
  380. # 数据处理
  381. InviteChatGroupDetail::updateOrCreate([
  382. 'chat_id' => $chatId,
  383. 'rule_id' => $ruleId,
  384. 'corpid' => $params['corpid'],
  385. ], [
  386. 'user_limit' => $config['user_limit'],
  387. 'status' => $status,
  388. 'sort' => $index,
  389. 'enable' => 1
  390. ]);
  391. }
  392. DB::commit();
  393. } catch (\Exception $e) {
  394. DB::rollback();
  395. EmailQueue::rPush('邀请入群规则配置过程发生异常', $e->getTraceAsString(), ['xiaohua.hou@kuxuan-inc.com'], '猎羽');
  396. Log::logError('邀请入群规则配置失败', [
  397. 'rule_id' => $ruleId,
  398. 'params' => $params,
  399. 'line' => $e->getLine(),
  400. 'msg' => $e->getMessage()
  401. ], 'SetInviteRule');
  402. return 4824;
  403. }
  404. return 0;
  405. }
  406. public static function checkSingleUserChatGroup($params, $chatIdList) {
  407. if(1 == $params['is_for_all']) {
  408. return 0;
  409. }
  410. $usersArr = explode(',', $params['users']);
  411. if(count($usersArr) > 1) {
  412. return 0;
  413. }
  414. # 查询选中的群聊信息
  415. $pageSize = count($chatIdList);
  416. list($chatGroupInfoList, $count) = ChatGroup::getGroupListByCorp([$params['corpid']], null, $chatIdList
  417. , null, null, null, 1, $pageSize);
  418. # 提取群主id
  419. $ownerList = array_unique(array_column($chatGroupInfoList->toArray(), 'owner'));
  420. # 判断群主id与选择客服的关系
  421. if(1 == $params['owner_type']) {
  422. if(count($ownerList) > 1 || count($ownerList) < 1 || $params['users'] != $ownerList[0]) {
  423. return 4828;
  424. }
  425. } else if(2 == $params['owner_type']) {
  426. if(in_array($params['users'], $ownerList)) {
  427. return 4829;
  428. }
  429. }
  430. return 0;
  431. }
  432. public static function checkUserBindDevice($params, $chatIdList) {
  433. $usersArr = explode(',', $params['users']);
  434. if(isset($params['owner_type']) && 2 == $params['owner_type']) {
  435. $pageSize = count($chatIdList);
  436. list($chatGroupInfoList, $count) = ChatGroup::getGroupListByCorp([$params['corpid']], null, $chatIdList
  437. , null, null, null, 1, $pageSize);
  438. # 提取群主id
  439. if($chatGroupInfoList->isNotEmpty()) {
  440. $ownerList = array_unique(array_column($chatGroupInfoList->toArray(), 'owner'));
  441. $usersArr = array_unique(array_merge($usersArr, $ownerList));
  442. }
  443. }
  444. $userCount = count($usersArr);
  445. $deviceInfo = AndroidBindCorp::getDeviceIdListByUser($params['corpid'], $usersArr);
  446. if($deviceInfo->isNotEmpty()) {
  447. $deviceUserCount = count(array_unique(array_column($deviceInfo->toArray(), 'user_id')));
  448. } else {
  449. $deviceUserCount = 0;
  450. }
  451. if($deviceUserCount < $userCount) {
  452. return 4820;
  453. }
  454. return 0;
  455. }
  456. /**
  457. * 获取邀请入群规则列表
  458. * */
  459. public static function getInviteRuleList($corpid, $userId, $sysGroupId, $keyword, $status, $page, $pageSize)
  460. {
  461. list($list, $count) = InviteChatGroupRule::inviteRuleList($corpid, $userId, $sysGroupId, $keyword, $status, $page, $pageSize);
  462. if(!$count) return [$list, $count];
  463. # 获取操作人员的信息
  464. $adminIdList = $list->pluck('admin_id');
  465. $adminList = Users::select('id', 'name')->whereIn('id', $adminIdList)->get();
  466. foreach ($list as $item) {
  467. # 操作人员信息处理
  468. $userInfo = $adminList->where('id', $item->admin_id)->first();
  469. $item->user_name = $userInfo->name ?? null;
  470. }
  471. return [$list, $count];
  472. }
  473. /**
  474. * 邀请入群规则详情
  475. * */
  476. public static function inviteRuleDetail($ruleId, $sysGroupId)
  477. {
  478. $ruleInfo = InviteChatGroupRule::selectRaw("id as rule_id, title, is_for_all, users, join_type, status"
  479. .", corpid, customer_filter, filter_type, add_time_later, add_time_st, add_time_et, invite_type, invite_time"
  480. .", owner_type, announcement, gender, tag_screen_type, tag_list, pay_status, pay_num_min, pay_num_max, upper_limit"
  481. .", continuously_attract_groups, supplementary_invite_cycle, supplementary_invite, supplementary_invite_time,"
  482. ."last_supplementary_invite_time, next_supplementary_invite_time")
  483. ->where('enable', 1)->where('sys_group_id', $sysGroupId)
  484. ->where('id', $ruleId)->first();
  485. if(empty($ruleInfo)) return [];
  486. if(!$ruleInfo->is_for_all) $ruleInfo->users = explode(',', $ruleInfo->users);
  487. # 获取配置详情
  488. $ruleDetail = InviteChatGroupDetail::select('chat_id', 'sort', 'user_limit', 'status')
  489. ->where('rule_id', $ruleId)->where('enable', 1)
  490. ->orderBy('sort')->get();
  491. # 获取群信息
  492. $chatIdList = $ruleDetail->pluck('chat_id');
  493. $chatList = ChatGroup::select('chat_id', 'name')->whereIn('chat_id', $chatIdList)->where('corpid', $ruleInfo->corpid)->get();
  494. foreach ($ruleDetail as $item) {
  495. # 获取群名称
  496. $chatGroupInfo = $chatList->where('chat_id', $item->chat_id)->first();
  497. $item->group_name = $chatGroupInfo->name ?? '';
  498. }
  499. $ruleInfo->invite_config = $ruleDetail;
  500. return $ruleInfo;
  501. }
  502. /**
  503. * 删除邀请入群配置
  504. * */
  505. public static function inviteRuleDel($ruleId, $sysGroupId, $adminId)
  506. {
  507. try {
  508. DB::beginTransaction();
  509. $isExist = InviteChatGroupRule::where('enable', 1)->where('sys_group_id', $sysGroupId)
  510. ->where('id', $ruleId)->exists();
  511. if(!$isExist) {
  512. DB::rollback();
  513. return 4821;
  514. }
  515. # 执行删除
  516. $result = InviteChatGroupRule::where('id', $ruleId)->where('enable', 1)->where('sys_group_id', $sysGroupId)
  517. ->update(['enable' => 0, 'admin_id' => $adminId]);
  518. if(!$result) {
  519. DB::rollback();
  520. return 4826;
  521. }
  522. InviteChatGroupDetail::where('rule_id', $ruleId)->where('enable', 1)->update(['enable' => 0]);
  523. DB::commit();
  524. } catch (\Exception $e) {
  525. DB::rollback();
  526. EmailQueue::rPush('删除邀请入群规则过程发生异常', $e->getTraceAsString(), ['xiaohua.hou@kuxuan-inc.com'], '猎羽');
  527. Log::logError('删除邀请入群规则异常', [
  528. 'rule_id' => $ruleId,
  529. 'line' => $e->getLine(),
  530. 'msg' => $e->getMessage()
  531. ], 'SetInviteRule');
  532. return 4825;
  533. }
  534. return 0;
  535. }
  536. /**
  537. * 修改邀请入群规则状态
  538. * */
  539. public static function updateRuleStatus($ruleId, $adminId, $status, $sysGroupId)
  540. {
  541. # 验证规则是否存在
  542. $inviteConfig = InviteChatGroupRule::where('enable', 1)->where('sys_group_id', $sysGroupId)
  543. ->where('id', $ruleId)->first();
  544. if(empty($inviteConfig)) return 4821;
  545. # 变更规则状态和下次邀请入群时间
  546. $datetimeNow = date('Y-m-d H:i:s');
  547. $nextInviteTime = $datetimeNow;
  548. if($inviteConfig->invite_type == 2) {
  549. $nextInviteTime = CircleMassMsgService::getNextSendTime(1, $inviteConfig->invite_time, 0, $datetimeNow);
  550. }
  551. $result = InviteChatGroupRule::where('sys_group_id', $sysGroupId)->where('id', $ruleId)
  552. ->update(['status' => $status, 'admin_id' => $adminId, 'next_invite_time' => $nextInviteTime]);
  553. if(!$result) return 4827;
  554. return 0;
  555. }
  556. public static function resetSupplementaryInviteTime($ruleId, $adminId, $sysGroupId) {
  557. # 验证规则是否存在
  558. $inviteConfig = InviteChatGroupRule::where('enable', 1)->where('sys_group_id', $sysGroupId)
  559. ->where('id', $ruleId)->first();
  560. if(empty($inviteConfig)) return 4821;# 邀请入群配置不存在
  561. if(1 != $inviteConfig->supplementary_invite) {
  562. return 4850;# 客户补拉未开启
  563. }
  564. # 计算下次邀请入群的时间点
  565. $datetimeNow = date('Y-m-d H:i:s');
  566. $nextSupplementaryInviteTime = CircleMassMsgService::getNextSupplementaryInviteTime(
  567. 1, $inviteConfig->supplementary_invite_time, $inviteConfig->supplementary_invite_cycle, $datetimeNow);
  568. $result = InviteChatGroupRule::where('sys_group_id', $sysGroupId)->where('id', $ruleId)
  569. ->update(['last_supplementary_invite_time' => null, 'next_supplementary_invite_time' => $nextSupplementaryInviteTime
  570. , 'admin_id' => $adminId]);
  571. if(!$result) return 4851;
  572. return 0;
  573. }
  574. /**
  575. * 客户群数据--按客户群统计
  576. * */
  577. public static function chatGroupStatistic(
  578. $sysGroupId, $owner, $ownerList, $keyword, $corpid, $createTimeSt, $createTimeEt, $minMember, $maxMember, $page, $pageSize
  579. )
  580. {
  581. $corpIds = AdminManageCorp::where('sys_user_id', $sysGroupId)
  582. ->where('is_delete', 0)
  583. ->pluck('corpid');
  584. $corpList = AuthorizeCorp::select('corpid', 'corp_name')->whereIn('id', $corpIds)
  585. ->where(function($query) use($corpid) {
  586. if($corpid) $query->where('corpid', $corpid);
  587. })
  588. ->where('enable', 1)
  589. ->get();
  590. $corpidList = $corpList->pluck('corpid');
  591. if(empty($corpidList)) return [[], 0];
  592. # 根据多企微客服筛选获取对应的chat_id集合
  593. if(!is_array($ownerList)) {
  594. $ownerList = json_decode($ownerList, true);
  595. }
  596. $chatIdList = [];
  597. if(!empty($ownerList)) {
  598. foreach ($ownerList as $ownerInfo) {
  599. $corpid = $ownerInfo['corpid'] ?? null;
  600. $senderList = $ownerInfo['user_list'] ?? null;
  601. $chatIds = ChatGroup::where('corpid', $corpid)->whereIn('owner', $senderList)->pluck('chat_id')->toArray();
  602. $chatIdList = array_merge($chatIdList, $chatIds);
  603. }
  604. }
  605. # 根据筛选条件搜索群聊
  606. if($keyword || $owner) {
  607. $chatIdList = ChatGroup::select('chat_id')->where('enable', 1)->whereIn('corpid', $corpList)
  608. ->where(function($query) use($keyword) {
  609. if($keyword)
  610. $query->where('name', 'like', '%'.$keyword.'%');
  611. })->where(function($query) use($chatIdList) {
  612. if(!empty($chatIdList))
  613. $query->whereIn('chat_id', $chatIdList);
  614. })->where(function($query) use($owner) {
  615. if($owner)
  616. $query->where('owner', $owner);
  617. })->pluck('chat_id')->toArray();
  618. }
  619. # 统计客户群数据
  620. list($groupList, $count) = ChatGroupMember::chatGroupMemberDataList(
  621. $chatIdList, $corpidList, $createTimeSt, $createTimeEt, $minMember, $maxMember, $page, $pageSize
  622. );
  623. if(empty($groupList)) return [[], 0];
  624. $chatIds = array_column($groupList, 'chat_id');
  625. $chatGroupData = ChatGroup::getChatGroupInfo($chatIds);
  626. # 提取群主
  627. $ownerIdList = $chatGroupData->pluck('owner')->unique();
  628. # 获取群主信息
  629. $ownerList = DjUser::select('user_id', 'name')->whereIn('user_id', $ownerIdList)->get();
  630. foreach ($groupList as &$group) {
  631. $chatInfo = $chatGroupData->where('chat_id', $group['chat_id'])->first();
  632. if(!isset($chatInfo->owner)) {
  633. continue;
  634. }
  635. # 处理群主信息
  636. $ownerInfo = $ownerList->where('user_id', $chatInfo->owner)->first();
  637. $group['owner_name'] = $ownerInfo->name ?? '';
  638. # 处理群所属主体信息
  639. $corpInfo = $corpList->where('corpid', $chatInfo->corpid)->first();
  640. $group['corp_name'] = $corpInfo->corp_name ?? '';
  641. # 获取群累计人数和累计退群人数
  642. $group['member_total'] = $group['member_count'] + $group['member_quit_count'];
  643. $group['name'] = $chatInfo->name ?? '';
  644. $group['create_time'] = $chatInfo->create_time ?? '';
  645. $group['status'] = $chatInfo->status ?? '';
  646. }
  647. return [$groupList, $count];
  648. }
  649. /**
  650. * 获取系统组的群数据汇总
  651. * */
  652. public static function chatGroupCondition(
  653. $sysGroupId, $owner, $ownerList, $corpid, $createTimeSt, $createTimeEt, $minMember, $maxMember
  654. )
  655. {
  656. $corpIds = AdminManageCorp::where('sys_user_id', $sysGroupId)
  657. ->where('is_delete', 0)
  658. ->pluck('corpid');
  659. $corpList = AuthorizeCorp::select('corpid', 'corp_name')->whereIn('id', $corpIds)
  660. ->where(function($query) use($corpid) {
  661. if($corpid) $query->where('corpid', $corpid);
  662. })
  663. ->where('enable', 1)
  664. ->get();
  665. $corpidList = $corpList->pluck('corpid');
  666. if(empty($corpidList)) return [[], 0];
  667. $chatIdList = [];
  668. if(!empty($ownerList)) {
  669. foreach ($ownerList as $ownerInfo) {
  670. $corpid = $ownerInfo['corpid'] ?? null;
  671. $senderList = $ownerInfo['user_list'] ?? null;
  672. $chatIds = ChatGroup::where('corpid', $corpid)->whereIn('owner', $senderList)->pluck('chat_id')->toArray();
  673. $chatIdList = array_merge($chatIdList, $chatIds);
  674. }
  675. }
  676. # 当有群人数条件筛选时,筛选符合条件的客户群id
  677. if(is_numeric($minMember) && is_numeric($maxMember)) {
  678. $chatIdList = ChatGroupMember::getChatGroupIdList(
  679. $chatIdList, $corpidList, $createTimeSt, $createTimeEt, $minMember, $maxMember
  680. );
  681. }
  682. # 群聊总数
  683. $queryModel = ChatGroup::whereIn('corpid', $corpidList)
  684. ->where(function($query) use($owner) {
  685. if($owner) $query->where('owner', $owner);
  686. })
  687. ->where(function($query) use($chatIdList, $createTimeSt, $createTimeEt) {
  688. if($chatIdList) $query->whereIn('chat_id', $chatIdList);
  689. })
  690. ->where('enable', 1);
  691. $groupCount = $queryModel->count();
  692. # 今日新增群聊数
  693. $groupTodayCount = $queryModel->where('create_time', '>=', date('Y-m-d') . ' 00:00:00')->count();
  694. # 汇总群人数数据
  695. list($joinTodayCount, $memberCount, $memberQuitCount) = ChatGroupMember::getChatGroupCondition(
  696. $corpidList, $chatIdList, $createTimeSt, $createTimeEt, $minMember, $maxMember
  697. );
  698. # 整理数据
  699. $data = [
  700. 'group_count' => $groupCount, // 群聊总数
  701. 'member_total' => $memberQuitCount + $memberCount, // 累计群人数
  702. 'member_count' => $memberCount, // 留存群人数
  703. 'member_quit_count' => $memberQuitCount, // 流失群人数
  704. 'today_join_count' => $joinTodayCount, // 今日新增群人数
  705. 'today_create_count' => $groupTodayCount // 今日新增群聊数
  706. ];
  707. return $data;
  708. }
  709. public static function syncCorpChatGroup($corpid) {
  710. // 判断键是否存在
  711. $redisKey = 'Playlet::getCorChatGroupList-'.$corpid;
  712. $value = RedisModel::get($redisKey);
  713. if(!empty($value)) {
  714. Log::logInfo('getCorChatGroupList 操作太快 request:'.json_encode(['corpid' => $corpid], JSON_UNESCAPED_UNICODE), [], 'interface');
  715. return ['操作太快', 2007];
  716. // return [['error' => '操作太快'], 2007];
  717. }
  718. Log::logInfo('start', [time()], 'syncCorpChatGroup');
  719. try{
  720. # owner_filter参数处理
  721. // $userIdList = DjUser::select(['user_id'])->where('corpid', $corpid)->where('enable', 1)
  722. // ->where('status', 1)->orderBy('id')
  723. // ->distinct()->pluck('user_id')->toArray();
  724. $userIdList = DjUser::getActiveUserListById($corpid);
  725. if(empty($userIdList)) {
  726. return ['待同步成员列表为空', 2014];
  727. }
  728. # 获取队列长度,超过6000报警
  729. $length = RedisModel::lLen(ChatGroup::CHAT_GROUP_DETAIL_RDS);
  730. if($length > ChatGroup::CHAT_GROUP_DETAIL_RDS_LIMIT) {
  731. EmailQueue::rPush('同步企微客户群队列长度超过阈值', json_encode([
  732. 'redis_key' => ChatGroup::CHAT_GROUP_DETAIL_RDS, 'length' => $length
  733. ]), ['song.shen@kuxuan-inc.com'], '猎羽');
  734. }
  735. $userCount = count($userIdList);
  736. # 需要截取的段数
  737. $spliceCount = ceil($userCount / 100);
  738. for ($i=1; $i<=$spliceCount; $i++) {
  739. $start = ($i - 1) * 100;
  740. $ownerFilter = array_slice($userIdList, $start, 100);
  741. # 循环获取企微下的客户群列表
  742. list($res, $code) = self::getCorpChatGroupList($ownerFilter, $corpid);
  743. if(0 != $code) return [$res, $code];
  744. }
  745. } catch (\Exception $exception){
  746. Log::logError('更新企微客户群列表异常', [
  747. 'corpid' => $corpid,
  748. 'file' => $exception->getFile(),
  749. 'line' => $exception->getLine(),
  750. 'msg' => $exception->getMessage(),
  751. 'trace'=> $exception->getTraceAsString()
  752. ], 'syncCorpChatGroup');
  753. return ['同步失败,请联系管理员', 500];
  754. }
  755. RedisModel::set($redisKey, time());
  756. RedisModel::expire($redisKey, 600);
  757. Log::logInfo('end', [time()], 'syncCorpChatGroup');
  758. return ['同步中', 0];
  759. }
  760. public static function getCorpChatGroupList($ownerFilter, $corpid) {
  761. $flag = true;
  762. $nextCursor = null;
  763. while($flag) {
  764. # 获取群基本信息
  765. $responseData = QyCommon::getGroupChatList($corpid, $ownerFilter, 1000, $nextCursor);
  766. if(isset($responseData['errcode']) && $responseData['errcode']) {
  767. if(!in_array($responseData['errcode'], [701008])) {
  768. EmailQueue::rPush('群基本信息获取失败', json_encode($responseData, JSON_UNESCAPED_UNICODE)
  769. , ['song.shen@kuxuan-inc.com'], '群基本信息获取失败');
  770. }
  771. Log::logError('群基本信息获取失败', [
  772. 'corpid' => $corpid,
  773. 'ownerFilter' => $ownerFilter,
  774. 'cursor' => $nextCursor,
  775. 'data' => $responseData,
  776. ], 'GroupBasicInfo');
  777. return ['群基本信息获取失败', 2015];
  778. }
  779. $chatGroupList = $responseData['group_chat_list'] ?? [];
  780. # 翻页查询外部联系人所有的关联员工
  781. if(!empty($responseData['next_cursor'])) {
  782. $nextCursor = $responseData['next_cursor'];
  783. } else {
  784. $flag = false;
  785. }
  786. foreach ($chatGroupList as $chatGroupInfo) {
  787. list($res, $code) = self::getCorpChatGroupDetail($corpid, $ownerFilter, $chatGroupInfo);
  788. if(0 != $code) return [$res, $code];
  789. }
  790. }
  791. }
  792. public static function getCorpChatGroupDetail($corpid, $ownerFilter, $chatGroupInfo, $retry = 0) {
  793. # 将chat_id和status置入队列供客户群详情脚本消费
  794. $chatId = $chatGroupInfo['chat_id'] ?? '';
  795. $status = $chatGroupInfo['status'] ?? null;
  796. $result = RedisModel::lPush(ChatGroup::CHAT_GROUP_DETAIL_RDS, json_encode([
  797. 'corpid' => $corpid,
  798. 'chat_id' => $chatId,
  799. 'status' => $status
  800. ]));
  801. if(!$result) {
  802. if($retry >= 3) {
  803. Log::logError('群基本信息解析入队列失败', [
  804. 'corpid' => $corpid,
  805. 'ownerFilter' => $ownerFilter,
  806. 'data' => $chatGroupInfo,
  807. ], 'GroupBasicInfo');
  808. return ['群基本信息解析入队列失败', 2016];
  809. } else {
  810. $retry++;
  811. return self::getCorpChatGroupDetail($corpid, $ownerFilter, $chatGroupInfo, $retry);
  812. }
  813. }
  814. return ['处理成功', 0];
  815. }
  816. public static function receiveCreateChatGroupData($deviceId, $corpid, $userName, $groupList) {
  817. # 验证企微id,客服名称以及客户群聊id的合法性
  818. $corpInfo = AuthorizeCorp::getCorpInfo($corpid);
  819. if(empty($corpInfo)) {
  820. Log::logError('接收创建群聊任务-企微信息查询异常', [
  821. 'corpid' => $corpid,
  822. 'device_id' => $deviceId,
  823. 'corp_info' => $corpInfo
  824. ], 'receiveCreateChatGroupData');
  825. return ['企微id不合法', 1102];
  826. }
  827. $userInfoList = DjUser::getUserBySearch(['corpid' => $corpid, 'user_name' => $userName]);
  828. if($userInfoList->isEmpty()) {
  829. Log::logError('接收创建群聊任务异常-客服信息查询异常', [
  830. 'corpid' => $corpid,
  831. 'device_id' => $deviceId,
  832. 'user_name' => $userName,
  833. 'user_info' => $userInfoList
  834. ], 'receiveCreateChatGroupData');
  835. }
  836. # 根据企微以及群主查询对应的设备信息
  837. $dataList = [];
  838. $groupList = json_decode($groupList, 1);
  839. $ownerIdList = array_unique(array_column($groupList, 'owner'));
  840. $deviceInfoList = AndroidBindCorp::getDeviceIdListByUser($corpid, $ownerIdList);
  841. # 根据群聊id查询对应的群主,并按照群主对群聊进行分组处理
  842. foreach($groupList as $groupInfo) {
  843. $deviceInfo = $deviceInfoList->where('corpid', $corpid)->where('user_id', $groupInfo['owner'])
  844. ->first();
  845. $deviceId = $deviceInfo->device_id ?? null;
  846. if(empty($deviceId)) {
  847. Log::logError('接收创建群聊任务-群聊对应群主设备信息查询异常', [
  848. 'corpid' => $corpid,
  849. 'device_id' => $deviceId,
  850. 'group_list' => $groupList,
  851. 'owner' => $groupInfo['owner'],
  852. 'device_info_list' => $deviceInfoList,
  853. 'device_info' => $deviceInfo
  854. ], 'receiveCreateChatGroupData');
  855. continue;
  856. }
  857. $dataList[$deviceId][] = [
  858. 'corpid' => $corpid,
  859. 'owner' => $groupInfo['owner'],
  860. 'groupName' => $groupInfo['groupName'],
  861. 'manager' => $userName,
  862. 'announcement' => $groupInfo['announcement'] ?? '',
  863. ];
  864. }
  865. # 将待创建的群聊id,群聊名称以及管理员信息保存入待执行队列
  866. foreach($dataList as $deviceId => $data) {
  867. $res = RedisModel::lPush(self::CREATE_GROUP_WAIT_RDS.'_'.$deviceId, json_encode([
  868. 'companyName' => $corpInfo->corp_name,
  869. 'groupBeans' => $data,
  870. 'request_time'=> time(),
  871. ],256));
  872. if(!$res) {
  873. Log::logError('接收创建群聊任务-创建群任务入缓存失败', [
  874. 'corpid' => $corpid,
  875. 'device_id' => $deviceId,
  876. 'group_list' => $groupList,
  877. 'redis_key' => self::CREATE_GROUP_WAIT_RDS.'_'.$deviceId,
  878. 'redis_value' => json_encode([
  879. 'companyName' => $corpInfo->corp_name,
  880. 'groupBeans' => $data
  881. ],256)
  882. ], 'receiveCreateChatGroupData');
  883. return ['创建群任务入缓存失败', 500];
  884. }
  885. }
  886. return ['', 0];
  887. }
  888. public static function getCreateGroupTask($deviceId) {
  889. $response = RedisModel::rPop(self::CREATE_GROUP_WAIT_RDS.'_'.$deviceId);
  890. if(!empty($response)) {
  891. $responseData = json_decode($response, 1);
  892. $requestTime = $responseData['request_time'] ?? time();
  893. if(time() - $requestTime >= 43200) { // 超过12个小时的任务不再下发
  894. return self::getCreateGroupTask($deviceId);
  895. }
  896. return $responseData;
  897. } else {
  898. return [
  899. 'companyName' => '',
  900. 'groupBeans' => []
  901. ];
  902. }
  903. }
  904. public static function setWelcomeTemplate($params, &$error) {
  905. $attachmentsArr = !is_array($params['attachments']) ? json_decode($params['attachments'], 1) : $params['attachments'];
  906. # 素材内容验证
  907. $verifyRes = ChatGroupMassMsgService::welcomeTemplateAttachmentVerify($attachmentsArr);
  908. if($verifyRes) {
  909. Log::logError('添加客户入群欢迎语素材接口数据格式不合法', [
  910. 'corpid' => $params['corpid'],
  911. 'text' => $params['content'],
  912. 'attachments' => $attachmentsArr,
  913. 'errcode' => $verifyRes
  914. ], 'setWelcomeTemplateTrace');
  915. $error = $verifyRes; return ;
  916. }
  917. # 素材ID替换
  918. $newAttachments = MaterialService::chatGroupWelcomeTemplateMediaIdReplace($attachmentsArr, $params['corpid'], 'setWelcomeTemplateTrace');
  919. # 处理包含链接,H5推广链接的附件信息
  920. $newAttachments = MaterialService::promoteAttachments($params['corpid'], $newAttachments, 'setWelcomeTemplate');
  921. if(!empty($params['template_id'])) {
  922. $templateId = $params['template_id'];
  923. # 请求企微创建素材接口
  924. $responseData = QyCommon::editChatGroupWelcomeTemplate($params['corpid'], $templateId, $params['content'], $newAttachments);
  925. if(isset($responseData['errcode']) && $responseData['errcode']) {
  926. $errMsg = $responseData['errmsg'] ?? $responseData['errcode'];
  927. EmailQueue::rPush('编辑客户入群欢迎语素材接口返回错误码', $errMsg, ['song.shen@kuxuan-inc.com'], '猎羽');
  928. Log::logError('编辑客户入群欢迎语素材接口返回错误码', [
  929. 'corpid' => $params['corpid'],
  930. 'template_id' => $templateId,
  931. 'text' => $params['content'],
  932. 'attachments' => $newAttachments,
  933. 'response' => $responseData
  934. ], 'setWelcomeTemplateTrace');
  935. $error = 5240; return ;
  936. }
  937. } else {
  938. # 请求企微创建素材接口
  939. $responseData = QyCommon::addChatGroupWelcomeTemplate($params['corpid'], $params['content'], $newAttachments);
  940. if(isset($responseData['errcode']) && $responseData['errcode']) {
  941. $errMsg = $responseData['errmsg'] ?? $responseData['errcode'];
  942. EmailQueue::rPush('添加客户入群欢迎语素材接口返回错误码', $errMsg, ['song.shen@kuxuan-inc.com'], '猎羽');
  943. Log::logError('添加客户入群欢迎语素材接口返回错误码', [
  944. 'corpid' => $params['corpid'],
  945. 'text' => $params['content'],
  946. 'attachments' => $newAttachments,
  947. 'response' => $responseData
  948. ], 'setWelcomeTemplateTrace');
  949. $error = 5240; return ;
  950. }
  951. $templateId = $responseData['template_id'] ?? '';
  952. }
  953. # 将数据保存
  954. $res = ChatGroupWelcomeTemplate::saveData($params['sys_group_id'], $params['admin_id'], $params['corpid']
  955. , $params['name'], $params['content'], $attachmentsArr, $templateId);
  956. if(!$res) {
  957. $error = 500; return ;
  958. }
  959. }
  960. public static function welcomeTemplateList($corpid, $sysGroupId, $keyword, $creatorId, $page, $pageSize) {
  961. list($list, $count) = ChatGroupWelcomeTemplate::getList($corpid, $sysGroupId, $keyword, $creatorId, $page, $pageSize);
  962. # 获取创建人信息
  963. $adminIdList = array_unique(array_column($list->toArray(),'admin_id'));
  964. $adminData = Users::query()->whereIn('id', $adminIdList)->select(['id','name'])->get();
  965. foreach($list as $info) {
  966. $adminInfo = $adminData->where('id', $info->admin_id)->first();
  967. $info->creator = isset($adminInfo->name) ? $adminInfo->name : '';
  968. # 文本内容中客户昵称信息替换
  969. $info->content = str_replace('%NICKNAME%', '「客户昵称」', $info->content);
  970. # 通过素材ID获取素材链接
  971. $attachments = json_decode($info->attachments, 1);
  972. if(isset($attachments['image']['media_id'])) {
  973. $materialInfo = Material::select(['oss_url'])
  974. ->where('id', $attachments['image']['media_id'])->where('type', 1)->first();
  975. $attachments['image']['media_url'] = $materialInfo->oss_url ?? '';
  976. }
  977. if(isset($attachments['miniprogram']['pic_media_id'])) {
  978. $materialInfo = Material::select(['oss_url'])
  979. ->where('id', $attachments['miniprogram']['pic_media_id'])->where('type', 1)->first();
  980. $attachments['miniprogram']['pic_media_url'] = $materialInfo->oss_url ?? '';
  981. }
  982. if(isset($attachments['file']['media_id'])) {
  983. $materialInfo = Material::select(['oss_url'])
  984. ->where('id', $attachments['file']['media_id'])->where('type', 4)->first();
  985. $attachments['file']['media_url'] = $materialInfo->oss_url ?? '';
  986. }
  987. if(isset($attachments['video']['media_id'])) {
  988. $materialInfo = Material::select(['oss_url'])
  989. ->where('id', $attachments['video']['media_id'])->where('type', 3)->first();
  990. $attachments['video']['media_url'] = $materialInfo->oss_url ?? '';
  991. }
  992. $info->attachments = $attachments;
  993. }
  994. return [$list, $count];
  995. }
  996. public static function welcomeTemplateDetail($sysGroupId, $corpid, $templateId) {
  997. # 获取素材信息
  998. $templateInfo = ChatGroupWelcomeTemplate::getInfo($sysGroupId, $corpid, $templateId);
  999. $templateInfo = json_decode(json_encode($templateInfo), 1);
  1000. if(empty($templateInfo)) {
  1001. return [];
  1002. }
  1003. # 素材信息格式化
  1004. # 获取创建人信息
  1005. $adminInfo = Users::query()->where('id', $templateInfo['admin_id'])->select(['id','name'])->first();
  1006. $templateInfo['creator'] = isset($adminInfo->name) ? $adminInfo->name : '';
  1007. # 通过素材ID获取素材链接
  1008. $attachments = json_decode($templateInfo['attachments'], 1);
  1009. if(isset($attachments['image']['media_id'])) {
  1010. $materialInfo = Material::select(['oss_url'])
  1011. ->where('id', $attachments['image']['media_id'])->where('type', 1)->first();
  1012. $attachments['image']['media_url'] = $materialInfo->oss_url ?? '';
  1013. }
  1014. if(isset($attachments['miniprogram']['pic_media_id'])) {
  1015. $materialInfo = Material::select(['oss_url'])
  1016. ->where('id', $attachments['miniprogram']['pic_media_id'])->where('type', 1)->first();
  1017. $attachments['miniprogram']['pic_media_url'] = $materialInfo->oss_url ?? '';
  1018. }
  1019. if(isset($attachments['file']['media_id'])) {
  1020. $materialInfo = Material::select(['oss_url'])
  1021. ->where('id', $attachments['file']['media_id'])->where('type', 4)->first();
  1022. $attachments['file']['media_url'] = $materialInfo->oss_url ?? '';
  1023. }
  1024. if(isset($attachments['video']['media_id'])) {
  1025. $materialInfo = Material::select(['oss_url'])
  1026. ->where('id', $attachments['video']['media_id'])->where('type', 3)->first();
  1027. $attachments['video']['media_url'] = $materialInfo->oss_url ?? '';
  1028. }
  1029. $templateInfo['attachments'] = $attachments;
  1030. return $templateInfo;
  1031. }
  1032. public static function delWelcomeTemplate($sysGroupId, $corpid, $templateId, &$error) {
  1033. # 请求企微创建素材接口
  1034. $responseData = QyCommon::delChatGroupWelcomeTemplate($corpid, $templateId);
  1035. if(isset($responseData['errcode']) && $responseData['errcode']) {
  1036. $errMsg = $responseData['errmsg'] ?? $responseData['errcode'];
  1037. EmailQueue::rPush('删除客户入群欢迎语素材接口返回错误码', $errMsg, ['song.shen@kuxuan-inc.com'], '猎羽');
  1038. Log::logError('删除客户入群欢迎语素材接口返回错误码', [
  1039. 'sys_group_id' => $sysGroupId,
  1040. 'corpid' => $corpid,
  1041. 'template_id' => $templateId,
  1042. 'response' => $responseData
  1043. ], 'delWelcomeTemplateTrace');
  1044. $error = 5241; return ;
  1045. }
  1046. $res = ChatGroupWelcomeTemplate::updateStatus($sysGroupId, $corpid, $templateId);
  1047. if(!$res) {
  1048. $error = 500; return ;
  1049. }
  1050. }
  1051. public static function setForwardChatGroupCreateRule($ruleId, $params) {
  1052. try {
  1053. if(1 == $params['is_for_all']) {
  1054. $params['users'] = '';
  1055. # 判断当前企微是否有绑定设备客服
  1056. list($bindUserList, $bindUserCount) = AndroidBindCorp::getDeviceList(null, $params['corpid'], null, $params['sys_group_id'], 1, 20);
  1057. if(0 == $bindUserCount) return 4857;// 当前企微下已绑定设备的客服列表为空
  1058. } else {
  1059. # 判断选定的群主是否已经绑定了设备信息
  1060. $error = self::checkUserBindDevice($params, null);
  1061. if($error > 0) return 4856;// 所选群主含未绑定设备客服
  1062. }
  1063. if($ruleId) {
  1064. $ruleInfo = ForwardChatGroupRule::getInfo($ruleId);
  1065. if(empty($ruleInfo)) {return 4852;}// 创建客户群规则配置不存在
  1066. }
  1067. DB::beginTransaction();
  1068. # 基础数据入dj_invite_chat_group_rule表
  1069. $errno = ForwardChatGroupRule::editRule($ruleId, $params);
  1070. if($errno) {
  1071. DB::rollback();
  1072. return $errno;
  1073. }
  1074. DB::commit();
  1075. } catch (\Exception $e) {
  1076. DB::rollback();
  1077. EmailQueue::rPush('转发消息客服入群规则配置过程发生异常', $e->getTraceAsString(), ['song.shen@kuxuan-inc.com'], '猎羽');
  1078. Log::logError('转发消息客服入群规则配置失败', [
  1079. 'rule_id' => $ruleId,
  1080. 'params' => $params,
  1081. 'line' => $e->getLine(),
  1082. 'msg' => $e->getMessage()
  1083. ], 'setForwardChatGroupCreateRule');
  1084. return 4853;
  1085. }
  1086. return 0;
  1087. }
  1088. public static function forwardChatGroupCreateRuleList($corpid, $userId, $sysGroupId, $keyword, $status, $page, $pageSize) {
  1089. list($list, $count) = ForwardChatGroupRule::ruleList($corpid, $userId, $sysGroupId, $keyword, $status, $page, $pageSize);
  1090. if(!$count) return [$list, $count];
  1091. # 获取操作人员的信息
  1092. $adminIdList = $list->pluck('admin_id');
  1093. $adminList = Users::query()->select('id', 'name')->whereIn('id', $adminIdList)->get();
  1094. foreach ($list as $item) {
  1095. # 操作人员信息处理
  1096. $adminInfo = $adminList->where('id', $item->admin_id)->first();
  1097. $item->admin_name = $adminInfo->name ?? null;
  1098. // $item->forward_users = json_decode($item->forward_users, 1);
  1099. $item->users = !empty($item->users) ? explode(',', $item->users) : [];
  1100. }
  1101. return [$list, $count];
  1102. }
  1103. public static function forwardChatGroupCreateRuleDetail($ruleId) {
  1104. $ruleInfo = ForwardChatGroupRule::getInfo($ruleId);
  1105. if(empty($ruleInfo)) return [];
  1106. $ruleInfo->users = !empty($ruleInfo->users) ? explode(',', $ruleInfo->users) : [];
  1107. return $ruleInfo;
  1108. }
  1109. public static function forwardChatGroupCreateRuleDelete($ruleId, $sysGroupId, $adminId) {
  1110. try {
  1111. DB::beginTransaction();
  1112. $isExist = ForwardChatGroupRule::getInfo($ruleId);
  1113. if(empty($isExist)) {
  1114. DB::rollback();
  1115. return 4852;
  1116. }
  1117. # 执行删除
  1118. $result = ForwardChatGroupRule::delRule($ruleId, $adminId);
  1119. if(!$result) {
  1120. DB::rollback();
  1121. return 4854;
  1122. }
  1123. DB::commit();
  1124. } catch (\Exception $e) {
  1125. DB::rollback();
  1126. EmailQueue::rPush('删除转发消息客服入群规则过程发生异常', $e->getTraceAsString(), ['song.shen@kuxuan-inc.com'], '猎羽');
  1127. Log::logError('删除转发消息客服入群规则异常', [
  1128. 'rule_id' => $ruleId,
  1129. 'line' => $e->getLine(),
  1130. 'msg' => $e->getMessage()
  1131. ], 'forwardChatGroupCreateRuleDelete');
  1132. return 4854;
  1133. }
  1134. return 0;
  1135. }
  1136. public static function forwardChatGroupCreateRuleChangeStatus($ruleId, $adminId, $status, $sysGroupId) {
  1137. # 验证规则是否存在
  1138. $inviteConfig = ForwardChatGroupRule::getInfo($ruleId);
  1139. if(empty($inviteConfig)) return 4852;
  1140. $update = ['status' => $status, 'admin_id' => $adminId];
  1141. $result = ForwardChatGroupRule::updateStatus($ruleId, $sysGroupId, $update);
  1142. if(!$result) return 4855;
  1143. return 0;
  1144. }
  1145. }