Sfoglia il codice sorgente

Merge branch 'countGoodsAndReceived' into Haozi

# Conflicts:
#	app/Http/Controllers/TestController.php
haozi 4 anni fa
parent
commit
738f95c16e

+ 3 - 1
app/Http/Controllers/StoreBlindReceiveController.php

@@ -12,7 +12,9 @@ class StoreBlindReceiveController extends Controller
 {
     public function index()
     {
-        $excels=InventoryBlindReceiveExcel::orderBy('id','desc')->get();
+        $excels=InventoryBlindReceiveExcel::query()
+            ->where('name','not like','清点%')
+            ->orderByDesc('id')->get();
         return view('store.blindReceive.excel.index',['excels'=>$excels]);
     }
     public function create()

+ 145 - 0
app/Http/Controllers/StoreCountGoodsAndReceiveController.php

@@ -0,0 +1,145 @@
+<?php
+
+namespace App\Http\Controllers;
+
+use App\Components\AsyncResponse;
+use App\Exports\InventoryBlindReceiveExcelExport;
+use App\InventoryBlindReceiveExcel;
+use App\OracleDOCASNDetail;
+use App\Services\HandInStorageService;
+use Carbon\Carbon;
+use Doctrine\DBAL\Exception;
+use Doctrine\DBAL\Exception\DatabaseObjectExistsException;
+use Illuminate\Http\Request;
+use Illuminate\Support\Facades\Auth;
+use Illuminate\Support\Facades\Cache;
+use Maatwebsite\Excel\Facades\Excel;
+
+class StoreCountGoodsAndReceiveController extends Controller
+{
+    use AsyncResponse;
+
+    public function index()
+    {
+        /** @var HandInStorageService $handInStorageService  */
+        $handInStorageService=app('HandInStorageService');
+        $qualityStatus=$handInStorageService->getQualityStatus();
+        $attributeLocations=$handInStorageService->getAttributeLocation();
+        return view('store.countGoodsAndReceive.index',
+            compact('qualityStatus','attributeLocations'));
+    }
+    public function excel()
+    {
+        $excels=InventoryBlindReceiveExcel::query()
+            ->where('name','like','清点%')
+            ->orderByDesc('id')->get();
+        return view('store.countGoodsAndReceive.excel',['excels'=>$excels]);
+    }
+
+    public function createExcel(Request $request): array
+    {
+        $goodses=$request->input('goodses')??'';
+        $excelFileName=$request->input('filename')??'';
+        if(!$goodses||!is_array($goodses)||count($goodses)==0){
+            return ['result'=>'failure','fail_info'=>'没有数据提交!'];
+        }
+        $goodsExcelArray=[['条码','数量','箱号']];
+        foreach ($goodses as $goods){
+            array_push($goodsExcelArray,[$goods['barcode'],$goods['amount'],$goods['cast_number']]);
+        }
+        $fileName=Carbon::now()->toDateTimeLocalString().'.xlsx';
+        $fileName = str_replace( ':', '_',$fileName);
+        $goodsNeateningExcel = new InventoryBlindReceiveExcel(['file' => $fileName, 'goods_amount' => count($goodses), 'name'=>'清点_'.$excelFileName]);
+        $goodsNeateningExcel->save();
+        Excel::store(new InventoryBlindReceiveExcelExport($goodsExcelArray),$fileName,'public');
+        $this->removeExpiredExcel();
+        return ['result'=>'success'];
+    }
+    private function removeExpiredExcel(){
+        $excels=InventoryBlindReceiveExcel::query()->where('created_at','<',Carbon::now()->subDays(100)->toDateTimeString())->get();
+        $excels->each(
+            /** @throws \Exception */
+            function(InventoryBlindReceiveExcel $excel){
+            $excel->delete();
+        });
+    }
+
+    public function getReceiveTaskByAsnNoAndBarcodes(Request $request)
+    {
+        $asnno=$request->input('asnno');
+        $goods=$request->input('goods');
+        $asnDetails=OracleDOCASNDetail::query()
+            ->select('asnno','asnlineno','customerid','sku','expectedqty','receivedqty_each',
+                'lotatt01','lotatt02','lotatt03','lotatt04','lotatt05','lotatt08')
+            ->with('basSku.lotId')
+            ->where('asnno',$asnno)
+            ->whereIn('linestatus', ['00', '30'])
+            ->get();
+        $status=false;
+       foreach ($goods as &$good){
+           foreach ($asnDetails as $asnDetail){
+               if (!$asnDetail['basSku']??false)continue;
+               if ($good['sku']==$asnDetail['basSku']['alternate_sku1']
+               ||$good['sku']==$asnDetail['basSku']['alternate_sku2']
+               ||$good['sku']==$asnDetail['basSku']['alternate_sku3']){
+                   $good['basSku']=$asnDetail['basSku'];
+                   $good['customerid']=$asnDetail['customerid'];
+                   $good['asn_amount']=($asnDetail['expectedqty']-$asnDetail['receivedqty_each']);
+                   $good['diff_val']=($good['asn_amount']-$good['amount']);
+                   $good['receiveStatus']=true;
+                   $status=true;
+                   $good['asnlineno']=$asnDetail['asnlineno'];
+                   $good['lotatt01']=$asnDetail['lotatt01'];
+                   $good['lotatt02']=$asnDetail['lotatt02'];
+                   $good['lotatt03']=$asnDetail['lotatt03'];
+                   $good['lotatt04']=$asnDetail['lotatt04'];
+                   $good['lotatt05']=$asnDetail['lotatt05'];
+                   $good['lotatt08']=$asnDetail['lotatt08'];
+               }
+           }
+       }
+       if ($status)$this->success($goods);
+        else $this->error('当前ASN单号未查询到下述商品信息!');
+    }
+
+    public function fluxReceive(Request $request)
+    {
+        $info=$request->input('good');
+        $isSku=$info['sku']??false;
+        if ($info['lotatt02']&&Carbon::now()->gt($info['lotatt02']))$this->error('失效日期超过入库效期');
+        if (!$info['customerid']||$isSku===false||!$info['asnno']) $this->error('参数错误');
+        /** @var HandInStorageService $handInStorageService  */
+        $handInStorageService=app('HandInStorageService');
+        if ($info['customerid']=='ONKYO'||$info['customerid']=='ANMEILAI'||$info['customerid']=='FEIHE'){
+            $res=$handInStorageService->checkWidthHeight($info);
+            if ($res===1)$this->error('需要维护产品档案');
+            if ($res===2)$this->error('需要维护该产品档案中的长宽高');
+        }
+        if ($info['customerid']=='TANGENBEI'||$info['customerid']=='ANMEILAI'){
+            $result=$handInStorageService->checkCubicWeight($info);
+            if ($result===1)$this->error('需要维护产品档案');
+            if ($result===2)$this->error('需要维护该产品档案中的重量体积');
+        }
+        if ($info['customerid']=='JIANSHANG'&&$handInStorageService->checkForwardingLoc($info)===1)$this->error('请维护拣货位');
+        $key = $info['asnno'] . '_' . $info['sku'] . '_' . Auth::id();
+        $ttl = 10;
+        try {
+            //缓存校验操作
+            if (Cache::has($key)){
+                $this->error('当前已操作');
+            }else{
+                Cache::put($key,true, $ttl);
+            }
+            //收货操作
+            $resultIn = $handInStorageService->fluxHandIn($info);
+            if ($resultIn===1)$this->error("超收");
+            if ($resultIn){
+                $this->success('收货成功');
+            } else $this->error("收货失败");
+        } catch (\Exception $e) {
+            app('LogService')->log(__METHOD__,'error_'.__FUNCTION__,json_encode($info).'|catch:'.$e->getMessage());
+        } finally {
+            Cache::forget($key);
+        }
+    }
+}

+ 1 - 0
app/Http/Controllers/TestController.php

@@ -39,6 +39,7 @@ use App\Logistic;
 use App\MaterialBox;
 use App\MaterialBoxModel;
 use App\Notifications\RoutineNotification;
+use App\OracleDOCASNDetail;
 use App\OracleDOCASNHeader;
 use App\OracleDOCOrderHeader;
 use App\OracleDocOrderPackingSummary;

+ 1 - 1
app/OracleBasSKU.php

@@ -10,9 +10,9 @@ use Illuminate\Database\Eloquent\Model;
  */
 use App\Traits\ModelTimeFormat;
 use App\Traits\ModelLogChanging;
-
 class OracleBasSKU extends Model
 {
+    use \Awobaz\Compoships\Compoships;
     use ModelLogChanging;
 
     use ModelTimeFormat;

+ 7 - 0
app/OracleDOCASNDetail.php

@@ -9,6 +9,7 @@ use App\Traits\ModelLogChanging;
 
 class OracleDOCASNDetail extends Model
 {
+    use \Awobaz\Compoships\Compoships;
     use ModelLogChanging;
 
     use ModelTimeFormat;
@@ -29,4 +30,10 @@ class OracleDOCASNDetail extends Model
         return $this->hasOne(OracleBasCode::class,'code','lotatt08')
             ->where('codeid','QLT_STS');
     }
+    public function basSku()
+    {
+        return $this->hasOne(OracleBasSKU::class,['customerid','sku'],['customerid','sku'])
+            ->select('customerid','sku','lotid','alternate_sku1','alternate_sku2','alternate_sku3');
+
+    }
 }

+ 3 - 2
composer.json

@@ -12,8 +12,10 @@
         "ext-bcmath": "*",
         "ext-json": "*",
         "ext-mbstring": "*",
+        "ext-oci8": "*",
         "ext-openssl": "*",
         "ext-pdo": "*",
+        "awobaz/compoships": "^2.1",
         "doctrine/dbal": "^2.10",
         "endroid/qr-code": "^3.7",
         "facade/ignition": "^2.0",
@@ -33,8 +35,7 @@
         "predis/predis": "^1.1",
         "pusher/pusher-php-server": "^4.1",
         "te7a-houdini/laravel-trix": "^2.0",
-        "yajra/laravel-oci8": "7.0",
-        "ext-oci8": "*"
+        "yajra/laravel-oci8": "7.0"
     },
     "require-dev": {
         "barryvdh/laravel-debugbar": "^3.2",

+ 63 - 3
composer.lock

@@ -4,8 +4,68 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
         "This file is @generated automatically"
     ],
