WorkSync.php 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. <?php namespace App\Http\Controllers\Admin;
  2. use App\Models\Custom;
  3. use App\Models\Work\Sync as Model;
  4. use App\Models\Work\Tag as WorkTag;
  5. use App\Models\Work\User as WorkUser;
  6. use App\Models\Work\External as WorkExternal;
  7. use App\Facades\Servers\Redis\RedisLock;
  8. use App\Facades\Servers\WechatWork\ExternalContact;
  9. /**
  10. * 客户同步
  11. *
  12. * @author 刘相欣
  13. *
  14. */
  15. class WorkSync extends Auth{
  16. protected function _initialize(){
  17. parent::_initialize();
  18. $this->assign('breadcrumb1','客户同步');
  19. $this->assign('breadcrumb2','同步任务');
  20. }
  21. /**
  22. * 列表页
  23. *
  24. * */
  25. public function index(Model $Model){
  26. // 接受参数
  27. // 查询条件
  28. $map = [];
  29. // 查询数据
  30. $list = $Model->query()->where($map)->orderByDesc('id')->paginate(config('page_num',10));
  31. // 分配数据
  32. $this->assign('empty', '<tr><td colspan="20">~~暂无数据</td></tr>');
  33. $this->assign('list',$list);
  34. // 加载模板
  35. return $this->fetch();
  36. }
  37. /**
  38. * 添加
  39. *
  40. * */
  41. public function add(Model $Model){
  42. // 接收数据
  43. $data['cursor'] = request('cursor','');
  44. $data['has_total'] = request('has_total',0);
  45. $data['sync_total'] = request('sync_total',0);
  46. $data['status'] = request('status',0);
  47. // 查询是否有进行中的任务
  48. $runing = $Model->query()->where([['status','=',0]])->value('id');
  49. // 如果操作失败
  50. if( $runing ) return json_send(['code'=>'error','msg'=>'请等待任务完成']);
  51. // 写入数据表
  52. $id = $Model->add($data);
  53. // 如果操作失败
  54. if( !$id ) return json_send(['code'=>'error','msg'=>'新增失败']);
  55. // 记录行为
  56. $this->addAdminHistory(admin('uid'),$Model->getTable(),$id,1,[],$data);
  57. // 告知结果
  58. return json_send(['code'=>'success','msg'=>'新增成功','path'=>'']);
  59. }
  60. /**
  61. * 仅取消
  62. *
  63. * */
  64. public function set_status(Model $Model){
  65. // 设置状态
  66. $id = request('id',0);
  67. $status = request('status',4);
  68. // 查询用户
  69. $oldData = $Model->where(['id'=>$id])->first();
  70. // 如果用户不存在
  71. if( !$oldData ) return json_send(['code'=>'error','msg'=>'任务不存在']);
  72. // 执行修改
  73. $result = $Model->edit($id,['status'=>$status]);
  74. // 提示新增失败
  75. if( !$result ) return json_send(['code'=>'error','msg'=>'设置失败']);
  76. // 记录行为
  77. $this->addAdminHistory(admin('uid'),$Model->getTable(),$id,2,$oldData,['status'=>$status]);
  78. // 告知结果
  79. return json_send(['code'=>'success','msg'=>'设置成功','path'=>'']);
  80. }
  81. /**
  82. * 执行任务
  83. *
  84. * */
  85. public function run_task(){
  86. // 实例
  87. $Model = New Model();
  88. // 获取数据
  89. $taskList = $Model->getList();
  90. // 如果没有任务列表,结束
  91. if( !$taskList ) return ['error'=>'无待执行任务'];
  92. // 如果没有任务列表,结束
  93. $task = array_pop($taskList);
  94. // 返回结果
  95. if( !$task ) return ['error'=>'无待执行任务'];
  96. // 异步锁上锁,失败结束
  97. if( !RedisLock::lock('work:sync:task:id',$task['id'],'180') ) return ['error'=>'任务执行中...'];
  98. // 获取接待人员
  99. $userIdList = ExternalContact::getFollowUsers();
  100. // 如果没有成员ID列表,结束
  101. if( !$userIdList ) {
  102. // 解锁
  103. RedisLock::unlock('work:sync:task:id',$task['id']);
  104. // 无需同步
  105. return ['error'=>'未获取到跟进人员'];
  106. }
  107. // 获取游标
  108. $cursor = $task['cursor'];
  109. // 批量获取客户详情
  110. $extUserList = ExternalContact::batchGetByUser($userIdList,$cursor,100);
  111. // 如果没有客户列表,结束
  112. if( !$extUserList ) {
  113. // 解锁
  114. RedisLock::unlock('work:sync:task:id',$task['id']);
  115. // 结束
  116. return ['error'=>'未获取到外部联系人'];
  117. }
  118. // 实例其他模型
  119. $CustomModel = New Custom();
  120. $WorkExternalModel = New WorkExternal();
  121. $WorkUserModel = New WorkUser();
  122. $WorkTagModel = New WorkTag();
  123. // 下一页游标
  124. $task['cursor'] = $extUserList['next_cursor'];
  125. // 外部联系人列表
  126. $extUserList = $extUserList['external_contact_list'];
  127. // 更新的数据
  128. $extUsers = [];
  129. $followUsers = [];
  130. $followTags = [];
  131. // 时间
  132. $time = time();
  133. // 循环处理
  134. foreach ( $extUserList as $key=>$value ) {
  135. // 外部联系人
  136. $extUser = [];
  137. $extUser['name'] = $value['external_contact']['name'];
  138. $extUser['avatar'] = str_ireplace('http://','https://',$value['external_contact']['avatar']);
  139. $extUser['gender'] = $value['external_contact']['gender'];
  140. $extUser['work_type'] = $value['external_contact']['type'];
  141. $extUser['external_userid'] = $value['external_contact']['external_userid'];
  142. $extUser['insert_time'] = $time;
  143. $extUser['update_time'] = $time;
  144. // 处理外部联系人
  145. $extUsers[] = $extUser;
  146. // 跟进客服
  147. $followUser = [];
  148. $followUser['external_userid'] = $extUser['external_userid'];
  149. $followUser['work_userid'] = $value['follow_info']['userid'];
  150. $followUser['remark'] = $value['follow_info']['remark'];
  151. $followUser['description'] = $value['follow_info']['description'];
  152. $followUser['insert_time'] = $time;
  153. $followUser['update_time'] = $time;
  154. $followUser['remark_mobiles'] = implode(',',$value['follow_info']['remark_mobiles']);
  155. $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'];
  156. $followUsers[] = $followUser;
  157. // 跟进人员标签组合
  158. foreach ( $value['follow_info']['tag_id'] as $tagId ) {
  159. // 重组
  160. $followTags[] = ['tag_id'=>$tagId,'external_userid'=>$followUser['external_userid'],'work_userid'=>$followUser['work_userid'],'update_time'=>$time];
  161. }
  162. // 跟进人员是否备注手机号
  163. $extUser['phone'] = $value['follow_info']['remark_mobiles'] ? $value['follow_info']['remark_mobiles'][0] : '';
  164. // 重组数据
  165. $extUserList[$key] = $extUser;
  166. }
  167. // 标签写入
  168. if( $followTags ) $WorkTagModel->query()->insert($followTags);
  169. // 需要更新的数据
  170. $WorkExternalModel->query()->upsert($extUsers,'external_userid',['name','avatar','gender','work_type','update_time']);
  171. // 需要更新的数据
  172. $WorkUserModel->query()->upsert($followUsers,['external_userid','work_userid'],['remark','description','remark_mobiles','remark_company','update_time']);
  173. // 获取外部联系人ID,并去重
  174. $customIds = array_values(array_unique(array_filter(array_column($extUserList,'external_userid'))));
  175. // 获取外部联系人ID,并去重
  176. $customPhones = array_values(array_unique(array_filter(array_column($extUserList,'phone'))));
  177. // 查询客户表中是否存在该客户
  178. $customIds = $customIds ? $WorkExternalModel->getPluckInFiled('external_userid',$customIds,'custom_uid','external_userid') : [];
  179. // 获取
  180. $customPhones = $customPhones ? $CustomModel->getPluckInFiled('phone',$customPhones,'external_userid','phone') : [];
  181. // 循环处理
  182. foreach ( $extUserList as $value ) {
  183. // 不存在外部联系人账号的跳过
  184. if( !isset($customIds[$value['external_userid']]) ) continue;
  185. // 存在在外部联系人账号但是绑定了账号的跳过
  186. if( $customIds[$value['external_userid']] ) continue;
  187. // 不存在手机号,跳过
  188. if( !$value['phone'] ) continue;
  189. // 如果绑定了其他外部联系人
  190. if( !empty($customPhones[$value['phone']]) ) continue;
  191. // 同步数量 +1
  192. $task['sync_total'] += 1;
  193. // 账号UID默认
  194. $uid = 0;
  195. // 账号未注册
  196. if( !isset($customPhones[$value['phone']]) ) {
  197. // 注册账号
  198. $uid = $CustomModel->add(['phone'=>$value['phone'],'username'=>$value['name'],'userpic'=>$value['avatar'],'sex'=>$value['gender'],'external_userid'=>$value['external_userid']]);
  199. // 注册失败,
  200. if( !$uid ) continue;
  201. }else{
  202. // 已经注册的,未绑定外部联系人
  203. if( !$customPhones[$value['phone']] ) {
  204. // 查询号码
  205. $custom = $CustomModel->getOneByPhone($value['phone']);
  206. // 没有账号,跳过
  207. if( !$custom ) continue;
  208. // 账号存在跳过
  209. if( $custom['external_userid'] ) {
  210. // 避免重复注册
  211. $customPhones[$value['phone']] = $custom['external_userid'];
  212. continue;
  213. }
  214. // 账号UID
  215. $uid = $custom['uid'];
  216. }
  217. }
  218. // 避免重复注册
  219. $customPhones[$value['phone']] = $value['external_userid'];
  220. // 修改
  221. $result = $uid ? $WorkExternalModel->query()->where([['external_userid','=',$value['external_userid']]])->update(['custom_uid'=>$uid,'update_time'=>$time]) : true;
  222. // 如果修改失败
  223. if( !$result ) continue;
  224. }
  225. // 如果没有下一页游标,标记任务完成
  226. if( !$task['cursor'] ) $task['status'] = 1;
  227. // 修改任务情况
  228. $Model->edit($task['id'],$task);
  229. // 解锁
  230. RedisLock::unlock('work:sync:task:id',$task['id']);
  231. // 结束
  232. return ['success'=>'批量成功=>'.$task['sync_total']];
  233. }
  234. }