WorkOrderController.php 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478
  1. <?php
  2. namespace App\Http\Controllers\App;
  3. use App\Filters\WorkOrderFilter;
  4. use App\Http\Resources\App\WorkOrderResource;
  5. use App\Jobs\VerifyChargeWorkOrderJob;
  6. use App\Jobs\VerifyWatchWorkOrderJob;
  7. use App\Models\AdminUser;
  8. use App\Models\LocationsLog;
  9. use App\Models\WorkOrder;
  10. use App\Utils\Admin;
  11. use App\Utils\GaodeMaps;
  12. use App\Utils\RedisKeys;
  13. use Carbon\Carbon;
  14. use Illuminate\Http\Request;
  15. use App\Http\Controllers\Controller;
  16. use Illuminate\Support\Facades\DB;
  17. use Illuminate\Support\Facades\Log;
  18. use Illuminate\Support\Facades\Redis;
  19. class WorkOrderController extends AppBaseController
  20. {
  21. /**
  22. * workOrderList 工单列表
  23. *
  24. * @param WorkOrderFilter $workOrderFilter
  25. * @return \Illuminate\Http\JsonResponse
  26. * @author Fx
  27. *
  28. */
  29. public function workOrderList(WorkOrderFilter $workOrderFilter)
  30. {
  31. $area_ids = self::$areaIds;
  32. $workOrderList = WorkOrder::query()
  33. ->whereIn('area_id', $area_ids)
  34. ->filter($workOrderFilter)
  35. ->orderBy('planned')
  36. ->orderByDesc('id')
  37. ->paginate();
  38. return $this->ok(WorkOrderResource::collection($workOrderList));
  39. }
  40. /**
  41. * myWorkOrder 我的工单列表
  42. *
  43. * @param WorkOrderFilter $workOrderFilter
  44. * @return \Illuminate\Http\JsonResponse
  45. * @author Fx
  46. *
  47. */
  48. public function myWorkOrder(WorkOrderFilter $workOrderFilter)
  49. {
  50. $admin_id = Admin::user()->id;
  51. $area_ids = self::$areaIds;
  52. $workOrderList = WorkOrder::query()
  53. ->whereIn('area_id', $area_ids)
  54. ->filter($workOrderFilter)
  55. ->where('worker_id', $admin_id)
  56. ->orderByDesc('id')
  57. ->paginate();
  58. return $this->ok(WorkOrderResource::collection($workOrderList));
  59. }
  60. /**
  61. * workOrderDetail 工单详情
  62. *
  63. * @param Request $request
  64. * @return \Illuminate\Http\JsonResponse
  65. * @author Fx
  66. *
  67. */
  68. public function workOrderDetail(Request $request)
  69. {
  70. $work_order_id = $request->get('work_order_id') ?? '';
  71. if (empty($work_order_id)) return $this->error('参数错误');
  72. $worker_order = WorkOrder::query()->find($work_order_id);
  73. if (empty($worker_order)) return $this->error('找不到该工单信息,请联系管理员');
  74. // 创建者
  75. $created_at = $worker_order->created_at;
  76. $created_man = WorkOrder::$sourceMaps[$worker_order->source];
  77. // 进度
  78. $planneds = WorkOrder::$plannedMaps[$worker_order->planned];
  79. $planned = $worker_order->planned;
  80. // 接单着
  81. $received_name = $worker_order->worker->name ?? '';
  82. $received_at = $worker_order->fix_start_time ?? '';
  83. $position = LocationsLog::getNewestLocationByBikeNo($worker_order->bike_no);
  84. $reason = $worker_order->reason ?? '';
  85. $type = $worker_order->type;
  86. // if($type === WorkOrder::TYPE_TROUBLE){
  87. $str = '';
  88. if (is_serialized($reason)) {
  89. $reasonArr = unserialize($reason);
  90. foreach ($reasonArr as $k => $v) {
  91. if ($v == 1) {
  92. $str .= WorkOrder::$warningMaps[$k] . "、";
  93. }
  94. }
  95. $str = rtrim($str, '、');
  96. $reason = $str;
  97. }
  98. // }
  99. $data = [
  100. 'reason' => empty($reason) ? $worker_order->type_name : $reason,
  101. 'planned' => $planned,
  102. 'planneds' => $planneds,
  103. 'bike_no' => $worker_order->bike_no,
  104. 'location' => GaodeMaps::getAddress([$position['lng'], $position['lat']]),
  105. 'created_at' => Carbon::parse($created_at)->format('Y-m-d H:i:s'),
  106. 'created_man' => $created_man
  107. ];
  108. switch ($planned) {
  109. case WorkOrder::PLANNED_STATUS_MEET:
  110. $data += [
  111. 'received_name' => '',
  112. 'received_at' => '',
  113. 'work_over_time' => '',
  114. 'work_over_name' => '',
  115. ];
  116. break;
  117. case WorkOrder::PLANNED_STATUS_WORK:
  118. $data += [
  119. 'received_name' => $received_name,
  120. 'received_at' => Carbon::parse($received_at)->format('Y-m-d H:i:s'),
  121. 'work_over_time' => '',
  122. 'work_over_name' => '',
  123. ];
  124. break;
  125. case WorkOrder::PLANNED_STATUS_WORKED:
  126. $data += [
  127. 'received_name' => $received_name,
  128. 'received_at' => Carbon::parse($received_at)->format('Y-m-d H:i:s'),
  129. 'work_over_time' => Carbon::parse($worker_order->fix_end_time)->format('Y-m-d H:i:s'),
  130. 'work_over_name' => $worker_order->workerOver->name ?? '系统',
  131. ];
  132. break;
  133. case WorkOrder::PLANNED_STATUS_OVER:
  134. $data += [
  135. 'received_name' => $received_name,
  136. 'received_at' => Carbon::parse($received_at)->format('Y-m-d H:i:s'),
  137. 'work_over_time' => Carbon::parse($worker_order->fix_end_time)->format('Y-m-d H:i:s'),
  138. 'work_over_name' => $worker_order->workerOver->name ?? '系统',
  139. ];
  140. break;
  141. default :
  142. $data += [
  143. 'received_name' => '',
  144. 'received_at' => '',
  145. 'work_over_time' => '',
  146. 'work_over_name' => '',
  147. ];
  148. }
  149. return $this->ok($data);
  150. }
  151. /**
  152. * workOrderStatistics 工单统计
  153. *
  154. * @param WorkOrderFilter $filter
  155. * @return \Illuminate\Http\JsonResponse
  156. * @author Fx
  157. *
  158. */
  159. public function workOrderStatistics(WorkOrderFilter $filter)
  160. {
  161. $area_ids = self::$areaIds;
  162. $type_num = WorkOrder::query()
  163. ->whereIn('area_id', $area_ids)
  164. ->where('status', WorkOrder::STATUS_NO)
  165. ->filter($filter)
  166. ->groupBy(['type'])
  167. ->select('type', DB::raw('COUNT(id) as type_num'))
  168. ->get()
  169. ->toArray();
  170. $data = [
  171. 'charge_num' => 0,
  172. 'watch_num' => 0,
  173. 'power_failure_num' => 0,
  174. 'alert_num' => 0,
  175. 'steal_num' => 0,
  176. 'headman_num' => 0,
  177. 'trouble_num' => 0,
  178. 'help_num' => 0,
  179. 'other_num' => 0,
  180. 'offline_num' => 0,
  181. 'planned_meet_num' => 0, // 未认领
  182. 'planned_work_num' => 0, // 处理中
  183. 'planned_worked_num' => 0, // 已处理
  184. 'planned_over_num' => 0,// 完结
  185. ];
  186. foreach ($type_num as $v) {
  187. switch ($v['type']) {
  188. case WorkOrder::TYPE_CHARGE:
  189. $data['charge_num'] = $v['type_num'];
  190. break;
  191. case WorkOrder::TYPE_WATCH:
  192. $data['watch_num'] = $v['type_num'];
  193. break;
  194. case WorkOrder::TYPE_POWER_FAILURE:
  195. $data['power_failure_num'] = $v['type_num'];
  196. break;
  197. case WorkOrder::TYPE_ALERT:
  198. $data['alert_num'] = $v['type_num'];
  199. break;
  200. case WorkOrder::TYPE_STEAL:
  201. $data['steal_num'] = $v['type_num'];
  202. break;
  203. case WorkOrder::TYPE_HEADMAN:
  204. $data['headman_num'] = $v['type_num'];
  205. break;
  206. case WorkOrder::TYPE_TROUBLE:
  207. $data['trouble_num'] = $v['type_num'];
  208. break;
  209. case WorkOrder::TYPE_HELP:
  210. $data['help_num'] = $v['type_num'];
  211. break;
  212. case WorkOrder::TYPE_OFFLINE:
  213. $data['offline_num'] = $v['type_num'];
  214. break;
  215. case WorkOrder::TYPE_OTHER:
  216. $data['other_num'] = $v['type_num'];
  217. break;
  218. default;
  219. }
  220. }
  221. $planned_num = WorkOrder::query()
  222. ->filter($filter)
  223. ->groupBy('planned')
  224. ->select('planned', DB::raw('COUNT(id) as planned_num'))
  225. ->get()
  226. ->toArray();
  227. foreach ($planned_num as $v) {
  228. switch ($v['planned']) {
  229. case WorkOrder::PLANNED_STATUS_MEET:
  230. $data['planned_meet_num'] = $v['planned_num'];
  231. break;
  232. case WorkOrder::PLANNED_STATUS_WORK:
  233. $data['planned_work_num'] = $v['planned_num'];
  234. break;
  235. case WorkOrder::PLANNED_STATUS_WORKED:
  236. $data['planned_worked_num'] = $v['planned_num'];
  237. break;
  238. case WorkOrder::PLANNED_STATUS_OVER:
  239. $data['planned_over_num'] = $v['planned_num'];
  240. break;
  241. default;
  242. }
  243. }
  244. return $this->ok($data);
  245. }
  246. /**
  247. * workOrderType 筛选项工单类型
  248. *
  249. * @return \Illuminate\Http\JsonResponse
  250. * @author Fx
  251. *
  252. */
  253. public function workOrderType()
  254. {
  255. $types = WorkOrder::$typeMaps;
  256. $data = [];
  257. foreach ($types as $k => $v) {
  258. $dataItem['key'] = $k;
  259. $dataItem['value'] = $v;
  260. $data[] = $dataItem;
  261. }
  262. return $this->ok($types);
  263. }
  264. /**
  265. * receiveWorkOrder 接单
  266. *
  267. * @param Request $request
  268. * @return \Illuminate\Http\JsonResponse
  269. * @author Fx
  270. *
  271. */
  272. public function receiveWorkOrder(Request $request)
  273. {
  274. $work_order_id = $request->get('work_order_id') ?? '';
  275. if (empty($work_order_id)) return $this->error('参数错误');
  276. $worker_order = WorkOrder::query()->find($work_order_id);
  277. if (empty($worker_order)) return $this->error('找不到该工单信息,请联系管理员');
  278. // 加锁防止重复
  279. $lock = $this->makeReceiveWorkLock($work_order_id);
  280. if (!$lock) return $this->error('该工单已被认领');
  281. if ($worker_order->planned > WorkOrder::PLANNED_STATUS_MEET) return $this->error('该工单已被认领');
  282. $worker_id = Admin::user()->id;
  283. $worker_order->planned = WorkOrder::PLANNED_STATUS_WORK;
  284. $worker_order->fix_start_time = Carbon::now();
  285. $worker_order->worker_id = $worker_id;
  286. $bool = $worker_order->save();
  287. if ($bool) {
  288. return $this->ok('接单成功');
  289. } else {
  290. return $this->error('出现错误,请联系管理员');
  291. }
  292. }
  293. /**
  294. * makeReceiveWorkLock 接单锁 防止重复接单
  295. *
  296. * @param $work_order_id
  297. * @return bool
  298. * @author Fx
  299. *
  300. */
  301. public function makeReceiveWorkLock($work_order_id)
  302. {
  303. $key = sprintf(RedisKeys::LOCK_RECEIVE_WORK, $work_order_id);
  304. $res = app()->redis->incr($key);
  305. app()->redis->Expire($key, RedisKeys::LOCK_EXPIRE_RECEIVE_WORK);
  306. return $res > 1 ? false : true;
  307. }
  308. /**
  309. * updateWorkOrderStatus 更新工单状态已处理
  310. *
  311. * @param Request $request
  312. * @return \Illuminate\Http\JsonResponse
  313. * @author Fx
  314. *
  315. */
  316. public function updateWorkOrderStatus(Request $request)
  317. {
  318. $work_order_id = $request->get('work_order_id') ?? '';
  319. if (empty($work_order_id)) return $this->error('参数错误');
  320. //验证工单存在
  321. $work_order = WorkOrder::query()->find($work_order_id);
  322. if (empty($work_order)) return $this->error('找不到该工单信息,请联系管理员');
  323. $work_order_type = $work_order->type;
  324. $worker_id = $work_order->worker_id;
  325. // 验证是否有权限操作此工单
  326. $worker_type = Admin::user()->type;
  327. $admin_id = Admin::user()->id;
  328. if ($worker_type != AdminUser::TYPE_ADMIN) {
  329. if ($admin_id != $worker_id) {
  330. return $this->error('无权限操作此工单');
  331. }
  332. }
  333. if ($work_order->planned == WorkOrder::PLANNED_STATUS_MEET) return $this->error('该工单暂未认领');
  334. if ($work_order->planned == WorkOrder::PLANNED_STATUS_WORKED) return $this->error('该工单为已处理状态不可重复提交');
  335. if ($work_order->planned == WorkOrder::PLANNED_STATUS_OVER) return $this->error('该工单为已完成状态不可重复提交');
  336. // 判断工单类型 进行验证是否真正完成
  337. switch ($work_order_type) {
  338. case WorkOrder::TYPE_WATCH: // 查看类型工单
  339. $res = $this->updateWorkOrder($work_order);
  340. if ($res) {
  341. // 延时队列 验证是否完成工单
  342. VerifyWatchWorkOrderJob::dispatch($work_order->work_no)->delay(Carbon::now()->addMinutes(config('queue.delay.verifyWatchWorkOrder')));
  343. return $this->ok('操作成功');
  344. } else {
  345. return $this->error('更新失败,请重新尝试');
  346. }
  347. break;
  348. case WorkOrder::TYPE_CHARGE: // 充电类型工单
  349. $res = $this->updateWorkOrder($work_order);
  350. if ($res) {
  351. // 延时队列 验证是否完成工单
  352. VerifyChargeWorkOrderJob::dispatch($work_order->work_no)->delay(Carbon::now()->addMinutes(config('queue.delay.verifyChargeWorkOrder')));
  353. return $this->ok('操作成功');
  354. } else {
  355. return $this->error('更新失败,请重新尝试');
  356. }
  357. break;
  358. // case WorkOrder::TYPE_TROUBLE: // 故障工单
  359. // // 需要修改车辆故障表 以及更新车辆状态
  360. // break;
  361. default: // 其他工单了类型暂时不验证 直接赋值成功
  362. $res = $this->updateWorkOrderOver($work_order);
  363. if ($res) {
  364. return $this->ok('操作成功');
  365. } else {
  366. return $this->error('更新失败,请重新尝试');
  367. }
  368. }
  369. }
  370. /**
  371. * updateWorkOrder 更新工单状态为已处理
  372. *
  373. * @param $work_order
  374. * @return mixed
  375. * @author Fx
  376. *
  377. */
  378. private function updateWorkOrder($work_order)
  379. {
  380. $work_order->planned = WorkOrder::PLANNED_STATUS_WORKED;
  381. $work_order->work_over_id = Admin::user()->id;
  382. $bool = $work_order->save();
  383. return $bool;
  384. }
  385. /**
  386. * updateWorkOrderOver 更新工单状态为已完成
  387. *
  388. * @param $work_order
  389. * @return mixed
  390. * @author Fx
  391. *
  392. */
  393. private function updateWorkOrderOver($work_order)
  394. {
  395. $work_order->planned = WorkOrder::PLANNED_STATUS_OVER;
  396. $work_order->status = WorkOrder::STATUS_OK;
  397. $work_order->work_over_id = Admin::user()->id;
  398. $work_order->fix_end_time = Carbon::now();
  399. $bool = $work_order->save();
  400. return $bool;
  401. }
  402. /**
  403. * upgradeGroupWorkOrder 升级为组长工单
  404. *
  405. * @param Request $request
  406. * @return \Illuminate\Http\JsonResponse
  407. * @author Fx
  408. *
  409. */
  410. public function upgradeGroupWorkOrder(Request $request)
  411. {
  412. $work_order_id = $request->get('work_order_id') ?? '';
  413. $remark = $request->get('remark') ?? '';
  414. if (empty($work_order_id) || empty($remark)) return $this->error('参数错误');
  415. //验证工单存在
  416. $work_order = WorkOrder::query()->find($work_order_id);
  417. if (empty($work_order)) return $this->error('找不到该工单信息,请联系管理员');
  418. $admin_id = Admin::user()->id;
  419. $worker_id = $work_order->worker_id;
  420. if ($work_order->planned == WorkOrder::PLANNED_STATUS_MEET) return $this->error('该工单暂未认领不能升级');
  421. if ($admin_id != $worker_id) {
  422. return $this->error('无权限操作此工单');
  423. }
  424. try {
  425. $work_order->type = WorkOrder::TYPE_HEADMAN;
  426. $work_order->type_name = WorkOrder::$typeMaps[WorkOrder::TYPE_HEADMAN];
  427. $work_order->remark = $remark; // 备注信息
  428. $work_order->save();
  429. return $this->ok('更改成功');
  430. } catch (\Exception $exception) {
  431. Log::error($exception->getMessage());
  432. return $this->error('更改失败,请联系管理员');
  433. }
  434. }
  435. }