WorkSync.php 7.3 KB

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