AiDispatch.php 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. <?php
  2. namespace app\api\controller;
  3. use app\common\util\AppMsg;
  4. use think\Controller;
  5. use think\Db;
  6. class AiDispatch extends Controller
  7. {
  8. private $url = "http://121.36.46.135:8000/api/v1/dispatch";
  9. public function dispatch()
  10. {
  11. try {
  12. // 获取需要分派的组织ID,缓存1小时
  13. $orgIds = cache('ai_send');
  14. if (!$orgIds) {
  15. $configId = Db::name('config')
  16. ->where('name', 'org_ai_send')
  17. ->value('id');
  18. $orgIds = Db::name('config_org')
  19. ->where('config_id', $configId)
  20. ->where('value', 1)
  21. ->column('org_id');
  22. cache('ai_send', $orgIds);
  23. }
  24. if (!empty($orgIds)) {
  25. foreach ($orgIds as $orgId) {
  26. $this->assignToWorker($orgId);
  27. }
  28. }
  29. } catch (\Throwable $e) {
  30. echo '出错了~';
  31. \think\facade\Log::error('dispatch error: ' . $e->getMessage());
  32. }
  33. }
  34. public function assignToWorker($orgId)
  35. {
  36. try {
  37. // 获取组织的AI时间间隔(秒),缓存1小时
  38. $second = cache('ai_time_' . $orgId);
  39. if ($second === false) {
  40. $configId = Db::name('config')->where('name', 'org_ai_time')->value('id');
  41. $value = Db::name('config_org')->where('config_id', $configId)->where('org_id', $orgId)->value('value');
  42. $second = intval($value ?: 0);
  43. cache('ai_time_' . $orgId, $second);
  44. }
  45. $second = intval($second) * 60;
  46. // 查询最近订单,按时间正序,限制20条
  47. $orders = Db::name('orders')
  48. ->where('del', 0)
  49. ->where('order_mode', 1)
  50. ->where('org_id', $orgId)
  51. ->whereIn('work_type_mode', [1,2,3,4])
  52. ->when($second, function ($query) use ($second) {
  53. $query->whereTime('create_time', '<=', date('Y-m-d H:i:s', time() - $second));
  54. })->whereNotExists(function ($query) {
  55. $query->table('ai_send_fail')
  56. ->whereColumn('ai_send_fail.order_id', 'orders.id');
  57. })
  58. ->field('id,sn,dep_id,work_type_mode')
  59. ->order('id desc')
  60. ->limit(20)
  61. ->select();
  62. if (empty($orders)) {
  63. return;
  64. }
  65. foreach ($orders as &$order) {
  66. $mode = $order['work_type_mode'];
  67. $workers = $this->getWorkersByMode($mode, $orgId);
  68. // 构建派工数据
  69. $data = [
  70. 'dispatch_type' => $mode,
  71. 'notify' => "http://wy.yjafw.com/api/ai_dispatch/notify",
  72. 'task' => [
  73. 'task_id' => $order['id'],
  74. ],
  75. 'workers' => $workers,
  76. ];
  77. if ($mode == 1) {
  78. // 获取部门用户
  79. $users = Db::name('dep')->where('id', $order['dep_id'])->value('users');
  80. $taskUsers = $users ? explode(',', $users) : [];
  81. $data['task']['users'] = $taskUsers;
  82. $typeId = Db::name('order_repair')->where('order_id', $order['id'])->value('type_id');
  83. if (!$typeId){
  84. continue;
  85. }
  86. $data['task']['required_skill'] = Db::name('order_type')->where('id', $typeId)->value('parent_id') ?? 0;
  87. }elseif ($mode == 3) {
  88. $users = Db::name('order_convey')
  89. ->alias('a')
  90. ->join('address b', 'b.id = a.start')
  91. ->where('a.order_id', $order['id'])
  92. ->value('b.users');
  93. $taskUsers = $users ? explode(',', $users) : [];
  94. $data['task']['users'] = $taskUsers;
  95. }
  96. $res = $this->curl_post($this->url, json_encode($data, JSON_UNESCAPED_UNICODE));
  97. // echo $res . PHP_EOL;
  98. \think\facade\Log::info('Dispatch result: ' . $res);
  99. }
  100. unset($order);
  101. } catch (\Throwable $e) {
  102. echo $e->getMessage();
  103. \think\facade\Log::error('assignToWorker error: ' . $e->getMessage());
  104. }
  105. }
  106. /**
  107. * 获取指定模式和组织下的可用工作人员
  108. */
  109. private function getWorkersByMode($mode, $orgId)
  110. {
  111. $workers = [];
  112. $users = cache('workers_mode_'.$mode.'_org_' . $orgId);
  113. if (!$users) {
  114. $roles = (new \app\common\model\WorkTypeMode())->getRoles($mode, $orgId);
  115. $roleIds = Db::name('roles')
  116. ->whereIn('parent_id', array_column($roles, 'id'))
  117. ->where('org_id', $orgId)
  118. ->where('del', 0)
  119. ->where('enable', 1)
  120. ->column('id');
  121. if (empty($roleIds)) return [];
  122. // 获取用户信息
  123. $users = Db::name('user_roles')
  124. ->alias('ur')
  125. ->join('user u', 'u.id = ur.user_id')
  126. ->where('u.del', 0)
  127. ->where('u.enable', 1)
  128. ->whereIn('ur.roles_id', $roleIds)
  129. ->where('u.work', 1)
  130. ->field('u.id as worker_id, u.real_name as name, u.label as skills')
  131. ->select();
  132. if (empty($users)){
  133. return [];
  134. }
  135. cache('workers_mode_'.$mode.'_org_' . $orgId,$users);
  136. }
  137. // 批量查询每个用户当前任务数,避免循环内count
  138. $userIds = array_column($users, 'worker_id');
  139. $todoCounts = Db::name('todo')
  140. ->where('org_id', $orgId)
  141. ->where('del', 0)
  142. ->whereIn('to_user_id', $userIds)
  143. ->whereIn('todo_mode', [1,2,3])
  144. ->where('create_yyyymm', date('Ym'))
  145. ->group('to_user_id')
  146. ->column('COUNT(*) as total_counts,COUNT(CASE WHEN todo_mode IN (1,2) THEN 1 END) as current_counts', 'to_user_id');
  147. foreach ($users as $user) {
  148. $user['current_orders'] = $todoCounts[$user['worker_id']]['current_counts'] ?? 0;
  149. $user['month_orders'] = $todoCounts[$user['worker_id']]['total_counts'] ?? 0;
  150. if ($mode == 1) {
  151. $user['skills'] = $user['skills'] ? explode(',', $user['skills']) : [];
  152. }
  153. $workers[] = $user;
  154. }
  155. return $workers;
  156. }
  157. public function addTodo($orderId,$workerId)
  158. {
  159. $time = getTime();
  160. $order = Db::name('orders')
  161. ->where('id',$orderId)
  162. ->field('org_id,work_type_mode,is_deal')
  163. ->find();
  164. if (!$order){
  165. return false;
  166. }
  167. $todoData = [
  168. 'order_id' => $orderId,
  169. 'todo_content' => "",
  170. 'create_user_id' => -1,
  171. 'org_id' => $order['org_id'],
  172. 'create_time' => $time,
  173. 'todo_mode' => 1,
  174. 'work_type_mode' => $order['work_type_mode'],
  175. 'create_yyyy' => date('Y'),
  176. 'create_yyyymm' => date('Ym'),
  177. 'create_yyyymmdd' => date('Ymd'),
  178. 'to_user_id' => $workerId,
  179. ];
  180. $todoData['sn'] = get_unique_sn(get_config('sn_prefix'));
  181. $todoId = Db::name('todo')
  182. ->insertGetId($todoData);
  183. $taskData = [
  184. 'org_id' => $order['org_id'],
  185. 'type' => 1,
  186. 'start_time' => $time,
  187. 'create_time' => $time,
  188. ];
  189. $taskData['user_id'] = $workerId;
  190. $taskData['bus_id'] = $todoId;
  191. Db::name('ai_send_success')
  192. ->insert([
  193. 'org_id' => $order['org_id'],
  194. 'order_id' => $orderId,
  195. 'todo_id' => $todoId,
  196. 'user_id' => $workerId,
  197. 'create_time' => $time,
  198. 'mode'=>$order['work_type_mode'],
  199. ]);
  200. $res = Db::name('task')
  201. ->insert($taskData);
  202. $deal = $order['is_deal'];
  203. if(check_two_dispatch($workerId)==1){
  204. $deal = 1;
  205. $dLog = [
  206. 'user_id'=>$workerId,
  207. 'to_user_id'=>$workerId,
  208. 'create_time' => $time,
  209. 'content' => '',
  210. 'order_id' => $orderId,
  211. 'roles_id' => 0
  212. ];
  213. $res = Db::name('dispatch_log')
  214. ->insert($dLog);
  215. }
  216. $r = Db::name('orders')
  217. ->where('id',$orderId)
  218. ->update(['is_deal'=>$deal,'order_mode'=>4]);
  219. send_jpush([$workerId],AppMsg::PUSH_WORKER_ORDER_SEND,'',['id'=>$todoId]);
  220. }
  221. public function notify()
  222. {
  223. $json = file_get_contents('php://input');
  224. $data = json_decode($json, true);
  225. if ($data){
  226. if (!empty($data['order_id'])){
  227. if (!empty($data['worker_id'])){
  228. $this->addTodo($data['order_id'], $data['worker_id']);
  229. }else{
  230. $order = Db::name('orders')
  231. ->where('id',$data['order_id'])
  232. ->field('org_id,work_type_mode,is_deal')
  233. ->find();
  234. Db::name('ai_send_fail')->insert([
  235. 'org_id' => $order['org_id'],
  236. 'order_id' => $data['order_id'],
  237. 'create_time' => getTime(),
  238. 'mode'=>$order['work_type_mode'],
  239. 'msg'=>$order['message'] ?? '',
  240. ]);
  241. }
  242. }
  243. }
  244. trace('ai派单:数据错误','error');
  245. }
  246. function curl_post($url , $data=array()){
  247. $ch = curl_init();
  248. curl_setopt($ch, CURLOPT_URL, $url);
  249. curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
  250. curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
  251. curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
  252. curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json; charset=utf-8'));//重点
  253. // POST数据
  254. curl_setopt($ch, CURLOPT_POST, 1);
  255. // 把post的变量加上
  256. curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
  257. $output = curl_exec($ch);
  258. curl_close($ch);
  259. return $output;
  260. }
  261. }