Workorder.php 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638
  1. <?php
  2. namespace app\api\controller;
  3. use think\Db;
  4. use fast\Random;
  5. use think\Validate;
  6. use app\common\controller\Api;
  7. use addons\workorder\model\Kbs;
  8. use addons\workorder\model\Orders;
  9. use addons\workorder\model\Engineer;
  10. use addons\workorder\library\General;
  11. use addons\workorder\library\Captcha;
  12. /**
  13. * 工单系统API
  14. */
  15. class Workorder extends Api
  16. {
  17. // 无需登录的接口,*表示全部
  18. protected $noNeedLogin = ['login', 'captcha', 'captchaPre'];
  19. // 无需鉴权的接口,*表示全部
  20. protected $noNeedRight = ['*'];
  21. /**
  22. * @var General 实例
  23. */
  24. protected $General = null;
  25. protected $pageCount = 15;
  26. protected $userEngineerId = null;
  27. public function _initialize()
  28. {
  29. parent::_initialize();
  30. $this->General = General::instance();
  31. // 当前用户是否是工程师
  32. if ($this->auth) {
  33. $this->userEngineerId = Engineer::where('user_id', $this->auth->id)->where('status', '1')->value('id');
  34. }
  35. $this->General->autoClose();
  36. }
  37. public function index()
  38. {
  39. $this->success('', [
  40. 'engineer' => $this->userEngineerId ? true : false
  41. ]);
  42. }
  43. public function login()
  44. {
  45. $username = $this->request->post('username');
  46. $password = $this->request->post('password');
  47. $captcha = $this->request->post('captcha');
  48. $captchaId = $this->request->post('captcha_id');
  49. $rule = [
  50. 'captcha' => 'require|length:4,6',
  51. 'username' => 'require|length:3,30',
  52. 'password' => 'require|length:6,30',
  53. 'captcha_id' => 'require'
  54. ];
  55. $msg = [
  56. 'captcha.require' => 'Please enter the verification code',
  57. 'captcha.length' => 'Please enter the correct verification code~',
  58. 'username.require' => 'User name cannot be empty',
  59. 'username.length' => 'User name must be 3 to 30 characters',
  60. 'password.require' => 'Password cannot be empty',
  61. 'password.length' => 'The password must be between 3 and 30 characters',
  62. 'captcha_id.require' => 'Missing parameter!'
  63. ];
  64. $data = [
  65. 'username' => $username,
  66. 'password' => $password,
  67. 'captcha' => $captcha,
  68. 'captcha_id' => $captchaId
  69. ];
  70. $captchaObj = new Captcha();
  71. if (!$captchaObj->check($captcha, $captchaId)) {
  72. $this->error(__('Please enter the correct verification code~'));
  73. }
  74. $validate = new Validate($rule, $msg);
  75. $result = $validate->check($data);
  76. if (!$result) {
  77. $this->error(__($validate->getError()));
  78. }
  79. $ret = $this->auth->login($username, $password);
  80. if ($ret) {
  81. $data = ['userinfo' => $this->auth->getUserinfo()];
  82. $data['userinfo']['avatar'] = cdnurl($data['userinfo']['avatar'], true);
  83. $this->success(__('Logged in successful'), $data);
  84. } else {
  85. $this->error($this->auth->getError());
  86. }
  87. }
  88. public function captchaPre()
  89. {
  90. $captchaId = md5(Random::uuid());
  91. $this->success('', [
  92. 'captcha_id' => $captchaId
  93. ]);
  94. }
  95. public function captcha()
  96. {
  97. $captchaId = $this->request->request('captcha_id');
  98. $config = array(
  99. 'codeSet' => '123456789', // 验证码字符集合
  100. 'fontSize' => 22, // 验证码字体大小(px)
  101. 'useCurve' => false, // 是否画混淆曲线
  102. 'useNoise' => true, // 是否添加杂点
  103. 'length' => 4, // 验证码位数
  104. 'bg' => array(255, 255, 255), // 背景颜色
  105. );
  106. $captcha = new Captcha($config);
  107. return $captcha->entry($captchaId);
  108. }
  109. public function manage()
  110. {
  111. if (!$this->userEngineerId) {
  112. $this->error(__('You have no permission to operate!'));
  113. }
  114. $page = $this->request->param('page') ?? 1;
  115. $type = $this->request->param('type') ?? '0';
  116. $min = ($page == 1) ? 0 : (($page - 1) * $this->pageCount);
  117. $where['orders.engineer_id'] = $this->userEngineerId;
  118. switch ($type) {
  119. case '1':
  120. $where['orders.status'] = ['in', '1,2'];
  121. break;
  122. case '2' :
  123. $where['orders.status'] = 3;
  124. break;
  125. case '3':
  126. $where['orders.status'] = ['in', '4,5'];
  127. break;
  128. }
  129. $orders = Orders::where($where)
  130. ->with(['category', 'urgentrank', 'user'])
  131. ->order('createtime desc')
  132. ->limit($min, $this->pageCount)
  133. ->select();
  134. foreach ($orders as $key => $item) {
  135. $item->getRelation('category')->visible(['logo_image']);
  136. $item->getRelation('urgentrank')->visible(['name']);
  137. $item->getRelation('user')->visible(['nickname']);
  138. $item->status = $this->General->handleStatus($item->status, true);
  139. $item->title = $item->title ?? __('Untitled');
  140. if ($item->category->logo_image) {
  141. $item->logo_image = cdnurl($item->category->logo_image, true);
  142. unset($item->category);
  143. }
  144. }
  145. $this->success('ok', [
  146. 'type' => $type,
  147. 'page' => $page,
  148. 'orders' => $orders,
  149. 'next' => !(count($orders) < $this->pageCount)
  150. ]);
  151. }
  152. public function searchTransfer()
  153. {
  154. $this->request->filter(['trim', 'strip_tags', 'htmlspecialchars']);
  155. $word = (array)$this->request->request("q_word/a");
  156. $keyword = $this->request->param("keyword") ?? false;
  157. if ($keyword) {
  158. if (strpos($keyword, ' ') !== false) {
  159. $word = explode(' ', $keyword);
  160. } else {
  161. $word[] = $keyword;
  162. }
  163. }
  164. $engineers = Engineer::all(function ($query) use ($word) {
  165. $word = array_filter(array_unique($word));
  166. if (count($word) == 1) {
  167. $query->where('title', "like", "%" . reset($word) . "%");
  168. } else {
  169. $query->where(function ($query) use ($word) {
  170. foreach ($word as $index => $item) {
  171. $query->whereOr(function ($query) use ($item) {
  172. $query->where('title', "like", "%{$item}%");
  173. });
  174. }
  175. });
  176. }
  177. $query->where('status', '1');
  178. $query->where('user_id', '<>', $this->auth->id);
  179. });
  180. return json(['list' => $engineers, 'total' => count($engineers)]);
  181. }
  182. public function transfer()
  183. {
  184. $id = $this->request->param('id');
  185. $row = Orders::get($id);
  186. if (!$row) {
  187. $this->error(__('Work order not found~'));
  188. }
  189. $isCurrentEngineer = ($row->engineer_id === $this->userEngineerId) ? true : false;
  190. if (!$isCurrentEngineer) {
  191. $this->error(__('You have no permission to operate!'));
  192. }
  193. if ($this->request->isPost()) {
  194. $param = $this->request->param();
  195. $res = $this->General->transfer($row, $param['transfer_engineer']);
  196. if ($res['code'] == 1) {
  197. $this->output($res);
  198. } else {
  199. $this->error($res['msg']);
  200. }
  201. }
  202. $this->success('ok', [
  203. 'info' => $row
  204. ]);
  205. }
  206. public function userInfo()
  207. {
  208. $id = $this->request->param('id');
  209. $userId = $this->request->param('user_id') ?? 0;
  210. $engineerId = $this->request->param('engineer_id') ?? 0;
  211. $row = Orders::get($id, ['user']);
  212. if (!$row) {
  213. $this->error(__('Work order not found~'));
  214. }
  215. if ($userId && $row['user_id'] == $userId) {
  216. $userInfo = [
  217. 'nickname' => $row->user->nickname,
  218. 'avatar' => $row->user->avatar ? cdnurl($row->user->avatar, true) : (function_exists('letter_avatar') ? letter_avatar($row->user->nickname) : cdnurl('/assets/img/avatar.png', true)),
  219. 'bio' => $row->user->bio,
  220. 'id' => $row->user->id
  221. ];
  222. } elseif ($engineerId) {
  223. $engineer = Engineer::get($engineerId, ['user']);
  224. if (!$engineer) {
  225. $this->error(__('engineer not found~'));
  226. }
  227. $userInfo = $engineer;
  228. $userInfo['email'] = $engineer->user->email;
  229. $userInfo['mobile'] = $engineer->user->mobile;
  230. $userInfo['avatar'] = $engineer->user->avatar ? cdnurl($engineer->user->avatar, true) : (function_exists('letter_avatar') ? letter_avatar($engineer->user->nickname) : cdnurl('/assets/img/avatar.png', true));
  231. unset($userInfo['user'], $userInfo['openid'], $userInfo['work_order_quantity']);
  232. } else {
  233. $this->error(__('user not found~'));
  234. }
  235. $this->success('ok', [
  236. 'userinfo' => $userInfo
  237. ]);
  238. }
  239. public function my()
  240. {
  241. $page = $this->request->param('page') ?? 1;
  242. $min = ($page == 1) ? 0 : (($page - 1) * $this->pageCount);
  243. if ($this->request->isDelete()) {
  244. $order_id = (int)$this->request->param('order_id');
  245. $order = Orders::get($order_id);
  246. if (!$order) {
  247. $this->error(__('Work order not found~'));
  248. }
  249. if ($order->status != 5) {
  250. $this->error(__('You can delete a work order after closing it!'));
  251. }
  252. if (Orders::destroy(['id' => $order_id, 'user_id' => $this->auth->id])) {
  253. General::orderNumberChangeCalcEngineerStatistics($order->id, $order->engineer_id, 'del');
  254. $this->success(__('Delete Success~'));
  255. } else {
  256. $this->error(__('Delete Fail!'));
  257. }
  258. }
  259. $this->relationSearch = true;
  260. $orders = Orders::where('user_id', $this->auth->id)
  261. ->with(['category', 'urgentrank'])
  262. ->order('createtime desc')
  263. ->limit($min, $this->pageCount)
  264. ->select();
  265. foreach ($orders as $key => $item) {
  266. $item->getRelation('category')->visible(['logo_image']);
  267. $item->getRelation('urgentrank')->visible(['name']);
  268. $item->status = $this->General->handleStatus($item->status, false);
  269. $item->title = $item->title ?? __('Untitled');
  270. if ($item->category->logo_image) {
  271. $item->logo_image = cdnurl($item->category->logo_image, true);
  272. unset($item->category);
  273. }
  274. }
  275. $this->success('ok', [
  276. 'page' => $page,
  277. 'orders' => $orders,
  278. 'next' => !(count($orders) < $this->pageCount)
  279. ]);
  280. }
  281. public function detail()
  282. {
  283. $id = $this->request->param('id');
  284. $row = Orders::get($id, ['user', 'category', 'urgentrank']);
  285. if (!$row) {
  286. $this->error(__('Work order not found~'));
  287. }
  288. $isUser = ($row->user_id == $this->auth->id) ? true : false;
  289. $isCurrentEngineer = ($row->engineer_id === $this->userEngineerId) ? true : false;
  290. if (!$isUser && !$isCurrentEngineer) {
  291. $this->error(__('You have no permission to operate!'));
  292. }
  293. if ($this->request->isPost()) {
  294. $type = $this->request->param('type');
  295. if ($type == 'close') {
  296. $this->output($this->General->closeOrder($row, $isCurrentEngineer));
  297. } elseif ($type == 'urging' && $isUser) {
  298. $this->output($this->General->urgingOrder($row));
  299. } elseif ($type == 'evaluate') {
  300. if ($row['status'] == 1) {
  301. $this->error(__('The current status of the work order cannot be evaluated~'));
  302. }
  303. if ($row['status'] == 5) {
  304. $this->error(__('The work order has been evaluated~'));
  305. }
  306. $this->success('ok', [
  307. 'info' => $row
  308. ]);
  309. }
  310. $this->error(__('Nothing happened~'));
  311. }
  312. $orderInfo = $this->General->orderInfoHandle($row, $isUser, $isCurrentEngineer);
  313. foreach ($orderInfo['basicField'] as $key => &$value) {
  314. $value['value'] = strip_tags($value['value']);
  315. }
  316. // 聊天记录和工程师资料
  317. $records = $this->General->orderRecords($id, $row->engineer_id);
  318. $replyField = $row->getFields(null, $isUser ? 1 : 2);
  319. $this->success('ok', [
  320. 'row' => $orderInfo['order'],
  321. 'isUser' => $isUser,
  322. 'fields' => $replyField,
  323. 'records' => $records['records'],
  324. 'title' => $orderInfo['order']->title . ' – ' . __('Work order details'),
  325. 'basicField' => $orderInfo['basicField']
  326. ]);
  327. }
  328. public function evaluate()
  329. {
  330. $id = $this->request->param('id');
  331. $order = Orders::get($id);
  332. if (!$order) {
  333. $this->error(__('Work order not found~'));
  334. }
  335. if ($order->status == 1) {
  336. $this->error(__('The current status of the work order cannot be evaluated~'));
  337. }
  338. if ($order->status == 5) {
  339. $this->error(__('The work order has been evaluated~'));
  340. }
  341. if ($this->request->isPost()) {
  342. $row = $this->request->param();
  343. unset($row['id']);
  344. $this->output($this->General->createEvaluate($order, $row, $this->auth->id));
  345. }
  346. }
  347. public function reply()
  348. {
  349. $row = $this->request->param();
  350. $order = Orders::get($row['id']);
  351. if (!$order) {
  352. $this->error(__('Work order not found~'));
  353. }
  354. $user = ($order->user_id == $this->auth->id) ? $this->auth : false;
  355. $engineer = ($order->engineer_id == $this->userEngineerId) ? Engineer::get($this->userEngineerId) : false;
  356. if (!$user && !$engineer) {
  357. $this->error(__('You have no permission to operate!'));
  358. }
  359. $res = $this->General->createReply($order, $user, $engineer, $row);
  360. if ($res['code'] == 1) {
  361. $this->success($res['msg'], [
  362. 'records' => $res['data']['records']
  363. ]);
  364. } else {
  365. $this->error($res['msg']);
  366. }
  367. }
  368. public function showConfidential()
  369. {
  370. $id = $this->request->param('id');
  371. // 直接读取数据库中的数据
  372. $row = Db::name('workorder_records')
  373. ->where('id', $id)
  374. ->find();
  375. if (!$row) {
  376. $this->error(__('Record order not found!'));
  377. }
  378. $order = Orders::get($row['order_id']);
  379. $isUser = ($order->user_id == $this->auth->id) ? true : false;
  380. $isCurrentEngineer = ($order->engineer_id === $this->userEngineerId) ? true : false;
  381. if (!$isUser && !$isCurrentEngineer) {
  382. $this->error(__('You have no permission to operate!'));
  383. }
  384. $this->success('ok', $row);
  385. }
  386. public function category()
  387. {
  388. $category = Db::name('workorder_category')
  389. ->where('status', 1)
  390. ->where('deletetime', null)
  391. ->order('weigh desc')
  392. ->select();
  393. foreach ($category as $index => $item) {
  394. $pid = $item['pid'];
  395. $item['logo_image'] = cdnurl($item['logo_image'], true);
  396. if ($pid == 0) {
  397. $categoryList[] = $item;
  398. } else {
  399. $categoryChildTemp[$pid][] = $item;
  400. }
  401. }
  402. foreach ($categoryList as $index => $item) {
  403. $categoryList[$index]['child'] = isset($categoryChildTemp[$item['id']]) ? $categoryChildTemp[$item['id']] : [];
  404. }
  405. $this->success('ok', [
  406. 'category' => $categoryList
  407. ]);
  408. }
  409. public function search()
  410. {
  411. $type = $this->request->param('type') ?? 'category';
  412. $page = $this->request->param('page') ?? 1;
  413. $keywords = $this->request->param('keywords') ?? false;
  414. $category = $this->request->param('category') ?? 0;
  415. $min = ($page == 1) ? 0 : (($page - 1) * $this->pageCount);
  416. if ($type == 'category') {
  417. $category = Db::name('workorder_category')
  418. ->where('status', 1)
  419. ->where('pid', '>', 0)
  420. ->where('name', 'like', '%' . $keywords . '%')
  421. ->where('deletetime', null)
  422. ->order('weigh desc')
  423. ->limit($min, $this->pageCount)
  424. ->select();
  425. foreach ($category as $key => $item) {
  426. $category[$key]['logo_image'] = cdnurl($item['logo_image'], true);
  427. }
  428. $this->success('ok', [
  429. 'res' => $category,
  430. 'page' => $page,
  431. 'next' => !(count($category) < $this->pageCount)
  432. ]);
  433. }
  434. }
  435. public function kbs()
  436. {
  437. $keywords = $this->request->param('keywords') ?? false;
  438. $category = $this->request->param('category') ?? 0;
  439. $kbsIds = Db::name('workorder_category')
  440. ->where('id', $category)
  441. ->where('status', '1')
  442. ->where('deletetime', null)
  443. ->value('kbs_ids');
  444. $kbs = [];
  445. if ($kbsIds) {
  446. $where['id'] = ['in', $kbsIds];
  447. $where['status'] = '1';
  448. $where['deletetime'] = null;
  449. if ($keywords) {
  450. $where['title'] = ['like', '%' . $keywords . '%'];
  451. }
  452. $kbs = Db::name('workorder_kbs')
  453. ->field('id,title,views,likes,url')
  454. ->where($where)
  455. ->order('weigh desc')
  456. ->limit($this->pageCount)
  457. ->select();
  458. }
  459. $submitChannel = Db::name('workorder_submit_channel')
  460. ->where('status', 1)
  461. ->order('weigh desc')
  462. ->select();
  463. foreach ($submitChannel as $index => $item) {
  464. $submitChannel[$index]['logo_image'] = cdnurl($item['logo_image'], true);
  465. }
  466. $this->success('ok', [
  467. 'res' => $kbs,
  468. 'channel' => $submitChannel
  469. ]);
  470. }
  471. public function kbsInfo()
  472. {
  473. $id = $this->request->param('id');
  474. $category = $this->request->param('category') ?? 0;
  475. $kbs = Kbs::get(['id' => $id, 'status' => '1']);
  476. if (!$kbs) {
  477. $this->error(__('I cant find the knowledge~'));
  478. }
  479. $kbs->setInc('views', 1);
  480. $recKbs = $this->General->recKbs($id, $category);
  481. $this->success('ok', [
  482. 'kbs' => $kbs,
  483. 'rec' => $recKbs
  484. ]);
  485. }
  486. public function kbsOperate()
  487. {
  488. $id = $this->request->param('id');
  489. $type = $this->request->param('type');
  490. $kbs = Kbs::get(['id' => $id, 'status' => '1']);
  491. if (!$kbs) {
  492. $this->error(__('I cant find the knowledge~'));
  493. }
  494. if ($type == 'likes' || $type == 'dislikes') {
  495. $kbs->setInc($type);
  496. $this->success('ok');
  497. }
  498. }
  499. public function create()
  500. {
  501. $category = $this->request->param('category');
  502. $fields = Orders::getFields(null, 0);
  503. $categoryName = Db::name('workorder_category')
  504. ->where('id', $category)
  505. ->where('status', '1')
  506. ->where('deletetime', null)
  507. ->value('name');
  508. if (!$categoryName) {
  509. $this->error(__('Product / service classification not found~'));
  510. }
  511. $urgentrank = Db::name('workorder_urgentrank')
  512. ->where('status', '1')
  513. ->where('deletetime', null)
  514. ->order('weigh desc')
  515. ->select();
  516. if (!$urgentrank) {
  517. $this->error(__('Emergency level of no work order available!'));
  518. }
  519. if ($this->request->isPost()) {
  520. $row = $this->request->param();
  521. unset($row['category']);
  522. $row['category_id'] = $category;
  523. $res = $this->General->createOrder($row, $this->auth->id);
  524. if ($res['code'] == 1) {
  525. $this->success(__('Submitted successfully~'), [
  526. 'order_id' => $res['data']['id']
  527. ]);
  528. } else {
  529. $this->error($res['msg']);
  530. }
  531. }
  532. $this->success('create', [
  533. 'fields' => $fields,
  534. 'urgentrank' => $urgentrank,
  535. 'categoryName' => $categoryName
  536. ]);
  537. }
  538. public function uploadMultipart()
  539. {
  540. // 获取上传配置
  541. $upload = \app\common\model\Config::upload();
  542. \think\Hook::listen("upload_config_init", $upload);
  543. $this->success('ok', [
  544. 'uploadurl' => $upload['uploadurl'],
  545. 'multipart' => (isset($upload['multipart']) && $upload['multipart']) ? $upload['multipart'] : false,
  546. ]);
  547. }
  548. /**
  549. * 输出方法返回结果
  550. */
  551. protected function output($res)
  552. {
  553. if ($res['code'] == 1) {
  554. $this->success($res['msg']);
  555. } else {
  556. $this->error($res['msg']);
  557. }
  558. }
  559. }