where('user_id', $handoverUserId) ->where('corpid', $corpid) ->where('enable', 1) ->first(); if(empty($user) || (isset($user->status) && $user->status != 5)) { return ['原跟进员工需为离职状态', 3003]; } } $record = CustomerAssignmentTotal::query() ->create([ 'corpid' => $corpid, 'handover_userid' => $handoverUserId, 'takeover_userid' => $takeoverUserId, 'transfer_success_msg' => $transferSuccessMsg, 'external_userid' => json_encode($externalUserIdList), 'type' => $type, 'select_all' => $selectAll, 'status' => 1, ]); return isset($record->id) ? ['申请成功', 0] : ['申请失败', 400]; } /** * 返回客户来源列表 * @return array */ public static function addWayList() { $arr = [ ['key' => 0 , 'val' => '未知来源'], ['key' => 1 , 'val' => '扫描二维码'], ['key' => 2 , 'val' => '搜索手机号'], ['key' => 3 , 'val' => '名片分享'], ['key' => 4 , 'val' => '群聊'], ['key' => 5 , 'val' => '手机通讯录'], ['key' => 6 , 'val' => '微信联系人'], ['key' => 8 , 'val' => '安装第三方应用时自动添加的客服人员'], ['key' => 9 , 'val' => '搜索邮箱'], ['key' => 10 , 'val' => '视频号添加'], ['key' => 11 , 'val' => '通过日程参与人添加'], ['key' => 12 , 'val' => '通过会议参与人添加'], ['key' => 13 , 'val' => '添加微信好友对应的企业微信'], ['key' => 14 , 'val' => '通过智慧硬件专属客服添加'], ['key' => 15 , 'val' => '通过上门服务客服添加'], ['key' => 16 , 'val' => '通过获客链接添加'], ['key' => 17 , 'val' => '通过定制开发添加'], ['key' => 18 , 'val' => '通过需求回复添加'], ['key' => 201 , 'val' => '内部成员共享'], ['key' => 202 , 'val' => '管理员/负责人分配'], ]; return $arr; } // 客户管理列表 public static function customerList($search, $page, $pageSize, $source) { $extra = ''; // 当用户筛选了客户关注起止时间时,返回列表中客户对应的客服列表 $customerQuery = CustomerDetails::getCustomerBySearchNew($search, $source); $corpid = $search['corpid']; $customerRelationCount = clone $customerQuery; $followCount = $customerRelationCount->selectRaw('count(distinct(`con_user_cus`)) as count')->first(); $followCount = $followCount->count; $customerQueryCount = clone $customerQuery; $count = $customerQueryCount->selectRaw('count(distinct(`external_userid`)) as count')->first(); $count = $count->count; $customerLossQ = clone $customerQuery; $lossCountInfo = $customerLossQ->where('loss_status', 0)->selectRaw('count(distinct(`external_userid`)) as count')->first(); $loss_count = $lossCountInfo->count ?? 0; if($search['add_date_start'] && $search['add_date_end']) { $userListQuery = clone $customerQuery; $userIdList = $userListQuery->selectRaw('distinct(user_id) as user_id')->pluck('user_id'); if($userIdList->isNotEmpty()) { $userNameList = DjUser::select('name')->whereIn('user_id', $userIdList)->where('corpid', $corpid)->pluck('name'); $extra = implode(',', $userNameList->toArray()); } } if($pageSize == 20000) $pageSize = 100000; // 临时修改,增加业务导出量 $offset = ($page - 1) * $pageSize; $data = $customerQuery->selectRaw("customer_id, name, gender, loss_time, external_userid, user_id, remark, createtime, add_way, corpid, pay_num, loss_status as relation_enable, blacklist_status, con_user_cus, tag_list, loss_time, is_new_customer_no_loss, retained_status") ->groupBy('con_user_cus') ->orderBy('createtime', 'desc') ->offset($offset) ->limit($pageSize) ->get() ->toArray(); // 提取客户id列表 $customerIdList = array_column($data, 'customer_id'); // 获取客户基础信息 $customerDataList = Customer::suffix($corpid) ->where('corpid', $corpid) ->whereIn('id', $customerIdList) ->get() ->keyBy('id') ->toArray(); $insideUserIdList = array_unique(array_column($data, 'user_id')); // 查询客服基本信息 $insideUserDataList = DjUser::query() ->select(['user_id', 'name', 'open_user_id', 'avatar', 'avatar', 'department']) ->whereIn('user_id', $insideUserIdList) // ->where('enable', 1) ->where('corpid', $corpid) ->get() ->keyBy('user_id') ->toArray(); $tagList = Tag::query() ->where('corpid', $corpid) ->where('enable', 1) ->get() ->keyBy('tag_md5') ->toArray(); // 查询部门列表 $departmentList = DjDepartment::query() ->selectRaw('department_id, name as department_name') ->where('enable', 1) ->where('corpid', $corpid) ->get() ->keyBy('department_id') ->toArray(); // 获取添加渠道数据 $addWayData = self::addWayList(); $addWayData = array_column($addWayData, null, 'key'); // 循环将数据补充 foreach($data as $key => $value) { $customerInfo = isset($customerDataList[$value['customer_id']]) ? $customerDataList[$value['customer_id']] : []; $customerTag = []; $customerTagList = empty($value['tag_list']) ? [] : explode(',', $value['tag_list']); foreach($customerTagList as $tagId) { $tagName = isset($tagList[$tagId]['tag_name']) ? $tagList[$tagId]['tag_name'] : ''; if(!empty($tagName)) { $customerTag[] = $tagName; } } $data[$key]['type'] = isset($customerInfo['type']) ? $customerInfo['type'] : 0; $data[$key]['avatar'] = isset($customerInfo['avatar']) ? $customerInfo['avatar'] : 0; $customerServiceData = []; $departmentData = null; $userId = $value['user_id']; if(isset($insideUserDataList[$userId])) { $customerServiceData = $insideUserDataList[$userId]; $departmentIdData = explode(',', $insideUserDataList[$userId]['department']); foreach ($departmentIdData as $item) { $departmentData = isset($departmentList[$item]['department_name']) ? $departmentList[$item]['department_name'] : ''; } } $data[$key]['user_list'] = $customerServiceData; $data[$key]['department_list'] = [$departmentData]; $data[$key]['tag_list'] = $customerTag; $data[$key]['createtime'] = date('Y-m-d H:i', $value['createtime']); $data[$key]['add_way'] = isset($addWayData[$value['add_way']]['val']) ? $addWayData[$value['add_way']]['val'] : ''; } $excludeCount = $followCount - $count; return [['list' => $data, 'count' => $count, 'exclude_count' => $excludeCount, 'cust_loss_uc' => $loss_count], $followCount, $extra]; } // 客户订单列表 public static function customerOrderList($corpid, $customerId, $page, $pageSize) { $offset = ($page - 1) * $pageSize; // 获取客户的外部联系人id $externalUserId = Customer::suffix($corpid) ->where('corpid', $corpid) ->where('id', $customerId) ->first(); $externalUserId = isset($externalUserId->external_userid) ? $externalUserId->external_userid : null; if(empty($externalUserId)) { return [[], 0]; } $query = DjOrder::query() ->select(['order_id', 'pay_money', 'created_ts', 'pay_status', 'playlet_name', 'order_type', 'bind_app_id' , 'adq_account_id', 'origin_pay_money', 'pay_type']) ->where('system_corpid', $corpid) ->where('pay_status', 1) ->where('external_userid', $externalUserId); $count = $query->count(); $data = $query->orderBy('created_ts', 'desc') ->offset($offset) ->limit($pageSize) ->get() ->toArray(); # 提取公众号APPID $appIdList = array_column($data, 'bind_app_id'); $appList = OfficialAccount::query()->select(['mp_name', 'mp_app_id'])->whereIn('mp_app_id', $appIdList)->get(); // 循环将数据格式化 foreach($data as $key => $value) { $data[$key]['pay_money'] = round($value['pay_money']/10000, 2); $data[$key]['origin_pay_money'] = round($value['origin_pay_money']/10000, 2); $data[$key]['created_ts'] = date('Y-m-d H:i', round($value['created_ts']/1000, 0)); # 投放账号 if(1 == $value['order_type']) { # 公众号 $wxAccountInfo = $appList->where('mp_app_id', $value['bind_app_id'])->first(); $data[$key]['launch_account'] = isset($wxAccountInfo->mp_name) ? $wxAccountInfo->mp_name : '-'; } else { $data[$key]['launch_account'] = $value['adq_account_id']; } $payType = $value['pay_type'] == 1 ? '小程序虚拟支付' : '其他类型支付'; $data[$key]['pay_type'] = $payType; } return [$data, $count]; } // 客户概览(废弃) public static function customerDetail($corpid, $customerId, $userId) { // 查询客户基础信息 $customerInfo = Customer::suffix($corpid) ->select(['external_userid', 'name', 'avatar', 'type', 'gender', 'e_weibo', 'e_company', 'e_source', 'e_qq', 'e_position', 'e_phone', 'e_email', 'e_desc', 'e_birthday', 'e_age', 'e_address']) ->selectRaw('id as customer_id') ->where('id', $customerId) ->where('corpid', $corpid) // ->where('enable', 1) ->first(); if(empty($customerInfo)) { $requestData = [ 'corpid' => $corpid, 'customer_id' => $customerId, 'user_id' => $userId, ]; Log::logInfo('customerDetail 数据为空 request:'.json_encode($requestData, JSON_UNESCAPED_UNICODE), [], 'interface'); return ['数据为空', 3002]; } $customerInfo = json_decode(json_encode($customerInfo), 1); $customerInfo['e_birthday'] = !empty($customerInfo['e_birthday']) ? date('Y-m-d', strtotime($customerInfo['e_birthday'])) : null; // 查询客户跟进信息 $followList = CustomerDetails::suffix($corpid) ->select(['user_id', 'add_way', 'createtime', 'remark', 'tag_list']) ->where('corpid', $corpid) ->where('external_userid', $customerInfo['external_userid']) ->where('user_id', $userId) ->orderBy('loss_status', 'desc') ->first(); $tagIdList = empty($followList->tag_list) ? [] : explode(',', $followList->tag_list); if(!empty($tagIdList)) { $tagList = Tag::query() ->whereIn('tag_md5', $tagIdList) ->where('corpid', $corpid) ->where('enable', 1) ->get() ->toArray(); $customerInfo['tag_list'] = array_column($tagList, 'tag_name'); } else { $customerInfo['tag_list'] = []; } // 提取跟进信息中的客服id $userDataList = DjUser::query() ->select(['user_id', 'name', 'avatar']) // ->where('enable', 1) ->where('user_id', $userId) ->where('corpid', $corpid) ->first(); $userDataList = !empty($userDataList) ? $userDataList->toArray() : []; // 获取添加渠道数据 $addWayData = self::addWayList(); $addWayData = array_column($addWayData, null, 'key'); $followList = empty($followList) ? [] : json_decode(json_encode($followList), 1); $followList['user_name'] = isset($userDataList['name']) ? $userDataList['name'] : ''; $followList['avatar'] = isset($userDataList['avatar']) ? $userDataList['avatar'] : ''; $followList['createtime'] = isset($followList['createtime']) ? date('Y-m-d H:i', $followList['createtime']) : null; $followList['add_way'] = (isset($followList['add_way']) && isset($addWayData[$followList['add_way']]['val'])) ? $addWayData[$followList['add_way']]['val'] : ''; $customerInfo['follow_list'] = $followList; return [$customerInfo, 0]; } // 客户概览 public static function customerDetails($corpid, $customerId) { // 查询客户基础信息 $customerInfo = Customer::suffix($corpid) ->select(['external_userid', 'name', 'avatar', 'type', 'gender', 'e_weibo', 'e_company', 'e_source', 'e_qq', 'e_position', 'e_phone', 'e_email', 'e_desc', 'e_birthday', 'e_age', 'e_address']) ->selectRaw('id as customer_id') ->where('id', $customerId) ->where('corpid', $corpid) // ->where('enable', 1) ->first(); if(empty($customerInfo)) { $requestData = [ 'corpid' => $corpid, 'customer_id' => $customerId, ]; Log::logInfo('customerDetails 数据为空 request:'.json_encode($requestData, JSON_UNESCAPED_UNICODE), [], 'interface'); return ['数据为空', 3002]; } $customerInfo = json_decode(json_encode($customerInfo), 1); $customerInfo['e_birthday'] = !empty($customerInfo['e_birthday']) ? date('Y-m-d', strtotime($customerInfo['e_birthday'])) : null; // 查询客户跟进信息 $followList = CustomerDetails::suffix($corpid) ->select(['user_id', 'add_way', 'createtime', 'remark', 'tag_list']) ->where('corpid', $corpid) ->where('external_userid', $customerInfo['external_userid']) ->where('loss_status', 1) ->orderBy('loss_status', 'desc') ->get(); $userTagIdList = $allTagIdList = $userList = []; if($followList->isNotEmpty()) { foreach($followList as $followInfo) { $tagIdList = empty($followInfo->tag_list) ? [] : explode(',', $followInfo->tag_list); $userTagIdList[$followInfo['user_id']] = $tagIdList; $allTagIdList = array_merge($allTagIdList, $tagIdList); $userList[] = $followInfo['user_id']; } $allTagIdList = array_unique($allTagIdList); } $userTagList = []; if(!empty($allTagIdList)) { $tagList = Tag::query() ->whereIn('tag_md5', $allTagIdList) ->where('corpid', $corpid) ->where('enable', 1) ->get(); foreach($userTagIdList as $userId => $userTag) { $userTagList[$userId] = $tagList->whereIn('tag_md5', $userTag)->pluck('tag_name'); } } // 提取跟进信息中的客服id $userDataList = DjUser::query() ->select(['user_id', 'name', 'avatar']) // ->where('enable', 1) ->whereIn('user_id', $userList) ->where('corpid', $corpid) ->get() ->toArray(); // 获取添加渠道数据 $addWayData = self::addWayList(); $addWayData = array_column($addWayData, null, 'key'); foreach($userDataList as $userData) { $item['user_name'] = isset($userData['name']) ? $userData['name'] : ''; $item['avatar'] = isset($userData['avatar']) ? $userData['avatar'] : ''; $followData = $followList->where('user_id', $userData['user_id'])->first(); $item['createtime'] = date('Y-m-d H:i', $followData->createtime); $item['add_way'] = isset($addWayData[$followData->add_way]['val']) ? $addWayData[$followData->add_way]['val'] : ''; $item['remark'] = isset($followData->remark) ? $followData->remark : ''; $item['user_id'] = $userData['user_id']; $item['tag_list'] = isset($userTagList[$userData['user_id']]) ? $userTagList[$userData['user_id']] : []; $customerInfo['follow_list'][] = $item; } return [$customerInfo, 0]; } // 客户详情信息编辑 public static function customerInfoUpdate($corpid, $customerId, $params) { $res = Customer::suffix($corpid) ->where('corpid', $corpid) ->where('id', $customerId) ->update($params); $requestData = [ 'corpid' => $corpid, 'customer_id' => $customerId, 'params' => $params, ]; if($res > 0) { // Log::logInfo('customerInfoUpdate 编辑成功, request:'.json_encode($requestData, JSON_UNESCAPED_UNICODE), [], 'interface'); return ['编辑成功', 0]; } else { Log::logInfo('customerInfoUpdate 编辑失败, request:'.json_encode($requestData, JSON_UNESCAPED_UNICODE), [], 'interface'); return ['编辑失败', 400]; } } public static function moveCustomerToBlackList($corpid, $customerId, $userId, $reason) { // 获取客户的外部联系人id $customerInfo = Customer::getCustomerInfoById($corpid, $customerId); $customerInfo = json_decode(json_encode($customerInfo), 1); $externalUserId = $customerInfo['external_userid']; $operUserID = Auth::id(); // 开启事务 \DB::begintransaction(); $recordRes = BlackListRecord::query() ->updateOrCreate([ 'corpid' => $corpid, 'user_id' => $userId, 'customer_id' => $customerId ], [ 'external_userid' => $externalUserId, 'oper_user_id' => $operUserID, 'enable' => 1, 'reason' => $reason, ]); $relationRes = CustomerDetails::suffix($corpid) ->where('user_id', $userId) ->where('corpid', $corpid) ->where('external_userid', $externalUserId) ->update(['blacklist_status' => 1]); CustomerDynamic::customerDynamicSave($corpid, $externalUserId, $userId, 6); # 给客户添加黑名单用户标签 RedisModel::lPush(CustomerTagService::CUSTOMER_TAG_MARK_RDS, json_encode([ 'corpid' => $corpid, 'user_id' => $userId, 'external_userid' => $externalUserId, 'type' => 2, 'tag_group_name' => '猎羽', 'tag_name_list' => ['黑名单客户'] ], 256)); $requestData = [ 'corpid' => $corpid, 'customer_id' => $customerId, 'user_id' => $userId, 'reason' => $reason ]; if($relationRes > 0 && (isset($recordRes->id) && $relationRes > 0)) { \DB::commit(); // Log::logInfo('moveCustomerToBlackList 操作成功 request:'.json_encode($requestData, JSON_UNESCAPED_UNICODE), [], 'interface'); return ['操作成功', 0]; } else { \DB::rollBack(); Log::logInfo('moveCustomerToBlackList 操作失败 request:'.json_encode($requestData, JSON_UNESCAPED_UNICODE), [], 'interface'); return ['操作失败', 400]; } } public static function removeCustomerFromBlackList($corpid, $customerId, $userId) { // 获取客户的外部联系人id $customerInfo = Customer::getCustomerInfoById($corpid, $customerId); $customerInfo = json_decode(json_encode($customerInfo), 1); $externalUserId = $customerInfo['external_userid']; $operUserID = Auth::id(); // 开启事务 \DB::begintransaction(); $recordRes = BlackListRecord::query() ->updateOrCreate([ 'corpid' => $corpid, 'user_id' => $userId, 'customer_id' => $customerId ], [ 'external_userid' => $externalUserId, 'oper_user_id' => $operUserID, 'enable' => 0 ]); $relationRes = CustomerDetails::suffix($corpid) ->where('user_id', $userId) ->where('corpid', $corpid) ->where('external_userid', $externalUserId) ->update(['blacklist_status' => 0]); CustomerDynamic::customerDynamicSave($corpid, $externalUserId, $userId, 7); # 将客户黑名单标签取消(先查询黑名单标签ID,并且查看用户当前是否含有该标签) $tagGroupId = TagGroup::getGroupIdByGroupName($corpid, '猎羽'); if(!empty($tagGroupId)) { $tagInfoList = Tag::getTagInfoByTagGroup($corpid, $tagGroupId); $tagInfo = $tagInfoList->where('tag_name', '黑名单客户')->first(); $tagId = $tagInfo->tag_id ?? null; if (!empty($tagId)) { RedisModel::lPush(CustomerTagService::CUSTOMER_TAG_MARK_RDS, json_encode([ 'corpid' => $corpid, 'user_id' => $userId, 'external_userid' => $externalUserId, 'type' => 1, 'tag_group_id' => $tagGroupId, 'remove_tag_id_list' => [$tagId] ], 256)); } } $requestData = [ 'corpid' => $corpid, 'customer_id' => $customerId, 'user_id' => $userId ]; if($relationRes > 0 && (isset($recordRes->id) && $relationRes > 0)) { \DB::commit(); // Log::logInfo('removeCustomerFromBlackList 操作成功 request:'.json_encode($requestData, JSON_UNESCAPED_UNICODE), [], 'interface'); return ['操作成功', 0]; } else { \DB::rollBack(); Log::logInfo('removeCustomerFromBlackList 操作失败 request:'.json_encode($requestData, JSON_UNESCAPED_UNICODE), [], 'interface'); return ['操作失败', 400]; } } // 黑名单列表 public static function blackList($corpid, $addWay, $customerName, $adminId, $page, $pageSize) { $customerQuery = CustomerDetails::suffix($corpid) ->where('blacklist_status', 1) ->whereIn('loss_status', [0, 1, 2]); if(!empty($customerName)) { $customerQuery = $customerQuery->where('name', 'like', '%'.$customerName.'%');} if(is_numeric($addWay)) { $customerQuery = $customerQuery->where('add_way', $addWay);} $customerQuery = $customerQuery->where('corpid', $corpid); $customerQueryCount = clone $customerQuery; $count = $customerQueryCount->selectRaw('count(distinct(`external_userid`)) as count')->first(); $count = $count->count; $offset = ($page - 1) * $pageSize; $data = $customerQuery->selectRaw('customer_id, name, enable as relation_enable, loss_time, external_userid, user_id, remark, createtime, add_way, blacklist_status, con_user_cus') ->groupBy('con_user_cus') ->offset($offset) ->limit($pageSize) ->get() ->toArray(); // 提取客户id列表 $customerIdList = array_column($data, 'customer_id'); // 获取客户基础信息 $customerDataList = Customer::suffix($corpid) ->where('corpid', $corpid) ->whereIn('id', $customerIdList) ->get() ->keyBy('id') ->toArray(); // 提取客服id列表 $insideUserIdList = array_unique(array_column($data, 'user_id')); // 查询客户对应的操作记录 $blackListRecord = BlackListRecord::query() ->whereIn('customer_id', $customerIdList) ->where('enable', 1) ->where('corpid', $corpid) ->get() ->toArray(); $blackListData = []; foreach($blackListRecord as $item) { $key = $item['customer_id'].'-'.$item['user_id']; $blackListData[$key] = $item; } // 查询客服基本信息 $insideUserDataList = DjUser::query() ->select(['user_id', 'name', 'open_user_id', 'avatar', 'avatar', 'department']) ->whereIn('user_id', $insideUserIdList) // ->where('enable', 1) ->where('corpid', $corpid) ->get() ->keyBy('user_id') ->toArray(); // 获取添加渠道数据 $addWayData = self::addWayList(); $addWayData = array_column($addWayData, null, 'key'); // 循环将数据补充 foreach($data as $key => $value) { $k = $value['customer_id'].'-'.$value['user_id']; $blackList = isset($blackListData[$k]) ? $blackListData[$k] : []; $customerInfo = isset($customerDataList[$value['customer_id']]) ? $customerDataList[$value['customer_id']] : []; $customerServiceData = []; $userId = $value['user_id']; if(isset($insideUserDataList[$userId])) { $customerServiceData = $insideUserDataList[$userId]; } $data[$key]['type'] = isset($customerInfo['type']) ? $customerInfo['type'] : 0; $data[$key]['avatar'] = isset($customerInfo['avatar']) ? $customerInfo['avatar'] : ''; $data[$key]['reason'] = isset($blackList['reason']) ? $blackList['reason'] : ''; $data[$key]['operate_time'] = isset($blackList['create_time']) ? $blackList['create_time'] : ''; $data[$key]['user_list'] = $customerServiceData; $data[$key]['createtime'] = date('Y-m-d H:i', $value['createtime']); $data[$key]['add_way'] = isset($addWayData[$value['add_way']]['val']) ? $addWayData[$value['add_way']]['val'] : ''; } return [$data, $count]; } // 黑名单列表(新) public static function blackListNew($corpid, $addWay, $customerName, $adminId, $page, $pageSize) { $customerList = $customerIdList = null; if(!empty($addWay) || !empty($customerName)) { // 从客户关系表中查询符合条件的外部联系人id列表 $customerList = CustomerDetails::suffix($corpid) ->where('corpid', $corpid) ->where('blacklist_status', 1) ->whereIn('loss_status', [0, 1, 2]) ->where(function($query) use ($addWay, $customerName) { if($addWay) $query->where('add_way', $addWay); if($customerName) $query->where('customer_name', 'like', '%'.$customerName.'%'); })->get(); $customerIdList = $customerList->pluck('customer_id')->toArray(); } // 查询客户对应的操作记录 $blackListRecordQuery = BlackListRecord::query() ->where('enable', 1) ->where('corpid', $corpid); if(!is_null($customerIdList)) { $blackListRecordQuery->whereIn('customer_id', $customerIdList); } if($adminId) { $blackListRecordQuery->where('oper_user_id', $adminId); } $blackListRecordCountQuery = clone $blackListRecordQuery; $countRres = $blackListRecordCountQuery->selectRaw('count(distinct(customer_id)) as count')->first(); $count = !empty($countRres->count) ? $countRres->count : 0; $offset = ($page - 1) * $pageSize; $blackListRecordList = $blackListRecordQuery ->select(['user_id', 'customer_id', 'external_userid', 'oper_user_id', 'reason', 'create_time']) ->offset($offset) ->limit($pageSize) ->orderBy('id', 'desc') ->get(); $insideUserIdList = array_unique(array_column($blackListRecordList->toArray(), 'user_id')); $customerIds = array_unique(array_column($blackListRecordList->toArray(), 'customer_id')); $operUserIds = array_unique(array_column($blackListRecordList->toArray(), 'oper_user_id')); // 查询客服基本信息 $insideUserDataList = DjUser::query() ->select(['user_id', 'name', 'open_user_id', 'avatar', 'avatar', 'department']) ->whereIn('user_id', $insideUserIdList) // ->where('enable', 1) ->where('corpid', $corpid) ->get(); // 获取添加渠道数据 $addWayData = self::addWayList(); $addWayData = array_column($addWayData, null, 'key'); // 获取客户基础信息 $customerDataList = Customer::suffix($corpid) // ->where('corpid', $corpid) ->whereIn('id', $customerIds) ->get(); // 获取操作用户信息 $users = Users::query() ->whereIn('id', $operUserIds) ->get(); if(empty($customerList)) { $customerList = CustomerDetails::suffix($corpid) ->where('blacklist_status', 1) ->whereIn('loss_status', [0, 1, 2]) ->where('corpid', $corpid) ->whereIn('customer_id', $customerIds) ->get(); } foreach($blackListRecordList as &$blackList) { # 客户详细信息 添加渠道,客户状态,添加时间 $customerDetails = !empty($customerList) ? $customerList->where('user_id', $blackList->user_id) ->where('external_userid', $blackList->external_userid)->first() : null; # 客户信息 头像,昵称,来源 $customer = $customerDataList->where('id', $blackList->customer_id)->first(); # 客服信息 昵称 $user = $insideUserDataList->where('user_id', $blackList->user_id)->first(); # 操作人信息 $operUser = $users->where('id', $blackList->oper_user_id)->first(); $blackList->type = !empty($customer) ? $customer->type : 0; $blackList->avatar = !empty($customer) ? $customer->avatar : ''; $blackList->name = !empty($customer) ? $customer->name : ''; $blackList->operate_time = $blackList->create_time; $blackList->user_list = $user; $blackList->createtime = !empty($customerDetails) ? date('Y-m-d H:i', $customerDetails->createtime) : ''; $blackList->add_way = !empty($addWayData[$customerDetails->add_way]) ? $addWayData[$customerDetails->add_way]['val'] : ''; $blackList->oper_user = !empty($operUser) ? $operUser->name : ''; $blackList->blacklist_status = 1; $blackList->remark = !empty($customerDetails) ? $customerDetails->remark : ''; $blackList->relation_enable = !empty($customerDetails) ? $customerDetails->enable : 1; } return [$blackListRecordList, $count]; } /** * 待分配客户列表 * @param $customerName string 客户名称 * @param $userIdList string 客服user_id列表 * @param $addDateStart string 起始添加时间 * @param $addDateEnd string 截止添加时间 * @param $addWay int 添加渠道 * @param $payStatus int 付款状态 * @param $payNumMin int 最小付款次数 * @param $payNumMax int 最大付款次数 * @param $tagType int 标签筛选类型 0不筛选 1满足其一 2同时满足 3没有标签 * @param $tagIdList array 标签id列表 * @param $corpid string 企业id * @param $page * @param $pageSize * @return array */ public static function unassignedCustomerList( $customerName, $userIdList, $addDateStart, $addDateEnd, $addWay, $payStatus, $payNumMin, $payNumMax, $tagType, $tagIdList, $corpid, $page, $pageSize ) { $customerQuery = CustomerDetails::suffix($corpid) ->where('loss_status', 2) ->where('corpid', $corpid); if(!empty($customerName)) { $customerQuery = $customerQuery->where('name', 'like', '%'.$customerName.'%');} if(!empty($userIdList)) { $customerQuery = $customerQuery->whereIn('user_id', $userIdList);} if(!empty($addDateStart)) { $customerQuery = $customerQuery->where('createtime', '>=', strtotime($addDateStart . ' 00:00:00'));} if(!empty($addDateEnd)) { $customerQuery = $customerQuery->where('createtime', '<=', strtotime($addDateEnd . ' 23:59:59'));} if(is_numeric($addWay)) { $customerQuery = $customerQuery->where('add_way', $addWay);} // 付款状态,付款次数筛选 if(is_numeric($payStatus)) { if(0 == $payStatus) { $payNumMax=0; $payNumMin=0; } else { if(empty($payNumMin)) { $payNumMin = 1; } } if(is_numeric($payNumMax)) { $customerQuery = $customerQuery->where('pay_num', '<=', $payNumMax); } if(is_numeric($payNumMin)) { $customerQuery = $customerQuery->where('pay_num', '>=', $payNumMin); } } if(1 == $tagType) { $tagRaw = ''; foreach($tagIdList as $k=>$tagId) { $tagRaw .= $tagId; if($k < count($tagIdList) -1){ $tagRaw = $tagRaw.' '; } } $customerQuery = $customerQuery->whereRaw('match(`tag_list`) against ("'.$tagRaw.'" in boolean mode)'); } if(2 == $tagType) { $tagRaw = ''; foreach($tagIdList as $k=>$tagId) { $tagRaw .= '+'.$tagId; if($k < count($tagIdList) -1){ $tagRaw = $tagRaw.' '; } } $customerQuery = $customerQuery->whereRaw('match(`tag_list`) against ("'.$tagRaw.'" in boolean mode)'); } if(3 == $tagType) { $customerQuery = $customerQuery->whereNull('tag_list'); } $customerQueryCount = clone $customerQuery; $count = $customerQueryCount->selectRaw('count(distinct(`external_userid`)) as count')->first(); $count = $count->count; $offset = ($page - 1) * $pageSize; $data = $customerQuery->selectRaw('customer_id, name, gender, enable as relation_enable, external_userid, user_id, remark, createtime, add_way, corpid, pay_num, loss_time, blacklist_status, con_user_cus, tag_list') ->groupBy('con_user_cus') ->offset($offset) ->limit($pageSize) ->get() ->toArray(); // 提取客户id列表 $customerIdList = array_column($data, 'customer_id'); // 获取客户基础信息 $customerDataList = Customer::suffix($corpid) ->where('corpid', $corpid) ->whereIn('id', $customerIdList) ->get() ->keyBy('id') ->toArray(); $insideUserIdList = array_unique(array_column($data, 'user_id')); $tagList = Tag::query() ->where('corpid', $corpid) ->where('enable', 1) ->get() ->keyBy('tag_md5') ->toArray(); // 查询客服基本信息 $insideUserDataList = DjUser::query() ->select(['user_id', 'name', 'open_user_id', 'avatar', 'avatar', 'department']) ->whereIn('user_id', $insideUserIdList) // ->where('enable', 1) ->where('corpid', $corpid) ->get() ->keyBy('user_id') ->toArray(); // 获取添加渠道数据 $addWayData = self::addWayList(); $addWayData = array_column($addWayData, null, 'key'); // 查询部门列表 $departmentList = DjDepartment::query() ->selectRaw('department_id, name as department_name') ->where('enable', 1) ->where('corpid', $corpid) ->get() ->keyBy('department_id') ->toArray(); // 循环将数据补充 foreach($data as $key => $value) { $customerInfo = isset($customerDataList[$value['customer_id']]) ? $customerDataList[$value['customer_id']] : []; $customerServiceData = []; $departmentData = null; $userId = $value['user_id']; $customerTag = []; $customerTagList = empty($value['tag_list']) ? [] : explode(',', $value['tag_list']); foreach($customerTagList as $tagId) { $tagName = isset($tagList[$tagId]['tag_name']) ? $tagList[$tagId]['tag_name'] : ''; if(!empty($tagName)) { $customerTag[] = $tagName; } } $data[$key]['type'] = isset($customerInfo['type']) ? $customerInfo['type'] : 0; $data[$key]['avatar'] = isset($customerInfo['avatar']) ? $customerInfo['avatar'] : 0; if(isset($insideUserDataList[$userId])) { $customerServiceData = $insideUserDataList[$userId]; $departmentIdData = explode(',', $insideUserDataList[$userId]['department']); foreach($departmentIdData as $item) { $departmentData = isset($departmentList[$item]['department_name']) ? $departmentList[$item]['department_name'] : ''; } } $data[$key]['user_list'] = $customerServiceData; $data[$key]['department_list'] = [$departmentData]; $data[$key]['tag_list'] = $customerTag; $data[$key]['createtime'] = date('Y-m-d H:i', $value['createtime']); $data[$key]['add_way'] = isset($addWayData[$value['add_way']]['val']) ? $addWayData[$value['add_way']]['val'] : ''; } return [$data, $count]; } /** * 流失客户列表 * @param $userIdList array 客服user_id * @param $addDateStart string 起始添加时间 * @param $addDateEnd string 截止添加时间 * @param $lossDateStart string 起始流失时间 * @param $lossDateEnd string 截止流失时间 * @param $addDurationMin int 最小添加天数 * @param $addDurationMax int 最大添加天数 * @param $corpid string 企业id * @param $page * @param $pageSize * @return array */ public static function lossCustomerList( $userIdList, $addDateStart, $addDateEnd, $lossDateStart, $lossDateEnd, $addDurationMin, $addDurationMax, $corpid, $page, $pageSize ) { $customerQuery = CustomerDetails::suffix($corpid) ->where('loss_status', 0) ->where('corpid', $corpid); // 统一处理添加天数和添加时间 if(empty($addDateStart) && empty($addDateEnd) && !empty($addDurationMin) && !empty($addDurationMax)) { // 没有添加时间筛选,只有添加时长筛选 $addDateStart = date('Y-m-d', strtotime('-'.$addDurationMax.' days')); $addDateEnd = date('Y-m-d', strtotime('-'.$addDurationMin.' days')); } else if(!empty($addDateStart) && !empty($addDateEnd) && !empty($addDurationMin) && !empty($addDurationMax)) { // 既有添加时间筛选,又有添加时长筛选 $addDurationStatDate = date('Y-m-d', strtotime('-'.$addDurationMax.' days')); $addDurationEndDate = date('Y-m-d', strtotime('-'.$addDurationMin.' days')); if($addDurationStatDate > $addDateStart) $addDateStart = $addDurationStatDate; if($addDurationEndDate < $addDateEnd) $addDateEnd = $addDurationEndDate; if($addDateStart > $addDateEnd) return [[], 0]; } if(!empty($customerName)) { $customerQuery = $customerQuery->where('name', 'like', '%'.$customerName.'%');} if(!empty($userIdList)) { $customerQuery = $customerQuery->whereIn('user_id', $userIdList);} if(!empty($addDateStart)) { $customerQuery = $customerQuery->where('createtime', '>=', strtotime($addDateStart . ' 00:00:00'));} if(!empty($addDateEnd)) { $customerQuery = $customerQuery->where('createtime', '<=', strtotime($addDateEnd . ' 23:59:59'));} if(!empty($lossDateStart)) { $customerQuery = $customerQuery->where('loss_time', '>=', $lossDateStart.' 00:00:00');} if(!empty($lossDateEnd)) { $customerQuery = $customerQuery->where('loss_time', '<=', $lossDateEnd.' 23:59:59');} $customerQueryCount = clone $customerQuery; $count = $customerQueryCount->selectRaw('count(distinct(`external_userid`)) as count')->first(); $count = $count->count; $offset = ($page - 1) * $pageSize; $data = $customerQuery->selectRaw('customer_id, name, gender, loss_time, external_userid, user_id, remark, createtime, add_way, corpid, blacklist_status, loss_status as relation_enable, con_user_cus, tag_list') ->groupBy('con_user_cus') ->offset($offset) ->limit($pageSize) ->get() ->toArray(); // 提取客户id列表 $customerIdList = array_column($data, 'customer_id'); // 获取客户基础信息 $customerDataList = Customer::suffix($corpid) ->where('corpid', $corpid) ->whereIn('id', $customerIdList) ->get() ->keyBy('id') ->toArray(); $insideUserIdList = array_unique(array_column($data, 'user_id')); $tagList = Tag::query() ->where('corpid', $corpid) ->where('enable', 1) ->get() ->keyBy('tag_md5') ->toArray(); // 查询客服基本信息 $insideUserDataList = DjUser::query() ->select(['user_id', 'name', 'open_user_id', 'avatar', 'avatar', 'department']) ->whereIn('user_id', $insideUserIdList) // ->where('enable', 1) ->where('corpid', $corpid) ->get() ->keyBy('user_id') ->toArray(); // 获取添加渠道数据 $addWayData = self::addWayList(); $addWayData = array_column($addWayData, null, 'key'); // 查询部门列表 $departmentList = DjDepartment::query() ->selectRaw('department_id, name as department_name') ->where('enable', 1) ->where('corpid', $corpid) ->get() ->keyBy('department_id') ->toArray(); // 循环将数据补充 foreach($data as $key => $value) { $customerInfo = isset($customerDataList[$value['customer_id']]) ? $customerDataList[$value['customer_id']] : []; $customerTag = []; $customerTagList = empty($value['tag_list']) ? [] : explode(',', $value['tag_list']); foreach($customerTagList as $tagId) { $tagName = isset($tagList[$tagId]['tag_name']) ? $tagList[$tagId]['tag_name'] : ''; if(!empty($tagName)) { $customerTag[] = $tagName; } } $data[$key]['type'] = isset($customerInfo['type']) ? $customerInfo['type'] : 0; $data[$key]['avatar'] = isset($customerInfo['avatar']) ? $customerInfo['avatar'] : 0; $customerServiceData = []; $departmentData = null; $userId = $value['user_id']; if(isset($insideUserDataList[$userId])) { $customerServiceData = $insideUserDataList[$userId]; $departmentIdData = explode(',', $insideUserDataList[$userId]['department']); foreach($departmentIdData as $departmentId) { $departmentData = isset($departmentList[$departmentId]['department_name']) ? $departmentList[$departmentId]['department_name'] : ''; } } $data[$key]['user_list'] = $customerServiceData; $data[$key]['department_list'] = [$departmentData]; $data[$key]['tag_list'] = $customerTag; $data[$key]['createtime'] = date('Y-m-d H:i', $value['createtime']); $data[$key]['add_way'] = isset($addWayData[$value['add_way']]['val']) ? $addWayData[$value['add_way']]['val'] : ''; // 计算添加时长 $data[$key]['add_duration_days'] = floor((time() - $value['createtime']) / 86400); } return [$data, $count]; } /** * 客户分配记录 * @param $corpid string 企业id * @param $handoverUserId string 转接员工userId * @param $takeoverUserId string 接替员工userid * @param $assignmentDateStart string 起始接替时间 * @param $assignmentDateEnd string 截止接替时间 * @param $assignmentStatus int 接替状态 * @param $type int 接替类型 1在职 2离职 * @param $page * @param $pageSize * @return array */ public static function customerAssignmentRecordList( $corpid, $handoverUserId, $operatorId, $takeoverUserId, $assignmentDateStart, $assignmentDateEnd, $assignmentStatus, $type, $page, $pageSize ) { $customerAssignmentQuery = CustomerAssignmentTotal::query()->where('corpid', $corpid) ->where('enable', 1); if(!empty($assignmentDateStart)) { $customerAssignmentQuery = $customerAssignmentQuery->where('create_time', '>=', $assignmentDateStart.' 00:00:00'); } if(!empty($assignmentDateEnd)) { $customerAssignmentQuery = $customerAssignmentQuery->where('create_time', '<=', $assignmentDateEnd.' 23:59:59'); } if(!empty($type)) { $customerAssignmentQuery = $customerAssignmentQuery->where('type', $type); } if(!empty($handoverUserId)) { $customerAssignmentQuery = $customerAssignmentQuery->where('handover_userid', $handoverUserId); } if(!empty($takeoverUserId)) { $customerAssignmentQuery = $customerAssignmentQuery->where('takeover_userid', $takeoverUserId); } if(!empty($assignmentStatus)) { $customerAssignmentQuery = $customerAssignmentQuery->where('status', $assignmentStatus); } if(!empty($operatorId)) { $customerAssignmentQuery = $customerAssignmentQuery->where('operator_id', $operatorId); } $customerAssignmentCountQuery = clone $customerAssignmentQuery; $count = $customerAssignmentCountQuery->count(); $offset = ($page - 1) * $pageSize; $data = $customerAssignmentQuery->selectRaw('create_time, takeover_userid, status, type, corpid' . ',handover_userid, id as record_id, customer_number, operator_id')->orderBy('id', 'desc') ->offset($offset) ->limit($pageSize) ->get() ->toArray(); $takeOverUserIdList = array_unique(array_column($data, 'takeover_userid')); $handOverUserIdList = array_unique(array_column($data, 'handover_userid')); $userIdList = array_unique(array_merge($takeOverUserIdList, $handOverUserIdList)); $userInfoList = DjUser::query()->where('corpid', $corpid) ->whereIn('user_id', $userIdList)->get()->keyBy('user_id')->toArray(); $operatorIdList = array_unique(array_column($data, 'operator_id')); $operatorInfoList = Users::query()->whereIn('id', $operatorIdList) ->get()->keyBy('id')->toArray(); $errcodeConf = config('qyWechat.errcode'); foreach($data as $key => $value) { // 接替客服昵称 $data[$key]['takeover_username'] = isset($userInfoList[$value['takeover_userid']]['name']) ? $userInfoList[$value['takeover_userid']]['name'] : ''; // 迁出客服昵称 $data[$key]['handover_username'] = isset($userInfoList[$value['handover_userid']]['name']) ? $userInfoList[$value['handover_userid']]['name'] : ''; // 迁移失败原因展示 $data[$key]['err_msg'] = []; $errCodeList = CustomerAssignmentRecord::suffix($value['corpid'])->where('record_id', $value['record_id']) ->where('errcode', '!=', 0)->select('errcode')->get(); if($errCodeList->isNotEmpty()) { $errCodeList = $errCodeList->toArray(); foreach ($errCodeList as $errCode) { $errCode = $errCode['errcode']; $errMsg = $errcodeConf[$errCode] ?? null; $errMsg = $value['status'] == '-1' ? $errMsg : ('部分迁移失败由于'.$errMsg); if($errMsg && !in_array($errMsg, $data[$key]['err_msg'])) { $data[$key]['err_msg'][] = $errMsg; } } } // 创建人 $data[$key]['operator_name'] = isset($operatorInfoList[$value['operator_id']]['name']) ? $operatorInfoList[$value['operator_id']]['name'] : ''; } return [$data, $count]; } /** * 客户分配记录 * @param $corpid string 企业id * @param $customerName string 客户名称 * @param $recordId int 分配记录id * @param $assignmentDateStart string 起始接替时间 * @param $assignmentDateEnd string 截止接替时间 * @param $assignmentStatus int 接替状态 * @param $page * @param $pageSize * @return array */ public static function customerAssignmentList( $corpid, $customerName, $recordId, $assignmentDateStart, $assignmentDateEnd, $assignmentStatus, $page, $pageSize ) { $customerAssignmentQuery = CustomerAssignmentRecord::suffix($corpid) ->where('corpid', $corpid)->where('enable', 1)->where('record_id', $recordId); if(!empty($customerName)){ $customerAssignmentQuery = $customerAssignmentQuery->where('customer_name', 'like', '%'.$customerName.'%'); } if(!empty($assignmentDateStart)) { $customerAssignmentQuery = $customerAssignmentQuery->where('takeover_time', '>=', $assignmentDateStart.' 00:00:00'); } if(!empty($assignmentDateEnd)) { $customerAssignmentQuery = $customerAssignmentQuery->where('takeover_time', '<=', $assignmentDateEnd.' 23:59:59'); } if(!empty($assignmentStatus)) { if(2 == $assignmentStatus) { $customerAssignmentQuery = $customerAssignmentQuery->whereIn('status', [0, 2]); } else if(-1 == $assignmentStatus) { $customerAssignmentQuery = $customerAssignmentQuery->where('errcode', '>', 0); }else { $customerAssignmentQuery = $customerAssignmentQuery->where('status', $assignmentStatus); } } $customerAssignmentCountQuery = clone $customerAssignmentQuery; $count = $customerAssignmentCountQuery->count(); $offset = ($page - 1) * $pageSize; $data = $customerAssignmentQuery->select(['customer_name', 'takeover_userid', 'status', 'takeover_time', 'customer_id', 'corpid', 'errcode', 'handover_userid'])->orderBy('id', 'desc') ->offset($offset) ->limit($pageSize) ->get() ->toArray(); $takeOverUserIdList = array_unique(array_column($data, 'takeover_userid')); $handOverUserIdList = array_unique(array_column($data, 'handover_userid')); $userIdList = array_unique(array_merge($takeOverUserIdList, $handOverUserIdList)); $userInfoList = DjUser::query() ->where('corpid', $corpid) ->whereIn('user_id', $userIdList) ->get() ->keyBy('user_id') ->toArray(); $errcodeConf = config('qyWechat.errcode'); foreach($data as $key => $value) { if( 0 == $value['status']) { $data[$key]['status'] = 2; } $data[$key]['takeover_username'] = isset($userInfoList[$value['takeover_userid']]['name']) ? $userInfoList[$value['takeover_userid']]['name'] : ''; $data[$key]['handover_username'] = isset($userInfoList[$value['handover_userid']]['name']) ? $userInfoList[$value['handover_userid']]['name'] : ''; $data[$key]['err_msg'] = null; if(!empty($value['errcode'])) { $data[$key]['err_msg'] = $errcodeConf[$value['errcode']] ?? null; } } return [$data, $count]; } /** * 客户动态列表 * @param $corpid string 企业id * @param $customerId integer 客户id * @return array */ public static function customerDynamicList($corpid, $customerId) { // 根据客户id查询客户信息 $customerInfo = Customer::suffix($corpid) ->where('id', $customerId) ->first(); if(empty($customerInfo)) { return []; } $externalUserid = $customerInfo->external_userid; $data = CustomerDynamic::suffix($corpid) ->select(['type', 'handover_userid', 'takeover_userid', 'create_time', 'radar_name', 'request_id']) ->where('corpid', $corpid) ->where('external_userid', $externalUserid) ->orderBy('create_time', 'desc') ->get() ->toArray(); // 提取客服信息 $handOverUserIdList = array_column($data, 'handover_userid'); $takeOverUserIdList = array_column($data, 'takeover_userid'); $userIdList = array_unique(array_merge($handOverUserIdList, $takeOverUserIdList)); $userDataList = DjUser::query() ->select(['user_id', 'name']) ->whereIn('user_id', $userIdList) ->where('corpid', $corpid) ->get() ->keyBy('user_id') ->toArray(); // 提取雷达request_id $requestIdList = array_column($data, 'request_id'); $radarCustomerBehaviorList = RadarCustomerBehavior::query() ->whereIn('request_id', $requestIdList) ->get(); $weekName = array('星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'); $result = []; foreach($data as $key => $item) { $date = date('Y-m-d', strtotime($item['create_time'])); $item['customer_id'] = $customerInfo->id; $item['customer_name'] = $customerInfo->name; $value = $item; if(!isset($result[$date])) { $week = $weekName[date('w', strtotime($item['create_time']))]; $result[$date]['date'] = $date; $result[$date]['week'] = $week; } $value['time'] = date('H:i:s', strtotime($item['create_time'])); if(!empty($item['handover_userid'])) { $item['handover_username'] = isset($userDataList[$item['handover_userid']]['name']) ? $userDataList[$item['handover_userid']]['name'] : ''; } else { $item['handover_username'] = ''; } if(!empty($item['takeover_userid'])) { $item['takeover_username'] = isset($userDataList[$item['takeover_userid']]['name']) ? $userDataList[$item['takeover_userid']]['name'] : ''; } else { $item['takeover_username'] = ''; } switch($item['type']) { case 1: $value['type_desc'] = '添加好友'; $value['content'] = $item['customer_name'].'添加了'.$item['handover_username'].'为好友'; break; case 2: $value['type_desc'] = '被员工删除'; $value['content'] = $item['handover_username'].'将'.$item['customer_name'].'删除了'; break; case 3: $value['type_desc'] = '删除跟进客户'; $value['content'] = $item['customer_name'].'将'.$item['handover_username'].'删除了'; break; case 4: $value['type_desc'] = '客户转移'; $value['content'] = $item['customer_name'].'从'.$item['handover_username'].'迁移到了'. $item['takeover_username']; break; case 5: $value['type_desc'] = '客户下单'; $value['content'] = '客户'.$item['customer_name'].'下单了'; break; case 6: $value['type_desc'] = '加入黑名单'; $value['content'] = '将'.$item['customer_name'].'加入黑名单'; break; case 7: $value['type_desc'] = '移出黑名单'; $value['content'] = '将'.$item['customer_name'].'从黑名单中移除'; break; case 8: $value['type_desc'] = '聊天'; $value['content'] = $item['customer_name'].'与'.$item['handover_username'].'聊天了'; break; case 9: $value['type_desc'] = '查看智能雷达'; $radarCustomerBehaviorInfo = $radarCustomerBehaviorList->where('request_id', $item['request_id'])->first(); $second = !empty($radarCustomerBehaviorInfo->view_time) ? $radarCustomerBehaviorInfo->view_time : 0; $value['content'] = $item['customer_name'].'点击了【'.$item['radar_name'].'】雷达,浏览时长'.$second.'秒'; break; default: $value['type_desc'] = ''; $value['content'] = ''; break; } $result[$date]['sub'][] = $value; } return array_values($result); } /** * 客户详情-编辑标签时标签展示 * @param $corpid string 企业id * @param $customerId int 客户id * @param $userId string 客服user_id * @return array */ public static function customerDetailTagList($corpid, $customerId, $userId) { $followList = CustomerDetails::suffix($corpid) ->where('corpid', $corpid) ->where('customer_id', $customerId) ->where('user_id', $userId) ->where('loss_status', 1) ->first(); $tagIdList = empty($followList->tag_list) ? [] : explode(',', $followList->tag_list); // 获取企业下所有标签数据 $tagGroupList = TagGroup::query() ->where('corpid', $corpid) ->where('enable', 1) ->orderBy('order', 'asc') ->get() ->toArray(); $data = []; foreach($tagGroupList as $tagGroup) { $item = []; $item['group_id'] = $tagGroup['group_id']; $item['group_name'] = $tagGroup['group_name']; $tagList = Tag::query() ->select(['tag_name', 'tag_md5', 'order']) ->where('corpid', $corpid) ->where('enable', 1) ->where('group_id', $item['group_id']) ->get() ->toArray(); foreach($tagList as $k=>$v) { $tagList[$k]['tag_id'] = $v['tag_md5']; if(in_array($v['tag_md5'], $tagIdList)){ $tagList[$k]['selected'] = 1; } else { $tagList[$k]['selected'] = 0; } } $item['tag_list'] = $tagList; $item['tag_num'] = count($tagList); if($item['tag_num'] > 0) { $data[] = $item; } } return $data; } // 更新客户标签 public static function customerDetailTagUpdate($corpid, $externalUserId, $userId, $selectedTagIdList) { // 判断客户跟进关系状态是否支持打标签 $customerRelation = CustomerDetails::suffix($corpid) ->where('corpid', $corpid) ->where('external_userid', $externalUserId) ->where('user_id', $userId) ->where('enable', 1) ->where('loss_status', 1) ->first(); if(empty($customerRelation)) { // 已流失或者是待分配状态 因为没有客服跟进关系,所以不能调用企业微信打标签功能 return ['客户状态不可用,不可编辑标签', 2008]; } $tagIdList = Tag::query() ->where('corpid', $corpid) ->where('enable', 1) ->get() ->keyBy('tag_md5') ->toArray(); $customerTagIdList = empty($customerRelation->tag_list) ? [] : explode(',', $customerRelation->tag_list); $removeTagIdList = array_values(array_diff($customerTagIdList, $selectedTagIdList)); $addTagIdList = array_values(array_diff($selectedTagIdList, $customerTagIdList)); $newRemoveTagIdList = []; $newAddTagIdList = []; foreach ($removeTagIdList as $tagId) { if(!isset($tagIdList[$tagId]['tag_id'])) continue; $newRemoveTagIdList[] = $tagIdList[$tagId]['tag_id']; } foreach($addTagIdList as $tagId) { if(!isset($tagIdList[$tagId]['tag_id'])) continue; $newAddTagIdList[] = $tagIdList[$tagId]['tag_id']; } $accessToken = AuthorizeCorp::getAccessToken($corpid, '更新客户标签'); $url = 'https://qyapi.weixin.qq.com/cgi-bin/externalcontact/mark_tag?access_token='.$accessToken; $params['userid'] = $userId; $params['external_userid'] = $externalUserId; $params['add_tag'] = $newAddTagIdList; $params['remove_tag'] = $newRemoveTagIdList; $result = HttpService::httpPost($url, json_encode($params), true); $result= json_decode($result, 1); // Log::logInfo('编辑客户标签结果', [$result], 'mark_tag'); if(isset($result['errcode']) && $result['errcode'] == 0) { // 处理系统数据 // $res = self::updateCustomerTag($corpid, $externalUserId, $userId, $addTagIdList, $removeTagIdList); $res = TagService::updateLocalCustomerTagSecond($corpid, $userId, $externalUserId, $newAddTagIdList, $newRemoveTagIdList); if($res) { return ['编辑成功', 0]; } else { return ['编辑失败', 400]; } } else { if('84061' == $result['errcode']) { RedisModel::lPush(CustomerDetails::CUSTOMER_LOSS_INFO_RDS, json_encode([ 'corpid' => $corpid, 'user_id' => $userId, 'external_userid' => $externalUserId ], 256)); return ['编辑失败,客户关系不存在', 2011]; } if('40068' == $result['errcode']) { // 编辑标签ID不存在,报警 EmailQueue::rPush('编辑客户标签时,客户标签不存在', json_encode([ 'corpid' => $corpid,'user_id' => $userId, 'external_userid' => $externalUserId, 'add_tag' => $newAddTagIdList, 'remove_tag' => $newRemoveTagIdList ], 256), ['song.shen@kuxuan-inc.com'], '猎羽'); } Log::logError('单独编辑客户标签失败', [ 'params' => ['user_id' => $userId, 'corpid' => $corpid, 'external_userid' => $externalUserId , 'add_tag' => $newAddTagIdList, 'remove_tag' => $newRemoveTagIdList], 'result' => $result ], 'mark_tag'); // 记录 return ['编辑失败', 400]; } } public static function updateCustomerTag($corpid, $externalUserId, $userId, $addTagIdList, $removeTagIdList) { \DB::begintransaction(); if(!empty($removeTagIdList)) { $res1 = CustomerTag::suffix($corpid) ->where('corpid', $corpid) ->where('external_userid', $externalUserId) ->where('user_id', $userId) ->whereIn('tag_id', $removeTagIdList) ->update(['enable' => 0]); } else { $res1 = true; } if(!empty($addTagIdList)) { // 查询标签对应的标签名以及标签组名 $tagList = Tag::query() ->where('corpid', $corpid) ->whereIn('tag_id', $addTagIdList) ->get() ->keyBy('tag_id') ->toArray(); $groupIdList = array_unique(array_column($tagList, 'group_id')); $tagGroupList = TagGroup::query() ->where('corpid', $corpid) ->whereIn('group_id', $groupIdList) ->get() ->keyBy('group_id') ->toArray(); // 获取员工id $customeInfo = Customer::suffix($corpid) ->where('corpid', $corpid) ->where('external_userid', $externalUserId) ->first() ->toArray(); $createData = []; foreach($tagList as $tag) { $item['corpid'] = $corpid; $item['user_id'] = $userId; $item['customer_id'] = $customeInfo['id']; $item['external_userid'] = $externalUserId; $item['tag_id'] = $tag['tag_id']; $item['tag_name'] = $tag['tag_name']; $item['type'] = 1; $item['group_name'] = isset($tagGroupList[$tag['group_id']]['group_name']) ? $tagGroupList[$tag['group_id']]['group_name'] : ''; $createData[] = $item; } $res2 = CustomerTag::suffix($corpid) ->insert($createData); } else { $res2 = true; } if($res1 > 0 && $res2 > 0) { \DB::commit(); return true; } else { \DB::rollback(); return false; } } // 客户迁移 public static function addCustomerAssignmentNew( $corpid, $takeoverUserId, $externalUserList, $transferSuccessMsg, $type, $portraitInheritance, $selectAll, $filterCustomerList, $params ) { $requestData = [ 'corpid' => $corpid, 'takeover_userid' => $takeoverUserId, 'external_user_list' => $externalUserList, 'transfer_success_msg' => $transferSuccessMsg, 'type' => $type, 'portrait_inheritance' => $portraitInheritance, 'select_all' => $selectAll, 'filter_customer_list' => $filterCustomerList, 'params' => $params, ]; // 检测接替员工是否为在职状态 $takeoverUserInfo = DjUser::query()->where('user_id', $takeoverUserId)->where('corpid', $corpid) ->where('status', 1)->first(); if(empty($takeoverUserInfo)){ return ['接替员工状态不合法', 2012]; } if(1 == $selectAll) { $res = BatchTransferCustomer::query() ->insert([ 'corpid' => $corpid, 'params' => json_encode($params, JSON_UNESCAPED_UNICODE), 'takeover_userid' => $takeoverUserId, 'filter_customer_list' => json_encode($filterCustomerList, JSON_UNESCAPED_UNICODE), 'transfer_success_msg' => $transferSuccessMsg, 'portrait_inheritance' => $portraitInheritance, 'type' => $type, 'operator_id' => \Auth::id(), ]); if(isset($res)) { return ['申请成功', 0]; } else { Log::logInfo('addCustomerAssignmentNew 申请失败, params:'.json_encode($requestData, JSON_UNESCAPED_UNICODE), [], 'interface'); return ['申请失败', 400]; } } else { $handoverUserList = []; foreach($externalUserList as $data) { $handoverUserList[$data['handover_userid']][] = $data['external_userid']; } \DB::begintransaction(); foreach($handoverUserList as $handoverUserId => $externalUserIdList) { $enableExternalUserIdList = []; if(1 == $type) { // 检测接替员工是否为在职状态 $handoverUserInfo = DjUser::query()->where('user_id', $handoverUserId)->where('corpid', $corpid) ->where('status', 1)->first(); if(empty($handoverUserInfo)){ return ['迁出员工状态不合法', 2013]; } $enableExternalUserIdList = CustomerDetails::suffix($corpid) ->where('corpid', $corpid) ->where('user_id', $handoverUserId) ->whereIn('external_userid', $externalUserIdList) // ->where('loss_status', 1) ->get(); $enableExternalUserIdList = $enableExternalUserIdList->isNotEmpty() ? $enableExternalUserIdList->toArray() : []; $enableExternalUserIdList = array_column($enableExternalUserIdList, 'external_userid'); } else if(2 == $type) { // 检测接替员工是否为在职状态 $handoverUserInfo = DjUser::query()->where('user_id', $handoverUserId)->where('corpid', $corpid) ->where('status', 5)->first(); if(empty($handoverUserInfo)){ return ['迁出员工状态不合法', 2013]; } $enableExternalUserIdList = CustomerDetails::suffix($corpid) ->where('corpid', $corpid) ->where('user_id', $handoverUserId) ->whereIn('external_userid', $externalUserIdList) // ->where('loss_status', 2) ->get(); $enableExternalUserIdList = $enableExternalUserIdList->isNotEmpty() ? $enableExternalUserIdList->toArray() : []; $enableExternalUserIdList = array_column($enableExternalUserIdList, 'external_userid'); } if(count($enableExternalUserIdList) > 0) { $res = CustomerAssignmentTotal::query() ->insert([ 'corpid' => $corpid, 'handover_userid' => $handoverUserId, 'takeover_userid' => $takeoverUserId, 'transfer_success_msg' => $transferSuccessMsg, 'external_userid' => json_encode($enableExternalUserIdList), 'type' => $type, 'status' => 1, 'portrait_inheritance' => $portraitInheritance, 'operator_id' => \Auth::id(), 'customer_number' => count($enableExternalUserIdList) ]); if(!$res) { \DB::rollBack(); Log::logInfo('addCustomerAssignmentNew 申请失败, params:'.json_encode($requestData, JSON_UNESCAPED_UNICODE), [], 'interface'); return ['申请失败', 400]; } } } \DB::commit(); return ['申请成功', 0]; } } /** * 获取外部联系人信息 * */ public static function updateExternalInfo($corpid, $userId, $externalUserid, $state, $changeType) { $flag = true; $nextCursor = null; try { while($flag) { # 获取外部联系人详情 $externalUserData = ExternalContactService::getExternalContactDetail($corpid, $externalUserid, $nextCursor); if(empty($externalUserData)) { if($externalUserData === false) { Log::logError('外部联系人详情获取失败', [ 'corpid' => $corpid, 'user_id' => $userId, 'external_userid' => $externalUserid, 'state' => $state, 'change_type' => $changeType, 'nextCursor' => $nextCursor ], 'UpdateExternalContact'); } $flag = false; continue; } # 更新外部联系人信息至数据库 $customerId = 0; ExternalContactService::updateExternalContacts($externalUserData, $corpid, $userId, $state, $changeType, $customerId); if($customerId) { // $followInfo = [ // 'createtime' => time(), // 'userid' => $userId, // ]; // TagService::autoMarkCustomerAddDateTag($corpid, $customerId, $followInfo); if('add_external_contact' == $changeType) { # 设置自动标签 $tagNameList = [date('Y年m月')]; $redisArr = [ 'corpid' => $corpid, 'user_id' => $userId, 'external_userid' => $externalUserid, 'tag_group_name' => '自动标签', 'tag_name_list' => $tagNameList, 'type' => 2 ]; RedisModel::lPush(CustomerTagService::CUSTOMER_TAG_MARK_RDS, json_encode($redisArr, 1)); } } # 翻页查询外部联系人所有的关联员工 if(isset($externalUserData['next_cursor']) && !empty($externalUserData['next_cursor'])) { $nextCursor = $externalUserData['next_cursor']; } else { $flag = false; } } } catch (\Exception $e) { Log::logError('获取外部联系人详情', [ 'line' => $e->getLine(), 'msg' => $e->getMessage(), 'corpid' => $corpid, 'user_id' => $userId, 'external_userid' => $externalUserid, 'state' => $state, 'change_type' => $changeType, 'nextCursor' => $nextCursor ], 'UpdateExternalContact-Exception'); $flag = false; return false; } return true; } /** * 获取外部联系人信息 * */ public static function getCustomerInfo($corpid, $externalUserid, $userid) { return CustomerDetails::suffix($corpid) ->select(['name', 'remark']) ->where('user_id', $userid) ->where('external_userid', $externalUserid) ->where('loss_status', 1) ->first(); } /** * 获取待邀请入群的新用户 * */ public static function waitInvite($deviceId, $beginTime, $endTime, $retry, $requestCorpId, $customerNumber) { # 校验开始时间和结束时间,最大时间差不超过十分钟 $endTimestamps = strtotime($endTime); $beginTimestamps = strtotime($beginTime); if($endTimestamps - $beginTimestamps > 600) { $beginTimestamps = strtotime('-10 minute', $endTimestamps); } # 持续邀请客户入群任务单次最大请求次数配置 $maxRequestNum = 5; # 查询设备对应的企微及客服信息 $userList = AndroidBindCorp::select('corpid', 'user_id')->where('device_id', $deviceId) ->where('enable', 1)->where(function($query) use ($requestCorpId) { if($requestCorpId) $query->where('corpid', $requestCorpId); })->get(); if(empty($userList)) { Log::logError('此设备号未绑定任何企微信息', [ 'device_id' => $deviceId ], 'WaitInvite'); return []; } # 查询支持无障碍模式的企微列表 $corpIds = $userList->pluck('corpid'); $corpList = AuthorizeCorp::select('corpid', 'corp_name')->whereIn('corpid', $corpIds)->where('enable', 1)->get(); $data = []; # 查询企微和客服是否配置了邀请入群功能 foreach ($userList as $userInfo) { $corpid = $userInfo->corpid ?? null; $userId = $userInfo->user_id ?? null; if(!$corpid || !$userId) { Log::logError('检索待邀请入群的客服时存在异常数据', [ 'user_info' => $userInfo->toArray(), 'device_id' => $deviceId ], 'WaitInvite'); continue; } # 使用更新时间最近的配置 $inviteConfig = InviteChatGroupRule::where('corpid', $corpid) ->whereRaw("FIND_IN_SET('".$userId."', `users`)") ->where('status', 1)->where('enable', 1) ->orderBy('updated_at', 'desc') ->first(); if(empty($inviteConfig)) { $inviteConfig = InviteChatGroupRule::where('corpid', $corpid) ->where('is_for_all', 1) ->where('enable', 1)->where('status', 1) ->orderBy('updated_at', 'desc') ->first(); } if(empty($inviteConfig)) { Log::logError('客服暂未配置邀请入群规则', [ 'user_info' => $userInfo->toArray(), 'device_id' => $deviceId ], 'WaitInvite'); continue; } $datetimeNow = date('Y-m-d H:i:s'); if(1 == $inviteConfig->continuously_attract_groups) {// 客户续拉任务 if(1 == $inviteConfig->invite_type) { Log::logError('含有重试标识,邀请类型不能是立即邀请', [ 'user_info' => $userInfo->toArray(), 'device_id' => $deviceId, 'config_info' => $inviteConfig->toArray() ], 'WaitInvite'); continue; } # 重试 if(strtotime($inviteConfig->next_invite_time) > time()) { # 查询当前请求次数 $requestNum = WaitInviteRequest::getNumber($inviteConfig->id, $corpid, $deviceId); $requestNum = intval($requestNum); if($requestNum >= $maxRequestNum) { Log::logError('客户续拉任务重试次数超过限制', [ 'user_info' => $userInfo->toArray(), 'device_id' => $deviceId, 'config_info' => $inviteConfig->toArray(), 'request_num' => $requestNum+1, 'max_request_num' => $maxRequestNum, 'retry' => $retry ], 'WaitInvite'); continue; } else { WaitInviteRequest::saveData($inviteConfig->id, $corpid, $deviceId, $requestNum+1); Log::logInfo('客户续拉任务', [ 'user_info' => $userInfo->toArray(), 'device_id' => $deviceId, 'config_info' => $inviteConfig->toArray(), 'request_num' => $requestNum+1, 'retry' => $retry ], 'WaitInvite'); } } else { # 首次 $customerNumber = null; WaitInviteRequest::saveData($inviteConfig->id, $corpid, $deviceId, 1); Log::logInfo('客户续拉任务首次请求',[ 'user_info' => $userInfo->toArray(), 'device_id' => $deviceId, 'config_info' => $inviteConfig->toArray(), 'request_num' => 1, 'retry' => $retry ], 'WaitInvite'); $nextInviteTime = CircleMassMsgService::getNextSendTime(1, $inviteConfig->invite_time, 0, $datetimeNow); $result = InviteChatGroupRule::where('id', $inviteConfig->id)->update(['next_invite_time' => $nextInviteTime]); if(!$result) { Log::logError('更新下次邀请时间失败', [ 'user_info' => $userInfo->toArray(), 'device_id' => $deviceId, 'config_info' => $inviteConfig->toArray(), 'next_invite_time' => $nextInviteTime ], 'WaitInvite'); } } } else { $customerNumber = null; if($inviteConfig->invite_type == 2 && strtotime($inviteConfig->next_invite_time) > time()) { Log::logError('对应客服尚未到定时邀请入群时间', [ 'user_info' => $userInfo->toArray(), 'device_id' => $deviceId, 'config_info' => $inviteConfig->toArray() ], 'WaitInvite'); continue; } # 满足邀请入群时间 # 更新下次邀请入群时间 if($inviteConfig->invite_type == 2) { // 定时邀请 $nextInviteTime = CircleMassMsgService::getNextSendTime(1, $inviteConfig->invite_time, 0, $datetimeNow); $result = InviteChatGroupRule::where('id', $inviteConfig->id)->update(['next_invite_time' => $nextInviteTime]); if(!$result) { Log::logError('更新下次邀请时间失败', [ 'user_info' => $userInfo->toArray(), 'device_id' => $deviceId, 'config_info' => $inviteConfig->toArray(), 'next_invite_time' => $nextInviteTime ], 'WaitInvite'); } } } # 规则ID $ruleId = $inviteConfig->id; $joinType = $inviteConfig->join_type; $filterType = $inviteConfig->filter_type; $addTimeLater = $inviteConfig->add_time_later; $announcement = $inviteConfig->announcement; # 单次创建群聊任务建群数量上限 $upperLimit = $inviteConfig->upper_limit; # 建群类型 1当前客户直接建群 2其他客服建群 $ownerType = in_array($inviteConfig->owner_type, [1, 2]) ? $inviteConfig->owner_type : 1; # 是否为持续拉取客户入群任务 $continuouslyAttractGroups = $inviteConfig->continuously_attract_groups; $cursor = intval($inviteConfig->cursor); # 获取邀请入群配置 $configList = InviteChatGroupDetail::select('corpid', 'chat_id', 'sort', 'user_limit') ->where('enable', 1)->where('status', 1)->where('rule_id', $ruleId) ->orderBy('sort')->get(); if(empty($configList)) { Log::logError('该企业成员无可用的群配置', [ 'device_id' => $deviceId, 'join_type' => $joinType, 'corpid' => $corpid, 'add_time_later' => $addTimeLater, 'filter_type' => $filterType, 'add_time_st' => $inviteConfig->add_time_st, 'add_time_et' => $inviteConfig->add_time_et, 'userId' => $userId, 'rule_id' => $ruleId, ], 'WaitInvite'); continue; } # 获取群信息 $chatIdList = $configList->pluck('chat_id'); $chatGroupData = ChatGroup::select('chat_id', 'name', 'owner')->where('corpid', $corpid) ->whereIn('chat_id', $chatIdList)->get(); # 拉取客户人数 $userLimit = 40; foreach ($configList as $config) { $groupInfo = $chatGroupData->where('chat_id', $config->chat_id)->first(); $config->groupName = $groupInfo->name; $config->owner = $groupInfo->owner; $config->announcement = $announcement; $userLimit = min($userLimit, $config->user_limit); } $limit = $upperLimit * ($userLimit-1); if(is_numeric($customerNumber)) { $limit = $customerNumber; } $customerList = self::getInviteCustomerList($inviteConfig, $filterType, $deviceId, $joinType, $datetimeNow , $corpid, $addTimeLater, $userId, $ruleId, $continuouslyAttractGroups, $cursor, $limit); if(empty($customerList) || $customerList->isEmpty()) { Log::logError('该企业成员无新添加的客户', [ 'device_id' => $deviceId, 'corpid' => $corpid, 'userId' => $userId, 'begin_time' => $beginTimestamps, 'end_time' => $endTimestamps, 'invite_config' => $inviteConfig, 'filter_type' => $filterType, 'join_type' => $joinType, 'datetimenow' => $datetimeNow, 'add_time_later' => $addTimeLater, 'rule_id' => $ruleId, 'continuouslyAttractGroups'=>$continuouslyAttractGroups, 'cursor' =>$cursor, 'limit' => $limit ], 'WaitInvite'); continue; } $corpInfo = $corpList->where('corpid', $corpid)->first(); $corpName = $corpInfo->corp_name ?? null; if(is_null($corpName)) { Log::logError('企微名称获取为空', [ 'device_id' => $deviceId, 'corpid' => $corpid, 'userId' => $userId, ], 'WaitInvite'); continue; } # 持续拉取客户入群任务更新游标 if(1 == $continuouslyAttractGroups) { $newCursor = $customerList->max('id'); InviteChatGroupRule::updateCursor($ruleId, $newCursor); } $data[] = [ 'companyName' => $corpName, 'corpid' => $corpid, 'joinType' => $joinType, 'owner_type' => $ownerType, 'groupBeans' => $configList, 'peopleList' => $customerList, 'upper_limit' => $upperLimit, 'retry' => $retry ]; } return $data; } public static function getInviteCustomerList( $inviteConfig, $filterType, $deviceId, $joinType, $datetimeNow, $corpid, $addTimeLater, $userId, $ruleId, $continuouslyAttractGroups, $cursor, $limit ) { $search = []; if($inviteConfig->customer_filter == 1) { # 客户添加时间范围 if($filterType == 1) { # 根据筛选条件重新定义$beginTimestamps和$endTimestamps $endTimestamps = strtotime($datetimeNow); $beginTimestamps = strtotime('- ' . $inviteConfig->add_time_later . ' hours', $endTimestamps); } elseif ($filterType == 2) { $endTimestamps = strtotime($inviteConfig->add_time_et); $beginTimestamps = strtotime($inviteConfig->add_time_st); } # 性别 $gender = (!is_null($inviteConfig->gender) && $inviteConfig->gender != '') ? explode(',', $inviteConfig->gender) : []; if(!empty($gender)) $search['gender'] = $gender; # 标签 $tagScreenType = $inviteConfig->tag_screen_type ?? null; $tagList = $inviteConfig->tag_list ?? null; if($tagScreenType == 1 && empty($tagList)) { Log::logError('筛选条件异常 - 选择标签为空', [ 'device_id' => $deviceId, 'join_type' => $joinType, 'gender' => $inviteConfig->gender, 'corpid' => $corpid, 'add_time_later' => $addTimeLater, 'tag_list' => $inviteConfig->tag_list, 'filter_type' => $filterType, 'add_time_st' => $inviteConfig->add_time_st, 'add_time_et' => $inviteConfig->add_time_et, 'tag_screen_type' => $inviteConfig->tag_screen_type, 'userId' => $userId, 'rule_id' => $ruleId, ], 'WaitInvite'); return []; } if($tagScreenType) { $search['tag_screen_type'] = $tagScreenType; $search['tag_list'] = explode(',', $tagList); } // 付费情况 $payStatus = $inviteConfig->pay_status; $payNumMin = $inviteConfig->pay_num_min; $payNumMax = $inviteConfig->pay_num_max; if (is_numeric($payStatus)) { $search['pay_status'] = $payStatus; } if (is_numeric($payNumMin) && $payNumMin > 0) { $search['pay_num_min'] = $payNumMin; } if (is_numeric($payNumMax) && $payNumMax > 0) { $search['pay_num_max'] = $payNumMax; } } # 获取新加入的客户信息 $customerListQuery = CustomerDetails::suffix($corpid)->where('corpid', $corpid) ->select('external_userid', 'name', 'remark', 'id') ->where('user_id', $userId) ->where('loss_status', 1) ->where('blacklist_status', 0); if(!empty($beginTimestamps)) { $customerListQuery->where('createtime', '>', $beginTimestamps); } if(!empty($endTimestamps)) { $customerListQuery->where('createtime', '<=', $endTimestamps); } # 按性别搜索 if(isset($search['gender'])) { $customerListQuery->whereIn('gender', $search['gender']); } # 按标签搜索 if(isset($search['tag_screen_type'])) { $tagList = $search['tag_list'] ?? []; $tagRaw = ''; switch($search['tag_screen_type']) { case 1: // 所选标签满足其一 foreach($tagList as $tagId) { $tagRaw .= $tagId. ' '; } if(isset($search['exclude_tag_list']) && !empty($search['exclude_tag_list'])) { # 增加屏蔽标签 $tagRaw = CustomerDetails::excludeTagSqlDeal($search['exclude_tag_list'], $tagRaw); } if(!empty($tagRaw)) $customerListQuery->whereRaw('match(`tag_list`) against ("'.$tagRaw.'" in boolean mode)'); break; case 2: // 所选标签同时满足 foreach($tagList as $tagId) { $tagRaw .= '+' .$tagId. ' '; } if(isset($search['exclude_tag_list']) && !empty($search['exclude_tag_list'])) { # 增加屏蔽标签 $tagRaw = CustomerDetails::excludeTagSqlDeal($search['exclude_tag_list'], $tagRaw); } if(!empty($tagRaw)) $customerListQuery->whereRaw('match(`tag_list`) against ("'.$tagRaw.'" in boolean mode)'); break; case 3: $customerListQuery->whereNull('tag_list'); break; } } # 按付费状态 if(isset($search['pay_status'])) { if($search['pay_status']) { $customerListQuery->where('is_paid', 1); } else { $customerListQuery->where('is_paid', 0); } } # 最小付费次数 if(isset($search['pay_num_min'])) { $customerListQuery->where('pay_num', '>=', $search['pay_num_min']); } # 最大付费次数 if(isset($search['pay_num_max'])) { $customerListQuery->where('pay_num', '<=', $search['pay_num_max']); } if(1 == $continuouslyAttractGroups) { $customerList = $customerListQuery->where('id', '>', $cursor)->limit($limit)->orderby('createtime')->get(); } else { $customerList = $customerListQuery->orderby('createtime')->get(); } return $customerList; } /** * 获取待邀请入群的新用户 * */ public static function waitShare($deviceId, $beginTime, $endTime) { $endTimestamps = strtotime($endTime); $beginTimestamps = strtotime($beginTime); # 查询设备对应的企微及客服信息 $userList = AndroidBindCorp::select('corpid', 'user_id')->where('device_id', $deviceId) ->where('enable', 1)->get(); if(empty($userList)) { Log::logError('此设备号未绑定任何企微信息', [ 'device_id' => $deviceId ], 'waitShare'); return []; } # 查询支持无障碍模式的企微列表 $corpIds = $userList->pluck('corpid'); $corpList = AuthorizeCorp::select('corpid', 'corp_name')->whereIn('corpid', $corpIds)->where('enable', 1)->get(); $data = []; # 查询企微和客服待共享的客户列表 foreach ($userList as $userInfo) { $corpid = $userInfo->corpid ?? null; $userId = $userInfo->user_id ?? null; if(!$corpid || !$userId) { Log::logError('检索待共享好友的客服时存在异常数据', [ 'user_info' => $userInfo->toArray(), 'device_id' => $deviceId ], 'waitShare'); continue; } # 检索共享好友配置 $takeoverUserIdList = CustomerShareRelation::where('status', 1)->where('enable', 1)->where('corpid', $corpid) ->where('user_id', $userId)->value('takeover_users'); if(empty($takeoverUserIdList)) { Log::logError('未检索到共享好友配置', [ 'corpid' => $corpid, 'user_id' => $userId, 'device_id' => $deviceId ], 'waitShare'); continue; } $takeoverUserIds = explode(',', $takeoverUserIdList); $takeoverUserList = DjUser::where('corpid', $corpid)->whereIn('user_id', $takeoverUserIds)->where('enable', 1) ->where('status', 1)->pluck('name'); # 获取新加入的客户信息 $customerList = CustomerDetails::suffix($corpid)->where('corpid', $corpid) ->select('name') ->where('user_id', $userId)->where('createtime', '>', $beginTimestamps) ->where('createtime', '<=', $endTimestamps) ->where('loss_status', 1) ->get()->pluck('name'); if($customerList->isEmpty()) { Log::logError('该企业成员无新添加的客户', [ 'device_id' => $deviceId, 'corpid' => $corpid, 'userId' => $userId, 'begin_time' => $beginTimestamps, 'end_time' => $endTimestamps, '' ], 'waitShare'); continue; } $corpInfo = $corpList->where('corpid', $corpid)->first(); $corpName = $corpInfo->corp_name ?? null; if(is_null($corpName)) { Log::logError('企微名称获取为空', [ 'device_id' => $deviceId, 'corpid' => $corpid, 'userId' => $userId, ], 'waitShare'); continue; } $data[] = [ 'companyName' => $corpName, 'colleagueNames' => $takeoverUserList, 'clientNames' => $customerList ]; } return $data; } public static function waitSupplementaryInvite($deviceId, $beginTime, $endTime) { # 校验开始时间和结束时间,最大时间差不超过十分钟 $endTimestamps = strtotime($endTime); $beginTimestamps = strtotime($beginTime); if($endTimestamps - $beginTimestamps > 600) { $beginTimestamps = strtotime('-10 minute', $endTimestamps); } # 查询设备对应的企微及客服信息 $userList = AndroidBindCorp::select('corpid', 'user_id')->where('device_id', $deviceId) ->where('enable', 1)->get(); if(empty($userList)) { Log::logError('此设备号未绑定任何企微信息', [ 'device_id' => $deviceId ], 'waitSupplementaryInvite'); return []; } # 查询支持无障碍模式的企微列表 $corpIds = $userList->pluck('corpid'); $corpList = AuthorizeCorp::select('corpid', 'corp_name')->whereIn('corpid', $corpIds)->where('enable', 1)->get(); $data = []; # 查询企微和客服是否配置了邀请入群功能 foreach ($userList as $userInfo) { $corpid = $userInfo->corpid ?? null; $userId = $userInfo->user_id ?? null; if(!$corpid || !$userId) { Log::logError('检索待邀请入群的客服时存在异常数据', [ 'user_info' => $userInfo->toArray(), 'device_id' => $deviceId ], 'waitSupplementaryInvite'); continue; } # 使用更新时间最近的配置 $inviteConfig = InviteChatGroupRule::where('corpid', $corpid) ->whereRaw("FIND_IN_SET('".$userId."', `users`)") ->where('status', 1)->where('enable', 1)->where('supplementary_invite', 1) ->orderBy('updated_at', 'desc') ->first(); if(empty($inviteConfig)) { $inviteConfig = InviteChatGroupRule::where('corpid', $corpid) ->where('is_for_all', 1)->where('supplementary_invite', 1) ->where('enable', 1)->where('status', 1) ->orderBy('updated_at', 'desc') ->first(); } if(empty($inviteConfig)) { Log::logError('客服暂未配置邀请入群规则', [ 'user_info' => $userInfo->toArray(), 'device_id' => $deviceId ], 'waitSupplementaryInvite'); continue; } $datetimeNow = date('Y-m-d H:i:s'); if($inviteConfig->invite_type == 2 && strtotime($inviteConfig->next_supplementary_invite_time) > time()) { Log::logError('对应客服尚未到定时补充邀请入群时间', [ 'user_info' => $userInfo->toArray(), 'device_id' => $deviceId, 'config_info' => $inviteConfig->toArray() ], 'waitSupplementaryInvite'); continue; } $lastSupplementaryInviteTime = $inviteConfig->last_supplementary_invite_time; # 满足邀请入群时间 # 更新下次邀请入群时间 if($inviteConfig->invite_type == 2) { // 定时邀请 $nextSupplementaryInviteTime = CircleMassMsgService::getNextSupplementaryInviteTime(1 , $inviteConfig->invite_time, $inviteConfig->supplementary_invite_cycle, $datetimeNow); $result = InviteChatGroupRule::where('id', $inviteConfig->id)->update([ 'next_supplementary_invite_time' => $nextSupplementaryInviteTime, 'last_supplementary_invite_time' => $datetimeNow ]); if(!$result) { Log::logError('更新下次邀请时间失败', [ 'user_info' => $userInfo->toArray(), 'device_id' => $deviceId, 'config_info' => $inviteConfig->toArray(), 'last_supplementary_invite_time' => $lastSupplementaryInviteTime, 'next_supplementary_invite_time' => $nextSupplementaryInviteTime, 'now_supplementary_invite_time' => $datetimeNow ], 'waitSupplementaryInvite'); } } # 规则ID $ruleId = $inviteConfig->id; # 建群类型 1当前客户直接建群 2其他客服建群 $ownerType = in_array($inviteConfig->owner_type, [1, 2]) ? $inviteConfig->owner_type : 1; # 获取邀请入群配置 $configList = InviteChatGroupDetail::select('corpid', 'chat_id', 'sort', 'user_limit') ->where('enable', 1)->where('status', 1)->where('rule_id', $ruleId) ->orderBy('sort')->get(); if(empty($configList)) { Log::logError('该企业成员无可用的群配置', [ 'device_id' => $deviceId, 'add_time_et' => $datetimeNow, 'corpid' => $corpid, 'add_time_st' => $lastSupplementaryInviteTime, 'userId' => $userId, 'rule_id' => $ruleId, ], 'waitSupplementaryInvite'); continue; } # 获取群信息 $chatIdList = $configList->pluck('chat_id'); $chatGroupData = ChatGroup::select('chat_id', 'name', 'owner')->where('corpid', $corpid) ->whereIn('chat_id', $chatIdList)->get(); $userList = DjUser::getUserBySearch([ 'corp_list' => [$corpid] ]); # 拉取客户人数 foreach ($configList as $config) { $groupInfo = $chatGroupData->where('chat_id', $config->chat_id)->first(); $config->groupName = $groupInfo->name ?? ''; $config->owner = $groupInfo->owner ?? ''; $ownerInfo = $userList->where('user_id', $config->owner)->first(); $config->owner_name = $ownerInfo->name ?? ''; # 找到所有群主为当前客服的模板群聊 $chatGroupModel = ChatGroup::getSearchModel([ 'status' => 1, 'corpid' => $corpid, 'owner' => $config->owner, 'name' => $config->groupName ]); $userChatList = $chatGroupModel->select(['chat_id'])->get(); if($userChatList->isEmpty()) { Log::logError('该群模板无法找到当前客服所属的群聊', [ 'device_id' => $deviceId, 'corpid' => $corpid, 'user_id' => $userId, 'name' => $config->groupName, 'rule_id' => $ruleId, 'invite_config' => $inviteConfig, 'config' => $config ], 'waitSupplementaryInvite'); $config->people_list = []; continue; } $userChatIdList = array_column($userChatList->toArray(), 'chat_id'); Log::logInfo('根据群模板获取到的群聊结果', [ 'device_id' => $deviceId, 'corpid' => $corpid, 'user_id' => $userId, 'owner' => $config->owner, 'name' => $config->groupName, 'rule_id' => $ruleId, 'invite_config' => $inviteConfig, 'config' => $config, 'user_chat_id_list' => $userChatIdList ], 'waitSupplementaryInvite'); if(2 == $ownerType) {# 群主与进粉客服不是同一人,再次筛选包含进粉客服的群聊ID $newChatList = ChatGroupMember::getGroupMember([ 'corpid' => $corpid, 'chat_id_list' => $userChatIdList, 'user_id' => $userId, 'status' => 1 ]); if(empty($newChatList)) { Log::logError('查找进粉客服在群聊中的群聊信息', [ 'device_id' => $deviceId, 'corpid' => $corpid, 'user_id' => $userId, 'owner' => $config->owner, 'name' => $config->groupName, 'rule_id' => $ruleId, 'invite_config' => $inviteConfig, 'config' => $config, 'user_chat_id_list' => $userChatIdList, 'new_chat_list'=> $newChatList ], 'waitSupplementaryInvite'); $config->people_list = []; continue; } $newUserChatIdList = array_unique(array_column($newChatList, 'chat_id')); Log::logInfo('查找进粉客服在群聊中的群聊信息结果', [ 'device_id' => $deviceId, 'corpid' => $corpid, 'user_id' => $userId, 'owner' => $config->owner, 'name' => $config->groupName, 'rule_id' => $ruleId, 'invite_config' => $inviteConfig, 'config' => $config, 'user_chat_id_list' => $userChatIdList, 'new_user_chat_id_list' => $newUserChatIdList ], 'waitSupplementaryInvite'); $userChatIdList = $newUserChatIdList; } # 找到这些群聊在间隔时间范围内退群的客户外部联系人ID $externalUserList = ChatGroupMember::getGroupMember([ 'corpid' => $corpid, 'chat_id_list' => $userChatIdList, 'status' => 2, 'quit_time_st' => $lastSupplementaryInviteTime, 'quit_time_ed' => $datetimeNow ]); if(empty($externalUserList)) { Log::logError('退群客户为空', [ 'device_id' => $deviceId, 'corpid' => $corpid, 'user_id' => $userId, 'name' => $config->groupName, 'rule_id' => $ruleId, 'invite_config' => $inviteConfig, 'config' => $config, 'chat_id_list' => $userChatIdList, 'quit_time_st' => $lastSupplementaryInviteTime, 'quit_time_ed' => $datetimeNow ], 'waitSupplementaryInvite'); $config->people_list = []; continue; } # 通过外部联系人ID查询客户信息 $externalUserIdList = array_unique(array_column($externalUserList, 'user_id')); Log::logInfo('客户ID列表', $externalUserIdList, 'waitSupplementaryInvite'); $customerList = CustomerDetails::suffix($corpid)->select(['external_userid', 'name', 'remark', 'id']) ->where('corpid', $corpid)->whereIn('external_userid', $externalUserIdList) ->where('loss_status', 1)->where('blacklist_status', 0)->groupBy('external_userid')->orderBy('id', 'desc')->get(); if($customerList->isEmpty()) { Log::logError('查询客户列表结果为空', [ 'device_id' => $deviceId, 'corpid' => $corpid, 'user_id' => $userId, 'name' => $config->groupName, 'rule_id' => $ruleId, 'invite_config' => $inviteConfig, 'config' => $config, "external_userid_list" => $externalUserIdList ], 'waitSupplementaryInvite'); continue; } $config->people_list = $customerList; } $corpInfo = $corpList->where('corpid', $corpid)->first(); $corpName = $corpInfo->corp_name ?? null; if(is_null($corpName)) { Log::logError('企微名称获取为空', [ 'device_id' => $deviceId, 'corpid' => $corpid, 'userId' => $userId, ], 'waitSupplementaryInvite'); continue; } $data[] = [ 'companyName' => $corpName, 'corpid' => $corpid, 'owner_type' => $ownerType, 'groupBeans' => $configList, ]; } return $data; } public static function waitInviteTargetGroup($deviceId, $beginTime, $endTime) { # 查询设备对应的企微及客服信息 $userList = AndroidBindCorp::select('corpid', 'user_id')->where('device_id', $deviceId) ->where('enable', 1)->get(); if(empty($userList)) { Log::logError('此设备号未绑定任何企微信息', [ 'device_id' => $deviceId ], 'waitInviteTargetGroup'); return []; } # 查询支持无障碍模式的企微列表 $corpIds = $userList->pluck('corpid'); $corpList = AuthorizeCorp::select('corpid', 'corp_name')->whereIn('corpid', $corpIds)->where('enable', 1)->get(); $data = []; # 查询企微和客服是否配置了邀请入群功能 foreach ($userList as $userInfo) { $corpid = $userInfo->corpid ?? null; $userId = $userInfo->user_id ?? null; if(!$corpid || !$userId) { Log::logError('检索待邀请入群的客服时存在异常数据', [ 'user_info' => $userInfo->toArray(), 'device_id' => $deviceId ], 'waitInviteTargetGroup'); continue; } # 使用更新时间最近的配置 $inviteConfig = InviteChatGroupRule::where('corpid', $corpid) ->whereRaw("FIND_IN_SET('".$userId."', `users`)") ->where('status', 1)->where('enable', 1)->where('supplementary_invite', 1) ->orderBy('updated_at', 'desc') ->first(); if(empty($inviteConfig)) { $inviteConfig = InviteChatGroupRule::where('corpid', $corpid) ->where('is_for_all', 1)->where('supplementary_invite', 1) ->where('enable', 1)->where('status', 1) ->orderBy('updated_at', 'desc') ->first(); } if(empty($inviteConfig)) { Log::logError('客服暂未配置邀请入群规则', [ 'user_info' => $userInfo->toArray(), 'device_id' => $deviceId ], 'waitInviteTargetGroup'); continue; } $datetimeNow = date('Y-m-d H:i:s'); if($inviteConfig->invite_type == 2 && strtotime($inviteConfig->next_supplementary_invite_time) > time()) { Log::logError('对应客服尚未到定时补充邀请入群时间', [ 'user_info' => $userInfo->toArray(), 'device_id' => $deviceId, 'config_info' => $inviteConfig->toArray() ], 'waitInviteTargetGroup'); continue; } $lastSupplementaryInviteTime = $inviteConfig->last_supplementary_invite_time; # 满足邀请入群时间,更新下次邀请入群时间 if($inviteConfig->invite_type == 2) { // 定时邀请 $nextSupplementaryInviteTime = CircleMassMsgService::getNextSupplementaryInviteTime(1 , $inviteConfig->invite_time, $inviteConfig->supplementary_invite_cycle, $datetimeNow); $result = InviteChatGroupRule::where('id', $inviteConfig->id)->update([ 'next_supplementary_invite_time' => $nextSupplementaryInviteTime, 'last_supplementary_invite_time' => $datetimeNow ]); if(!$result) { Log::logError('更新下次邀请时间失败', [ 'user_info' => $userInfo->toArray(), 'device_id' => $deviceId, 'config_info' => $inviteConfig->toArray(), 'last_supplementary_invite_time' => $lastSupplementaryInviteTime, 'next_supplementary_invite_time' => $nextSupplementaryInviteTime, 'now_supplementary_invite_time' => $datetimeNow ], 'waitInviteTargetGroup'); } } # 规则ID $ruleId = $inviteConfig->id; # 建群类型 1当前客户直接建群 2其他客服建群 $ownerType = in_array($inviteConfig->owner_type, [1, 2]) ? $inviteConfig->owner_type : 1; # 获取邀请入群配置 $configList = InviteChatGroupDetail::select('corpid', 'chat_id', 'sort', 'user_limit') ->where('enable', 1)->where('status', 1)->where('rule_id', $ruleId) ->orderBy('sort')->get(); if(empty($configList)) { Log::logError('该企业成员无可用的群配置', [ 'device_id' => $deviceId, 'add_time_et' => $datetimeNow, 'corpid' => $corpid, 'add_time_st' => $lastSupplementaryInviteTime, 'userId' => $userId, 'rule_id' => $ruleId, ], 'waitInviteTargetGroup'); continue; } # 获取群信息 $chatIdList = $configList->pluck('chat_id'); $chatGroupData = ChatGroup::select('chat_id', 'name', 'owner')->where('corpid', $corpid) ->whereIn('chat_id', $chatIdList)->get(); $userList = DjUser::getUserBySearch([ 'corp_list' => [$corpid] ]); # 拉取客户人数 foreach ($configList as $config) { $groupInfo = $chatGroupData->where('chat_id', $config->chat_id)->first(); $config->groupName = $groupInfo->name ?? ''; $config->owner = $groupInfo->owner ?? ''; $ownerInfo = $userList->where('user_id', $config->owner)->first(); $config->owner_name = $ownerInfo->name ?? ''; # 找到所有群主为当前客服的模板群聊 $chatGroupModel = ChatGroup::getSearchModel([ 'status' => 1, 'corpid' => $corpid, 'owner' => $config->owner, 'name' => $config->groupName ]); $userChatList = $chatGroupModel->select(['chat_id'])->get(); if($userChatList->isEmpty()) { Log::logError('该群模板无法找到当前客服所属的群聊', [ 'device_id' => $deviceId, 'corpid' => $corpid, 'user_id' => $userId, 'name' => $config->groupName, 'rule_id' => $ruleId, 'invite_config' => $inviteConfig, 'config' => $config ], 'waitInviteTargetGroup'); $config->people_list = []; continue; } $userChatIdList = array_column($userChatList->toArray(), 'chat_id'); Log::logInfo('根据群模板获取到的群聊结果', [ 'device_id' => $deviceId, 'corpid' => $corpid, 'user_id' => $userId, 'owner' => $config->owner, 'name' => $config->groupName, 'rule_id' => $ruleId, 'invite_config' => $inviteConfig, 'config' => $config, 'user_chat_id_list' => $userChatIdList ], 'waitInviteTargetGroup'); if(2 == $ownerType) { // 群主与进粉客服不是同一人,再次筛选包含进粉客服的群聊ID $newChatList = ChatGroupMember::getGroupMember([ 'corpid' => $corpid, 'chat_id_list' => $userChatIdList, 'user_id' => $userId, 'status' => 1 ]); if(empty($newChatList)) { Log::logError('查找进粉客服在群聊中的群聊信息', [ 'device_id' => $deviceId, 'corpid' => $corpid, 'user_id' => $userId, 'owner' => $config->owner, 'name' => $config->groupName, 'rule_id' => $ruleId, 'invite_config' => $inviteConfig, 'config' => $config, 'user_chat_id_list' => $userChatIdList, 'new_chat_list'=> $newChatList ], 'waitInviteTargetGroup'); $config->people_list = []; continue; } $newUserChatIdList = array_unique(array_column($newChatList, 'chat_id')); Log::logInfo('查找进粉客服在群聊中的群聊信息结果', [ 'device_id' => $deviceId, 'corpid' => $corpid, 'user_id' => $userId, 'owner' => $config->owner, 'name' => $config->groupName, 'rule_id' => $ruleId, 'invite_config' => $inviteConfig, 'config' => $config, 'user_chat_id_list' => $userChatIdList, 'new_user_chat_id_list' => $newUserChatIdList ], 'waitInviteTargetGroup'); $userChatIdList = $newUserChatIdList; } $inviteList = []; foreach ($userChatIdList as $userChatId) { # 查找对应群在指定时间的流失客户 $externalUserList = ChatGroupMember::getGroupMember([ 'corpid' => $corpid, 'chat_id' => $userChatId, 'status' => 2, 'quit_time_st' => $lastSupplementaryInviteTime, 'quit_time_ed' => $datetimeNow ]); if(empty($externalUserList)) { Log::logError('退群客户为空', [ 'device_id' => $deviceId, 'corpid' => $corpid, 'user_id' => $userId, 'name' => $config->groupName, 'rule_id' => $ruleId, 'invite_config' => $inviteConfig, 'config' => $config, 'chat_id' => $userChatId, 'quit_time_st' => $lastSupplementaryInviteTime, 'quit_time_ed' => $datetimeNow ], 'waitInviteTargetGroup'); continue; } # 通过外部联系人ID查询客户信息 $externalUserIdList = array_unique(array_column($externalUserList, 'user_id')); Log::logInfo('客户ID列表', $externalUserIdList, 'waitInviteTargetGroup'); $customerList = CustomerDetails::suffix($corpid)->select(['external_userid', 'name', 'remark', 'id']) ->where('corpid', $corpid)->whereIn('external_userid', $externalUserIdList) ->where('loss_status', 1)->where('blacklist_status', 0)->groupBy('external_userid') ->orderBy('id', 'desc') ->get(); if($customerList->isEmpty()) { Log::logError('查询客户列表结果为空', [ 'device_id' => $deviceId, 'corpid' => $corpid, 'user_id' => $userId, 'name' => $config->groupName, 'rule_id' => $ruleId, 'invite_config' => $inviteConfig, 'config' => $config, "external_userid_list" => $externalUserIdList ], 'waitInviteTargetGroup'); continue; } $inviteList[] = [ 'chat_id' => $userChatId, 'group_name' => $config->groupName, 'owner' => $config->owner, 'owner_name' => $config->owner_name, 'customer_list' => $customerList ]; } $config->invite_list = $inviteList; } $corpInfo = $corpList->where('corpid', $corpid)->first(); $corpName = $corpInfo->corp_name ?? null; if(is_null($corpName)) { Log::logError('企微名称获取为空', [ 'device_id' => $deviceId, 'corpid' => $corpid, 'userId' => $userId, ], 'waitInviteTargetGroup'); continue; } $data[] = [ 'companyName' => $corpName, 'corpid' => $corpid, 'owner_type' => $ownerType, 'groupBeans' => $configList, ]; } return $data; } public static function inviteNewUser($deviceId, $beginTime, $endTime) { # 校验开始时间和结束时间,最大时间差不超过十分钟 $endTimestamps = strtotime($endTime); $beginTimestamps = strtotime($beginTime); if($endTimestamps - $beginTimestamps > 600) { $beginTimestamps = strtotime('-10 minute', $endTimestamps); } # 查询设备对应的企微及客服信息 $userList = AndroidBindCorp::select('corpid', 'user_id')->where('device_id', $deviceId) ->where('enable', 1)->get(); if(empty($userList)) { Log::logError('此设备号未绑定任何企微信息', [ 'device_id' => $deviceId ], 'inviteNewUser'); return []; } # 查询支持无障碍模式的企微列表 $corpIds = $userList->pluck('corpid'); $corpList = AuthorizeCorp::select('corpid', 'corp_name')->whereIn('corpid', $corpIds)->where('enable', 1)->get(); $data = []; # 查询企微和客服是否配置了新用户邀请入群功能 foreach ($userList as $userInfo) { $corpid = $userInfo->corpid ?? null; $userId = $userInfo->user_id ?? null; if(!$corpid || !$userId) { Log::logError('检索待邀请入群的客服时存在异常数据', [ 'user_info' => $userInfo->toArray(), 'device_id' => $deviceId ], 'inviteNewUser'); continue; } $ruleInfo = WelcomeMsgRelation::select('id', 'is_invite_user', 'group_name_prefix')->where('corpid', $corpid) ->whereRaw("FIND_IN_SET('".$userId."', users)")->where('enable', 1)->where('is_for_all', 0) ->where('is_del', 0)->orderBy('updated_at', 'desc') ->first(); if(empty($ruleInfo)) { // 未查询到该员工的专属配置,则查询企业全体员工通用配置 $ruleInfo = WelcomeMsgRelation::select('id', 'is_invite_user', 'group_name_prefix')->where('corpid', $corpid) ->where('enable', 1)->where('is_del', 0) ->where('is_for_all', 1)->orderBy('updated_at', 'desc') ->first(); } if(empty($ruleInfo) || !$ruleInfo->is_invite_user || !$ruleInfo->group_name_prefix) { Log::logError('客服未配置邀请新用户入群', [ 'user_info' => $userInfo->toArray(), 'device_id' => $deviceId, 'config' => $ruleInfo ], 'inviteNewUser'); continue; } $search = array('is_invited' => 0, 'add_time_start' => $beginTimestamps, 'add_time_end' => $endTimestamps); $field = 'id, name'; list($customerList, $count) = CustomerDetails::getUserInfo($corpid, $search, $field, 1, 200, []); if(!$count) { Log::logError('该企业成员无新添加的客户', [ 'device_id' => $deviceId, 'corpid' => $corpid, 'datetime_now' => date("Y-m-d H:i:s"), 'userId' => $userId, 'begin_time' => $beginTimestamps, 'end_time' => $endTimestamps, 'invite_config' => $ruleInfo, ], 'inviteNewUser'); continue; } if($count == 200) { Log::logError('待邀请入群用户数超出200', [ 'user_info' => $userInfo->toArray(), 'device_id' => $deviceId, 'config' => $ruleInfo ], 'inviteNewUser'); } # 更新该批次用户的is_invited信息 CustomerDetails::suffix($corpid)->whereIn('id', $customerList->pluck('id'))->update(['is_invited' => 1]); $corpInfo = $corpList->where('corpid', $corpid)->first(); $corpName = $corpInfo->corp_name ?? null; if(is_null($corpName)) { Log::logError('企微名称获取为空', [ 'device_id' => $deviceId, 'corpid' => $corpid, 'userId' => $userId, ], 'inviteNewUser'); continue; } $data[] = [ 'companyName' => $corpName, 'corpid' => $corpid, 'groupNamePrefix' => $ruleInfo->group_name_prefix, 'peopleList' => $customerList->pluck('name'), ]; } return $data; } /** * 获取客户首次关注时间 * */ public static function getCustomerFirstAddTime($name, $avatar, $createTime) { if(!$name && !$avatar) { // 客户头像和昵称都为空,异常情况 $datetimeNow = time(); return [$datetimeNow, $datetimeNow]; } # 生成uni_customer_label $uniCustomerLabel = md5($name . $avatar); # 优先从dj_customer_unique中获取最早关注时间 $firstAddTimeData = CustomerUnique::getFirstAddTime($uniCustomerLabel); $firstAddTime = $firstAddTimeData->first_add_time ?? null; $firstAddTimeNoLoss = $firstAddTimeData->first_add_time_no_loss ?? null; if($firstAddTime && $firstAddTimeNoLoss) return [strtotime($firstAddTime), strtotime($firstAddTimeNoLoss)]; # 遍历50个客户详情表,找到最早关注时间 $firstAddTime = $firstAddTimeNoLoss = $createTime; for ($i=0; $i<50; $i++) { $minCreateTime = CustomerDetails::suffix($i)->where('uni_customer_label', $uniCustomerLabel) ->min('createtime'); $minCreateTimeNoLoss = CustomerDetails::suffix($i)->where('uni_customer_label', $uniCustomerLabel) ->where('enable', 1)->where('loss_status', 1) ->min('createtime'); if($minCreateTime && $minCreateTime < $firstAddTime) $firstAddTime = $minCreateTime; if($minCreateTimeNoLoss && $minCreateTimeNoLoss < $firstAddTimeNoLoss) $firstAddTimeNoLoss = $minCreateTimeNoLoss; } # 记录并返回首次关注时间 CustomerUnique::updateOrCreate(['uni_customer_label' => $uniCustomerLabel], [ 'name' => $name, 'avatar' => $avatar, 'first_add_time' => date('Y-m-d H:i:s', $firstAddTime), 'first_add_time_no_loss' => date('Y-m-d H:i:s', $firstAddTimeNoLoss), 'enable' => 1 ]); return [$firstAddTime, $firstAddTimeNoLoss]; } /** * 更新客户首次关注时间 * */ public static function updateCustomerFirstAddTime($name, $avatar, $createtime) { if(!$name && !$avatar) { // 客户头像和昵称都为空,异常情况 EmailQueue::rPush( '更新客户首次关注时间时,用户头像和昵称异常', json_encode(['name' => $name, 'avatar' => $avatar]), ['xiaohua.hou@kuxuan-inc.com'], '猎羽' ); return false; } # 生成uni_customer_label $uniCustomerLabel = md5($name . $avatar); # 优先从dj_customer_unique中获取最早关注时间 $firstAddTimeData = CustomerUnique::getFirstAddTime($uniCustomerLabel); $firstAddTimeNoLoss = $firstAddTimeData->first_add_time_no_loss ?? null; if($createtime == strtotime($firstAddTimeNoLoss)) { // 当前流失用户为留存用户中关注最早的 # 重新检索该用户在用户池中还留存的最早关注时间 $firstAddTimeNoLoss = null; for ($i=0; $i<50; $i++) { $minCreateTimeNoLoss = CustomerDetails::suffix($i)->where('uni_customer_label', $uniCustomerLabel) ->where('enable', 1)->where('loss_status', 1) ->min('createtime'); if($minCreateTimeNoLoss && (is_null($firstAddTimeNoLoss) || $minCreateTimeNoLoss <= $firstAddTimeNoLoss)) $firstAddTimeNoLoss = $minCreateTimeNoLoss; } if(is_null($firstAddTimeNoLoss)) { CustomerUnique::where('uni_customer_label', $uniCustomerLabel)->update(['enable' => 0]); } else { CustomerUnique::where('uni_customer_label', $uniCustomerLabel)->update([ 'first_add_time_no_loss' => date('Y-m-d H:i:s', $firstAddTimeNoLoss )]); } } return true; } /** * 校验客户是否在单主体内全部流失 * */ public static function checkCustomerLossStatusInCorp($corpid, $externalUserId) { # 判断客户是否有单主体内全部流失标识 $isExist = CustomerDetails::suffix($corpid)->where('corpid', $corpid) ->where('external_userid', $externalUserId) ->where('loss_status', 1)->where('can_receive', 1) ->where('enable', 1)->exists(); if($isExist) { $rst = CustomerDetails::suffix($corpid)->where('corpid', $corpid) ->where('external_userid', $externalUserId) ->where('retained_status', 0) ->update(['retained_status'=>1]); } else { $rst = CustomerDetails::suffix($corpid)->where('corpid', $corpid) ->where('retained_status', 1) ->where('external_userid', $externalUserId) ->update(['retained_status'=>0]); } Log::logInfo('本次起始ID为:', [ 'corpid' => $corpid, 'external_userid' => $externalUserId, 'rst' => $rst, 'is_exist' => $isExist ], 'CheckCustomerLossStatusInCorp'); } public static function customerCountStat($search) { $source = 1; $customerQuery = CustomerDetails::getCustomerBySearchNew($search, $source); $data = $customerQuery->selectRaw("user_id, count(1) as count")->groupBy('user_id')->orderByDesc('count')->get(); $insideUserIdList = array_unique(array_column($data->toArray(), 'user_id')); // 查询客服基本信息 $search = ['corpid' => $search['corpid'], 'user_list' => $insideUserIdList]; $userDataList = DjUser::getUserBySearch($search); $result = []; foreach($data as $key => $item) { $userInfo = $userDataList->where('user_id', $item->user_id)->first(); if(empty($userInfo)) {// 已离职的客服过滤不显示 unset($data[$key]); continue; } $item->user_name = $userInfo->name ?? null; $item->is_active = $userInfo->is_active ?? null; $result[] = $item; } return $result; } }