UpdateWorkerScore.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. <?php
  2. namespace app\common\command;
  3. use think\facade\Log;
  4. use think\console\Input;
  5. use think\console\Output;
  6. use think\console\Command;
  7. use think\console\input\Argument;
  8. use app\common\model\works\IssueWork;
  9. use app\common\model\works\ReturnWork;
  10. use app\common\model\works\ServiceWork;
  11. use app\common\model\goods_time\GoodsTime;
  12. use app\common\model\reviews\GoodsReviews;
  13. use app\common\model\master_worker\MasterWorker;
  14. use app\common\model\effective\OrderEffectiveLog;
  15. use app\common\model\works\ServiceWorkReceiveLog;
  16. use app\common\model\master_worker\MasterWorkerTeam;
  17. use app\common\model\master_worker\MasterWorkerScore;
  18. use app\common\model\works\ServiceWorkAllocateWorkerLog;
  19. use app\common\model\master_worker\MasterWorkerServiceTime;
  20. class UpdateWorkerScore extends Command
  21. {
  22. protected $defaultServiceTime = 300; //默认服务时长 300 分钟
  23. protected function configure()
  24. {
  25. $this->setName('update_worker_score')
  26. ->setDescription('更新工程师综合评分和服务时长')
  27. ->addArgument('type', Argument::OPTIONAL, '类型可选');
  28. }
  29. protected function execute(Input $input, Output $output)
  30. {
  31. // 获取传递的参数
  32. $type = $input->getArgument('type');
  33. if ($type == 'init') {
  34. $this->initMasterWorkerScore();
  35. } else {
  36. //更新工程师评分
  37. $this->changeWorderScore();
  38. //更新团队服务评分
  39. $this->changeWorkTeamScore();
  40. }
  41. }
  42. /**
  43. * 初始化工程师汇总评分数据,只执行一次即可
  44. */
  45. protected function initMasterWorkerScore()
  46. {
  47. $masterWorker = MasterWorker::field('id')->order('id','asc')->select()->toArray();
  48. foreach($masterWorker as $item) {
  49. //添加工程师汇总评分数据
  50. MasterWorkerScore::create([
  51. 'worker_id' => $item['id']
  52. ]);
  53. }
  54. }
  55. /*
  56. * 每周统计并更新一次工程师的综合评分
  57. 1、用户评分
  58. 2、完单率 = 完结工单/总工单
  59. 3、接单率 = 已领的工单/总工单
  60. 4、工单投诉率 = 投诉的工单(判定工程师原因) /已完成工单
  61. 5、客户粘性率 = 工程师第一次联系客户时间-领单时间 和定义的时间(10分钟)进行比较
  62. 6、保修率 = 保修工单/已完成工单(去除保修单)
  63. 7、返修率 = 返修工单/已完成工单
  64. 8、加单率 = 加单个数/派单数
  65. */
  66. protected function changeWorderScore()
  67. {
  68. $startTime = date('Y-m-d 00:00:00', strtotime('-7 days'));
  69. $endTime = date('Y-m-d 23:59:59', strtotime('-1 days'));
  70. $page = 0;
  71. $size = 50;
  72. while(true) {
  73. $page++;
  74. $offset = ($page - 1) * $size;
  75. $list = MasterWorker::field('id,category_ids')
  76. ->limit($offset, $size)
  77. ->select()
  78. ->toArray();
  79. if (!$list) {
  80. break;
  81. }
  82. foreach($list as $item) {
  83. $workId = $item['id'];
  84. $this->updateComprehensiveScore($startTime,$endTime,$workId);
  85. //更新工程师平均服务时长
  86. $this->updateServiceTime($startTime,$endTime,$item);
  87. }
  88. }
  89. }
  90. /**
  91. * 更新工程师服务类目的平均服务时长
  92. */
  93. protected function updateServiceTime($startTime,$endTime,$worker) {
  94. if ($worker['category_ids']) {
  95. $category_ids = explode(",",$worker['category_ids']);
  96. foreach($category_ids as $categoryId) {
  97. $avgTime = ServiceWork::where('master_worker_id',$worker['id'])->where('service_status',3)->whereIn('work_type',[0,1])->whereBetweenTime('create_time', $startTime, $endTime)->field('AVG(finished_time - appointment_time) as avg_time')->find();
  98. if (isset($avgTime['avg_time']) && $avgTime['avg_time'] > 0) {
  99. $avgTime = $avgTime['avg_time'] / 60 ;
  100. } else {
  101. $avgTime = GoodsTime::whereRaw('FIND_IN_SET('.$categoryId.', goods_category_ids)')->value('service_time');
  102. $avgTime = $avgTime ?? $this->defaultServiceTime;//默认服务时长
  103. }
  104. $exists = MasterWorkerServiceTime::where('master_worker_id',$worker['id'])->where('goods_category_id',$categoryId)->value('id');
  105. if ($exists) {
  106. MasterWorkerServiceTime::where('master_worker_id',$worker['id'])->where('goods_category_id',$categoryId)->update([
  107. 'service_time' => $avgTime
  108. ]);
  109. } else {
  110. MasterWorkerServiceTime::create([
  111. 'master_worker_id' => $worker['id'],
  112. 'goods_category_id' => $categoryId,
  113. 'service_time' => $avgTime
  114. ]);
  115. }
  116. }
  117. }
  118. }
  119. /**
  120. * 更新工程师综合评分
  121. */
  122. protected function updateComprehensiveScore($startTime,$endTime,$workId) {
  123. try {
  124. //查询本周平均评分值
  125. $goodsReviewsAvg = GoodsReviews::alias('a')->leftJoin("service_work b","a.work_id = b.id")->whereBetweenTime('a.create_time', $startTime, $endTime)->avg('rating');
  126. $commentScore = $goodsReviewsAvg > 0 ? bcdiv($goodsReviewsAvg, 5, 2) : 0;
  127. //总工单:统计派单日志记录
  128. $allOrder = ServiceWorkAllocateWorkerLog::where('master_worker_id',$workId)->whereBetweenTime('create_time', $startTime, $endTime)->count();
  129. //完结工单:统计工单表已完成的工单
  130. $completeOrder = ServiceWork::where('master_worker_id',$workId)->where('service_status',3)->whereBetweenTime('create_time', $startTime, $endTime)->count();
  131. if ($allOrder == 0) {
  132. $completionRate = 0;
  133. $acceptRate = 0;
  134. } else {
  135. //完单率
  136. $completionRate = bcdiv($completeOrder, $allOrder ,2);
  137. //接单率
  138. $acceptOrder = ServiceWorkReceiveLog::where('master_worker_id',$workId)->whereBetweenTime('create_time', $startTime, $endTime)->count();
  139. $acceptRate = bcdiv($acceptOrder, $allOrder ,2);
  140. }
  141. if ($completeOrder == 0) {
  142. $issueRate = 0;
  143. $returnRate = 0;
  144. $addRate = 0;
  145. } else {
  146. //工单投诉率
  147. $issueWork = IssueWork::where('master_worker_id',$workId)->where('responsible',2)->whereBetweenTime('create_time', $startTime, $endTime)->count();
  148. $issueRate = bcdiv($issueWork, $completeOrder ,2);
  149. $issueRate = 1 - ($issueRate > 1 ? 1 : $issueRate);
  150. //返修率
  151. $returnWord = ReturnWork::where('master_worker_id',$workId)->whereBetweenTime('create_time', date('Y-m-d 00:00:00', strtotime('-30 days')), $endTime)->count();
  152. $returnRate = bcdiv($returnWord, $completeOrder ,2);
  153. $returnRate = 1 - ($returnRate > 1 ? 1 : $returnRate);
  154. //加单率
  155. $addWord = ServiceWork::where('master_worker_id',$workId)->where('work_type',2)->whereBetweenTime('create_time', $startTime, $endTime)->count();
  156. $addRate = bcdiv($addWord, $completeOrder ,2);
  157. $addRate = $addRate > 1 ? 1 : $addRate;
  158. }
  159. //客户粘性率(10分钟内)
  160. $avgTime = ServiceWork::where('master_worker_id',$workId)->where('work_status','>',1)->where('first_contact_time','>',0)->whereBetweenTime('create_time', $startTime, $endTime)->field('AVG(first_contact_time - receive_time) as avg_time')->find();
  161. $avgTime = $avgTime['avg_time'] ? $avgTime['avg_time'] / 60 : 0;
  162. $viscosityRate = $avgTime <= 10 && $avgTime > 0 ? 1 : 0;
  163. $partOrder = ServiceWork::where('master_worker_id',$workId)->where('work_status','>',1)->where('order_effective_id',0)->whereBetweenTime('create_time', $startTime, $endTime)->count();
  164. if ($partOrder == 0) {
  165. $warrantyRate = 0;
  166. } else {
  167. //保修率
  168. $effectiveOder = OrderEffectiveLog::alias('a')->leftJoin('service_work b', 'a.work_id = b.id')->where('b.id',$workId)->whereBetweenTime('a.create_time', date('Y-m-d 00:00:00', strtotime('-30 days')), $endTime)->count();
  169. $warrantyRate = bcdiv($effectiveOder, $partOrder ,2);
  170. $warrantyRate = 1 - ($warrantyRate > 1 ? 1 : $warrantyRate);
  171. }
  172. //工程师汇总评分
  173. $comprehensiveScore = $commentScore + $completionRate + $acceptRate + $issueRate + $viscosityRate + $warrantyRate + $returnRate + $addRate;
  174. $comprehensiveScore = bcdiv($comprehensiveScore, 8, 2) * 100;
  175. MasterWorkerScore::where('worker_id',$workId)->update(['comprehensive_score' => $comprehensiveScore]);
  176. } catch (\Exception $e) {
  177. Log::write('更新工程师综合评分异常:'.$e->getMessage());
  178. return false;
  179. }
  180. }
  181. /**
  182. * 更新团队服务评分
  183. */
  184. protected function changeWorkTeamScore() {
  185. $page = 0;
  186. $size = 50;
  187. while(true) {
  188. $page++;
  189. $offset = ($page - 1) * $size;
  190. $list = MasterWorkerTeam::alias('a')->leftJoin('master_worker b','a.master_worker_id=b.id')->field('a.id,b.tenant_id')
  191. ->limit($offset, $size)
  192. ->select()
  193. ->toArray();
  194. if (!$list) {
  195. break;
  196. }
  197. try {
  198. foreach($list as $item) {
  199. $comprehensiveScore = 3.5;
  200. if ($item['tenant_id'] > 0) {
  201. $avg = MasterWorker::alias('a')->leftJoin('master_worker_score b','a.id=b.worker_id')
  202. ->where('a.tenant_id',$item['tenant_id'])
  203. ->field('AVG(b.comprehensive_score) as avg')
  204. ->find();
  205. if (isset($avg['avg']) && $avg['avg'] > 0) {
  206. $comprehensiveScore = bcdiv($avg['avg'], 20 , 1);
  207. $comprehensiveScore = $comprehensiveScore < 3.5 ? 3.5 : $comprehensiveScore;
  208. $comprehensiveScore = $comprehensiveScore > 5 ? 5 : $comprehensiveScore;
  209. }
  210. }
  211. MasterWorkerTeam::where('id',$item['id'])->update(['comprehensive_score' => $comprehensiveScore]);
  212. }
  213. } catch (\Exception $e) {
  214. Log::write('更新团队综合评分异常:'.$e->getMessage());
  215. return false;
  216. }
  217. }
  218. }
  219. }