'timestamp', ]; public static $address = [ '北京', '上海', '天津', '广东', '浙江', '海南', '福建', '湖南', '湖北', '重庆', '辽宁', '吉林', '黑龙江', '河北', '河南', '山东', '陕西', '甘肃', '青海', '新疆', '山西', '四川', '贵州', '安徽', '江西', '江苏', '云南', '内蒙古', '广西', '西藏', '宁夏' ]; /** * [getDataList 客户list] * @param [string] $map [查询条件] * @param [number] $page [当前页数] * @param [number] $limit [每页数量] * @return [array] [description] * @author Michael_xu */ public function getDataList($request) { $userModel = new \app\admin\model\User(); $fieldModel = new \app\admin\model\Field(); $search = $request['search']; $user_id = $request['user_id']; $scene_id = (int)$request['scene_id']; $is_excel = $request['is_excel']; //导出 $order_field = $request['order_field']; $order_type = $request['order_type']; $is_remind = $request['is_remind']; $getCount = $request['getCount']; $otherMap = $request['otherMap']; $overdue = $request['overdue']; // 待办事项下需联系客户(逾期) # 需要过滤的参数 $unsetRequest = ['scene_id', 'search', 'user_id', 'is_excel', 'action', 'order_field', 'order_type', 'is_remind', 'getCount', 'type', 'otherMap', 'poolId', 'overdue']; foreach ($unsetRequest as $v) { unset($request[$v]); } # 格式化参数 $request = $this->fmtRequest($request); $requestMap = $request['map'] ?: []; $sceneModel = new \app\admin\model\Scene(); # 客户默认条件 $customerMap = $this->getWhereByCustomer(); # getCount是代办事项传来的参数,代办事项不需要使用场景 $sceneMap = []; if (empty($getCount)) { if ($scene_id) { //自定义场景 $sceneMap = $sceneModel->getDataById($scene_id, $user_id, 'customer') ?: []; } else { //默认场景 $sceneMap = $sceneModel->getDefaultData('crm_customer', $user_id) ?: []; } } # 普通筛选 $searchMap = []; if ($search || $search == '0') { $searchMap = function ($query) use ($search) { $query->where('customer.name', array('like', '%' . $search . '%')) ->whereOr('customer.mobile', array('like', '%' . $search . '%')) ->whereOr('customer.telephone', array('like', '%' . $search . '%')); }; } # 优先级:普通筛选 > 高级筛选 > 场景 $map = []; $partMap = []; $teamMap = $requestMap['team_id']; //团队成员 高级筛选 if ($teamMap) { $partMap = advancedQueryFormatForTeam($teamMap, 'customer', ''); unset($requestMap['team_id']); $map = $requestMap ? array_merge($sceneMap, $requestMap) : $sceneMap; } else { $map = $requestMap ? array_merge($sceneMap, $requestMap) : $sceneMap; } # 高级筛选 $map = advancedQuery($map, 'crm', 'customer', 'index'); # 工作台仪表盘 $requestData = $this->requestData(); $dashboardWhere = []; if ($requestData['a'] == 'indexlist' && $requestData['c'] == 'index') { $dashboardWhere = function ($query) use ($requestMap) { $query->where('customer.create_time', array('between', [$requestMap['create_time']['start'], $requestMap['create_time']['end']])) ->whereOr('customer.obtain_time', array('between', [$requestMap['create_time']['start'], $requestMap['create_time']['end']])); }; unset($map['customer.create_time']); } # 权限 $authMap = []; $a = 'index'; if ($is_excel) $a = 'excelExport'; $auth_user_ids = $userModel->getUserByPer('crm', 'customer', $a); //过滤权限 if (isset($map['customer.owner_user_id'])) { if (!is_array($map['customer.owner_user_id'][1])) { $map['customer.owner_user_id'][1] = [$map['customer.owner_user_id'][1]]; } if (in_array($map['customer.owner_user_id'][0], ['neq', 'notin'])) { $auth_user_ids = array_diff($auth_user_ids, $map['customer.owner_user_id'][1]) ?: []; //取差集 } else { $auth_user_ids = array_intersect($map['customer.owner_user_id'][1], $auth_user_ids) ?: []; //取交集 } unset($map['customer.owner_user_id']); $auth_user_ids = array_merge(array_unique(array_filter($auth_user_ids))) ?: ['-1']; //负责人、相关团队 $authMap['customer.owner_user_id'] = array('in', $auth_user_ids); } else { $authMapData = []; $authMapData['auth_user_ids'] = $auth_user_ids; $authMapData['user_id'] = $user_id; $authMap = function ($query) use ($authMapData) { $query->where(['customer.owner_user_id' => array('in', $authMapData['auth_user_ids'])]) ->whereOr(function ($query) use ($authMapData) { $query->where('FIND_IN_SET("' . $authMapData['user_id'] . '", customer.ro_user_id)')->where(['customer.owner_user_id' => array('neq', '')]); }) ->whereOr(function ($query) use ($authMapData) { $query->where('FIND_IN_SET("' . $authMapData['user_id'] . '", customer.rw_user_id)')->where(['customer.owner_user_id' => array('neq', '')]); }); }; } // 过滤角色 $groupIds = db('admin_access')->where("user_id", array("eq", $user_id))->column("group_id"); if (!in_array(1,$groupIds)){ $groupNameArray = db('admin_group')->where("pid", array("eq", 2))->where("id", array("in", $groupIds))->column("title"); if ($groupNameArray) $map['customer.crm_roziuw'] = array('in', $groupNameArray); } # 代办事项 - 待进入公海 $remindWhere = []; if ($is_remind) { $userIds = getSubUserId(false, 0, $user_id); $userIds[] = $user_id; $poolDays = $this->getPoolDay([], $userIds); $remindWhere['customer.customer_id'] = ['in', array_keys($poolDays)]; $remindWhere['customer.pool_remain'] = 0; if ($getCount == 1) { $intoPoolCount = db('crm_customer')->alias('customer')->where($remindWhere)->count(); return ['dataCount' => $intoPoolCount]; } } // 待办事项下需联系客户(逾期) $overdueWhere = ''; if (!empty($overdue)) { $overdueWhere = "(FROM_UNIXTIME(`customer`.`last_time`,'%Y-%m-%d') < FROM_UNIXTIME(`customer`.`next_time`,'%Y-%m-%d') OR (ISNULL(`customer`.`last_time`) AND `customer`.`next_time` < " . time() . "))"; } $dataCount = db('crm_customer')->alias('customer') ->where($map) ->where($dashboardWhere) ->where($searchMap) ->where($customerMap) ->where($authMap) ->where($partMap) ->where($otherMap) ->where($remindWhere) ->where($overdueWhere) ->count(); if ($getCount == 1) { $data['dataCount'] = $dataCount ?: 0; return $data; } $indexField = $fieldModel->getIndexField('crm_customer', $user_id, 1) ?: array('name'); // 列表展示字段 $userField = $fieldModel->getFieldByFormType('crm_customer', 'user'); // 人员类型 $structureField = $fieldModel->getFieldByFormType('crm_customer', 'structure'); // 部门类型 # 处理人员和部门类型的排序报错问题(前端传来的是包含_name的别名字段) $temporaryField = str_replace('_name', '', $order_field); if (in_array($temporaryField, $userField) || in_array($temporaryField, $structureField)) { $order_field = $temporaryField; } # 排序 if ($order_type && $order_field && $order_field != 'owner_user_structure_name') { $order = $fieldModel->getOrderByFormtype('crm_customer', 'customer', $order_field, $order_type); } else { $order = 'customer.update_time desc'; } $list = db('crm_customer')->alias('customer') ->where($map) ->where($dashboardWhere) ->where($searchMap) ->where($customerMap) ->where($authMap) ->where($partMap) ->where($otherMap) ->where($remindWhere) ->where($overdueWhere) ->limit($request['offset'], $request['length']) ->field($indexField) ->orderRaw($order) ->select(); $readAuthIds = $userModel->getUserByPer('crm', 'customer', 'read'); $updateAuthIds = $userModel->getUserByPer('crm', 'customer', 'update'); $deleteAuthIds = $userModel->getUserByPer('crm', 'customer', 'delete'); if (!empty($list)) { $customer_id_list = array_column($list, 'customer_id'); $business_count = db('crm_business') ->field([ 'COUNT(*)' => 'count', 'customer_id' ]) ->where([ 'customer_id' => ['IN', $customer_id_list] ]) ->group('customer_id') ->select(); $business_count = array_column($business_count, null, 'customer_id'); $field_list = $fieldModel->getIndexFieldConfig('crm_customer', $user_id); $field_list = array_column($field_list, 'field'); # 获取进入公海天数 $poolDays = $this->getPoolDay($customer_id_list); # 处理数据 $list = getFieldData($list, 'crm_customer', $user_id); # 整理数据 foreach ($list as $k => $v) { $list[$k]['create_user_id_info'] = isset($v['create_user_id']) ? $userModel->getUserById($v['create_user_id']) : []; $list[$k]['owner_user_id_info'] = isset($v['owner_user_id']) ? $userModel->getUserById($v['owner_user_id']) : []; $list[$k]['create_user_name'] = !empty($list[$k]['create_user_id_info']['realname']) ? $list[$k]['create_user_id_info']['realname'] : ''; $list[$k]['owner_user_name'] = !empty($list[$k]['owner_user_id_info']['realname']) ? $list[$k]['owner_user_id_info']['realname'] : ''; # 商机数 $list[$k]['business_count'] = $business_count[$v['customer_id']]['count'] ?: 0; # 权限 $roPre = $userModel->rwPre($user_id, $v['ro_user_id'], $v['rw_user_id'], 'read'); $rwPre = $userModel->rwPre($user_id, $v['ro_user_id'], $v['rw_user_id'], 'update'); $permission = []; $is_read = 0; $is_update = 0; $is_delete = 0; if (in_array($v['owner_user_id'], $readAuthIds) || $roPre || $rwPre) $is_read = 1; if (in_array($v['owner_user_id'], $updateAuthIds) || $rwPre) $is_update = 1; if (in_array($v['owner_user_id'], $deleteAuthIds)) $is_delete = 1; $permission['is_read'] = $is_read; $permission['is_update'] = $is_update; $permission['is_delete'] = $is_delete; $list[$k]['permission'] = $permission; # 关注 $starWhere = ['user_id' => $user_id, 'target_id' => $v['customer_id'], 'type' => 'crm_customer']; $star = Db::name('crm_star')->where($starWhere)->value('star_id'); $list[$k]['star'] = !empty($star) ? 1 : 0; # 日期 $list[$k]['create_time'] = !empty($v['create_time']) ? date('Y-m-d H:i:s', $v['create_time']) : null; $list[$k]['update_time'] = !empty($v['update_time']) ? date('Y-m-d H:i:s', $v['update_time']) : null; $list[$k]['last_time'] = !empty($v['last_time']) ? date('Y-m-d H:i:s', $v['last_time']) : null; # 进入公海天数 $list[$k]['pool_day'] = isset($poolDays[$v['customer_id']]) ? $poolDays[$v['customer_id']] : ''; $list[$k]['is_pool'] = 0; # 系统字段 负责人部门 zjf 20210726 $list[$k]['owner_user_structure_name'] = $list[$k]['owner_user_id_info']['structure_name']; } } $data = []; $data['list'] = $list ?: []; $data['dataCount'] = $dataCount ?: 0; return $data; } /** * 创建客户主表信息 * @param * @return * @author Michael_xu */ public function createData($param) { unset($param['excel']); // 客户扩展表数据 $customerData = []; $userId = $param['user_id']; $fieldModel = new \app\admin\model\Field(); $customerConfigModel = new \app\crm\model\CustomerConfig(); // 添加上限检测 if (!$customerConfigModel->checkData($param['create_user_id'], 1)) { $this->error = $customerConfigModel->getError(); return false; } // 获取客户时间 $param['obtain_time'] = time(); // 地址 $param['address'] = $param['address'] ? implode(chr(10), $param['address']) : ''; $param['deal_time'] = time(); //领取、分配时间 $param['deal_status'] = '未成交'; // 线索转客户 if ($param['leads_id']) { $leadsData = $param; $leadsData['create_user_id'] = $param['create_user_id']; $leadsData['owner_user_id'] = $param['owner_user_id']; $leadsData['ro_user_id'] = ''; $leadsData['rw_user_id'] = ''; $leadsData['detail_address'] = $param['detail_address'] ?: ''; $param = $leadsData; } // 数据验证 $validateResult = $this->fieldDataValidate($param, 'crm_customer', $userId); if (!empty($validateResult)) { $this->error = $validateResult; return false; } // 删除无效数据 unset($param['user_id']); unset($param['customer_id']); // 处理部门、员工、附件、多选类型字段 $arrFieldAtt = $fieldModel->getArrayField('crm_customer'); foreach ($arrFieldAtt as $k => $v) { $param[$v] = arrayToString($param[$v]); } // 处理日期(date)类型 $dateField = $fieldModel->getFieldByFormType('crm_customer', 'date'); if (!empty($dateField)) { foreach ($param as $key => $value) { if (in_array($key, $dateField) && empty($value)) $param[$key] = null; } } // 处理手写签名类型 $handwritingField = $fieldModel->getFieldByFormType('crm_customer', 'handwriting_sign'); if (!empty($handwritingField)) { foreach ($param as $key => $value) { if (in_array($key, $handwritingField)) { $param[$key] = !empty($value['file_id']) ? $value['file_id'] : ''; } } } // 处理地址、定位、日期区间、明细表格类型字段 $positionField = $fieldModel->getFieldByFormType('crm_customer', 'position'); $locationField = $fieldModel->getFieldByFormType('crm_customer', 'location'); $dateIntervalField = $fieldModel->getFieldByFormType('crm_customer', 'date_interval'); $detailTableField = $fieldModel->getFieldByFormType('crm_customer', 'detail_table'); $dateField = $fieldModel->getFieldByFormType('crm_customer', 'date'); foreach ($param as $key => $value) { // 处理地址类型字段数据 if (in_array($key, $positionField)) { if (!empty($value) && is_array($value)) { $customerData[] = [ 'field' => $key, 'content' => json_encode($value, JSON_NUMERIC_CHECK), 'create_time' => time() ]; $positionNames = array_column($value, 'name'); $param[$key] = implode(',', $positionNames); } elseif (!empty($value) && !is_array($value)) { $param[$key] = $value; } else { $param[$key] = ''; } } // 处理定位类型字段数据 if (in_array($key, $locationField)) { if (!empty($value) && isset($value['address'])) { $customerData[] = [ 'field' => $key, 'content' => json_encode($value, JSON_NUMERIC_CHECK), 'create_time' => time() ]; $param[$key] = $value['address']; } elseif (!empty($value) && !isset($value['address'])) { $vv['address'] = $value; $customerData[] = [ 'field' => $key, 'content' => json_encode($vv, JSON_NUMERIC_CHECK), 'create_time' => time() ]; $param[$key] = $value; } else { $param[$key] = ''; } } // 处理日期区间类型字段数据 if (in_array($key, $dateIntervalField)) { if (!empty($value) && is_array($value)) { $customerData[] = [ 'field' => $key, 'content' => json_encode($value, JSON_NUMERIC_CHECK), 'create_time' => time() ]; $param[$key] = trim(implode('_', $value), '"'); } elseif (!empty($value) && !is_array($value)) { $param[$key] = $value; } else { $param[$key] = ''; } } // 处理明细表格类型字段数据 if (in_array($key, $detailTableField)) { if (!empty($value)) { $customerData[] = [ 'field' => $key, 'content' => json_encode($value, JSON_NUMERIC_CHECK), 'create_time' => time() ]; $param[$key] = $key; } else { $param[$key] = ''; } } $param[$key] = !empty($value) ? trim($value, ',') : ''; if (in_array($key, $dateField)) { if (!empty($value)) { $customerData[] = [ 'field' => $key, 'content' => json_encode($value, JSON_NUMERIC_CHECK), 'create_time' => time() ]; $param[$key] = $value; } else { $param[$key] = null; } } } # 设置今日需联系客户 if (!empty($param['next_time']) && $param['next_time'] >= strtotime(date('Y-m-d 00:00:00'))) $param['is_dealt'] = 0; $pool_id = !empty($param['pool_id']) ? $param['pool_id'] : 0; unset($param['pool_id']); if ($this->data($param)->allowField(true)->isUpdate(false)->save()) { $data['customer_id'] = $this->customer_id; $data['name'] = $param['name']; if (!empty($pool_id)) { db('crm_customer_pool_relation')->insertGetId(['pool_id' => $pool_id, 'customer_id' => $this->customer_id]); } // 修改记录 if (empty($param['leads_id'])) { updateActionLog($param['create_user_id'], 'crm_customer', $data['customer_id'], '', '', '创建了客户'); RecordActionLog($param['create_user_id'], 'crm_customer', 'save', $param['name'], '', '', '新增了客户' . $param['name']); } // 添加活动记录 Db::name('crm_activity')->insert([ 'type' => 2, 'activity_type' => 2, 'activity_type_id' => $data['customer_id'], 'content' => $data['name'], 'create_user_id' => $param['create_user_id'], 'update_time' => time(), 'create_time' => time() ]); // 添加客户扩展数据 array_walk($customerData, function (&$val) use ($data) { $val['customer_id'] = $data['customer_id']; }); db('crm_customer_data')->insertAll($customerData); return $data; } else { $this->error = '添加失败'; return false; } } //根据IDs获取数组 public function getDataByStr($idstr) { $idArr = stringToArray($idstr); if (!$idArr) { return []; } $list = db('crm_customer')->where(['customer_id' => ['in', $idArr]])->select(); return $list; } /** * 编辑客户主表信息 * @param * @return * @author Michael_xu */ public function updateDataById($param, $customer_id = '') { // 客户扩展表数据 $customerData = []; $user_id = $param['user_id']; $dataInfo = $this->get($customer_id); if (!$dataInfo) { $this->error = '数据不存在或已删除'; return false; } $id = !empty($param['id']) ? $param['id'] : $customer_id; $param['customer_id'] = $customer_id; // 数据权限判断 $userModel = new \app\admin\model\User(); $auth_user_ids = $userModel->getUserByPer('crm', 'customer', 'update'); // 读写权限 $rwPre = $userModel->rwPre($user_id, $dataInfo['ro_user_id'], $dataInfo['rw_user_id'], 'update'); // 判断是否客户池数据 if (empty($param['pool_id'])) { $wherePool = $this->getWhereByPool(); $resPool = db('crm_customer')->alias('customer')->where(['customer_id' => $id])->where($wherePool)->find(); if ($resPool || (!in_array($dataInfo['owner_user_id'], $auth_user_ids) && !$rwPre)) { $this->error = '无权操作'; return false; } } // 过滤不能修改的字段 $unUpdateField = ['create_user_id', 'is_deleted', 'delete_time', 'user_id']; foreach ($unUpdateField as $v) { unset($param[$v]); } $param['deal_status'] = $dataInfo['deal_status']; $fieldModel = new \app\admin\model\Field(); // 数据验证 $validateResult = $this->fieldDataValidate($param, 'crm_customer', $user_id, $id); if (!empty($validateResult)) { $this->error = $validateResult; return false; } // 地址 $param['address'] = $param['address'] ? implode(chr(10), $param['address']) : ''; if ($param['deal_status'] == '已成交' && $dataInfo->data['deal_status'] == '未成交') { $param['deal_time'] = time(); } // 处理部门、员工、附件、多选类型字段 $arrFieldAtt = $fieldModel->getArrayField('crm_customer'); foreach ($arrFieldAtt as $k => $v) { if (isset($param[$v])) $param[$v] = arrayToString($param[$v]); } // 处理日期(date)类型 $dateField = $fieldModel->getFieldByFormType('crm_customer', 'date'); if (!empty($dateField)) { foreach ($param as $key => $value) { if (in_array($key, $dateField) && empty($value)) $param[$key] = null; } } // 处理手写签名类型 $handwritingField = $fieldModel->getFieldByFormType('crm_customer', 'handwriting_sign'); if (!empty($handwritingField)) { foreach ($param as $key => $value) { if (in_array($key, $handwritingField)) { $param[$key] = !empty($value['file_id']) ? $value['file_id'] : ''; } } } // 处理地址、定位、日期区间、明细表格类型字段 $positionField = $fieldModel->getFieldByFormType('crm_customer', 'position'); $locationField = $fieldModel->getFieldByFormType('crm_customer', 'location'); $dateIntervalField = $fieldModel->getFieldByFormType('crm_customer', 'date_interval'); $detailTableField = $fieldModel->getFieldByFormType('crm_customer', 'detail_table'); foreach ($param as $key => $value) { // 处理地址类型字段数据 if (in_array($key, $positionField)) { if (!empty($value)) { $customerData[] = [ 'field' => $key, 'content' => json_encode($value, JSON_NUMERIC_CHECK), 'create_time' => time() ]; $positionNames = array_column($value, 'name'); $param[$key] = implode(',', $positionNames); } else { $param[$key] = ''; } } // 处理定位类型字段数据 if (in_array($key, $locationField)) { if (!empty($value)) { $customerData[] = [ 'field' => $key, 'content' => json_encode($value, JSON_NUMERIC_CHECK), 'create_time' => time() ]; $param[$key] = $value['address']; } else { $param[$key] = ''; } } // 处理日期区间类型字段数据 if (in_array($key, $dateIntervalField)) { if (!empty($value)) { $customerData[] = [ 'field' => $key, 'content' => json_encode($value, JSON_NUMERIC_CHECK), 'create_time' => time() ]; $param[$key] = implode('_', $value); } else { $param[$key] = ''; } } // 处理明细表格类型字段数据 if (in_array($key, $detailTableField)) { if (!empty($value)) { $customerData[] = [ 'field' => $key, 'content' => json_encode($value, JSON_NUMERIC_CHECK), 'create_time' => time() ]; $param[$key] = $key; } else { $param[$key] = ''; } } } // 设置今日需联系客户 if (!empty($param['next_time']) && $param['next_time'] >= strtotime(date('Y-m-d 00:00:00'))) $param['is_dealt'] = 0; // 修改数据 if ($this->update($param, ['customer_id' => $customer_id], true)) { $data['customer_id'] = $customer_id; // 修改公海 if (!empty($param['pool_id'])) { db('crm_customer_pool_relation')->where('customer_id', $customer_id)->update(['pool_id' => $param['pool_id']]); } // 修改记录 updateActionLog($user_id, 'crm_customer', $customer_id, $dataInfo->data, $param); RecordActionLog($user_id, 'crm_customer', 'update', $dataInfo['name'], $dataInfo->data, $param); // 添加客户扩展数据 db('crm_customer_data')->where('customer_id', $customer_id)->delete(); array_walk($customerData, function (&$val) use ($customer_id) { $val['customer_id'] = $customer_id; }); db('crm_customer_data')->insertAll($customerData); return $data; } else { $this->error = '编辑失败'; return false; } } /** * 客户数据 * * @param string $id * @param int $userId * @return Common|array|bool|\PDOStatement|string|\think\Model|null * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\ModelNotFoundException * @throws \think\exception\DbException */ public function getDataById($id = '', $userId = 0, $model = '') { $dataInfo = db('crm_customer')->where(['customer_id' => $id])->find(); if (!$dataInfo) { $this->error = '数据不存在或已删除'; return false; } if (empty($model) && $model != 'update') { $grantData = getFieldGrantData($userId); foreach ($grantData['crm_customer'] as $key => $value) { foreach ($value as $ke => $va) { if ($va['maskType'] != 0) { $fieldGrant[$ke]['maskType'] = $va['maskType']; $fieldGrant[$ke]['form_type'] = $va['form_type']; $fieldGrant[$ke]['field'] = $va['field']; } } } foreach ($fieldGrant as $key => $val) { //掩码相关类型字段 if ($val['maskType'] != 0 && $val['form_type'] == 'mobile') { $pattern = "/(1[3458]{1}[0-9])[0-9]{4}([0-9]{4})/i"; $rs = preg_replace($pattern, "$1****$2", $dataInfo[$val['field']]); $dataInfo[$val['field']] = !empty($dataInfo[$val['field']]) ? (string)$rs : null; } elseif ($val['maskType'] != 0 && $val['form_type'] == 'email') { $email_array = explode("@", $dataInfo[$val['field']]); $prevfix = (strlen($email_array[0]) < 4) ? "" : substr($dataInfo[$val['field']], 0, 2); //邮箱前缀 $str = preg_replace('/([\d\w+_-]{0,100})@/', "***@", $dataInfo[$val['field']], -1, $count); $rs = $prevfix . $str; $dataInfo[$val['field']] = !empty($dataInfo[$val['field']]) ? $rs : null; } elseif ($val['maskType'] != 0 && in_array($val['form_type'], ['position', 'floatnumber'])) { $dataInfo[$val['field']] = !empty($dataInfo[$val['field']]) ? (string)substr_replace($dataInfo[$val['field']], '*****', 0, strlen($dataInfo[$val['field']])) : null; } } } $userModel = new \app\admin\model\User(); $dataInfo['create_user_id_info'] = isset($dataInfo['create_user_id']) ? $userModel->getUserById($dataInfo['create_user_id']) : []; $dataInfo['owner_user_id_info'] = !empty($dataInfo['owner_user_id']) ? $userModel->getUserById($dataInfo['owner_user_id']) : []; $dataInfo['before_owner_user_id_info'] = !empty($dataInfo['before_owner_user_id']) ? $userModel->getUserById($dataInfo['before_owner_user_id']) : []; $dataInfo['create_user_name'] = !empty($dataInfo['create_user_id_info']['realname']) ? $dataInfo['create_user_id_info']['realname'] : ''; $dataInfo['owner_user_name'] = !empty($dataInfo['owner_user_id_info']['realname']) ? $dataInfo['owner_user_id_info']['realname'] : ''; $dataInfo['before_owner_user_name'] = !empty($dataInfo['before_owner_user_id_info']['realname']) ? $dataInfo['before_owner_user_id_info']['realname'] : ''; # 公海信息 $poolData = $this->getPoolDay([$id]); $dataInfo['pool_day'] = !empty($poolData[$id]) ? $poolData[$id] : ''; $dataInfo['is_pool'] = !empty($dataInfo['owner_user_id']) ? 0 : 1; # 关注 $starId = empty($userId) ? 0 : Db::name('crm_star')->where(['user_id' => $userId, 'target_id' => $id, 'type' => 'crm_customer'])->value('star_id'); $dataInfo['star'] = !empty($starId) ? 1 : 0; # 首要联系人 $primaryId = Db::name('crm_contacts')->where(['customer_id' => $id, 'primary' => 1])->value('contacts_id'); $dataInfo['contacts_id'] = !empty($primaryId) && $this->getContactsAuth($primaryId) ? $primaryId : 0; # 处理时间格式 $fieldModel = new \app\admin\model\Field(); $datetimeField = $fieldModel->getFieldByFormType('crm_customer', 'datetime'); //日期时间类型 foreach ($datetimeField as $key => $val) { $dataInfo[$val] = !empty($dataInfo[$val]) ? date('Y-m-d H:i:s', $dataInfo[$val]) : null; } $dataInfo['create_time'] = !empty($dataInfo['create_time']) ? date('Y-m-d H:i:s', $dataInfo['create_time']) : null; $dataInfo['update_time'] = !empty($dataInfo['update_time']) ? date('Y-m-d H:i:s', $dataInfo['update_time']) : null; $dataInfo['last_time'] = !empty($dataInfo['last_time']) ? date('Y-m-d H:i:s', $dataInfo['last_time']) : null; $dataInfo['into_pool_time'] = !empty($dataInfo['into_pool_time']) ? date('Y-m-d H:i:s', $dataInfo['into_pool_time']) : null; // 字段授权 if (!empty($userId)) { $grantData = getFieldGrantData($userId); $userLevel = isSuperAdministrators($userId); foreach ($dataInfo as $key => $value) { if (!$userLevel && !empty($grantData['crm_customer'])) { $status = getFieldGrantStatus($key, $grantData['crm_customer']); # 查看权限 if ($status['read'] == 0) unset($dataInfo[$key]); } } } // 新建发票时,使用的联系人数据(首要联系人) $contactsInfo = db('crm_contacts')->field(['mobile', 'name', 'telephone', 'detail_address'])->where(['customer_id' => $id, 'primary' => 1])->find(); $contactsMobile = !empty($contactsInfo['mobile']) ? $contactsInfo['mobile'] : $contactsInfo['telephone']; $dataInfo['contacts_name'] = $contactsInfo['name']; $dataInfo['contacts_mobile'] = $contactsMobile; $dataInfo['contacts_address'] = $contactsInfo['detail_address']; return $dataInfo; } /** * [客户统计] * @param * @return * @author Michael_xu */ public function getStatistics($request) { $userModel = new \app\admin\model\User(); $adminModel = new \app\admin\model\Admin(); $request['start_time'] = strtotime($request['start_time']); $request['end_time'] = strtotime($request['end_time']); $perUserIds = $userModel->getUserByPer('bi', 'customer', 'read'); //权限范围内userIds $whereArr = $adminModel->getWhere($request, '', $perUserIds); //统计条件 $userIds = $whereArr['userIds']; $request = $this->fmtRequest($request); $map = $request['map'] ?: []; unset($map['search']); $where = []; //时间段 $start_time = $map['start_time']; $end_time = $map['end_time'] ? $map['end_time'] : time(); if ($start_time && $end_time) { $start_date = date('Y-m-d', $start_time); $end_date = date('Y-m-d', $end_time); $where_time = " BETWEEN {$start_time} AND {$end_time} "; $where_date = " BETWEEN '{$start_date}' AND '{$end_date}' "; } else { $where_time = " > 0 "; $where_date = " != '' "; } //员工IDS $map_user_ids = []; if (!empty($map['user_id'])) { $map_user_ids = array($map['user_id']); } elseif (!empty($map['structure_id'])) { $map_user_ids = $userModel->getSubUserByStr($map['structure_id'], 2); } $prefix = config('database.prefix'); $count = count($userIds); $configModel = new \app\crm\model\ConfigData(); $configInfo = $configModel->getData(); $follow_day = $configInfo['follow_day'] ?: 0; $deal_day = $configInfo['deal_day'] ?: 0; //默认公海条件(没有负责人或已经到期) $data['follow_time'] = time() - $follow_day * 86400; $data['deal_time'] = time() - $deal_day * 86400; $data['deal_status'] = '未成交'; $sql = ''; foreach ($userIds as $key => $user_id) { $sql .= " SELECT (SELECT realname FROM {$prefix}admin_user WHERE id = {$user_id}) as realname, COUNT(cu.customer_id) AS customer_num, SUM(cu.deal_status = '已成交') AS deal_customer_num, IFNULL( (SELECT SUM(money) FROM {$prefix}crm_contract WHERE owner_user_id = {$user_id} AND order_date {$where_date} AND check_status = 2 ), 0 ) as contract_money, IFNULL( (SELECT SUM(money) FROM {$prefix}crm_receivables WHERE owner_user_id = {$user_id} AND return_time {$where_date} AND check_status = 2 ), 0 ) as receivables_money FROM {$prefix}crm_customer as cu WHERE (cu.create_time {$where_time} OR obtain_time {$where_time}) AND cu.owner_user_id = {$user_id} AND (( ( deal_time > " . $data['deal_time'] . " ) OR (update_time > " . $data['follow_time'] . " AND deal_time > " . $data['deal_time'] . "))OR deal_status = '已成交' OR is_lock = 1 ) "; if ($count > 1 && $key != $count - 1) { $sql .= " UNION ALL "; } } if ($sql == '') { return []; } $customerCount = 0; # 客户总数 $dealCustomerCount = 0; # 成交客户总数 $contractMoneyCount = 0; # 合同总金额 $receivablesMoneyCount = 0; # 回款总金额 $list = queryCache($sql); foreach ($list as &$val) { $val['deal_customer_num'] = Floor($val['deal_customer_num']); $val['contract_money'] = Floor($val['contract_money']); $val['receivables_money'] = Floor($val['receivables_money']); $val['deal_customer_rate'] = $val['customer_num'] ? round(($val['deal_customer_num'] / $val['customer_num']) * 100, 2) : 0; $val['un_receivables_money'] = $val['contract_money'] - $val['receivables_money'] >= 0 ? $val['contract_money'] - $val['receivables_money'] : '0.00'; $val['deal_receivables_rate'] = $val['contract_money'] ? round(($val['receivables_money'] / $val['contract_money']) * 100, 2) : 0; $customerCount += $val['customer_num']; $dealCustomerCount += $val['deal_customer_num']; $contractMoneyCount += $val['contract_money']; $receivablesMoneyCount += $val['receivables_money']; } return ['list' => $list, 'total' => [ 'realname' => '总计', 'customer_num' => $customerCount, 'deal_customer_num' => $dealCustomerCount, 'contract_money' => $contractMoneyCount, 'receivables_money' => $receivablesMoneyCount ]]; } /** * [客户数量] * @param * @return * @author Michael_xu */ public function getDataCount($map) { $dataCount = $this->where($map)->fetchSql(false)->count(); $count = $dataCount ?: 0; return $count; } /** * 客户默认条件 * * @return array * @since 2021-05-12 * @author fanqi */ public function getWhereByCustomer() { return ['customer.owner_user_id' => ['neq', 0]]; } /** * 客户公海条件 * * @return array * @since 2021-05-12 * @author fanqi */ public function getWhereByPool() { return ['customer.owner_user_id' => ['eq', 0]]; } /** * 客户权限判断(是否客户公海) * @param type 1 是公海返回false,默认是公海返回true * @return * @author Michael_xu */ public function checkData($customer_id, $type = '') { //权限范围 $userModel = new \app\admin\model\User(); $authIds = $userModel->getUserByPer(); //权限范围的user_id //是否客户公海 $map = $this->getWhereByPool(); $where['customer_id'] = $customer_id; $customerInfo = db('crm_customer')->alias('customer')->where($where)->where($map)->find(); if ($customerInfo && !$type) { return true; } else { $customerInfo = db('crm_customer')->where(['customer_id' => $customer_id])->find(); if (in_array($customerInfo['owner_user_id'], $authIds)) { return true; } } $this->error = '没有权限'; return false; } /** * 客户到期天数 * * @param array $customerIds 客户ID * @return array * @since 2021-04-19 * @author fanqi */ public function getPoolDay($customerIds = [], $userIds = []) { $result = []; $where['pool.status'] = 1; # 公海开启 $where['pool.remind_conf'] = 1; # 提醒开启 $poolRules = db('crm_customer_pool_rule')->alias('rule')->field(['rule.*', 'pool.remain_day'])->join('__CRM_CUSTOMER_POOL__ pool', 'rule.pool_id = pool.pool_id', 'LEFT')->where($where)->select(); if (!empty($poolRules)) { foreach ($poolRules as $key => $value) { if ($value['type'] == 1) $result[] = $this->getFollowUpQueryResult($value['level_conf'], $value['level'], $value['deal_handle'], $value['business_handle'], $value['remain_day'], $customerIds, $userIds); if ($value['type'] == 2) $result[] = $this->getBusinessQueryResult($value['level_conf'], $value['level'], $value['deal_handle'], $value['remain_day'], $customerIds, $userIds); if ($value['type'] == 3) $result[] = $this->getDealQueryResult($value['level_conf'], $value['level'], $value['business_handle'], $value['remain_day'], $customerIds, $userIds); } } return $this->getMinIntoPoolDay($result); } /** * 获取每个客户最快进入公海天数 * * @param $data * @return array * @since 2021-04-19 * @author fanqi */ private function getMinIntoPoolDay($data) { $result = []; $temporary = []; # 整理数据 foreach ($data as $k1 => $v1) { if (empty($v1)) continue; foreach ($v1 as $k2 => $v2) { $temporary[$k2][] = $v2; } } # 每个客户最快进入公海天数 foreach ($temporary as $k1 => $v1) { $result[$k1] = min($v1); } return $result; } /** * 获取公海规则最小数字(最快进入公海天数) * * @param $data * @return int * @since 2021-04-19 * @author fanqi */ private function getMinDay($data) { $number = 1; foreach ($data as $k1 => $v1) { if (empty($number) || $v1['limit_day'] < $number) $number = $v1['limit_day']; } return $number; } /** * N天内无新建跟进记录的客户 * * @param int $type 类型:1 所有用户,不分级别,2 根据用户级别区分 * @param Json $levels 级别数据 * @param int $dealStatus 是否排除成交用户:1 排除,0 不排除 * @param int $businessStatus 是否排除有商机用户:1 排除,0 不排除 * @param int $remainDay 提前几天提醒 * @param array $customerIds 客户ID * @param array $userIds 员工ID * @return array * @author fanqi * @since 2021-04-01 */ private function getFollowUpQueryResult($type, $levels, $dealStatus, $businessStatus, $remainDay, $customerIds = [], $userIds = []) { # 结果数据 $result = []; # 转换格式 $levels = json_decode($levels, true); # 用于最后计算还有几天进入公海池 $limitDay = []; # 数据权限 $authUserIds = (new User())->getUserByPer('crm', 'customer', 'index'); if (empty($authUserIds)) return $result; # 默认条件 $where = "`customer`.`owner_user_id` IN (" . implode(',', $authUserIds) . ")"; # 所有用户,不区分级别 if ($type == 1) { foreach ($levels as $k1 => $v1) { if (!empty($v1['limit_day'])) { $time = strtotime(date('Y-m-d 00:00:00', time() - 86400 * $v1['limit_day'])); $where .= " AND ((`customer`.`last_time` > " . $time . " AND `customer`.`last_time` > `customer`.`obtain_time`) OR (`customer`.`obtain_time` > " . $time . " AND `customer`.`obtain_time` > `customer`.`last_time`) OR (`customer`.`obtain_time` > " . $time . " AND ISNULL(`customer`.`last_time`)))"; $limitDay['all'] = $v1['limit_day']; } } } # 根据用户级别设置条件 if ($type == 2) { foreach ($levels as $k1 => $v1) { if (!empty($v1['level']) && !empty($v1['limit_day'])) { $time = strtotime(date('Y-m-d 00:00:00', time() - 86400 * $v1['limit_day'])); if ($k1 == 0) { $where .= " AND ( ((`customer`.`level` = '" . $v1['level'] . "' AND `customer`.`last_time` > " . $time . " AND `customer`.`last_time` > `customer`.`obtain_time`) OR (`customer`.`level` = '" . $v1['level'] . "' AND `customer`.`obtain_time` > " . $time . " AND `customer`.`obtain_time` > `customer`.`last_time`) OR (`customer`.`level` = '" . $v1['level'] . "' AND `customer`.`obtain_time` > " . $time . " AND ISNULL(`customer`.`last_time`)))"; } else { $where .= " OR ((`customer`.`level` = '" . $v1['level'] . "' AND `customer`.`last_time` > " . $time . " AND `customer`.`last_time` > `customer`.`obtain_time`) OR (`customer`.`level` = '" . $v1['level'] . "' AND `customer`.`obtain_time` > " . $time . " AND `customer`.`obtain_time` > `customer`.`last_time`) OR (`customer`.`level` = '" . $v1['level'] . "' AND `customer`.`obtain_time` > " . $time . " AND ISNULL(`customer`.`last_time`)))"; } $limitDay[$v1['level']] = $v1['limit_day']; } } # 获取最小天数,对于没有设置级别的客户数据使用 $minLimit = $this->getMinDay($levels); $minTime = strtotime(date('Y-m-d 00:00:00', time() - 86400 * $minLimit)); $where .= " OR ((!`customer`.`level` AND `customer`.`last_time` > " . $minTime . " AND `customer`.`last_time` > `customer`.`obtain_time`) OR (!`customer`.`level` AND `customer`.`obtain_time` > " . $time . " AND `customer`.`obtain_time` > `customer`.`last_time`) OR (!`customer`.`level` AND `customer`.`obtain_time` > " . $minTime . " AND ISNULL(`customer`.`last_time`))) )"; } # 选择不进入公海的客户(已成交客户) if (!empty($dealStatus)) $where .= " AND (`customer`.`deal_status` <> '已成交' OR ISNULL(`customer`.`deal_status`))"; # 选择不进入公海的客户(有商机客户) if (!empty($businessStatus)) $where .= " AND ISNULL(`business`.`customer_id`)"; # 查询指定客户 if (!empty($customerIds)) $where .= " AND `customer`.`customer_id` IN (" . implode(',', $customerIds) . ")"; # 查询指定员工 if (!empty($userIds)) $where .= " AND `customer`.`owner_user_id` IN (" . implode(',', $userIds) . ")"; # 锁定的客户不提醒 $where .= " AND `customer`.`is_lock` = 0"; # 查询符合条件的客户 $data = db('crm_customer')->alias('customer') ->field(['customer.customer_id', 'customer.obtain_time', 'customer.level', 'customer.last_time']) ->join('__CRM_BUSINESS__ business', 'business.customer_id = customer.customer_id', 'LEFT') ->where($where)->select(); # 计算到期天数 foreach ($data as $k1 => $v1) { if ($type == 1) { $customerTime = !empty($v1['last_time']) && $v1['last_time'] > $v1['obtain_time'] ? $v1['last_time'] : $v1['obtain_time']; $date = date('Y-m-d 00:00:00', ($customerTime + $limitDay['all'] * 86400) - $remainDay * 86400); $dateRange = strtotime($date); if (time() > $dateRange) { $inPool = (($customerTime + $limitDay['all'] * 86400) - time()) / 86400; $result[$v1['customer_id']] = $inPool > 0 ? round($inPool) : 0; } } if ($type == 2) { $customerTime = !empty($v1['last_time']) && $v1['last_time'] > $v1['obtain_time'] ? $v1['last_time'] : $v1['obtain_time']; $day = !empty($limitDay[$v1['level']]) ? $limitDay[$v1['level']] : min($limitDay); $date = date('Y-m-d 00:00:00', ($customerTime + $day * 86400) - $remainDay * 86400); $dateRange = strtotime($date); if (time() > $dateRange) { $inPool = (($customerTime + $day * 86400) - time()) / 86400; $result[$v1['customer_id']] = $inPool > 0 ? round($inPool) : 0; } } } return $result; } /** * N天内无新建商机的客户 * * @param int $type 类型:1 所有用户,不分级别,2 根据用户级别区分 * @param Json $levels 级别数据 * @param int $dealStatus 是否排除成交用户:1 排除,0 不排除 * @param int $remainDay 提前几天提醒 * @param array $customerIds 客户ID * @param array $userIds 员工ID * @return array|false|string * @since 2021-04-01 * @author fanqi */ private function getBusinessQueryResult($type, $levels, $dealStatus, $remainDay, $customerIds = [], $userIds = []) { # 结果数据 $result = []; # 转换格式 $levels = json_decode($levels, true); # 用于最后计算还有几天进入公海池 $limitDay = []; # 数据权限 $authUserIds = (new User())->getUserByPer('crm', 'customer', 'index'); if (empty($authUserIds)) return $result; # 默认条件 $where = "`customer`.`owner_user_id` IN (" . implode(',', $authUserIds) . ")"; # 所有用户,不区分级别 if ($type == 1) { foreach ($levels as $k1 => $v1) { if (!empty($v1['limit_day'])) { $time = strtotime(date('Y-m-d 00:00:00', time() - 86400 * $v1['limit_day'])); $where .= " AND ( (ISNULL(`business`.`customer_id`) AND `customer`.`obtain_time` > " . $time . ") OR (`customer`.`obtain_time` > " . $time . " AND `customer`.`obtain_time` > `business`.`create_time`) OR (`business`.`create_time` > " . $time . " AND `business`.`create_time` > `customer`.`obtain_time`) )"; $limitDay['all'] = $v1['limit_day']; } } } # 根据用户级别设置条件 if ($type == 2) { foreach ($levels as $k1 => $v1) { if (!empty($v1['level']) && !empty($v1['limit_day'])) { $time = strtotime(date('Y-m-d 00:00:00', time() - 86400 * $v1['limit_day'])); if ($k1 == 0) { $where .= " AND ( ((ISNULL(`business`.`customer_id`) AND `customer`.`obtain_time` > " . $time . " AND `customer`.`level` = '" . $v1['level'] . "') OR (`customer`.`obtain_time` > " . $time . " AND `customer`.`obtain_time` > `business`.`create_time` AND `customer`.`level` = '" . $v1['level'] . "') OR (`business`.`create_time` > $time AND `business`.`create_time` > `customer`.`obtain_time` AND `customer`.`level` = '" . $v1['level'] . "'))"; } else { $where .= " OR ((ISNULL(`business`.`customer_id`) AND `customer`.`obtain_time` > " . $time . " AND `customer`.`level` = '" . $v1['level'] . "') OR (`customer`.`obtain_time` > " . $time . " AND `customer`.`obtain_time` > `business`.`create_time` AND `customer`.`level` = '" . $v1['level'] . "') OR (`business`.`create_time` > $time AND `business`.`create_time` > `customer`.`obtain_time` AND `customer`.`level` = '" . $v1['level'] . "'))"; } } $limitDay[$v1['level']] = $v1['limit_day']; } # 获取最小天数,对于没有设置级别的客户数据使用 $minLimit = $this->getMinDay($levels); $minTime = strtotime(date('Y-m-d 00:00:00', time() - 86400 * $minLimit)); $where .= " OR ((ISNULL(`business`.`customer_id`) AND `customer`.`obtain_time` > " . $minTime . " AND !`customer`.`level`) OR (`customer`.`obtain_time` > " . $minTime . " AND `customer`.`obtain_time` > `business`.`create_time` AND !`customer`.`level`) OR (`business`.`create_time` > " . $minTime . " AND `business`.`create_time` > `customer`.`obtain_time` AND !`customer`.`level`)) )"; } # 选择不进入公海的客户(已成交客户) if (!empty($dealStatus)) $where .= " AND (`customer`.`deal_status` <> '已成交' OR ISNULL(`customer`.`deal_status`))"; # 查询指定客户 if (!empty($customerIds)) $where .= " AND `customer`.`customer_id` IN (" . implode(',', $customerIds) . ")"; # 查询指定员工 if (!empty($userIds)) $where .= " AND `customer`.`owner_user_id` IN (" . implode(',', $userIds) . ")"; # 锁定的客户不提醒 $where .= " AND `customer`.`is_lock` = 0"; # 查询匹配条件的客户 $data = db('crm_customer')->alias('customer') ->field(['customer.customer_id', 'customer.obtain_time AS customer_time', 'customer.level', 'business.create_time AS business_time']) ->join('__CRM_BUSINESS__ business', 'business.customer_id = customer.customer_id', 'LEFT') ->where($where)->select(); # 计算到期天数 foreach ($data as $k1 => $v1) { if ($type == 1) { $customerTime = !empty($v1['business_time']) && $v1['business_time'] > $v1['customer_time'] ? $v1['business_time'] : $v1['customer_time']; $date = date('Y-m-d 00:00:00', ($customerTime + $limitDay['all'] * 86400) - $remainDay * 86400); $dateRange = strtotime($date); if (time() > $dateRange) { $inPool = (($customerTime + $limitDay['all'] * 86400) - time()) / 86400; $result[$v1['customer_id']] = $inPool > 0 ? round($inPool) : 0; } } if ($type == 2) { $customerTime = !empty($v1['business_time']) && $v1['business_time'] > $v1['customer_time'] ? $v1['business_time'] : $v1['customer_time']; $day = !empty($limitDay[$v1['level']]) ? $limitDay[$v1['level']] : min($limitDay); $date = date('Y-m-d 00:00:00', ($customerTime + $day * 86400) - $remainDay * 86400); $dateRange = strtotime($date); if (time() > $dateRange) { $inPool = (($customerTime + $day * 86400) - time()) / 86400; $result[$v1['customer_id']] = $inPool > 0 ? round($inPool) : 0; } } } return $result; } /** * N天内没有成交的客户 * * @param int $type 类型:1 所有用户,不分级别,2 根据用户级别区分 * @param Json $levels 级别数据 * @param int $businessStatus 是否排除有商机用户:1 排除,0 不排除 * @param int $remainDay 提前几天提醒 * @param array $customerIds 客户ID * @param array $userIds 员工ID * @return array|false|string * @since 2021-04-01 * @author fanqi */ private function getDealQueryResult($type, $levels, $businessStatus, $remainDay, $customerIds = [], $userIds = []) { # 结果数据 $result = []; # 转换格式 $levels = json_decode($levels, true); # 用于最后计算还有几天进入公海池 $limitDay = []; # 数据权限 $authUserIds = (new User())->getUserByPer('crm', 'customer', 'index'); if (empty($authUserIds)) return $result; # 默认条件 $where = "`customer`.`owner_user_id` IN (" . implode(',', $authUserIds) . ")"; # 所有用户,不区分级别 if ($type == 1) { foreach ($levels as $k1 => $v1) { if (!empty($v1['limit_day'])) { $time = strtotime(date('Y-m-d 00:00:00', time() - 86400 * $v1['limit_day'])); $where .= " AND ( (ISNULL(`contract`.`customer_id`) AND `customer`.`obtain_time` > " . $time . ") OR (`customer`.`obtain_time` > " . $time . " AND `customer`.`obtain_time` > `contract`.`create_time`) OR (`contract`.`create_time` > " . $time . " AND `contract`.`create_time` > `customer`.`obtain_time`) )"; $limitDay['all'] = $v1['limit_day']; } } } # 根据用户级别设置条件 if ($type == 2) { foreach ($levels as $k1 => $v1) { if (!empty($v1['level']) && !empty($v1['limit_day'])) { $time = strtotime(date('Y-m-d 00:00:00', time() - 86400 * $v1['limit_day'])); if ($k1 == 0) { $where .= " AND ( ((ISNULL(`contract`.`customer_id`) AND `customer`.`level` = '" . $v1['level'] . "' AND `customer`.`obtain_time` > " . $time . ") OR (`customer`.`level` = '" . $v1['level'] . "' AND `customer`.`obtain_time` > " . $time . " AND `customer`.`obtain_time` > `contract`.`create_time`) OR (`contract`.`create_time` > " . $time . " AND `contract`.`create_time` > `customer`.`obtain_time` AND `customer`.`level` = '" . $v1['level'] . "'))"; } else { $where .= " OR ((ISNULL(`contract`.`customer_id`) AND `customer`.`level` = '" . $v1['level'] . "' AND `customer`.`obtain_time` > " . $time . ") OR (`customer`.`level` = '" . $v1['level'] . "' AND `customer`.`obtain_time` > " . $time . " AND `customer`.`obtain_time` > `contract`.`create_time`) OR (`contract`.`create_time` > " . $time . " AND `contract`.`create_time` > `customer`.`obtain_time` AND `customer`.`level` = '" . $v1['level'] . "'))"; } } $limitDay[$v1['level']] = $v1['limit_day']; } # 获取最小天数,对于没有设置级别的客户数据使用 $minLimit = $this->getMinDay($levels); $minTime = strtotime(date('Y-m-d 00:00:00', time() - 86400 * $minLimit)); $where .= " OR ((ISNULL(`contract`.`customer_id`) AND !`customer`.`level` AND `customer`.`obtain_time` > " . $minTime . ") OR (!`customer`.`level` AND `customer`.`obtain_time` > " . $minTime . " AND `customer`.`obtain_time` > `contract`.`create_time`) OR (`contract`.`create_time` > " . $minTime . " AND `contract`.`create_time` > `customer`.`obtain_time` AND !`customer`.`level`)) )"; } # 选择不进入公海的客户(有商机客户) if (!empty($businessStatus)) $where .= " AND ISNULL(`business`.`customer_id`)"; # 查询指定客户 if (!empty($customerIds)) $where .= " AND `customer`.`customer_id` IN (" . implode(',', $customerIds) . ")"; # 查询指定员工 if (!empty($userIds)) $where .= " AND `customer`.`owner_user_id` IN (" . implode(',', $userIds) . ")"; # 锁定的客户不提醒 $where .= " AND `customer`.`is_lock` = 0"; # 查询符合条件的客户 $data = db('crm_customer')->alias('customer') ->field(['customer.customer_id', 'customer.obtain_time AS customer_time', 'customer.level', 'contract.create_time AS contract_time']) ->join('__CRM_BUSINESS__ business', 'business.customer_id = customer.customer_id', 'LEFT') ->join('__CRM_CONTRACT__ contract', 'contract.customer_id = customer.customer_id', 'LEFT') ->where($where)->select(); # 计算到期天数 foreach ($data as $k1 => $v1) { if ($type == 1) { $customerTime = !empty($v1['contract_time']) && $v1['contract_time'] > $v1['customer_time'] ? $v1['contract_time'] : $v1['customer_time']; $date = date('Y-m-d 00:00:00', ($customerTime + $limitDay['all'] * 86400) - $remainDay * 86400); $dateRange = strtotime($date); if (time() > $dateRange) { $inPool = (($customerTime + $limitDay['all'] * 86400) - time()) / 86400; $result[$v1['customer_id']] = $inPool > 0 ? round($inPool) : 0; } } if ($type == 2) { $customerTime = !empty($v1['contract_time']) && $v1['contract_time'] > $v1['customer_time'] ? $v1['contract_time'] : $v1['customer_time']; $day = !empty($limitDay[$v1['level']]) ? $limitDay[$v1['level']] : min($limitDay); $date = date('Y-m-d 00:00:00', ($customerTime + $day * 86400) - $remainDay * 86400); $dateRange = strtotime($date); if (time() > $dateRange) { $inPool = (($customerTime + $day * 86400) - time()) / 86400; $result[$v1['customer_id']] = $inPool > 0 ? round($inPool) : 0; } } } return $result; } /** * [今日进入客户池条件] * @param * @return * @author Michael_xu */ public function getWhereByToday() { $configModel = new \app\crm\model\ConfigData(); $configInfo = $configModel->getData(); $config = $configInfo['config'] ?: 0; $follow_day = $configInfo['follow_day'] ?: 0; $deal_day = $configInfo['deal_day'] ?: 0; $whereData = []; //启用 if ($config == 1) { //默认公海条件(没有负责人或已经到期) //通过提前提醒时间,计算查询时间段 if (($follow_day > 0) && ($deal_day > 0)) { $follow_between = array(strtotime(date('Y-m-d', time() - $follow_day * 86400)), time() - $follow_day * 86400); $deal_between = array(strtotime(date('Y-m-d', time() - $deal_day * 86400)), time() - $deal_day * 86400); $data['update_time'] = time() - $follow_day * 86400; $data['deal_time'] = time() - $deal_day * 86400; $data['update_between'] = $follow_between; $data['deal_between'] = $deal_between; if ($follow_day < $deal_day) { $whereData = function ($query) use ($data) { $query->where(['customer.owner_user_id' => 0]) ->whereOr(function ($query) use ($data) { $query->where(function ($query) use ($data) { $query->where(['customer.update_time' => array('between', $data['update_between'])]) ->whereOr(['customer.deal_time' => array('between', $data['deal_between'])]); }) ->where(['customer.is_lock' => 0]) ->where(['customer.deal_status' => ['neq', '已成交']]); }); }; } else { $whereData = function ($query) use ($data) { $query->where(['customer.owner_user_id' => 0]) ->whereOr(function ($query) use ($data) { $query->where(function ($query) use ($data) { $query->where(['customer.deal_time' => array('between', $data['deal_between'])]); }) ->where(['customer.is_lock' => 0]) ->where(['customer.deal_status' => ['neq', '已成交']]); }); }; } } else { $whereData['customer.customer_id'] = 0; } } else { $whereData['customer.owner_user_id'] = 0; $whereData['customer.update_time'] = array('between', array(strtotime(date('Y-m-d', time())), time())); } return $whereData ?: ''; } /** * 获取客户拥有数或锁定数 * * @param int $userId 用户ID * @param int $isDeal 成交客户是否占用拥有客户数条件:1 占用 0 不占用 * @param int $types 类型:1 拥有客户数,2 锁定客户数 * @return int * @since 2021-04-15 * @author fanqi */ public function getCountByHave($userId, $isDeal = 0, $types = 1) { # 默认条件 $where['owner_user_id'] = $userId; # 成交客户是否占用拥有客户数条件 if ($types == 1 && empty($isDeal)) { $where['deal_status'] = ['neq', '已成交']; } # 锁定客户数条件,默认排除已成交客户 if ($types == 2) { $where['deal_status'] = ['neq', '已成交']; $where['is_lock'] = 1; } return $this->where($where)->count(); } // public function getCountByHave($user_id, $is_deal = 0,$types = 1) // { // $where = []; // $where['owner_user_id'] = $user_id; // //公海逻辑 // $configModel = new \app\crm\model\ConfigData(); // $userModel = new \app\admin\model\User(); // $configInfo = $configModel->getData(); // $config = $configInfo['config'] ? : 0; // $follow_day = $configInfo['follow_day'] ? : 0; // $deal_day = $configInfo['deal_day'] ? : 0; // //默认条件(没有到期或已锁定) // $data['follow_time'] = time()-$follow_day*86400; // $data['deal_time'] = time()-$deal_day*86400; // $whereData = ''; // //公海开启 // if ($config == 1) { // switch ($types) { // case '1' : // if ($is_deal !== 1) { // //不包含成交客户 // $where['deal_status'] = ['neq','已成交']; // if ($follow_day < $deal_day) { // $whereData = function($query) use ($data){ // $query->where(function ($query) use ($data) { // $query->where(['update_time' => array('gt',$data['follow_time']),'deal_time' => array('gt',$data['deal_time'])]); // }); // }; // } else { // $whereData = function($query) use ($data){ // $query->where(function ($query) use ($data) { // $query->where(['deal_time' => array('gt',$data['deal_time'])]); // }); // }; // } // } else { // if ($follow_day < $deal_day) { // $whereData = function($query) use ($data){ // $query->where(function ($query) use ($data) { // $query->where(['update_time' => array('gt',$data['follow_time']),'deal_time' => array('gt',$data['deal_time'])]); // }) // ->whereOr(['deal_status' => ['eq','已成交']]); // }; // } else { // $whereData = function($query) use ($data){ // $query->where(function ($query) use ($data) { // $query->where(['deal_time' => array('gt',$data['deal_time'])]); // }) // ->whereOr(['deal_status' => ['eq','已成交']]); // }; // } // } // break; // case '2' : // $where['is_lock'] = ['eq',1]; // //默认不包含成交客户 // $where['deal_status'] = ['neq','已成交']; // break; // } // } else { // //公海未开启 // if ($is_deal !== 1) { // //不包含成交客户 // $where['deal_status'] = ['neq','已成交']; // } // switch ($types) { // case '2' : // //锁定,默认不包含成交客户 // $where['deal_status'] = ['neq','已成交']; // $where['is_lock'] = 1; // break; // } // } // $count = $this->where($where)->where($whereData)->count(); // return $count ? : 0; // } /** * [客户成交新增数量] * @param * @return * @author Michael_xu */ public function getAddDealSql($map) { $prefix = config('database.prefix'); $sql = "SELECT '{$map['type']}' AS type, '{$map['start_time']}' AS start_time, '{$map['end_time']}' AS end_time, IFNULL( ( SELECT count(customer_id) FROM {$prefix}crm_customer WHERE create_time BETWEEN {$map['start_time']} AND {$map['end_time']} AND owner_user_id IN ({$map['create_user_id']}) ), 0 ) AS customer_num, IFNULL( count(customer_id), 0 ) AS deal_customer_num FROM {$prefix}crm_customer WHERE create_time BETWEEN {$map['start_time']} AND {$map['end_time']} AND deal_status = '{$map['deal_status']}' AND owner_user_id IN ({$map['create_user_id']})"; return $sql; } /** * [客户统计sql] * @param * @return * @author Michael_xu */ public function getAddressCountBySql($map) { $prefix = config('database.prefix'); $sql = "SELECT '{$map['address']}' AS address, IFNULL( ( SELECT count(customer_id) FROM {$prefix}crm_customer WHERE address LIKE '%{$map['address']}%' AND owner_user_id IN ({$map['owner_user_id']}) ), 0 ) AS allCustomer, IFNULL( count(customer_id), 0 ) AS dealCustomer FROM {$prefix}crm_customer WHERE address LIKE '%{$map['address']}%' AND deal_status = '{$map['deal_status']}' AND owner_user_id IN ({$map['owner_user_id']})"; $list = $this->query($sql) ?: []; return $list; } /** * 获取附近的客户 * * @param $param * @return array * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\ModelNotFoundException * @throws \think\exception\DbException */ public function getNearbyList($param) { $apiCommon = new ApiCommon(); $userModel = new \app\admin\model\User(); $poolStatus = checkPerByAction('crm', 'customer', 'pool'); # 客户 $customerAuth = []; $customerWhere = []; if ((!empty($param['type']) && $param['type'] == 2) || !$poolStatus) { $customerWhere = $this->getWhereByCustomer(); } # 公海 $poolWhere = []; if (!empty($param['type']) && $param['type'] == 9 && $poolStatus) { $poolWhere = ['customer.owner_user_id' => 0]; } # 附近 $lngLatRange = $this->getLngLatRange($param['lng'], $param['lat'], $param['distance']); $lngLatWhere = function ($query) use ($lngLatRange) { $query->where(['lng' => ['egt', $lngLatRange['minLng']]]); $query->where(['lng' => ['elt', $lngLatRange['maxLng']]]); $query->where(['lat' => ['egt', $lngLatRange['minLat']]]); $query->where(['lat' => ['elt', $lngLatRange['maxLat']]]); }; # 经纬度值计算出错 if (empty($lngLatRange['minLng']) || empty($lngLatRange['maxLng']) || empty($lngLatRange['minLat']) || empty($lngLatRange['maxLat'])) { return ['list' => [], 'count' => 0]; } $count = db('crm_customer')->alias('customer')->where($customerWhere)->where($poolWhere)->where($lngLatWhere)->count(); $list = db('crm_customer')->alias('customer') ->where($customerWhere) ->where($poolWhere) ->where($lngLatWhere) ->where($customerAuth) ->field(['customer_id', 'name', 'address', 'detail_address', 'owner_user_id', 'lat', 'lng', 'next_time', 'last_time']) ->order('update_time', 'desc') ->select(); # 组装数据 foreach ($list as $key => $value) { # todo 暂时将查询写在循环中 $ownerUserInfo = !empty($value['owner_user_id']) ? $userModel->getUserById($value['owner_user_id']) : []; $ownerUserName = !empty($ownerUserInfo['realname']) ? $ownerUserInfo['realname'] : ''; $list[$key]['owner_user_name'] = !empty($ownerUserName) ? $ownerUserName : '暂无负责人'; $list[$key]['distance'] = $this->getLngLatDistance($param['lng'], $param['lat'], $value['lng'], $value['lat'], 1, 0); $list[$key]['last_time'] = !empty($value['last_time']) ? date('y-m-d H:i:s', $value['last_time']) : !empty($value['next_time']) ? date('y-m-d H:i:s', $value['next_time']) : null; if ($value['owner_user_id'] != 0) { $list[$key]['model'] = '客户'; } else { $list[$key]['model'] = '公海'; } } return ['list' => $list, 'count' => $count]; } /** * 计算两点地理坐标之间的距离 * * @param number $longitude1 起点经度 * @param number $latitude1 起点纬度 * @param number $longitude2 终点经度 * @param number $latitude2 终点纬度 * @param int $unit 单位:1米;2公里 * @param int $decimal 精度:保留小数位数 * @return float */ private function getLngLatDistance($longitude1, $latitude1, $longitude2, $latitude2, $unit = 2, $decimal = 2) { $EARTH_RADIUS = 6370.996; // 地球半径系数 $PI = 3.1415926; $radLat1 = $latitude1 * $PI / 180.0; $radLat2 = $latitude2 * $PI / 180.0; $radLng1 = $longitude1 * $PI / 180.0; $radLng2 = $longitude2 * $PI / 180.0; $a = $radLat1 - $radLat2; $b = $radLng1 - $radLng2; $distance = 2 * asin(sqrt(pow(sin($a / 2), 2) + cos($radLat1) * cos($radLat2) * pow(sin($b / 2), 2))); $distance = $distance * $EARTH_RADIUS * 1000; if ($unit == 2) $distance = $distance / 1000; return round($distance, $decimal); } /** * 获取经纬度范围值 * * @param $myLng * @param $myLat * @param $distance * @return array */ private function getLngLatRange($myLng, $myLat, $distance) { $pi = pi(); # 公里 $distance = $distance / 1000; # 计算纬度区间 $latRange = 180 / $pi * $distance / 6372.797; # 计算进度区间 $lngRang = $latRange / cos($myLat * $pi / 180); $maxLng = $myLng + $lngRang; # 最大经度 $minLng = $myLng - $lngRang; # 最小经度 $maxLat = $myLat + $latRange; # 最大纬度 $minLat = $myLat - $latRange; # 最小纬度 return ['maxLng' => $maxLng, 'minLng' => $minLng, 'maxLat' => $maxLat, 'minLat' => $minLat]; } /** * 获取系统信息 * * @param $id * @return array * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\ModelNotFoundException * @throws \think\exception\DbException */ public function getSystemInfo($id) { # 客户 $field = ['obtain_time', 'owner_user_id', 'create_user_id', 'deal_status', 'update_time', 'create_time', 'last_time', 'last_record']; $customer = Db::name('crm_customer')->field($field)->where('customer_id', $id)->find(); # 创建人 $createUserName = Db::name('admin_user')->where('id', $customer['create_user_id'])->value('realname'); # zjf 20210726 $userModel = new \app\admin\model\User(); $ownerUserInfo = $userModel->getUserById($customer['owner_user_id']); # 负责人部门 $ownerStructureName = $ownerUserInfo['structure_name']; # 负责人 $ownerUserName = $ownerUserInfo['realname']; return [ 'obtain_time' => !empty($customer['obtain_time']) ? date('Y-m-d H:i:s', $customer['obtain_time']) : '', 'last_record' => !empty($customer['last_record']) ? $customer['last_record'] : '', 'create_user_id' => $createUserName, 'owner_user_id' => $ownerUserName, 'create_time' => date('Y-m-d H:i:s', $customer['create_time']), 'update_time' => date('Y-m-d H:i:s', $customer['update_time']), 'last_time' => !empty($customer['last_time']) ? date('Y-m-d H:i:s', $customer['last_time']) : '', 'deal_status' => $customer['deal_status'], 'owner_user_structure_name' => $ownerStructureName ]; } /** * 判断联系人详情权限 todo 商机模块也在用,以后抽成一个公共的方法 * * @param $contactsId * @return bool */ private function getContactsAuth($contactsId) { $ownerUserId = db('crm_contacts')->where('contacts_id', $contactsId)->value('owner_user_id'); $authUserIds = (new \app\admin\model\User())->getUserByPer('crm', 'contacts', 'read'); return in_array($ownerUserId, $authUserIds); } /** * 客户销售分析 * * @param $id * @return array * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\ModelNotFoundException * @throws \think\exception\DbException */ public function getCustomerSaleStatistics($param, $user_id) { $userModel = new \app\admin\model\User(); $type = $param['type']; unset($param['type']); # 日期条件 if ($type) { $timeArr = getTimeByType($type); $timeData['start_time'] = $timeArr[0]; $timeData['end_time'] = $timeArr[1]; } else { if (!empty($timeData['start_time'])) $timeData['start_time'] = strtotime($timeData['start_time'] . ' 00:00:00'); if (!empty($timeData['end_time'])) $timeData['end_time'] = strtotime($timeData['end_time'] . ' 23:59:59'); } if ($param['user_id']) { $map_user_ids = array($param['user_id']); } else { if ($param['structure_id']) { $map_user_ids = $userModel->getSubUserByStr($param['structure_id'], 2); } } unset($param['user_id']); # 格式化参数 $request = $this->fmtRequest($param); $perUserIds = $userModel->getUserByPer('jxc', 'bi', 'jxcProductPurchaseStatistics'); //权限范围内userIds $userIds = $map_user_ids ? array_intersect($map_user_ids, $perUserIds) : $perUserIds; //数组交集 $dataCount = db('crm_customer')->alias('a') ->where(['owner_user_id' => ['in', $userIds]]) ->count(); $list = db('crm_customer')->alias('a') ->where(['owner_user_id' => ['in', $userIds]]) ->limit($request['offset'], $request['length']) ->field('customer_id, name') ->orderRaw('customer_id desc') ->select(); $userIds = implode(',', $userIds); $prefix = config('database.prefix'); $start_time = date('Y-m-d', $timeData['start_time']); $end_time = date('Y-m-d', $timeData['end_time']); $arr = []; foreach ($list as $key => $value) { $sql = "SELECT a.customer_id, a.`name`, count(distinct b.sale_id) AS sale_num, IFNULL( sum(c.sale_product_number), 0 ) AS sale_product_number, IFNULL( sum(c.sale_product_subtotal), 0 ) AS sale_product_subtotal FROM {$prefix}crm_customer as a INNER JOIN {$prefix}jxc_sale as b ON a.customer_id = b.customer_id INNER JOIN {$prefix}jxc_sale_product as c ON c.sale_id = b.sale_id WHERE a.customer_id = {$value['customer_id']} AND b.owner_user_id IN ({$userIds}) AND b.check_status IN (7, 2) AND b.create_time BETWEEN {$timeData['start_time']} AND {$timeData['end_time']}"; $data = queryCache($sql); $sql1 = "SELECT a.customer_id, a.`name`, count(distinct b.salereturn_id) AS salereturn_num, IFNULL( sum(c.salereturn_number), 0 ) AS salereturn_number, IFNULL( sum(c.salereturn_subtotal), 0 ) AS salereturn_subtotal FROM {$prefix}crm_customer as a INNER JOIN {$prefix}jxc_salereturn as b ON a.customer_id = b.customer_id INNER JOIN {$prefix}jxc_salereturn_product as c ON c.salereturn_id = b.salereturn_id WHERE a.customer_id = {$value['customer_id']} AND b.owner_user_id IN ({$userIds}) AND b.check_status IN (7, 2) AND b.create_time BETWEEN {$timeData['start_time']} AND {$timeData['end_time']}"; $data1 = queryCache($sql1); $item = []; foreach ($data as $key => $value) { $item = array_merge($value, $data1[$key]); } $arr['items'][] = $item; } $data = []; $data['list'] = $arr ?: []; $data['dataCount'] = $dataCount ?: 0; return $data; } }