فهرست منبع

Merge branch 'master' into zzd-vue-resize

# Conflicts:
#	app/Http/Controllers/TestController.php
zhouzhendong 4 سال پیش
والد
کامیت
f0329ac222
53فایلهای تغییر یافته به همراه2488 افزوده شده و 281 حذف شده
  1. 1 1
      app/Batch.php
  2. 2 2
      app/Console/Commands/CreateOwnerReport.php
  3. 1 0
      app/Console/Kernel.php
  4. 18 0
      app/Http/Controllers/KpiController.php
  5. 2 1
      app/Http/Controllers/LaborCompanyDispatchController.php
  6. 6 19
      app/Http/Controllers/OrderController.php
  7. 23 3
      app/Http/Controllers/PackageLogisticController.php
  8. 23 4
      app/Http/Controllers/ReceiveRecordController.php
  9. 126 0
      app/Http/Controllers/ReplenishmentController.php
  10. 3 1
      app/Http/Controllers/StoreBlindReceiveController.php
  11. 145 0
      app/Http/Controllers/StoreCountGoodsAndReceiveController.php
  12. 126 154
      app/Http/Controllers/TestController.php
  13. 76 0
      app/Http/Controllers/WaveController.php
  14. 32 12
      app/Http/Controllers/api/thirdPart/haochuang/SortingController.php
  15. 19 0
      app/Http/Requests/OrderDelivering.php
  16. 45 0
      app/Jobs/BroadcastBatchToZhengCangJob.php
  17. 2 0
      app/Jobs/LaborApplyRecordJob.php
  18. 12 3
      app/Jobs/LogisticYDSync.php
  19. 1 1
      app/Jobs/LogisticYTOSync.php
  20. 6 0
      app/LaborCompanyDispatch.php
  21. 1 1
      app/OracleBasSKU.php
  22. 7 0
      app/OracleDOCASNDetail.php
  23. 2 0
      app/Providers/AppServiceProvider.php
  24. 1 5
      app/Services/ForeignZhenCangService.php
  25. 1 1
      app/Services/HandInStorageService.php
  26. 5 2
      app/Services/LaborApplyService.php
  27. 2 3
      app/Services/LogisticSFService.php
  28. 1 1
      app/Services/LogisticYTOService.php
  29. 2 2
      app/Services/OwnerService.php
  30. 1 1
      app/Services/RejectedBillService.php
  31. 184 0
      app/Services/ReplenishmentService.php
  32. 1 1
      app/Traits/LogisticSyncTrait.php
  33. 3 2
      composer.json
  34. 63 3
      composer.lock
  35. 32 0
      database/migrations/2021_11_08_133051_add_chick_user_id_to_labor_company_dispatches_table.php
  36. 32 0
      database/migrations/2021_11_08_152146_change_batches_add_column_partition_size.php
  37. 141 0
      resources/views/inventory/stockOut/index.blade.php
  38. 174 0
      resources/views/kpi/day/index.blade.php
  39. 186 0
      resources/views/kpi/month/index.blade.php
  40. 7 0
      resources/views/order/wave/_printBody.blade.php
  41. 23 0
      resources/views/order/wave/_split.blade.php
  42. 131 0
      resources/views/order/wave/picking.blade.php
  43. 69 1
      resources/views/order/wave/search.blade.php
  44. 92 31
      resources/views/package/logistic/index.blade.php
  45. 1 1
      resources/views/personnel/laborApply/create.blade.php
  46. 3 1
      resources/views/personnel/laborApply/dispatch/index.blade.php
  47. 1 1
      resources/views/personnel/laborApply/index.blade.php
  48. 12 7
      resources/views/personnel/laborReport/index.blade.php
  49. 55 3
      resources/views/rejected/record.blade.php
  50. 31 0
      resources/views/store/countGoodsAndReceive/excel.blade.php
  51. 516 0
      resources/views/store/countGoodsAndReceive/index.blade.php
  52. 1 0
      resources/views/store/inStorage/androidIndex.blade.php
  53. 38 13
      routes/web.php

+ 1 - 1
app/Batch.php

@@ -12,7 +12,7 @@ class Batch extends Model
     use ModelLogChanging;
 
     protected $fillable = [
-        'id','code','type', 'wms_type', 'status', 'wms_status', 'wms_created_at',"remark","owner_id",
+        'id','code','type', 'wms_type', 'status', 'wms_status', 'wms_created_at',"remark","owner_id","split_size"
     ];
 
     const WMS_STATUS = [

+ 2 - 2
app/Console/Commands/CreateOwnerReport.php

@@ -68,12 +68,12 @@ class CreateOwnerReport extends Command
         $bills = OwnerBillReport::query()->where("counting_month","like",$year."-".$lastMonth."%")->get();
 
         //日均单量统计
-        $query = DB::raw("select  count(*) c,CUSTOMERID from DOC_ORDER_HEADER where SOSTATUS = '99' and EDITTIME >= to_date('".$year."-".$lastMonth."-01 00:00:00','yyyy-mm-dd hh24:mi:ss') and EDITTIME <= to_date('".$year."-".$lastMonth."-".$lastDay." 23:59:59','yyyy-mm-dd hh24:mi:ss') group by CUSTOMERID");
+        /*$query = DB::raw("select  count(*) c,CUSTOMERID from DOC_ORDER_HEADER where SOSTATUS = '99' and EDITTIME >= to_date('".$year."-".$lastMonth."-01 00:00:00','yyyy-mm-dd hh24:mi:ss') and EDITTIME <= to_date('".$year."-".$lastMonth."-".$lastDay." 23:59:59','yyyy-mm-dd hh24:mi:ss') group by CUSTOMERID");
         $orderStatistic = DB::connection("oracle")->select($query);
         $map = [];
         foreach ($orderStatistic as $item){
             $map[$item->customerid] = $item->c;
-        }
+        }*/
 
         //已存在的报表记录
         $reportMap = [];

+ 1 - 0
app/Console/Kernel.php

@@ -78,6 +78,7 @@ class  Kernel extends ConsoleKernel
         $schedule->command('sync:order')->everyMinute();
         $schedule->command('syncOrderPackageLogisticRouteTask')->dailyAt('6:01')->runInBackground();//同步快递信息到orderPackage
         $schedule->command('syncOrderPackageLogisticRouteTask')->dailyAt('12:01')->runInBackground();//同步快递信息到orderPackage
+        $schedule->command('syncOrderPackageLogisticRouteTask')->dailyAt('18:01')->runInBackground();//同步快递信息到orderPackage
 //        $schedule->command('updateOrderPackageExceptionTypeCountingRecordTask')->dailyAt('2:20');//更新OrderPackageExceptionTypeCountingRecord
         $schedule->command('SyncWmsCommoditiesInformation')->everyMinute();
         $schedule->command('clear:cancelledOrder')->everyMinute();

+ 18 - 0
app/Http/Controllers/KpiController.php

@@ -0,0 +1,18 @@
+<?php
+
+namespace App\Http\Controllers;
+
+use Illuminate\Http\Request;
+
+class KpiController extends Controller
+{
+    public function monthIndex(Request $request)
+    {
+        return view('kpi.month.index');
+    }
+
+    public function dayIndex(Request $request)
+    {
+        return view('kpi.day.index');
+    }
+}

+ 2 - 1
app/Http/Controllers/LaborCompanyDispatchController.php

@@ -21,7 +21,7 @@ class LaborCompanyDispatchController extends Controller
         /** @var Builder $builder */
         $builder = LaborCompanyDispatch::query()
             ->filter($filters)
-            ->with(['laborCompany', 'laborCompanyDispatchDetails','warehouse']);
+            ->with(['laborCompany', 'laborCompanyDispatchDetails','warehouse','checkUser']);
 
         /** @var User $user */
         $user = auth()->user();
@@ -97,6 +97,7 @@ class LaborCompanyDispatchController extends Controller
     public function personnelCheck(LaborCompanyDispatch $laborCompanyDispatch, Request $request)
     {
         $laborCompanyDispatch->status = $request->status;
+        $laborCompanyDispatch->check_user_id = auth()->id();
         $laborCompanyDispatch->save();
         return redirect()->back()->with('success', '人事确认成功!');
 

+ 6 - 19
app/Http/Controllers/OrderController.php

@@ -4,20 +4,17 @@ namespace App\Http\Controllers;
 
 use App\Components\Database;
 use App\Http\Requests\OrderDelivering;
-use App\OracleActAllocationDetails;
 use App\OracleDOCOrderHeader;
 use App\OracleDOCWaveDetails;
 use App\OrderIssueType;
-use App\OrderPackage;
 use App\Services\LogisticService;
 use App\Services\LogService;
 use App\Services\OrderPackageService;
 use App\Services\OrderService;
 use App\Services\RejectedBillItemService;
 use App\Services\RejectedBillService;
-use Illuminate\Database\Eloquent\Builder;
+use GuzzleHttp\Exception\GuzzleException;
 use Illuminate\Http\Request;
-use Illuminate\Support\Collection;
 use Illuminate\Support\Facades\Auth;
 use Illuminate\Support\Facades\DB;
 use Illuminate\Support\Facades\Gate;
@@ -33,21 +30,6 @@ class OrderController extends Controller
         /** @var OrderService $orderService */
         $orderService = app('OrderService');
         $request = $request->input();
-        if (!app("UserService")->checkAdminIdentity(Auth::id())){
-            $owners = app('OwnerService')->getIntersectPermitting(['id', 'code']);
-            $codes = array_column($owners->toArray(), 'code');
-            if ($request['customerid'] ?? false) {
-                $arr = explode(',', $request['customerid']);
-                $request['customerid'] = [];
-                foreach ($arr as $value) {
-                    if (in_array($value, $codes)) $request['customerid'][] = $value;
-                }
-                if (count($request['customerid']) < 1) $request['customerid'] = [''];
-            } else $request['customerid'] = $codes;
-        }else if (isset($request['customerid'])){
-            $request['customerid'] = explode(',', $request['customerid']);
-            if ($request['customerid']<0)unset($request['customerid']);
-        }
         $service = app(LogisticService::class);
         $logistics = $service->getSelection(['id', 'name']);
         $result = $orderService->paginate($request);
@@ -64,6 +46,10 @@ class OrderController extends Controller
     }
 
     //导出
+
+    /**
+     * @throws \Exception|GuzzleException
+     */
     public function export(Request $request)
     {
         $is_merge = $request->is_merge ?? false;
@@ -74,6 +60,7 @@ class OrderController extends Controller
         if ($request->data) {
             $req["sql"] = $orderService->getSql(['data' => $request->data]);
         } else {
+            new OrderDelivering();
             $req["sql"] = $orderService->getSql($request->input());
         }
         $e = new Export();

+ 23 - 3
app/Http/Controllers/PackageLogisticController.php

@@ -49,12 +49,32 @@ class PackageLogisticController extends Controller
                     }]);
                 }])
             ->orderByDesc('id')
-            ->paginate($request->paginate ?? 50);
+            ->simplePaginate($request->paginate ?? 50);
         $logistics = Logistic::all();
-        $owners = Owner::find($owner_ids);
+        $owners = app("OwnerService")->getIntersectPermitting();
         return view('package.logistic.index', compact('orderPackages', 'logistics', 'owners', 'paginateParams'));
     }
 
+    /**
+     * 获取查询条件下的总条数
+     * @param Request $request
+     * @param OrderPackageFilters $filters
+     * @return array
+     */
+    public function getTotal(Request $request, OrderPackageFilters $filters): array
+    {
+
+        /** @var UserService $userService */
+        $userService = app('UserService');
+        $owner_ids = $userService->getPermittingOwnerIds(auth()->user());
+        $total = OrderPackage::query()
+            ->selectRaw("count(*) as total")
+            ->filter($filters)
+            ->whereIn('owner_id', $owner_ids)
+            ->first();
+        return ['success' => true, 'data' => ['total' => $total->total]];
+    }
+
     public function update(Request $request)
     {
         $data = [];
@@ -102,7 +122,7 @@ class PackageLogisticController extends Controller
         $userService = app('UserService');
         $owner_ids = $userService->getPermittingOwnerIds(auth()->user());
         $query = OrderPackage::query()
-            ->whereIn('owner_id',$owner_ids)
+            ->whereIn('owner_id', $owner_ids)
             ->filter($filters)
             ->with([
                 'order.logistic',

+ 23 - 4
app/Http/Controllers/ReceiveRecordController.php

@@ -8,6 +8,7 @@ use App\Logistic;
 use App\ReceiveRecord;
 use App\Services\LogisticService;
 use App\Warehouse;
+use Firebase\JWT\ExpiredException;
 use Firebase\JWT\JWT;
 use Illuminate\Database\Eloquent\Builder;
 use Illuminate\Database\QueryException;
@@ -86,8 +87,7 @@ class ReceiveRecordController extends Controller
         $jwtToken = app("UserService")->getJWTToken(Auth::user(),$privateKey);
         return view("rejected.record",compact("warehouses","jwtToken"));
     }
-
-    public function receive()
+    public function refreshToken()
     {
         $jwtToken = \request()->header("jwtToken");
         if (!$jwtToken)$this->error("非法请求");
@@ -96,8 +96,27 @@ class ReceiveRecordController extends Controller
         });
         $payload = JWT::decode($jwtToken, $publicKey, ['RS256']);
         $user = app("UserService")->getOrRefreshCache($payload->data->id,$payload->exp);
-        if (!$user)$this->error("登录过期");
-        Auth::setUser($user);
+
+        $privateKey = file_get_contents(base_path().'/private.pem');
+        $jwtToken = app("UserService")->getJWTToken($user,$privateKey);
+        $this->success($jwtToken);
+    }
+
+    public function receive()
+    {
+        $jwtToken = \request()->header("jwtToken");
+        if (!$jwtToken)$this->error("非法请求");
+        $publicKey = Cache::remember("TOKEN_PUBLIC_KEY",7200,function (){
+            return file_get_contents(base_path().'/public.pem');
+        });
+        try {
+            $payload = JWT::decode($jwtToken, $publicKey, ['RS256']);
+            $user = app("UserService")->getOrRefreshCache($payload->data->id,$payload->exp);
+            if (!$user)throw new ExpiredException();
+            Auth::setUser($user);
+        }catch (ExpiredException $e){
+            $this->error("认证过期,请保存当前失败记录刷新页面");
+        }
         $this->gate("退货管理-退件记录");
         $logisticNumber = \request("logisticNumber");
         $warehouse = \request("warehouse");

+ 126 - 0
app/Http/Controllers/ReplenishmentController.php

@@ -0,0 +1,126 @@
+<?php
+
+namespace App\Http\Controllers;
+
+use App\Components\AsyncResponse;
+use App\Owner;
+use App\Services\ReplenishmentService;
+use Illuminate\Http\Request;
+use Oursdreams\Export\Export;
+
+class ReplenishmentController extends Controller
+{
+    use AsyncResponse;
+
+    public function getReplenishmentInfoByCustomer(Request $request)
+    {
+        $this->gate("库存管理-补货列表");
+        $customer = $request->input('customer');
+        if (!$customer) $this->error('请选择指定货主!');
+        $orders = $this->getOrders($customer);
+        $orders = array_filter($orders,function($item){
+            return $item['amount'] > 0;
+        });
+        if (count($orders) > 0) $this->success($orders);
+        else $this->error('未查询到相应信息!');
+
+
+    }
+
+
+    public function index(Request $request)
+    {
+        $this->gate("库存管理-补货列表");
+        /** @var UserService $userService */
+        $userService = app('UserService');
+        $owners = Owner::query()->whereIn('id', $userService->getPermittingOwnerIds(auth()->user()))->get();
+        return view('inventory.stockOut.index', compact('owners'));
+    }
+
+    public function export(Request $request)
+    {
+        $this->gate("库存管理-补货列表");
+
+        $customer = $request->input('customer');
+        $orders = array_filter($this->getOrders($customer),function($item){
+            return $item['amount'] > 0;
+        });
+        $row = [
+            '货主',
+            '商品名称',
+            '商品条码',
+            '拣货库位',
+            '缺货数',
+            '存储库位',
+            '数量',
+            '批次号'
+        ];
+        $json = [];
+
+        foreach ($orders as $order) {
+            $eaLocation = '';
+            $rsLocation = '';
+            $qty = '';
+            $lot = '';
+
+            foreach ($order['eaLocation'] as $v) {
+                $eaLocation .= $v . "\r\n";
+            }
+
+            foreach ($order['rsLocation'] as $v) {
+                $rsLocation .= $v['location'] ."\r\n";
+            }
+            foreach ($order['rsLocation'] as $v) {
+                $qty .= $v['qty'] ."\r\n";
+            }
+            foreach ($order['rsLocation'] as $v) {
+                $lot .= $v['lot'] ."\r\n";
+            }
+
+            $data = [
+                $order['customerid'],
+                $order['sku'],
+                $order['alternate_sku1'],
+                $eaLocation,
+                $order['amount'],
+                $rsLocation,
+                $qty,
+                $lot,
+            ];
+            $json[] = $data;
+        }
+        return Export::make($row, $json, "库存管理-补货列表");
+    }
+
+    /**
+     * @param $customer
+     * @return array
+     */
+    private function getOrders($customer): array
+    {
+        /** @var ReplenishmentService $service */
+        $service = app('ReplenishmentService');
+        $orders = $service->getOrderInfoRecentMonthByCustomer($customer);
+        $skuArr = array_diff(array_unique(data_get($orders, '*.sku')), ['', '*', null]);
+        $info = $service->getEaInventoryByCustomerAndSku($customer, $skuArr);
+        $rsInfo = $service->getRsInventoryByCustomerAndSku($customer, $skuArr);
+
+        //将整合后拣货位信息 结合订单汇总
+        foreach ($orders as &$order) {
+            if (isset($info[$order['sku']])) {
+                $item = $info[$order['sku']];
+                $order['amount'] = ($order['amount'] - $item['qty']);
+                $order['eaLocation'] = $item['locationid'];
+            } else {
+                $order['eaLocation'] = [];
+            }
+            if (isset($rsInfo[$order['sku']])) {
+                $rsItem = $rsInfo[$order['sku']];
+                $order['rsLocation'] = $rsItem['locationid'];
+            } else {
+                $order['rsLocation'] = [];
+            }
+        }
+        return $orders;
+    }
+}

+ 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);
+        }
+    }
+}

