// +---------------------------------------------------------------------- namespace app\services\work; use app\dao\work\WorkClientDao; use app\jobs\work\WorkClientJob; use app\services\BaseServices; use app\services\user\label\UserLabelServices; use app\services\user\UserServices; use crmeb\services\wechat\config\WorkConfig; use crmeb\services\wechat\WechatResponse; use crmeb\services\wechat\Work; use crmeb\traits\ServicesTrait; use think\exception\ValidateException; use think\facade\Log; /** * 企业微信客户 * Class WorkClientServices * @package app\services\work * @mixin WorkClientDao */ class WorkClientServices extends BaseServices { use ServicesTrait; /** * WorkClientServices constructor. * @param WorkClientDao $dao */ public function __construct(WorkClientDao $dao) { $this->dao = $dao; } /** * @param array $where * @param array $field * @param bool $isPage * @return array */ public function getList(array $where, array $field = ['*'], bool $isPage = true) { $page = $limit = 0; if ($isPage) { [$page, $limit] = $this->getPageValue(); } $list = $this->dao->getDataList($where, $field, $page, $limit, 'create_time', [ 'followOne' => function ($query) { $query->with([ 'member' => function ($query) { $query->field(['userid', 'id', 'name', 'main_department']) ->with(['mastareDepartment']); } ])->field(['userid', 'client_id', 'state', 'id']); }, 'follow' => function ($query) { $query->field(['id', 'client_id'])->with(['tags']); }, ]); foreach ($list as &$item) { if (!empty($item['follow'])) { $tags = []; foreach ($item['follow'] as $value) { if (!empty($value['tags'])) { $tags = array_merge($tags, $value['tags']); } } $newTags = []; foreach ($tags as $tag) { if (!in_array($tag['tag_name'], array_column($newTags, 'tag_name'))) { $newTags[] = $tag; } } $item['followOne']['tags'] = $newTags; } } $count = $this->dao->count($where); return compact('list', 'count'); } /** * 自动同步客户 * @param int $page * @param string $cursor * @return bool */ public function authGetExternalcontact(int $page = 1, string $cursor = '') { /** @var WorkConfig $config */ $config = app()->make(WorkConfig::class); $corpId = $config->get('corpId'); if (!$corpId) { return true; } /** @var WorkMemberServices $memberService */ $memberService = app()->make(WorkMemberServices::class); $menmberList = $memberService->getDataList(['corp_id' => $corpId], ['userid'], $page, 10); //没有数据就返回成功 if (!$menmberList) { return true; } $userids = array_column($menmberList, 'userid'); $response = Work::getBatchClientList($userids, $cursor); $externalContactList = $response['external_contact_list'] ?? []; $external = []; $followUser = [];//内部人员跟踪 $externalUserids = [];//客户信息 $this->transaction(function () use ($externalContactList, $corpId, $externalUserids, $followUser, $external) { foreach ($externalContactList as $item) { $externalContact = $item['external_contact']; $unionid = $externalContact['unionid'] ?? ''; if (isset($externalContact['unionid'])) { unset($externalContact['unionid']); } $corpName = $corpFullName = $position = ''; if (isset($externalContact['corp_name'])) { $corpName = $externalContact['corp_name']; unset($externalContact['corp_name']); } if (isset($externalContact['corp_full_name'])) { $corpFullName = $externalContact['corp_full_name']; unset($externalContact['corp_full_name']); } if (isset($externalContact['position'])) { $position = $externalContact['position']; unset($externalContact['position']); } $externalContact['position'] = $position; $externalContact['external_profile'] = json_encode($externalContact['external_profile'] ?? []); $followUserData = [ 'userid' => $item['follow_info']['userid'], 'remark' => $item['follow_info']['remark'] ?? '', 'description' => $item['follow_info']['description'] ?? '', 'createtime' => $item['follow_info']['createtime'] ?? '', 'remark_corp_name' => $item['follow_info']['remark_corp_name'] ?? '', 'remark_mobiles' => json_encode($item['follow_info']['remark_mobiles'] ?? ''), 'add_way' => $item['follow_info']['add_way'] ?? '', 'oper_userid' => $item['follow_info']['oper_userid'] ?? '', 'create_time' => time(), 'tags' => [], ]; if (!empty($item['follow_info']['tag_id'])) { $tagRes = Work::getCorpTags($item['follow_info']['tag_id']); foreach ($tagRes['tag_group'] ?? [] as $group) { foreach ($group['tag'] as $tag) { $followUserData['tags'][] = [ 'group_name' => $group['group_name'] ?? '', 'tag_name' => $tag['name'] ?? '', 'type' => $tag['type'] ?? 1, 'tag_id' => $tag['id'], 'create_time' => time() ]; } } } $followUser[$externalContact['external_userid']] = $followUserData; $externalUserids[] = $externalContact['external_userid']; $externalUserid = $externalContact['external_userid']; $externalContact['corp_id'] = $corpId; $externalContact['unionid'] = $unionid; $externalContact['corp_name'] = $corpName; $externalContact['corp_full_name'] = $corpFullName; if ($this->dao->count(['external_userid' => $externalUserid, 'corp_id' => $corpId])) { unset($externalContact['external_userid']); $this->dao->update(['external_userid' => $externalUserid], $externalContact); } else { $externalContact['create_time'] = time(); $externalContact['update_time'] = time(); $external[] = $externalContact; } } if ($external) { $this->dao->saveAll($external); } $clientList = $this->dao->getColumn([['external_userid', 'in', $externalUserids], ['corp_id', '=', $corpId]], 'id', 'external_userid'); /** @var WorkClientFollowServices $followService */ $followService = app()->make(WorkClientFollowServices::class); if ($followUser) { /** @var WorkClientFollowTagsServices $tagService */ $tagService = app()->make(WorkClientFollowTagsServices::class); foreach ($followUser as $userid => $items) { $items['client_id'] = $clientList[$userid]; if (($id = $followService->value(['client_id' => $clientList[$userid], 'userid' => $items['userid']], 'id'))) { $followService->update($id, [ 'remark' => $items['remark'], 'description' => $items['description'], 'createtime' => $items['createtime'], 'remark_corp_name' => $items['remark_corp_name'], 'remark_mobiles' => $items['remark_mobiles'], 'add_way' => $items['add_way'], 'oper_userid' => $items['oper_userid'], ]); } else { $res = $followService->save($items); $id = $res->id; } if (!empty($items['tags'])) { $tagService->delete(['follow_id' => $id]); foreach ($items['tags'] as &$tag) { $tag['follow_id'] = $id; } $tagService->saveAll($items['tags']); } } } }); if (isset($response['next_cursor']) && $response['next_cursor']) { WorkClientJob::dispatchDo('authClient', [$page, $response['next_cursor'] ?? '']); } else if (count($userids) >= 10 && empty($response['next_cursor'])) { WorkClientJob::dispatchDo('authClient', [$page + 1, '']); } return true; } public function saveClientTags(array $tagGroup) { } /** * 创建客户 * @param array $payload * @return mixed */ public function createClient(array $payload) { $corpId = $payload['ToUserName'];//企业id $externalUserID = $payload['ExternalUserID'];//外部企业userid $state = $payload['State'] ?? '';//扫码值 $userId = $payload['UserID'];//成员userid //保存客户 $clientId = $this->saveOrUpdateClient($corpId, $externalUserID, $userId); //发送欢迎语 try { event('work.welcome', [$payload['WelcomeCode'] ?? '', $state, $clientId, $userId]); } catch (\Throwable $e) { Log::error([ 'message' => '发送欢迎语失败:' . $e->getMessage(), 'file' => $e->getFile(), 'line' => $e->getLine() ]); } //设置欢客户标签 try { event('work.label', [$state, $userId, $externalUserID]); } catch (\Throwable $e) { Log::error([ 'message' => '设置欢客户标签失败:' . $e->getMessage(), 'file' => $e->getFile(), 'line' => $e->getLine() ]); } //关联客户与商城用户 try { event('work.user', [$clientId]); } catch (\Throwable $e) { Log::error([ 'message' => '关联客户与商城用户失败:' . $e->getMessage(), 'file' => $e->getFile(), 'line' => $e->getLine() ]); } return $clientId; } /** * 更新客户信息 * @param array $payload * @return mixed */ public function updateClient(array $payload) { $corpId = $payload['ToUserName']; $externalUserID = $payload['ExternalUserID']; $userId = $payload['UserID'];//成员serid $clientId = $this->saveOrUpdateClient($corpId, $externalUserID, $userId); //关联客户与商城用户 try { event('work.user', [$clientId]); } catch (\Throwable $e) { Log::error([ 'message' => '关联客户与商城用户失败:' . $e->getMessage(), 'file' => $e->getFile(), 'line' => $e->getLine() ]); } return $clientId; } /** * 企业成员删除客户 * @param array $payload * @return bool * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\DbException * @throws \think\db\exception\ModelNotFoundException */ public function deleteClient(array $payload) { $corpId = $payload['ToUserName']; $externalUserID = $payload['ExternalUserID']; $userId = $payload['UserID'];//成员serid $clientInfo = $this->dao->get(['external_userid' => $externalUserID, 'corp_id' => $corpId], ['id']); if ($clientInfo) { $this->transaction(function () use ($clientInfo, $userId) { $this->dao->destroy($clientInfo->id); /** @var WorkClientFollowServices $followService */ $followService = app()->make(WorkClientFollowServices::class); $followService->update(['client_id' => $clientInfo->id, 'userid' => $userId], ['is_del_user' => 1]); }); } return true; } /** * 客户删除企业微信成员 * @param array $payload * @return bool * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\DbException * @throws \think\db\exception\ModelNotFoundException */ public function deleteFollowClient(array $payload) { $corpId = $payload['ToUserName']; $externalUserID = $payload['ExternalUserID']; $userId = $payload['UserID'];//成员serid $clientInfo = $this->dao->get(['external_userid' => $externalUserID, 'corp_id' => $corpId], ['id']); /** @var WorkClientFollowServices $followService */ $followService = app()->make(WorkClientFollowServices::class); if ($clientInfo) { $followService->update(['client_id' => $clientInfo->id, 'userid' => $userId], ['is_del_user' => 1]); } return true; } /** * 更新或者添加客户信息 * @param string $corpId * @param string $externalUserID * @param string $userId * @return mixed */ public function saveOrUpdateClient(string $corpId, string $externalUserID, string $userId) { $response = Work::getClientInfo($externalUserID); $externalContact = $response['external_contact'] ?? []; $followUser = $response['follow_user'] ?? []; $res = true; $externalContact['corp_id'] = $corpId; $externalContact['external_profile'] = json_encode($externalContact['external_profile'] ?? []); $clientId = $this->dao->value(['external_userid' => $externalContact['external_userid'], 'corp_id' => $corpId], 'id'); try { $clientId = $this->transaction(function () use ($userId, $res, $clientId, $externalContact, $followUser) { if ($clientId) { $this->dao->update($clientId, $externalContact); } else { $res = $this->dao->save($externalContact); $clientId = $res->id; } $userids = []; $res1 = false; foreach ($followUser as &$item) { $item['create_time'] = time(); if ($userId === $item['userid']) { $res1 = true; } $userids[] = $item['userid']; $item['client_id'] = $clientId; if (isset($item['wechat_channels'])) { unset($item['wechat_channels']); } } if (!$res1 && $userId) { $followUser[] = [ 'client_id' => $clientId, 'userid' => $userId, 'createtime' => time(), 'tags' => [] ]; } //添加了此外部联系人的企业成员 if ($followUser) { /** @var WorkClientFollowServices $followService */ $followService = app()->make(WorkClientFollowServices::class); /** @var WorkClientFollowTagsServices $tagService */ $tagService = app()->make(WorkClientFollowTagsServices::class); foreach ($followUser as $item) { if (($id = $followService->value(['client_id' => $clientId, 'userid' => $item['userid']], 'id'))) { $followService->update($id, [ 'remark' => $item['remark'], 'description' => $item['description'], 'remark_corp_name' => $item['remark_corp_name'] ?? '', 'add_way' => $item['add_way'] ?? '', 'oper_userid' => $item['oper_userid'] ?? '', ]); } else { $res = $followService->save($item); $id = $res->id; } $tagService->delete(['follow_id' => $id]); if (!empty($item['tags'])) { $tagsNews = []; foreach ($item['tags'] as $tag) { $tag['follow_id'] = $id; $tagsNews[] = $tag; } $tagService->saveAll($tagsNews); } } } if (!$res) { throw new ValidateException('保存失败'); } return $clientId; }); } catch (\Throwable $e) { Log::error([ 'message' => $e->getMessage(), 'file' => $e->getFile(), 'line' => $e->getLine() ]); } return $clientId; } /** * @param string $userid * @param array $clientInfo * @return array */ public function getClientInfo(string $userid, array $clientInfo) { $clientInfo['userInfo'] = []; if ($clientInfo['uid']) { /** @var UserServices $make */ $make = app()->make(UserServices::class); $userInfo = $make->get($clientInfo['uid'], ['*'], ['label', 'userGroup', 'spreadUser']); if ($userInfo) { $clientInfo['userInfo'] = $userInfo->toArray(); $clientInfo['userInfo']['birthday'] = $clientInfo['userInfo']['birthday'] ? date('Y-m-d', $clientInfo['userInfo']['birthday']) : ''; } } return $clientInfo; } /** * 异步批量设置标签 * @param array $addTag * @param array $removeTag * @param array $userId * @param array $where * @param int $isAll * @return bool */ public function synchBatchLabel(array $addTag, array $removeTag, array $userId, array $where, int $isAll = 0) { if ($isAll) { $clientList = $this->dao->getDataList($where, ['external_userid', 'id', 'unionid', 'uid'], 0, 0, null, ['followOne']); } else { $clientList = $this->dao->getDataList(['external_userid' => $userId], ['external_userid', 'id', 'unionid', 'uid'], 0, 0, null, ['followOne']); } $batchClient = []; foreach ($clientList as $item) { if (!empty($item['followOne'])) { $batchClient[] = [ 'external_userid' => $item['external_userid'], 'userid' => $item['followOne']['userid'], 'add_tag' => $addTag, 'remove_tag' => $removeTag, ]; } } if ($batchClient) { foreach ($batchClient as $item) { WorkClientJob::dispatchDo('setLabel', [$item]); } } return true; } /** * 设置客户标签 * @param array $markTag * @return WechatResponse|false */ public function setClientMarkTag(array $markTag) { try { $res = Work::markTags($markTag['userid'], $markTag['external_userid'], $markTag['add_tag'], $markTag['remove_tag']); $res = new WechatResponse($res); //同步标签后同步用户信息 /** @var WorkConfig $config */ $config = app()->make(WorkConfig::class); $corpId = $config->get('corpId'); WorkClientJob::dispatchSece(2, 'saveClientInfo', [$corpId, $markTag['external_userid'], $markTag['userid']]); return $res; } catch (\Throwable $e) { Log::error([ 'message' => '修改客户标签发生错误:' . $e->getMessage(), 'file' => $e->getFile(), 'line' => $e->getLine() ]); return false; } } /** * 查找成员下附带的客户人数 * @param array $where * @return int */ public function getUserIdsByCount(array $where) { if ($where['is_all']) { unset($where['time'], $where['label'], $where['notLabel']); } $where['timeKey'] = 'create_time'; if (!empty($where['label'])) { /** @var UserLabelServices $service */ $service = app()->make(UserLabelServices::class); $tagId = $service->getColumn([ ['id', 'in', $where['label']], ], 'tag_id'); $where['label'] = array_unique($tagId); } if (!empty($where['notLabel'])) { /** @var UserLabelServices $service */ $service = app()->make(UserLabelServices::class); $tagId = $service->getColumn([ ['id', 'in', $where['notLabel']], ], 'tag_id'); $where['notLabel'] = array_unique($tagId); } return $this->dao->getClientCount($where); } /** * 解绑用户 * @param int $uid */ public function unboundUser(int $uid) { try { $this->dao->update(['uid' => $uid], ['uid' => 0]); } catch (\Throwable $e) { Log::error([ 'message' => '解绑用户失败:' . $e->getMessage(), 'file' => $e->getFile(), 'line' => $e->getLine() ]); } } }