企微短剧业务系统

ChatGroupService.php 57KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357
  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. if(empty($userIdList)) {
  725. return ['待同步成员列表为空', 2014];
  726. }
  727. # 获取队列长度,超过6000报警
  728. $length = RedisModel::lLen(ChatGroup::CHAT_GROUP_DETAIL_RDS);
  729. if($length > ChatGroup::CHAT_GROUP_DETAIL_RDS_LIMIT) {
  730. EmailQueue::rPush('同步企微客户群队列长度超过阈值', json_encode([
  731. 'redis_key' => ChatGroup::CHAT_GROUP_DETAIL_RDS, 'length' => $length
  732. ]), ['song.shen@kuxuan-inc.com'], '猎羽');
  733. }
  734. $userCount = count($userIdList);
  735. # 需要截取的段数
  736. $spliceCount = ceil($userCount / 100);
  737. for ($i=1; $i<=$spliceCount; $i++) {
  738. $start = ($i - 1) * 100;
  739. $ownerFilter = array_slice($userIdList, $start, 100);
  740. # 循环获取企微下的客户群列表
  741. list($res, $code) = self::getCorpChatGroupList($ownerFilter, $corpid);
  742. if(0 != $code) return [$res, $code];
  743. }
  744. } catch (\Exception $exception){
  745. Log::logError('更新企微客户群列表异常', [
  746. 'corpid' => $corpid,
  747. 'file' => $exception->getFile(),
  748. 'line' => $exception->getLine(),
  749. 'msg' => $exception->getMessage(),
  750. 'trace'=> $exception->getTraceAsString()
  751. ], 'syncCorpChatGroup');
  752. return ['同步失败,请联系管理员', 500];
  753. }
  754. RedisModel::set($redisKey, time());
  755. RedisModel::expire($redisKey, 600);
  756. Log::logInfo('end', [time()], 'syncCorpChatGroup');
  757. return ['同步中', 0];
  758. }
  759. public static function getCorpChatGroupList($ownerFilter, $corpid) {
  760. $flag = true;
  761. $nextCursor = null;
  762. while($flag) {
  763. # 获取群基本信息
  764. $responseData = QyCommon::getGroupChatList($corpid, $ownerFilter, 1000, $nextCursor);
  765. if(isset($responseData['errcode']) && $responseData['errcode']) {
  766. if(!in_array($responseData['errcode'], [701008])) {
  767. EmailQueue::rPush('群基本信息获取失败', json_encode($responseData, JSON_UNESCAPED_UNICODE)
  768. , ['song.shen@kuxuan-inc.com'], '群基本信息获取失败');
  769. }
  770. Log::logError('群基本信息获取失败', [
  771. 'corpid' => $corpid,
  772. 'ownerFilter' => $ownerFilter,
  773. 'cursor' => $nextCursor,
  774. 'data' => $responseData,
  775. ], 'GroupBasicInfo');
  776. return ['群基本信息获取失败', 2015];
  777. }
  778. $chatGroupList = $responseData['group_chat_list'] ?? [];
  779. # 翻页查询外部联系人所有的关联员工
  780. if(!empty($responseData['next_cursor'])) {
  781. $nextCursor = $responseData['next_cursor'];
  782. } else {
  783. $flag = false;
  784. }
  785. foreach ($chatGroupList as $chatGroupInfo) {
  786. list($res, $code) = self::getCorpChatGroupDetail($corpid, $ownerFilter, $chatGroupInfo);
  787. if(0 != $code) return [$res, $code];
  788. }
  789. }
  790. }
  791. public static function getCorpChatGroupDetail($corpid, $ownerFilter, $chatGroupInfo, $retry = 0) {
  792. # 将chat_id和status置入队列供客户群详情脚本消费
  793. $chatId = $chatGroupInfo['chat_id'] ?? '';
  794. $status = $chatGroupInfo['status'] ?? null;
  795. $result = RedisModel::lPush(ChatGroup::CHAT_GROUP_DETAIL_RDS, json_encode([
  796. 'corpid' => $corpid,
  797. 'chat_id' => $chatId,
  798. 'status' => $status
  799. ]));
  800. if(!$result) {
  801. if($retry >= 3) {
  802. Log::logError('群基本信息解析入队列失败', [
  803. 'corpid' => $corpid,
  804. 'ownerFilter' => $ownerFilter,
  805. 'data' => $chatGroupInfo,
  806. ], 'GroupBasicInfo');
  807. return ['群基本信息解析入队列失败', 2016];
  808. } else {
  809. $retry++;
  810. return self::getCorpChatGroupDetail($corpid, $ownerFilter, $chatGroupInfo, $retry);
  811. }
  812. }
  813. return ['处理成功', 0];
  814. }
  815. public static function receiveCreateChatGroupData($deviceId, $corpid, $userName, $groupList) {
  816. # 验证企微id,客服名称以及客户群聊id的合法性
  817. $corpInfo = AuthorizeCorp::getCorpInfo($corpid);
  818. if(empty($corpInfo)) {
  819. Log::logError('接收创建群聊任务-企微信息查询异常', [
  820. 'corpid' => $corpid,
  821. 'device_id' => $deviceId,
  822. 'corp_info' => $corpInfo
  823. ], 'receiveCreateChatGroupData');
  824. return ['企微id不合法', 1102];
  825. }
  826. $userInfoList = DjUser::getUserBySearch(['corpid' => $corpid, 'user_name' => $userName]);
  827. if($userInfoList->isEmpty()) {
  828. Log::logError('接收创建群聊任务异常-客服信息查询异常', [
  829. 'corpid' => $corpid,
  830. 'device_id' => $deviceId,
  831. 'user_name' => $userName,
  832. 'user_info' => $userInfoList
  833. ], 'receiveCreateChatGroupData');
  834. }
  835. # 根据企微以及群主查询对应的设备信息
  836. $dataList = [];
  837. $groupList = json_decode($groupList, 1);
  838. $ownerIdList = array_unique(array_column($groupList, 'owner'));
  839. $deviceInfoList = AndroidBindCorp::getDeviceIdListByUser($corpid, $ownerIdList);
  840. # 根据群聊id查询对应的群主,并按照群主对群聊进行分组处理
  841. foreach($groupList as $groupInfo) {
  842. $deviceInfo = $deviceInfoList->where('corpid', $corpid)->where('user_id', $groupInfo['owner'])
  843. ->first();
  844. $deviceId = $deviceInfo->device_id ?? null;
  845. if(empty($deviceId)) {
  846. Log::logError('接收创建群聊任务-群聊对应群主设备信息查询异常', [
  847. 'corpid' => $corpid,
  848. 'device_id' => $deviceId,
  849. 'group_list' => $groupList,
  850. 'owner' => $groupInfo['owner'],
  851. 'device_info_list' => $deviceInfoList,
  852. 'device_info' => $deviceInfo
  853. ], 'receiveCreateChatGroupData');
  854. continue;
  855. }
  856. $dataList[$deviceId][] = [
  857. 'corpid' => $corpid,
  858. 'owner' => $groupInfo['owner'],
  859. 'groupName' => $groupInfo['groupName'],
  860. 'manager' => $userName,
  861. 'announcement' => $groupInfo['announcement'] ?? '',
  862. ];
  863. }
  864. # 将待创建的群聊id,群聊名称以及管理员信息保存入待执行队列
  865. foreach($dataList as $deviceId => $data) {
  866. $res = RedisModel::lPush(self::CREATE_GROUP_WAIT_RDS.'_'.$deviceId, json_encode([
  867. 'companyName' => $corpInfo->corp_name,
  868. 'groupBeans' => $data,
  869. 'request_time'=> time(),
  870. ],256));
  871. if(!$res) {
  872. Log::logError('接收创建群聊任务-创建群任务入缓存失败', [
  873. 'corpid' => $corpid,
  874. 'device_id' => $deviceId,
  875. 'group_list' => $groupList,
  876. 'redis_key' => self::CREATE_GROUP_WAIT_RDS.'_'.$deviceId,
  877. 'redis_value' => json_encode([
  878. 'companyName' => $corpInfo->corp_name,
  879. 'groupBeans' => $data
  880. ],256)
  881. ], 'receiveCreateChatGroupData');
  882. return ['创建群任务入缓存失败', 500];
  883. }
  884. }
  885. return ['', 0];
  886. }
  887. public static function getCreateGroupTask($deviceId) {
  888. $response = RedisModel::rPop(self::CREATE_GROUP_WAIT_RDS.'_'.$deviceId);
  889. if(!empty($response)) {
  890. $responseData = json_decode($response, 1);
  891. $requestTime = $responseData['request_time'] ?? time();
  892. if(time() - $requestTime >= 43200) { // 超过12个小时的任务不再下发
  893. return self::getCreateGroupTask($deviceId);
  894. }
  895. return $responseData;
  896. } else {
  897. return [
  898. 'companyName' => '',
  899. 'groupBeans' => []
  900. ];
  901. }
  902. }
  903. public static function setWelcomeTemplate($params, &$error) {
  904. $attachmentsArr = !is_array($params['attachments']) ? json_decode($params['attachments'], 1) : $params['attachments'];
  905. # 素材内容验证
  906. $verifyRes = ChatGroupMassMsgService::welcomeTemplateAttachmentVerify($attachmentsArr);
  907. if($verifyRes) {
  908. Log::logError('添加客户入群欢迎语素材接口数据格式不合法', [
  909. 'corpid' => $params['corpid'],
  910. 'text' => $params['content'],
  911. 'attachments' => $attachmentsArr,
  912. 'errcode' => $verifyRes
  913. ], 'setWelcomeTemplateTrace');
  914. $error = $verifyRes; return ;
  915. }
  916. # 素材ID替换
  917. $newAttachments = MaterialService::chatGroupWelcomeTemplateMediaIdReplace($attachmentsArr, $params['corpid'], 'setWelcomeTemplateTrace');
  918. # 处理包含链接,H5推广链接的附件信息
  919. $newAttachments = MaterialService::promoteAttachments($params['corpid'], $newAttachments, 'setWelcomeTemplate');
  920. if(!empty($params['template_id'])) {
  921. $templateId = $params['template_id'];
  922. # 请求企微创建素材接口
  923. $responseData = QyCommon::editChatGroupWelcomeTemplate($params['corpid'], $templateId, $params['content'], $newAttachments);
  924. if(isset($responseData['errcode']) && $responseData['errcode']) {
  925. $errMsg = $responseData['errmsg'] ?? $responseData['errcode'];
  926. EmailQueue::rPush('编辑客户入群欢迎语素材接口返回错误码', $errMsg, ['song.shen@kuxuan-inc.com'], '猎羽');
  927. Log::logError('编辑客户入群欢迎语素材接口返回错误码', [
  928. 'corpid' => $params['corpid'],
  929. 'template_id' => $templateId,
  930. 'text' => $params['content'],
  931. 'attachments' => $newAttachments,
  932. 'response' => $responseData
  933. ], 'setWelcomeTemplateTrace');
  934. $error = 5240; return ;
  935. }
  936. } else {
  937. # 请求企微创建素材接口
  938. $responseData = QyCommon::addChatGroupWelcomeTemplate($params['corpid'], $params['content'], $newAttachments);
  939. if(isset($responseData['errcode']) && $responseData['errcode']) {
  940. $errMsg = $responseData['errmsg'] ?? $responseData['errcode'];
  941. EmailQueue::rPush('添加客户入群欢迎语素材接口返回错误码', $errMsg, ['song.shen@kuxuan-inc.com'], '猎羽');
  942. Log::logError('添加客户入群欢迎语素材接口返回错误码', [
  943. 'corpid' => $params['corpid'],
  944. 'text' => $params['content'],
  945. 'attachments' => $newAttachments,
  946. 'response' => $responseData
  947. ], 'setWelcomeTemplateTrace');
  948. $error = 5240; return ;
  949. }
  950. $templateId = $responseData['template_id'] ?? '';
  951. }
  952. # 将数据保存
  953. $res = ChatGroupWelcomeTemplate::saveData($params['sys_group_id'], $params['admin_id'], $params['corpid']
  954. , $params['name'], $params['content'], $attachmentsArr, $templateId);
  955. if(!$res) {
  956. $error = 500; return ;
  957. }
  958. }
  959. public static function welcomeTemplateList($corpid, $sysGroupId, $keyword, $creatorId, $page, $pageSize) {
  960. list($list, $count) = ChatGroupWelcomeTemplate::getList($corpid, $sysGroupId, $keyword, $creatorId, $page, $pageSize);
  961. # 获取创建人信息
  962. $adminIdList = array_unique(array_column($list->toArray(),'admin_id'));
  963. $adminData = Users::query()->whereIn('id', $adminIdList)->select(['id','name'])->get();
  964. foreach($list as $info) {
  965. $adminInfo = $adminData->where('id', $info->admin_id)->first();
  966. $info->creator = isset($adminInfo->name) ? $adminInfo->name : '';
  967. # 文本内容中客户昵称信息替换
  968. $info->content = str_replace('%NICKNAME%', '「客户昵称」', $info->content);
  969. # 通过素材ID获取素材链接
  970. $attachments = json_decode($info->attachments, 1);
  971. if(isset($attachments['image']['media_id'])) {
  972. $materialInfo = Material::select(['oss_url'])
  973. ->where('id', $attachments['image']['media_id'])->where('type', 1)->first();
  974. $attachments['image']['media_url'] = $materialInfo->oss_url ?? '';
  975. }
  976. if(isset($attachments['miniprogram']['pic_media_id'])) {
  977. $materialInfo = Material::select(['oss_url'])
  978. ->where('id', $attachments['miniprogram']['pic_media_id'])->where('type', 1)->first();
  979. $attachments['miniprogram']['pic_media_url'] = $materialInfo->oss_url ?? '';
  980. }
  981. if(isset($attachments['file']['media_id'])) {
  982. $materialInfo = Material::select(['oss_url'])
  983. ->where('id', $attachments['file']['media_id'])->where('type', 4)->first();
  984. $attachments['file']['media_url'] = $materialInfo->oss_url ?? '';
  985. }
  986. if(isset($attachments['video']['media_id'])) {
  987. $materialInfo = Material::select(['oss_url'])
  988. ->where('id', $attachments['video']['media_id'])->where('type', 3)->first();
  989. $attachments['video']['media_url'] = $materialInfo->oss_url ?? '';
  990. }
  991. $info->attachments = $attachments;
  992. }
  993. return [$list, $count];
  994. }
  995. public static function welcomeTemplateDetail($sysGroupId, $corpid, $templateId) {
  996. # 获取素材信息
  997. $templateInfo = ChatGroupWelcomeTemplate::getInfo($sysGroupId, $corpid, $templateId);
  998. $templateInfo = json_decode(json_encode($templateInfo), 1);
  999. if(empty($templateInfo)) {
  1000. return [];
  1001. }
  1002. # 素材信息格式化
  1003. # 获取创建人信息
  1004. $adminInfo = Users::query()->where('id', $templateInfo['admin_id'])->select(['id','name'])->first();
  1005. $templateInfo['creator'] = isset($adminInfo->name) ? $adminInfo->name : '';
  1006. # 通过素材ID获取素材链接
  1007. $attachments = json_decode($templateInfo['attachments'], 1);
  1008. if(isset($attachments['image']['media_id'])) {
  1009. $materialInfo = Material::select(['oss_url'])
  1010. ->where('id', $attachments['image']['media_id'])->where('type', 1)->first();
  1011. $attachments['image']['media_url'] = $materialInfo->oss_url ?? '';
  1012. }
  1013. if(isset($attachments['miniprogram']['pic_media_id'])) {
  1014. $materialInfo = Material::select(['oss_url'])
  1015. ->where('id', $attachments['miniprogram']['pic_media_id'])->where('type', 1)->first();
  1016. $attachments['miniprogram']['pic_media_url'] = $materialInfo->oss_url ?? '';
  1017. }
  1018. if(isset($attachments['file']['media_id'])) {
  1019. $materialInfo = Material::select(['oss_url'])
  1020. ->where('id', $attachments['file']['media_id'])->where('type', 4)->first();
  1021. $attachments['file']['media_url'] = $materialInfo->oss_url ?? '';
  1022. }
  1023. if(isset($attachments['video']['media_id'])) {
  1024. $materialInfo = Material::select(['oss_url'])
  1025. ->where('id', $attachments['video']['media_id'])->where('type', 3)->first();
  1026. $attachments['video']['media_url'] = $materialInfo->oss_url ?? '';
  1027. }
  1028. $templateInfo['attachments'] = $attachments;
  1029. return $templateInfo;
  1030. }
  1031. public static function delWelcomeTemplate($sysGroupId, $corpid, $templateId, &$error) {
  1032. # 请求企微创建素材接口
  1033. $responseData = QyCommon::delChatGroupWelcomeTemplate($corpid, $templateId);
  1034. if(isset($responseData['errcode']) && $responseData['errcode']) {
  1035. $errMsg = $responseData['errmsg'] ?? $responseData['errcode'];
  1036. EmailQueue::rPush('删除客户入群欢迎语素材接口返回错误码', $errMsg, ['song.shen@kuxuan-inc.com'], '猎羽');
  1037. Log::logError('删除客户入群欢迎语素材接口返回错误码', [
  1038. 'sys_group_id' => $sysGroupId,
  1039. 'corpid' => $corpid,
  1040. 'template_id' => $templateId,
  1041. 'response' => $responseData
  1042. ], 'delWelcomeTemplateTrace');
  1043. $error = 5241; return ;
  1044. }
  1045. $res = ChatGroupWelcomeTemplate::updateStatus($sysGroupId, $corpid, $templateId);
  1046. if(!$res) {
  1047. $error = 500; return ;
  1048. }
  1049. }
  1050. public static function setForwardChatGroupCreateRule($ruleId, $params) {
  1051. try {
  1052. if(1 == $params['is_for_all']) {
  1053. $params['users'] = '';
  1054. # 判断当前企微是否有绑定设备客服
  1055. list($bindUserList, $bindUserCount) = AndroidBindCorp::getDeviceList(null, $params['corpid'], null, $params['sys_group_id'], 1, 20);
  1056. if(0 == $bindUserCount) return 4857;// 当前企微下已绑定设备的客服列表为空
  1057. } else {
  1058. # 判断选定的群主是否已经绑定了设备信息
  1059. $error = self::checkUserBindDevice($params, null);
  1060. if($error > 0) return 4856;// 所选群主含未绑定设备客服
  1061. }
  1062. if($ruleId) {
  1063. $ruleInfo = ForwardChatGroupRule::getInfo($ruleId);
  1064. if(empty($ruleInfo)) {return 4852;}// 创建客户群规则配置不存在
  1065. }
  1066. DB::beginTransaction();
  1067. # 基础数据入dj_invite_chat_group_rule表
  1068. $errno = ForwardChatGroupRule::editRule($ruleId, $params);
  1069. if($errno) {
  1070. DB::rollback();
  1071. return $errno;
  1072. }
  1073. DB::commit();
  1074. } catch (\Exception $e) {
  1075. DB::rollback();
  1076. EmailQueue::rPush('转发消息客服入群规则配置过程发生异常', $e->getTraceAsString(), ['song.shen@kuxuan-inc.com'], '猎羽');
  1077. Log::logError('转发消息客服入群规则配置失败', [
  1078. 'rule_id' => $ruleId,
  1079. 'params' => $params,
  1080. 'line' => $e->getLine(),
  1081. 'msg' => $e->getMessage()
  1082. ], 'setForwardChatGroupCreateRule');
  1083. return 4853;
  1084. }
  1085. return 0;
  1086. }
  1087. public static function forwardChatGroupCreateRuleList($corpid, $userId, $sysGroupId, $keyword, $status, $page, $pageSize) {
  1088. list($list, $count) = ForwardChatGroupRule::ruleList($corpid, $userId, $sysGroupId, $keyword, $status, $page, $pageSize);
  1089. if(!$count) return [$list, $count];
  1090. # 获取操作人员的信息
  1091. $adminIdList = $list->pluck('admin_id');
  1092. $adminList = Users::query()->select('id', 'name')->whereIn('id', $adminIdList)->get();
  1093. foreach ($list as $item) {
  1094. # 操作人员信息处理
  1095. $adminInfo = $adminList->where('id', $item->admin_id)->first();
  1096. $item->admin_name = $adminInfo->name ?? null;
  1097. // $item->forward_users = json_decode($item->forward_users, 1);
  1098. $item->users = !empty($item->users) ? explode(',', $item->users) : [];
  1099. }
  1100. return [$list, $count];
  1101. }
  1102. public static function forwardChatGroupCreateRuleDetail($ruleId) {
  1103. $ruleInfo = ForwardChatGroupRule::getInfo($ruleId);
  1104. if(empty($ruleInfo)) return [];
  1105. $ruleInfo->users = !empty($ruleInfo->users) ? explode(',', $ruleInfo->users) : [];
  1106. return $ruleInfo;
  1107. }
  1108. public static function forwardChatGroupCreateRuleDelete($ruleId, $sysGroupId, $adminId) {
  1109. try {
  1110. DB::beginTransaction();
  1111. $isExist = ForwardChatGroupRule::getInfo($ruleId);
  1112. if(empty($isExist)) {
  1113. DB::rollback();
  1114. return 4852;
  1115. }
  1116. # 执行删除
  1117. $result = ForwardChatGroupRule::delRule($ruleId, $adminId);
  1118. if(!$result) {
  1119. DB::rollback();
  1120. return 4854;
  1121. }
  1122. DB::commit();
  1123. } catch (\Exception $e) {
  1124. DB::rollback();
  1125. EmailQueue::rPush('删除转发消息客服入群规则过程发生异常', $e->getTraceAsString(), ['song.shen@kuxuan-inc.com'], '猎羽');
  1126. Log::logError('删除转发消息客服入群规则异常', [
  1127. 'rule_id' => $ruleId,
  1128. 'line' => $e->getLine(),
  1129. 'msg' => $e->getMessage()
  1130. ], 'forwardChatGroupCreateRuleDelete');
  1131. return 4854;
  1132. }
  1133. return 0;
  1134. }
  1135. public static function forwardChatGroupCreateRuleChangeStatus($ruleId, $adminId, $status, $sysGroupId) {
  1136. # 验证规则是否存在
  1137. $inviteConfig = ForwardChatGroupRule::getInfo($ruleId);
  1138. if(empty($inviteConfig)) return 4852;
  1139. $update = ['status' => $status, 'admin_id' => $adminId];
  1140. $result = ForwardChatGroupRule::updateStatus($ruleId, $sysGroupId, $update);
  1141. if(!$result) return 4855;
  1142. return 0;
  1143. }
  1144. }