index.blade.php 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492
  1. @extends('layouts.app')
  2. @section('content')
  3. <div id="nav2">
  4. @component('store.menu')@endcomponent
  5. @component('store.blindReceive.menu')@endcomponent
  6. </div>
  7. <div class="container">
  8. <audio src="{{asset('sound/warning_otherBarcode.mp3')}}" controls="controls" preload id="soundWarning" hidden>
  9. </audio>
  10. <audio src="{{asset('sound/ding.mp3')}}" controls="controls" preload id="soundDing" hidden>
  11. </audio>
  12. <div class="row mt-2">
  13. <div class="col-12" id="scanColumn">
  14. <div class="card" :class="borderByMode">
  15. <div class="card-body">
  16. <div class="row">
  17. <div class="col-12">
  18. <p class="text-muted" style="font-size: 0.5em" v-if="inputMode=='regular'">常规:可输入效期,相同条码记录不会合并</p>
  19. <p class="text-muted" style="font-size: 0.5em" v-if="inputMode=='increasing'">逐一扫描:处理单一重复商品,每扫一次对应隔口总数量自动递增,扫到不同条码会提示</p>
  20. <p class="text-muted" style="font-size: 0.5em" v-if="inputMode=='multiIncreasing'">边扫边分:处理多种商品,自动将扫到的不同条码数量递增到各自隔口号</p>
  21. <ul class="nav nav-tabs mb-4 mt-n3">
  22. <li class="nav-item"><a href="#" class="nav-link" :class="inputMode=='regular'?'active':''"
  23. @click="inputMode='regular';changeToManualInputAmount();cleanInputs();inputting.fromIncreasing=false">常规</a></li>
  24. <li class="nav-item"><a href="#" class="nav-link" :class="inputMode=='increasing'?'active':''"
  25. @click="inputMode='increasing';changeToScanInputAmount();cleanInputs();inputting.fromIncreasing=true;">逐一扫描</a></li>
  26. <li class="nav-item"><a href="#" class="nav-link" :class="inputMode=='multiIncreasing'?'active':''"
  27. @click="inputMode='multiIncreasing';changeToScanInputAmount();cleanInputs();inputting.fromIncreasing=true">边扫边分</a></li>
  28. </ul>
  29. </div>
  30. <div class="col-6">
  31. <div v-if="inputMode=='regular'">
  32. <div class="btn btn-sm btn-outline-primary"
  33. v-if="!isManualInputtingBarcode" @click="changeToManualInputBarcode">手动输入</div>
  34. <div class="btn btn-sm btn-outline-danger"
  35. @click="changeToScanInputBarcode" v-if="isManualInputtingBarcode">扫描输入</div>
  36. </div>
  37. <input type="text" id="barcode" class="form-control" :disabled="status.barcodeDisable" placeholder="扫入条码" @focusin="focusOutDocument" @focusout="focusDocument" v-model="inputting.barcode">
  38. <div v-if="inputMode=='regular'">
  39. <div class="card-title">
  40. 生产日期:
  41. </div>
  42. <input type="date" class="form-control mb-2" v-model="inputting.produce_date" @focusin="focusOutDocument" @focusout="focusDocument" @keyup="oninputEnter">
  43. </div>
  44. <div v-if="inputMode=='regular'">
  45. <div class="card-title">
  46. 失效日期:
  47. </div>
  48. <input type="date" class="form-control mb-2" v-model="inputting.valid_date" @focusin="focusOutDocument" @focusout="focusDocument" @keyup="oninputEnter">
  49. </div>
  50. <div v-if="inputMode=='regular'" class="mt-0">
  51. <div class="card-title">
  52. 唯一码:
  53. </div>
  54. <input type="text" class="form-control mb-2" v-model="inputting.unique_code" @focusin="focusOutDocument" @focusout="focusDocument" @keyup="oninputEnter">
  55. </div>
  56. </div>
  57. <div class="col-6">
  58. <div class="card-title" id="amountLabel">
  59. 手动输入数量:
  60. </div>
  61. <div class="input-group mt-n2 mb-2">
  62. <input type="number" id="amount" class="form-control" placeholder="" :disabled="status.amountDisable"
  63. v-model="inputting.amount" @focusin="focusOutDocument" @focusout="focusDocument" @keyup="oninputEnter"
  64. style='height: 40px;font-size: 1.6em;color:blue;font-weight: bolder;padding: 3px;text-align: center'>
  65. </div>
  66. <div class="card-title">
  67. 格口号:
  68. </div>
  69. <input type="number" id="bin" class="form-control mt-n2 mb-2"
  70. v-model="inputting.bin"
  71. :disabled="status.binDisable" @focusin="focusOutDocument" @focusout="focusDocument" @keyup="oninputEnter"
  72. style='height: 100px;font-size: 5em;color:red;font-weight: bolder;padding: 3px;text-align: center'>
  73. <div v-if="inputMode=='regular'" class="mt-4">
  74. <div class="card-title">
  75. 批次号:
  76. </div>
  77. <input type="text" class="form-control mb-2" v-model="inputting.batch_number" @focusin="focusOutDocument" @focusout="focusDocument" @keyup="oninputEnter">
  78. </div>
  79. </div>
  80. <div class="col-12" v-if="commitButtonVisible && inputMode=='regular'" >
  81. <button class="btn btn-success btn form-control" @click="commitGoods">确定</button>
  82. </div>
  83. </div>
  84. <p class="card-text text-muted mt-3 mb-n3 text-center">
  85. 已完成:
  86. </p>
  87. <hr>
  88. <table class="table table-sm table-striped" v-if="goodses.length>0">
  89. <tr>
  90. <th>隔口号</th>
  91. <th>数量</th>
  92. <th>条码</th>
  93. <th>生产日期</th>
  94. <th>失效日期</th>
  95. <th>批次号</th>
  96. <th>唯一码</th>
  97. <th>操作</th>
  98. </tr>
  99. <tr v-for="(goods,i) in goodses" @click="selectTr===i+1?selectTr=0:selectTr=i+1" :class="selectTr===i+1?'focusing' : ''">
  100. <td>@{{ goods.bin }}</td>
  101. <td>@{{ goods.amount }}</td>
  102. <td>@{{ goods.barcode }}</td>
  103. <td>@{{ goods.produce_date }}</td>
  104. <td>@{{ goods.valid_date }}</td>
  105. <td>@{{ goods.batch_number }}</td>
  106. <td>@{{ goods.unique_code }}</td>
  107. <td>
  108. <button class="btn btn-outline-danger btn-sm" @click="removeGoods($event,goods.barcode)">删</button>
  109. </td>
  110. </tr>
  111. </table>
  112. <hr>
  113. <span class="btn btn-outline-dark btn form-control" style="cursor: pointer" @click="submitExcelData">结束并生成Excel</span>
  114. </div>
  115. </div>
  116. </div>
  117. </div>
  118. </div>
  119. @endsection
  120. @section('lastScript')
  121. <script>
  122. new Vue({
  123. el: '#app',
  124. data:{
  125. focusing:'document',
  126. commitButtonVisible:false,
  127. isManualInputtingBarcode:false,
  128. isManualInputtingAmount:true,
  129. lastScannedBarcode:'',
  130. inputMode:'regular',//regular,increasing,multiIncreasing
  131. inputting:{
  132. barcode:'',amount:'',bin:'',produce_date:'',valid_date:'',batch_number:'',fromIncreasing:false,unique_code:''
  133. },
  134. status:{
  135. scanEndInputted:false,binDisable:false,barcodeDisable:true,amountDisable:false,
  136. },
  137. goodses:[],//{barcode,amount,bin,produce_date,valid_date,batch_number}
  138. selectTr:0,
  139. },
  140. mounted() {
  141. this.scanListening();
  142. },
  143. methods: {
  144. changeToManualInputAmount:function(){
  145. this.status.amountDisable=false;
  146. this.isManualInputtingAmount=true;
  147. $('#amountLabel').text('输入数量:');
  148. // $('#amount').attr('placeholder','数字');
  149. },
  150. changeToScanInputAmount:function(){
  151. this.status.amountDisable=true;
  152. this.isManualInputtingAmount=false;
  153. $('#amountLabel').text('自动扫入数量:');
  154. // $('#amount').attr('placeholder','自动');
  155. },
  156. changeToManualInputBarcode:function(){
  157. this.status.barcodeDisable=false;
  158. this.isManualInputtingBarcode=true;
  159. $('#barcode').attr('placeholder','手工输入条码');
  160. },
  161. changeToScanInputBarcode:function(){
  162. let data = this;
  163. this.isManualInputtingBarcode=false;
  164. this.inputting.barcode='';
  165. let $barcode = $('#barcode');
  166. this.status.barcodeDisable=false;
  167. setTimeout(function () {
  168. $barcode.focus();
  169. data.status.barcodeDisable=true;
  170. },20);
  171. $barcode.attr('placeholder','扫入条码');
  172. },
  173. oninputEnter:function(e){
  174. if (e.key === 'Enter') {
  175. this.focusDocument();
  176. }
  177. },
  178. focusDocument: function () {
  179. this.focusing = 'document';
  180. this.showCommitButton();
  181. },
  182. focusOutDocument: function () {
  183. this.focusing = '';
  184. this.autoFillBin();
  185. },
  186. scanListening: function () {
  187. let data = this;
  188. $(document).on('keypress', function (e) {
  189. if(data.focusing!=='document'){return}
  190. if(data.isManualInputtingBarcode){return}
  191. if (e.keyCode !== 13) {
  192. if(data.status.scanEndInputted){
  193. data.lastScannedBarcode=data.inputting.barcode;
  194. data.inputting.barcode='';
  195. data.status.scanEndInputted=false;
  196. }
  197. data.inputting.barcode += String.fromCharCode(e.keyCode);
  198. } else {
  199. if(data.inputting.barcode.length<=1){
  200. window.tempTip.setDuration(4500);
  201. window.tempTip.show('未扫入条码,请检查扫码枪设置,尝试调至“直接键盘输出”模式');
  202. return;
  203. }
  204. data.status.scanEndInputted = true;
  205. data.showCommitButton();
  206. data.autoFillBin();
  207. switch(data.inputMode){
  208. case 'increasing': data.commitGoodsOnIncreasingMode();break;
  209. case 'multiIncreasing': data.commitGoodsOnMultiIncreasingMode();break;
  210. }
  211. }
  212. });
  213. },
  214. commitGoodsOnIncreasingMode: function () {
  215. let data = this;
  216. function doIt(){
  217. let repeatedBarcode=data.repeatedIncreasingBarcodeFromSaved();
  218. function increase(){
  219. data.inputting.bin=repeatedBarcode.bin;
  220. repeatedBarcode.amount++;
  221. data.inputting.amount=repeatedBarcode.amount;
  222. window.tempTip.setDuration(500);
  223. window.tempTip.showSuccess(repeatedBarcode.amount);
  224. data.focusDocument();
  225. data.audioDing();
  226. }
  227. if(!repeatedBarcode){
  228. data.focusOutDocument();
  229. data.alertVibrate();
  230. window.tempTip.setInputType('number');
  231. window.tempTip.inputVal('该商品第一件递增请输入隔口号:',function(bin){
  232. if(bin===''){
  233. window.tempTip.setDuration(1500);
  234. window.tempTip.show('未输入隔口号,请重新扫描');
  235. data.alertVibrate();
  236. data.focusDocument();return}
  237. data.inputting.bin=bin;
  238. data.inputting.amount=1;
  239. data.goodses.unshift(JSON.parse(JSON.stringify(data.inputting)));
  240. data.status.binDisable=true;
  241. window.tempTip.setDuration(500);
  242. window.tempTip.showSuccess('保存成功');
  243. data.focusDocument();
  244. data.audioDing();
  245. })
  246. }else{
  247. increase();
  248. }
  249. }
  250. if(data.lastScannedBarcode!==data.inputting.barcode && data.lastScannedBarcode){
  251. data.audioWarning_otherBarcode();
  252. data.focusOutDocument();
  253. window.tempTip.confirm('扫到其它条码,是否切换至新条码并记录?',doIt,function () {
  254. data.inputting.barcode=data.lastScannedBarcode;
  255. // data.cleanInputs();
  256. data.focusDocument();
  257. })
  258. }else{
  259. doIt()
  260. }
  261. },
  262. commitGoodsOnMultiIncreasingMode: function () {
  263. let data = this;
  264. let repeatedBarcode=this.repeatedIncreasingBarcodeFromSaved();
  265. function increase(){
  266. data.inputting.bin=repeatedBarcode.bin;
  267. repeatedBarcode.amount++;
  268. data.inputting.amount=repeatedBarcode.amount;
  269. window.tempTip.setDuration(500);
  270. window.tempTip.showSuccess(repeatedBarcode.amount);
  271. data.focusDocument();
  272. data.audioDing();
  273. }
  274. if(!repeatedBarcode){
  275. data.focusOutDocument();
  276. data.alertVibrate();
  277. window.tempTip.setInputType('number');
  278. window.tempTip.inputVal('该商品第一件递增请输入隔口号:',function(bin){
  279. if(bin===''){
  280. window.tempTip.setDuration(1500);
  281. window.tempTip.show('未输入隔口号,请重新扫描');
  282. data.alertVibrate();
  283. data.focusDocument();return}
  284. data.inputting.bin=bin;
  285. data.inputting.amount=1;
  286. data.goodses.unshift(JSON.parse(JSON.stringify(data.inputting)));
  287. data.status.binDisable=true;
  288. window.tempTip.setDuration(500);
  289. window.tempTip.showSuccess('保存成功');
  290. data.focusDocument();
  291. data.audioDing();
  292. })
  293. }else{
  294. increase();
  295. }
  296. },
  297. audioWarning_otherBarcode: function () {
  298. let audio = document.getElementById('soundWarning');
  299. audio.currentTime = 0;//重新播放
  300. if(audio.paused){
  301. audio.play();// 播放
  302. }
  303. this.alertVibrate();
  304. },
  305. audioDing: function () {
  306. let audio = document.getElementById('soundDing');
  307. audio.currentTime = 0;//重新播放
  308. audio.play();// 播放
  309. function startVibrate(duration) {
  310. if (navigator.vibrate) {
  311. navigator.vibrate(duration);
  312. } else if (navigator.webkitVibrate) {
  313. navigator.webkitVibrate(duration);
  314. }
  315. }
  316. startVibrate(500);
  317. },
  318. alertVibrate: function () {
  319. function startVibrate(duration) {
  320. if (navigator.vibrate) {
  321. navigator.vibrate(duration);
  322. } else if (navigator.webkitVibrate) {
  323. navigator.webkitVibrate(duration);
  324. }
  325. }
  326. let vibrateInterval = setInterval(function() {
  327. startVibrate(150);
  328. }, 50);
  329. setTimeout(function() {
  330. clearInterval(vibrateInterval)
  331. }, 2000);
  332. },
  333. autoFillBin: function () {
  334. let data = this;
  335. let isNotRepeatingBarcode=this.goodses.every(function(goods){
  336. if(goods.barcode===data.inputting.barcode){
  337. data.inputting.bin=goods.bin;
  338. data.status.binDisable=true;
  339. return false;
  340. }
  341. return true;
  342. });
  343. if(isNotRepeatingBarcode){
  344. data.status.binDisable=false;
  345. }
  346. },
  347. repeatedIncreasingBarcodeFromSaved: function () {
  348. let data = this;
  349. let repeatedGoods=null;
  350. data.goodses.every(function(goods){
  351. if(goods.barcode===data.inputting.barcode && goods.fromIncreasing){
  352. repeatedGoods=goods;
  353. return false;
  354. }
  355. return true;
  356. });
  357. return repeatedGoods;
  358. },
  359. commitGoods: function () {
  360. let data = this;
  361. window.tempTip.setDuration(3500);
  362. if(!data.inputting.barcode){window.tempTip.show('请扫入条码');return;}
  363. else if(!data.inputting.amount){window.tempTip.show('请输入数量');return;}
  364. //else if(!data.inputting.bin){window.tempTip.show('请输入隔口号');return;}
  365. data.recordOrPlusGoods();
  366. window.tempTip.setDuration(1500);
  367. window.tempTip.showSuccess('成功提交:' + data.inputting.barcode);
  368. data.cleanInputs();
  369. data.audioDing();
  370. },
  371. cleanInputs: function () {
  372. this.changeToScanInputBarcode();
  373. this.inputting.barcode='';
  374. this.inputting.amount='';
  375. this.inputting.bin='';
  376. this.inputting.produce_date='';
  377. this.inputting.valid_date='';
  378. this.inputting.batch_number='';
  379. this.inputting.unique_code='';
  380. this.commitButtonVisible=false;
  381. this.status.binDisable=false;
  382. this.lastScannedBarcode='';
  383. },
  384. recordOrPlusGoods: function () {
  385. let data = this;
  386. if(this.inputMode==='regular'){
  387. data.goodses.unshift(JSON.parse(JSON.stringify(data.inputting)));
  388. return;
  389. }
  390. let isNotRepeating=data.goodses.every(function(goods){
  391. if(goods.barcode===data.inputting.barcode){
  392. goods.amount=parseInt(goods.amount)+parseInt(data.inputting.amount);
  393. return false;
  394. }
  395. return true;
  396. });
  397. if(isNotRepeating){
  398. data.goodses.unshift(JSON.parse(JSON.stringify(data.inputting)));
  399. }
  400. },
  401. removeGoods: function ($e,barcode) {
  402. if(!confirm('确定要删除条码为'+barcode+'的记录吗'))return;
  403. let data = this;
  404. data.goodses.every(function(goods,i){
  405. if(goods.barcode===barcode){
  406. data.goodses.splice(i,1)
  407. return false;
  408. }
  409. return true;
  410. })
  411. },
  412. showCommitButton: function () {
  413. let data = this;
  414. if(data.inputting.barcode && data.inputting.amount /*&& data.inputting.bin*/){
  415. data.commitButtonVisible=true;
  416. }else{
  417. if (this.inputMode==='regular' && this.status.barcodeDisable && !this.inputting.amount && this.inputting.barcode){
  418. this.focusing = '';
  419. document.getElementById('amount').focus();
  420. }
  421. }
  422. },
  423. submitExcelData: function () {
  424. let data = this;
  425. data.focusOutDocument();
  426. if(data.goodses.length===0){
  427. window.tempTip.show('请先录入数据再提交EXCEL');return;
  428. }
  429. window.tempTip.confirm('请检查表格,确定全部完成。提交后数据将全部清空,不能后退',
  430. function () {
  431. window.tempTip.setInputType('input');
  432. window.tempTip.setIndex(999999);
  433. window.tempTip.inputVal('请输入文件名:',function(val){
  434. if(val===''){
  435. window.tempTip.setDuration(2500);
  436. window.tempTip.show('失败!文件名不能为空,请重新点击生成');
  437. return;
  438. }
  439. window.tempTip.setDuration(15500);
  440. window.tempTip.waitingTip('提交Excel中...');
  441. let expireHandler = setTimeout(function () {
  442. window.tempTip.cancelWaitingTip();
  443. window.tempTip.setDuration(1500);
  444. window.tempTip.show('响应超时! 请检查网络,确保可以连接后再重试。');
  445. },9000);
  446. let url='{{url("store/blindReceive/excels/apiStore")}}';
  447. axios.post(url,{'goodses':data.goodses,'filename':val})
  448. .then(function(response){
  449. if(response.data.result==='success'){
  450. data.goodses=[];
  451. data.cleanInputs();
  452. window.tempTip.cancelWaitingTip();
  453. window.tempTip.setDuration(1500);
  454. window.tempTip.showSuccess('成功生成EXCEL,可在列表页查看');
  455. data.focusDocument();
  456. }else{
  457. window.tempTip.setDuration(1500);
  458. window.tempTip.show('生成EXCEL失败:'+response.data.fail_info);
  459. console.log(response);
  460. data.focusDocument();
  461. data.alertVibrate()
  462. }
  463. clearInterval(expireHandler);
  464. })
  465. .catch(function (err) {
  466. window.tempTip.setDuration(3500);
  467. window.tempTip.show('网络或系统错误,请将以下信息提交给开发者:'+err);
  468. clearInterval(expireHandler);
  469. data.alertVibrate();
  470. });
  471. });
  472. },function () {
  473. data.focusDocument();
  474. })
  475. }
  476. },
  477. computed: {
  478. borderByMode: function () {
  479. return {
  480. // 'border-info':this.inputMode==='regular',
  481. 'border-success':this.inputMode==='increasing',
  482. 'border-danger':this.inputMode==='multiIncreasing'
  483. }
  484. }
  485. }
  486. });
  487. </script>
  488. @endsection