index.blade.php 67 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122
  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. <button type="button"
  11. class="ml-1 btn btn-outline-dark btn-sm form-control-sm tooltipTarget"
  12. @click="createOrderIssue(null,false)" style="background: #dad7e8;">生成问题件
  13. </button>
  14. @endcan
  15. @can('订单管理-订单问题件生成')
  16. <button type="button"
  17. class="ml-1 btn btn-outline-primary btn-sm form-control-sm tooltipTarget"
  18. @click="exportText()">导出文本
  19. </button>
  20. @endcan
  21. @can('订单管理-工单处理-审核')
  22. <button type="button"
  23. class="ml-1 btn btn-outline-success btn-sm form-control-sm tooltipTarget"
  24. @click="batchReview">批量审核
  25. </button>
  26. @endcan
  27. <button type="button"
  28. class="ml-1 btn btn-outline-dark btn-sm form-control-sm tooltipTarget"
  29. @click="copyLogisticNumber()" style="background: #dad7e8;">批量复制单号
  30. </button>
  31. @can('订单管理-工单处理-审核')
  32. <button type="button"
  33. class="ml-1 btn btn-outline-success btn-sm form-control-sm tooltipTarget"
  34. @click="showEditIssueType">批量修改问题件类型
  35. </button>
  36. @endcan
  37. </div>
  38. <div>
  39. <table class="table table-sm table-striped table-hover table-bordered td-min-width-80" id="table">
  40. <tbody class="">
  41. <template v-for="(item,i) in workOrders">
  42. <tr @click="selectTr===i+1?selectTr=0:selectTr=i+1" :class="selectTr===i+1?'focusing' : ''">
  43. <td>
  44. <label><input type="checkbox" :value="item.id"></label>
  45. </td>
  46. <td class="text-center">
  47. <span v-text="i+1"></span>
  48. <span v-show="item.is_issue_order" class="badge badge-primary">问题件</span>
  49. </td>
  50. <td class="text-left">
  51. @can('订单管理-订单问题件生成')
  52. <button class="btn btn-sm btn-outline-primary"
  53. v-show="!item.is_issue_order "
  54. @click="createOrderIssue(item,true)">生成问题件
  55. </button>
  56. @endcan
  57. @can('订单管理-工单处理-审核')
  58. <button class="btn btn-sm btn-outline-success"
  59. v-show="item.status !== '已处理'"
  60. @click="review(item,i)">审核
  61. </button>
  62. @endcan
  63. @can('订单管理-工单处理-货主编辑')
  64. <button class="btn btn-sm btn-outline-secondary"
  65. v-if="item['issue_type']['name'] ==='快递丢件'"
  66. @click="showFillModel(item,i)">信息填充
  67. </button>
  68. @endcan
  69. @can('订单管理-工单处理-承运商编辑')
  70. <button class="btn btn-sm btn-outline-secondary"
  71. v-if="['快递丢件','破损'].includes(item['issue_type']['name'])"
  72. @click="showEditLog(item,i,2)">快递处理
  73. </button>
  74. @endcan
  75. @can('订单管理-工单处理-宝时编辑')
  76. <button class="btn btn-sm btn-outline-secondary"
  77. v-if="['快递丢件','破损'].includes(item['issue_type']['name'])"
  78. @click="showEditLog(item,i,1)">宝时处理
  79. </button>
  80. @endcan
  81. </td>
  82. <td class="text-center">
  83. @can('订单管理-工单处理-宝时编辑')
  84. <select class="form-control form-control-sm"
  85. :value="item['work_order_status']"
  86. :disabled="item['work_order_status'] === '工单完成'"
  87. @change="updateWorkOrderStatus(item,$event)">
  88. <option value="">无</option>
  89. <option :value="status" v-for="status in workOrderStatus"
  90. v-text="status"></option>
  91. </select>
  92. @else
  93. @{{ item.work_order_status }}
  94. @endcan
  95. </td>
  96. <td class="text-center">@{{ item.status }}</td>
  97. <td class="text-center">@{{ item.owner ? item.owner.name : '' }}</td>
  98. <td class="text-center">@{{ item.order ? item.order.client_code : ''}}</td>
  99. <td>@{{item.order ? (item.order.logistic ? item.order.logistic.name : '') : '' }}</td>
  100. <td class="text-center">
  101. <div v-if="item.order">
  102. <p v-if="item.order.packages && item.order.packages.length === 1"
  103. v-text="item.order.packages[0].logistic_number">
  104. </p>
  105. <div v-else-if="item.order.packages && item.order.packages.length > 0">
  106. <div v-if="selectOrder === item.order.id">
  107. <p v-for="(package,index) in item.order.packages"
  108. v-text="package.logistic_number"></p>
  109. </div>
  110. <div v-else>
  111. <p v-text="item.order.packages[0].logistic_number"></p>
  112. </div>
  113. <button class="btn btn-sm btn-outline-primary"
  114. v-show="selectOrder === null"
  115. @click="selectOrder = item.order.id">展开
  116. </button>
  117. <button class="btn btn-sm btn-outline-primary"
  118. v-show="selectOrder === item.order.id"
  119. @click="selectOrder = null">收起
  120. </button>
  121. </div>
  122. </div>
  123. </td>
  124. <td>
  125. {{-- 承运商处理日志 --}}
  126. <div v-if="item['logistic_log']" class="alert alert-light">
  127. <div>
  128. <span class="text-muted">承运商处理</span>
  129. <button class="btn btn-sm btn-outline-info float-right"
  130. v-show="selectLogisticLogId === item['logistic_log']['id']"
  131. @click="selectLogisticLogId = null">隐藏
  132. </button>
  133. <button class="btn btn-sm btn-outline-info float-right"
  134. v-show="selectLogisticLogId !== item['logistic_log']['id']"
  135. @click="selectLogisticLogId = item['logistic_log']['id']">显示
  136. </button>
  137. </div>
  138. <transition name="fade">
  139. <div v-show="selectLogisticLogId === item['logistic_log']['id']">
  140. <div>
  141. <span class="mr-2">是否赔偿:</span>
  142. <span class="text-truncate"
  143. v-text="item['logistic_log']['is_indemnity']"></span>
  144. </div>
  145. <div v-if="item['logistic_log']['is_indemnity'] === '是'">
  146. <span class="mr-2">赔偿金额:</span>
  147. <span class="text-truncate"
  148. v-text="item['logistic_log']['indemnity']"></span>
  149. </div>
  150. <div v-if="item['logistic_log']['is_indemnity'] === '否'">
  151. <span class="mr-2">不赔偿理由:</span>
  152. <span v-text="item['logistic_log']['remark']"></span>
  153. </div>
  154. </div>
  155. </transition>
  156. </div>
  157. <div v-if="item['process_log']" class="alert alert-light">
  158. <div>
  159. <span class="text-muted">宝时处理</span>
  160. <button class="btn btn-sm btn-outline-info float-right"
  161. v-if="selectBaoShiLogId === item['process_log']['id']"
  162. @click="selectBaoShiLogId = null">隐藏
  163. </button>
  164. <button class="btn btn-sm btn-outline-info float-right"
  165. v-if="selectBaoShiLogId !== item['process_log']['id']"
  166. @click="selectBaoShiLogId = item['process_log']['id']">显示
  167. </button>
  168. </div>
  169. <transition name="fade">
  170. <div v-show="selectBaoShiLogId === item['process_log']['id']">
  171. <div>
  172. <span class="text-muted">是否赔偿: </span>
  173. <span v-text="item['process_log']['is_indemnity']"
  174. class="ml-2 text-truncate"></span></div>
  175. <div v-if="item['process_log']['is_indemnity'] === '是'">
  176. <span class="text-muted">赔偿方:</span>
  177. <span class="text-truncate"
  178. v-text="item['process_log']['indemnitor']"></span>
  179. </div>
  180. <div v-if="item['process_log']['is_indemnity'] === '是'">
  181. <span class="text-muted">赔偿金额:</span>
  182. <span class="ml-2 text-truncate"
  183. v-text="item['process_log']['indemnity']"></span>
  184. </div>
  185. <div v-if="item['process_log']['is_indemnity'] === '否'">
  186. <span class="text-muted">不赔偿理由:</span>
  187. <span class="ml-2" v-text=" item['process_log']['remark']"></span>
  188. </div>
  189. </div>
  190. </transition>
  191. </div>
  192. </td>
  193. <td>
  194. {{-- 工单详情 --}}
  195. <div v-if="item.details.length > 0" class="alert alert-light mb-0">
  196. <div class="header-alert">
  197. <span class="text-monospace">工单详情</span>
  198. <button type="button" class="btn btn-sm btn-outline-primary float-right"
  199. v-show="selectDetailId !== item.id"
  200. @click="selectDetailId = item.id">显示
  201. </button>
  202. <button type="button" class="btn btn-sm btn-outline-primary float-right"
  203. v-show="selectDetailId === item.id"
  204. @click="selectDetailId = null">隐藏
  205. </button>
  206. </div>
  207. <transition name="fade">
  208. <div class="body-alert" v-if="selectDetailId === item.id">
  209. <div class="card-body row col-12 mb-0 pb-0"
  210. v-for="(detail,i) in item.details">
  211. {{-- 快递丢件工单详情 --}}
  212. <div v-if="item['issue_type']['name'] === '快递丢件'">
  213. <div v-if="detail.logistic_number">
  214. <span class="mr-3">丢件快递单号:</span>
  215. <span class="text-truncate"
  216. v-text="detail.logistic_number"></span>
  217. </div>
  218. <div>
  219. <span class="mr-3">丢件价值:</span>
  220. <span class="text-truncate"
  221. v-text="detail.price"></span>
  222. </div>
  223. {{-- 工单登记商品详情 --}}
  224. <div v-for="(item,i) in item.commodities">
  225. <span class="mr-2">sku</span>
  226. <span v-text="item.sku"></span>
  227. <span class="mr-2">商品名</span>
  228. <span
  229. v-text="item.commodity ? item.commodity.name : ''"></span>
  230. <span class="mr-2">数量</span>
  231. <span v-text="item.amount"></span>
  232. </div>
  233. </div>
  234. {{-- 破损工单详情 --}}
  235. <div v-if="item['issue_type']['name'] === '破损'">
  236. <div>
  237. <div>
  238. <span class="mr-3">破损sku数:</span>
  239. <span class="text-truncate"
  240. v-text="detail.sku_amount"></span>
  241. </div>
  242. <div>
  243. <span class="mr-3">快递单号:</span>
  244. <span class="text-truncate"
  245. v-text="detail.logistic_number"></span>
  246. </div>
  247. <div>
  248. <span class="mr-3">破损商品价值:</span>
  249. <span v-text="detail.price"></span>
  250. </div>
  251. </div>
  252. </div>
  253. {{-- 交易截图 --}}
  254. <div class="row"
  255. v-if="item['deal_images'] && item['deal_images'].length > 0">
  256. <div class="col-12">
  257. <hr>
  258. <span class="text-monospace" v-text="'交易截图'"></span>
  259. </div>
  260. <div class="card-body col-sm-6"
  261. v-for="(dealImage,i) in item['deal_images']">
  262. <div class="">
  263. <a target="_blank"
  264. :href="filePrefix+dealImage.upload_file.url + '.'+dealImage.upload_file.type">
  265. <img class="image-w"
  266. :src="filePrefix+dealImage.upload_file.url + '.'+dealImage.upload_file.type"
  267. alt="交易截图">
  268. </a>
  269. </div>
  270. </div>
  271. </div>
  272. {{-- 退款截图 --}}
  273. <div class="row"
  274. v-if="item['refund_image'] && item['refund_image'].length > 0">
  275. <div class="col-12">
  276. <hr>
  277. <span class="text-monospace" v-text="'退款截图'"></span>
  278. </div>
  279. <div class="card-body col-sm-6"
  280. v-for="(refundImage,i) in item['refund_images']">
  281. <a target="_blank"
  282. :href="filePrefix+refundImage.upload_file.url + '.'+refundImage.upload_file.type">
  283. <img class="image-w"
  284. :src="filePrefix+refundImage.upload_file.url + '.'+refundImage.upload_file.type"
  285. alt="退款截图">
  286. </a>
  287. </div>
  288. </div>
  289. {{-- 外包装截图 --}}
  290. <div class="row"
  291. v-if="item['package_images'] && item['package_images'].length > 0">
  292. <div class="col-12">
  293. <hr>
  294. <span class="text-monospace" v-text="'外包装截图'"></span>
  295. </div>
  296. <div class="card-body col-sm-6"
  297. v-for="(packageImage,i) in item['package_images']">
  298. <a target="_blank"
  299. :href="filePrefix+packageImage.upload_file.url + '.'+packageImage.upload_file.type">
  300. <img class="image-w"
  301. :src="filePrefix+packageImage.upload_file.url + '.'+packageImage.upload_file.type"
  302. alt="外包装截图">
  303. </a>
  304. </div>
  305. </div>
  306. {{-- 内物破损图片 --}}
  307. <div class="row"
  308. v-if="item['commodity_images'] && item['commodity_images'].length > 0">
  309. <div class="col-12">
  310. <hr>
  311. <span class="text-monospace" v-text="'内物破损图片'"></span>
  312. </div>
  313. <div class="card-body col-sm-6"
  314. v-for="(commodityImage,i) in item['commodity_images']">
  315. <a target="_blank"
  316. :href="filePrefix+commodityImage.upload_file.url + '.'+commodityImage.upload_file.type">
  317. <img class="image-w"
  318. :src="filePrefix+commodityImage.upload_file.url + '.'+commodityImage.upload_file.type"
  319. alt="内物破损图片">
  320. </a>
  321. </div>
  322. </div>
  323. </div>
  324. {{-- 破损商品详情 --}}
  325. <div class="row"
  326. v-if="item['issue_type']['name'] === '破损'">
  327. <div class="col-12">
  328. <hr>
  329. <div class="text-monospace">破损商品详情</div>
  330. </div>
  331. <div class="card-body col-12"
  332. v-for="(commodity,i) in item.commodities">
  333. <div>
  334. <span class="mr-3">SKU:</span>
  335. <span class="text-truncate" v-text="commodity.sku"></span>
  336. </div>
  337. <div>
  338. <span class="mr-3">商品名称:</span>
  339. <span class="text-truncate"
  340. v-text="commodity.commodity ? commodity.commodity.name : '' "></span>
  341. </div>
  342. <div>
  343. <span class="mr-3">数量:</span>
  344. <span class="text-truncate"
  345. v-text="commodity.amount"></span>
  346. </div>
  347. </div>
  348. </div>
  349. </div>
  350. </transition>
  351. </div>
  352. </td>
  353. <td class="text-center">
  354. @can('订单管理-工单处理-审核')
  355. <select class="form-control form-control-sm"
  356. :disabled="item.review_at || item.is_issue_order"
  357. :value="item.order_issue_type_id"
  358. @change="changeIssueType(item,$event)">
  359. <option value="0"></option>
  360. <option v-for="type in orderIssueTypes" :value="type.name">@{{ type.value
  361. }}
  362. </option>
  363. </select>
  364. @else
  365. @{{ item.issue_type ? item.issue_type.name : '' }}
  366. @endcan
  367. </td>
  368. <td class="text-center">@{{ item.remark }}</td>
  369. <td class="text-center">
  370. @{{ item.result_explain ?item.result_explain : '' }}
  371. </td>
  372. <td class="text-center">
  373. @{{ item.issue_order_type ?item.issue_order_type : '' }}
  374. </td>
  375. <td class="text-center p-0">
  376. <template v-if="item.issue_logs">
  377. <template v-if="item.issue_logs.length === 1">
  378. <table class="table table-sm m-0">
  379. <tr class="table table-sm">
  380. <td>@{{ item.issue_logs[0].content }}</td>
  381. <td>@{{ item.issue_logs[0].username }}</td>
  382. <td>@{{ item.issue_logs[0].created_at | dataTime}}</td>
  383. </tr>
  384. </table>
  385. </template>
  386. <template v-else>
  387. <transition name="fade">
  388. <table class="table table-sm m-0" v-if="selectOrderIssue === item.id">
  389. <tr v-for="log in item.issue_logs">
  390. <td>@{{ log.content }}</td>
  391. <td>@{{ log.username }}</td>
  392. <td>@{{ log.created_at | dataTime}}</td>
  393. </tr>
  394. </table>
  395. </transition>
  396. <transition name="fade">
  397. <table class="table table-sm m-0" v-if="selectOrderIssue !== item.id">
  398. <tr>
  399. <td>@{{ item.issue_logs[0].content }}</td>
  400. <td>@{{ item.issue_logs[0].username }}</td>
  401. <td>@{{ item.issue_logs[0].created_at | dataTime}}</td>
  402. </tr>
  403. </table>
  404. </transition>
  405. <button class="btn btn-sm btn-outline-primary"
  406. v-show="selectOrderIssue !== item.id"
  407. @click="selectOrderIssue = item.id">展开
  408. </button>
  409. <button class="btn btn-sm btn-outline-primary"
  410. v-show="selectOrderIssue === item.id"
  411. @click="selectOrderIssue = null">收起
  412. </button>
  413. </template>
  414. </template>
  415. </td>
  416. <td class="text-center">
  417. <template v-if="item.review_at">
  418. <div v-if="item.order && item.order.packages">
  419. <template v-for="package in item.order.packages">
  420. <template
  421. v-if="package.transfer_status && package.transfer_status.length > 0">
  422. <div v-if="selectOrderPackage === package.id">
  423. <template v-for="transfer in package.transfer_status">
  424. <p>@{{
  425. transfer['accept_time']+':'+transfer['accept_address']
  426. }}</p>
  427. </template>
  428. </div>
  429. <div v-else>
  430. @{{
  431. package.transfer_status[0]['accept_time']+':'+package.transfer_status[0]['accept_address']
  432. }}
  433. </div>
  434. <button class="btn btn-sm btn-outline-primary"
  435. v-if="selectOrderPackage !== package.id"
  436. @click="selectOrderPackage = package.id">展开
  437. </button>
  438. <button class="btn btn-sm btn-outline-primary" v-else
  439. @click="selectOrderPackage = null">收起
  440. </button>
  441. </template>
  442. </template>
  443. </div>
  444. </template>
  445. </td>
  446. <td class="text-center">@{{ item.creator ? item.creator.name : '' }}</td>
  447. <td class="text-center">@{{ item.created_at | dataTime}}</td>
  448. <td>@{{ item.reviewer ? item.reviewer.name : ''}}</td>
  449. <td>@{{ item.review_at |dataTime}}</td>
  450. @can('订单管理-工单处理-删除')
  451. <td>
  452. <button class="btn btn-sm btn-outline-danger"
  453. @click="destroy(item,i)">
  454. 删除
  455. </button>
  456. </td>
  457. @endcan
  458. </tr>
  459. </template>
  460. </tbody>
  461. </table>
  462. {{ $workOrders->withQueryString()->links() }}
  463. </div>
  464. </div>
  465. @can('订单管理-工单处理-审核')
  466. @include('order.workOrder._edit_issue_type')
  467. @endcan
  468. @include('order.workOrder._fill_loss_work_order')
  469. @include('order.workOrder._edit_process_log')
  470. </div>
  471. </div>
  472. @endsection()
  473. @section("lastScript")
  474. <script type="text/javascript" src="{{asset('js/queryForm/queryForm.js')}}"></script>
  475. <script type="text/javascript" src="{{mix('js/queryForm/header.js')}}"></script>
  476. <style>
  477. .fade-enter-active, .fade-leave-active {
  478. transition: opacity .3s;
  479. }
  480. .fade-enter, .fade-leave-to {
  481. opacity: 0;
  482. }
  483. .image-div {
  484. }
  485. .image-w {
  486. width: 100%;
  487. }
  488. </style>
  489. <script>
  490. let list = new Vue({
  491. el: "#list",
  492. data: {
  493. workOrders: {!! $workOrders->toJson() !!}['data'],
  494. form: null,
  495. logistics: [
  496. @foreach($logistics as $logistic)
  497. {
  498. name: {{$logistic->id}}, value: '{{$logistic->name}}'
  499. },
  500. @endforeach
  501. ],
  502. orderIssueTypes: [
  503. @foreach($orderIssueTypes as $type)
  504. {
  505. name: '{{$type->id}}', value: "{{$type->name}}"
  506. },
  507. @endforeach
  508. ],
  509. owners: [
  510. @foreach($owners as $owner)
  511. {
  512. name: '{{$owner->id}}', value: '{{$owner->name}}'
  513. },
  514. @endforeach
  515. ],
  516. workOrder: {
  517. id: null,
  518. index: null,
  519. reissue_logistic_number: null, // 补发单号
  520. logistic_number: null, // 丢件快递单号
  521. refundImages: [], // 退款图
  522. dealImages: [], // 交易图
  523. },
  524. processLog: {
  525. id: null, // log->id
  526. index: '', // 下标
  527. work_order_id: null, // work_order_id
  528. type: null, // 类型
  529. is_indemnity: null, // 是否赔偿
  530. indemnity: null, // 金额
  531. remark: null,
  532. indemnitor: null, // 赔偿方
  533. },
  534. workOrderStatus: ['信息未填写', '信息已填写', '快递已处理', '工单完成'],
  535. selectTr: null,
  536. selectOrderPackage: null,
  537. selectOrder: null,
  538. selectLogisticLogId: null,
  539. selectBaoShiLogId: null,
  540. selectDetailId: null,
  541. selectOrderIssue: null,
  542. selectIssueType: '',
  543. filePrefix: "{{asset("/storage")}}",
  544. },
  545. mounted() {
  546. let data = [[
  547. {name: 'created_at_start', type: 'time', tip: ['工单创建开始日期', '时间']},
  548. {name: 'created_at_end', type: 'time', tip: ['工单创建结束日期', '时间']},
  549. {
  550. name: 'logistic',
  551. type: 'select_multiple_select',
  552. data: this.logistics,
  553. tip: ['输入关键词快速定位下拉列表,回车确定', '选择要显示的承运商'],
  554. placeholder: ['承运商', '定位或多选承运商']
  555. },
  556. @can('订单管理-订单问题件生成')
  557. {
  558. name: 'owner',
  559. type: 'select_multiple_select',
  560. data: this.owners,
  561. tip: ['输入关键词快速定位下拉列表,回车确定', '选择要显示的货主'],
  562. placeholder: ['货主', '定位或多选货主']
  563. },
  564. @endcan
  565. {
  566. name: 'logistic_number', type: 'input', placeholder: '快递单号'
  567. },
  568. {
  569. name: 'is_issue_order',
  570. type: 'select',
  571. placeholder: '问题件',
  572. data: [{name: 'true', value: '有'}, {name: 'false', value: '无'}]
  573. },
  574. {name: 'creator', type: 'input', placeholder: '创建人'},
  575. ], [{name: 'review_at_start', type: 'time', tip: ['工单审核开始日期', '时间']},
  576. {name: 'review_at_end', type: 'time', tip: ['工单审核结束日期', '时间']},
  577. {name: 'order_issue_type', type: 'select', placeholder: '问题件类型', data: this.orderIssueTypes},
  578. {name: 'client_code', type: 'input', placeholder: '客户订单号'},
  579. {name: 'is_review', type: 'checkbox', tip: '是否审核', data: [{name: 'true', value: '已审核'}]},
  580. ]];
  581. this.form = new query({
  582. el: '#form_div',
  583. condition: data,
  584. });
  585. // this.form.init();
  586. let column = [
  587. {name: 'no', value: '序号', neglect: true},
  588. {name: 'operation', value: '操作', neglect: true},
  589. {name: 'work_order_status', value: '工单状态', neglect: true},
  590. {name: 'status', value: '状态', neglect: true},
  591. {name: 'owner', value: '货主', neglect: true},
  592. {name: 'client_code', value: '订单号', neglect: true},
  593. {name: 'logisticName', value: '承运商', neglect: true},
  594. {name: 'logisticNumber', value: '快递单号'},
  595. {name: 'processLog', value: '处理日志'},
  596. {name: 'workOrderDetails', value: '工单详情'},
  597. {name: 'issueType', value: '问题件类型'},
  598. {name: 'workOrderInfo', value: '问题描述', neglect: true},
  599. {name: 'result_explain', value: '情况说明', neglect: true},
  600. {name: 'orderIssueType', value: '问题件类别'},
  601. {
  602. name: 'orderIssueProcessLogs', type: 'multi', title: "处理结果", rows: [
  603. {value: "内容", col: "4"},
  604. {value: "操作人", col: "4"},
  605. {value: "时间", col: "4"},
  606. ], neglect: true
  607. },
  608. {name: 'Info', value: '物流跟踪信息', neglect: true},
  609. {name: 'creator', value: '创建人', neglect: true},
  610. {name: 'submit_at', value: '提交时间', neglect: true},
  611. {name: 'reviewer', value: '审核人', neglect: true},
  612. {name: 'review_at', value: '审核时间', neglect: true},
  613. @can('订单管理-工单处理-删除')
  614. {
  615. name: 'delete_operation', value: '其他操作', neglect: true
  616. },
  617. @endcan()
  618. ];
  619. new Header({
  620. el: "table",
  621. name: "workOrders",
  622. column: column,
  623. data: this.workOrders,
  624. fixedTop: ($('#form_div').height()) + 2,
  625. }).init();
  626. $("#list").removeClass("d-none");
  627. },
  628. created() {
  629. this.workOrders.forEach(item => {
  630. if (!item.order) return;
  631. if (!item.order.packages) return;
  632. this.sortOrder(item);
  633. });
  634. },
  635. filters: {
  636. dataTime: function (value) {
  637. if (value !== null) {
  638. return moment(value).format('yyyy-MM-DD');
  639. }
  640. return value
  641. },
  642. },
  643. methods: {
  644. sortOrder(workOrder) {
  645. if (!workOrder.order) return;
  646. if (workOrder['order_issue']) {
  647. workOrder.result_explain = workOrder['order_issue'].result_explain;
  648. if (workOrder['order_issue']['issue_type']) {
  649. workOrder.issue_order_type = workOrder['order_issue']['issue_type']['name'];
  650. }
  651. if (workOrder['order_issue'].logs) {
  652. workOrder.issue_logs = this.mapLogs(workOrder['order_issue'].logs);
  653. }
  654. }
  655. if (!workOrder.order.packages) return;
  656. workOrder.order.packages.forEach(item => {
  657. this.sortTransfer(item)
  658. })
  659. },
  660. mapLogs(logs) {
  661. return logs.map(item => {
  662. return {
  663. username: item.user ? item.user.name : '',
  664. content: item.content,
  665. created_at: item.created_at
  666. };
  667. });
  668. },
  669. sortTransfer(item) {
  670. if (!("transfer_status" in item)) return;
  671. if (item.transfer_status == null || !(item.transfer_status instanceof Array)) return;
  672. item.transfer_status.sort(function (item1, item2) {
  673. let date1 = new Date(item1['accept_time']);
  674. let date2 = new Date(item2['accept_time']);
  675. if (date1 - date2 > 0) return -1;
  676. if (date1 - date2 < 0) return 1;
  677. return 0;
  678. });
  679. },
  680. review(item, i) {
  681. let url = '{{route('workOrder.reviewApi')}}';
  682. let data = {id: item.id};
  683. window.axios.post(url, data).then(res => {
  684. if (res.data.success) {
  685. res.data.data.is_issue_order = item.is_issue_order;
  686. this.sortOrder(res.data.data);
  687. this.$set(this.workOrders, i, res.data.data);
  688. window.tempTip.showSuccess("审核完成");
  689. } else {
  690. window.tempTip.show(res.data.message ? res.data.message : '审核异常');
  691. }
  692. }).catch(err => {
  693. window.tempTip.show(err)
  694. })
  695. },
  696. createOrderIssue(item, tag) { // 生成问题件
  697. let url = '{{route('workOrder.buildOrderIssueApi')}}';
  698. let data = {};
  699. if (tag) data.ids = [item.id];
  700. else data.ids = checkData;
  701. if (!confirm('是否生成对应的问题件')) return;
  702. window.tempTip.waitingTip('生成中........');
  703. window.axios.post(url, data).then(res => {
  704. if (res.data.success) {
  705. this.replaceWorkOrder(res.data.data);
  706. this.$forceUpdate();
  707. window.tempTip.cancelWaitingTip();
  708. window.tempTip.showSuccess('已生成对应的问题件');
  709. } else {
  710. window.tempTip.cancelWaitingTip();
  711. window.tempTip.show(res.data.message ? res.data.message : '生成问题件异常');
  712. }
  713. }).catch(err => {
  714. window.tempTip.cancelWaitingTip();
  715. window.tempTip.show(err)
  716. });
  717. },
  718. replaceWorkOrder(workOrders) {
  719. let data = [];
  720. workOrders.forEach(workOrder => {
  721. data[workOrder.id] = workOrder;
  722. });
  723. this.workOrders.forEach((workOrder, i) => {
  724. if (data[workOrder.id]) {
  725. let item = data[workOrder.id];
  726. this.sortOrder(item);
  727. this.$set(this.workOrders, i, item);
  728. }
  729. });
  730. this.$forceUpdate();
  731. },
  732. getMessageWorkOrder() {
  733. let selected = checkData;
  734. if (!selected) {
  735. window.tempTip.show('未选中任何信息');
  736. return null;
  737. }
  738. return this.workOrders.filter((item) => {
  739. if (!item.order) return false;
  740. if (!item.order.packages) return false;
  741. return selected.includes(item.id + '');
  742. });
  743. },
  744. exportText() {
  745. let items = this.getMessageWorkOrder();
  746. if (items == null) return;
  747. let text = '';
  748. items.forEach(item => {
  749. if (item.order) text += this.getExportText(item);
  750. });
  751. this.copyText(text);
  752. },
  753. getExportText(item) {
  754. if (!item.order) return '';
  755. if (!item.order.packages) return '';
  756. let message = '';
  757. let issue_type = item['issue_type'] ? item['issue_type'].name : '';
  758. switch (issue_type) {
  759. case '拦截':
  760. message = this.interceptMessage(item);
  761. break;
  762. case '信息更改':
  763. message = this.modificationMessage(item);
  764. break;
  765. default:
  766. message = this.getMessage(item);
  767. break;
  768. }
  769. return message;
  770. },
  771. interceptMessage(item) {
  772. let message = '';
  773. if (item.order['logistic']['code'].includes('SF') || item.order['logistic'].code.includes('ZTO')) {
  774. item.order.packages.forEach(node => {
  775. message += node.logistic_number + '\n';
  776. });
  777. message = message.trim('\n') + ' ——拦截\n';
  778. } else {
  779. let item_order_logistic_name = item.order['logistic']['name'];
  780. let item_order_adder = item.order['consignee_name'] + ' '
  781. + item.order['consignee_phone'] + ' '
  782. + ' ' + item.order.address;
  783. item.order.packages.forEach(p => {
  784. if (p) message += item_order_logistic_name + ' ' + p.logistic_number + ' ' + item_order_adder + '\n';
  785. });
  786. message = message.trim('\n') + ' ——拦截\n';
  787. }
  788. return message;
  789. },
  790. modificationMessage(item) {
  791. let message = '';
  792. let logistic_code = item.order['logistic']['code'];
  793. let adder = item.order['consignee_name'] + ' ' + item.order['consignee_phone'] + ' '
  794. + item.order.province + ' ' + item.order.city + ' ' + item.order.district + ' ' + item.order.address;
  795. item.order.packages.forEach(node => {
  796. if (logistic_code.includes('SF')) { // 顺丰订单
  797. message += node['logistic_number'] + ' ——改信息: ' + item.remark + ',运费到付或月结' + '\n';
  798. } else if (logistic_code.includes('ZTO')) {
  799. message += node['logistic_number'] + ' ——改信息:' + item.remark + '\n';
  800. } else {
  801. message += node['logistic_number'] + ' ' + adder + ' ——改地址' + item.remark + '\n';
  802. }
  803. });
  804. return message;
  805. },
  806. getMessage(item) {
  807. let message = '';
  808. if (!item.order.packages) return message;
  809. let adder = item.order['consignee_name'] + ' ' + item.order['consignee_phone'] + ' '
  810. + item.order.province + ' ' + item.order.city + ' ' + item.order.district + ' ' + item.order.address;
  811. item.order.packages.forEach(p => {
  812. message += p.logistic_number + ' ' + adder + ' ——描述 ' + item.remark + '\n';
  813. });
  814. return message;
  815. },
  816. copyText(text) {
  817. let ele = document.querySelector('#copy_text');
  818. if (ele == null) {
  819. ele = document.createElement("textarea");
  820. ele.setAttribute('id', 'copy_text')
  821. ele.style.opacity = 0;
  822. document.querySelector('body').append(ele);
  823. }
  824. try {
  825. $("#copy_text").text(text).select().focus();
  826. document.execCommand("Copy");
  827. tempTip.showSuccess('复制成功')
  828. } catch (e) {
  829. tempTip.showSuccess('复制失败:' + e)
  830. }
  831. },
  832. batchReview() {
  833. let url = '{{route('workOrder.batchReviewApi')}}';
  834. let data = {ids: checkData};
  835. window.tempTip.setIndex('1999');
  836. if (!confirm('是否对当前选中订单进行审核')) return;
  837. window.tempTip.waitingTip('审核中........');
  838. window.axios.post(url, data).then(res => {
  839. if (res.data.success) {
  840. this.replaceWorkOrder(res.data.data);
  841. this.$forceUpdate();
  842. window.tempTip.cancelWaitingTip();
  843. window.tempTip.showSuccess('审核完成');
  844. } else {
  845. window.tempTip.cancelWaitingTip();
  846. window.tempTip.show(res.data.message ? res.data.message : '审核出现异常');
  847. }
  848. }).catch(err => {
  849. window.tempTip.cancelWaitingTip();
  850. window.tempTip.show(err);
  851. })
  852. },
  853. changeIssueType(item, e) {
  854. let url = '{{route('workOrder.updateIssueTypeApi')}}';
  855. let data = {
  856. id: item.id,
  857. type_id: $(e.target).val()
  858. };
  859. window.tempTip.waitingTip('修改中.........');
  860. window.axios.post(url, data).then(res => {
  861. if (res.data.success) {
  862. window.tempTip.cancelWaitingTip();
  863. window.tempTip.showSuccess('修改成功');
  864. item.order_issue_type_id = data.type_id;
  865. } else {
  866. window.tempTip.cancelWaitingTip();
  867. window.tempTip.show(res.data.message ? res.data.message : '修改异常');
  868. }
  869. }).catch(err => {
  870. window.tempTip.cancelWaitingTip();
  871. window.tempTip.show(err);
  872. });
  873. },
  874. copyLogisticNumber() {
  875. let items = this.getMessageWorkOrder();
  876. let logistic_numbers = '';
  877. items.forEach(item => {
  878. item.order.packages.forEach(node => {
  879. logistic_numbers += node.logistic_number + '\n';
  880. });
  881. })
  882. this.copyText(logistic_numbers);
  883. },
  884. showEditIssueType() {
  885. this.selectIssueType = 0;
  886. $("#edit-issue-type-type-modal").modal('show');
  887. },
  888. editOrderIssueType() {
  889. let url = '{{route('workOrder.batchUpdateIssueTypeApi')}}'
  890. let data = {ids: checkData, type: this.selectIssueType};
  891. window.tempTip.setIndex(1999);
  892. window.axios.post(url, data).then(res => {
  893. if (res.data.success) {
  894. window.tempTip.showSuccess('修改问题件类型成功');
  895. this.replaceWorkOrder(res.data.data);
  896. $("#edit-issue-type-type-modal").modal('hide');
  897. return;
  898. }
  899. window.tempTip.show(res.data.message ? res.data.message : '修改异常');
  900. }).catch(err => {
  901. window.tempTip.show(err)
  902. })
  903. },
  904. destroy(item, i) {
  905. let url = '{{url('apiLocal/workOrder/')}}' + '/' + item.id;
  906. if (!confirm('是否删除当前工单')) return;
  907. window.tempTip.waitingTip('删除.........');
  908. window.axios.delete(url).then(res => {
  909. if (res.data.success) {
  910. this.$delete(this.workOrders, i);
  911. window.tempTip.cancelWaitingTip();
  912. window.tempTip.showSuccess('删除成功');
  913. } else {
  914. window.tempTip.cancelWaitingTip();
  915. window.tempTip.show(res.data.message ? res.data.message : '');
  916. }
  917. }).catch(err => {
  918. window.tempTip.cancelWaitingTip();
  919. window.tempTip.show(err);
  920. })
  921. },
  922. pushImagesAndShow(e, images) {
  923. let map = [];
  924. for (let i = 0; i < e.target.files.length; i++) {
  925. let image = e.target.files[i];
  926. if (this.imageExist(image, images)) {
  927. map.push(image.name);
  928. continue;
  929. }
  930. let src = window.URL.createObjectURL(image);
  931. images.push({src: src, file: image});
  932. }
  933. e.target.value = '';
  934. if (map.length === 0) return;
  935. window.tempTip.setIndex(1999);
  936. window.tempTip.show(map.join('\n,') + '图片重复');
  937. },
  938. spliceImage(i, images) {
  939. if (!confirm('是否取消选择该图片')) return;
  940. images.splice(i, 1);
  941. },
  942. imageExist(image, images) {
  943. let arr = images.filter(item => {
  944. return item.file.name === image.name;
  945. });
  946. return arr.length > 0;
  947. },
  948. showFillModel(item, index) {
  949. this.workOrder.id = item.id;
  950. this.workOrder.index = index;
  951. this.workOrder.reissue_logistic_number = null; // 补发单号
  952. this.workOrder.logistic_number = null; // 补发单号
  953. this.workOrder.dealImages = []; // 交易图
  954. this.workOrder.refundImages = []; // 退款图
  955. $("#fill-loss-work-order-modal").modal('show');
  956. },
  957. updateLossWorkOrder() {
  958. let formData = new FormData();
  959. formData.append('id', this.workOrder.id);
  960. formData.append('reissue_logistic_number', this.workOrder.reissue_logistic_number);
  961. formData.append('logistic_number', this.workOrder.logistic_number);
  962. formData.append('price', this.workOrder.price);
  963. let dealImages = this.getImages(this.workOrder.dealImages);
  964. let refundImages = this.getImages(this.workOrder.refundImages);
  965. this.setFormDataImagePrefix(formData, 'dealImages', dealImages);
  966. this.setFormDataImagePrefix(formData, 'refundImages', refundImages);
  967. this.fillLossWorkOrder(formData);
  968. },
  969. setFormDataImagePrefix(formData, prefix, images) {
  970. images.forEach((item, i) => {
  971. formData.append(`${prefix}[]`, item);
  972. });
  973. },
  974. getImages(images) {
  975. return images.map((item) => {
  976. return item.file;
  977. })
  978. },
  979. fillLossWorkOrder(data) {
  980. let url = "{{route('workOrder.lossApi')}}";
  981. window.tempTip.setIndex(1999);
  982. window.axios.post(url, data, {'Content-Type': 'multipart/form-data'}).then(res => {
  983. if (res.data.success) {
  984. this.sortOrder(res.data.data);
  985. this.$set(this.workOrders, this.workOrder.index, res.data.data);
  986. window.tempTip.showSuccess('工单信息填充成功');
  987. } else {
  988. window.tempTip.show(res.data.message);
  989. }
  990. }).catch(err => {
  991. window.tempTip.show(err);
  992. });
  993. },
  994. showEditLog(item, index, type) {
  995. this.processLog.type = type;
  996. this.processLog.index = index;
  997. this.processLog.work_order_id = item.id;
  998. this.processLog.indemnity = null;
  999. this.processLog.is_indemnity = null;
  1000. this.processLog.remark = null;
  1001. this.processLog.indemnitor = null;
  1002. $("#work-order-process-log-modal").modal('show');
  1003. },
  1004. storeLogisticProcessLog() {
  1005. let url = "{{route('workOrderProcessLog.logisticLogApi')}}";
  1006. let data = {
  1007. indemnity: this.processLog.indemnity,
  1008. work_order_id: this.processLog.work_order_id,
  1009. is_indemnity: this.processLog.is_indemnity,
  1010. remark: this.processLog.remark,
  1011. };
  1012. if (!this.verifiedProcessLog()) return;
  1013. window.tempTip.setDuration(9999);
  1014. window.tempTip.setIndex(1999);
  1015. window.tempTip.waitingTip('操作中请稍后');
  1016. window.axios.post(url, data).then(res => {
  1017. window.tempTip.cancelWaitingTip();
  1018. window.tempTip.setIndex(1999);
  1019. window.tempTip.setDuration(2000);
  1020. if (res.data.success) {
  1021. window.tempTip.showSuccess('创建成功');
  1022. this.$set(this.workOrders[this.processLog.index], 'logistic_log', res.data.data);
  1023. $('#work-order-process-log-modal').modal('hide');
  1024. } else {
  1025. window.tempTip.show(res.data.message ? res.data.message : '创建异常,刷新页面重试');
  1026. }
  1027. }).catch(err => {
  1028. window.tempTip.setIndex(1999);
  1029. window.tempTip.setDuration(2000);
  1030. window.tempTip.show(err);
  1031. });
  1032. },
  1033. storeProcessLog() {
  1034. let url = "{{route('workOrderProcessLog.LogApi')}}";
  1035. let data = {
  1036. indemnity: this.processLog.indemnity,
  1037. work_order_id: this.processLog.work_order_id,
  1038. is_indemnity: this.processLog.is_indemnity,
  1039. remark: this.processLog.remark,
  1040. indemnitor: this.processLog.indemnitor,
  1041. };
  1042. if (!this.verifiedProcessLog()) return;
  1043. window.tempTip.setDuration(9999);
  1044. window.tempTip.setIndex(1999);
  1045. window.tempTip.waitingTip('操作中请稍后');
  1046. window.axios.post(url, data).then(res => {
  1047. window.tempTip.cancelWaitingTip();
  1048. window.tempTip.setDuration(2000);
  1049. if (res.data.success) {
  1050. window.tempTip.showSuccess('创建成功');
  1051. this.$set(this.workOrders[this.processLog.index], 'process_log', res.data.data);
  1052. $('#work-order-process-log-modal').modal('hide');
  1053. } else {
  1054. window.tempTip.show(res.data.message ? res.data.message : '创建异常,刷新页面重试');
  1055. }
  1056. }).catch(err => {
  1057. window.tempTip.setDuration(2000);
  1058. window.tempTip.show(err);
  1059. });
  1060. },
  1061. updateWorkOrderStatus(item, e, i) {
  1062. let url = "{{route('workOrder.updateWorkOrderStatusApi')}}";
  1063. let data = {
  1064. id: item.id,
  1065. work_order_status: e.target.value
  1066. }
  1067. window.tempTip.waitingTip('处理中......');
  1068. window.tempTip.setDuration('1999');
  1069. window.axios.post(url, data).then(res => {
  1070. window.tempTip.cancelWaitingTip();
  1071. window.tempTip.setDuration('1999');
  1072. if (res.data.success) {
  1073. item.work_order_status = data.work_order_status;
  1074. window.tempTip.showSuccess('修改成功');
  1075. return;
  1076. }
  1077. window.tempTip.show(res.data.message ? res.data.message : '修改失败');
  1078. }).catch(err => {
  1079. window.tempTip.show('修饰异常:' + err);
  1080. });
  1081. },
  1082. verifiedProcessLog() { // 校验处理信息
  1083. window.tempTip.setIndex(1999);
  1084. window.tempTip.setDuration(2000);
  1085. if (this.processLog.is_indemnity === null) {
  1086. window.tempTip.show('选择处理方式');
  1087. return false;
  1088. }
  1089. if (this.processLog.type === 1 && this.processLog.indemnitor == null) {
  1090. window.tempTip.show('指定赔偿方');
  1091. return false;
  1092. }
  1093. if (this.processLog.is_indemnity === '1') {
  1094. if (!this.processLog.indemnity) {
  1095. window.tempTip.show('填写赔偿金额');
  1096. return false;
  1097. }
  1098. } else if (this.processLog.is_indemnity === '2') {
  1099. if (this.processLog.remark === null || this.processLog.remark.trim(' ').length === 0) {
  1100. window.tempTip.show('填写不赔偿理由');
  1101. return false;
  1102. }
  1103. }
  1104. return true;
  1105. }
  1106. },
  1107. });
  1108. </script>
  1109. @endsection