企微短剧业务系统

CustomerStageService.php 23KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519
  1. <?php
  2. /**
  3. * Created by PhpStorm.
  4. * User: shensong
  5. * Date: 2022/11/23
  6. * Time: 21:07
  7. */
  8. namespace App\Service;
  9. use App\Log;
  10. use App\Models\CustomerDetails;
  11. use App\Models\DjCustomerStage;
  12. use App\Models\DjCustomerStageDailyReport;
  13. use App\Models\Tag;
  14. use App\RedisModel;
  15. class CustomerStageService
  16. {
  17. public static function setStageRule($ruleId, $params)
  18. {
  19. $params['stage_rule'] = is_array($params['stage_rule']) ? json_encode($params['stage_rule'], 256)
  20. : $params['stage_rule'];
  21. try {
  22. // 验证每种规则只可以添加一次
  23. $code = DjCustomerStage::validateRule($params['stage_rule']);
  24. if(0 != $code) return $code;
  25. if($ruleId){ // 编辑群发规则
  26. $result = DjCustomerStage::query()->where('id', $ruleId)->update($params);
  27. } else {
  28. # 设置新群发规则
  29. $customerStageModel = new DjCustomerStage();
  30. $customerStageModel->creator_id = \Auth::id();
  31. $customerStageModel->corpid = $params['corpid'];
  32. $customerStageModel->sys_group_id = $params['sys_group_id'];
  33. $customerStageModel->stage_title = $params['stage_title'];
  34. $customerStageModel->stage_desc = $params['stage_desc'];
  35. $customerStageModel->stage_rule = $params['stage_rule'];
  36. $customerStageModel->deep = 1;
  37. # 开启事务
  38. \DB::begintransaction();
  39. $result = $customerStageModel->save();
  40. // 将现有阶段深度全部自增
  41. $updateRes = DjCustomerStage::query()->where('corpid', $params['corpid'])
  42. ->where('sys_group_id', $params['sys_group_id'])->where('enable', 1)
  43. ->increment('deep');
  44. if($updateRes && $result) {
  45. \DB::commit();
  46. } else {
  47. \DB::rollBack();
  48. return 3702;
  49. }
  50. }
  51. if(!$result) return 3701;
  52. } catch (\Exception $e) {
  53. Log::logError('客户阶段规则设置发生异常', [
  54. 'line' => $e->getLine(),
  55. 'msg' => $e->getMessage(),
  56. 'trace' => $e->getTraceAsString(),
  57. 'params' => $params
  58. ], 'SetCustomerStageRule');
  59. return 3702;
  60. }
  61. return 0;
  62. }
  63. public static function stageRuleList($corpid, $sysGroupId, $page, $pageSize)
  64. {
  65. $offset = ($page - 1) * $pageSize;
  66. $customerStageQuery = DjCustomerStage::query()->where('sys_group_id', $sysGroupId)
  67. ->where('corpid', $corpid)->where('enable', 1);
  68. $countQuery = clone $customerStageQuery;
  69. $count = $countQuery->count();
  70. $data = $customerStageQuery->selectRaw('id as rule_id, stage_title, stage_desc, stage_rule, deep')
  71. ->offset($offset)->limit($pageSize)->orderBy('deep', 'asc')->get();
  72. return [$data, $count];
  73. }
  74. public static function stageRuleSort($params)
  75. {
  76. try{
  77. // 查询被操作规则原始排序值
  78. $operatorRule = DjCustomerStage::query()->where('id', $params['operate_rule_id'])->first();
  79. $operatorRuleOriginalSortOrder = $operatorRule->deep;
  80. if(!empty($params['behind_rule_id']) && empty($params['front_rule_id'])) {
  81. // 上移到第一位,判断是否有调整后的排在调整规则后面的规则id
  82. $behindRule = DjCustomerStage::query()->where('id', $params['behind_rule_id'])->first();
  83. $behindRuleOriginalSortOrder = $behindRule->deep;
  84. list($data, $code) = self::ruleMoveUp($params, $behindRuleOriginalSortOrder, $operatorRuleOriginalSortOrder);
  85. return [$data, $code];
  86. } else if(!empty($params['front_rule_id']) && empty($params['behind_rule_id'])) {
  87. // 下移到最后一位,判断是否有调整后的排在调整规则前面的规则id
  88. $frontRule = DjCustomerStage::query()->where('id', $params['front_rule_id'])->first();
  89. $frontRuleOriginalSortOrder = $frontRule->deep;
  90. list($data, $code) = self::ruleMoveDown($params, $frontRuleOriginalSortOrder, $operatorRuleOriginalSortOrder);
  91. return [$data, $code];
  92. } else if(!empty($params['front_rule_id']) && !empty($params['behind_rule_id'])) {
  93. $frontRule = DjCustomerStage::query()->where('id', $params['front_rule_id'])->first();
  94. $frontRuleOriginalSortOrder = $frontRule->deep;
  95. $behindGroup = DjCustomerStage::query()->where('id', $params['behind_rule_id'])->first();
  96. $behindGroupOriginalSortOrder = $behindGroup->deep;
  97. if($operatorRuleOriginalSortOrder < $frontRuleOriginalSortOrder) {
  98. // 下移
  99. list($data, $code) = self::ruleMoveDown($params, $frontRuleOriginalSortOrder, $operatorRuleOriginalSortOrder);
  100. } else {
  101. // 上移
  102. list($data, $code) = self::ruleMoveUp($params, $behindGroupOriginalSortOrder, $operatorRuleOriginalSortOrder);
  103. }
  104. return [$data, $code];
  105. } else {
  106. Log::logError('stageRuleSort', [
  107. 'params' => $params,
  108. 'message' => '被操作规则前后规则id不可同时为空',
  109. ],'interface');
  110. return ['被操作规则前后规则id不可同时为空', 3405];
  111. }
  112. } catch (\Exception $exception) {
  113. Log::logError('stageRuleSort', [
  114. 'params' => $params,
  115. 'file' => $exception->getFile(),
  116. 'line' => $exception->getLine(),
  117. 'message' => $exception->getMessage(),
  118. 'trace' => $exception->getTraceAsString(),
  119. ], 'interface');
  120. return ['移动失败', 400];
  121. }
  122. }
  123. // 上移
  124. public static function ruleMoveUp($params, $behindGroupOriginalSortOrder, $operatorRuleOriginalSortOrder)
  125. {
  126. \DB::begintransaction();
  127. $moveRes = DjCustomerStage::query()
  128. ->where('corpid', $params['corpid'])->where('sys_group_id', $params['sys_group_id'])
  129. ->where('enable', 1)
  130. ->where('deep', '<', $operatorRuleOriginalSortOrder)
  131. ->where('deep', '>=', $behindGroupOriginalSortOrder)->increment('deep');// 自增1
  132. $operatorRes = DjCustomerStage::query()->where('id', $params['operate_rule_id'])
  133. ->update(['deep' => $behindGroupOriginalSortOrder]);
  134. if($moveRes && $operatorRes) {
  135. \DB::commit();
  136. return ['移动成功', 0];
  137. } else {
  138. \DB::rollBack();
  139. Log::logError('stageRuleSort', [
  140. 'type' => '上移',
  141. 'params' => $params,
  142. 'message' => '移动失败',
  143. 'move_res' => $moveRes,
  144. 'operator_res' => $operatorRes,
  145. 'operator_deep' => $operatorRuleOriginalSortOrder,
  146. 'behind_deep' => $behindGroupOriginalSortOrder,
  147. ],'interface');
  148. return ['移动失败', 400];
  149. }
  150. }
  151. // 下移
  152. public static function ruleMoveDown($params, $frontRuleOriginalSortOrder, $operatorRuleOriginalSortOrder)
  153. {
  154. \DB::begintransaction();
  155. $moveRes = DjCustomerStage::query()->where('corpid', $params['corpid'])->where('enable', 1)
  156. ->where('sys_group_id', $params['sys_group_id'])
  157. ->where('deep', '>', $operatorRuleOriginalSortOrder)
  158. ->where('deep', '<=', $frontRuleOriginalSortOrder)
  159. ->decrement('deep');// 自减1
  160. $operatorRes = DjCustomerStage::query()->where('id', $params['operate_rule_id'])
  161. ->update(['deep' => $frontRuleOriginalSortOrder]);
  162. if($moveRes && $operatorRes) {
  163. \DB::commit();
  164. return ['移动成功', 0];
  165. } else {
  166. \DB::rollBack();
  167. Log::logError('stageRuleSort', [
  168. 'type' => '下移',
  169. 'params' => $params,
  170. 'message' => '移动失败',
  171. 'move_res' => $moveRes,
  172. 'operator_res' => $operatorRes,
  173. 'operator_deep' => $operatorRuleOriginalSortOrder,
  174. 'front_deep' => $frontRuleOriginalSortOrder,
  175. ],'interface');
  176. return ['移动失败', 400];
  177. }
  178. }
  179. public static function stageRuleDel($ruleId, $corpid, $sysGroupId)
  180. {
  181. \DB::begintransaction();
  182. $res = DjCustomerStage::query()->where('id', $ruleId)->update(['enable' => 0]);
  183. # 当前阶段是被删除阶段的情况
  184. $customerCount1 = CustomerDetails::suffix($corpid)->where('corpid', $corpid)->where('now_stage', $ruleId)
  185. ->count();
  186. if($customerCount1 > 0) {
  187. $customerRes1 = CustomerDetails::suffix($corpid)->where('corpid', $corpid)
  188. ->where('now_stage', $ruleId)->update([
  189. 'now_stage' => 0, 'last_stage' => 0, 'stage_change_date' => null
  190. ]);
  191. } else {
  192. $customerRes1 = true;
  193. }
  194. # 上一阶段是当前被删除的阶段,且当前客户未流失
  195. $customerCount2 = CustomerDetails::suffix($corpid)->where('corpid', $corpid)->where('last_stage', $ruleId)
  196. ->where('loss_status', 1)->count();
  197. if($customerCount2 > 0) {
  198. $customerRes2 = CustomerDetails::suffix($corpid)->where('corpid', $corpid)->where('last_stage', $ruleId)
  199. ->where('loss_status', 1)
  200. ->update([
  201. 'now_stage' => 0, 'last_stage' => 0, 'stage_change_date' => null,
  202. ]);
  203. } else {
  204. $customerRes2 = true;
  205. }
  206. # 上一阶段是当前被删除的阶段,且当前客户已流失
  207. $customerCount3 = CustomerDetails::suffix($corpid)->where('corpid', $corpid)->where('last_stage', $ruleId)
  208. ->where('loss_status', 0)->count();
  209. if($customerCount3 > 0) {
  210. $customerRes3 = CustomerDetails::suffix($corpid)->where('corpid', $corpid)->where('last_stage', $ruleId)
  211. ->where('loss_status', 0)
  212. ->update([
  213. 'last_stage' => 0
  214. ]);
  215. } else {
  216. $customerRes3 = true;
  217. }
  218. if($res && $customerRes1 && $customerRes2 && $customerRes3) {
  219. \DB::commit();
  220. return 0;
  221. } else {
  222. \DB::rollBack();
  223. return 3704;
  224. }
  225. }
  226. public static function confirmSet($corpid, $sysGroupId)
  227. {
  228. // 将此消息加入待处理队列
  229. RedisModel::lPush(DjCustomerStage::CUSTOMER_STAGE_SYNC, json_encode(['corpid' => $corpid], 256));
  230. return 0;
  231. }
  232. public static function basicDataAnalysis($corpid)
  233. {
  234. # 添加缓存
  235. // $dataJson = RedisModel::get('Playlet::basicDataAnalysis-'.$corpid);
  236. // if(!empty($dataJson)) {
  237. // return json_decode($dataJson, 1);
  238. // }
  239. # 客户性别占比
  240. $manCnt = CustomerDetails::suffix($corpid)->selectRaw('count(distinct(external_userid)) as count')
  241. ->where('corpid', $corpid)->where('gender', 1)->where('loss_status', 1)->first();
  242. $data['gender_stat']['man_cnt'] = $manCnt->count ?? 0;
  243. $womenCnt = CustomerDetails::suffix($corpid)->selectRaw('count(distinct(external_userid)) as count')
  244. ->where('corpid', $corpid)->where('gender', 2)->where('loss_status', 1)->first();
  245. $data['gender_stat']['women_cnt'] = $womenCnt->count ?? 0;
  246. $unknownGenderCnt = CustomerDetails::suffix($corpid)->selectRaw('count(distinct(external_userid)) as count')
  247. ->where('corpid', $corpid)->where('gender', 0)->where('loss_status', 1)->first();
  248. $data['gender_stat']['unknown_cnt'] = $unknownGenderCnt->count ?? 0;
  249. # 客户付费情况占比
  250. $payCnt = CustomerDetails::suffix($corpid)->selectRaw('count(distinct(external_userid)) as count')
  251. ->where('corpid', $corpid)->where('pay_num', '>', 0)->where('loss_status', 1)->first();
  252. $data['pay_stat']['pay_cnt'] = $payCnt->count ?? 0;
  253. $unPayCnt = CustomerDetails::suffix($corpid)->selectRaw('count(distinct(external_userid)) as count')
  254. ->where('corpid', $corpid)->where('pay_num', 0)->where('loss_status', 1)->first();
  255. $data['pay_stat']['unpay_cnt'] = $unPayCnt->count ?? 0;
  256. # 不同性别付费情况占比
  257. $payManCnt = CustomerDetails::suffix($corpid)->selectRaw('count(distinct(external_userid)) as count')
  258. ->where('corpid', $corpid)->where('gender', 1)->where('loss_status', 1)->where('pay_num', '>', 0)->first();
  259. $data['gender_pay_stat']['man_cnt'] = $payManCnt->count ?? 0;
  260. $payWomenCnt = CustomerDetails::suffix($corpid)->selectRaw('count(distinct(external_userid)) as count')
  261. ->where('corpid', $corpid)->where('gender', 2)->where('loss_status', 1)->where('pay_num', '>', 0)->first();
  262. $data['gender_pay_stat']['women_cnt'] = $payWomenCnt->count ?? 0;
  263. $unKnownGenderPayCnt = CustomerDetails::suffix($corpid)->selectRaw('count(distinct(external_userid)) as count')
  264. ->where('corpid', $corpid)->where('gender', 0)->where('loss_status', 1)->where('pay_num', '>', 0)->first();
  265. $data['gender_pay_stat']['unknown_cnt'] = $unKnownGenderPayCnt->count ?? 0;
  266. # 客户付费情况分析
  267. $twentyPayCnt = CustomerDetails::suffix($corpid)->selectRaw('count(distinct(external_userid)) as count')
  268. ->where('corpid', $corpid)->whereBetween('pay_num', [1, 20])->where('loss_status', 1)->first();
  269. $data['pay_num_stat']['twenty'] = $twentyPayCnt->count ?? 0;
  270. $fortyPayCnt = CustomerDetails::suffix($corpid)->selectRaw('count(distinct(external_userid)) as count')
  271. ->where('corpid', $corpid)->whereBetween('pay_num', [21, 40])->where('loss_status', 1)->first();
  272. $data['pay_num_stat']['forty'] = $fortyPayCnt->count ?? 0;
  273. $sixtyPayCnt = CustomerDetails::suffix($corpid)->selectRaw('count(distinct(external_userid)) as count')
  274. ->where('corpid', $corpid)->whereBetween('pay_num', [41, 60])->where('loss_status', 1)->first();
  275. $data['pay_num_stat']['sixty'] = $sixtyPayCnt->count ?? 0;
  276. $eightyPayCnt = CustomerDetails::suffix($corpid)->selectRaw('count(distinct(external_userid)) as count')
  277. ->where('corpid', $corpid)->whereBetween('pay_num', [61, 80])->where('loss_status', 1)->first();
  278. $data['pay_num_stat']['eight'] = $eightyPayCnt->count ?? 0;
  279. $hundredPayCnt = CustomerDetails::suffix($corpid)->selectRaw('count(distinct(external_userid)) as count')
  280. ->where('corpid', $corpid)->whereBetween('pay_num', [81, 100])->where('loss_status', 1)->first();
  281. $data['pay_num_stat']['hundred'] = $hundredPayCnt->count ?? 0;
  282. $moreThanHundredPayCnt = CustomerDetails::suffix($corpid)->selectRaw('count(distinct(external_userid)) as count')
  283. ->where('corpid', $corpid)->where('pay_num', '>', 100)->where('loss_status', 1)->first();
  284. $data['pay_num_stat']['more'] = $moreThanHundredPayCnt->count ?? 0;
  285. # 客户添加时长
  286. $twoMonthAddTimeCnt = CustomerDetails::suffix($corpid)->selectRaw('count(distinct(external_userid)) as count')
  287. ->where('corpid', $corpid)->where('loss_status', 1)
  288. ->where('createtime', '>=', strtotime('-2 months'))
  289. ->first();
  290. $data['add_time_stat']['two'] = $twoMonthAddTimeCnt->count ?? 0;
  291. $fourMonthAddTimeCnt = CustomerDetails::suffix($corpid)->selectRaw('count(distinct(external_userid)) as count')
  292. ->where('corpid', $corpid)->where('loss_status', 1)
  293. ->where('createtime', '>=', strtotime('-4 months'))
  294. ->where('createtime', '<', strtotime('-2 months'))
  295. ->first();
  296. $data['add_time_stat']['four'] = $fourMonthAddTimeCnt->count ?? 0;
  297. $sixMonthAddTimeCnt = CustomerDetails::suffix($corpid)->selectRaw('count(distinct(external_userid)) as count')
  298. ->where('corpid', $corpid)->where('loss_status', 1)
  299. ->where('createtime', '>=', strtotime('-6 months'))
  300. ->where('createtime', '<', strtotime('-4 months'))
  301. ->first();
  302. $data['add_time_stat']['six'] = $sixMonthAddTimeCnt->count ?? 0;
  303. $eightMonthAddTimeCnt = CustomerDetails::suffix($corpid)->selectRaw('count(distinct(external_userid)) as count')
  304. ->where('corpid', $corpid)->where('loss_status', 1)
  305. ->where('createtime', '>=', strtotime('-8 months'))
  306. ->where('createtime', '<', strtotime('-6 months'))
  307. ->first();
  308. $data['add_time_stat']['eight'] = $eightMonthAddTimeCnt->count ?? 0;
  309. $tenMonthAddTimeCnt = CustomerDetails::suffix($corpid)->selectRaw('count(distinct(external_userid)) as count')
  310. ->where('corpid', $corpid)->where('loss_status', 1)
  311. ->where('createtime', '>=', strtotime('-10 months'))
  312. ->where('createtime', '<', strtotime('-8 months'))
  313. ->first();
  314. $data['add_time_stat']['ten'] = $tenMonthAddTimeCnt->count ?? 0;
  315. $twelveMonthAddTimeCnt = CustomerDetails::suffix($corpid)->selectRaw('count(distinct(external_userid)) as count')
  316. ->where('corpid', $corpid)->where('loss_status', 1)
  317. ->where('createtime', '>=', strtotime('-12 months'))
  318. ->where('createtime', '<', strtotime('-10 months'))
  319. ->first();
  320. $data['add_time_stat']['twelve'] = $twelveMonthAddTimeCnt->count ?? 0;
  321. $moreThanTwelveMonthAddTimeCnt = CustomerDetails::suffix($corpid)
  322. ->selectRaw('count(distinct(external_userid)) as count')
  323. ->where('corpid', $corpid)->where('loss_status', 1)
  324. ->where('createtime', '<', strtotime('-12 months'))
  325. ->first();
  326. $data['add_time_stat']['more'] = $moreThanTwelveMonthAddTimeCnt->count ?? 0;
  327. RedisModel::set('Playlet::basicDataAnalysis-'.$corpid, json_encode($data));
  328. // 缓存十分钟
  329. RedisModel::expire('Playlet::basicDataAnalysis-'.$corpid, 600);
  330. return $data;
  331. }
  332. public static function tagRankList($corpid, $page, $pageSize)
  333. {
  334. $offset = ($page - 1) * $pageSize;
  335. $tagQuery = Tag::query()
  336. ->where('corpid', $corpid)
  337. ->where('enable', 1);
  338. $countQuery = clone $tagQuery;
  339. $count = $countQuery->count();
  340. $data = $tagQuery->select(['tag_id', 'tag_name', 'customer_num'])->offset($offset)->limit($pageSize)
  341. ->orderBy('customer_num', 'desc')->get();
  342. return [$data, $count];
  343. }
  344. public static function analysis($corpid, $sysGroupId)
  345. {
  346. $data = [];
  347. # 客户资产
  348. $customerCnt = CustomerDetails::suffix($corpid)->where('corpid', $corpid)->where('loss_status', 1)->count();
  349. $data[] = [
  350. 'rule_id' => 0,
  351. 'stage_title' => '客户资产',
  352. 'cnt' => $customerCnt,
  353. ];
  354. # 阶段列表
  355. $stageList = DjCustomerStage::query()->where('corpid', $corpid)->where('sys_group_id', $sysGroupId)
  356. ->where('enable', 1)->select(['id', 'stage_title'])->orderBy('deep', 'asc')
  357. ->get();
  358. $stageIdList = array_column($stageList->toArray(), 'id');
  359. # 批量查询各个阶段客户数
  360. $stageCustomerCntList = CustomerDetails::suffix($corpid)->where('corpid', $corpid)->where('loss_status', 1)
  361. ->whereIn('now_stage', $stageIdList)->selectRaw('now_stage, count(1) as count')->groupBy('now_stage')->get();
  362. # 各个阶段当前客户数
  363. foreach($stageList as $stageInfo) {
  364. $item = [];
  365. $customerInfo = $stageCustomerCntList->where('now_stage', $stageInfo->id)->first();
  366. $item['rule_id'] = $stageInfo->id;
  367. $item['stage_title'] = $stageInfo->stage_title;
  368. $item['cnt'] = $customerInfo->count ?? 0;
  369. $data[] = $item;
  370. }
  371. return $data;
  372. }
  373. public static function trend($ruleId, $corpid, $startDate, $endDate)
  374. {
  375. $list = DjCustomerStageDailyReport::query()->where('rule_id', $ruleId)->where('corpid', $corpid)
  376. ->whereBetween('ref_date', [$startDate, $endDate])->where('enable', 1)
  377. ->select(['total_cnt', 'ref_date', 'new_contact_cnt', 'loss_contact_cnt', 'net_growth_contact_cnt'
  378. , 'pay_contact_cnt', 'pay_money'])
  379. ->orderBy('ref_date', 'asc')->get();
  380. return $list;
  381. }
  382. public static function situation($corpid, $sysGroupId, $startDate, $endDate)
  383. {
  384. # 获取阶段列表
  385. $stageList = DjCustomerStage::query()->where('enable', 1)
  386. ->where('corpid', $corpid)->where('sys_group_id', $sysGroupId)
  387. ->selectRaw('id as rule_id, stage_title')->orderBy('deep', 'asc')->get();
  388. if($stageList->isEmpty()) {
  389. return [];
  390. }
  391. $stageList = $stageList->toArray();
  392. $total = 0;
  393. foreach($stageList as $key=>$stageInfo) {
  394. list($data, $cnt) = self::getCustomerStageConversion($stageInfo, $corpid, $sysGroupId, $startDate, $endDate);
  395. $stageList[$key]['conversion'] = $data;
  396. $stageList[$key]['cnt'] = $cnt;
  397. $total += $cnt;
  398. }
  399. return ['data' => $stageList, 'total' => $total];
  400. }
  401. public static function getCustomerStageConversion($stageInfo, $corpid, $sysGroupId, $startDate, $endDate)
  402. {
  403. $data = [];
  404. $total = 0;
  405. # 查询时间范围内各个阶段客户数
  406. $list = CustomerDetails::suffix($corpid)->where('corpid', $corpid)->where('last_stage', $stageInfo['rule_id'])
  407. ->whereBetween('stage_change_date', [$startDate . ' 00:00:00', $endDate . ' 23:59:59'])
  408. ->selectRaw('now_stage, count(1) as cnt')->groupBy('now_stage')->get();
  409. $ruleData = DjCustomerStage::query()->where('corpid', $corpid)->where('enable', 1)
  410. ->where('sys_group_id', $sysGroupId)->selectRaw('id as rule_id,'
  411. .' stage_title')->orderBy('deep', 'asc')->get();
  412. $lossStat = $list->where('now_stage', -1)->first();
  413. $lossCnt = $lossStat->cnt ?? 0;
  414. $data[] = [
  415. 'rule_id' => -1,
  416. 'stage_title' => '已流失',
  417. 'cnt' => $lossCnt,
  418. ];
  419. $total += $lossCnt;
  420. foreach($ruleData as $rule){
  421. $item = json_decode(json_encode($rule), 1);
  422. $customerStat = $list->where('now_stage', $rule->rule_id)->first();
  423. $cnt = $customerStat->cnt ?? 0;
  424. $total += $cnt;
  425. $item['cnt'] = $cnt;
  426. $data[] = $item;
  427. }
  428. return [$data, $total];
  429. }
  430. }