+ 126 - 154
app/Http/Controllers/TestController.php

@@ -5,6 +5,7 @@ namespace App\Http\Controllers;
 use App\Authority;
 use App\Batch;
 use App\Commodity;
+use App\CommodityBarcode;
 use App\CommodityMaterialBoxModel;
 use App\Components\AsyncResponse;
 use App\Components\Database;
@@ -12,6 +13,7 @@ use App\Components\ErrorPush;
 use App\ErrorTemp;
 use App\Feature;
 use App\Http\ApiControllers\LoginController;
+use App\Http\Controllers\api\thirdPart\haochuang\SortingController;
 use App\Http\Controllers\api\thirdPart\syrius\beans\StorageTypeCell;
 use App\Http\Controllers\api\thirdPart\syrius\beans\StorageTypeRelation;
 use App\Http\Controllers\api\thirdPart\syrius\beans\Task;
@@ -22,6 +24,7 @@ use App\Http\Controllers\api\thirdPart\syrius\units\StorageTypeAttribute;
 use App\Http\Requests\AndroidGateRequest;
 use App\Http\Requests\OrderDelivering;
 use App\Jobs\BatchTaskJob;
+use App\Jobs\BroadcastBatchToZhengCangJob;
 use App\Jobs\CacheShelfTaskJob;
 use App\Jobs\OrderCreateInstantBill;
 use App\Jobs\OrderCreateWaybill;
@@ -36,16 +39,20 @@ 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;
+use App\OracleDOCWaveDetails;
 use App\Order;
 use App\OrderBin;
+use App\OrderCommodity;
 use App\OrderIssue;
 use App\OrderIssueProcessLog;
 use App\OrderPackage;
 use App\Owner;
 use App\OwnerAreaReport;
+use App\OwnerBillReport;
 use App\OwnerFeeDetail;
 use App\OwnerFeeDetailLogistic;
 use App\OwnerFeeExpress;
@@ -56,15 +63,18 @@ use App\OwnerFeeStorage;
 use App\OwnerPriceExpress;
 use App\OwnerPriceOperation;
 use App\OrderPackageCountingRecord;
+use App\OwnerReport;
 use App\ProcurementCheckSheet;
 use App\RejectedBill;
 use App\SeeLog;
 use App\Services\AuthorityService;
 use App\Services\BatchService;
 use App\Services\CacheShelfService;
+use App\Services\common\BatchUpdateService;
 use App\Services\ForeignHaiRoboticsService;
 use App\Services\ForeignZhenCangService;
 use App\Services\LogisticService;
+use App\Services\LogService;
 use App\Services\NotificationService;
 use App\Services\OracleDOCOrderHeaderService;
 use App\Services\OrderPackageCommoditiesService;
@@ -74,13 +84,16 @@ use App\Services\OrderService;
 use App\Services\OwnerFeeTotalService;
 use App\Services\OwnerLogisticFeeReportService;
 use App\Services\OwnerPriceOperationService;
+use App\Services\OwnerService;
 use App\Services\OwnerStoreFeeReportService;
 use App\Services\OwnerStoreOutFeeReportService;
+use App\Services\ReplenishmentService;
 use App\Services\ReviewService;
 use App\Services\StationService;
 use App\Services\StorageService;
 use App\Services\StoreService;
 use App\Services\SyriusTaskService;
+use App\SortingStation;
 use App\Station;
 use App\StationTask;
 use App\StationTaskMaterialBox;
@@ -97,7 +110,9 @@ use App\WorkOrder;
 use Carbon\Carbon;
 use Carbon\CarbonPeriod;
 use Decimal\Decimal;
+use Doctrine\DBAL\Driver\AbstractDB2Driver;
 use Doctrine\DBAL\Exception;
+use Firebase\JWT\ExpiredException;
 use Firebase\JWT\JWT;
 use Illuminate\Database\Eloquent\Builder;
 use Illuminate\Database\Eloquent\Collection;
@@ -120,6 +135,7 @@ use Laravel\Horizon\Events\JobFailed;
 use Monolog\Handler\IFTTTHandler;
 use phpDocumentor\Reflection\Types\Resource_;
 use PhpOffice\PhpSpreadsheet\Calculation\Web\Service;
+use PhpParser\Node\Stmt\DeclareDeclare;
 use Ramsey\Uuid\Uuid;
 use Symfony\Component\ErrorHandler\Error\FatalError;
 
@@ -142,163 +158,121 @@ class TestController extends Controller
             dd("方法不存在");
         }
     }
