list.blade.php 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460
  1. @extends('layouts.app')
  2. @section('title')预约管理-入库预约@endsection
  3. @section('content')
  4. <div class="container-fluid d-none" id="container">
  5. <div id="form"></div>
  6. <div class="mt-1">
  7. <button type="button" class="btn btn-outline-dark btn-sm form-control-sm dropdown-toggle tooltipTarget" :class="[checkData.length>0?'btn-dark text-light':'']"
  8. data-toggle="dropdown" title="导出所有页将会以搜索条件得到的筛选结果,将其全部记录(每一页)导出">
  9. 导出Excel
  10. </button>
  11. <div class="dropdown-menu">
  12. <a class="dropdown-item" @click="executeExport(false)" href="javascript:">导出勾选内容</a>
  13. <a class="dropdown-item" @click="executeExport(true)" href="javascript:">导出所有页</a>
  14. </div>
  15. @can("入库管理-入库预约-质检")<button type="button" class="btn btn-outline-primary" @click="qualityInspectionMark()">质检</button>@endcan
  16. </div>
  17. <table class="table table-striped table-hover text-nowrap td-min-width-80" id="table">
  18. <tr class="text-center">
  19. <th>
  20. <label for="all" id="cloneCheckAll">
  21. <input id="all" type="checkbox" @click="checkAll($event)">全选
  22. </label>
  23. </th>
  24. <th>序号</th>
  25. <th>操作</th>
  26. <th>状态</th>
  27. <th>货主</th>
  28. <th>预约时间</th>
  29. <th>仓库</th>
  30. <th>
  31. <div class="row" style="min-width: 800px">
  32. <div class="col-12">车辆信息</div>
  33. </div>
  34. <div class="row">
  35. <div class="col-2">预约号</div>
  36. <div class="col-2">车牌号</div>
  37. <div class="col-2">车型</div>
  38. <div class="col-1">司机姓名</div>
  39. <div class="col-2">司机电话</div>
  40. <div class="col-3">操作/送达时间</div>
  41. </div>
  42. </th>
  43. <th>吨</th>
  44. <th>立方</th>
  45. <th>箱数</th>
  46. <th>快递公司</th>
  47. <th>快递单号</th>
  48. <th>采购单号</th>
  49. <th>ASN单号</th>
  50. <th>
  51. <div class="row">
  52. <div class="col-12 text-center">明细单</div>
  53. </div>
  54. <div class="row" style="min-width: 500px">
  55. <div class="col-5 text-center">商品名称</div>
  56. <div class="col-4 text-center">条码</div>
  57. <div class="col-2 text-center">数量</div>
  58. </div>
  59. </th>
  60. <th>预约备注</th>
  61. <th>创建时间</th>
  62. </tr>
  63. <tr v-for="(info,i) in list">
  64. <td>
  65. <label>
  66. <input class="checkItem" type="checkbox" :value="info.id" v-model="checkData">
  67. </label>
  68. </td>
  69. <td>@{{ i+1 }}</td>
  70. <td>
  71. <span v-if="info.status==0">
  72. @can("入库管理-入库预约-预约管理-签到")<button class="btn btn-sm btn-outline-success" @click="signIn(i,0)" v-if="info.status==0 && info.cars[0].status==0 && info.appointment_date==today">签到</button>@endcan<br>
  73. <button type="button" @click="cancel(info.id,i)" class="btn btn-sm btn-outline-danger">取消预约</button><br>
  74. <button type="button" @click="updateDeliveryDate(info,i)" class="btn btn-sm btn-outline-primary">修改预约</button>
  75. </span>
  76. <span v-if="info.status==2">
  77. <button type="button" @click="printReceipt(info)" class="btn btn-sm btn-outline-success"><i class="fa fa-print"></i>&nbsp;打印</button>
  78. </span>
  79. </td>
  80. <td>
  81. <span v-if="info.status==0 && info.cars.length>0 && info.cars[0].status==1">
  82. <span class="fa fa-circle text-primary">作业中</span>
  83. </span>
  84. <span v-else>
  85. <label v-if="!poolMapping.status">
  86. <span class="fa fa-circle text-secondary">未知</span>
  87. </label>
  88. <label v-else>
  89. <small><span class="fa fa-circle" :class="info.status==0 ? 'text-info' : (info.status==2 ? 'text-success' : 'text-danger')"></span></small>
  90. @{{ poolMapping.status[info.status] }}
  91. <span v-if="info.type_mark==0" class="badge badge-primary">质检单</span>
  92. </label>
  93. </span>
  94. </td>
  95. <td>
  96. <label v-if="!poolMapping.owners"></label>
  97. <label v-else>@{{ poolMapping.owners[info.owner_id] }}</label>
  98. </td>
  99. <td class="text-primary">@{{ info.appointment_date }}&nbsp;&nbsp;@{{ info.period }}</td>
  100. <td>
  101. <label v-if="!poolMapping.warehouses"></label>
  102. <label v-else>@{{ poolMapping.warehouses[info.warehouse_id] }}</label>
  103. </td>
  104. <td>
  105. <div v-if="info.cars.length>0" class="text-center">
  106. <div class="row">
  107. <div class="col-2 font-weight-bold">@{{ info.cars[0].appointment_number }}</div>
  108. <div class="col-2 text-secondary">@{{ info.cars[0].license_plate_number }}</div>
  109. <div class="col-2 text-secondary">@{{ info.cars[0].car ? info.cars[0].car.name : '' }}</div>
  110. <div class="col-1 text-secondary">@{{ info.cars[0].driver_name }}</div>
  111. <div class="col-2 text-secondary">@{{ info.cars[0].driver_phone }}</div>
  112. <div class="col-3">
  113. @can("入库管理-入库预约-预约管理-卸货完成")<button class="btn btn-sm btn-outline-success" @click="unloading(i,0)" v-if="info.cars[0].status==1">卸货完成</button>@endcan
  114. <div v-if="info.cars[0].status==2">@{{ info.cars[0].delivery_time }}</div>
  115. </div>
  116. </div>
  117. <div class="up" :id="'item-'+info.id" v-show="info.cars.length>1">
  118. <div class="row" v-for="(car,j) in info.cars" v-if="j!==0">
  119. <div class="col-2 font-weight-bold">@{{ car.appointment_number }}</div>
  120. <div class="col-2 text-secondary">@{{ car.license_plate_number }}</div>
  121. <div class="col-2 text-secondary">@{{ car.car ? car.car.name : '' }}</div>
  122. <div class="col-1 text-secondary">@{{ car.driver_name }}</div>
  123. <div class="col-2 text-secondary">@{{ car.driver_phone }}</div>
  124. <div class="col-3">
  125. @can("入库管理-入库预约-预约管理-卸货完成")<button class="btn btn-sm btn-outline-success" @click="unloading(i,j)" v-if="car.status==1">卸货完成</button>@endcan
  126. <div v-if="car.status==2">@{{ car.delivery_time }}</div>
  127. </div>
  128. </div>
  129. </div>
  130. <div class="text-center m-auto small cursor-pointer" v-if="info.cars.length>1" @click="upAll(info.id)">
  131. <span class="fa" :class="upList[info.id] ? 'fa-angle-double-down' : 'fa-angle-double-right'" style="margin-top: 2px;"></span>&nbsp;
  132. <span v-if="upList[info.id]">收起其余@{{ info.cars.length-1 }}条</span>
  133. <span v-else>展开其余@{{ info.cars.length-1 }}条</span>
  134. </div>
  135. </div>
  136. </td>
  137. <td>@{{ info.tonne>0 ? info.tonne : '-' }}</td>
  138. <td>@{{ info.cubic_meter>0 ? info.cubic_meter : '-' }}</td>
  139. <td>@{{ info.box_amount>0 ? info.box_amount : '-' }}</td>
  140. <td>@{{ info.logistic ? info.logistic.name : '' }}</td>
  141. <td>@{{ info.logistic_number }}</td>
  142. <td><span v-html="warpText(info.procurement_number)"></span></td>
  143. <td><span v-html="warpText(info.asn_number)"></span></td>
  144. <td>
  145. <div v-if="info.details.length>0">
  146. <div class="row">
  147. <div class="col-5 font-weight-bold text-overflow-warp">@{{ info.details[0].commodity_id ? (info.details[0].commodity ? info.details[0].commodity.name : '') : info.details[0].name }}</div>
  148. <div class="col-4 text-secondary text-overflow-warp">@{{ info.details[0] | getCommodity }}</div>
  149. <div class="col-2 text-secondary">@{{ info.details[0].amount }}</div>
  150. </div>
  151. <div class="up" :id="'detail-'+info.id" v-show="info.details.length>1">
  152. <div class="row" v-for="(detail,i) in info.details" v-if="i!==0">
  153. <div class="col-5 font-weight-bold text-overflow-warp">@{{ detail.commodity_id ? (detail.commodity ? detail.commodity.name : '') : detail.name }}</div>
  154. <div class="col-4 text-secondary text-overflow-warp">@{{ detail | getCommodity }}</div>
  155. <div class="col-2 text-secondary">@{{ detail.amount }}</div>
  156. </div>
  157. </div>
  158. <div class="text-center m-auto small cursor-pointer" v-if="info.details.length>1" @click="upAllDetail(info.id)">
  159. <span class="fa" :class="upListDetail[info.id] ? 'fa-angle-double-down' : 'fa-angle-double-right'" style="margin-top: 2px;"></span>&nbsp;
  160. <span v-if="upListDetail[info.id]">收起其余@{{ info.details.length-1 }}条</span>
  161. <span v-else>展开其余@{{ info.details.length-1 }}条</span>
  162. </div>
  163. </div>
  164. </td>
  165. <td>@{{ info.remark }}</td>
  166. <td>@{{ info.created_at }}</td>
  167. </tr>
  168. </table>
  169. {{$list->appends($params)->links()}}
  170. @include("store.deliveryAppointment._selectDate")
  171. @include("store.deliveryAppointment._printBody")
  172. @include("store.deliveryAppointment._printInfo")
  173. </div>
  174. @stop
  175. @section("lastScript")
  176. <script type="text/javascript" src="{{mix('js/queryForm/export.js')}}"></script>
  177. <script type="text/javascript" src="{{mix('js/queryForm/queryForm.js')}}"></script>
  178. <script>
  179. new Vue({
  180. el:"#container",
  181. data:{
  182. list:[@foreach($list as $data)@json($data),@endforeach],
  183. status:[],
  184. warehouses:[],
  185. owners:[@foreach($owners as $owner){name:"{{$owner->id}}",value:"{{$owner->name}}"},@endforeach],
  186. checkData:[],
  187. poolMapping:{},
  188. upList:{},
  189. upListDetail:{},
  190. sum:Number("{{$list->total()}}"),
  191. capacities:[],
  192. btnName:"确定修改预约",
  193. index:"",
  194. selectDate:{},
  195. periods:@json(\App\DeliveryAppointment::PERIOD),
  196. printInfo:{},
  197. infoShow:false,
  198. today:"",
  199. },
  200. mounted(){
  201. let status = [];
  202. let statusMap = {};
  203. let warehouses = [];
  204. let warehouseMap = {};
  205. let owners = [];
  206. let ownerMap = [];
  207. @foreach(\App\DeliveryAppointment::STATUS as $index=>$status)
  208. status.push({name:"{{$index}}",value:"{{$status}}"});
  209. statusMap["{{$index}}"] = "{{$status}}";
  210. @endforeach
  211. this.status = status;
  212. this.$set(this.poolMapping,"status",statusMap);
  213. @foreach($warehouses as $warehouse)
  214. warehouses.push({name:"{{$warehouse->id}}",value:"{{$warehouse->name}}"});
  215. warehouseMap["{{$warehouse->id}}"] = "{{$warehouse->name}}";
  216. @endforeach
  217. this.warehouses = warehouses;
  218. this.poolMapping.warehouses = warehouseMap;
  219. @foreach($owners as $owner)
  220. owners.push({name:"{{$owner->id}}",value:"{{$owner->name}}"});
  221. ownerMap["{{$owner->id}}"] = "{{$owner->name}}";
  222. @endforeach
  223. this.owners = owners;
  224. this.poolMapping.owners = ownerMap;
  225. $(".up").slideUp();
  226. $("#container").removeClass("d-none");
  227. this._renderingForm();
  228. let now = new Date();
  229. let yy = now.getFullYear();
  230. let mm = now.getMonth() + 1;
  231. let dd = now.getDate();
  232. this.today = yy+'-'+(mm<10 ? '0'+mm : mm)+'-'+(dd<10 ? '0'+dd : dd);
  233. },
  234. watch:{
  235. checkData:{
  236. handler(){
  237. document.querySelector('#all').checked = this.checkData.length === this.list.length;
  238. },
  239. deep:true
  240. },
  241. },
  242. methods: {
  243. exePrint(){
  244. this.infoShow = true;
  245. if (!this.printInfo.signer){
  246. window.tempTip.setIndex(1099);
  247. window.tempTip.show("请填写签收人");
  248. return;
  249. }
  250. $("#printModal").modal('hide');
  251. let iframe=document.getElementById("print-iframe");
  252. if(!iframe){
  253. let el = document.getElementById("printContent");
  254. iframe = document.createElement('IFRAME');
  255. iframe.setAttribute("id", "print-iframe");
  256. iframe.setAttribute('style', 'position:absolute;width:0;height:0;left:-500px;top:-500px;');
  257. document.body.appendChild(iframe);
  258. let doc = iframe.contentWindow.document;
  259. doc.write('<LINK rel="stylesheet" type="text/css" href="{{ asset(mix("css/app.css")) }}">');
  260. doc.write('<div>' + el.innerHTML + '</div>');
  261. doc.close();
  262. iframe.contentWindow.focus();
  263. }
  264. this.infoShow = false;
  265. setTimeout(function () {
  266. iframe.contentWindow.print();
  267. if (navigator.userAgent.indexOf("MSIE") > 0){
  268. document.body.removeChild(iframe);
  269. }
  270. },200);
  271. },
  272. _renderingForm(){
  273. let data=[
  274. [
  275. {name:'created_at_start',type:'dateTime',tip:"选择显示创建日期的结束时间"},
  276. {name:'appointment_date_start',type:'dateTime',tip:"选择显示预约日期的结束时间"},
  277. {name:'owner_id',type:'select_multiple_select',tip:['输入关键词快速定位下拉列表,回车确定','选择要显示的客户'],
  278. placeholder:['货主','定位或多选货主'],data:this.owners},
  279. {name:'status',type:'select',placeholder: '状态',data:this.status},
  280. ],
  281. [
  282. {name:'created_at_end',type:'dateTime',tip:"选择显示创建日期的结束时间"},
  283. {name:'appointment_date_end',type:'dateTime',tip:"选择显示预约日期的结束时间"},
  284. {name:'warehouse_id',type:'select',placeholder: '仓库',data:this.warehouses},
  285. ],
  286. ];
  287. let form = new query({
  288. el:"#form",
  289. condition:data,
  290. });
  291. form.init();
  292. },
  293. upAll(id){
  294. let dom = "#item-"+id;
  295. if (this.upList[id]) $(dom).slideUp();
  296. else $(dom).slideDown();
  297. this.$set(this.upList,id,!this.upList[id]);
  298. },
  299. upAllDetail(id){
  300. let dom = "#detail-"+id;
  301. if (this.upListDetail[id]) $(dom).slideUp();
  302. else $(dom).slideDown();
  303. this.$set(this.upListDetail,id,!this.upListDetail[id]);
  304. },
  305. unloading(i,j){
  306. window.tempTip.confirm("确定已经完成卸货?",()=>{
  307. window.tempTip.postBasicRequest("{{url('store/deliveryAppointment/unloading')}}",{id:this.list[i].cars[j].id},res=>{
  308. this.list[i].cars[j].status = 2;
  309. if (this.list[i].cars.every(car=>{
  310. if (car.status!=2)return false;
  311. return true
  312. }))this.list[i].status = 2;
  313. return "成功确认";
  314. })
  315. })
  316. },
  317. signIn(i,j){
  318. window.tempTip.confirm("确定为司机签到?",()=>{
  319. window.tempTip.postBasicRequest("{{url('store/deliveryAppointment/signIn')}}",{id:this.list[i].cars[j].id},()=>{
  320. this.list[i].cars[j].status = 1;
  321. return "成功签到";
  322. })
  323. })
  324. },
  325. cancel(id,index){
  326. window.tempTip.confirm("确定要取消该次预约吗?此操作不可逆,请谨慎选择",()=>{
  327. window.tempTip.postBasicRequest("{{url('store/deliveryAppointment/cancel')}}",{id:id},res=>{
  328. this.$set(this.list[index],"status",res);
  329. return "成功取消该单预约";
  330. })
  331. })
  332. },
  333. checkAll(e){
  334. if (e.target.checked){
  335. this.checkData = [];
  336. this.list.forEach((el)=>{
  337. this.checkData.push(el.id);
  338. });
  339. }else this.checkData = [];
  340. },
  341. executeExport(isAll){
  342. let url = '{{url('store/deliveryAppointment/export')}}';
  343. let token='{{ csrf_token() }}';
  344. excelExport(isAll,this.checkData,url,this.sum,token);
  345. },
  346. updateDeliveryDate(info,index){
  347. for (let i=0;i<info.cars.length;i++){
  348. if (info.cars[i].status!=0){
  349. window.tempTip.setDuration("3000");
  350. window.tempTip.show("车辆已达,无法修改预约");
  351. return;
  352. }
  353. this.index = index;
  354. let param = {
  355. model:info,
  356. detail_amount:info.details.length,
  357. };
  358. window.tempTip.postBasicRequest("{{url('store/deliveryAppointment/getCapacity')}}",param,res=>{
  359. this.capacities = res;
  360. $("#modal").modal("show");
  361. });
  362. }
  363. },
  364. submitAppointment(){
  365. window.tempTip.setDuration(3000);
  366. window.tempTip.setIndex(1099);
  367. if (!this.selectDate.date){
  368. window.tempTip.show("尚未选择预约时间");
  369. return;
  370. }
  371. let url = "{{url('store/deliveryAppointment/updateAppointment')}}";
  372. let param = {
  373. id:this.list[this.index].id,
  374. date:this.selectDate,
  375. };
  376. window.tempTip.postBasicRequest(url,param,res=>{
  377. if (res && res.isFail){
  378. this.capacities.some(capacity=>{
  379. if (capacity.date === this.selectDate.date){
  380. capacity.period.some(p=>{
  381. if (p.index === this.selectDate.time){
  382. p.isAvailable = false;
  383. return true;
  384. }
  385. });
  386. return true;
  387. }
  388. });
  389. this.selectDate={};
  390. window.tempTip.show("该预约时段已经被抢占了,请选择其他时段");
  391. return;
  392. }
  393. this.list[this.index].appointment_date = this.selectDate.date;
  394. this.list[this.index].date_period = this.selectDate.time;
  395. this.list[this.index].period = this.periods[this.selectDate.time];
  396. $("#modal").modal("hide");
  397. return "修改预约时间成功";
  398. },true);
  399. },
  400. selectPeriod(date,time,isSelect){
  401. if (isSelect) this.selectDate = {date:date,time:time};
  402. },
  403. qualityInspectionMark(){
  404. if (this.checkData.length<1){
  405. window.tempTip.setDuration("3000");
  406. window.tempTip.show("未勾选记录");
  407. return;
  408. }
  409. let url = "{{url('store/deliveryAppointment/qualityInspectionMark')}}";
  410. window.tempTip.postBasicRequest(url,{ids:this.checkData},()=>{
  411. this.list.forEach(data=>{
  412. if (this.checkData.indexOf(data.id)!==-1){
  413. data.type_mark = 0;
  414. }
  415. });
  416. return "标记质检成功";
  417. });
  418. },
  419. printReceipt(info){
  420. let d = new Date();
  421. let str = '';
  422. str += d.getFullYear() + '年';
  423. str += d.getMonth() + 1 + '月';
  424. str += d.getDate() + '日';
  425. str += d.getHours() + '时';
  426. str += d.getMinutes() + '分';
  427. str += d.getSeconds() + '秒';
  428. this.printInfo = info;
  429. this.printInfo.print_date = str;
  430. $("#printModal").modal("show");
  431. },
  432. warpText(code){
  433. if (!code)return code;
  434. code = code.split(/[,, ]+/is);
  435. let str = "";
  436. for (let i=0;i<code.length;i++){
  437. str += code[i]+"<br>";
  438. }
  439. return str;
  440. }
  441. },
  442. filters:{
  443. getCommodity(detail){
  444. if (!detail.commodity_id)return detail.name;
  445. if (detail.commodity && detail.commodity.barcodes.length>0)return detail.commodity.barcodes[0].code;
  446. return "";
  447. },
  448. },
  449. });
  450. </script>
  451. @stop