-    "content-hash": "5dc450e032b783ab6f83fb3d7348eb9e",
+    "content-hash": "a8a45b0f4001cb3c8e61821f0cc50383",
     "packages": [
+        {
+            "name": "awobaz/compoships",
+            "version": "2.1.2",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/topclaudy/compoships.git",
+                "reference": "df6a9eb558d03c2c8be2ebb07e277568eb3302c0"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/topclaudy/compoships/zipball/df6a9eb558d03c2c8be2ebb07e277568eb3302c0",
+                "reference": "df6a9eb558d03c2c8be2ebb07e277568eb3302c0",
+                "shasum": ""
+            },
+            "require": {
+                "illuminate/database": ">=5.6 <9.0"
+            },
+            "require-dev": {
+                "ext-sqlite3": "*"
+            },
+            "suggest": {
+                "awobaz/blade-active": "Blade directives for the Laravel 'Active' package",
+                "awobaz/eloquent-auto-append": "Automatically append accessors to model serialization",
+                "awobaz/eloquent-mutators": "Reusable mutators (getters/setters) for Laravel 5's Eloquent",
+                "awobaz/syntactic": "Syntactic sugar for named and indexed parameters call."
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Awobaz\\Compoships\\": "src"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Claudin J. Daniel",
+                    "email": "cdaniel@awobaz.com"
+                }
+            ],
+            "description": "Laravel relationships with support for composite/multiple keys",
+            "keywords": [
+                "laravel",
+                "laravel composite keys",
+                "laravel relationships"
+            ],
+            "support": {
+                "issues": "https://github.com/topclaudy/compoships/issues",
+                "source": "https://github.com/topclaudy/compoships/tree/2.1.2"
+            },
+            "funding": [
+                {
+                    "url": "https://paypal.me/awobaz",
+                    "type": "custom"
+                }
+            ],
+            "time": "2021-09-04T16:00:10+00:00"
+        },
         {
             "name": "bacon/bacon-qr-code",
             "version": "2.0.4",
@@ -10515,9 +10575,9 @@
         "ext-bcmath": "*",
         "ext-json": "*",
         "ext-mbstring": "*",
+        "ext-oci8": "*",
         "ext-openssl": "*",
-        "ext-pdo": "*",
-        "ext-oci8": "*"
+        "ext-pdo": "*"
     },
     "platform-dev": [],
     "platform-overrides": {

+ 31 - 0
resources/views/store/countGoodsAndReceive/excel.blade.php

@@ -0,0 +1,31 @@
+@extends('layouts.app')
+@section('title')点收一体-表格@endsection
+
+
+@section('content')
+    <div class="container">
+        <div class="row mt-2">
+            <div class="col-12">
+                <p><span class="h4">Excel文件列表</span><span class="text-muted">(仅保留三个月以内的文件)</span></p>
+                <table class="table table-striped" >
+                    <tr>
+                        <th>序号</th>
+                        <th>名称</th>
+                        <th>时间</th>
+                        <th>条目数</th>
+                        <th>文件下载</th>
+                    </tr>
+                    @foreach($excels as $i=>$excel)
+                        <tr>
+                            <td>{{$i+1}}</td>
+                            <td>{{$excel['name']}}</td>
+                            <td>{{$excel['created_at']}}</td>
+                            <td>{{$excel['goods_amount']}}</td>
+                            <td><a href="{{asset('storage/'.$excel['file'])}}"><span class="fa fa-download"></span><span class="fa fa-download"></span><span class="fa fa-download"></span></a></td>
+                        </tr>
+                    @endforeach
+                </table>
+            </div>
+        </div>
+    </div>
+@endsection

+ 504 - 0
resources/views/store/countGoodsAndReceive/index.blade.php

@@ -0,0 +1,504 @@
+@extends('layouts.app')
+@section('title')点收一体@endsection
+
+@section('content')
+    <div class="d-none" id="container">
+        <audio src="{{asset('sound/warning_otherBarcode.mp3')}}" controls="controls" preload id="soundWarning" hidden>
+        </audio>
+        <audio src="{{asset('sound/ding.mp3')}}" controls="controls" preload id="soundDing" hidden>
+        </audio>
+        <div class="row">
+            <div class="col-4 p-0 m-0" id="countGoods">
+                <div class="col-12 text-center bg-white mt-2">
+                    <h4 class="font-weight-bold text-dark">清点模式</h4>
+                </div>
+                    <div class="card-body">
+                            <div class="row pl-5">
+                                <div class="col-6">
+                                    <label class="text-left font-weight-bold text-muted">条码</label>
+                                    <input type="text" id="barcode" class="form-control" :disabled="status.barcodeDisable" placeholder="扫入条码"
+                                           @focusin="focusOutDocument" @focusout="focusDocument" v-model="inputting.barcode">
+                                </div>
+
+                                <div v-if="inputMode==='sweepModel'" class="col-6">
+                                    <label class="text-left font-weight-bold text-muted">已扫数量</label>
+                                    <input type="number" id="amount" class="form-control mt-0" placeholder="" :disabled="status.amountDisable"
+                                           v-model="inputting.amount" style='height: 40px;font-size: 1.6em;color:blue;font-weight: bolder;padding: 3px;text-align: center'>
+                                </div>
+                            </div>
+                        <p class="card-text text-muted mt-3 mb-n3 text-center">已完成:</p>
+                        <hr>
+                        <table class="table table-sm table-striped table-bordered" v-if="goodses.length>0">
+                            <tr>
+                                <th class="text-center">条码</th>
+                                <th class="text-center">数量</th>
+                                <th class="text-center">箱规</th>
+                                <th class="text-center">操作</th>
+                            </tr>
+                            <tr v-for="(goods,i) in goodses" :id="'tr_'+i">
+                                <td class="text-center">@{{ goods.barcode }}</td>
+                                <td class="text-center">@{{ goods.amount }}</td>
+                                <td class="text-center">
+                                    <span v-if="goods.cast_number">第@{{ goods.cast_number }}箱</span>
+                                </td>
+                                <td class="text-center">
+                                    <span v-if="goods.countGoodStatus">
+                                        <button class="btn btn-outline-info btn-sm" @click="countGoods(i,goods.barcode)">完成清点</button>
+                                    </span>
+                                    <button class="btn btn-outline-danger btn-sm" @click="removeGoods($event,goods.barcode)">删</button>
+                                </td>
+                            </tr>
+                        </table>
+                        <hr>
+                        <span class="btn btn-outline-dark btn form-control" style="cursor: pointer" @click="submitExcelData">结束清点</span>
+                    </div>
+            </div>
+            <div class="col-8 p-0 m-0" id="receive">
+                <div class="col-12 text-center bg-white mt-2">
+                    <h4 class="font-weight-bold text-dark">收货模式</h4>
+                </div>
+                <div class="card-body m-0">
+                        <div class="col-8 offset-2 row">
+                             <label for="asnno" class="font-weight-bold text-muted ">输入ASN</label>
+                            <input type="text" id="asnno" class="form-control" @focusin="focusOutDocument" autocomplete="off"
+                                   @change="getReceiveTaskByAsnNoAndBarcodes()" disabled="true" placeholder="ASN单号" v-model="asnno">
+                        </div>
+                    <table class="table table-sm table-striped" v-if="regroupGoods.length>0">
+                        <hr>
+                        <tr>
+                            <th class="text-center">货主</th>
+                            <th class="text-center">条码</th>
+                            <th class="text-center">清点数量</th>
+                            <th class="text-center">ASN数量</th>
+                            <th class="text-center">差值</th>
+                            <th class="text-center">容器号</th>
+                            <th class="text-center">生产日期</th> <!--lotatt01-->
+                            <th class="text-center">失效日期</th> <!--lotatt02-->
+                            <th class="text-center">批号</th>    <!--lotatt04-->
+                            <th class="text-center">属性仓</th>  <!--lotatt05-->
+                            <th class="text-center">质量状态</th> <!--lotatt08-->
+                            <th class="text-center">入库日期</th> <!--lotatt03-->
+                            <th class="text-center">操作</th>
+                        </tr>
+                        <tr v-for="(goods,i) in regroupGoods">
+                            <td class="text-center">@{{ goods.customerid }}</td>
+                            <td class="text-center">@{{ goods.sku }}</td>
+                            <td class="text-center">@{{ goods.amount }}</td>
+                            <td class="text-center">@{{ goods.asn_amount }}</td>
+                            <td class="text-center">@{{ goods.diff_val }}</td>
+
+                            <td class="text-center">
+                                <span v-if="goods.receiveStatus">
+                                    <input type="text" autocomplete="off" class="form-control form-control-sm" :class="errors.trackNumber ? 'is-invalid' : ''"
+                                           id="trackNumber" v-model="goods.trackNumber">
+                                    <span class="invalid-feedback offset-3" role="alert" v-if="errors.trackNumber">
+                                        <strong>@{{ errors.trackNumber[0] }}</strong>
+                                    </span>
+                                </span>
+                            </td>
+
+                            <td class="text-center">
+                                <span v-if="goods.basSku.lot_id">
+                                    <input type="date" autocomplete="off" class="form-control form-control-sm input-sm" :class="errors.lotatt01 ? 'is-invalid' : ''"
+                                           :disabled="goods.basSku.lot_id.lotkey01==='N'"  id="lotatt01" v-model="goods.lotatt01">
+                                     <span class="invalid-feedback offset-3" role="alert" v-if="errors.lotatt01">
+                                        <strong>@{{ errors.lotatt01[0] }}</strong>
+                                    </span>
+                                </span>
+                            </td>
+                            <td class="text-center">
+                               <span v-if="goods.basSku.lot_id">
+                                    <input type="date" autocomplete="off" class="form-control form-control-sm input-sm" :class="errors.lotatt02 ? 'is-invalid' : ''"
+                                           :disabled="goods.basSku.lot_id.lotkey02==='N'"  id="lotatt02" v-model="goods.lotatt02">
+                                    <span class="invalid-feedback offset-3" role="alert" v-if="errors.lotatt02">
+                                        <strong>@{{ errors.lotatt02[0] }}</strong>
+                                    </span>
+                                </span>
+                            </td>
+                            <td class="text-center">
+                                <span v-if="goods.basSku.lot_id">
+                                    <input type="text" autocomplete="off" class="form-control form-control-sm input-sm" :class="errors.lotatt04 ? 'is-invalid' : ''"
+                                           :disabled="goods.basSku.lot_id.lotkey04==='N'"  id="lotatt04" v-model="goods.lotatt04">
+                                     <span class="invalid-feedback offset-3" role="alert" v-if="errors.lotatt04">
+                                        <strong>@{{ errors.lotatt04[0] }}</strong>
+                                    </span>
+                                </span>
+                            </td>
+                            <td class="text-center">
+                                <span v-if="goods.basSku.lot_id">
+                                    <select class="form-control form-control-sm" :disabled="goods.basSku.lot_id.lotkey05==='N'"
+                                            id="lotatt05" v-model="goods.lotatt05" :class="errors.lotatt05 ? 'is-invalid' : ''">
+                                        <option v-for="(attributeLocation,i) in attributeLocations"
+                                            :value="attributeLocation.code">@{{ attributeLocation.codename_c }}</option>
+                                    </select>
+                                     <span class="invalid-feedback offset-3" role="alert" v-if="errors.lotatt05">
+                                        <strong>@{{ errors.lotatt05[0] }}</strong>
+                                    </span>
+                                </span>
+                            </td>
+                            <td class="text-center">
+                                <span v-if="goods.basSku.lot_id">
+                                     <select class="form-control form-control-sm" :class="errors.lotatt08 ? 'is-invalid' : ''"
+                                             :disabled="goods.basSku.lot_id.lotkey08==='N'" id="lotatt08" v-model="goods.lotatt08">
+                                        <option v-for="(quality,i) in qualityStatus"  :value="quality.code">@{{ quality.codename_c }}</option>
+                                    </select>
+                                     <span class="invalid-feedback offset-3" role="alert" v-if="errors.lotatt08">
+                                        <strong>@{{ errors.lotatt08[0] }}</strong>
+                                    </span>
+                                </span>
+                            </td>
+                            <td class="text-center">
+                                <span v-if="goods.basSku.lot_id">
+                                    <input type="date" autocomplete="off" class="form-control form-control-sm input-sm" :class="errors.lotatt03 ? 'is-invalid' : ''"
+                                           :disabled="goods.basSku.lot_id.lotkey03==='N'"  id="lotatt03" v-model="goods.lotatt03">
+                                     <span class="invalid-feedback offset-3" role="alert" v-if="errors.lotatt03">
+                                        <strong>@{{ errors.lotatt03[0] }}</strong>
+                                    </span>
+                                </span>
+                            </td>
+                            <td class="text-center">
+                                <span v-if="goods.receiveStatus&&goods.diff_val>=0">
+                                    <button class="btn btn-outline-info btn-sm" @click="receiveGoods(goods)">收</button>
+                                </span>
+                            </td>
+                        </tr>
+                    </table>
+                    <span class="btn btn-outline-dark btn form-control mt-5" v-if="status.finishReceiveButton"
+                          style="cursor: pointer" @click="finishReceive()">结束收货</span>
+                </div>
+            </div>
+        </div>
+    </div>
+@endsection
+
+@section('lastScript')
+    <script>
+        new Vue({
+            el: '#app',
+            data:{
+                qualityStatus:{!! $qualityStatus !!},
+                attributeLocations:{!! $attributeLocations !!},
+                focusing:'document',
+                lastScannedBarcode:'',
+                inputMode:'sweepModel',
+                inputting:{
+                    barcode:'',amount:'',fromIncreasing:true,cast_number:'',countGoodStatus:true
+                },
+                status:{
+                    scanEndInputted:false,barcodeDisable:true,amountDisable:true,finishReceiveButton:false,
+                },
+                asnno:'',
+                basSku:{
+                    lot_id:'',
+                },
+                goodses:[],
+                initGoods:[],
+                regroupGoods:[],
+                errors:{},
+            },
+            mounted() {
+                if (navigator.userAgent.indexOf("Android")!==-1)this.isAndroid = true;
+                this.pageInit();
+                $("#container").removeClass("d-none");
+                this.scanListening();
+            },
+            methods: {
+                //页面初始化
+                pageInit(){
+                    if (!this.isAndroid)return;
+                    let element = document.getElementById("navbarSupportedContent").parentElement;
+                    element.className = "row";
+                    element.children[0].className += " col-5";
+                    element.innerHTML = element.children[0].outerHTML;
+                    let e1 = document.getElementById("menu");
+                    let e2 = document.getElementById("demand-div");
+                    if (e1)e1.remove();
+                    if (e2)e2.remove();
+                },
+                focusDocument: function () {
+                    this.focusing = 'document';
+                },
+                focusOutDocument: function () {
+                    this.focusing = '';
+                },
+                scanListening: function () {
+                    let data = this;
+                    $(document).on('keypress', function (e) {
+                        if(data.focusing!=='document'){return}
+                        if (e.keyCode !== 13) {
+                            if(data.status.scanEndInputted){
+                                data.lastScannedBarcode=data.inputting.barcode;
+                                data.inputting.barcode='';
+                                data.status.scanEndInputted=false;
+                            }
+                            data.inputting.barcode += String.fromCharCode(e.keyCode);
+                        } else {
+                            if(data.inputting.barcode.length<=1){
+                                window.tempTip.setDuration(4500);
+                                window.tempTip.show('未扫入条码,请检查扫码枪设置,尝试调至“直接键盘输出”模式');
+                                return;
+                            }
+                            data.status.scanEndInputted = true;
+                            switch(data.inputMode){
+                                case 'sweepModel': data.commitGoodsOnSweepModel();break;
+                            }
+                        }
+                    });
+                },
+                commitGoodsOnSweepModel(){
+                    let repeatedBarcode=this.repeatedIncreasingBarcodeFromSaved();
+                    if(!repeatedBarcode){
+                        this.focusOutDocument();
+                        this.alertVibrate();
+                        this.inputting.amount=1;
+                        this.goodses.unshift(JSON.parse(JSON.stringify(this.inputting)));
+                        window.tempTip.setDuration(500);
+                        window.tempTip.showSuccess('保存成功');
+                        this.focusDocument();
+                        this.audioDing();
+                    }else{
+                        repeatedBarcode.amount++;
+                        this.inputting.amount=repeatedBarcode.amount;
+                        window.tempTip.setDuration(500);
+                        window.tempTip.showSuccess(repeatedBarcode.amount);
+                        this.focusDocument();
+                        this.audioDing();
+                    }
+                },
+                audioDing: function () {
+                    let audio = document.getElementById('soundDing');
+                    audio.currentTime = 0;//重新播放
+                    audio.play();// 播放
+                    function startVibrate(duration) {
+                        if (navigator.vibrate) {
+                            navigator.vibrate(duration);
+                        } else if (navigator.webkitVibrate) {
+                            navigator.webkitVibrate(duration);
+                        }
+                    }
+                    startVibrate(500);
+                },
+                alertVibrate: function () {
+                    function startVibrate(duration) {
+                        if (navigator.vibrate) {
+                            navigator.vibrate(duration);
+                        } else if (navigator.webkitVibrate) {
+                            navigator.webkitVibrate(duration);
+                        }
+                    }
+                    let vibrateInterval = setInterval(function() {
+                        startVibrate(150);
+                    }, 50);
+                    setTimeout(function() {
+                        clearInterval(vibrateInterval)
+                    }, 2000);
+                },
+                repeatedIncreasingBarcodeFromSaved: function () {
+                    let data = this;
+                    let repeatedGoods=null;
+                    data.goodses.every(function(goods){
+                        if(goods.barcode===data.inputting.barcode && goods.fromIncreasing && goods.countGoodStatus){
+                            repeatedGoods=goods;
+                            return false;
+                        }
+                        return true;
+                    });
+                    return repeatedGoods;
+                },
+                cleanInputs: function () {
+                    this.inputting.barcode='';
+                    this.inputting.amount='';
+                    this.inputting.cast_number='';
+                    this.lastScannedBarcode='';
+                },
+                countGoods: function (i,barcode) {
+                    if(!confirm('确定要结束清点'+barcode+'的记录吗'))return;
+                    let data = this;
+                    let cast_number=0;
+                    data.goodses.forEach(function (goods) {
+                        if (goods.barcode===barcode)cast_number++
+                    });
+
+                    data.goodses.every(function(goods,i){
+                        if(goods.barcode===barcode &&goods.countGoodStatus){
+                            goods.countGoodStatus=false;
+                            goods.cast_number=cast_number;
+                            return false;
+                        }
+                        return true;
+                    })
+
+                    $('#tr_'+i).attr("class",'alert alert-dark');
+                },
+                removeGoods: function ($e,barcode) {
+                    if(!confirm('确定要删除条码为'+barcode+'的记录吗'))return;
+                    let data = this;
+                    data.goodses.every(function(goods,i){
+                        if(goods.barcode===barcode){
+                            data.goodses.splice(i,1)
+                            return false;
+                        }
+                        return true;
+                    })
+                },
+                regroupArr(arr){
+                    let a =JSON.parse(JSON.stringify(arr));
+                    return a.reduce((total, cur, index) => {
+                        let hasValue = total.findIndex(current => {
+                            return current.barcode === cur.barcode
+                        })
+                        hasValue === -1 && total.push(cur)
+                        hasValue !== -1 && (total[hasValue].amount = total[hasValue].amount + cur.amount)
+                        return total
+                    }, []);
+                },
+                assignRegroupGoods(){
+                    let data=this;
+                    data.initGoods=data.regroupArr(data.goodses);
+                    data.initGoods.forEach(function (obj){
+                        delete obj.fromIncreasing;
+                        delete obj.cast_number;
+                        delete obj.countGoodStatus;
+                        obj.asnno='';obj.customerid='';
+                        obj.location='';obj.asn_amount='';
+                        obj.diff_val='';obj.receiveStatus=false;
+                        obj.basSku=data.basSku;obj.asnlineno='';
+                        obj.lotatt01='';obj.lotatt02='';
+                        obj.lotatt03='';obj.lotatt04='';
+                        obj.lotatt05='';obj.lotatt08='';
+                    })
+                    data.initGoods=JSON.parse(JSON.stringify(data.initGoods).replace(/barcode/g,"sku"));
+                    data.regroupGoods=data.initGoods;
+                },
+                receiveGoods(goods){
+                    let data=this;
+                    this.errors={};
+                    this.checkGood(goods);
+                    if (JSON.stringify(this.errors)!=='{}')return;
+                    goods.asnno=data.asnno;
+                    tempTip.setDuration(99999);
+                    tempTip.waitingTip('提交中');
+                    let url='{{url("store/countGoodsAndReceive/fluxReceive")}}';
+                    axios.post(url,{good:goods})
+                        .then(function(res){
+                            if(res.data.success){
+                                data.regroupGoods.forEach(function (good,i){
+                                    if (goods.sku==good.sku){
+                                        data.regroupGoods.splice(i,1)
+                                    }
+                                })
+                                tempTip.setDuration(2000);
+                                tempTip.cancelWaitingTip();
+                                tempTip.showSuccess(res.data.data);
+                            }else{
+                                tempTip.setDuration(3000);
+                                tempTip.cancelWaitingTip();
+                                tempTip.show(res.data.data);
+                                data.alertVibrate()
+                            }
+                        })
+                        .catch(function (err) {
+                            tempTip.setDuration(2000);
+                            tempTip.cancelWaitingTip();
+                            tempTip.show("网络错误:"+err);
+                            data.alertVibrate()
+                        });
+                },
+                checkGood(good){
+                    let error = {};
+                    if (!good.trackNumber)error.trackNumber = ["容器号必填"];
+                    if (good.basSku.lot_id && good.basSku.lot_id.lotkey01==='Y' && !good.lotatt01) error.lotatt01=["生产日期为选"];
+                    if (good.basSku.lot_id && good.basSku.lot_id.lotkey02==='Y' && !good.lotatt02) error.lotatt02=["失效日期为选"];
+                    if (good.basSku.lot_id && good.basSku.lot_id.lotkey03==='Y' && !good.lotatt03) error.lotatt03=["入库日期为选"];
+                    if (good.basSku.lot_id && good.basSku.lot_id.lotkey04==='Y' && !good.lotatt04) error.lotatt04=["批号未填"];
+                    if (good.basSku.lot_id && good.basSku.lot_id.lotkey05==='Y' && !good.lotatt05) error.lotatt05=["属性仓未选"];
+                    if (good.basSku.lot_id && good.basSku.lot_id.lotkey08==='Y' && !good.lotatt08) error.lotatt08=["质量状态未选"];
+                    if (JSON.stringify(error)!=='{}'){this.errors = error;}
+                },
+                getReceiveTaskByAsnNoAndBarcodes(){
+                    let data=this;
+                    data.regroupGoods=data.initGoods;//验证asn下商品时 初始商品数据
+                    if(data.asnno===''||data.asnno===null||data.asnno===undefined) window.tempTip.show('请先输入ASN单号!');
+                    if (data.asnno && data.asnno.indexOf('ASN')===-1)window.tempTip.show('无效ASN号!');
+                    let url='{{url("store/countGoodsAndReceive/getReceiveTaskByAsnNoAndBarcodes")}}';
+                    window.axios.post(url,{asnno:data.asnno,goods:data.initGoods})
+                        .then(res=>{
+                            if (res.data.success){
+                                data.regroupGoods=res.data.data;
+                                this.$forceUpdate()
+                            }else {
+                                tempTip.setDuration(3000);
+                                tempTip.show(res.data.data);
+                            }
+                        }).catch(err=>{
+                        window.tempTip.setDuration(2000);
+                        window.tempTip.show("网络错误:"+err);
+                    })
+                },
+                removeDisable(){
+                    let asnNo=$('#asnno');
+                    asnNo.removeAttr('disabled');
+                    this.status.finishReceiveButton=true;
+                    asnNo.focus();
+                },
+                submitExcelData: function () {
+                    let data = this;
+                    data.focusOutDocument();
+                    if(data.goodses.length===0){
+                        window.tempTip.show('请先录入数据再提交收货');return;
+                    }
+                    window.tempTip.confirm('请检查表格,确定全部完成。',
+                        function () {
+                            window.tempTip.setInputType('input');
+                            window.tempTip.setIndex(999999);
+                            window.tempTip.inputVal('收货前将上传excel文件,请输入文件名:',function(val){
+                                if(val===''){
+                                    window.tempTip.setDuration(2500);
+                                    window.tempTip.show('失败!文件名不能为空,请重新点击生成');
+                                    return;
+                                }
+                                window.tempTip.setDuration(15500);
+                                window.tempTip.waitingTip('提交Excel中...');
+                                let expireHandler = setTimeout(function () {
+                                    window.tempTip.cancelWaitingTip();
+                                    window.tempTip.setDuration(1500);
+                                    window.tempTip.show('响应超时! 请检查网络,确保可以连接后再重试。');
+                                },9000);
+                                let url='{{url("store/countGoodsAndReceive/createExcel")}}';
+                                axios.post(url,{'goodses':data.goodses,'filename':val})
+                                    .then(function(response){
+                                        if(response.data.result==='success'){
+                                            data.removeDisable();//收货解锁asnno input标签
+                                            data.assignRegroupGoods();//结束清点,重组收货所需数据
+                                            data.goodses=[];
+                                            data.cleanInputs();
+                                            window.tempTip.cancelWaitingTip();
+                                            window.tempTip.setDuration(1500);
+                                            window.tempTip.showSuccess('成功生成EXCEL,可在列表页查看');
+                                        }else{
+                                            window.tempTip.setDuration(1500);
+                                            window.tempTip.show('生成EXCEL失败');
+                                            data.focusDocument();
+                                            data.alertVibrate()
+                                        }
+                                        clearInterval(expireHandler);
+                                    })
+                                    .catch(function (err) {
+                                        window.tempTip.setDuration(3500);
+                                        window.tempTip.show('网络或系统错误,请将以下信息提交给开发者:'+err);
+                                        clearInterval(expireHandler);
+                                        data.alertVibrate();
+                                    });
+                            });
+                        },function () {
+                            data.focusDocument();
+                        })
+                },
+                finishReceive(){
+                    if(!confirm('确定要结束收货吗?'))return;
+                    setTimeout(function (){window.location.reload()},10)
+                }
+            },
+        });
+    </script>
+@endsection

+ 9 - 0
routes/web.php

@@ -545,6 +545,7 @@ Route::group(['prefix'=>'package'],function(){
             Route::post('changeAsnRule','StorageController@changeAsnRule');
             Route::post('callRobot','StorageController@callRobot');
         });
+        /** 手持入库 */
         Route::group(['prefix'=>'handInStorage'],function() {
             Route::get('receive',function (){return view('store.handInStorage.receive');});//收货页面
             Route::get('putaway',function (){return view('store.handInStorage.putaway');});//上架页面
@@ -561,6 +562,14 @@ Route::group(['prefix'=>'package'],function(){
             Route::post('handFluxPa','HandInStorageController@handFluxPa');
             Route::get('receiveDetailPage/{asnno}/{customerid}','HandInStorageController@receiveDetailPage');
         });
+
+        Route::group(['prefix'=>'countGoodsAndReceive'],function() {
+            Route::get('index', 'StoreCountGoodsAndReceiveController@index');
+            Route::get('excel', 'StoreCountGoodsAndReceiveController@excel');
+            Route::post('createExcel', 'StoreCountGoodsAndReceiveController@createExcel');
+            Route::any('fluxReceive','StoreCountGoodsAndReceiveController@fluxReceive');
+            Route::post('getReceiveTaskByAsnNoAndBarcodes', 'StoreCountGoodsAndReceiveController@getReceiveTaskByAsnNoAndBarcodes');
+        });
         Route::group(['prefix'=>'fast'],function() {
             Route::resource('storeItem','StoreItemController');
         });