-    /**
-     * @param $wave
-     * @return string
-     */
-    private function wms_status($wave): string
-    {
-        switch ($wave->wavestatus) {
-            case 00:
-                $wms_status = '创建';
-                break;
-            case 40:
-                $wms_status = '部分收货';
-                break;
-            case 90:
-                $wms_status = '取消';
-                break;
-            case 99:
-                $wms_status = '完成';
-                break;
-            case 62:
-                $wms_status = '部分装箱';
-                break;
-            default:
-                $wms_status = (string)$wave->wavestatus;
+    function process(Request $request){
+        $token = trim($request->input('token'));
+        $station_id = 'test';
+        $batch_id = 'W211111001514-6';
+
+        $childIndex = null;
+        $arr = explode('-',$batch_id);
+        if (count($arr)==2){
+            $batch_id = $arr[0];
+            $childIndex = (int)$arr[1];
+            $request->offsetSet("batch_id",$batch_id);
         }
-        return $wms_status;
-    }
-    public function assignBatch()
-    {
-        $code = \request("code");
-        $batches = Batch::query()->where("code",$code)->get();
-        if (!$batches->count()){
-            $wave = DB::connection("oracle")->selectOne(DB::raw("select * from DOC_WAVE_HEADER where WAVENO = ?"),[$code]);
-            if (!$wave){
-                dd("FLUX无波次");
-            }
-            $owner = app("OwnerService")->codeGetOwner($wave->customerid);
-            $obj = [
-                "wms_status" => $this->wms_status($wave),
-                "wms_type"=>$wave->descr,
-                "created_at"=>date("Y-m-d H:i:s"),
-                "wms_created_at"=>$wave->addtime,
-                "updated_at"=>$wave->edittime,
-                "owner_id"=>$owner->id,
-            ];
-            $wave = Batch::query()->where("code",$code)->first();
-            if (!$wave){
-                $obj["code"] = $code;
-                $wave = Batch::query()->create($obj);
-            }else{
-                Batch::query()->where("code",$code)->update($obj);
-            }
-            $ordernos = array_column(DB::connection("oracle")->select(DB::raw("select orderno from DOC_WAVE_DETAILS where WAVENO = ?"),[$code]),"orderno");
-            Order::query()->whereIn("code",$ordernos)->update([
-                "batch_id"=>$wave->id
-            ]);
-            Order::query()->with(["batch","bin"])->whereIn("code",$ordernos)->get()->each(function ($order){
-                if (!$order->bin){
-                    $bin = DB::connection("oracle")->selectOne(DB::raw("select seqno from DOC_WAVE_DETAILS where waveno = ? and orderno = ?"),[$order->batch->code,$order->code]);
-                    if ($bin){
-                        OrderBin::query()->create([
-                            'order_id' => $order->id,
-                            'number' => $bin->seqno,
-                        ]);
+
+        /** @var Batch|\stdClass $batch */
+        $batch=Batch::query()->where('code',$batch_id)->orderBy('id','desc')->first();
+        $data=[
+            'result'=>'success',
+            'station_id'=>$station_id,
+            'batch_id'=>$batch_id,
+            'orders'=>[]
+        ];
+        if ($childIndex!==null && $batch->split_size){
+            $start = (($childIndex-1)*$batch->split_size)+1;
+            $end = $childIndex*$batch->split_size;
+            $sql = <<<SQL
+SELECT ORDERNO
+FROM (SELECT T.ORDERNO, ROWNUM AS NO
+FROM (SELECT ORDERNO FROM DOC_WAVE_DETAILS WHERE WAVENO = '{$batch_id}' ORDER BY SEQNO) T)
+WHERE NO BETWEEN {$start} AND {$end}
+SQL;
+            dd($sql);
+            $waves = DB::connection("oracle")->select(DB::raw($sql));
+            $codes = array_column($waves,'orderno');
+            $orders = Order::query()->with(["bin","owner","orderCommodities.commodity.barcodes"])->whereIn("code",$codes)->get();
+        }else $orders = $batch->orders()->with(["bin","owner","orderCommodities.commodity.barcodes"])->get();
+
+        $ordersSorted=$orders->sortBy(function(Order $order){
+            return $order->bin->number;
+        });
+        $ordersSorted->each(function(Order $order)use(&$data,$request,$childIndex,$batch){
+            if($order['status']=='取消')return;
+            $orderData=[
+                'order_id'=>$order['code'],
+                'owner'=>$order->owner->code,
+                'status'=>$order['status']=='未处理'?'available':$order['status'],
+                'created_at'=>$order['created_at']->toDateTimeString(),
+                'bin'=>(function()use($order,$childIndex,$batch){
+                    $bin=$order->bin->number??'';
+                    if(!$bin){
+                        $bin=OracleDOCWaveDetails::query()->where('orderno', 'SO201230003574')->get('seqno')->first()['seqno']??'';
+                        LogService::log(__METHOD__,__FUNCTION__,'bin缺失补查:'.$bin.'. order:'.$order->toJson());
+                        return $childIndex!==null ? $bin-(($childIndex-1)*$batch->split_size) : $bin;
                     }
+                    return $childIndex!==null ? $bin-(($childIndex-1)*$batch->split_size) : $bin;
+                })(),
+                'barcodes'=>[]
+            ];
+            $order->orderCommodities->each(function(OrderCommodity $orderCommodity)use(&$orderData,$request){
+                $commodity=$orderCommodity->commodity;
+                if(!$commodity){
+                    app('LogService')->log(__METHOD__, 'error' . __FUNCTION__, '播种位数据准备出错,找不到订单对应的Commodity id的对象'.$orderCommodity['commodity_id'].',是否表数据在波次生成后丢失?'.json_encode($request->all()));
+                    return;
                 }
+                $barcodeStr=$commodity->barcodes->map(function(CommodityBarcode $barcode){
+                    return $barcode['code'];
+                })->filter(function($code){
+                    return $code&&(!preg_match('/[\x{4e00}-\x{9fa5}]/u',$code));
+                })->join(',');
+                $orderData['barcodes'][]=[
+                    'id'=>$orderCommodity['id']??'',
+                    'barcode_id'=>$barcodeStr??'',
+                    'name'=>$commodity['name']??'',
+                    'sku'=>$commodity['sku']??'',
+                    'amount'=>$orderCommodity['amount']??'',
+                    'location'=>$orderCommodity['location']??'',
+                ];
             });
-            $batches = Batch::query()->where("code",$code)->get();
-        }
-        app("BatchService")->assignTasks($batches);
-    }
-    private function i3()
-    {
-        $taskItem = new TaskItem();
-        $taskItem->name = "测试衣服商品名3";
-        $taskItem->barcode = "TEST-014";
-        $taskItem->quantity = (int)1;
-        $taskItem->binLocations = [
-            "G04-039-1",
-        ];
-        $taskItem->attributes = [
-            "orderLineNo" => "1",
-            "skuLineNo"   => "1",
-            "sku"         => "TEST3",
-            "lotNum"      => "LOT1792011",
-            "logisticNumber"=> "极兔",
-        ];
-        return (array)$taskItem->get();
-    }
-    private function i2()
-    {
-        $taskItem = new TaskItem();
-        $taskItem->name = "测试衣服商品名2";
-        $taskItem->barcode = "TEST-013";
-        $taskItem->quantity = (int)1;
-        $taskItem->binLocations = [
-            "G04-056-1",
-        ];
-        $taskItem->attributes = [
-            "orderLineNo" => "1",
-            "skuLineNo"   => "1",
-            "sku"         => "TEST1",
-            "lotNum"      => "LOT179201",
-            "logisticNumber"=> "圆通",
-        ];
-        return (array)$taskItem->get();
+            $data['orders'][]=$orderData;
+        });
+        return $data;
     }
-    private function i1()
-    {
-        $taskItem = new TaskItem();
-        $taskItem->name = "测试衣服  商品名";
-        $taskItem->barcode = "TEST-012";
-        $taskItem->quantity = (int)1;
-        $taskItem->binLocations = [
-            "G04-046-0",
-        ];
-        $taskItem->attributes = [
-            "orderLineNo" => "1",
-            "skuLineNo"   => "1",
-            "sku"         => "TEST",
-            "lotNum"      => "LOT17920",
-            "logisticNumber"=> "顺丰",
-        ];
-        return (array)$taskItem->get();
-    }
-    private function t1()
-    {
-        $task = new Task();
-        $task->id = "TEST0010";
-        $task->batchId = "WTEST0002";
-        $task->warehouseId = "101";
-        $task->attributes = [
-            "customer" => "幼岚",
-        ];
-        $task->type = Task::TOTAL_PICKING;
-        $task->storages = [["type"=>"1A_container"]];
-        $task->items = [
-            $this->i1(),
-            $this->i2(),
-            $this->i3(),
-        ];
-        return $task->get();
-    }
-    use Signature;
-    private static $delayedHour = 48;
+
     public function test(Request $request)
     {
-        return view("equipment.index");
-        echo 'Now memory_get_usage: ' . memory_get_usage() . '<br />';
-        $t1 = microtime(true);
-// ... 执行代码 ...
-        $t2 = microtime(true);
-        echo '耗时'.round($t2-$t1,3).'秒<br>';
-        echo 'Now memory_get_usage: ' . memory_get_usage() . '<br />';
-        return;
-        $a = new \App\Http\Controllers\api\thirdPart\syrius\producer\OrderController();
-        dd($a->createOrder($this->t1())->body());
+        dd(1);
+
+        dd($this->process($request));
+        $batch = Batch::query()->where("code","W211111001514")->first();
+        dd($batch->orders()->with("bin")->first());
+        $path = '';
+        $id = 109;
+
+        $file = fopen($path, "r");
+        $user=array();
+        $i=0;
+        //输出文本中所有的行,直到文件结束为止。
+        while(! feof($file)){
+            $user[$i]= trim(fgets($file));//fgets()函数从文件指针中读取一行
+            $i++;
+        }
+        fclose($file);
+        foreach ($user as $item){
+            $arr = explode(",",$item);
+            if (count($arr)!=2){
+                dump($item);
+                continue;
+            }
+            DB::table("details")->insert([
+                "name" => $arr[0],
+                "size" => $arr[1],
+                "created_at" => date("Y-m-d H:i:s"),
+                "updated_at" => date("Y-m-d H:i:s"),
+                "header_id" => $id
+            ]);
+        }
     }
     public function test1()
     {
@@ -763,9 +737,7 @@ sql;
 
     public function testZhenCang()
     {
-        $batches=Batch::query()->with(['orders.orderCommodities.commodity.barcodes'])->find(161071);
-        /** @var ForeignZhenCangService  $foreignZhenCangService */
-       $foreignZhenCangService=app('ForeignZhenCangService');;
-       $foreignZhenCangService->broadcastBatch($batches);
+        $batches=Batch::query()->where('id',161071)->get();
+        BroadcastBatchToZhengCangJob::dispatch($batches);
     }
 }

+ 76 - 0
app/Http/Controllers/WaveController.php

@@ -159,4 +159,80 @@ class WaveController extends Controller
         return $wms_status;
     }
 
+    public function split()
+    {
+        $codes = \request("codes",[]);
+        $splitSize = \request("split");
+        $splitNumber = \request("number");
+        if (!$codes || (!$splitSize && !$splitNumber))$this->error("无记录");
+        if ((!is_numeric($splitSize) || !is_int((int)$splitSize)) && !is_numeric($splitNumber) || !is_int((int)$splitNumber))$this->error("非法输入");
+        if ($splitSize){
+            $size = Batch::query()->whereIn("code",$codes)->whereNull("split_size")->count();
+            if ($size!=count($codes))$this->error("波次不全或不允许二次分割");
+            Batch::query()->whereIn("code",$codes)->whereNull("split_size")->update([
+                "split_size" => $splitSize
+            ]);
+        }else{
+            $no = "";
+            foreach ($codes as $code){
+                $no .= "'".$code."',";
+            }
+            $no = rtrim($no,',');
+            $sql = <<<SQL
+SELECT WAVENO,MAX(SEQNO) count from DOC_WAVE_DETAILS WHERE WAVENO IN ({$no}) GROUP BY WAVENO
+SQL;
+            foreach (DB::connection("oracle")->select(DB::raw($sql)) as $wave){
+                Batch::query()->where("code",$wave->waveno)->update(["split_size" => (int)ceil($wave->count/$splitNumber)]);
+            };
+        }
+        $this->success();
+    }
+
+    public function printChild()
+    {
+        $codes = \request("codes",[]);
+        if (!$codes)$this->error("无记录");
+        $batches = [];
+        foreach (Batch::query()->select("code","split_size","id")
+                     ->whereIn("code",$codes)->whereNotNull("split_size")->get() as $batch){
+            if ($batch->orders_count==0)continue;
+            $bin = OrderBin::query()->selectRaw("MAX(number) max")->whereIn("order_id",Order::query()
+                ->select("id")->where("batch_id",$batch->id))->first();
+            $batches[$batch->code] = (int)ceil($bin->max/$batch->split_size);
+        }
+        $this->success($batches);
+    }
+
+    public function picking()
+    {
+        return view("order/wave/picking");
+    }
+
+    public function loadBatch()
+    {
+        $code = \request("code");
+        $batch = null;
+        if (!$code || !$batch = Batch::query()->select("id","split_size")->where("code",$code)->first())$this->error("无记录");
+        $sql = <<<SQL
+SELECT a.ORDERNO,a.QTY,s.ALTERNATE_SKU1,a.LOCATION,w.SEQNO FROM ACT_ALLOCATION_DETAILS a
+    LEFT JOIN DOC_ORDER_HEADER o ON a.ORDERNO = o.ORDERNO
+    LEFT JOIN DOC_WAVE_DETAILS w ON o.ORDERNO = w.ORDERNO
+    LEFT JOIN BAS_SKU s ON a.SKU = s.SKU
+WHERE w.WAVENO = '{$code}' ORDER BY w.SEQNO
+SQL;
+        $orders = DB::connection("oracle")->select(DB::raw($sql));
+        $result = [];
+        $currentList = [];
+        $nodeSign = "";
+        foreach ($orders as $order){
+            if ($order->seqno%$batch->split_size==0 && $nodeSign!=$order->orderno){
+                $result[] = $currentList;
+                $currentList = [];
+                $nodeSign = $order->orderno;
+            }
+            $currentList[] = ["barcode"=>$order->alternate_sku1,"qty"=>$order->qty,"location"=>$order->location];
+        }
+        if ($currentList)$result[] = $currentList;
+        $this->success($result);
+    }
 }

+ 32 - 12
app/Http/Controllers/api/thirdPart/haochuang/SortingController.php

@@ -62,6 +62,15 @@ class SortingController extends Controller
         $token = trim($request->input('token'));
         $station_id = $request->input('station_id');
         $batch_id = $request->input('batch_id');
+
+        $childIndex = null;
+        $arr = explode('-',$batch_id);
+        if (count($arr)==2){
+            $batch_id = $arr[0];
+            $childIndex = (int)$arr[1];
+            $request->offsetSet("batch_id",$batch_id);
+        }
+
         $errors=$this->processValidator($request->all())->errors();
         if(count($errors)>0){
             app('LogService')->log(__METHOD__, 'error' . __FUNCTION__, json_encode($request->all()).'|'.json_encode($errors));
@@ -74,7 +83,7 @@ class SortingController extends Controller
         // 同步orderCommodity
         $this->syncOrder($batch_id);
 
-        /** @var Batch $batch */
+        /** @var Batch|\stdClass $batch */
         $batch=Batch::query()->where('code',$batch_id)->orderBy('id','desc')->first();
         $data=[
             'result'=>'success',
@@ -82,34 +91,45 @@ class SortingController extends Controller
             'batch_id'=>$batch_id,
             'orders'=>[]
         ];
-        $ordersSorted=$batch->orders()->get()->sortBy(function(Order $order){
-            return $order->bin()->first()['number'];
+        if ($childIndex!==null && $batch->split_size){
+            $start = (($childIndex-1)*$batch->split_size)+1;
+            $end = $childIndex*$batch->split_size;
+            $sql = <<<SQL
+SELECT ORDERNO FROM DOC_WAVE_DETAILS WHERE WAVENO = '{$batch_id}' AND SEQNO BETWEEN {$start} AND {$end};
+SQL;
+            $waves = DB::connection("oracle")->select(DB::raw($sql));
+            $codes = array_column($waves,'orderno');
+            $orders = Order::query()->with(["bin","owner","orderCommodities.commodity.barcodes"])->whereIn("code",$codes)->get();
+        }else $orders = $batch->orders()->with(["bin","owner","orderCommodities.commodity.barcodes"])->get();
+
+        $ordersSorted=$orders->sortBy(function(Order $order){
+            return $order->bin->number;
         });
-        $ordersSorted->each(function(Order $order)use(&$data,$request){
+        $ordersSorted->each(function(Order $order)use(&$data,$request,$childIndex,$batch){
             if($order['status']=='取消')return;
             $orderData=[
                 'order_id'=>$order['code'],
-                'owner'=>$order->owner()->first()['code'],
+                'owner'=>$order->owner->code,
                 'status'=>$order['status']=='未处理'?'available':$order['status'],
                 'created_at'=>$order['created_at']->toDateTimeString(),
-                'bin'=>(function()use($order){
-                    $bin=$order->bin()->first()['number']??'';
+                'bin'=>(function()use($order,$childIndex,$batch){
+                    $bin=$order->bin->number??'';
                     if(!$bin){
                         $bin=OracleDOCWaveDetails::query()->where('orderno', 'SO201230003574')->get('seqno')->first()['seqno']??'';
                         LogService::log(__METHOD__,__FUNCTION__,'bin缺失补查:'.$bin.'. order:'.$order->toJson());
-                        return $bin;
+                        return $childIndex!==null ? $bin-(($childIndex-1)*$batch->split_size) : $bin;
                     }
-                    return $bin;
+                    return $childIndex!==null ? $bin-(($childIndex-1)*$batch->split_size) : $bin;
                 })(),
                 'barcodes'=>[]
             ];
-            $order->orderCommodities()->each(function(OrderCommodity $orderCommodity)use(&$orderData,$request){
-                $commodity=$orderCommodity->commodity()->first();
+            $order->orderCommodities->each(function(OrderCommodity $orderCommodity)use(&$orderData,$request){
+                $commodity=$orderCommodity->commodity;
                 if(!$commodity){
                     app('LogService')->log(__METHOD__, 'error' . __FUNCTION__, '播种位数据准备出错,找不到订单对应的Commodity id的对象'.$orderCommodity['commodity_id'].',是否表数据在波次生成后丢失?'.json_encode($request->all()));
                     return;
                 }
-                $barcodeStr=$commodity->barcodes()->get()->map(function(CommodityBarcode $barcode){
+                $barcodeStr=$commodity->barcodes->map(function(CommodityBarcode $barcode){
                     return $barcode['code'];
                 })->filter(function($code){
                     return $code&&(!preg_match('/[\x{4e00}-\x{9fa5}]/u',$code));

+ 19 - 0
app/Http/Requests/OrderDelivering.php

@@ -2,6 +2,8 @@
 
 namespace App\Http\Requests;
 
+use Illuminate\Support\Facades\Auth;
+
 class OrderDelivering extends GateRequest
 {
     public function __construct()
@@ -31,5 +33,22 @@ class OrderDelivering extends GateRequest
             $date = date('Y-m-d',strtotime("-{$increment} day"));
             request()->offsetSet("orderdate_start",$date." 00:00");
         }
+
+        if (!app("UserService")->checkAdminIdentity(Auth::id())){
+            $owners = app('OwnerService')->getIntersectPermitting(['id', 'code']);
+            $codes = array_column($owners->toArray(), 'code');
+            if (request("customerid")) {
+                $arr = explode(',', request("customerid"));
+                $customer = [];
+                foreach ($arr as $value) {
+                    if (in_array($value, $codes)) $customer[] = $value;
+                }
+                if (count($customer) < 1) $customer = [''];
+                request()->offsetSet("customerid",$customer);
+            } else request()->offsetSet("customerid",$codes);
+        }else if (request("customerid")){
+            $codes = explode(',', request("customerid"));
+            if ($codes<0)request()->offsetUnset("customerid");
+        }
     }
 }

+ 45 - 0
app/Jobs/BroadcastBatchToZhengCangJob.php

@@ -0,0 +1,45 @@
+<?php
+
+namespace App\Jobs;
+
+use App\Batch;
+use App\Services\ForeignZhenCangService;
+use Illuminate\Bus\Queueable;
+use Illuminate\Contracts\Queue\ShouldQueue;
+use Illuminate\Foundation\Bus\Dispatchable;
+use Illuminate\Queue\InteractsWithQueue;
+use Illuminate\Queue\SerializesModels;
+
+class BroadcastBatchToZhengCangJob implements ShouldQueue
+{
+    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
+
+    private $batches;
+
+    /**
+     * Create a new job instance.
+     *
+     * @return void
+     */
+    public function __construct($batches)
+    {
+        $this->batches=$batches;
+    }
+
+    /**
+     * Execute the job.
+     *
+     * @return void
+     */
+    public function handle()
+    {
+        /** @var ForeignZhenCangService  $foreignZhenCangService */
+        $foreignZhenCangService=app('ForeignZhenCangService');
+        foreach ($this->batches as &$batch){
+            $batch->loadMissing([
+                'orders.orderCommodities.commodity.barcodes'
+            ]);
+            $foreignZhenCangService->broadcastBatch($batch);
+        }
+    }
+}

+ 2 - 0
app/Jobs/LaborApplyRecordJob.php

@@ -9,6 +9,7 @@ use Illuminate\Contracts\Queue\ShouldQueue;
 use Illuminate\Foundation\Bus\Dispatchable;
 use Illuminate\Queue\InteractsWithQueue;
 use Illuminate\Queue\SerializesModels;
+use Illuminate\Support\Facades\Log;
 
 class LaborApplyRecordJob implements ShouldQueue
 {
@@ -37,6 +38,7 @@ class LaborApplyRecordJob implements ShouldQueue
      */
     public function handle()
     {
+        Log::debug("LaborApplyRecordJob isAppend = " . ($this->isAppend + 1) . "");
         $response = $this->service->allocationLaborToLaborCompany($this->isAppend);
         if (!$response['success']) throw new WarningException($response['error_message']);
     }

+ 12 - 3
app/Jobs/LogisticYDSync.php

@@ -11,14 +11,17 @@ use Illuminate\Contracts\Queue\ShouldQueue;
 use Illuminate\Foundation\Bus\Dispatchable;
 use Illuminate\Queue\InteractsWithQueue;
 use Illuminate\Queue\SerializesModels;
+use Illuminate\Support\Facades\Cache;
 
 class LogisticYDSync implements ShouldQueue
 {
+    const TAG = 'LOGISTIC_YD_SYNC';
     public $tries = 2;
 
     public $timeout = 10;
 
     use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
+
     /** @var $logistic_number string */
 
     protected $logistic_number;
@@ -46,15 +49,21 @@ class LogisticYDSync implements ShouldQueue
     {
         LogService::log(LogisticYDSync::class, "JOB-YD", $this->logistic_number);
         //标记上有同步的操作
-        OrderPackage::query()->where('logistic_number', $this->logistic_number)->update(['sync_routes_flag'=> true]);
+        OrderPackage::query()->where('logistic_number', $this->logistic_number)->update(['sync_routes_flag' => true]);
 
         $this->logisticYDService = app('LogisticYDService');
         //先订阅订单
-        $this->logisticYDService->registerApi([$this->logistic_number]);
+        $hasRegistered = Cache::tags([self::TAG])->get($this->logistic_number, false);
+        if (!$hasRegistered) {
+            $registerResult = $this->logisticYDService->registerApi([$this->logistic_number]);
+            if ($registerResult->code === '0000') {
+                Cache::tags([self::TAG])->put($this->logistic_number, true, 60 * 60 * 24 * 3);
+            }
+        }
         //查询订单路由信息
         $nativeResponse = $this->logisticYDService->query($this->logistic_number);
         //格式化信息
-        $formattedData = $this->logisticYDService->format($nativeResponse,$this->logistic_number);
+        $formattedData = $this->logisticYDService->format($nativeResponse, $this->logistic_number);
         $this->orderPackageReceivedSyncService = app('OrderPackageReceivedSyncService');
         //更新数据
         $this->orderPackageReceivedSyncService->update([$formattedData]);

+ 1 - 1
app/Jobs/LogisticYTOSync.php

@@ -58,7 +58,7 @@ class LogisticYTOSync implements ShouldQueue
         try {
             if ($formattedData && isset($formattedData['logistic_number'])) $this->orderPackageReceivedSyncService->update([$formattedData]);
         } catch (\Exception $e) {
-            LogService::log(LogisticYTOService::class, "YTO快递无快递单号异常", json_encode($formattedData));
+//            LogService::log(LogisticYTOService::class, "YTO快递无快递单号异常", json_encode($formattedData));
         }
     }
 }

+ 6 - 0
app/LaborCompanyDispatch.php

@@ -25,6 +25,7 @@ class LaborCompanyDispatch extends Model
         'exceed_max_labor_num_status',//是否超过最大允许值 1 未超过 2 超过
         'status',//状态
         'warehouse_id',//仓库ID
+        'check_user_id',//确认人ID
     ];
 
 
@@ -78,6 +79,11 @@ class LaborCompanyDispatch extends Model
         return $this->belongsTo(Warehouse::class);
     }
 
+    public function checkUser(): BelongsTo
+    {
+        return $this->belongsTo(User::class, 'check_user_id', 'id');
+    }
+
     public function scopeFilter($query, $filters)
     {
         return $filters->apply($query);

+ 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');
+
+    }
 }

+ 2 - 0
app/Providers/AppServiceProvider.php

@@ -190,6 +190,7 @@ use App\Services\WorkOrderImageService;
 use App\Services\WorkOrderProcessLogService;
 use App\Services\LaborApplyService;
 use App\Services\SyriusTaskService;
+use App\Services\ReplenishmentService;
 
 class AppServiceProvider extends ServiceProvider
 {
@@ -391,6 +392,7 @@ class AppServiceProvider extends ServiceProvider
         app()->singleton('WorkOrderProcessLogService',WorkOrderProcessLogService::class);
         app()->singleton('WorkOrderService',WorkOrderService::class);
         app()->singleton('WorkOrderTypeService',WorkOrderTypeService::class);
+        app()->singleton('ReplenishmentService',ReplenishmentService::class);
     }
 
     private function registerObserver()

+ 1 - 5
app/Services/ForeignZhenCangService.php

@@ -33,13 +33,9 @@ class ForeignZhenCangService
             }
             $body['orders'][] = $orderArr;
         }
+        dd($body);
         $response = Http::withHeaders([
             'Host' => 'zc-it.com',
         ])->post('http://1.116.164.201:8080/api/createBatch',$body);
     }
-
-    public function broadcastBatchByFlux()
-    {
-
-    }
 }

+ 1 - 1
app/Services/HandInStorageService.php

@@ -453,7 +453,7 @@ sql;
      * @throws \Throwable
      * flux手持端 上架
      */
-    public function fluxHandPa(array $info, array $taskParam): bool
+    public function fluxHandPa(array $info, array $taskParam)
     {
         $tasks = $this->selectFluxTask($taskParam, $info['amount']);
         if (!$tasks) return false; //获取任务失败

+ 5 - 2
app/Services/LaborApplyService.php

@@ -92,11 +92,12 @@ class LaborApplyService
         $warehouses = Warehouse::all();
         //给每个仓库计算分配数据 更改申请状态为指派成功
         foreach ($warehouses as $warehouse) {
-            //查询当日的的申请,将申请的男女工分别加和
+            //根据时间,仓库,状态 查询当日的的申请,将申请的男女工分别加和
             $builder = DB::table('labor_applies')
                 ->selectRaw("sum(man_num) as man_num ,sum(woman_num) as woman_num")
                 ->whereBetween('created_at', [now()->startOfDay(), now()->endOfDay()])
-                ->where('warehouse_id', $warehouse->id);
+                ->where('warehouse_id', $warehouse->id)
+                ->where('status', 1);
             //如果是追加模式
             if ($isAppend) {
                 //只查询最后一次分配后的申请
@@ -154,6 +155,8 @@ class LaborApplyService
                 'exceed_max_labor_num_status' => LaborCompanyDispatch::NOT_EXCEED_MAX_LABOR_NUM,//没有超限额
                 'status' => 1,//创建
                 'warehouse_id' => $warehouse_id,
+                'created_at' => now(),
+                'updated_at' => now(),
             ];
         }
         //分配男工

+ 2 - 3
app/Services/LogisticSFService.php

@@ -5,7 +5,6 @@ namespace App\Services;
 
 
 use App\Exceptions\WarningException;
-use App\Traits\LogisticSyncTrait;
 use Exception;
 use Illuminate\Http\Client\Response;
 use Illuminate\Support\Facades\Http;
@@ -104,7 +103,7 @@ xml;
             $data = $this->switchOpCodeToStatus($lastRoute, $data);
             $data['transfer_status'] = $this->transformRoutes($routeResponse['Route']);
         } catch (Exception $e) {
-            throw new WarningException("单号没有查询到快递路由信息','LogisticSFService->transformSFOneToArr->{$data['logistic_number']}");
+//            throw new WarningException("单号没有查询到快递路由信息','LogisticSFService->transformSFOneToArr->{$data['logistic_number']}");
         } finally {
             $data['routes_length'] = array_key_exists('transfer_status', $data) ? count($data['transfer_status']) : 0;
             return $data;
@@ -196,7 +195,7 @@ xml;
         try {
             $response = Http::withHeaders(['Content-Type' => 'text/xml'])->get($url, ['xml' => $xml, 'verifyCode' => $verifyCode]);
         } catch (Exception $e) {
-            throw new WarningException("HTTP请求顺丰接口异常->{$e->getMessage()}");
+//            throw new WarningException("HTTP请求顺丰接口异常->{$e->getMessage()}");
         }
         return $response;
     }

+ 1 - 1
app/Services/LogisticYTOService.php

@@ -53,7 +53,7 @@ class LogisticYTOService
             try {
                 if (is_array($response))$result['logistic_number'] = $response[0]->waybill_No;
             } catch (\Exception $e) {
-                LogService::log(LogisticYTOService::class, "YTO快递信息异常", $logistic_number);
+//                LogService::log(LogisticYTOService::class, "YTO快递信息异常", $logistic_number);
                 return [
                     'logistic_number' => $logistic_number,
                 ];

+ 2 - 2
app/Services/OwnerService.php

@@ -124,8 +124,8 @@ class OwnerService implements UserFilter
     }
 
     public function firstOrCreate(array $params, array $values = null){
-        if (!$values) return Owner::query()->firstOrCreate($params);
-        return Owner::query()->firstOrCreate($params,$values);
+        if (!$values) return Owner::query()->whereNull("deleted_at")->firstOrCreate($params);
+        return Owner::query()->whereNull("deleted_at")->firstOrCreate($params,$values);
     }
 
 

+ 1 - 1
app/Services/RejectedBillService.php

@@ -392,7 +392,7 @@ class RejectedBillService
         if ($stores->count())return;
         $rejectedBill->loadMissing("items");
         $GLOBALS["FEE_INFO"] = [];
-        list($id,$money,$taxFee) = $service->matching($rejectedBill, Feature::MAPPING["rejected_bill"], $rejectedBill->id_owner, "入库",0);
+        list($id,$money,$taxFee) = $service->matching(substr($rejectedBill->updated_at,0,7),$rejectedBill, Feature::MAPPING["rejected_bill"], $rejectedBill->id_owner, "入库",0);
         app("OwnerFeeDetailService")->create([
             "owner_id" => $rejectedBill->id_owner,
             "worked_at" => $rejectedBill->updated_at,

+ 184 - 0
app/Services/ReplenishmentService.php

@@ -0,0 +1,184 @@
+<?php
+
+namespace App\Services;
+
+use App\Traits\ServiceAppAop;
+use Carbon\Carbon;
+use Illuminate\Support\Facades\DB;
+
+
+class ReplenishmentService
+{
+    use ServiceAppAop;
+
+    /**
+     * @param $customer
+     * @return array
+     * 根据货主,订单状态为拣货完成之前的
+     * 订单信息
+     */
+    public function getOrderInfoRecentMonthByCustomer($customer): array
+    {
+        $db = DB::connection("oracle");
+        $sql = <<<sql
+select orders.customerid, orders.sku,orders.amount,BAS_SKU.ALTERNATE_SKU1,BAS_SKU.ALTERNATE_SKU2,BAS_SKU.ALTERNATE_SKU3
+from (
+         select customerid, sku, sum(QTYORDERED_EACH) amount
+         from DOC_ORDER_DETAILS
+         where ORDERNO in (select ORDERNO
+                           from DOC_ORDER_HEADER
+                           where SOSTATUS IN ('00', '10', '20', '30', '40', '50')
+                             AND customerid = ?
+                             AND ADDTIME >= TO_DATE(?, 'yyyy-mm-dd hh24:mi:ss')
+                             AND ADDTIME <= TO_DATE(?, 'yyyy-mm-dd hh24:mi:ss'))
+         group by customerid, sku
+     ) orders
+left join BAS_SKU on orders.customerid=BAS_SKU.customerid and orders.sku = BAS_SKU.SKU
+order by orders.amount desc
+sql;
+        $res= $db->select(DB::raw($sql),[$customer,Carbon::now()->subDays(30)->toDateTimeString(),Carbon::now()->toDateTimeString()]);
+        $orders=array();
+        foreach ($res as $item){
+            $orders[]=json_decode( json_encode( $item),true);
+        }
+        return $orders;
+
+    }
+
+    /**
+     * @param $customer
+     * @param array $skuArr
+     * @return array
+     * 根据货主和发货sku 获取库存拣货位及拣货位商品数量
+     * 并整合为sku 为key的数组
+     */
+    public function getEaInventoryByCustomerAndSku($customer,array $skuArr): array
+    {
+        $db = DB::connection("oracle");
+        $info=array();
+        foreach (array_chunk($skuArr,1000) as $item){
+            $sql = <<<sql
+select INV_LOT_LOC_ID.CUSTOMERID,INV_LOT_LOC_ID.SKU,INV_LOT_LOC_ID.LOCATIONID,sum(INV_LOT_LOC_ID.QTY) qty
+from INV_LOT_LOC_ID
+         left join BAS_LOCATION on BAS_LOCATION.LOCATIONID = INV_LOT_LOC_ID.LOCATIONID
+where BAS_LOCATION.LOCATIONUSAGE = 'EA'
+  AND customerid = ?
+
+sql;
+        if (count($item) > 0) {
+            $sql .= " and sku in (";
+            foreach ($item as $index => $str) {
+                if ($index == 0) {
+                    $sql .= "'" . $str . "'";
+                    continue;
+                }
+                $sql .= ",'" . $str . "'";
+            }
+            $sql .= ")";
+        }
+            $sql.= ' group by INV_LOT_LOC_ID.CUSTOMERID,INV_LOT_LOC_ID.SKU,INV_LOT_LOC_ID.LOCATIONID';
+            $info[]= $db->select(DB::raw($sql),[$customer]);
+        }
+        $info = array_merge(...$info);
+        //整合同sku下的拣货库位
+        $tmpArray = array();
+        foreach ($info as $row) {
+            $key = $row->sku;
+            if (array_key_exists($key, $tmpArray)) {
+                if (is_array($tmpArray[$key]['locationid'])) {
+                    $tmpArray[$key]['locationid'][] = $row->locationid;
+                } else {
+                    $tmpArray[$key]['locationid'] = array($tmpArray[$key]['locationid'], $row->locationid);
+                }
+                if ($tmpArray[$key]['qty']) {
+                    $tmpArray[$key]['qty'] += $row->qty;
+                } else {
+                    $tmpArray[$key]['qty'] =  $row->qty;
+                }
+            } else {
+                $tmpArray[$key] = array('sku'=>$row->sku,'locationid'=>array($row->locationid),'qty'=>$row->qty);
+            }
+        }
+        return $tmpArray;
+    }
+
+    /**
+     * @param $customer
+     * @param array $skuArr
+     * @return array
+     * 根据货主和发货sku 获取库存存储位及存储位商品数量
+     * 并整合为sku 为key的数组
+     */
+    public function getRsInventoryByCustomerAndSku($customer,array $skuArr): array
+    {
+        $db = DB::connection("oracle");
+        $info=array();
+        foreach (array_chunk($skuArr,1000) as $item){
+            $sql = <<<sql
+select INV_LOT_LOC_ID.CUSTOMERID,INV_LOT_LOC_ID.SKU,INV_LOT_LOC_ID.LOCATIONID,INV_LOT_LOC_ID.LOTNUM,sum(INV_LOT_LOC_ID.QTY) qty
+from INV_LOT_LOC_ID
+         left join BAS_LOCATION on BAS_LOCATION.LOCATIONID = INV_LOT_LOC_ID.LOCATIONID
+where BAS_LOCATION.LOCATIONUSAGE = 'RS'
+  AND customerid = ?
+sql;
+            if (count($item) > 0) {
+                $sql .= " and sku in (";
+                foreach ($item as $index => $str) {
+                    if ($index == 0) {
+                        $sql .= "'" . $str . "'";
+                        continue;
+                    }
+                    $sql .= ",'" . $str . "'";
+                }
+                $sql .= ")";
+            }
+            $sql.= ' group by INV_LOT_LOC_ID.CUSTOMERID,INV_LOT_LOC_ID.SKU,INV_LOT_LOC_ID.LOCATIONID,INV_LOT_LOC_ID.LOTNUM order by qty desc';
+            $info[]= $db->select(DB::raw($sql),[$customer]);
+        }
+        $info=array_merge(...$info);
+        //整合同sku下的存储库位
+        $tmpArray = array();
+        foreach ($info as $row) {
+            $key = $row->sku;
+            if (array_key_exists($key, $tmpArray)) {
+                if (is_array($tmpArray[$key]['locationid'])) {
+                    if (count($tmpArray[$key]['locationid'])<5){
+                        $tmpArray[$key]['locationid'][] = ['location'=>$row->locationid,'qty'=>$row->qty,'lot'=>$row->lotnum];
+                    }
+                } else {
+                    $tmpArray[$key]['locationid'] = array($tmpArray[$key]['locationid'], ['location'=>$row->locationid,'qty'=>$row->qty,'lot'=>$row->lotnum]);
+                }
+            } else {
+                $tmpArray[$key] = array('sku'=>$row->sku,'locationid'=>array(['location'=>$row->locationid,'qty'=>$row->qty,'lot'=>$row->lotnum]));
+            }
+        }
+        return $tmpArray;
+    }
+
+    public function combinationSql(array $skuArr,$sql)
+    {
+        foreach (array_chunk($skuArr,1000) as $index=>$item){
+            if ($index==0){
+                $sql .= " and sku in (";
+                foreach ($item as $i => $str) {
+                    if ($i == 0) {
+                        $sql .= "'" . $str . "'";
+                        continue;
+                    }
+                    $sql .= ",'" . $str . "'";
+                }
+            }else{
+                $sql .= " or sku in (";
+                foreach ($item as $a => $str) {
+                    if ($a == 0) {
+                        $sql .= "'" . $str . "'";
+                        continue;
+                    }
+                    $sql .= ",'" . $str . "'";
+                }
+            }
+            $sql .= ")";
+        }
+        return $sql;
+    }
+}

+ 1 - 1
app/Traits/LogisticSyncTrait.php

@@ -199,7 +199,7 @@ trait LogisticSyncTrait
         if ((!empty($logistic_id)) && ($logistic_id === 6 || $logistic_id === 88)) {
             if (!empty($transfer_status)) {
                 $this->sortTransferStatusByAcceptTimeDESC($transfer_status);
-                $last_remark = $this->getLastRemark($transfer_status);
+                $last_remark = $this->getLastRemark($transfer_status[0]);
                 if (Str::contains($last_remark, ['等待揽收', '商品已下单'])) {
                     $data['status'] = '已复核';
                 }

+ 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": {

+ 32 - 0
database/migrations/2021_11_08_133051_add_chick_user_id_to_labor_company_dispatches_table.php

@@ -0,0 +1,32 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+class AddChickUserIdToLaborCompanyDispatchesTable extends Migration
+{
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        Schema::table('labor_company_dispatches', function (Blueprint $table) {
+            $table->unsignedInteger('check_user_id')->nullable()->comment('确认人ID');
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        Schema::table('labor_company_dispatches', function (Blueprint $table) {
+            $table->dropColumn('check_user_id');
+        });
+    }
+}

+ 32 - 0
database/migrations/2021_11_08_152146_change_batches_add_column_partition_size.php

@@ -0,0 +1,32 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+class ChangeBatchesAddColumnPartitionSize extends Migration
+{
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        Schema::table('batches', function (Blueprint $table) {
+            $table->integer("split_size")->nullable()->comment("分割大小");
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        Schema::table('batches', function (Blueprint $table) {
+            $table->dropColumn("split_size");
+        });
+    }
+}

+ 141 - 0
resources/views/inventory/stockOut/index.blade.php

@@ -0,0 +1,141 @@
+@extends('layouts.app')
+@section('title')库存管理-补货列表@endsection
+@section('content')
+    <div id="list" class="d-none item-logistic-index">
+        <div class="container-fluid">
+            <div class="m-2 form-inline" id="btn">
+                <select class="form-control form-control-sm tooltipTarget" name="owner_id" id="owner_id"
+                        style="width: 150px;position: relative" title="选择指定货主" v-model="owner_id">
+                    <option value="">货主</option>
+                    <option v-for="owner in owners" :value="owner.name">@{{ owner.value }}</option>
+                </select>
+                <input placeholder="定位货主" id="ownerName" autocomplete="off" @input="定位货主($event)"
+                       class="form-control form-control-sm tooltipTarget" style="width: 100px" title="输入关键字定位货主">
+                <button class="btn btn-sm btn-outline-info ml-3" @click="search()" >查询</button>
+
+                <button type="button"
+                        @click="orderItemExport(true)"
+                        class="btn btn-outline-dark btn-sm ml-2"
+                        title="导出所有页将会以搜索条件得到的筛选结果,将其全部记录(每一页)导出">导出Excel
+                </button>
+
+            </div>
+            <table class="table table-striped table-bordered table-hover card-body td-min-width-80" id="table">
+                <tr v-if="item.amount > 0 " v-for="(item,i) in details" @click="selectTr===i+1?selectTr=0:selectTr=i+1"
+                    :class="selectTr===i+1?'focusing' : ''">
+                    <td>@{{ item.customerid }}</td>
+                    <td>@{{ item.sku }}</td>
+                    <td>@{{ item.alternate_sku1 }}</td>
+                    <td>
+                        <ul style="list-style: none" v-if="item.eaLocation.length>0">
+                            <li v-for="(v,k) in item.eaLocation" v-if="k<3 || item.moreEaLocation">@{{ v }}</li>
+                            <a v-if="item.eaLocation.length >= 3" href="javascript:;"
+                               @click="item.moreEaLocation = !(item.moreEaLocation)">展示更多</a>
+                        </ul>
+                        <div v-else>拣货库位不存在</div>
+                    </td>
+                    <td>@{{ item.amount }}</td>
+                    <td>
+                        <ul style="list-style: none">
+                            <li v-for="(v,k) in item.rsLocation" v-if="k<3 || item.moreRaLocation">@{{ v.location }}
+                                <span class="font-weight-bold text-dark">&nbsp;&nbsp;&nbsp;:@{{ v.qty }}</span>
+                                <span class="font-weight-bold text-dark">&nbsp;&nbsp;&nbsp;:@{{ v.lot }}</span>
+                            </li>
+                            <a v-if="item.rsLocation.length >= 3" href="#javascript:;"
+                               @click="item.moreRaLocation = !(item.moreRaLocation)">展示更多</a>
+                        </ul>
+                    </td>
+                </tr>
+            </table>
+        </div>
+    </div>
+@endsection
+
+@section('lastScript')
+    <script type="text/javascript" src="{{mix('js/queryForm/export.js')}}"></script>
+    <script type="text/javascript" src="{{mix('js/queryForm/header.js')}}"></script>{{--新版2--}}
+    <script>
+        let vue = new Vue({
+            el: "#list",
+            data: {
+                selectTr: 0,
+                owner_id: '',
+                owners: [
+                        @foreach($owners as $owner)
+                    {
+                        name: '{{$owner->code}}', value: '{{$owner->name}}'
+                    },
+                    @endforeach
+                ],
+                details: []
+            },
+            created() {
+            },
+            mounted() {
+                $('#list').removeClass('d-none');
+                $(".up").slideUp();
+                let column = [
+                    {name: 'owner_name', value: '货主'},
+                    {name: 'sku', value: '商品名称'},
+                    {name: 'barcode', value: '商品条码'},
+                    {name: 'ea_location', value: '拣货库位'},
+                    {name: 'amount', value: '缺货数'},
+                    {name: 'rs_location', value: '存储库位'},
+                ];
+                new Header({
+                    el: "table",
+                    name: "item",
+                    column: column,
+                    data: this.details,
+                    restorationColumn: 'addtime',
+                    fixedTop: ($('#form_div').height()) + ($('#btn').height()) + 1,
+                }).init();
+                $('#table tr:eq(0) th:eq(0)').remove();
+            },
+            methods: {
+                orderItemExport(sign) {
+                    if (this.owner_id === '') {
+                        tempTip.show('请选择货主!');
+                        return;
+                    }
+                    let url = '{{url('inventory/stockOut/export')}}';
+                    let token = '{{ csrf_token() }}';
+                    if (sign) {
+                        excelExport(true, checkData, url, this.total, token, {customer: this.owner_id});
+                    }
+                },
+
+                定位货主(e) {
+                    this.owners.some(owner => {
+                        if (owner.value.indexOf(e.target.value) !== -1) {
+                            this.owner_id = owner.name;
+                            return true;
+                        }
+                    });
+                    if (e.target.value === '' || e.target.value === null || e.target.value === undefined) {
+                        this.owner_id = '';
+                    }
+                },
+
+                search() {
+                    let url = "{{ url('inventory/stockOut/getReplenishmentInfoByCustomer') }}"
+                    axios.post(url, {
+                        customer: this.owner_id
+                    }).then(res => {
+                        if (res.data.success){
+                            this.details = res.data.data
+                        }else {
+                            window.tempTip.show(res.data.data);
+                            window.tempTip.setDuration(2000);
+                        }
+
+                    }).catch(function (err){
+                        window.tempTip.show('网络异常'+err);
+                        window.tempTip.setDuration(2000);
+                    });
+                }
+            },
+            filters: {},
+        });
+    </script>
+@endsection

+ 174 - 0
resources/views/kpi/day/index.blade.php

@@ -0,0 +1,174 @@
+@extends('layouts.app')
+@section('title')KPI-日报表@endsection
+@section('content')
+    <div class="d-none" id="list">
+        <div class="container-fluid">
+            <div id="form_div"></div>
+            <!--            导出-->
+            <span class="dropdown"></span>
+            <h3>2021</h3>
+            <!--            表格-->
+            <table class="table table-striped table-bordered table-hover text-nowrap waybill-table td-min-width-80"
+                   style="background: #fff;" id="table">
+                <tr v-for="(item,i) in details.data" :key="i">
+                    <td><input class="checkItem" type="checkbox" :value="item.id"></td>
+                    <td class="td-warm text-muted"><span>@{{ item.statTime.slice(0,10) }}</span></td>
+                    <td class="td-warm text-muted"><span>@{{ item.avgOnDutyTime }}</span></td>
+                    <td class="td-warm text-muted"><span>@{{ item.avgOffDutyTime }}</span></td>
+                    <td class="td-warm text-muted"><span>@{{ item.attendanceNum }}</span></td>
+                    <td class="td-warm text-muted"><span>@{{ Math.round(item.workTimes) }}</span></td>
+                    <td class="td-warm text-muted"><span>@{{ item.totalDeliveryQty }}</span></td>
+                    <td class="td-warm text-muted"><span>@{{ item.expressCollectQty }}</span></td>
+                    <td class="td-warm text-muted"><span>@{{ item.whDeliveryNum }}</span></td>
+                    <td class="td-warm text-muted"><span>@{{ item.transferDeliveryNum }}</span></td>
+                    <td class="td-warm text-muted"><span>@{{ item.purchaseEntryNum }}</span></td>
+                    <td class="td-warm text-muted"><span>@{{ item.transferEntryNum }}</span></td>
+                    <td class="td-warm text-muted"><span>@{{ item.returnEntryNum }}</span></td>
+                    <td class="td-warm text-muted"><span>@{{ item.inventoryNum }}</span></td>
+                    <td class="td-warm text-muted"><span>@{{ item.inventoryQty }}</span></td>
+                    <td class="td-warm text-muted"><span>@{{ item.occupationArea }}</span></td>
+                    <td class="td-warm text-muted"><span>@{{ item.delay24Qty }}</span></td>
+                    <td class="td-warm text-muted"><span>@{{ item.delay48Qty }}</span></td>
+                </tr>
+            </table>
+            <nav aria-label="...">
+                <ul class="pagination">
+                    <li class="page-item" :class="current===1?'disabled':''">
+                        <button class="page-link" @click="pagination('pre')">上一页</button>
+                    </li>
+                    <li class="page-item" :class="current===details.pages?'disabled':''">
+                        <button class="page-link" @click="pagination('next')">下一页</button>
+                    </li>
+                </ul>
+            </nav>
+        </div>
+    </div>
+
+
+@endsection
+
+@section('lastScript')
+    <script type="text/javascript" src="{{mix('js/queryForm/export.js')}}"></script>
+    <script type="text/javascript" src="{{mix('js/queryForm/queryForm.js')}}"></script>
+    <script type="text/javascript" src="{{mix('js/queryForm/header.js')}}"></script>{{--新版2--}}
+    <script>
+        let vue = new Vue({
+            el: "#list",
+            data: {
+                selectTr: '',
+                details: {
+                    data: [],
+                    total: null,
+                    current: null,
+                    pages: null,
+                    size: null
+                },
+                size: 10,
+                current: 1
+            },
+            created() {
+                let url = this.getBaseUrl();
+                url += `/api/deliver/getDayPage?size=${this.size}&current=${this.current}`;
+                axios.get(url).then(res => {
+                    this.details.data = res.data.data.list;
+                    this.details.total = res.data.data.page.total;
+                    this.details.current = res.data.data.page.pageNum;
+                    this.details.pages = res.data.data.page.pages
+                    this.details.size = res.data.data.page.pageSize;
+                });
+            },
+            mounted: function () {
+                $('#list').removeClass('d-none');
+                let data = [
+                    [
+                        {name: 'date_start', type: 'time', tip: '选择显示指定日期的起始时间'},
+                    ]
+                ];
+                this.form = new query({
+                    el: "#form_div",
+                    condition: data,
+                });
+                this.form.init();
+                this.rendingHeader();
+
+            },
+            methods: {
+                //根据环境获取不同的url
+                getBaseUrl() {
+                    let url = '';
+                    let env = "{{ config('app.env') }}";
+                    if (env === 'local') {
+                        url = ' http://127.0.0.1:8111'
+                    } else if (env === 'production') {
+                        url = ' http://101.133.135.193'
+                    }
+                    return url;
+                },
+                pagination(flag) {
+                    if (flag === 'pre' && this.current > 1) {
+                        this.current--;
+                    } else if (flag === 'next' && this.current < this.details.pages) {
+                        this.current++;
+                    }
+                    let env = "{{ config('env') }}";
+                    console.log(env);
+                    let url = this.getBaseUrl();
+
+                    url += `/api/deliver/getDayPage?size=${this.size}&current=${this.current}`;
+                    axios.get(url).then(res => {
+                        this.details.data = res.data.data.list;
+                        this.details.total = res.data.data.page.total;
+                        this.details.current = res.data.data.page.pageNum;
+                        this.details.pages = res.data.data.page.pages
+                        this.details.size = res.data.data.page.pageSize;
+                    });
+                },
+                rendingHeader() {
+                    let column = [
+                        {name: 'stat_time', value: '统计日期', neglect: true, class: "td-cool"},
+                        {name: 'avg_on_duty_time', value: '平均上班时间', neglect: true, class: "td-cool"},
+                        {name: 'avg_off_duty_time', value: '平均下班时间', class: "td-cool"},
+                        {name: 'attendance_num', value: '出勤人数', neglect: true, class: "td-cool"},
+                        {name: 'work_times', value: '生产工时', class: "td-cool"},
+
+                        {name: 'total_delivery_qty', value: '总发货量', class: "td-warm"},
+                        {name: 'express_collect_qty', value: '快递揽收数量', neglect: true, class: "td-warm"},
+                        {name: 'wh_delivery_num', value: '仓库发货个数', class: "td-warm"},
+                        {name: 'transfer_delivery_num', value: '调拨出库总个数', class: "td-warm"},
+
+                        {name: 'purchase_entry_num', value: '采购入库数', class: "td-cool"},
+                        {name: 'transfer_entry_num', value: '调拨入库数', class: "td-cool"},
+                        {name: 'return_entry_num', value: '退货入库数', class: "td-cool"},
+
+                        {name: 'inventory_num', value: '盘点库位数', class: "td-warm"},
+                        {name: 'inventory_qty', value: '盘点数量', class: "td-warm"},
+                        {name: 'occupation_area', value: '盘点数量', class: "td-warm"},
+
+                        {name: 'delay_24_qty', value: '24小时延迟数', neglect: true, class: "td-cool"},
+                        {name: 'delay_48_qty', value: '24小时延迟数', neglect: true, class: "td-cool"},
+                    ];
+                    new Header({
+                        el: "table",
+                        name: "details",
+                        column: column,
+                        data: this.details.data,
+                        restorationColumn: 'id',
+                        fixedTop: ($('#form_div').height()) + ($('#btn').height()) + 2,
+                        before: [
+                            {colspan: '6', value: '人员工时(含临时工)', class: "table-header-layer-1"},
+                            {
+                                colspan: '4',
+                                value: '出库',
+                                font: "fa fa-file-text-o",
+                                class: "table-header-layer-1"
+                            },
+                            {colspan: '3', value: '入库', font: "fa fa-truck", class: "table-header-layer-1"},
+                            {colspan: '3', value: '库存', font: "fa fa-truck", class: "table-header-layer-1"},
+                            {colspan: '2', value: '异常', font: "fa fa-truck", class: "table-header-layer-1"},
+                        ],
+                    }).init();
+                },
+            },
+        });
+    </script>
+@endsection

+ 186 - 0
resources/views/kpi/month/index.blade.php

@@ -0,0 +1,186 @@
+@extends('layouts.app')
+@section('title')KPI-月报表@endsection
+@section('content')
+    <div class="d-none" id="list">
+        <div class="container-fluid">
+            <div id="form_div"></div>
+            <!--            导出-->
+            <span class="dropdown"></span>
+            <h3>2021</h3>
+            <!--            表格-->
+            <table class="table table-striped table-bordered table-hover text-nowrap waybill-table td-min-width-80"
+                   style="background: #fff;" id="table">
+                <tr v-for="(item,i) in details.data" :key="i">
+                    <td><input class="checkItem" type="checkbox" :value="item.id"></td>
+                    <td class="td-warm text-muted"><span>@{{item.userWorkgroupName}}</span></td>
+                    <td class="td-warm text-muted"><span>@{{item.statTime.slice(0,10)}}</span></td>
+                    <td class="td-warm text-muted"><span>@{{item.purchseEntry}}</span></td>
+                    <td class="td-warm text-muted"><span>@{{item.allocateTransferEntry}}</span></td>
+                    <td class="td-warm text-muted"><span>@{{item.b2bEntry}}</span></td>
+                    <td class="td-warm text-muted"><span>@{{item.inWarehouseEntry}}</span></td>
+                    <td class="td-warm text-muted"><span>@{{item.otherEntry}}</span></td>
+                    <td class="td-warm text-muted"><span>@{{item.returnEntry}}</span></td>
+                    <td class="td-warm text-muted"><span>@{{item.barterEntry}}</span></td>
+                    <td class="td-warm text-muted"><span>@{{item.adjustEntry}}</span></td>
+                    <td class="td-warm text-muted"><span>@{{item.virtualEntry}}</span></td>
+                    <td class="td-warm text-muted"><span>@{{item.overtimeShelve}}</span></td>
+                    <td class="td-warm text-muted"><span>@{{item.b2cDeliveryQty}}</span></td>
+                    <td class="td-warm text-muted"><span>@{{item.b2cDeliveryNum}}</span></td>
+                    <td class="td-warm text-muted"><span>@{{item.b2cDelayNum}}</span></td>
+                    <td class="td-warm text-muted"><span>@{{item.b2cErrorNum}}</span></td>
+                    <td class="td-warm text-muted"><span>@{{item.b2cComplainNum}}</span></td>
+                    <td class="td-warm text-muted"><span>@{{item.b2bDeliveryNum}}</span></td>
+                    <td class="td-warm text-muted"><span>@{{item.b2bDeliveryQty}}</span></td>
+                    <td class="td-warm text-muted"><span>@{{item.b2bComplainNum}}</span></td>
+                    <td class="td-warm text-muted"><span>@{{item.b2bDeliveryBulk}}</span></td>
+                    <td class="td-warm text-muted"><span>@{{item.b2bDeliveryWeigh}}</span></td>
+                    <td class="td-warm text-muted"><span>@{{item.inventory}}</span></td>
+                    <td class="td-warm text-muted"><span>@{{item.inventoryProfit}}</span></td>
+                    <td class="td-warm text-muted"><span>@{{item.inventoryLoss}}</span></td>
+                </tr>
+            </table>
+            <nav aria-label="...">
+                <ul class="pagination">
+                    <li class="page-item" :class="current===1?'disabled':''">
+                        <button class="page-link" @click="pagination('pre')">上一页</button>
+                    </li>
+                    <li class="page-item" :class="current===details.pages?'disabled':''">
+                        <button class="page-link" @click="pagination('next')">下一页</button>
+                    </li>
+                </ul>
+            </nav>
+        </div>
+    </div>
+
+
+@endsection
+
+@section('lastScript')
+    <script type="text/javascript" src="{{mix('js/queryForm/export.js')}}"></script>
+    <script type="text/javascript" src="{{mix('js/queryForm/queryForm.js')}}"></script>
+    <script type="text/javascript" src="{{mix('js/queryForm/header.js')}}"></script>{{--新版2--}}
+    <script>
+        let vue = new Vue({
+            el: "#list",
+            data: {
+                selectTr: '',
+                details: {
+                    data: [],
+                    total: null,
+                    current: null,
+                    pages: null,
+                    size: null
+                },
+                size: 10,
+                current: 1
+            },
+            created() {
+                let url = this.getBaseUrl();
+                url += `/api/deliver/getMonthPage?size=${this.size}&current=${this.current}`;
+                axios.get(url).then(res => {
+                    this.details.data = res.data.data.list;
+                    this.details.total = res.data.data.page.total;
+                    this.details.current = res.data.data.page.pageNum;
+                    this.details.pages = res.data.data.page.pages
+                    this.details.size = res.data.data.page.pageSize;
+                });
+            },
+            mounted: function () {
+                $('#list').removeClass('d-none');
+                let data = [
+                    [
+                        {name: 'date_start', type: 'dateTime', tip: '选择显示指定日期的起始时间'},
+                    ]
+                ];
+                this.form = new query({
+                    el: "#form_div",
+                    condition: data,
+                });
+                this.form.init();
+                this.rendingHeader();
+
+            },
+            methods: {
+                getBaseUrl() {
+                    let url = '';
+                    let env = "{{ config('app.env') }}";
+                    if (env === 'local') {
+                        url = ' http://127.0.0.1:8111'
+                    } else if (env === 'production') {
+                        url = ' http://101.133.135.193'
+                    }
+                    return url;
+                },
+                pagination(flag) {
+                    console.log(flag);
+                    if (flag === 'pre' && this.current > 1) {
+                        this.current--;
+                    } else if (flag === 'next' && this.current < this.details.pages) {
+                        this.current++;
+                    }
+                    console.log(this.current, this.details.pages);
+                    let url = this.getBaseUrl();
+                    url += `/api/deliver/getMonthPage?size=${this.size}&current=${this.current}`;
+                    axios.get(url).then(res => {
+                        this.details.data = res.data.data.list;
+                        this.details.total = res.data.data.page.total;
+                        this.details.current = res.data.data.page.pageNum;
+                        this.details.pages = res.data.data.page.pages
+                        this.details.size = res.data.data.page.pageSize;
+                    });
+                },
+                rendingHeader() {
+                    let column = [
+                        {name: 'workgroupName', value: '组名', neglect: true, class: "td-warm"},
+                        {name: 'month', value: '月份', class: "td-warm"},
+                        {name: 'purchseEntry', value: '入库采购', neglect: true, class: "td-warm"},
+                        {name: 'allocateTransferEntry', value: '调拨入库', class: "td-warm"},
+                        {name: 'b2bEntry', value: 'B2B入库', class: "td-warm"},
+                        {name: 'inWarehouseEntry', value: '进仓入库', neglect: true, class: "td-warm"},
+                        {name: 'otherEntry', value: '其他入库', class: "td-warm"},
+                        {name: 'returnEntry', value: '退货入库', class: "td-warm"},
+                        {name: 'barterEntry', value: '换货入库', class: "td-warm"},
+                        {name: 'adjustEntry', value: '调整入库', class: "td-warm"},
+                        {name: 'virtualEntry', value: '虚拟入库', class: "td-warm"},
+                        {name: 'overtimeShelve', value: '未及时上架', class: "td-warm"},
+
+
+                        {name: 'b2cDeliveryQty', value: 'B2C发货个数', class: "td-cool"},
+                        {name: 'b2cDeliveryNum', value: 'B2C发货单数', class: "td-cool"},
+                        {name: 'b2cDelayNum', value: 'B2C延误单数', neglect: true, class: "td-cool"},
+                        {name: 'b2cErrorNum', value: 'B2C错漏发单数', neglect: true, class: "td-cool"},
+                        {name: 'b2cComplainNum', value: 'B2C客诉单数', class: "td-cool"},
+                        {name: 'b2bDeliveryNum', value: 'B2B发货行数', neglect: true, class: "td-cool"},
+                        {name: 'b2bDeliveryQty', value: 'B2B发货个数', class: "td-cool"},
+                        {name: 'b2bComplainNum', value: 'B2B客诉行数', class: "td-cool"},
+                        {name: 'b2bDeliveryBulk', value: 'B2B发货体积', class: "td-cool"},
+                        {name: 'b2bDeliveryWeigh', value: 'B2B发货重量', class: "td-cool"},
+
+
+                        {name: 'inventory', value: '盘点总数量', class: "td-warm"},
+                        {name: 'inventoryProfit', value: '盘盈数量', class: "td-warm"},
+                        {name: 'inventoryLoss', value: '盘亏数量', class: "td-warm"},
+                    ];
+                    new Header({
+                        el: "table",
+                        name: "details",
+                        column: column,
+                        data: this.details.data,
+                        restorationColumn: 'id',
+                        fixedTop: ($('#form_div').height()) + ($('#btn').height()) + 2,
+                        before: [
+                            {colspan: '13', value: '生产部-入库数据', class: "table-header-layer-1"},
+                            {
+                                colspan: '10',
+                                value: '生产部-发货数据',
+                                font: "fa fa-file-text-o",
+                                class: "table-header-layer-1"
+                            },
+                            {colspan: '4', value: '生产部-库存数据', font: "fa fa-truck", class: "table-header-layer-1"},
+                        ],
+                    }).init();
+                },
+            },
+        });
+    </script>
+@endsection

+ 7 - 0
resources/views/order/wave/_printBody.blade.php

@@ -0,0 +1,7 @@
+<div class="container"  id="printContent" v-show="infoShow">
+    <div class="card">
+        <div class="card-body mt-4 text-center" v-for="(value, key) in splitGroupBySize">
+            <div v-for="index in value" style="width: 100vw;height: 100vh"><img class="mt-1" style="width: 100vw" :id="key+'-'+index" alt="#" src="#"></div>
+        </div>
+    </div>
+</div>

+ 23 - 0
resources/views/order/wave/_split.blade.php

@@ -0,0 +1,23 @@
+<div class="modal fade" id="splitBatch" tabindex="-1" role="dialog" aria-hidden="true">
+    <div class="modal-dialog modal-dialog-centered" role="document">
+        <div class="modal-content">
+            <div class="modal-header">
+                <div class="text-center font-weight-bold">分割波次</div>
+                <button type="button" class="close" data-dismiss="modal">&times;</button>
+            </div>
+            <div class="modal-body">
+                <div class="form-group m-5">
+                    <label class="label">按订单大小</label>
+                    <input class="form-control" type="number" step="1" v-model="splitSize" placeholder="子波次大小">
+                </div>
+                <div class="form-group m-5">
+                    <label class="label">按波次数量</label>
+                    <input class="form-control" type="number" step="1" v-model="batchNumber" placeholder="子波次大小">
+                </div>
+            </div>
+            <div class="modal-footer">
+                <button class="col-12 btn btn-primary" @click="splitBatch()">确定</button>
+            </div>
+        </div>
+    </div>
+</div>

+ 131 - 0
resources/views/order/wave/picking.blade.php

@@ -0,0 +1,131 @@
+@extends('layouts.app')
+@section('title')波次分拣@endsection
+@section('content')
+    <div id="container" class="d-none container-fluid mt-2">
+        <div class="card">
+            <div class="card-header m-0">
+                <b>波次信息</b>
+                <button  class="btn text-white btn-sm btn-info pull-right" @click="isShow=!isShow" data-toggle="collapse" data-target="#body">@{{ isShow ? '隐藏' : '显示' }}</button>
+            </div>
+            <div class="card-body collapse" id="body">
+                <div v-for="(val,index) in waves" class="mt-2">
+                    <div class="card-title font-weight-bold mb-0">@{{ batch+'-'+(index+1) }}</div>
+                    <div class="card-text text-muted small">
+                        <div v-for="(obj,i) in val" class="row m-0" style="border-bottom: RGB(247,247,247) 1px solid">
+                            <span class="col-6">@{{ obj.barcode }}</span>
+                            <span class="col-6">@{{ obj.qty }}</span>
+                        </div>
+                    </div>
+                </div>
+            </div>
+            <div class="card mt-2">
+                <div class="card-header row m-0 p-0">
+                    <b class="col-4">分拣信息</b>
+                    <input id="barcode" v-model="barcode" @keydown.13="searchBarcode()" class="form-control form-control-sm rounded-pill col-6 offset-2" placeholder="条码"></input>
+                </div>
+                <div class="card-body">
+                    <div class="row border-info p-0" style="height:65vh;overflow-y: auto">
+                        <div class="col-4 m-0 p-1" style="height: 55px;border: 1px solid #aaaaaa;z-index:100;position:relative;" v-for="index in waves.length"
+                             :style="[waveQtyMap['_'+(index-1)] && waveQtyMap['_'+(index-1)].sum>0 ? {boxShadow: colorPool[colorIndex]+' 0 0 5px 5px inset'} : '']">
+                            <div class="text-center small font-weight-bold h-25 text-secondary">@{{ 'W-'+index }}</div>
+                            <div style="display:flex;align-items:center;justify-content:center;" class="w-100 h-50 text-primary font-weight-bold">
+                                @{{ waveQtyMap['_'+(index-1)] ? waveQtyMap['_'+(index-1)].sum : '0' }}
+                            </div>
+                            <div class="text-center small font-weight-bold h-25 text-muted mb-1">@{{ waveQtyMap['_'+(index-1)] ? waveQtyMap['_'+(index-1)].lot : '0' }}</div>
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </div>
+        <div class="bg-white w-100 row" id="searchBlock" style="position: fixed;top:0;left:0;
+            width: 100%; text-align: center; border-radius: 3px;">
+            <div class="position-relative offset-2 col-9 mt-3 mb-3">
+                <input id="loadBatch" class="form-control form-control-sm w-100 rounded-pill" @keydown.enter="loadBatch()" v-model="batch" type="text" placeholder="波次号"></input>
+                <a id="search" @click="loadBatch()"><button type="button" class="border btn btn-sm btn-primary text-white rounded-pill position-absolute" style="top: 0;right: 12px;">开始分拣</button></a>
+            </div>
+        </div>
+    </div>
+@endsection
+
+@section('lastScript')
+    <script>
+        new Vue({
+            el:"#container",
+            data:{
+                batch:"",
+                barcode:"",
+                isShow:false,
+                waves:[],
+                waveQtyMap:{},
+                colorIndex:0,
+                colorPool:[
+                    "RGB(224,41,43)","rgba(19,193,137)","RGB(97,179,233)"
+                ]
+            },
+            mounted:function(){
+                this.pageInit();
+                setTimeout(()=>{
+                    $("#container").removeClass('d-none');
+                },100);
+                setTimeout(()=>{
+                    $("#loadBatch").focus();
+                },200);
+            },
+            methods:{
+                //页面初始化
+                pageInit(){
+                    let element = document.getElementById("navbarSupportedContent").parentElement;
+                    element.className = "row";
+                    element.children[0].className += " col-5";
+                    element.children[0].href = "#";
+                    element.innerHTML = element.children[0].outerHTML;
+                    let e1 = document.getElementById("menu");
+                    let e2 = document.getElementById("demand-div");
+                    //let e3 = document.getElementsByClassName("navbar");
+                    if (e1)e1.remove();
+                    if (e2)e2.remove();
+                    //if (e3.length>0)e3[0].remove();
+                    element = document.getElementById("container");
+                    if (element)element.style.height = (window.innerHeight-100)+"px";
+                },
+                loadBatch(){
+                    window.tempTip.postBasicRequest("{{url('order/wave/loadBatch')}}",{code:this.batch},res=>{
+                        this.waves = res;
+                        $("#barcode").focus();
+                    })
+                },
+                searchBarcode(){
+                    let waveQtyMap = {};
+                    try {
+                        this.waves.forEach((wave,i)=>{
+                            wave.forEach(order=>{
+                                if (order.barcode === this.barcode){
+                                    if (order.scanSign!==undefined){
+                                        throw new Error("unique");
+                                    }
+                                    order.scanSign = true;
+                                    if (waveQtyMap['_'+i]===undefined){
+                                        waveQtyMap['_'+i] = {"sum":order.qty,"lot":order.location};
+                                    } else waveQtyMap['_'+i].sum += order.qty;
+                                }
+                            })
+                        })
+                    }catch (e){
+                        window.tempTip.setDuration(2000);
+                        window.tempTip.setIndex(999);
+                        window.tempTip.show("重复扫描");
+                        return;
+                    }finally {
+                        this.waveQtyMap = waveQtyMap;
+                        let el = $("#barcode");
+                        el.focus();
+                        el.select();
+                    }
+                    if (this.colorIndex===this.colorPool.length-1)this.colorIndex = 0;
+                    else this.colorIndex++;
+                },
+            }
+        });
+
+    </script>
+@endsection

+ 69 - 1
resources/views/order/wave/search.blade.php

@@ -40,6 +40,8 @@
 
 {{--                        <button type="button" class="btn btn-sm tooltipTarget btn-outline-dark" @click="batchCancelPrint">重置打印标记</button>--}}
                         <button type="button" class="btn btn-sm btn-outline-success" data-toggle="modal" data-target="#myModal">修复波次</button>
+                        <button type="button" class="btn btn-sm btn-outline-primary" data-toggle="modal" data-target="#splitBatch">分割波次</button>
+                        <button type="button" class="btn btn-sm btn-outline-primary" @click="exePrint()">打印子波条码</button>
                     </td>
                 </tr>
 
@@ -95,10 +97,13 @@
                    :placeholder="'当前页数:'+'{{$param['currPage']}}'+'/'+'{{$param['pageTotal']}}'" title="去往指定页">
             <span class="text-muted m-1">共 {{$param['count']}} 条 </span>
         </div>
+        @include("order.wave._split")
+        @include("order.wave._printBody")
     </div>
 @endsection
 
 @section("lastScript")
+    <script type="text/javascript" src="{{mix('js/utilities/barcode.js')}}"></script>
     <script type="text/javascript" src="{{mix('js/queryForm/queryForm.js')}}"></script>
     <script>
         let vueList = new Vue({
@@ -132,6 +137,10 @@
                 currPage:'{{$param['currPage']}}',
                 selectTr:'',
                 batchCodes:"",
+                splitSize:"",
+                batchNumber:"",
+                infoShow:false,
+                splitGroupBySize:{},
             },
             mounted: function () {
                 $('#wave_div').removeClass('d-none')
@@ -275,7 +284,66 @@
                         return;
                     }
                     this.selectedWaveNo = waveNo;
-                }
+                },
+                splitBatch(){
+                    window.tempTip.setDuration(2000);
+                    window.tempTip.setIndex(999);
+                    if (this.checkData.length<1){
+                        window.tempTip.show("未选中记录行");
+                        return;
+                    }
+                    if (!this.splitSize && !this.batchNumber){
+                        window.tempTip.show("未输入分割大小");
+                        return;
+                    }
+                    window.tempTip.postBasicRequest("{{url('order/wave/split')}}",{codes:this.checkData,split:this.splitSize,number:this.batchNumber},res=>{
+                        $("#splitBatch").modal('hide');
+                        return "分割成功";
+                    },true)
+                },
+                exePrint(){
+                    window.tempTip.setDuration(2000);
+                    if (this.checkData.length<1){
+                        window.tempTip.show("未选中记录行");
+                        return;
+                    }
+                    window.tempTip.postBasicRequest("{{url('order/wave/printChild')}}",{codes:this.checkData},res=>{
+                        this.splitGroupBySize = res;
+                        setTimeout(()=>{
+                            for(let key  in this.splitGroupBySize){
+                                for (let i=1;i<=this.splitGroupBySize[key];i++){
+                                    window.setBarcode(key+'-'+i, "#"+key+"-"+i, 2, 50, true)
+                                }
+                            }
+                        },10);
+                        setTimeout(()=>{
+                            exe();
+                        },50);
+                    })
+                    let exe = ()=>{
+                        let iframe=document.getElementById("print-iframe");
+                        this.infoShow=true;
+                        if(!iframe){
+                            iframe = document.createElement('IFRAME');
+                            iframe.setAttribute("id", "print-iframe");
+                            iframe.setAttribute('style', 'position:absolute;width:0;height:0;left:-500px;top:-500px;');
+                            document.body.appendChild(iframe);
+                        }else iframe.contentWindow.document.getElementById("iframe-content").remove();
+                        let doc = iframe.contentWindow.document;
+                        let el = document.getElementById("printContent");
+                        doc.write('<LINK rel="stylesheet" type="text/css" href="{{ asset(mix("css/app.css")) }}">');
+                        doc.write('<div id="iframe-content">' + el.innerHTML + '</div>');
+                        doc.close();
+                        iframe.contentWindow.focus();
+                        this.infoShow=false;
+                        setTimeout(function () {
+                            iframe.contentWindow.print();
+                            if (navigator.userAgent.indexOf("MSIE") > 0){
+                                document.body.removeChild(iframe);
+                            }
+                        },200);
+                    };
+                },
             }
         });
     </script>

+ 92 - 31
resources/views/package/logistic/index.blade.php

@@ -2,14 +2,15 @@
 @section('title')快递查询-包裹管理@endsection
 @section('head')
     <style>
-        .package-logistic-index{
-            position:relative;
+        .package-logistic-index {
+            position: relative;
         }
 
         /*备注容器*/
-        .order-package-remarks{
-            position:relative;
+        .order-package-remarks {
+            position: relative;
         }
+
         /*新建按钮*/
         .btn-create-remark {
             width: 25px;
@@ -24,9 +25,11 @@
             box-shadow: 0 0 6px #4747f1;
             float: left;
         }
-        .order-package-remarks:hover .btn-create-remark{
+
+        .order-package-remarks:hover .btn-create-remark {
             display: block;
         }
+
         /*新建输入框*/
         .remark-input {
             height: 30px;
@@ -36,6 +39,7 @@
             box-shadow: 0 0 6px #fff6a1;
             border-radius: 5px;
         }
+
         /*删除按钮*/
         .order-package-remarks table .destroy {
             float: right;
@@ -47,7 +51,7 @@
             border: 0 solid transparent !important;
         }
 
-        .remark-created_at{
+        .remark-created_at {
             border-right: none !important;
         }
 
@@ -59,7 +63,7 @@
             box-shadow: 0 0 6px #ac4a4a;
         }
 
-        .order-package-remarks table:hover .btn-destroy-remark{
+        .order-package-remarks table:hover .btn-destroy-remark {
             display: block;
         }
 
@@ -117,6 +121,18 @@
                         <button type="button" class="btn btn-outline-dark btn-sm form-control-sm  tooltipTarget"
                                 @click="copyLogisticNumber" style="background: #dad7e8;">复制快递单号</button>
                     </span>
+{{--                    获取查询条件下的总条数--}}
+                    <span class="ml-1">
+                        <button type="button" class="btn btn-outline-success btn-sm form-control-sm  tooltipTarget"
+                                @click="getTotal()"
+                                style="background: #dad7e8;">
+                            <span v-if="!total.loading">
+                                @{{ total.number===null?'获取总量':'总量:'+ total.number }}
+                            </span>
+                            <span v-else style="margin-left: 5px"><i class="fa fa-circle-o-notch fa-spin"></i>
+                            </span>
+                        </button>
+                    </span>
                 @endcan
             </div>
             <table class="table table-striped table-bordered table-hover card-body td-min-width-80" id="table">
@@ -135,12 +151,12 @@
                             <!--               是否为问题件         -->
                             <span class="badge badge-danger" v-if="package.order.issue">?</span>
 
-<!--       是否手动修改                     -->
+                            <!--       是否手动修改                     -->
                             <span v-if="package.is_manual_update">
                                 <i class="fa fa-hand-paper-o" aria-hidden="true"
                                    style="color: red;margin-left: 5px"></i>
                             </span>
-<!--     延时发货图标                       -->
+                            <!--     延时发货图标                       -->
                             <span
                                 v-if="package.is_delay_deliver"
                                 style="margin-left: 5px">
@@ -207,33 +223,40 @@
                             <label class="text-center mt-0 p-0 cursor-pointer pull-left">
                                 <span class="fa"
                                       :class="package.showMoreRemark ? 'fa-angle-double-down' : 'fa-angle-double-right'"></span>
-                                &nbsp;<span v-if="package.order_package_remarks && package.showMoreRemark">收起</span><span
-                                    v-else>展开</span>&nbsp;@{{ package.order_package_remarks.length }} 条
-                            </label>
-                        </div>
+                                    &nbsp;<span v-if="package.order_package_remarks && package.showMoreRemark">收起</span><span
+                                        v-else>展开</span>&nbsp;@{{ package.order_package_remarks.length }} 条
+                                </label>
+                            </div>
                         @endcan
                     </td>
-                    <td class="text-overflow-warp-200"><span v-if="package.order && package.order.issue">@{{ package.order.issue.result_explain }}</span></td>
+                    <td class="text-overflow-warp-200"><span v-if="package.order && package.order.issue">@{{ package.order.issue.result_explain }}</span>
+                    </td>
                     <td class="text-overflow-warp-200"><span
                             v-if="package.order && package.order.issue && package.order.issue.issue_type">@{{ package.order.issue.issue_type.name }}</span>
                     </td>
-                    <td class="text-overflow-warp-200">@{{ package.order && package.order.batch && package.order.batch.wms_type }}</td>
-                    <td class="text-overflow-warp-200">@{{ package.order && package.order.oracle_d_o_c_order_header && package.order.oracle_d_o_c_order_header.waveno }}</td>
+                    <td class="text-overflow-warp-200">@{{ package.order && package.order.batch &&
+                        package.order.batch.wms_type }}
+                    </td>
+                    <td class="text-overflow-warp-200">@{{ package.order && package.order.oracle_d_o_c_order_header &&
+                        package.order.oracle_d_o_c_order_header.waveno }}
+                    </td>
                     <td class="text-overflow-warp-200"><span
                             v-if="package.order && package.order.issue && package.order.issue.logs.length >0"><span
                                 v-for="log in package.order.issue.logs">@{{ log.content }}<br></span></span></td>
                     <td class="text-overflow-warp-200"><span
                             v-if="package.order && package.order.issue && package.order.issue.logs.length >0"><span
-                                v-for="log in package.order.issue.logs">@{{ log && log.user && log.user.name }}<br></span></span></td>
+                                v-for="log in package.order.issue.logs">@{{ log && log.user && log.user.name }}<br></span></span>
+                    </td>
                     <td class="text-overflow-warp-200"><span
                             v-if="package.order && package.order.issue && package.order.issue.logs.length >0"><span
                                 v-for="log in package.order.issue.logs">@{{ log.created_at }}<br></span></span></td>
                 </tr>
             </table>
-            <div class="text-info h5 btn btn">{{$orderPackages->count()}}/{{$orderPackages->total()}}</div>
-            {{$orderPackages->appends($paginateParams)->links()}}
+        {{--            <div class="text-info h5 btn btn">{{$orderPackages->count()}}/{{$orderPackages->total()}}</div>--}}
+        {{$orderPackages->appends($paginateParams)->links()}}
         <!-- Modal -->
-            <div class="modal fade" id="staticBackdrop" data-backdrop="static" data-keyboard="false" tabindex="-1" aria-labelledby="staticBackdropLabel" aria-hidden="true" z-index="51">
+            <div class="modal fade" id="staticBackdrop" data-backdrop="static" data-keyboard="false" tabindex="-1"
+                 aria-labelledby="staticBackdropLabel" aria-hidden="true" z-index="51">
                 <div class="modal-dialog">
                     <div class="modal-content">
                         <div class="modal-header">
@@ -244,11 +267,14 @@
                         </div>
                         <div class="modal-body">
                             <div class="form-group">
-                                <textarea v-model="bench_remark" style="width:80%;margin: 0 auto;" class="form-control" id="exampleFormControlTextarea1" rows="3"></textarea>
+                                <textarea v-model="bench_remark" style="width:80%;margin: 0 auto;" class="form-control"
+                                          id="exampleFormControlTextarea1" rows="3"></textarea>
                             </div>
                         </div>
                         <div class="modal-footer">
-                            <button @click="bench_remark = ''" type="button" class="btn btn-secondary" data-dismiss="modal">关闭</button>
+                            <button @click="bench_remark = ''" type="button" class="btn btn-secondary"
+                                    data-dismiss="modal">关闭
+                            </button>
                             <button @click="submitBenchRemark" type="button" class="btn btn-primary">提交</button>
                         </div>
                     </div>
@@ -267,6 +293,10 @@
         let vue = new Vue({
             el: "#list",
             data: {
+                total: {
+                    number: null,
+                    loading: false
+                },
                 packages: [
                     @foreach($orderPackages as $package)
                         {!! $package !!},
@@ -345,7 +375,7 @@
                             name: 'status',
                             type: 'select_multiple_select',
                             tip: ['输入关键词快速定位下拉列表,回车确定', '选择要显示的状态'],
-                            placeholder: ['状态','定位或多选状态'],
+                            placeholder: ['状态', '定位或多选状态'],
                             data: [
                                 {name: '0', value: '空'},
                                 {name: '1', value: '生成订单'},
@@ -470,14 +500,19 @@
                             ]
                         },
                         {name: 'default_date', type: 'checkbox', tip: '默认15天', data: [{name: 'ture', value: '默认15天'}]},
-                        {name: 'default_logistics', type: 'checkbox', tip: '默认承运商', data: [{name: 'ture', value: '默认承运商'}]},
+                        {
+                            name: 'default_logistics',
+                            type: 'checkbox',
+                            tip: '默认承运商',
+                            data: [{name: 'ture', value: '默认承运商'}]
+                        },
                         {name: 'virtual_receive', type: 'checkbox', tip: '虚拟揽收', data: [{name: 'ture', value: '虚拟揽收'}]},
                     ]
                 ];
                 _this.form = new query({
                     el: '#form_div',
                     condition: data,
-                    appendDom : "btn",
+                    appendDom: "btn",
                 });
                 _this.form.init();
                 let column = [
@@ -514,6 +549,31 @@
                 }).init();
             },
             methods: {
+                //获取查询条件下的总条数
+                getTotal() {
+                    if (!this.total.loading) {
+                        this.total.loading = true
+                        let query = "{{ request()->getQueryString() }}";
+                        query = query.replace(/amp;/g, "");
+                        let url = "{{ url()->current() }}";
+                        url += `/getTotal?${query}`;
+                        axios.get(url).then(res => {
+                            this.$forceUpdate();
+                            let responseData = res.data;
+                            if (responseData.success) {
+                                this.total.number = responseData.data.total;
+                                this.total.loading = false
+                                tempTip.showSuccess('获取总量成功!');
+                            }
+                        }).catch(e => {
+                            this.total.loading = false
+                            tempTip.show(`获取异常请稍后再试!${e}`);
+                        });
+                    } else {
+                        tempTip.show(`点击过于频繁请稍后再试!${e}`);
+                    }
+                },
+
                 showRoute(id) {
                     if (this.showList[id]) {
                         this.$set(this.showList, id, false);
@@ -535,7 +595,7 @@
                     this.$forceUpdate();
                 },
                 batchStatusUpdate() {
-                    if(!confirm('是否却认操作')) return;
+                    if (!confirm('是否却认操作')) return;
                     let _this = this;
                     if (checkData.length === 0) {
                         tempTip.show('没有勾选记录');
@@ -551,7 +611,7 @@
                     })
                 },
                 batchExceptionStatusUpdate() {
-                    if(!confirm('是否却认操作')) return;
+                    if (!confirm('是否却认操作')) return;
                     let _this = this;
                     if (checkData.length === 0) {
                         tempTip.show('没有勾选记录');
@@ -587,7 +647,7 @@
                     let _this = this;
                     tempTip.setDuration(2000);
                     tempTip.showSuccess('正在操作请稍后!');
-                    axios.put(url, {remark: _this.remark, orderPackageId: orderPackage.id}).then(response=>{
+                    axios.put(url, {remark: _this.remark, orderPackageId: orderPackage.id}).then(response => {
                         if (response.data.success) {
                             orderPackage.order_package_remarks = response.data.data
                             tempTip.setDuration(2000);
@@ -603,15 +663,16 @@
                         tempTip.show("网络错误:" + err)
                     });
                 },
-                destroyRemark(orderPackage,remarkId) {
+                destroyRemark(orderPackage, remarkId) {
                     let url = '{{url('apiLocal/package/logistic/delete')}}';
                     if (!confirm('是否却认删除', false)) {
                         return;
-                    };
+                    }
+                    ;
                     let _this = this;
                     tempTip.setDuration(2000);
                     tempTip.showSuccess('正在操作请稍后!');
-                    axios.post(url, {orderPackageId: orderPackage.id,remarkId:remarkId}).then(response=>{
+                    axios.post(url, {orderPackageId: orderPackage.id, remarkId: remarkId}).then(response => {
                         if (response.data.success) {
                             orderPackage.order_package_remarks = response.data.data
                             tempTip.setDuration(2000);

+ 1 - 1
resources/views/personnel/laborApply/create.blade.php

@@ -13,7 +13,7 @@
                    2 禁止开放
                    3 临时开放
                 -->
-                @can('人事管理')
+                @can('人事管理-临时工申请协调-录入-临时开放')
                     <form v-if="can_create_status === 2" action="{{ route('laborApply.temporaryOpen') }}" method="post"
                           accept-charset="UTF-8">
                         {{ csrf_field() }}

+ 3 - 1
resources/views/personnel/laborApply/dispatch/index.blade.php

@@ -42,7 +42,7 @@
                                 </a>
                             </div>
                         @endcan()
-                        @can('人事管理')
+                        @can('临时工申请协调-劳务派遣明细-人事确认')
                             <div class="float-left ml-3" v-if="labor_company_dispatch.status==='创建'">
                                 <form :action="getBaseUrl(labor_company_dispatch) + '/personnelCheck'" method="post"
                                       accept-charset="UTF-8" onsubmit="return confirm('是否确认!')">
@@ -62,6 +62,7 @@
                             </div>
                         @endcan()
                     </td>
+                    <td>@{{ labor_company_dispatch.check_user?labor_company_dispatch.check_user.name:'' }}</td>
                     <td>@{{ labor_company_dispatch.labor_company.name }}</td>
                     <td>@{{ labor_company_dispatch.warehouse ?labor_company_dispatch.warehouse.name:''}}</td>
                     <td><span :class="getStatusClass(labor_company_dispatch.status)">@{{ labor_company_dispatch.status }}</span>
@@ -182,6 +183,7 @@
                 let column = [
                     {name: 'index', value: '序号', neglect: true},
                     {name: 'do', value: '操作'},
+                    {name: 'check_user', value: '确认人'},
                     {name: 'name', value: '劳务公司'},
                     {name: 'warehouse', value: '仓库'},
                     {name: 'status', value: '状态 '},

+ 1 - 1
resources/views/personnel/laborApply/index.blade.php

@@ -6,7 +6,7 @@
         <div class="container-fluid">
             <div id="form_div"></div>
             <div class="ml-3 form-inline" id="btn">
-                @can('人事管理')
+                @can('临时工申请协调-查看-重新生成劳务派遣数据')
                     <span class="ml-1">
                         <a title="00:00 - 01:00 禁止生成数据" href="{{ route('laborApply.createDispatch') }}" type="button"
                            class="btn btn-sm ml-2 btn-outline-danger">重新生成劳务派遣数据</a>

+ 12 - 7
resources/views/personnel/laborReport/index.blade.php

@@ -105,13 +105,13 @@
                                                 @can('人事管理-门卫审核')
                                                     <span >
                                 <b v-if="laborReport.isAdult==1"   class="text-danger">童工</b>
-                                <b v-else-if="laborReport.userDutyCheckVerifyUserId{{--&&laborReport.amountOfJoined==1--}}"   class="text-success">已审核</b>
+                                <b v-else-if="laborReport.userDutyCheckVerifyUserId&&laborReport.amountOfJoined==1"   class="text-success">已审核</b>
                                 <b v-else-if="laborReport.userDutyCheckVerifyUserId&&laborReport.amountOfJoined&&laborReport.sequence"  class="text-black">&nbsp;&nbsp;&nbsp;@{{laborReport.sequence}}/@{{laborReport.amountOfJoined}}</b>
                                 <button v-else style="transform:scale(1.1)" class="btn btn-lg btn-outline-secondary"  @click="guardClockAudit(laborReport.id,laborReport.user_duty_check_id)">门卫审核</button>
                                 </span>
                                                 @else
                                                     <b v-if="laborReport.isAdult==1"   class="text-danger">童工</b>
-                                                    <b v-else-if="laborReport.userDutyCheckVerifyUserId{{--&&laborReport.amountOfJoined==1--}}"  class="text-success">已审核</b>
+                                                    <b v-else-if="laborReport.userDutyCheckVerifyUserId&&laborReport.amountOfJoined==1"  class="text-success">已审核</b>
                                                     <b v-else-if="laborReport.userDutyCheckVerifyUserId&&laborReport.amountOfJoined&&laborReport.sequence"  class="text-black">&nbsp;&nbsp;&nbsp;@{{ laborReport.sequence }}/@{{ laborReport.amountOfJoined }}</b>
                                                     <span v-else class="text-center"><b class="text-danger">门卫未审核</b></span>
                                                 @endcan
@@ -325,11 +325,12 @@
                     let tokenOfBroadcastEnterAndLeave='{{$tokenOfBroadcastEnterAndLeave}}';
                     if(tokenOfBroadcastEnterAndLeave){
                         Echo.channel('{{$laravelEchoPrefix}}'+tokenOfBroadcastEnterAndLeave).listen('ImportEvent',(e)=>{
-                            // let labor=e.laborReport;
-                            // laborReports.push(labor);
-                            setTimeout(function () {
-                                window.location.reload();
-                            },500);
+                            let labor=e.laborReport;
+                            laborReports.unshift(labor);
+
+                            // setTimeout(function () {
+                            //     window.location.reload();
+                            // },500);
                         });
                     }
                     //退场
@@ -357,6 +358,7 @@
                             if (laborReport.user_duty_check_id==userDutyCheck.id){
                                 laborReport.userDutyCheckVerifyUserId=userDutyCheck.verify_user_id;
                                 laborReport.user_duty_check_id=userDutyCheck.id;
+                                laborReport.amountOfJoined=1;
                                 return false
                             }
                             return true;
@@ -382,6 +384,7 @@
                     _this.permittingWorkgroups.forEach(function(workgroup){
                         Echo.channel('{{$laravelEchoPrefix}}'+workgroup.token).listen('ClockinEvent',(e)=>{
                             // let res=false;
+                            // let labor=e.laborReport;
                             // laborReports.forEach(function (item){
                             //     if(item.id==labor.id){
                             //         res=true;
@@ -405,6 +408,7 @@
                             //     labor.has_group_verify_right=labor.has_group_verify_right;
                             //     laborReports.push(labor);
                             // }
+
                             setTimeout(function () {
                                 window.location.reload();
                             },500);
@@ -604,6 +608,7 @@
                                 _this.laborReports.every(function (laborReport) {
                                     if (laborReport.id==id){
                                         laborReport.userDutyCheckVerifyUserId=response.data.data;
+                                        laborReport.amountOfJoined=1;
                                         tempTip.setDuration(1000);
                                         tempTip.showSuccess('审核通过!');
                                         return false

+ 55 - 3
resources/views/rejected/record.blade.php

@@ -104,6 +104,8 @@
             selected:"",
             name:"",
             errorSum:0,
+            jwtToken:"{{$jwtToken}}",
+            voiceLoadSign:false,
         },
         mounted() {
             this.registerEvent();
@@ -124,8 +126,43 @@
                 }
                 return '当前存在失败数据未处理';
             };
+            setTimeout(()=>{
+                this.refreshToken();
+            },600800000);
         },
         methods:{
+            playAudio(src){
+                let audio = document.createElement('audio');
+                audio.src = src;
+                document.body.append(audio);
+                setTimeout(()=>{
+                    audio.play();
+                },10);
+                setTimeout(()=>{
+                    audio.remove();
+                },5000);
+            },
+            refreshToken(){
+                window.axios.post('{{url('record/refreshToken')}}',{},{
+                    headers: {
+                        "jwtToken" : this.jwtToken
+                    }
+                }).then(body=>{
+                    let res = body.data;
+                    if (!res.success){
+                        this.playAudio('storage/logonFailure.mp3');
+                        this.buildToast(false,"tokenFailure");
+                        return;
+                    }
+                    this.jwtToken = res.data;
+                    setTimeout(()=>{
+                        this.refreshToken();
+                    },600800000);
+                }).catch(err=>{
+                    this.playAudio('storage/networkError.mp3');
+                    this.buildToast(false,"tokenFailure");
+                });
+            },
             selectedWarehouse(warehouse){
                 this.selected = warehouse.id;
                 this.name = warehouse.name;
@@ -164,6 +201,19 @@
             },
             registerEvent(){
                 $(document).on('keypress', e=>{
+                    if (!this.voiceLoadSign){
+                        this.voiceLoadSign = true;
+                        let audio = document.createElement('audio');
+                        let audio1 = document.createElement('audio');
+                        audio.src = 'storage/logonFailure.mp3';
+                        audio1.src = 'storage/networkError.mp3';
+                        document.body.append(audio);
+                        document.body.append(audio1);
+                        setTimeout(()=>{
+                            audio.remove();
+                            audio1.remove();
+                        },10);
+                    }
                     if (e.keyCode===13){
                         if(this.logisticNumber==="")return;
                         this.submitRecord(this.logisticNumber,this.recordAt);
@@ -185,7 +235,7 @@
                             this.recordAt = yy+'-'+(mm<10 ? '0'+mm : mm)+'-'+(dd<10 ? '0'+dd : dd)+" "+(hh<10 ? '0'+hh : hh)+":"+(m<10 ? '0'+m : m)+":"+(ss<10 ? '0'+ss : ss);
                         }
                         this.logisticNumber += e.key;
-                    }else console.log(e.key);
+                    }
                 });
             },
             failRetry(){
@@ -193,7 +243,7 @@
                     if (!item.status){
                         window.axios.post('{{url('record')}}',{logisticNumber:item.logisticNumber,warehouse:this.selected},{
                             headers: {
-                                "jwtToken" : "{{$jwtToken}}"
+                                "jwtToken" : this.jwtToken
                             }
                         }).then(body=>{
                             let res = body.data;
@@ -209,6 +259,7 @@
                                 this.errorSum--;
                             }
                         }).catch(err=>{
+                            this.playAudio('storage/networkError.mp3');
                             this.buildToast(false,item.logisticNumber);
                         });
                     }
@@ -217,7 +268,7 @@
             submitRecord(logisticNumber,recordAt){
                 window.axios.post('{{url('record')}}',{logisticNumber:logisticNumber,warehouse:this.selected},{
                     headers: {
-                        "jwtToken" : "{{$jwtToken}}"
+                        "jwtToken" : this.jwtToken,
                     }
                 }).then(body=>{
                     let res = body.data;
@@ -236,6 +287,7 @@
                     if (!status)this.errorSum++;
                     this.sum++;
                 }).catch(err=>{
+                    this.playAudio('storage/networkError.mp3');
                     this.buildToast(false,logisticNumber);
                     this.data.unshift({
                         logisticNumber:logisticNumber,logistic:"未知",recordAt:recordAt,status:false

+ 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

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

@@ -0,0 +1,516 @@
+@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">
+                                    <span v-if="goods.basSku.lot_id.lotkey01==='Y'">
+                                        <input type="date" autocomplete="off" class="form-control form-control-sm input-sm" :class="errors.lotatt01 ? 'is-invalid' : ''"
+                                                 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>
+                                </span>
+                            </td>
+                            <td class="text-center">
+                               <span v-if="goods.basSku.lot_id">
+                                   <span v-if="goods.basSku.lot_id.lotkey02==='Y'">
+                                       <input type="date" autocomplete="off" class="form-control form-control-sm input-sm" :class="errors.lotatt02 ? 'is-invalid' : ''"
+                                              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>
+                                </span>
+                            </td>
+                            <td class="text-center">
+                                <span v-if="goods.basSku.lot_id">
+                                    <span v-if="goods.basSku.lot_id.lotkey04==='Y'">
+                                    <input type="text" autocomplete="off" class="form-control form-control-sm input-sm" :class="errors.lotatt04 ? 'is-invalid' : ''"
+                                             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>
+                                </span>
+                            </td>
+                            <td class="text-center">
+                                <span v-if="goods.basSku.lot_id">
+                                    <span v-if="goods.basSku.lot_id.lotatt05==='Y'">
+                                    <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>
+                                </span>
+                            </td>
+                            <td class="text-center">
+                                <span v-if="goods.basSku.lot_id">
+                                     <span v-if="goods.basSku.lot_id.lotkey08==='Y'">
+                                     <select class="form-control form-control-sm" :class="errors.lotatt08 ? 'is-invalid' : ''"
+                                              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>
+                                </span>
+                            </td>
+                            <td class="text-center">
+                                <span v-if="goods.basSku.lot_id">
+                                    <span v-if="goods.basSku.lot_id.lotkey03==='Y'">
+                                    <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>
+                                </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

+ 1 - 0
resources/views/store/inStorage/androidIndex.blade.php

@@ -30,6 +30,7 @@
                 @can("入库管理-手持入库-收货")<a href="{{url('store/blindReceive')}}"><button class="btn btn-info w-75 h-25 mt-3 text-white" style="height: 60px"><h4>盲收</h4></button></a>@endcan
                 @can("运输管理-编辑")<a href="{{url('transport/waybill/android/shipment')}}"><button class="btn btn-info w-75 h-25 mt-3 text-white" style="height: 60px"><h4>运单发货</h4></button></a>@endcan
                 @can("运输管理-承运商调度")<a href="{{url('transport/waybill/delivering')}}"><button class="btn btn-info w-75 h-25 mt-3 text-white" style="height: 60px"><h4>运单调配</h4></button></a>@endcan
+                <a href="{{url('order/wave/picking')}}"><button class="btn btn-info w-75 h-25 mt-3 text-white" style="height: 60px"><h4>波次分拣</h4></button></a>
 
     <a href="{{ route('logout') }}" onclick="event.preventDefault();
                                                      document.getElementById('logout-form').submit();">

+ 38 - 13
routes/web.php

@@ -50,6 +50,7 @@ Route::get('personnel/checking-in/importAndExportQRCode','QRCodeController@impor
 Route::post('personnel/checking-in/refreshQRCode','QRCodeController@refreshQRCode');
 
 Route::post("record","ReceiveRecordController@receive");
+Route::post("record/refreshToken","ReceiveRecordController@refreshToken");
 Route::get("record",function (){return view("rejected.record");});
 
 
@@ -495,22 +496,23 @@ Route::group(['prefix'=>'package'],function(){
         Route::any('export/{type}','WeighExceptedController@export');
     });
 
-        Route::any('export','WeighController@export');
+    Route::any('export','WeighController@export');
+    Route::get('statistics','WeighController@statistics');
+    Route::get('relating', function () {return view('package.measureMonitor.menu');});
+    Route::group(['prefix' => 'weigh'], function () {
         Route::get('statistics','WeighController@statistics');
-        Route::get('relating', function () {return view('package.measureMonitor.menu');});
-        Route::group(['prefix' => 'weigh'], function () {
-            Route::get('statistics','WeighController@statistics');
-            /** 统计 */
-            Route::group(['prefix'=>'statistics'],function(){
-                Route::any('export','WeighController@statisticsExport');
-            });
+        /** 统计 */
+        Route::group(['prefix'=>'statistics'],function(){
+            Route::any('export','WeighController@statisticsExport');
         });
-        Route::get('weigh/index','WeighController@index');
-        Route::resource('weigh','WeighController');
-        Route::put('logistic/batchUpdate','PackageLogisticController@batchUpdate');
-        Route::any('logistic/export','PackageLogisticController@export');
-        Route::resource('logistic','PackageLogisticController');
     });
+    Route::get('weigh/index','WeighController@index');
+    Route::resource('weigh','WeighController');
+    Route::get('logistic/getTotal','PackageLogisticController@getTotal');
+    Route::put('logistic/batchUpdate','PackageLogisticController@batchUpdate');
+    Route::any('logistic/export','PackageLogisticController@export');
+    Route::resource('logistic','PackageLogisticController');
+});
     $route->resource('package','WeighController');
     /** 入库 */
     $route->group(['prefix'=>'store'],function(){
@@ -543,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');});//上架页面
@@ -559,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');
         });
@@ -728,6 +739,12 @@ Route::group(['prefix'=>'package'],function(){
     /** 库存 */
     $route->group(['prefix'=>'inventory'],function(){
         /** 说明 */
+        Route::group(['prefix' => 'stockOut'], function () {
+            Route::get('/', 'ReplenishmentController@index');
+            Route::post('/getReplenishmentInfoByCustomer', 'ReplenishmentController@getReplenishmentInfoByCustomer');
+            Route::get('/export', 'ReplenishmentController@export');
+        });
+
         Route::group(['prefix'=>'statement'],function(){
             /** 动库报表 */
             Route::group(['prefix'=>'changeInventory'],function(){
@@ -812,6 +829,10 @@ Route::group(['prefix'=>'package'],function(){
             Route::post('cancelPrinting','WaveController@cancelPrinting');
             Route::any('exportExcel','WaveController@exportExcelOnParams');
             Route::post('repairBatch','WaveController@repairBatch');
+            Route::post('split','WaveController@split');
+            Route::post('printChild','WaveController@printChild');
+            Route::get('picking','WaveController@picking');
+            Route::post('loadBatch','WaveController@loadBatch');
         });
         /** 问题件 */
         Route::group(['prefix'=>'issue'],function(){
@@ -1103,5 +1124,9 @@ Route::group(['prefix'=>'package'],function(){
             Route::post('/toTarget', 'NotificationController@toTarget');
         }
     );
+    Route::group(['prefix' => 'kpi'], function () {
+        Route::get( 'month', 'KpiController@monthIndex');
+        Route::get( 'day', 'KpiController@dayIndex');
+    });
 });