index.blade.php 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581
  1. @extends("layouts.app")
  2. @section('title','处理工单')
  3. @section("content")
  4. <div class="container-fluid d-none" id="list">
  5. <div>
  6. <div class="">
  7. <div id="form_div" style="min-width: 1220px;"></div>
  8. <div class="form-inline mt-1" id="btn">
  9. @can('订单管理-订单问题件生成')
  10. <span class="ml-1">
  11. <button type="button" class="btn btn-outline-dark btn-sm form-control-sm tooltipTarget"
  12. @click="createOrderIssue(null,false)" style="background: #dad7e8;">生成问题件</button>
  13. </span>
  14. @endcan
  15. @can('订单管理-订单问题件生成')
  16. <span class="ml-1">
  17. <button type="button" class="btn btn-outline-primary btn-sm form-control-sm tooltipTarget"
  18. @click="exportText()">导出文本</button>
  19. </span>
  20. @endcan
  21. @can('订单管理-工单处理-审核')
  22. <span class="ml-1">
  23. <button type="button" class="btn btn-outline-success btn-sm form-control-sm tooltipTarget"
  24. @click="batchReview">
  25. 批量审核
  26. </button>
  27. </span>
  28. @endcan
  29. <span class="ml-1">
  30. <button type="button" class="btn btn-outline-dark btn-sm form-control-sm tooltipTarget"
  31. @click="copyLogisticNumber()" style="background: #dad7e8;">批量复制单号</button>
  32. </span>
  33. @can('订单管理-工单处理-审核')
  34. <span class="ml-1">
  35. <button type="button" class="btn btn-outline-success btn-sm form-control-sm tooltipTarget"
  36. @click="showEditIssueType">
  37. 批量修改问题件类型
  38. </button>
  39. </span>
  40. @endcan
  41. </div>
  42. <div>
  43. <table class="table table-sm table-striped table-hover table-bordered td-min-width-80" id="table">
  44. <tbody class="">
  45. <template v-for="(item,i) in workOrders">
  46. <tr @click="selectTr===i+1?selectTr=0:selectTr=i+1" :class="selectTr===i+1?'focusing' : ''">
  47. <td>
  48. <label><input type="checkbox" :value="item.id"></label>
  49. </td>
  50. <td class="text-center">
  51. <span>@{{ i+1 }}</span>
  52. <span v-show="item.is_issue_order" class="badge badge-primary">问题件</span>
  53. </td>
  54. <td class="text-center">
  55. @can('订单管理-订单问题件生成')
  56. <button class="btn btn-sm btn-outline-primary" @click="createOrderIssue(item,true)" v-show="!item.is_issue_order ">
  57. 生成问题件
  58. </button>
  59. @endcan
  60. @can('订单管理-工单处理-审核')
  61. <button class="btn btn-sm btn-outline-success" v-show="item.status !== '已处理'" @click="review(item,i)">
  62. 审核
  63. </button>
  64. @endcan
  65. </td>
  66. <td class="text-center">@{{ item.status }}</td>
  67. <td>@{{item.order ? (item.order.logistic ? item.order.logistic.name : '') : '' }}</td>
  68. <td class="text-center">
  69. <template v-if="item.order">
  70. <template v-if="item.order.packages && item.order.packages.length === 1">
  71. <p>@{{ item.order.packages[0].logistic_number }}</p>
  72. </template>
  73. <template v-else-if="item.order.packages && item.order.packages.length > 0">
  74. <template v-if="selectOrder === item.order.id">
  75. <template v-for="(package,index) in item.order.packages">
  76. @{{ package.logistic_number }}
  77. </template>
  78. </template>
  79. <template v-else>
  80. <p>@{{ item.order.packages[0].logistic_number }}</p>
  81. </template>
  82. <button class="btn btn-sm btn-outline-primary" v-show="selectOrder === null"
  83. @click="selectOrder = item.order.id">
  84. 展开
  85. </button>
  86. <button class="btn btn-sm btn-outline-primary"
  87. v-show="selectOrder === item.order.id"
  88. @click="selectOrder = null">
  89. 收起
  90. </button>
  91. </template>
  92. </template>
  93. </td>
  94. <td class="text-center">
  95. @can('订单管理-工单处理-审核')
  96. <select class="form-control form-control-sm"
  97. :disabled="item.review_at || item.is_issue_order"
  98. :value="item.order_issue_type_id"
  99. @change="changeIssueType(item,$event)" >
  100. <option value="0"></option>
  101. <option v-for="type in orderIssueTypes" :value="type.name">@{{ type.value }}</option>
  102. </select>
  103. @else
  104. @{{ item.issue_type ? item.issue_type.name : '' }}
  105. @endcan
  106. </td>
  107. <td class="text-center">@{{ item.remark }}</td>
  108. <td class="text-center">
  109. @{{ item.result_explain ?item.result_explain : '' }}
  110. </td>
  111. <td class="text-center">
  112. @{{ item.issue_order_type ?item.issue_order_type : '' }}
  113. </td>
  114. <td class="text-center p-0">
  115. <template v-if="item.issue_logs">
  116. <template v-if="item.issue_logs.length === 1">
  117. <table class="table table-sm m-0">
  118. <tr class="table table-sm">
  119. <td>@{{ item.issue_logs[0].content }}</td>
  120. <td>@{{ item.issue_logs[0].username }}</td>
  121. <td>@{{ item.issue_logs[0].created_at }}</td>
  122. </tr>
  123. </table>
  124. </template>
  125. <template v-else>
  126. <transition name="fade">
  127. <table class="table table-sm m-0" v-if="selectOrderIssue === item.id">
  128. <tr v-for="log in item.issue_logs">
  129. <td>@{{ log.content }}</td>
  130. <td>@{{ log.username }}</td>
  131. <td>@{{ log.created_at }}</td>
  132. </tr>
  133. </table>
  134. </transition>
  135. <transition name="fade">
  136. <table class="table table-sm m-0" v-if="selectOrderIssue !== item.id">
  137. <tr>
  138. <td>@{{ item.issue_logs[0].content }}</td>
  139. <td>@{{ item.issue_logs[0].username }}</td>
  140. <td>@{{ item.issue_logs[0].created_at }}</td>
  141. </tr>
  142. </table>
  143. </transition>
  144. <button class="btn btn-sm btn-outline-primary"
  145. v-show="selectOrderIssue !== item.id"
  146. @click="selectOrderIssue = item.id">展开
  147. </button>
  148. <button class="btn btn-sm btn-outline-primary" v-show="selectOrderIssue === item.id"
  149. @click="selectOrderIssue = null">收起
  150. </button>
  151. </template>
  152. </template>
  153. </td>
  154. <td class="text-center">
  155. <template v-if="item.review_at">
  156. <div v-if="item.order && item.order.packages">
  157. <template v-for="package in item.order.packages">
  158. <template
  159. v-if="package.transfer_status && package.transfer_status.length > 0">
  160. <div v-if="selectOrderPackage === package.id">
  161. <template v-for="transfer in package.transfer_status">
  162. <p>@{{
  163. transfer['accept_time']+':'+transfer['accept_address']
  164. }}</p>
  165. </template>
  166. </div>
  167. <div v-else>
  168. @{{
  169. package.transfer_status[0]['accept_time']+':'+package.transfer_status[0]['accept_address']
  170. }}
  171. </div>
  172. <button class="btn btn-sm btn-outline-primary"
  173. v-if="selectOrderPackage !== package.id"
  174. @click="selectOrderPackage = package.id">展开
  175. </button>
  176. <button class="btn btn-sm btn-outline-primary" v-else
  177. @click="selectOrderPackage = null">收起
  178. </button>
  179. </template>
  180. </template>
  181. </div>
  182. </template>
  183. </td>
  184. <td class="text-center">@{{ item.creator.name }}</td>
  185. <td class="text-center">@{{ item.created_at }}</td>
  186. <td>@{{ item.reviewer ? item.reviewer.name : ''}}</td>
  187. <td>@{{ item.review_at }}</td>
  188. </tr>
  189. </template>
  190. </tbody>
  191. </table>
  192. {{ $workOrders->withQueryString()->links() }}
  193. </div>
  194. </div>
  195. @can('订单管理-工单处理-审核')
  196. @include('order.workOrder._edit_issue_type')
  197. @endcan
  198. </div>
  199. </div>
  200. @endsection()
  201. @section("lastScript")
  202. <script type="text/javascript" src="{{asset('js/queryForm/queryForm.js')}}"></script>
  203. <script type="text/javascript" src="{{mix('js/queryForm/header.js')}}"></script>
  204. <style>
  205. .fade-enter-active, .fade-leave-active {
  206. transition: opacity .5s;
  207. }
  208. .fade-enter, .fade-leave-to {
  209. opacity: 0;
  210. }
  211. </style>
  212. <script>
  213. let list = new Vue({
  214. el: "#list",
  215. data: {
  216. workOrders: {!! $workOrders->toJson() !!}['data'],
  217. selectTr: null,
  218. form: null,
  219. logistics: [
  220. @foreach($logistics as $logistic)
  221. {
  222. name: {{$logistic->id}}, value: '{{$logistic->name}}'
  223. },
  224. @endforeach
  225. ],
  226. orderIssueTypes:[
  227. @foreach($orderIssueTypes as $type)
  228. {name:'{{$type->id}}',value:"{{$type->name}}"},
  229. @endforeach
  230. ],
  231. selectOrderPackage: null,
  232. selectOrder: null,
  233. selectOrderIssue:null,
  234. selectIssueType:'',
  235. },
  236. mounted() {
  237. let data = [[
  238. {name: 'created_at_start', type: 'time', tip: ['工单创建开始日期', '时间']},
  239. {name: 'created_at_end', type: 'time', tip: ['工单创建结束日期', '时间']},
  240. {
  241. name: 'logistic',
  242. type: 'select_multiple_select',
  243. data: this.logistics,
  244. tip: ['输入关键词快速定位下拉列表,回车确定', '选择要显示的承运商'],
  245. placeholder: ['承运商', '定位或多选承运商']
  246. },
  247. {name: 'logistic_number', type: 'input', placeholder: '快递单号'},
  248. {
  249. name: 'grad',
  250. type: 'select',
  251. placeholder: '工单等级',
  252. data: [{name: 1, value: '一般'}, {name: 2, value: '重要'}, {name: 3, value: '紧急'}, {
  253. name: 4,
  254. value: '重要且紧急'
  255. },]
  256. },
  257. {
  258. name: 'is_issue_order',
  259. type: 'select',
  260. placeholder: '问题件',
  261. data: [{name: 'true', value: '有'}, {name: 'false', value: '无'}]
  262. },
  263. {name:'creator',type:'input',placeholder:'创建人'},
  264. ], [{name: 'review_at_start', type: 'time', tip: ['工单审核开始日期', '时间']},
  265. {name: 'review_at_end', type: 'time', tip: ['工单审核结束日期', '时间']},
  266. {name:'order_issue_type',type:'select',placeholder:'问题件类型',data:this.orderIssueTypes},
  267. {name: 'is_review', type: 'checkbox', tip: '是否审核', data: [{name: 'true', value: '已审核'}]},
  268. ]];
  269. this.form = new query({
  270. el: '#form_div',
  271. condition: data,
  272. });
  273. this.form.init();
  274. let column = [
  275. {name: 'no', value: '序号', neglect: true},
  276. {name: 'operation', value: '操作', neglect: true},
  277. {name: 'status', value: '状态'},
  278. {name: 'logisticName', value: '承运商'},
  279. {name: 'logisticNumber', value: '快递单号'},
  280. {name: 'issueType', value: '问题件类型'},
  281. {name: 'workOrderInfo', value: '问题描述'},
  282. {name:'result_explain',value:'情况说明'},
  283. {name:'orderIssueType',value:'问题件类别'},
  284. {name:'orderIssueProcessLogs',type:'multi',title:"处理结果",rows:[
  285. {value:"内容",col:"4"},
  286. {value:"操作人",col:"4"},
  287. {value:"时间",col:"4"},
  288. ]},
  289. {name: 'Info', value: '物流跟踪信息', neglect: true},
  290. {name: 'creator', value: '创建人'},
  291. {name: 'submit_at', value: '提交时间'},
  292. {name: 'reviewer', value: '审核人'},
  293. {name: 'review_at', value: '审核时间'},
  294. ];
  295. new Header({
  296. el: "table",
  297. name: "workOrders",
  298. column: column,
  299. data: this.workOrders,
  300. fixedTop:($('#form_div').height())+2,
  301. }).init();
  302. $("#list").removeClass("d-none");
  303. },
  304. created() {
  305. let self = this;
  306. $.each(this.workOrders, function (index, workOrder) {
  307. if (!workOrder.order) return;
  308. if (!workOrder.order.packages) return;
  309. self.sortOrder(workOrder);
  310. });
  311. },
  312. methods: {
  313. sortOrder(workOrder) {
  314. let self = this;
  315. if (!workOrder.order) return;
  316. if (workOrder.order_issue){
  317. workOrder.result_explain = workOrder.order_issue.result_explain;
  318. if (workOrder.order_issue.issue_type){
  319. workOrder.issue_order_type = workOrder.order_issue.issue_type.name;
  320. }
  321. if (workOrder.order_issue.logs){
  322. workOrder.issue_logs = workOrder.order_issue.logs.map(item=>{
  323. return {
  324. username : item.user ? item.user.name : '',
  325. content: item.content,
  326. created_at : item.created_at
  327. };
  328. });
  329. }
  330. }
  331. if (!workOrder.order.packages) return;
  332. $.each(workOrder.order.packages, function (i, item) {
  333. self.sortTransfer(item);
  334. })
  335. },
  336. sortTransfer(item) {
  337. if (!("transfer_status" in item)) return;
  338. if (item.transfer_status == null || !(item.transfer_status instanceof Array)) return;
  339. item.transfer_status.sort(function (item1, item2) {
  340. let date1 = new Date(item1['accept_time']);
  341. let date2 = new Date(item2['accept_time']);
  342. if (date1 - date2 > 0) return -1;
  343. if (date1 - date2 < 0) return 1;
  344. return 0;
  345. });
  346. },
  347. review(item, i) {
  348. let url = '{{route('workOrder.reviewApi')}}';
  349. let data = {id: item.id};
  350. window.axios.post(url, data).then(res => {
  351. if (res.data.success) {
  352. res.data.data.is_issue_order = item.is_issue_order;
  353. this.$set(this.workOrders, i, res.data.data);
  354. this.sortOrder(res.data.data);
  355. window.tempTip.showSuccess("审核完成");
  356. } else {
  357. window.tempTip.show(res.data.message ? res.data.message : '审核异常');
  358. }
  359. }).catch(err => {
  360. window.tempTip.show(err)
  361. })
  362. },
  363. createOrderIssue(item, tag) { // 生成问题件
  364. let url = '{{route('workOrder.buildOrderIssueApi')}}';
  365. let data = {};
  366. if (tag) data.ids = [item.id];
  367. else data.ids = checkData;
  368. if (!confirm('是否生成对应的问题件')) return;
  369. let _this =this;
  370. window.axios.post(url, data).then(res => {
  371. if (res.data.success) {
  372. res.data.data.forEach(item=>{
  373. this.workOrders.forEach((workOrder,i)=>{
  374. if (item.id === workOrder.id){
  375. _this.sortOrder(item);
  376. _this.$set(_this.workOrders,i,item);
  377. }
  378. });
  379. });
  380. this.$forceUpdate();
  381. window.tempTip.showSuccess('已生成对应的问题件');
  382. } else {
  383. window.tempTip.show(res.data.message ? res.data.message : '生成问题件异常');
  384. }
  385. }).catch(err => {
  386. window.tempTip.show(err)
  387. });
  388. },
  389. getMessageWorkOrder() {
  390. let selected = checkData;
  391. if (!selected) {
  392. window.tempTip.show('未选中任何信息');
  393. return null;
  394. }
  395. return this.workOrders.filter((item) => {
  396. if (!item.order) return false;
  397. if (!item.order.packages) return false;
  398. return selected.includes(item.id + '');
  399. });
  400. },
  401. exportText(){
  402. let items = this.getMessageWorkOrder();
  403. if (items == null) return ;
  404. let text = '';
  405. items.forEach(item=>{
  406. if (item.order) text += this.getExportText(item);
  407. });
  408. this.copyText(text);
  409. },
  410. getExportText(item){
  411. if (!item.order) return '';
  412. if (!item.order.packages) return '';
  413. let message = '';
  414. switch (item.issue_order_type){
  415. case '拦截':
  416. message = this.interceptMessage(item);
  417. break;
  418. case '信息更改':
  419. message = this.modificationMessage(item);
  420. break;
  421. default:
  422. message = this.getMessage(item);
  423. break;
  424. }
  425. return message;
  426. },
  427. interceptMessage(item) {
  428. let message = '';
  429. if (item.order.logistic.code.includes('SF') || item.order.logistic.code.includes('ZTO')) {
  430. item.order.packages.forEach(node => {
  431. message += node.logistic_number + '\n';
  432. });
  433. message = message.trim('\n') + ' ——拦截\n';
  434. } else {
  435. let item_order_logistic_name = item.order.logistic.name;
  436. let item_order_adder = item.order.consignee_name + ' '
  437. + item.order.consignee_phone + ' '
  438. + ' ' + item.order.address;
  439. item.order.packages.forEach(p => {
  440. if (p) message += item_order_logistic_name + ' ' + p.logistic_number + ' ' + item_order_adder + '\n';
  441. });
  442. message = message.trim('\n') + ' ——拦截\n';
  443. }
  444. return message;
  445. },
  446. modificationMessage(item) {
  447. let message = '';
  448. let logistic_code = item.order.logistic.code;
  449. let adder = item.order.consignee_name + ' ' + item.order.consignee_phone + ' '
  450. + item.order.province + ' ' + item.order.city + ' ' + item.order.district + ' ' + item.order.address;
  451. item.order.packages.forEach(node => {
  452. if (logistic_code.includes('SF')) { // 顺丰订单
  453. message += node.logistic_number + ' ——改信息: ' + item.remark + ',运费到付或月结' + '\n';
  454. } else if (logistic_code.includes('ZTO')) {
  455. message += node.logistic_number + ' ——改信息:' + item.remark + '\n';
  456. } else {
  457. message += node.logistic_number + ' ' + adder + ' ——改地址' + item.remark + '\n';
  458. }
  459. });
  460. return message;
  461. },
  462. getMessage(item){
  463. let message = '';
  464. if (!item.order.packages) return message;
  465. let adder = item.order.consignee_name + ' ' + item.order.consignee_phone + ' '
  466. + item.order.province + ' ' + item.order.city + ' ' + item.order.district + ' ' + item.order.address;
  467. item.order.packages.forEach(p=>{
  468. message+= p.logistic_number + ' '+ adder + ' ——描述 '+item.remark+'\n';
  469. });
  470. return message;
  471. },
  472. copyText(text) {
  473. let ele = document.querySelector('#copy_text');
  474. if (ele == null) {
  475. ele = document.createElement("textarea");
  476. ele.setAttribute('id', 'copy_text')
  477. ele.style.opacity = 0;
  478. document.querySelector('body').append(ele);
  479. }
  480. try {
  481. $("#copy_text").text(text).select().focus();
  482. document.execCommand("Copy");
  483. tempTip.showSuccess('复制成功')
  484. } catch (e) {
  485. tempTip.showSuccess('复制失败:' + e)
  486. }
  487. },
  488. batchReview() {
  489. let url = '{{route('workOrder.batchReviewApi')}}';
  490. let data = {ids: checkData};
  491. let _this = this;
  492. window.tempTip.setIndex('1999');
  493. if (!confirm('是否对当前选中订单进行审核')) return;
  494. window.axios.post(url, data).then(res => {
  495. if (res.data.success) {
  496. $.each(res.data.data, (i, data) => {
  497. $.each(_this.workOrders, (index, item) => {
  498. if (item.id === data.id) {
  499. _this.$set(this.workOrders, index, data);
  500. }
  501. });
  502. });
  503. this.$forceUpdate();
  504. window.tempTip.showSuccess('审核完成');
  505. } else {
  506. window.tempTip.show(res.data.message ? res.data.message : '审核出现异常');
  507. }
  508. }).catch(err => {
  509. window.tempTip.show(err);
  510. })
  511. },
  512. changeIssueType(item,e){
  513. let url = '{{route('workOrder.updateIssueTypeApi')}}';
  514. let data = {
  515. id:item.id,
  516. type_id: $(e.target).val()
  517. };
  518. window.axios.post(url,data).then(res=>{
  519. if (res.data.success){
  520. window.tempTip.showSuccess('修改成功');
  521. item.order_issue_type_id = data.type_id;
  522. }else{
  523. window.tempTip.show(res.data.message ? res.data.message : '修改异常');
  524. }
  525. }).catch(err=>{
  526. window.tempTip.show(err);
  527. });
  528. },
  529. copyLogisticNumber() {
  530. let items = this.getMessageWorkOrder();
  531. let logistic_numbers = '';
  532. items.forEach(item=>{
  533. item.order.packages.forEach(node => {
  534. logistic_numbers += node.logistic_number + '\n';
  535. });
  536. })
  537. this.copyText(logistic_numbers);
  538. },
  539. showEditIssueType(){
  540. this.selectIssueType = 0;
  541. $("#edit-issue-type-type-modal").modal('show');
  542. },
  543. editOrderIssueType(){
  544. let url = '{{route('workOrder.batchUpdateIssueTypeApi')}}'
  545. let data = {ids:checkData,type:this.selectIssueType};
  546. let _this = this;
  547. window.tempTip.setIndex(1999);
  548. window.axios.post(url,data).then(res=>{
  549. if (res.data.success){
  550. window.tempTip.showSuccess('修改问题件类型成功');
  551. res.data.data.forEach(item=>{
  552. _this.sortOrder(item);
  553. _this.workOrders.forEach((workOrder,i,array)=>{
  554. if (workOrder.id === item.id){
  555. array[i] = item;
  556. }
  557. })
  558. });
  559. this.$forceUpdate();
  560. $("#edit-issue-type-type-modal").modal('hide');
  561. return;
  562. }
  563. window.tempTip.show(res.data.message ? res.data.message : '修改异常');
  564. }).catch(err=>{
  565. window.tempTip.show(err)
  566. })
  567. },
  568. },
  569. });
  570. </script>
  571. @endsection