企微短剧业务系统

DjUserService.php 32KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822
  1. <?php
  2. /**
  3. * Created by PhpStorm.
  4. * User: shensong
  5. * Date: 2022/3/25
  6. * Time: 10:20
  7. */
  8. namespace App\Service;
  9. use App\Log;
  10. use App\Models\AccountLicenseRenewalJob;
  11. use App\Models\AccountLicenseRenewalJobRecord;
  12. use App\Models\AdqUser;
  13. use App\Models\AuthorizeCorp;
  14. use App\Models\CustomerDetails;
  15. use App\Models\DjDepartment;
  16. use App\Models\DjUser;
  17. use App\Models\OfficialAccount;
  18. use App\Models\OfficialWebUserActionSetId;
  19. use App\Models\Report\CustomerServiceData;
  20. use App\Models\Report\DjCustomerConversationReport;
  21. use App\Models\System\AdminManageCorp;
  22. use App\Models\System\Users;
  23. use App\Models\TencentAdConf;
  24. use App\RedisModel;
  25. use App\Support\EmailQueue;
  26. use App\Support\qyApi\QyCommon;
  27. class DjUserService
  28. {
  29. /**
  30. * 根据企业id查询内部员工列表
  31. * @param $corpid string 企业id
  32. * @param $userName string 客服名称
  33. * @return array
  34. */
  35. public static function userList($corpid, $userName, $status=null)
  36. {
  37. // 查询部门列表
  38. $departmentList = DjDepartment::query()
  39. ->selectRaw('department_id, name as department_name')
  40. ->where('enable', 1)
  41. ->where('corpid', $corpid)
  42. ->get()
  43. ->keyBy('department_id')
  44. ->toArray();
  45. $userList = DjUser::query()
  46. ->select(['user_id', 'name', 'open_user_id', 'avatar', 'department', 'status', 'is_active', 'expire_time'])
  47. ->where('corpid', $corpid)
  48. ->where('enable', 1)
  49. ->where('name', 'like', '%' . $userName . '%')
  50. ->where(function($query) use($status){
  51. if($status) $query->where('status', 1);
  52. })
  53. ->get()
  54. ->toArray();
  55. $departmentData = [];
  56. $userData = [];
  57. $total = 0;
  58. foreach ($userList as &$user) {
  59. $user['active_desc'] = '';
  60. if(!$user['is_active']) {
  61. $user['active_time'] = $user['expire_time'] = null;
  62. $user['active_desc'] = '未激活';
  63. } else {
  64. if($user['expire_time']) {
  65. $expireTimestamp = strtotime($user['expire_time']);
  66. if($expireTimestamp <= time()) {
  67. $user['active_desc'] = '未激活';
  68. } else {
  69. if($expireTimestamp - time() <= 86400 * 15) {
  70. $user['active_desc'] = '即将过期';
  71. }
  72. }
  73. }
  74. }
  75. $departmentIdList = explode(',', $user['department']);
  76. foreach ($departmentIdList as $departmentId) {
  77. if (!isset($departmentData[$departmentId])) {
  78. $departmentData[$departmentId] = isset($departmentList[$departmentId]) ? $departmentList[$departmentId] : [];
  79. }
  80. $user['department_list'][] = isset($departmentList[$departmentId]['department_name']) ? $departmentList[$departmentId]['department_name'] : '';
  81. $departmentData[$departmentId]['user_list'][] = $user;
  82. if (!in_array($user['user_id'], $userData)) {
  83. $userData[] = $user['user_id'];
  84. $total += 1;
  85. }
  86. }
  87. }
  88. return ['list' => array_values($departmentData), 'count' => $total];
  89. }
  90. /**
  91. * 成员管理列表
  92. * @param $corpid string 企业id
  93. * @param $userName string 客服名称
  94. * @param $departmentList array 部门列表
  95. * @param $page int 页码
  96. * @param $pageSize int 每页数据条数
  97. * @param $isActive
  98. * @param $appId
  99. * @param $accountId
  100. * @param $operatorId
  101. * @param $expireDays
  102. * @return array
  103. */
  104. public static function users($corpid, $userName, $userIds, $departmentList, $page, $pageSize, $isActive, $appId
  105. , $accountId, $operatorId, $expireDays)
  106. {
  107. if($userIds) {
  108. $userIds = explode(',', $userIds);
  109. }
  110. $users = [];
  111. if(!empty($appId) || !empty($accountId) || !empty($operatorId)) {
  112. $userResult = AdqUser::search([
  113. 'corpid' => $corpid,
  114. 'app_id' => $appId,
  115. 'account_id' => $accountId,
  116. 'operator_id' => $operatorId
  117. ]);
  118. $users = $userResult->pluck('user_id')->toArray();
  119. $users = array_filter($users);
  120. }
  121. $expireTime = null;
  122. if ($expireDays) {
  123. if(empty($isActive)) $isActive = 1;
  124. $expireTime = date('Y-m-d 00:00:00', strtotime('+' . $expireDays . ' days'));
  125. }
  126. list($userList, $userCount) = DjUser::getUserList($corpid, $userName, $userIds, $departmentList, $page, $pageSize
  127. , $isActive, $appId, $accountId, $operatorId, $users, $expireTime);
  128. // 查询部门列表
  129. $departmentList = DjDepartment::query()
  130. ->selectRaw('department_id, name as department_name')
  131. ->where('enable', 1)
  132. ->where('corpid', $corpid)
  133. ->get()
  134. ->keyBy('department_id')
  135. ->toArray();
  136. // 查询客服id列表
  137. $userIdList = array_column($userList, 'user_id');
  138. // 查询客服对应客户数
  139. $userCustomerCountList = CustomerDetails::suffix($corpid)
  140. ->selectRaw('user_id, count(1) as count')
  141. // ->whereIn('loss_status', [0, 1, 2])
  142. ->where('loss_status', 1)
  143. ->where('can_receive', 1)
  144. ->where('enable', 1)
  145. ->where('corpid', $corpid)
  146. ->whereIn('user_id', $userIdList)
  147. ->groupBy('user_id')
  148. ->get()
  149. ->keyBy('user_id')
  150. ->toArray();
  151. # 批量查询客服绑定的adq投放账号,公众号以及运营人员 投放人员
  152. $adqUserList = AdqUser::getUserList($corpid, $userIdList);
  153. $adqUserList = $adqUserList->keyBy('user_id')->toArray();
  154. # 提取客服绑定的公众号名称
  155. $appIdList = array_column($adqUserList, 'app_id');
  156. $appIdList = array_filter($appIdList);
  157. $appList = OfficialAccount::getAppInfoList($appIdList);
  158. # 提取客服绑定的运营人员名称
  159. $operatorIdList = array_column($adqUserList, 'operator_id');
  160. $operatorIdList = array_filter($operatorIdList);
  161. $operatorList = Users::getUserInfoList($operatorIdList);
  162. # 批量查询昨日新增客户数
  163. $yesterday = date('Y-m-d', strtotime('-1 days'));
  164. $reportList = DjCustomerConversationReport::query()
  165. ->whereIn('user_id', $userIdList)
  166. ->where('corpid', $corpid)
  167. ->where('date', $yesterday)
  168. ->select(['new_contact_cnt', 'loss_contact_cnt', 'user_id'])
  169. ->get();
  170. $yesterdayLoss = $yesterdayAdd = $customerCount = 0;
  171. foreach ($userList as $key => $value) {
  172. # 客服对应客户数
  173. $count = isset($userCustomerCountList[$value['user_id']]['count']) ? $userCustomerCountList[$value['user_id']]['count'] : 0;
  174. $userList[$key]['customer_number'] = $count;
  175. $userReport = $reportList->where('user_id', $value['user_id'])->first();
  176. $userList[$key]['new_contact_cnt'] = $userReport->new_contact_cnt ?? 0;
  177. $userList[$key]['loss_contact_cnt'] = $userReport->loss_contact_cnt ?? 0;
  178. $yesterdayLoss += $userList[$key]['loss_contact_cnt'];
  179. $yesterdayAdd += $userList[$key]['new_contact_cnt'];
  180. $customerCount += $count;
  181. # 客服对应部门
  182. $department = explode(',', $value['department']);
  183. $userList[$key]['department'] = $department;
  184. $departmentNameList = [];
  185. foreach($department as $item) {
  186. $departmentNameList[] = isset($departmentList[$item]['department_name']) ? $departmentList[$item]['department_name'] : '';
  187. }
  188. $userList[$key]['department_list'] = $departmentNameList;
  189. # 客服对应adq数据源
  190. $adqUserInfo = isset($adqUserList[$value['user_id']]) ? $adqUserList[$value['user_id']] : null;
  191. $userList[$key]['account_id'] = $adqUserInfo['account_id'] ?? null;
  192. $userList[$key]['order_type'] = empty($adqUserInfo['account_id']) ? 1 : 2;
  193. $userList[$key]['operator_id'] = $adqUserInfo['operator_id'] ?? null;
  194. $userList[$key]['app_id'] = $adqUserInfo['app_id'] ?? null;
  195. $userList[$key]['app_name'] = $appList[$userList[$key]['app_id']] ?? null;
  196. $userList[$key]['operator_name']=$operatorList[$userList[$key]['operator_id']] ?? null;
  197. # 激活状态描述
  198. $userList[$key]['active_desc'] = '';
  199. if(!$value['is_active']) {
  200. $userList[$key]['active_time'] = $userList[$key]['expire_time'] = null;
  201. $user['active_desc'] = '未激活';
  202. } else {
  203. if($value['expire_time']) {
  204. $expireTimestamp = strtotime($value['expire_time']);
  205. if($expireTimestamp <= time()) {
  206. $userList[$key]['active_desc'] = '未激活';
  207. } else {
  208. if($expireTimestamp - time() <= 86400 * 15) {
  209. $userList[$key]['active_desc'] = '即将过期';
  210. }
  211. }
  212. }
  213. }
  214. }
  215. return [$userList, $userCount, $yesterdayAdd, $yesterdayLoss, $customerCount];
  216. }
  217. /*
  218. * 成员详情
  219. * @param $corpid
  220. * @param $user_id
  221. */
  222. public static function user_info($corpid,$user_id){
  223. $ret = [];
  224. #成员基本信息
  225. $ret['user_info'] = DjUser::query()
  226. ->select(['user_id', 'name', 'open_user_id', 'avatar', 'department', 'status'])
  227. ->where('corpid', $corpid)
  228. ->where("user_id",$user_id)
  229. ->where('enable', 1)
  230. ->first();
  231. if(empty($ret['user_info'])) {
  232. return [];
  233. } else {
  234. $ret['user_info'] = $ret['user_info']->toArray();
  235. }
  236. #成员部门信息
  237. $ret['user_info']['department'] = DjDepartment::query()
  238. ->where('enable', 1)
  239. ->where('corpid', $corpid)
  240. ->whereIn("department_id",explode(',',$ret['user_info']['department']))
  241. ->pluck("name")
  242. ->toArray();
  243. # 客户总数
  244. $ret['customer']['total'] = CustomerDetails::suffix($corpid)
  245. ->whereIn('loss_status', [0, 1, 2])
  246. ->where('corpid', $corpid)
  247. ->where('user_id', $user_id)
  248. ->count();
  249. # 今日新增
  250. $ret['customer']['today'] = CustomerDetails::suffix($corpid)
  251. ->where('corpid', $corpid)
  252. ->where('user_id', $user_id)
  253. ->whereBetween("createtime",[strtotime(date("Y-m-d")),strtotime(date("Y-m-d 23:59:59"))])
  254. ->count();
  255. # 昨日新增
  256. $ret['customer']['yesterday'] = CustomerDetails::suffix($corpid)
  257. ->where('corpid', $corpid)
  258. ->where('user_id', $user_id)
  259. ->whereBetween("createtime",[strtotime(date("Y-m-d", strtotime("-1 days"))),strtotime(date("Y-m-d 23:59:59", strtotime("-1 days")))])
  260. ->count();
  261. # 总流失
  262. $ret['customer']['loss_total'] = CustomerDetails::suffix($corpid)
  263. ->where('loss_status', 0)
  264. ->where('corpid', $corpid)
  265. ->where('user_id', $user_id)
  266. ->count();
  267. # 今日流失
  268. $ret['customer']['today_loss'] = CustomerDetails::suffix($corpid)
  269. ->where('loss_status', 0)
  270. ->where('corpid', $corpid)
  271. ->where('user_id', $user_id)
  272. ->whereBetween("loss_time",[date("Y-m-d"),date("Y-m-d 23:59:59")])
  273. ->count();
  274. # 昨日流失
  275. $ret['customer']['yesterday_loss'] = CustomerDetails::suffix($corpid)
  276. ->where('loss_status', 0)
  277. ->where('corpid', $corpid)
  278. ->where('user_id', $user_id)
  279. ->whereBetween("loss_time",[date("Y-m-d", strtotime("-1 days")),date("Y-m-d 23:59:59", strtotime("-1 days"))])
  280. ->count();
  281. return $ret;
  282. }
  283. /*
  284. * 会话统计列表
  285. * @param $corpid
  286. * @param $user_id
  287. * @param $begin_date
  288. * @param $end_date
  289. */
  290. public static function conversation_report($corpid, $user_id, $begin_date, $end_date){
  291. $query = DjCustomerConversationReport::query()->where("corpid",$corpid)
  292. ->where("user_id",$user_id)
  293. ->whereBetween("date",[$begin_date,$end_date]);
  294. $list = $query->select(['date', 'chat_cnt', 'message_cnt', 'reply_percentage', 'avg_reply_time', 'new_contact_cnt', 'loss_contact_cnt'])
  295. ->orderBy("date","asc")
  296. ->get()->toArray();
  297. return $list;
  298. }
  299. /*
  300. * 会话统计列表
  301. * @param $corpid
  302. * @param $user_id
  303. * @param $begin_date
  304. * @param $end_date
  305. */
  306. public static function conversation_report_total($corpid, $user_id, $begin_date, $end_date){
  307. $query = DjCustomerConversationReport::query()->where("corpid",$corpid)
  308. ->where("user_id",$user_id)
  309. ->whereBetween("date",[$begin_date,$end_date]);
  310. /**汇总**/
  311. $total = $query->selectRaw("sum(chat_cnt) as chat_cnt")
  312. ->selectRaw("sum(message_cnt) as message_cnt")
  313. ->selectRaw("round(avg(reply_percentage),2) as reply_percentage")
  314. ->selectRaw("round(avg(avg_reply_time),2) as avg_reply_time")
  315. ->first();
  316. $total->chat_cnt = $total->chat_cnt===null ? 0:$total->chat_cnt;
  317. $total->message_cnt = $total->message_cnt===null ? 0:$total->message_cnt;
  318. $total->reply_percentage = $total->reply_percentage===null ? '0%':$total->reply_percentage."%";
  319. $total->avg_reply_time = $total->avg_reply_time===null ? 0:$total->avg_reply_time;
  320. return $total;
  321. }
  322. public static function departments($corpid)
  323. {
  324. // 查询部门列表
  325. $departmentList = DjDepartment::query()
  326. ->selectRaw('department_id, name as department_name, parent_id')
  327. ->where('enable', 1)
  328. ->where('corpid', $corpid)
  329. ->get()
  330. ->toArray();
  331. return $departmentList;
  332. }
  333. public static function bindUserAdqAccountId($corpid, $userId, $accountId, $sysGroupId, $appId, $operatorId)
  334. {
  335. $requestData = [
  336. 'corpid' => $corpid,
  337. 'user_id' => $userId,
  338. 'account_id' => $accountId,
  339. 'sys_group_id' => $sysGroupId,
  340. 'app_id' => $appId,
  341. 'operator_id' => $operatorId,
  342. ];
  343. try{
  344. $web_user_action_set_id = null;
  345. if(!empty($accountId)) {
  346. // 判断数据源ID是否已经授权到系统当中
  347. $adqInfo = OfficialWebUserActionSetId::query()
  348. ->where('account_id', $accountId)
  349. ->where('sys_group_id', $sysGroupId)
  350. ->first();
  351. if(empty($adqInfo)) {
  352. Log::logError('DjUserService.bindUserAdqAccountId', [
  353. 'params' => $requestData,
  354. 'err_msg' => 'adq投放账号ID查询失败,确认填写是否正确',
  355. ], 'interface');
  356. return ['adq投放账号ID查询失败,确认填写是否正确', 4900 ];
  357. }
  358. if(empty($adqInfo->web_user_action_set_id)) {
  359. Log::logError('DjUserService.bindUserAdqAccountId', [
  360. 'params' => $requestData,
  361. 'err_msg' => 'adq投放账号尚未绑定web数据源',
  362. ], 'interface');
  363. return ['adq投放账号尚未绑定web数据源', 4901];
  364. }
  365. $web_user_action_set_id = $adqInfo->web_user_action_set_id;
  366. }
  367. # 验证当公众号不为空时,投放账号以及运营人员也不能为空
  368. if(!empty($appId)) {
  369. if(empty($accountId)) {
  370. return ['公众号绑定adq投放账号必填', 4902];
  371. }
  372. if(empty($operatorId)) {
  373. return ['公众号绑定运营人员必填', 4903];
  374. }
  375. // # 验证一个公众号是否只绑定了一个运营人员
  376. // $operatorIdList = AdqUser::getOperateUidList($appId);
  377. // $newOperatorIdList = array_unique(array_merge([$operatorId], $operatorIdList));
  378. // if(count($newOperatorIdList) > 1) {
  379. // return ['一个公众号只可以绑定同一个运营人员', 4904];
  380. // }
  381. }
  382. // 查询数据是否已经在数据表中
  383. $row = AdqUser::query()
  384. ->where('corpid', $corpid)
  385. ->where('user_id', $userId)
  386. ->first();
  387. $enableUserIdList = Users::getCorpUserList($sysGroupId);
  388. $enableUserIdList[] = $row->operator_id ?? 0;
  389. if(!in_array($operatorId, $enableUserIdList)){
  390. return ['运营人员不合法', 5254];
  391. }
  392. if($row) {
  393. $res = AdqUser::query()
  394. ->where('corpid', $corpid)
  395. ->where('user_id', $userId)
  396. ->update([
  397. 'user_action_set_id' => $web_user_action_set_id,
  398. 'account_id' => $accountId,
  399. 'app_id' => $appId,
  400. 'operator_id' => $operatorId,
  401. 'update_time' => date('Y-m-d H:i:s')
  402. ]);
  403. } else {
  404. $userInfo = DjUser::query()
  405. ->where('corpid', $corpid)
  406. ->where('user_id', $userId)
  407. ->first();
  408. $res = AdqUser::query()
  409. ->insert([
  410. 'corpid' => $corpid,
  411. 'user_id' => $userId,
  412. 'user_action_set_id' => $web_user_action_set_id,
  413. 'account_id' => $accountId,
  414. 'app_id' => $appId,
  415. 'operator_id' => $operatorId,
  416. 'update_time' => date('Y-m-d H:i:s'),
  417. 'user_name' => $userInfo->name ?? null,
  418. ]);
  419. }
  420. if($res) {
  421. return ['成功', 0];
  422. } else {
  423. Log::logError('DjUserService.bindUserAdqAccountId', [
  424. 'params' => $requestData,
  425. 'err_msg' => '绑定客服数据源失败',
  426. ], 'interface');
  427. return ['失败', 400];
  428. }
  429. } catch (\Exception $exception) {
  430. Log::logError('DjUserService.bindUserAdqAccountId', [
  431. 'params' => $requestData,
  432. 'err_msg' => '绑定客服数据源程序异常',
  433. 'file' => $exception->getFile(),
  434. 'line' => $exception->getLine(),
  435. 'message' => $exception->getMessage(),
  436. 'trace' => $exception->getTraceAsString()
  437. ], 'interface');
  438. EmailQueue::rPush('绑定客服数据源程序异常', json_encode([
  439. 'params' => $requestData,
  440. 'err_msg' => '绑定客服数据源程序异常',
  441. 'file' => $exception->getFile(),
  442. 'line' => $exception->getLine(),
  443. 'message' => $exception->getMessage(),
  444. 'trace' => $exception->getTraceAsString()
  445. ], 256), ['song.shen@kuxuan-inc.com'], '猎羽');
  446. return ['失败', 400];
  447. }
  448. }
  449. public static function updateUserStatus($corpid, $userId, $status, &$errcode)
  450. {
  451. $customerServiceData = CustomerServiceData::query()->where('corpid', $corpid)
  452. ->where('user_id', $userId)->where('enable', 1)->first();
  453. if(empty($customerServiceData)) {
  454. $errcode = 1102;
  455. return false;
  456. }
  457. if($customerServiceData->status == $status) {
  458. return true;
  459. }
  460. $res = CustomerServiceData::query()->where('id', $customerServiceData->id)->update([
  461. 'status' => $status
  462. ]);
  463. if(!$res) {
  464. $errcode = 500;
  465. return false;
  466. }
  467. return true;
  468. }
  469. public static function nearExpiredUserList($corpid) {
  470. }
  471. # 创建客服许可续期任务
  472. public static function createRenewalJob($sysGroupId, $adminId, $title, $type, $accountList)
  473. {
  474. # 验证公司以及客服是否可用
  475. $corpIdList = AdminManageCorp::where('sys_user_id', $sysGroupId)
  476. ->where('is_delete', 0)->pluck('corpid')
  477. ->all();
  478. if (empty($corpIdList)) return ['没有可以操作的企微', 2704];
  479. $corpList = AuthorizeCorp::query()
  480. ->whereIn('id', $corpIdList)
  481. ->where('enable', 1)
  482. ->pluck('corpid')
  483. ->all();
  484. $userList = DjUser::query()
  485. ->select(['user_id', 'corpid', 'name', 'avatar', 'is_active', 'expire_time'])
  486. ->whereIn('corpid', $corpList)
  487. ->where('enable', 1)
  488. ->where('status', 1)
  489. ->where('active_code', '>', '')
  490. ->get();
  491. foreach($accountList as $accountInfo) {
  492. if(!isset($accountInfo['corpid']) || !isset($accountInfo['user_list'])) {
  493. return ['企微客服信息数据格式不合法, 请联系管理员', 2706];
  494. }
  495. if(!in_array($accountInfo['corpid'], $corpList)) {
  496. return ['企微列表超出操作范围', 2705];
  497. }
  498. foreach($accountInfo['user_list'] as $userId) {
  499. $userInfo = $userList->where('corpid', $accountInfo['corpid'])->where('user_id', $userId)->first();
  500. if(empty($userInfo)) {
  501. return ['所选择客服列表中存在不可续期客服', 2707];
  502. }
  503. }
  504. }
  505. \DB::beginTransaction();
  506. # 记录数据
  507. $ruleId = AccountLicenseRenewalJob::saveData($sysGroupId, $adminId, $accountList, $type, $title);
  508. if(empty($ruleId)) {
  509. \DB::rollBack();
  510. return ['程序1异常,请联系管理员', 500];
  511. }
  512. # 将信息写入Redis中处理
  513. $res = RedisModel::lPush(AccountLicenseRenewalJob::ACCOUNT_LICENSE_RENEWAL_JOB_LIST, $ruleId);
  514. if(!$res) {
  515. \DB::rollBack();
  516. return ['程序2异常,请联系管理员', 500];
  517. }
  518. \DB::commit();
  519. return ['添加成功', 0];
  520. }
  521. # 客服许可续期任务列表
  522. public static function renewalJobList($sysGroupId, $title, $status, $page, $pageSize, &$errno) {
  523. try{
  524. $jobModel = AccountLicenseRenewalJob::jobList($sysGroupId, $title, $status);
  525. $offset = ($page - 1) * $pageSize;
  526. $count = $jobModel->count();
  527. $list = $jobModel->orderBy('id', 'desc')->offset($offset)->limit($pageSize)->get();
  528. # 统计发送信息
  529. $ruleIds = $list->pluck('rule_id');
  530. $sendStatData = AccountLicenseRenewalJobRecord::query()->selectRaw("rule_id, count(1) as count")
  531. ->whereIn('rule_id', $ruleIds)->groupBy(['rule_id'])->get();
  532. $errStatData = AccountLicenseRenewalJobRecord::query()->select(['errcode', 'rule_id', 'user_id', 'corpid'])
  533. ->whereIn('rule_id', $ruleIds)->where('errcode', '!=', 0)->get();
  534. $senderIdList = [];
  535. foreach ($errStatData as $item) {
  536. $senderIdList[] = '("'.$item['corpid'].'","'.$item['user_id'].'")';
  537. }
  538. if(!empty($senderIdList)) {
  539. $senderInfoList = DjUser::query()->whereRaw('(corpid, user_id) in ('. implode(',', $senderIdList).')')
  540. ->where('enable', 1)->get();
  541. } else {
  542. $senderInfoList = DjUser::query()->where('enable', 1)->get();
  543. }
  544. $corpInfoList = AuthorizeCorp::query()->get();
  545. $errcodeConf = config('qyWechat.errcode');
  546. //数据格式化(异常状态码, 续期客服个数)
  547. foreach($list as $datum) {
  548. # 统计发送情况
  549. $sendStatInfo = $sendStatData->where('rule_id', $datum->rule_id)->first();
  550. $datum->user_num = $sendStatInfo->count ?? 0;
  551. if(0 == $datum->user_num) {
  552. # 记录表中客服数为空时从客服列表字段中解析客服个数
  553. $datum->user_num = self::getUserNum(json_decode($datum->account_list, 1));
  554. }
  555. # 查询失败信息
  556. $errList = $errStatData->where('rule_id', $datum->rule_id)->all();
  557. $err_msg_list = [];
  558. if(!empty($errList)){
  559. foreach ($errList as $item) {// 无可发送的客户
  560. $err_msg = $errcodeConf[$item['errcode']] ?? null;
  561. if(60111 == $item['errcode']) {//UserID不存在
  562. // 当出现此种错误时,将客服名称一并拼接起来展示
  563. $senderName = $senderInfoList->where('corpid', $item['corpid'])
  564. ->where('user_id', $item['user_id'])->first();
  565. $senderName = $senderName->name ?? '';
  566. $corpName = $corpInfoList->where('corpid', $item['corpid'])->first();
  567. $corpName = $corpName->corp_name ?? '';
  568. $err_msg = $corpName.$senderName.$err_msg;
  569. }
  570. $err_msg = $datum->status != 4 ? '部分失败由于'.$err_msg : $err_msg;
  571. if(!empty($err_msg) && !in_array($err_msg, $err_msg_list)) {
  572. $err_msg_list[] = $err_msg;
  573. }
  574. }
  575. }
  576. $datum->err_msg = $err_msg_list;
  577. unset($datum->account_list);
  578. }
  579. } catch (\Exception $e) {
  580. Log::logError('获取客服许可迁移列表过程发生异常', [
  581. 'line' => $e->getLine(),
  582. 'msg' => $e->getMessage(),
  583. ], 'renewalJobList');
  584. $errno = 5237;
  585. return [[], 0];
  586. }
  587. return [$list, $count];
  588. }
  589. public static function getUserNum($accountList) {
  590. $number = 0;
  591. foreach($accountList as $item) {
  592. $number += count($item['user_list']);
  593. }
  594. return $number;
  595. }
  596. # 客服许可续期任务详情
  597. public static function renewalJobDetail($ruleId, &$errno) {
  598. try{
  599. $selectColumn = 'id as rule_id, title, status, account_list, create_time';
  600. $detail = AccountLicenseRenewalJob::getRuleInfoById($ruleId, $selectColumn);
  601. if(empty($detail)) return [];
  602. # 查询详情列表
  603. $list = AccountLicenseRenewalJobRecord::getRecordList($ruleId);
  604. if($list->isNotEmpty()) {
  605. # 提取企微信息
  606. $corpIdList = array_unique(array_column($list->toArray(), 'corpid'));
  607. $corpInfoList = AuthorizeCorp::query()->whereIn('corpid', $corpIdList)->get();
  608. $senderInfoList = DjUser::query()->whereIn('corpid', $corpIdList)
  609. ->where('enable', 1)->get();
  610. $errcodeConf = config('qyWechat.errcode');
  611. foreach($list as $item) {
  612. $corpInfo = $corpInfoList->where('corpid', $item->corpid)->first();
  613. $item->corp_name = $corpInfo->corp_name ?? '';
  614. $senderInfo = $senderInfoList->where('corpid', $item->corpid)->where('user_id', $item->user_id)->first();
  615. $item->user_name = $senderInfo->name ?? '';
  616. $errmsg = '';
  617. if($item->errcode > 0) $errmsg = $errcodeConf[$item->errcode] ?? null;
  618. $item->errmsg = $errmsg;
  619. }
  620. } else {
  621. $accountList = json_decode($detail->account_list, 1);
  622. $list = [];
  623. # 提取企微信息
  624. $corpIdList = array_unique(array_column($accountList, 'corpid'));
  625. $corpInfoList = AuthorizeCorp::query()->whereIn('corpid', $corpIdList)->get();
  626. $senderInfoList = DjUser::query()->whereIn('corpid', $corpIdList)
  627. ->where('enable', 1)->get();
  628. foreach($accountList as $item) {
  629. foreach ($item['user_list'] as $userId) {
  630. $value = [
  631. "corpid" => $item['corpid'],
  632. "user_id"=> $userId,
  633. "status" => -1 == $detail->status ? 2 : 0,
  634. "errcode"=> 0,
  635. "errmsg" => "",
  636. ];
  637. $corpInfo = $corpInfoList->where('corpid', $item['corpid'])->first();
  638. $value['corp_name'] = $corpInfo->corp_name ?? '';
  639. $senderInfo = $senderInfoList->where('corpid', $item['corpid'])->where('user_id', $userId)->first();
  640. $value['user_name'] = $senderInfo->name ?? '';
  641. $list[] = $value;
  642. }
  643. }
  644. }
  645. unset($detail->account_list);
  646. $detail->list = $list;
  647. } catch (\Exception $e) {
  648. Log::logError('群发详情获取过程发生异常', [
  649. 'line' => $e->getLine(),
  650. 'msg' => $e->getMessage(),
  651. 'rule_id' => $ruleId
  652. ], 'ruleDetail');
  653. $errno = 5238;
  654. return [];
  655. }
  656. return $detail;
  657. }
  658. # 取消客服许可续期任务(只可取消未支付且未失效的订单)
  659. public static function cancelRenewalJob($ruleId, &$errno) {
  660. // 查询当前任务状态,如果为未执行,则直接修改任务状态为已取消,不在处理
  661. $selectColumn = 'status';
  662. \DB::begintransaction();
  663. $ruleInfo = AccountLicenseRenewalJob::getRuleInfoById($ruleId, $selectColumn);
  664. if($ruleInfo->status == AccountLicenseRenewalJob::NON_EXECUTION_JOB_STATUS) {
  665. $res = AccountLicenseRenewalJob::updateRuleStatus($ruleId, AccountLicenseRenewalJob::CANCELLED_JOB_STATUS);
  666. if($res) {
  667. \DB::commit();
  668. } else {
  669. \DB::rollBack();
  670. $errno = 500;
  671. }
  672. return [];
  673. }
  674. # 找到可以取消的订单id列表
  675. $orderList = AccountLicenseRenewalJobRecord::getUnPaidOrderIdList($ruleId);
  676. if($orderList->isEmpty()) {
  677. $errno = 5239;
  678. return '客服许可续期任务暂无可以取消的订单';
  679. }
  680. $resArr = [];
  681. $errcodeConf = config('qyWechat.errcode');
  682. $corpInfoList = AuthorizeCorp::query()->get();
  683. foreach ($orderList as $item) {
  684. $res = QyCommon::cancelOrder($item->corpid, $item->order_id);
  685. if(0 != $res['errcode']) {
  686. $corpInfo = $corpInfoList->where('corpid', $item->corpid)->first();
  687. $corpName = $corpInfo->corp_name ?? null;
  688. $err_msg = $errcodeConf[$res['errcode']] ?? null;
  689. $resArr[] = [
  690. 'corpid' => $item->corpid,
  691. 'corp_name' => $corpName,
  692. 'errcode' => $res['errcode'],
  693. 'errmsg' => $err_msg
  694. ];
  695. } else {
  696. AccountLicenseRenewalJobRecord::query()->where('corpid', $item->corpid)
  697. ->where('order_id', $item->order_id)->update(['status' => 2]);
  698. }
  699. }
  700. // 如果订单已经全部取消支付,则将任务状态变更为已取消
  701. $totalCount = AccountLicenseRenewalJobRecord::getRecordCount($ruleId, null);
  702. $cancelCount = AccountLicenseRenewalJobRecord::getRecordCount($ruleId, AccountLicenseRenewalJobRecord::CANCELLED_STATUS);
  703. if($totalCount > 0) {
  704. if($totalCount == $cancelCount) {
  705. AccountLicenseRenewalJob::updateRuleStatus($ruleId, AccountLicenseRenewalJob::CANCELLED_JOB_STATUS);
  706. }
  707. }
  708. if(!empty($resArr)) {
  709. $errno=2708;
  710. return $resArr;
  711. } else {
  712. return [];
  713. }
  714. }
  715. }