123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | Description: 商业智能-排行榜
  4. // +----------------------------------------------------------------------
  5. // | Author: Michael_xu | gengxiaoxu@5kcrm.com
  6. // +----------------------------------------------------------------------
  7. namespace app\bi\controller;
  8. use app\admin\controller\ApiCommon;
  9. use app\bi\traits\SortTrait;
  10. use think\Hook;
  11. use think\Request;
  12. use think\Db;
  13. use app\bi\model\Customer as CustomerModel;
  14. use app\bi\model\Contract as ContractModel;
  15. use app\bi\logic\ExcelLogic;
  16. class Ranking extends ApiCommon
  17. {
  18. use SortTrait;
  19. /**
  20. * 用于判断权限
  21. * @permission 无限制
  22. * @allow 登录用户可访问
  23. * @other 其他根据系统设置
  24. **/
  25. public function _initialize()
  26. {
  27. $action = [
  28. 'permission' => [''],
  29. 'allow' => [
  30. 'contract',
  31. 'receivables',
  32. 'signing',
  33. 'addcustomer',
  34. 'addcontacts',
  35. 'recordnun',
  36. 'recordcustomer',
  37. 'examine',
  38. 'product',
  39. 'excelexport'
  40. ]
  41. ];
  42. Hook::listen('check_auth', $action);
  43. $request = Request::instance();
  44. $a = strtolower($request->action());
  45. if (!in_array($a, $action['permission'])) {
  46. parent::_initialize();
  47. }
  48. if (!checkPerByAction('bi', 'ranking', 'read')) {
  49. header('Content-Type:application/json; charset=utf-8');
  50. exit(json_encode(['code' => 102, 'error' => '无权操作']));
  51. }
  52. }
  53. /**
  54. * 合同金额排行
  55. * @param
  56. * @return
  57. * @author Michael_xu
  58. */
  59. public function contract($param = '')
  60. {
  61. if($param['excel_type']!=1){
  62. $param = $this->param;
  63. }
  64. if (!empty($param['start_time'])) $param['start_time'] = strtotime($param['start_time'] . ' 00:00:00');
  65. if (!empty($param['end_time'])) $param['end_time'] = strtotime($param['end_time'] . ' 23:59:59');
  66. $whereArr = $this->com($param, 'contract');
  67. $whereArr['check_status'] = 2;
  68. //导出使用
  69. if (!empty($param['excel_type'])) return $this->handel(
  70. new \app\bi\model\Contract,
  71. $whereArr,
  72. ['field' => 'SUM(`money`)', 'alias' => 'money', 'default' => '0.00'],
  73. $param['excel_type']
  74. );
  75. return $this->handel(
  76. new \app\bi\model\Contract,
  77. $whereArr,
  78. ['field' => 'SUM(`money`)', 'alias' => 'money', 'default' => '0.00']
  79. );
  80. }
  81. /**
  82. * 回款金额排序
  83. * @return
  84. */
  85. public function receivables($param = '')
  86. {
  87. if($param['excel_type']!=1){
  88. $param = $this->param;
  89. }
  90. if (!empty($param['start_time'])) $param['start_time'] = strtotime($param['start_time'] . ' 00:00:00');
  91. if (!empty($param['end_time'])) $param['end_time'] = strtotime($param['end_time'] . ' 23:59:59');
  92. $whereArr = $this->com($param, 'receivables');
  93. $whereArr['check_status'] = 2;
  94. //导出使用
  95. if (!empty($param['excel_type'])) return $this->handel(
  96. new \app\bi\model\Receivables,
  97. $whereArr,
  98. ['field' => 'SUM(`money`)', 'alias' => 'money', 'default' => '0.00'],
  99. $param['excel_type']
  100. );
  101. return $this->handel(
  102. new \app\bi\model\Receivables,
  103. $whereArr,
  104. ['field' => 'SUM(`money`)', 'alias' => 'money', 'default' => '0.00']
  105. );
  106. }
  107. /**
  108. * 签约合同排序
  109. * @return
  110. */
  111. public function signing($param = '')
  112. {
  113. if($param['excel_type']!=1){
  114. $param = $this->param;
  115. }
  116. if (!empty($param['start_time'])) $param['start_time'] = strtotime($param['start_time'] . ' 00:00:00');
  117. if (!empty($param['end_time'])) $param['end_time'] = strtotime($param['end_time'] . ' 23:59:59');
  118. $whereArr = $this->com($param, 'contract');
  119. $whereArr['check_status'] = 2;
  120. //导出使用
  121. if (!empty($param['excel_type'])) $this->handel(
  122. new ContractModel,
  123. $whereArr,
  124. ['field' => 'COUNT(*)', 'alias' => 'count', 'default' => 0],
  125. $param['excel_type']
  126. );
  127. return $this->handel(
  128. new ContractModel,
  129. $whereArr,
  130. ['field' => 'COUNT(*)', 'alias' => 'count', 'default' => 0]
  131. );
  132. }
  133. /**
  134. * 新增客户排序
  135. * @return
  136. */
  137. public function addCustomer($param = '')
  138. {
  139. if($param['excel_type']!=1){
  140. $param = $this->param;
  141. }
  142. if (!empty($param['start_time'])) $param['start_time'] = strtotime($param['start_time'] . ' 00:00:00');
  143. if (!empty($param['end_time'])) $param['end_time'] = strtotime($param['end_time'] . ' 23:59:59');
  144. $whereArr = $this->com($param, 'customer');
  145. $poolWhere = $this->getWhereByPool();
  146. $poolId = db('crm_customer')->alias('customer')->where($poolWhere)->column('customer_id');
  147. if (!empty($poolId)) $whereArr['customer_id'] = ['notin', $poolId];
  148. //导出使用
  149. if (!empty($param['excel_type'])) return $this->handel(
  150. new \app\bi\model\Customer,
  151. $whereArr,
  152. ['field' => 'COUNT(*)', 'alias' => 'count', 'default' => 0],
  153. $param['excel_type']
  154. );
  155. return $this->handel(
  156. new \app\bi\model\Customer,
  157. $whereArr,
  158. ['field' => 'COUNT(*)', 'alias' => 'count', 'default' => 0]
  159. );
  160. }
  161. /**
  162. * 新增联系人排序
  163. * @return
  164. */
  165. public function addContacts()
  166. {
  167. $param = $this->param;
  168. if (!empty($param['start_time'])) $param['start_time'] = strtotime($param['start_time'] . ' 00:00:00');
  169. if (!empty($param['end_time'])) $param['end_time'] = strtotime($param['end_time'] . ' 23:59:59');
  170. $whereArr = $this->com($param, 'contacts');
  171. //导出使用
  172. if (!empty($param['excel_type'])) return $this->handel(
  173. new \app\bi\model\Contacts,
  174. $whereArr,
  175. ['field' => 'COUNT(*)', 'alias' => 'count', 'default' => 0],
  176. $param['excel_type']
  177. );
  178. return $this->handel(
  179. new \app\bi\model\Contacts,
  180. $whereArr,
  181. ['field' => 'COUNT(*)', 'alias' => 'count', 'default' => 0]
  182. );
  183. }
  184. /**
  185. * 跟进次数排行
  186. *
  187. * @param string $param
  188. * @return array|\think\response\Json
  189. * @throws \think\db\exception\DataNotFoundException
  190. * @throws \think\db\exception\ModelNotFoundException
  191. * @throws \think\exception\DbException
  192. */
  193. public function recordNun($param = '')
  194. {
  195. if($param['excel_type']!=1){
  196. $param = $this->param;
  197. }
  198. if (!empty($param['start_time'])) $param['start_time'] = strtotime($param['start_time'] . ' 00:00:00');
  199. if (!empty($param['end_time'])) $param['end_time'] = strtotime($param['end_time'] . ' 23:59:59');
  200. $whereArr = $this->com($param, 'record');
  201. # 权限内的员工列表
  202. $userData = [];
  203. $userList = db('admin_user')->alias('user')
  204. ->field(['user.id', 'user.realname AS user_name', 'structure.name AS structure_name'])
  205. ->join('__ADMIN_STRUCTURE__ structure', 'structure.id = user.structure_id')
  206. ->whereIn('user.id', $whereArr['create_user_id'][1])->select();
  207. foreach ($userList AS $key => $value) {
  208. $userData[$value['id']]['user_name'] = $value['user_name'];
  209. $userData[$value['id']]['structure_name'] = $value['structure_name'];
  210. }
  211. # 跟进记录列表
  212. $data = [];
  213. $recordWhere['type'] = 1;
  214. $recordWhere['activity_type'] = 2;
  215. $recordWhere['create_user_id'] = ['in', $whereArr['create_user_id'][1]];
  216. $recordWhere['create_time'] = ['between', [$whereArr['create_time'][1][0], $whereArr['create_time'][1][1]]];
  217. $recordList = db('crm_activity')->field(['count(*) as count', 'create_user_id'])->where($recordWhere)
  218. ->group('create_user_id')->order('count', 'desc')->select();
  219. foreach ($recordList AS $key => $value) {
  220. $data[] = [
  221. 'count' => $value['count'],
  222. 'user_name' => $userData[$value['create_user_id']]['user_name'],
  223. 'structure_name' => $userData[$value['create_user_id']]['structure_name']
  224. ];
  225. }
  226. //导出使用
  227. if (!empty($param['excel_type'])) return $data;
  228. return resultArray(['data' => $data]);
  229. }
  230. /**
  231. * 跟进客户数排行
  232. *
  233. * @param string $param
  234. * @return mixed|\think\response\Json
  235. * @throws \think\db\exception\DataNotFoundException
  236. * @throws \think\db\exception\ModelNotFoundException
  237. * @throws \think\exception\DbException
  238. */
  239. public function recordCustomer($param = '')
  240. {
  241. if($param['excel_type']!=1){
  242. $param = $this->param;
  243. }
  244. if (!empty($param['start_time'])) $param['start_time'] = strtotime($param['start_time'] . ' 00:00:00');
  245. if (!empty($param['end_time'])) $param['end_time'] = strtotime($param['end_time'] . ' 23:59:59');
  246. $whereArr = $this->com($param, 'record');
  247. # 权限内的员工列表
  248. $userData = [];
  249. $userList = db('admin_user')->alias('user')
  250. ->field(['user.id', 'user.realname AS user_name', 'structure.name AS structure_name'])
  251. ->join('__ADMIN_STRUCTURE__ structure', 'structure.id = user.structure_id')
  252. ->whereIn('user.id', $whereArr['create_user_id'][1])->select();
  253. foreach ($userList AS $key => $value) {
  254. $userData[$value['id']]['user_name'] = $value['user_name'];
  255. $userData[$value['id']]['structure_name'] = $value['structure_name'];
  256. }
  257. # 跟进记录列表
  258. $data = [];
  259. $recordWhere['type'] = 1;
  260. $recordWhere['activity_type'] = 2;
  261. $recordWhere['create_user_id'] = ['in', $whereArr['create_user_id'][1]];
  262. $recordWhere['create_time'] = ['between', [$whereArr['create_time'][1][0], $whereArr['create_time'][1][1]]];
  263. $recordList = db('crm_activity')->field(['create_user_id', 'activity_type_id'])->where($recordWhere)
  264. ->group('create_user_id, activity_type_id')->select();
  265. foreach ($recordList AS $key => $value) {
  266. if (empty($data[$value['create_user_id']]['user_name'])) {
  267. $data[$value['create_user_id']]['user_name'] = $userData[$value['create_user_id']]['user_name'];
  268. $data[$value['create_user_id']]['structure_name'] = $userData[$value['create_user_id']]['structure_name'];
  269. $data[$value['create_user_id']]['count'] = 1;
  270. } else {
  271. $data[$value['create_user_id']]['count'] = $data[$value['create_user_id']]['count'] + 1;
  272. }
  273. }
  274. $data = $this->sortCommon($data, 'count', 'desc');
  275. //导出使用
  276. if (!empty($param['excel_type'])) return $data;
  277. return resultArray(['data' => $data]);
  278. }
  279. /**
  280. * 出差次数排行
  281. * @return
  282. */
  283. public function examine($param = '')
  284. {
  285. if($param['excel_type']!=1){
  286. $param = $this->param;
  287. }
  288. if (!empty($param['start_time'])) $param['start_time'] = strtotime($param['start_time'] . ' 00:00:00');
  289. if (!empty($param['end_time'])) $param['end_time'] = strtotime($param['end_time'] . ' 23:59:59');
  290. $whereArr = $this->com($param, 'record');
  291. $whereArr['category_id'] = 3; // 审批类型,3出差
  292. $whereArr['check_status'] = 2;
  293. //导出使用
  294. if (!empty($param['excel_type'])) return $this->handel(
  295. new \app\bi\model\Examine,
  296. $whereArr,
  297. ['field' => 'COUNT(*)', 'alias' => 'count', 'default' => 0],
  298. $param['excel_type'],
  299. 'create_user_id'
  300. );
  301. return $this->handel(
  302. new \app\bi\model\Examine,
  303. $whereArr,
  304. ['field' => 'COUNT(*)', 'alias' => 'count', 'default' => 0],
  305. '',
  306. 'create_user_id'
  307. );
  308. }
  309. /**
  310. * 产品销量排行
  311. * @return
  312. */
  313. public function product($param = '')
  314. {
  315. $userModel = new \app\admin\model\User();
  316. $productModel = new \app\bi\model\Product();
  317. if($param['excel_type']!=1){
  318. $param = $this->param;
  319. }
  320. if (!empty($param['start_time'])) $param['start_time'] = strtotime($param['start_time'] . ' 00:00:00');
  321. if (!empty($param['end_time'])) $param['end_time'] = strtotime($param['end_time'] . ' 23:59:59');
  322. $list = $productModel->getSortByProduct($param);
  323. $list = array_column($list, null, 'owner_user_id');
  324. $whereArr = $this->com($param, 'contract');
  325. $data = [];
  326. foreach ($whereArr['owner_user_id'][1] as $val) {
  327. $user = $userModel->getUserById($val);
  328. $item = [];
  329. $item['num'] = !empty($list[$val]['num']) ? (int)$list[$val]['num'] : 0;
  330. $item['user_name'] = $user['realname'];
  331. $item['structure_name'] = $user['structure_name'];
  332. $data[] = $item;
  333. }
  334. # 排序
  335. if (!empty($data)) $data = $this->sortCommon($data, 'num', 'desc');
  336. //导出使用
  337. if (!empty($param['excel_type'])) return $data;
  338. return resultArray(['data' => $data]);
  339. }
  340. /**
  341. * 查询条件
  342. * @return
  343. */
  344. private function com($param, $type = '')
  345. {
  346. $userModel = new \app\admin\model\User();
  347. $adminModel = new \app\admin\model\Admin();
  348. $perUserIds = $userModel->getUserByPer('bi', 'ranking', 'read'); //权限范围内userIds
  349. $whereData = $adminModel->getWhere($param, '', $perUserIds); //统计条件
  350. $userIds = $whereData['userIds'];
  351. $between_time = $whereData['between_time'];
  352. if ($type == 'contract') {
  353. $where_time = 'order_date';
  354. } elseif (in_array($type, ['record', 'customer', 'contacts'])) {
  355. $where_time = 'create_time';
  356. } elseif ($type == 'receivables') {
  357. $where_time = 'return_time';
  358. } else {
  359. $where_time = 'start_time';
  360. }
  361. //时间戳:新增客户排行
  362. if ($type == 'contract' || $type == 'receivables') {
  363. $whereArr[$where_time] = array('between', array(date('Y-m-d', $between_time[0]), date('Y-m-d', $between_time[1])));
  364. } else {
  365. $whereArr[$where_time] = array('between', array($between_time[0], $between_time[1]));
  366. }
  367. if (in_array($type, ['customer', 'contract', 'receivables', 'contacts'])) {
  368. $whereArr['owner_user_id'] = ['IN', $userIds];
  369. } else {
  370. $whereArr['create_user_id'] = ['IN', $userIds];
  371. }
  372. return $whereArr;
  373. }
  374. /**
  375. * 查询统计数据
  376. *
  377. * @param model $model
  378. * @param array $whereArr
  379. * @return void
  380. * @author Ymob
  381. * @datetime 2019-11-25 11:11:59
  382. */
  383. private function handel($model, $whereArr, $field, $excel_type = '', $user_field = 'owner_user_id')
  384. {
  385. $userModel = new \app\admin\model\User();
  386. $sql = $model->field([
  387. $user_field,
  388. $field['field'] => $field['alias']
  389. ])
  390. ->where($whereArr)
  391. ->group($user_field)
  392. ->fetchSql()
  393. ->select();
  394. $list = queryCache($sql);
  395. $list = array_column($list, null, $user_field);
  396. $data = [];
  397. foreach ($whereArr[$user_field][1] as $val) {
  398. $user = $userModel->getUserById($val);
  399. $item = [];
  400. $item[$field['alias']] = $list[$val][$field['alias']] ?: $field['default'];
  401. $item['user_name'] = $user['realname'];
  402. $item['structure_name'] = $user['structure_name'];
  403. $data[] = $item;
  404. }
  405. array_multisort($data, SORT_DESC, array_column($data, $field['alias']));
  406. if (!empty($excel_type)) return $data;
  407. return resultArray(['data' => $data]);
  408. }
  409. /**
  410. * 导出
  411. * @param $type
  412. * @param $types
  413. */
  414. public function excelExport()
  415. {
  416. $param = $this->param;
  417. $excel_type = $param['excel_type'];
  418. $type = [];
  419. $type['excel_types'] = $param['excel_types'];
  420. switch ($param['excel_types']) {
  421. case 'contract':
  422. $list = $this->contract($param);
  423. foreach ($list as $key => $v) {
  424. $list[$key]['id'] = $key + 1;
  425. }
  426. $type['type'] = '合同金额排行';
  427. break;
  428. case'receivables':
  429. $list = $this->receivables($param);
  430. $type['type'] = '回款金额排行';
  431. break;
  432. case 'signing':
  433. $list = $this->signing($param);
  434. $type['type'] = '签约合同排行';
  435. break;
  436. case 'product':
  437. $list = $this->product($param);
  438. $type['type'] = '产品销量排行';
  439. break;
  440. case 'addCustomer':
  441. $list = $this->addCustomer($param);
  442. $type['type'] = '新增客户数排行';
  443. break;
  444. case 'addContacts':
  445. $list = $this->addContacts($param);
  446. $type['type'] = '新增联系人数排行';
  447. break;
  448. case 'recordNun':
  449. $list = $this->recordNun($param);
  450. $type['type'] = '跟进次数排行';
  451. break;
  452. case 'recordCustomer':
  453. $list = $this->recordCustomer($param);
  454. $type['type'] = '跟进客户数排行';
  455. break;
  456. case 'examine':
  457. $list = $this->examine($param);
  458. $type['type'] = '出差次数排行';
  459. break;
  460. }
  461. if(empty($list)){
  462. return resultArray(['data'=>'数据不存在']);
  463. }
  464. $excelLogic = new ExcelLogic();
  465. $data = $excelLogic->rankingExcle($param, $list);
  466. return $data;
  467. }
  468. /**
  469. * [客户公海条件]
  470. * @author Michael_xu
  471. * @param
  472. * @return
  473. */
  474. public function getWhereByPool()
  475. {
  476. $configModel = new \app\crm\model\ConfigData();
  477. $configInfo = $configModel->getData();
  478. $config = $configInfo['config'] ? : 0;
  479. $follow_day = $configInfo['follow_day'] ? : 0;
  480. $deal_day = $configInfo['deal_day'] ? : 0;
  481. $whereData = [];
  482. //启用
  483. if ($config == 1) {
  484. //默认公海条件(没有负责人或已经到期)
  485. $data['follow_time'] = time()-$follow_day*86400;
  486. $data['deal_time'] = time()-$deal_day*86400;
  487. $data['deal_status'] = '未成交';
  488. if ($follow_day < $deal_day) {
  489. $whereData = function($query) use ($data){
  490. $query->where(['customer.owner_user_id'=>0])
  491. ->whereOr(function ($query) use ($data) {
  492. $query->where(function ($query) use ($data) {
  493. $query->where(['customer.update_time' => array('elt',$data['follow_time'])])
  494. ->whereOr(['customer.deal_time' => array('elt',$data['deal_time'])]);
  495. })
  496. ->where(['customer.is_lock' => 0])
  497. ->where(['customer.deal_status' => ['neq','已成交']]);
  498. });
  499. };
  500. } else {
  501. $whereData = function($query) use ($data){
  502. $query->where(['customer.owner_user_id'=>0])
  503. ->whereOr(function ($query) use ($data) {
  504. $query->where(function ($query) use ($data) {
  505. $query->where(['customer.deal_time' => array('elt',$data['deal_time'])]);
  506. })
  507. ->where(['customer.is_lock' => 0])
  508. ->where(['customer.deal_status' => ['neq','已成交']]);
  509. });
  510. };
  511. }
  512. } else {
  513. $whereData['customer.owner_user_id'] = 0;
  514. }
  515. return $whereData ? : '';
  516. }
  517. }