WorkSync.php 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. <?php
  2. namespace App\Console\Commands;
  3. use Illuminate\Console\Command;
  4. use App\Facades\Servers\Redis\RedisLock;
  5. use App\Facades\Servers\WechatWork\ExternalContact;
  6. use App\Models\Custom;
  7. use App\Models\Work\Sync as Model;
  8. use App\Models\Work\Tag as WorkTag;
  9. use App\Models\Work\User as WorkUser;
  10. use App\Models\Work\External as WorkExternal;
  11. use App\Facades\Servers\WechatWork\CorpTag as CorpTag;
  12. use App\Facades\Servers\Logs\Log;
  13. class WorkSync extends Command
  14. {
  15. /**
  16. * 任务名称
  17. *
  18. * @var string
  19. */
  20. protected $signature = 'work_sync';
  21. /**
  22. * 任务描述
  23. *
  24. * @var string
  25. */
  26. protected $description = '企微客户任务同步任务';
  27. /**
  28. * Create a new command instance.
  29. *
  30. * @return void
  31. */
  32. public function __construct()
  33. {
  34. parent::__construct();
  35. }
  36. /**
  37. * Execute the console command.
  38. *
  39. * @return int
  40. */
  41. public function handle()
  42. {
  43. try {
  44. // 执行任务
  45. $this->run_task();
  46. return 0;
  47. } catch (\Throwable $th) {
  48. // 记录错误信息
  49. Log::error('work_sync',$th->getMessage());
  50. // 返回结果
  51. return 0;
  52. }
  53. }
  54. /**
  55. * 执行任务
  56. *
  57. * */
  58. public function run_task(){
  59. // 实例
  60. $Model = New Model();
  61. // 获取数据
  62. $taskList = $Model->getList();
  63. // 如果没有任务列表,结束
  64. if( !$taskList ) return ['error'=>'无待执行任务'];
  65. // 如果没有任务列表,结束
  66. $task = array_pop($taskList);
  67. // 返回结果
  68. if( !$task ) return ['error'=>'无待执行任务'];
  69. // 异步锁上锁,失败结束
  70. if( !RedisLock::lock('work:sync:task:id',$task['id'],'180') ) return ['error'=>'任务执行中...'];
  71. // 获取接待人员
  72. $userIdList = ExternalContact::getFollowUsers();
  73. // 如果没有成员ID列表,结束
  74. if( !$userIdList ) {
  75. // 解锁
  76. RedisLock::unlock('work:sync:task:id',$task['id']);
  77. // 无需同步
  78. return ['error'=>'未获取到跟进人员'];
  79. }
  80. // 获取游标
  81. $cursor = $task['cursor'];
  82. // 批量获取客户详情
  83. $extUserList = ExternalContact::batchGetByUser($userIdList,$cursor,100);
  84. // 如果没有客户列表,结束
  85. if( !$extUserList ) {
  86. // 解锁
  87. RedisLock::unlock('work:sync:task:id',$task['id']);
  88. // 结束
  89. return ['error'=>'未获取到外部联系人'];
  90. }
  91. // 获取标签数据
  92. $corpTagList = CorpTag::getList();
  93. // 实例其他模型
  94. $CustomModel = New Custom();
  95. $WorkExternalModel = New WorkExternal();
  96. $WorkUserModel = New WorkUser();
  97. $WorkTagModel = New WorkTag();
  98. // 下一页游标
  99. $task['cursor'] = $extUserList['next_cursor'];
  100. // 外部联系人列表
  101. $extUserList = $extUserList['external_contact_list'];
  102. // 更新的数据
  103. $extUsers = [];
  104. $followUsers = [];
  105. $followTags = [];
  106. // 时间
  107. $time = time();
  108. // 循环处理
  109. foreach ( $extUserList as $key=>$value ) {
  110. // 外部联系人
  111. $extUser = [];
  112. $extUser['name'] = $value['external_contact']['name'];
  113. $extUser['avatar'] = str_ireplace('http://','https://',$value['external_contact']['avatar']);
  114. $extUser['gender'] = $value['external_contact']['gender'];
  115. $extUser['work_type'] = $value['external_contact']['type'];
  116. $extUser['external_userid'] = $value['external_contact']['external_userid'];
  117. $extUser['insert_time'] = $time;
  118. $extUser['update_time'] = $time;
  119. // 处理外部联系人
  120. $extUsers[] = $extUser;
  121. // 跟进客服
  122. $followUser = [];
  123. $followUser['external_userid'] = $extUser['external_userid'];
  124. $followUser['work_userid'] = $value['follow_info']['userid'];
  125. $followUser['remark'] = $value['follow_info']['remark'];
  126. $followUser['description'] = $value['follow_info']['description'];
  127. $followUser['insert_time'] = $time;
  128. $followUser['update_time'] = $time;
  129. $followUser['remark_mobiles'] = implode(',',$value['follow_info']['remark_mobiles']);
  130. $followUser['remark_company'] = empty($value['external_contact']['corp_name'])? (empty($value['follow_info']['remark_corp_name']) ? '' : $value['follow_info']['remark_corp_name']) : $value['external_contact']['corp_name'];
  131. $followUsers[] = $followUser;
  132. foreach ($corpTagList as $group){
  133. foreach ($group['tag'] as $tag){
  134. if( in_array($tag['id'],$value['follow_info']['tag_id']) ) $followTags[] = ['group_name'=>$group['group_name'],'tag_name'=>$tag['name'],'tag_id'=>$tag['id'],'type'=>1,'external_userid'=>$followUser['external_userid'],'work_userid'=>$followUser['work_userid']];
  135. }
  136. }
  137. // 跟进人员是否备注手机号
  138. $extUser['phone'] = $value['follow_info']['remark_mobiles'] ? $value['follow_info']['remark_mobiles'][0] : '';
  139. // 重组数据
  140. $extUserList[$key] = $extUser;
  141. }
  142. // 标签写入
  143. if( $followTags ) $WorkTagModel->query()->insert($followTags);
  144. // 需要更新的数据
  145. $WorkExternalModel->query()->upsert($extUsers,'external_userid',['name','avatar','gender','work_type','update_time']);
  146. // 需要更新的数据
  147. $WorkUserModel->query()->upsert($followUsers,['external_userid','work_userid'],['remark','description','remark_mobiles','remark_company','update_time']);
  148. // 获取外部联系人ID,并去重
  149. $customIds = array_values(array_unique(array_filter(array_column($extUserList,'external_userid'))));
  150. // 获取外部联系人ID,并去重
  151. $customPhones = array_values(array_unique(array_filter(array_column($extUserList,'phone'))));
  152. // 查询客户表中是否存在该客户
  153. $customIds = $customIds ? $WorkExternalModel->getPluckInFiled('external_userid',$customIds,'custom_uid','external_userid') : [];
  154. // 获取
  155. $customPhones = $customPhones ? $CustomModel->getPluckInFiled('phone',$customPhones,'external_userid','phone') : [];
  156. // 循环处理
  157. foreach ( $extUserList as $value ) {
  158. // 不存在外部联系人账号的跳过
  159. if( !isset($customIds[$value['external_userid']]) ) continue;
  160. // 存在在外部联系人账号但是绑定了账号的跳过
  161. if( $customIds[$value['external_userid']] ) continue;
  162. // 不存在手机号,跳过
  163. if( !$value['phone'] ) continue;
  164. // 如果绑定了其他外部联系人
  165. if( !empty($customPhones[$value['phone']]) ) continue;
  166. // 账号UID默认
  167. $uid = 0;
  168. // 账号未注册
  169. if( !isset($customPhones[$value['phone']]) ) {
  170. // 注册账号
  171. $uid = $CustomModel->add(['phone'=>$value['phone'],'username'=>$value['name'],'userpic'=>$value['avatar'],'sex'=>$value['gender'],'external_userid'=>$value['external_userid']]);
  172. // 注册失败,
  173. if( !$uid ) continue;
  174. }else{
  175. // 已经注册的,未绑定外部联系人
  176. if( !$customPhones[$value['phone']] ) {
  177. // 查询号码
  178. $custom = $CustomModel->getOneByPhone($value['phone']);
  179. // 没有账号,跳过
  180. if( !$custom ) continue;
  181. // 账号存在跳过
  182. if( $custom['external_userid'] ) {
  183. // 避免重复注册
  184. $customPhones[$value['phone']] = $custom['external_userid'];
  185. continue;
  186. }
  187. // 账号UID
  188. $uid = $custom['uid'];
  189. }
  190. }
  191. // 避免重复注册
  192. $customPhones[$value['phone']] = $value['external_userid'];
  193. // 修改
  194. $result = $uid ? $WorkExternalModel->query()->where([['external_userid','=',$value['external_userid']]])->update(['custom_uid'=>$uid,'update_time'=>$time]) : true;
  195. // 如果修改失败
  196. if( !$result ) continue;
  197. // 同步数量 +1
  198. $task['sync_total'] += 1;
  199. }
  200. // 如果没有下一页游标,标记任务完成
  201. if( !$task['cursor'] ) $task['status'] = 1;
  202. // 修改任务情况
  203. $Model->edit($task['id'],$task);
  204. // 解锁
  205. RedisLock::unlock('work:sync:task:id',$task['id']);
  206. }
  207. }