Преглед изворни кода

Merge branch 'master' into Haozi

hu hao пре 5 година
родитељ
комит
30ceae28cf
100 измењених фајлова са 2795 додато и 846 уклоњено
  1. 45 0
      app/Console/Commands/UpdateOrderPackageExceptionTypeCountingRecordTask.php
  2. 3 1
      app/Console/Kernel.php
  3. 14 0
      app/Events/DeliveryAppointmentEvent.php
  4. 41 0
      app/Events/UpdateOrderPackageExceptionListenerEvent.php
  5. 11 47
      app/Http/Controllers/CacheShelfController.php
  6. 15 1
      app/Http/Controllers/ControlPanelController.php
  7. 2 1
      app/Http/Controllers/CustomerController.php
  8. 25 12
      app/Http/Controllers/DeliveryAppointmentController.php
  9. 11 1
      app/Http/Controllers/DischargeTaskController.php
  10. 19 6
      app/Http/Controllers/PackageLogisticController.php
  11. 8 0
      app/Http/Controllers/StoreController.php
  12. 113 8
      app/Http/Controllers/TestController.php
  13. 2 0
      app/Http/Controllers/WaybillController.php
  14. 10 7
      app/Http/Controllers/api/thirdPart/haiq/LightController.php
  15. 1 1
      app/Http/Controllers/api/thirdPart/weight/WeightBaseController.php
  16. 1 1
      app/Jobs/DeliveryAppointmentCheck.php
  17. 57 0
      app/Jobs/LogisticYDSync.php
  18. 6 157
      app/Jobs/LogisticZopSync.php
  19. 1 1
      app/Jobs/ResetInstantBill.php
  20. 5 1
      app/Listeners/AddOrUpdateOrderIssuesListener.php
  21. 5 1
      app/Listeners/UpdateOrderPackageExceptionListener.php
  22. 42 0
      app/Listeners/UpdateOrderPackageExceptionTypeCountingRecordListener.php
  23. 5 0
      app/OracleDOCOrderHeader.php
  24. 17 0
      app/OrderPackageExceptionTypeCountingRecord.php
  25. 4 0
      app/Providers/AppServiceProvider.php
  26. 0 1
      app/Providers/AuthServiceProvider.php
  27. 7 4
      app/Providers/EventServiceProvider.php
  28. 210 60
      app/Services/CacheShelfService.php
  29. 1 1
      app/Services/CityService.php
  30. 10 15
      app/Services/ForeignHaiRoboticsService.php
  31. 134 120
      app/Services/LogisticSFService.php
  32. 178 0
      app/Services/LogisticYDService.php
  33. 4 2
      app/Services/OracleDocWaveDetailService.php
  34. 71 0
      app/Services/OrderPackageExceptionTypeCountingRecordService.php
  35. 183 9
      app/Services/OrderPackageReceivedSyncService.php
  36. 7 5
      app/Services/OwnerPriceOperationService.php
  37. 12 0
      app/Services/PackageService.php
  38. 2 2
      app/Services/PackageStatisticsService.php
  39. 1 1
      app/Services/ProvinceService.php
  40. 1 0
      app/Services/RejectedBillService.php
  41. 0 1
      app/Services/StationCacheShelfGridService.php
  42. 12 15
      app/Services/StationTaskMaterialBoxService.php
  43. 134 2
      app/Services/StoreService.php
  44. 10 0
      app/Services/WaybillService.php
  45. 5 3
      app/Station.php
  46. 0 61
      app/StationCacheShelfGrid.php
  47. 1 1
      app/Warehouse.php
  48. 10 11
      app/library/zop/ZopClient.php
  49. 29 7
      config/api_logistic.php
  50. 12 0
      database/factories/OrderPackageExceptionTypeCountingRecordFactory.php
  51. 24 1
      database/factories/OrderPackageFactory.php
  52. 28 0
      database/migrations/2021_04_29_133306_drop_station_cache_shelf_grips_table.php
  53. 32 0
      database/migrations/2021_05_07_141019_add_index_exception_type_sent_at_owner_id_order_packages_table.php
  54. 35 0
      database/migrations/2021_05_07_141912_create_order_package_exception_type_counting_records_table.php
  55. 44 0
      database/migrations/2021_05_11_101611_exception_message_able_null_order_packages_table.php
  56. 36 0
      database/migrations/2021_05_14_100303_change_warehouses_table_add_column_address_column.php
  57. 30 0
      database/migrations/2021_05_18_151348_add_authority_order_package_remark.php
  58. 16 0
      database/seeds/OrderPackageExceptionTypeCountingRecordSeeder.php
  59. 4 5
      resources/js/queryForm/header.js
  60. 8 6
      resources/js/queryForm/queryForm.js
  61. 93 0
      resources/views/control/panel.blade.php
  62. 3 3
      resources/views/customer/project/create.blade.php
  63. 1 0
      resources/views/customer/project/part/_three.blade.php
  64. 0 1
      resources/views/demand/search/index.blade.php
  65. 1 1
      resources/views/inventory/statement/changeInventory.blade.php
  66. 2 3
      resources/views/inventory/stockInventory/mission.blade.php
  67. 1 0
      resources/views/maintenance/role/index.blade.php
  68. 2 1
      resources/views/maintenance/user/index.blade.php
  69. 36 0
      resources/views/maintenance/warehouse/create.blade.php
  70. 37 1
      resources/views/maintenance/warehouse/edit.blade.php
  71. 9 0
      resources/views/maintenance/warehouse/index.blade.php
  72. 0 1
      resources/views/order/index/delivering.blade.php
  73. 2 2
      resources/views/order/issue/index.blade.php
  74. 49 16
      resources/views/package/logistic/index.blade.php
  75. 10 4
      resources/views/personnel/discharge/task/_table.blade.php
  76. 12 0
      resources/views/personnel/discharge/task/index.blade.php
  77. 6 1
      resources/views/personnel/discharge/task/menu.blade.php
  78. 54 0
      resources/views/personnel/discharge/task/receipt.blade.php
  79. 1 1
      resources/views/process/index.blade.php
  80. 0 2
      resources/views/rejected/recycle.blade.php
  81. 0 2
      resources/views/rejected/search/general.blade.php
  82. 7 15
      resources/views/station/cachingShelf/list/_fillBox.blade.php
  83. 0 9
      resources/views/station/cachingShelf/list/_table.blade.php
  84. 85 82
      resources/views/station/cachingShelf/list/index.blade.php
  85. 95 0
      resources/views/store/deliveryAppointment/_printBody.blade.php
  86. 18 0
      resources/views/store/deliveryAppointment/_printInfo.blade.php
  87. 6 5
      resources/views/store/deliveryAppointment/appointment.blade.php
  88. 1 1
      resources/views/store/deliveryAppointment/delivery.blade.php
  89. 90 70
      resources/views/store/deliveryAppointment/exhibition.blade.php
  90. 81 17
      resources/views/store/deliveryAppointment/list.blade.php
  91. 2 4
      resources/views/store/fast/index.blade.php
  92. 137 0
      resources/views/store/inStorage/cacheRackStorage.blade.php
  93. 4 0
      resources/views/store/inStorage/menu.blade.php
  94. 14 2
      resources/views/transport/waybill/index.blade.php
  95. 0 21
      resources/views/unauthorized.blade.php/defaultException.blade.php
  96. 1 0
      routes/apiLocal.php
  97. 3 1
      routes/web.php
  98. 1 1
      tests/Feature/LogisticZopSyncTest.php
  99. 100 0
      tests/Services/CacheShelfService/CreateStationTask.php
  100. 77 0
      tests/Services/CacheShelfService/GetChildStationTest.php

+ 45 - 0
app/Console/Commands/UpdateOrderPackageExceptionTypeCountingRecordTask.php

@@ -0,0 +1,45 @@
+<?php
+
+namespace App\Console\Commands;
+
+use App\Services\LogService;
+use Illuminate\Console\Command;
+
+class UpdateOrderPackageExceptionTypeCountingRecordTask extends Command
+{
+    /**
+     * The name and signature of the console command.
+     *
+     * @var string
+     */
+    protected $signature = 'updateOrderPackageExceptionTypeCountingRecordTask';
+
+    /**
+     * The console command description.
+     *
+     * @var string
+     */
+    protected $description = '更新order_package_exception_type_counting_records';
+
+    /**
+     * Create a new command instance.
+     *
+     * @return void
+     */
+    public function __construct()
+    {
+        parent::__construct();
+    }
+
+    /**
+     * Execute the console command.
+     *
+     * @return int
+     */
+    public function handle()
+    {
+        LogService::log(__CLASS__,"更新order_package_exception_type_counting_records",'');
+        ini_set('memory_limit','2226M');
+        app('OrderPackageExceptionTypeCountingRecordService')->updateOrCreate(7);
+    }
+}

+ 3 - 1
app/Console/Kernel.php

@@ -72,8 +72,10 @@ class  Kernel extends ConsoleKernel
         $schedule->command('sync:batch')->everyMinute();
         $schedule->command('sync:order')->everyMinute();
         $schedule->command('syncOrderPackageLogisticRouteTask')->dailyAt('1:20');//同步快递信息到orderPackage
+        $schedule->command('syncOrderPackageLogisticRouteTask')->dailyAt('12:01');//同步快递信息到orderPackage
+        $schedule->command('updateOrderPackageExceptionTypeCountingRecordTask')->dailyAt('2:20');//更新OrderPackageExceptionTypeCountingRecord
         $schedule->command('SyncWmsCommoditiesInformation')->everyMinute();
-        $schedule->command('clear:cancelledOrder')->everyTenMinutes();
+        $schedule->command('clear:cancelledOrder')->everyMinute();
         $schedule->command('WasSyncWmsAsnInformation')->everyMinute();
         $schedule->command('create:weightStatistic')->dailyAt("00:30");
         $schedule->command('sync:carrier')->hourlyAt(1);

+ 14 - 0
app/Events/DeliveryAppointmentEvent.php

@@ -2,6 +2,7 @@
 
 namespace App\Events;
 
+use App\DeliveryAppointment;
 use App\DeliveryAppointmentCar;
 use Illuminate\Broadcasting\Channel;
 use Illuminate\Contracts\Broadcasting\ShouldBroadcastNow;
@@ -27,10 +28,23 @@ class DeliveryAppointmentEvent implements ShouldBroadcastNow
             /** @var Builder $query */
             $query->withCount("cars");
         }]);
+
+        $owner = $car->deliveryAppointment->owner->name ?? "";
+        $len = mb_strlen($owner);
+        $ownerName = "";
+        for($i=0;$i<$len-1;$i++)$ownerName .= "*";
+        $ownerName .= mb_substr($owner,$len-1,1);
+
         $count = $delivery->deliveryAppointment->cars_count ?? 0;
         $delivery->warehouse = $delivery->deliveryAppointment->warehouse_id ?? "";
         $delivery->cubic_meter = isset($delivery->deliveryAppointment->cubic_meter) && $delivery->deliveryAppointment->cubic_meter>0 ? ($count>1 ? $delivery->deliveryAppointment->cubic_meter."/".$count : $delivery->deliveryAppointment->cubic_meter) : "";
         $delivery->tonne = isset($delivery->deliveryAppointment->tonne) && $delivery->deliveryAppointment->tonne>0 ? ($count>1 ? $delivery->deliveryAppointment->tonne."/".$count : $delivery->deliveryAppointment->tonne) : "";
+        $delivery->license_plate_number = $delivery->license_plate_number ? $delivery->license_plate_number : substr($delivery->appointment_number,0,5)."****".substr($delivery->appointment_number,9,1);
+        $delivery->owner_name = $ownerName;
+        $delivery->status = DeliveryAppointmentCar::STATUS[$delivery->status];
+        $delivery->type = DeliveryAppointment::TYPE[$delivery->deliveryAppointment->type_mark] ?? '';
+        $delivery->period = isset($delivery->deliveryAppointment->date_period) ? ($delivery->deliveryAppointment->date_period==0 ? '上午' : '下午') : '';
+        $delivery->delivery_time = $delivery->delivery_time ? substr($delivery->delivery_time,11,5) : '';
         $this->delivery = $delivery->withoutRelations();
     }
 

+ 41 - 0
app/Events/UpdateOrderPackageExceptionListenerEvent.php

@@ -0,0 +1,41 @@
+<?php
+
+namespace App\Events;
+
+use Illuminate\Broadcasting\Channel;
+use Illuminate\Broadcasting\InteractsWithSockets;
+use Illuminate\Broadcasting\PresenceChannel;
+use Illuminate\Broadcasting\PrivateChannel;
+use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
+use Illuminate\Foundation\Events\Dispatchable;
+use Illuminate\Queue\SerializesModels;
+
+class UpdateOrderPackageExceptionListenerEvent
+{
+    use Dispatchable, InteractsWithSockets, SerializesModels;
+
+    /**
+     * @var $order_package_ids array
+     */
+    public $order_package_ids;
+
+    /**
+     * UpdateOrderPackageExceptionListenerEvent constructor.
+     * @param $order_package_ids
+     */
+    public function __construct($order_package_ids)
+    {
+        $this->order_package_ids = $order_package_ids;
+    }
+
+
+    /**
+     * Get the channels the event should broadcast on.
+     *
+     * @return \Illuminate\Broadcasting\Channel|array
+     */
+    public function broadcastOn()
+    {
+        return new PrivateChannel('channel-name');
+    }
+}

+ 11 - 47
app/Http/Controllers/CacheShelfController.php

@@ -3,12 +3,8 @@
 namespace App\Http\Controllers;
 
 use App\Components\AsyncResponse;
-use App\Exceptions\ErrorException;
-use App\MaterialBox;
 use App\Services\CacheShelfService;
-use App\Services\StationCacheShelfGridService;
 use App\Station;
-use App\StationCacheShelfGrid;
 use Illuminate\Contracts\Foundation\Application;
 use Illuminate\Contracts\View\Factory;
 use Illuminate\Database\Eloquent\Builder;
@@ -25,10 +21,10 @@ class CacheShelfController extends Controller
      */
     public function index()
     {
-        $stations = Station::query()->with('stationType:name', 'parent:name')->whereHas('stationType', function ($query) {
+        $stations = Station::query()->with('stationType:name', 'parent:name')->whereNull('parent_id')->whereIn('station_type_id', function ($query) {
             /** @var Builder $query */
-            $query->where('name', '缓存架');
-        })->paginate(100);
+            $query->from('station_types')->selectRaw('id')->where('name', '缓存架');
+        })->paginate(10);
 
         return view('station.cachingShelf.list.index', compact('stations'));
     }
@@ -42,54 +38,22 @@ class CacheShelfController extends Controller
     public function getTasksApi(Request $request,string $id,CacheShelfService $service)
     {
         /** @var Station $station */
-        $station = Station::query()->where('id',$id)->first();
-
-        $service->getTasks($station);
-        $this->success($station['grids']);
+        $station = $service->getChildStation($id);
+        $this->success($station);
     }
 
     /**
      * 缓存架亮灯
      * @param Request $request
-     * @param StationCacheShelfGridService $gridService
+     * @param CacheShelfService $service
+     * @return mixed
      */
-    public function lightOnApi(Request $request,StationCacheShelfGridService $gridService)
+    public function lightOnApi(Request $request,CacheShelfService $service)
     {
-        $grid_id = $request['index'];
-        /** @var Station $station */
-        $station = Station::query()->where('id',$request['id'])->first();
+        if($request['stationCode'] && $request['materialBoxCode'])
+        return $service->createStationTask($request['stationCode'],$request['materialBoxCode']);
 
-        $grid = StationCacheShelfGrid::query()->firstOrCreate(['station_id'=>$station['id'],'grid_id'=>$grid_id]);
-        $materialBox = MaterialBox::query()->firstOrCreate(['code'=>$request['code']]);
-
-        $grid->update(['material_box_id' => $materialBox['id'],'status' => 1]);
-
-        return $gridService->lightOn($station,$request['x'],$request['y']);
+        return ['success' => false,'message' => '参数错误'];
     }
 
-//    /**
-//     * 拍灯推送任务
-//     * @param Request $request
-//     * @param CacheShelfService $service
-//     */
-//    public function pushTaskApi(Request $request,CacheShelfService $service)
-//    {
-//        /**
-//         * @var Station $station
-//         * @var MaterialBox $materialBox
-//         * @var StationCacheShelfGrid $grid
-//         */
-//        $station = Station::query()->where('id',$request['id'])->first();
-//        $materialBox = MaterialBox::query()->where('code',$request['code'])->first();
-//        $grid = StationCacheShelfGrid::query()->where(['station_id'=>$station['id'],'grid_id'=>$request['index']])->first();
-//
-//        try {
-//            $bool = $service->putBinToStore($station, $materialBox, $grid);
-//            if($bool)$this->success();
-//            else $this->error('推送任务异常');
-//        } catch (ErrorException $e) {
-//            $this->error($e->getMessage());
-//        }
-//    }
-
 }

+ 15 - 1
app/Http/Controllers/ControlPanelController.php

@@ -160,6 +160,20 @@ class ControlPanelController extends Controller
         $this->success(["title"=>$title,"data"=>$data]);
     }
 
+    public function exceptionTypeApi(Request $request)
+    {
+        $ownerIds=$request->owner_ids;
+        if (!$ownerIds || in_array('all',$ownerIds)) $ownerIds = $this->getCountingOwnerIds(null);
+        $service = app('OrderPackageExceptionTypeCountingRecordService');
+
+        $data = $service->get([
+            'start_date' => $request->start,
+            'end_date' => $request->end,
+            'owner_ids' => $ownerIds,
+        ]);
+        $this->success(["title"=>'',"data"=>$data]);
+    }
+
     /**
      * 根据指定日期获取目标统计数据
      *
@@ -172,7 +186,7 @@ class ControlPanelController extends Controller
             $sql = <<<sql
 SELECT DATE_FORMAT(order_packages.created_at,'%Y-%m-%d') date,
 SUM(CASE WHEN order_packages.weighed_at IS NOT NULL THEN 1 ELSE 0 END) AS count,
-COUNT(1) total FROM order_packages LEFT JOIN orders ON order_packages.order_id=orders.id WHERE orders.wms_status != '订单取消' 
+COUNT(1) total FROM order_packages LEFT JOIN orders ON order_packages.order_id=orders.id WHERE orders.wms_status != '订单取消'
 AND order_packages.created_at >= '{$date} 00:00:00' GROUP BY date
 sql;
 

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

@@ -5,6 +5,7 @@ namespace App\Http\Controllers;
 use App\Components\AsyncResponse;
 use App\Jobs\OrderCreateInstantBill;
 use App\Jobs\ResetInstantBill;
+use App\Jobs\StoreCreateInstantBill;
 use App\Order;
 use App\Owner;
 use App\OwnerAreaReport;
@@ -571,7 +572,7 @@ class CustomerController extends Controller
             ->whereNotIn("id",OwnerFeeDetail::query()->select("outer_id")->where("outer_table_name","stores")
                 ->whereBetween("worked_at",["{$startData} 00:00:00","{$endDate} 23:59:59"]))->get();
         foreach ($stores->chunk(50) as $st){
-            dispatch(new OrderCreateInstantBill($st));
+            dispatch(new StoreCreateInstantBill($st));
         }
     }
     public function resetBillConfirmation()

+ 25 - 12
app/Http/Controllers/DeliveryAppointmentController.php

@@ -29,7 +29,7 @@ class DeliveryAppointmentController extends Controller
     {
         if(!Gate::allows('入库管理-入库预约-预约管理')){ return view("exception.authority");  }
         $list = app("DeliveryAppointmentService")->query(request()->input())
-            ->with("logistic")
+            ->with(["logistic",'warehouse','details.commodity.barcodes','cars.car'])
             ->paginate(request("paginate") ?? 50);
 
         $warehouses = Warehouse::query()->select("id","name")->get();
@@ -174,8 +174,8 @@ class DeliveryAppointmentController extends Controller
                 $len = strlen($appointment->id);
                 $ten = $len < 2 ? "0" : substr($appointment->id,$len-2,1);
                 $one = substr($appointment->id,$len-1,1);
-                //唯一码 随机数+十位+当前下标+个位+日期
-                $number = $rand.$ten.$index.$one.date("d");
+                //唯一码 仓库CODE+随机数+十位+当前下标+个位+日期
+                $number = $warehouse->code.$rand.$ten.$index.$one.date("d");
                 $insert[] = [
                     "delivery_appointment_id" => $appointment->id,
                     "license_plate_number"    => $car["license_plate_number"],
@@ -362,7 +362,7 @@ class DeliveryAppointmentController extends Controller
         $list = [];
         DeliveryAppointmentCar::query()->with(["deliveryAppointment"=>function($query){
             /** @var Builder $query */
-            $query->withCount("cars");
+            $query->withCount("cars")->with("owner");
         }])->whereHas("deliveryAppointment",function ($query)use($period,$warehouse,$date){
             /** @var Builder $query */
             $query->where("appointment_date",$date)
@@ -376,15 +376,24 @@ class DeliveryAppointmentController extends Controller
             ->limit(10)->get()->each(function ($car)use(&$list){
                 //$diff = $car->delivery_time ? (strtotime($car->delivery_time)+1799)-time() : 0;
                 $count = $car->deliveryAppointment->cars_count ?? 0;
+                $owner = $car->deliveryAppointment->owner->name ?? "";
+                $len = mb_strlen($owner);
+                $ownerName = "";
+                for($i=0;$i<$len-1;$i++)$ownerName .= "*";
+                $ownerName .= mb_substr($owner,$len-1,1);
                 $list[] = [
                     "id" => $car->id,
-                    "license_plate_number" => $car->license_plate_number,
+                    "license_plate_number" => $car->license_plate_number ? $car->license_plate_number : substr($car->appointment_number,0,5)."****".substr($car->appointment_number,9,1),
                     "driver_name" => $car->driver_name,
                     "driver_phone" => $car->driver_phone,
-                    "status" => $car->status,
+                    "status" => DeliveryAppointmentCar::STATUS[$car->status],
                     "cubic_meter" => isset($car->deliveryAppointment->cubic_meter) && $car->deliveryAppointment->cubic_meter>0 ? ($count>1 ? $car->deliveryAppointment->cubic_meter."/".$count : $car->deliveryAppointment->cubic_meter) : "",
                     "tonne" => isset($car->deliveryAppointment->tonne) && $car->deliveryAppointment->tonne>0 ? ($count>1 ? $car->deliveryAppointment->tonne."/".$count : $car->deliveryAppointment->tonne) : "",
                     //"diff" => $diff>0 ? $diff*1000 : 0,
+                    "owner_name" => $ownerName,
+                    "type" => DeliveryAppointment::TYPE[$car->deliveryAppointment->type_mark] ?? '',
+                    "period"=>isset($car->deliveryAppointment->date_period) ? ($car->deliveryAppointment->date_period==0 ? '上午' : '下午') : '',
+                    "delivery_time" => $car->delivery_time ? substr($car->delivery_time,11,5) : '',
                 ];
             });
         return $list;
@@ -576,14 +585,18 @@ html;
     public function verifyASN()
     {
         $this->gate("入库管理-入库预约-预约");
-        $asn = request("asn");
+        $asn = preg_split('/[,, ]+/is', request("asn"));
         $owner = request("owner_id");
-        if (!$asn || strlen($asn)<13)$this->error("非法ASN单号");
-        $query = Store::query()->where("asn_code",$asn);
+        if (!$asn || strlen(request("asn"))<13)$this->error("非法ASN单号");
+        $query = Store::query()->whereIn("asn_code",$asn);
         if ($owner)$query->where("owner_id",$owner);
-        $store = $query->with("storeItems")->first();
-        if (!$store)$this->error("无此ASN单号");
-        $this->success($store->storeItems);
+        $stores = $query->with("storeItems")->get();
+        if (!$stores)$this->error("无此ASN单号");
+        $items = [];
+        $stores->each(function ($store)use(&$items){
+            if ($store->storeItems)$items = array_merge($items,$store->storeItems->toArray());
+        });
+        $this->success($items);
     }
 
     /**

+ 11 - 1
app/Http/Controllers/DischargeTaskController.php

@@ -10,8 +10,10 @@ use App\Http\Requests\DischargeTask\DischargeTaskRequest;
 use App\Services\common\ExportService;
 use App\Services\OwnerService;
 use App\Warehouse;
+use Carbon\Carbon;
 use Illuminate\Http\Request;
- use Illuminate\Support\Facades\Gate;
+use Illuminate\Support\Facades\Gate;
+use function Sodium\compare;
 
 class DischargeTaskController extends Controller
 {
@@ -134,6 +136,14 @@ class DischargeTaskController extends Controller
         return app(ExportService::class)->json($row, $json, "卸货结算报表");
     }
 
+    // 回执单
+    public function receipt(Request $request)
+    {
+        $task = DischargeTask::query()->with(['facilitator', 'owner','warehouse'])->where('id' , $request['id'])->first();
+        $task->type = DischargeTask::types[$task->type];
+        return view('personnel.discharge.task.receipt',compact('task'));
+    }
+
     public function show(DischargeTask $dischargeTask)
     {
     }

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

@@ -2,11 +2,13 @@
 
 namespace App\Http\Controllers;
 
+use App\Events\UpdateOrderPackageExceptionListenerEvent;
 use App\Filters\OrderPackageFilters;
 use App\Logistic;
 use App\OrderPackage;
 use App\Owner;
 use App\Services\UserService;
+use Illuminate\Database\Eloquent\Builder;
 use Illuminate\Http\Request;
 
 class PackageLogisticController extends Controller
@@ -28,7 +30,9 @@ class PackageLogisticController extends Controller
         $orderPackages = OrderPackage::query()
             ->filter($filters)
             ->whereIn('owner_id', $owner_ids)->with(['order.logistic', 'order.owner', 'order.issue' => function ($query) {
-                $query->with(['issueType', 'logs.user']);
+                $query->with(['issueType', 'logs'=>function($query) {
+                    $query->with('user')->orderBy('created_at', 'DESC');
+                }]);
             }])->orderByDesc('id')->paginate($request->paginate ?? 50);
         $logistics = Logistic::all();
         $owners = Owner::find($owner_ids);
@@ -45,17 +49,26 @@ class PackageLogisticController extends Controller
             $data['exception_type'] = $request->input('exception_type');
         }
         OrderPackage::query()->where('id', $request['id'])->update($data);
+        //更新统计数据
+        event(new UpdateOrderPackageExceptionListenerEvent([$request['id']]));
     }
 
     public function batchUpdate(Request $request)
     {
-        if ('无' == $request->input('exception_type')) {
-            $data['exception_type'] = $request->input('exception_type');
-            $data['exception'] = "否";
-        } else {
-            $data['exception_type'] = $request->input('exception_type');
+        $data = [];
+        if (array_key_exists('exception_type',$request->all())) {
+            if ('无' == $request->input('exception_type')) {
+                $data['exception_type'] = $request->input('exception_type');
+                $data['exception'] = "否";
+            } else {
+                $data['exception_type'] = $request->input('exception_type');
+            }
+        }else if (array_key_exists('status',$request->all())) {
+            $data['status'] = $request->input('status');
         }
         $logistic_numbers = $request->input('logistic_numbers');
         OrderPackage::query()->whereIn('logistic_number', $logistic_numbers)->update($data);
+        //更新统计数据
+        event(new UpdateOrderPackageExceptionListenerEvent($logistic_numbers));
     }
 }

+ 8 - 0
app/Http/Controllers/StoreController.php

@@ -432,4 +432,12 @@ class StoreController extends Controller
         ])->validate();
         return $validator;
     }
+
+    /**
+     * 缓存架入库表单
+     */
+    public function cacheRackStorage()
+    {
+        return \view("store.inStorage.cacheRackStorage");
+    }
 }

+ 113 - 8
app/Http/Controllers/TestController.php

@@ -25,6 +25,7 @@ use App\Exceptions\ErrorException;
 use App\Events\CancelOrder;
 use App\Events\SendEmailEvent;
 use App\Exceptions\Exception;
+use App\Feature;
 use App\Http\Controllers\api\thirdPart\haiq\PickStationController;
 use App\Http\Controllers\api\thirdPart\hengli\PackageController;
 use App\Http\Controllers\api\thirdPart\weight\WeightBaseController;
@@ -103,6 +104,7 @@ use App\Services\OracleDocAsnHerderService;
 use App\Services\OracleDOCOrderHeaderService;
 use App\Services\OracleDocWaveDetailService;
 use App\Services\OrderCommodityService;
+use App\Services\OrderPackageExceptionTypeCountingRecordService;
 use App\Services\OrderPackageReceivedSyncService;
 use App\Services\OrderPackageService;
 use App\Services\OrderService;
@@ -176,16 +178,53 @@ class TestController extends Controller
     {
         return call_user_func([$this, $method], $request);
     }
-
     public function test()
     {
-        $order = Order::query()->where("code","SO210509003964")->first();
+        $asnno = "ASN2105141388";
+        $query = DB::raw("SELECT b.ALTERNATE_SKU1,h.WAREHOUSEID,h.asnno,d.ASNLINENO,d.SKUDESCRC,h.CUSTOMERID,d.SKU,d.PACKID,d.RECEIVEDQTY_EACH,d.EXPECTEDQTY_EACH,d.LOTATT01,d.LOTATT02,d.lotatt04,".
+            "d.lotatt05,d.lotatt08,d.USERDEFINE1,d.USERDEFINE2,d.USERDEFINE3,d.USERDEFINE4,d.USERDEFINE5,d.RECEIVINGLOCATION FROM DOC_ASN_DETAILS d ".
+            " LEFT JOIN BAS_SKU b ON d.CUSTOMERID = b.CUSTOMERID AND d.SKU = b.SKU INNER JOIN DOC_ASN_HEADER h ON d.ASNNO = h.ASNNO WHERE h.ASNNO = ?");
+        $detail = DB::connection("oracle")->selectOne($query,[$asnno]);
+        //dd($detail);
+        $ser = new StoreService();
+        $result = $ser->warehousing(array(
+            "IN_Warehouse" => $detail->warehouseid ?? '',
+            "In_ASNNo_C" => $detail->asnno ?? '',
+            "In_ASNLineNo_C" => $detail->asnlineno ?? '',
+            "In_New_TraceID_C" => (string)rand(100,999),
+            "In_CustomerID" => $detail->customerid ?? '',
+            "In_SKU" => $detail->sku ?? '',
+            "In_ReceivedQty" => (string)((int)$detail->expectedqty_each - (int)$detail->receivedqty_each) ?? '',
+            "In_PackID" => $detail->packid ?? '',
+            "In_LotAtt01_C" => $detail->lotatt01 ?? '',
+            "In_LotAtt02_C" => $detail->lotatt02 ?? '',
+            "In_LotAtt04_C" => $detail->lotatt04 ?? '',
+            "In_LotAtt05_C" => $detail->lotatt05 ?? '',
+            "In_LotAtt08_C" => $detail->lotatt08 ?? '',
+            "In_UserDefine1" => $detail->userdefine1 ?? '',
+            "In_UserDefine2" => $detail->userdefine2 ?? '',
+            "In_UserDefine3" => $detail->userdefine3 ?? '',
+            "In_UserDefine4" => $detail->userdefine4 ?? '',
+            "In_UserDefine5" => $detail->userdefine5 ?? '',
+            "In_FMLocation"  => 'STAGE' . $detail->warehouseid,
+            "In_TOLocation_C" => 'STAGE' . $detail->warehouseid,//'IDE0000001',
+        ));
+       dd($result);
+        /*$order = Order::query()->where("code","SO210511005663")->first();
         $ser = new OrderService();
         $ser->createInstantBill($order);
-        dd();
-        $store = Store::query()->find(164944);
+        dd();*/
+        $store = Store::query()->find(173382);dd($store->load("storeItems.commodity"));
         $ser = new StoreService();
         $ser->createInstantBill($store);
+        dd($store);
+    }
+    public function orderCreateBill()
+    {
+        $order = Order::query()->find(\request("id"));
+        $ser = new OrderService();
+        $ser->createInstantBill($order);
+        dd("order create bill success");
     }
     public function supplementMarchOwnerReport()
     {
@@ -760,7 +799,7 @@ class TestController extends Controller
 
     public function reNewBatches3()
     {
-        $batches = Batch::query()->where('id', '>', 97397)->get('code');
+        $batches = Batch::query()->where('id', '>', 111090)->get('code');
         $batchCodes = $batches->map(function ($batch) {
             return $batch['code'];
         })->toArray();
@@ -787,7 +826,7 @@ class TestController extends Controller
 //        dd($logs);
         foreach ($batchCodes as $code) {
 //            $request=Cache::get('temp'.$code)['description'];
-            $request = Log::query()->select('description')->where('CREATED_AT', '>=', '2021-04-14')
+            $request = Log::query()->select('description')->where('CREATED_AT', '>=', '2021-05-18 15:00')
                 ->where('method', "issued_newBatch")
                 ->where('description', 'like', "%{$code}%")
                 ->first();
@@ -919,8 +958,9 @@ class TestController extends Controller
         dump($orderPackage);
     }
 
-    public function logistic_route_sync_SF()
+    public function logistic_route_sync()
     {
+        ini_set('max_execution_time', 60*10);
         $orderPackageReceivedSyncService = new OrderPackageReceivedSyncService();
         $orderPackageReceivedSyncService->syncLogisticRoute();
     }
@@ -1465,5 +1505,70 @@ TEXT;
     {
         return view('httpTest');
     }
-}
 
+    public function updateStation()
+    {
+//        $hid = 'hengli004';
+//        $measuringMachine = MeasuringMachine::query()->firstOrCreate(['code' => $hid],['name' => $hid]); // 称重设备
+        StationTask::query()->where('id',709)->update(
+            ['status'=>'完成']
+        );
+//        StationTaskMaterialBox::query()->where('id',7033)->delete();
+//        Station::query()->where('id',9)->delete();
+//        Station::query()->where('code' ,'缓存架01')->update(['code' => 'B1']);
+//        Station::query()->where('code' ,'缓存架02')->update(['code' => 'B2']);
+//        Station::query()->where('name' ,'HAI缓存架01-03-03')->update(['name' => 'HAIB1-03-03']);
+    }
+
+    public function orderPackageUnique()
+    {
+        // select logistic_number,count(1) counts from order_packages where id >= 1590001   GROUP BY logistic_number HAVING counts > 1;
+        $orderPackages = OrderPackage::query()->selectRaw('count(1) counts,logistic_number')->where('id','>=','1590000')->groupBy('logistic_number')->having('counts','>','1')->get();
+        dd($orderPackages);
+        foreach ($orderPackages as $orderPackage) {
+            $items = OrderPackage::query()->where('logistic_number',$orderPackage['logistic_number'])->get();
+            $orderPackage = $items->first();
+            foreach ($items as $item) {
+                $orderPackage['batch_number'] = $item['batch_number'] ?? $orderPackage['batch_number'];
+                $orderPackage['batch_rule'] = $item['batch_rule'] ?? $orderPackage['batch_rule'];
+                $orderPackage['bulk'] = $item['bulk'] ?? $orderPackage['bulk'];
+                $orderPackage['weight'] = $item['weight'] ?? $orderPackage['weight'];
+                $orderPackage['length'] = $item['length'] ?? $orderPackage['length'];
+                $orderPackage['width'] = $item['width'] ?? $orderPackage['width'];
+                $orderPackage['height'] = $item['height'] ?? $orderPackage['height'];
+                $orderPackage['measuring_machine_id'] = $item['measuring_machine_id'] ?? $orderPackage['measuring_machine_id'];
+                $orderPackage['weighed_at'] = $item['weighed_at'] ?? $orderPackage['weighed_at'];
+                $orderPackage['owner_id'] = $item['owner_id'] ?? $orderPackage['owner_id'];
+                $orderPackage['received_at'] = $item['received_at'] ?? $orderPackage['received_at'];
+                $orderPackage['transfer_status'] = $item['transfer_status'] ?? $orderPackage['transfer_status'];
+                $orderPackage['status'] = $item['status'] != '无' ? $item['status'] : $orderPackage['transfer_status'];
+                $orderPackage['uploaded_to_wms'] = $item['uploaded_to_wms'] != '否' ? $item['uploaded_to_wms'] : $orderPackage['transfer_status'];
+            }
+            $orderPackages_filter = $items->filter(function($item)use($orderPackage){
+                if($orderPackage['id'] === $item['id'])return false;
+                return true;
+            });
+            $ids = $orderPackages_filter->map(function($item){
+                return $item['id'];
+            });
+            LogService::log('order_packages','order_packages_logistic_number_unique_delete',json_encode($orderPackages_filter));
+            OrderPackage::query()->whereIn('id',$ids)->delete();
+            $orderPackage->save();
+        }
+    }
+
+    public function endStationTask()
+    {
+        $stationTask = StationTask::query()->where('id',711)->first();
+        $stationTask->update(['status'=>'完成']);
+    }
+
+    public function order_package_exception_type_counting_record_init()
+    {
+        /**
+         * @var $service OrderPackageExceptionTypeCountingRecordService
+         */
+        $service = app('OrderPackageExceptionTypeCountingRecordService');
+        $service->updateOrCreate(30);
+    }
+}

+ 2 - 0
app/Http/Controllers/WaybillController.php

@@ -3,6 +3,7 @@
 namespace App\Http\Controllers;
 
 
+use App\CarType;
 use App\Components\AsyncResponse;
 use App\Region;
 use App\Services\CarTypeService;
@@ -61,6 +62,7 @@ class WaybillController extends Controller
             'waybills' => $waybills,
             'logistics' => $logisticService->getSelection(["id","name"],"物流"),
             'owners' => $ownerService->getIntersectPermitting(),
+            "carTypes" => CarType::query()->get(),
             'paginateParams'=>$paginateParams,
             'uriType'=>$request->uriType??'']);
     }

+ 10 - 7
app/Http/Controllers/api/thirdPart/haiq/LightController.php

@@ -8,7 +8,9 @@ namespace App\Http\Controllers\api\thirdPart\haiq;
 
 use App\Services\CacheShelfService;
 use App\Services\ForeignHaiRoboticsService;
+use App\Station;
 use Illuminate\Http\Request;
+use Illuminate\Support\Facades\Log;
 
 class LightController
 {
@@ -30,13 +32,14 @@ class LightController
      * @return array
      */
     public function update(Request $request){// 拍灯以后的消息发至此处
-
-//        if($request['PTLAction'] == 0){  // 拍灯 推送任务
-//            /** @var CacheShelfService $cacheShelfService */
-//            $cacheShelfService = app(CacheShelfService::class);
-//            $result =   $cacheShelfService->lightOffTask($request['locCode'],$request['PTLAction']);
-//            return ['location'=>$result['success'] ? 200 :0,'errMsg'=>$result['errMsg'] ?? null,'data'=>$request->all()];
-//        }
+        $station = Station::query()->with('stationType')->where('code',$request['locCode'])->first();
+        if( $station->stationType && $station->stationType->name == '缓存架' ){  // 拍灯 推送任务
+            if($request['PTLAction'] !== 0) return ['location' => 200,'errMsg' => 'is cacheShelf','data' => $request->all()];
+            /** @var CacheShelfService $cacheShelfService */
+            $cacheShelfService = app(CacheShelfService::class);
+            $result =   $cacheShelfService->lightOffTask($request['locCode'],$request['PTLAction']);
+            return ['location'=>$result['success'] ? 200 :0,'errMsg'=>$result['errMsg'] ?? null,'data'=>$request->all()];
+        }
         $success = $request->input('success');
         $location = $success?200:0;
         app('LogService')->log(__METHOD__,__FUNCTION__,'拍灯:'.json_encode($request->all()));

+ 1 - 1
app/Http/Controllers/api/thirdPart/weight/WeightBaseController.php

@@ -289,7 +289,7 @@ class WeightBaseController
     {
         $hid = $this->getValue($this->hid, $params);
         /** @var MeasuringMachine $measuringMachine */
-        $measuringMachine = MeasuringMachine::query()->firstOrCreate(['code' => $hid]); // 称重设备
+        $measuringMachine = MeasuringMachine::query()->firstOrCreate(['code' => $hid],['name' => $hid]); // 称重设备
         $measuringMachine->turnOn();
         $measuringMachine->turnOffInMinutes(30);
         return $measuringMachine;

+ 1 - 1
app/Jobs/DeliveryAppointmentCheck.php

@@ -38,7 +38,7 @@ class DeliveryAppointmentCheck implements ShouldQueue
         /** @var DeliveryAppointment|\stdClass $appointment */
         $appointment = DeliveryAppointment::query()->find($this->int);
         $time = explode("-",DeliveryAppointment::PERIOD[$appointment->date_period])[1];
-        if ($appointment && $appointment->status!=2
+        if ($appointment && $appointment->status==0
             && Carbon::now()->gt(Carbon::parse($appointment->appointment_date." ".$time.":00:00"))
         )$appointment->update(["status"=>3]);
     }

+ 57 - 0
app/Jobs/LogisticYDSync.php

@@ -0,0 +1,57 @@
+<?php
+
+namespace App\Jobs;
+
+use App\Services\LogisticYDService;
+use App\Services\OrderPackageReceivedSyncService;
+use Illuminate\Bus\Queueable;
+use Illuminate\Contracts\Queue\ShouldQueue;
+use Illuminate\Foundation\Bus\Dispatchable;
+use Illuminate\Queue\InteractsWithQueue;
+use Illuminate\Queue\SerializesModels;
+
+class LogisticYDSync implements ShouldQueue
+{
+    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
+    /**
+     * @var $logisticYDService LogisticYDService
+     * @var $orderPackageReceivedSyncService OrderPackageReceivedSyncService
+     * @var $orderPackageReceivedSyncService OrderPackageReceivedSyncService
+     * @var $logistic_number string
+     */
+
+    protected $logistic_number;
+
+    protected $logisticYDService;
+    protected $orderPackageReceivedSyncService;
+
+    /**
+     * LogisticYDSync constructor.
+     * @param $logistic_number
+     */
+    public function __construct($logistic_number)
+    {
+        $this->logistic_number = $logistic_number;
+    }
+
+
+    /**
+     * Execute the job.
+     *
+     * @return void
+     */
+    public function handle()
+    {
+        ini_set('max_execution_time', 10);
+        $this->logisticYDService = app('LogisticYDService');
+        //先订阅订单
+        $this->logisticYDService->registerApi([$this->logistic_number]);
+        //查询订单路由信息
+        $nativeResponse = $this->logisticYDService->query($this->logistic_number);
+        //格式化信息
+        $formattedData = $this->logisticYDService->format($nativeResponse);
+        $this->orderPackageReceivedSyncService = app('OrderPackageReceivedSyncService');
+        //更新数据
+        $this->orderPackageReceivedSyncService->update([$formattedData]);
+    }
+}

+ 6 - 157
app/Jobs/LogisticZopSync.php

@@ -92,7 +92,10 @@ class LogisticZopSync implements ShouldQueue
             $resultItem['transfer_status'] = [];
         }
         try {
-            $resultItem = $this->setExceptionType($resultItem, $lastRoute ? $lastRoute->scanDate / 1000 : null);
+            $orderPackageReceivedSyncService = app('OrderPackageReceivedSyncService');
+            $exceptionData = $orderPackageReceivedSyncService->setExceptionType($resultItem, $lastRoute ? $lastRoute->scanDate / 1000 : null);
+            $resultItem['exception_type'] = $exceptionData['exception_type'];
+            $resultItem['exception'] = $exceptionData['exception'];
         } catch (\Exception $e) {
         }
         if ($resultItem['status'] == null) {
@@ -107,164 +110,10 @@ class LogisticZopSync implements ShouldQueue
             $resultItem['exception_type'] = '无';
             $resultItem['exception'] = '否';
         }
+        $resultItem['routes_length'] = array_key_exists('transfer_status', $resultItem) ? count($resultItem['transfer_status']) : 0;
         $result[] = $resultItem;
         return $result;
     }
-
-    /**
-     * @param array $data
-     * @param $lastRouteDate
-     * @return array
-     */
-    private function setExceptionType(array $data, $lastRouteDate = null): array
-    {
-        $logistic_number = $data['logistic_number'];
-        /** @var OrderPackage $orderPackage */
-        $orderPackage = OrderPackage::query()->with('order')->where('logistic_number', $logistic_number)->first();
-        $delivered_duration = now()->diffInHours(Carbon::parse($orderPackage['sent_at']));
-        $last_routed_duration = now()->diffInHours(Carbon::parse($lastRouteDate));
-        $VALID_HOURS = 4;
-        $SHORT_RESPONSE_HOURS = (function ($province) {
-            switch ($province) {
-                case '浙江省':
-                case '江苏省':
-                case '上海':
-                case '安徽省':
-                    return 24;
-                case '北京':
-                case '天津':
-                case '江西省':
-                case '湖北省':
-                case '湖南省':
-                case '广东省':
-                case '福建省':
-                case '山东省':
-                case '河北省':
-                case '河南省':
-                case '山西省':
-                case '四川省':
-                case '陕西省':
-                case '重庆':
-                case '广西壮族自治区':
-                case '贵州省':
-                case '云南省':
-                case '海南省':
-                case '吉林省':
-                case '黑龙江省':
-                case '辽宁省':
-                    return 72;
-                case '青海省':
-                case '宁夏回族自治区':
-                case '甘肃省':
-                case '内蒙古自治区':
-                case '新疆维吾尔自治区':
-                case '西藏自治区':
-                    return 120;
-                default:
-                    return 24;
-            }
-        })($orderPackage->order->province);
-        $LONG_RESPONSE_HOURS = (function ($province) {
-            switch ($province) {
-                case '浙江省':
-                case '江苏省':
-                case '上海':
-                case '安徽省':
-                    return 72;
-                case '北京':
-                case '天津':
-                case '江西省':
-                case '湖北省':
-                case '湖南省':
-                case '广东省':
-                case '福建省':
-                case '山东省':
-                case '河北省':
-                case '河南省':
-                case '山西省':
-                case '四川省':
-                case '陕西省':
-                case '重庆':
-                case '广西壮族自治区':
-                case '贵州省':
-                case '云南省':
-                case '海南省':
-                case '吉林省':
-                case '黑龙江省':
-                case '辽宁省':
-                    return 120;
-                case '青海省':
-                case '宁夏回族自治区':
-                case '甘肃省':
-                case '内蒙古自治区':
-                case '新疆维吾尔自治区':
-                case '西藏自治区':
-                    return 168;
-                default:
-                    return 72;
-            }
-        })($orderPackage->order->province);
-        $SENDING_RESPONSE_HOURS = 48;
-        $IS_ROUTED = 1;               //0000 0001 有路由信息
-        $IS_IN_VALID_TIME = 2;        //0000 0010 大于4小时
-        $IS_WEIGHED = 4;              //0000 0100 称重过
-        $IS_RECEIVED = 8;          //0000 1000 已经收货
-        $IS_SENDING = 16;             //0001 0000 正在派送
-        $IS_SHORT_NO_RESPONSE = 32;     //0010 0000 中转异常
-        $IS_LONG_NO_RESPONSE = 64;     //0010 0000 疑似丢件
-        $IS_SENDING_NO_RESPONSE = 128;     //0010 0000 派送异常
-        $conclusion = (function () use (
-            $data, $delivered_duration, $last_routed_duration,
-            $VALID_HOURS, $IS_ROUTED, $IS_IN_VALID_TIME, $IS_WEIGHED, $IS_RECEIVED, $IS_SENDING, $IS_SHORT_NO_RESPONSE, $IS_LONG_NO_RESPONSE, $IS_SENDING_NO_RESPONSE,
-            $SHORT_RESPONSE_HOURS, $LONG_RESPONSE_HOURS, $SENDING_RESPONSE_HOURS,
-            $orderPackage
-        ) {
-            $conclusion = 0;
-            $conclusion |= !empty($data['transfer_status']) ? $IS_ROUTED : 0;
-            $conclusion |= ($delivered_duration > $VALID_HOURS) ? $IS_IN_VALID_TIME : 0;
-            $conclusion |= ($orderPackage->weighed_at) ? $IS_WEIGHED : 0;
-            $conclusion |= ($data['status'] == '已收件') ? $IS_RECEIVED : 0;
-            $conclusion |= ($data['status'] == '派送中') ? $IS_SENDING : 0;//
-            $conclusion |= ($last_routed_duration > $SHORT_RESPONSE_HOURS && $last_routed_duration < $LONG_RESPONSE_HOURS) ? $IS_SHORT_NO_RESPONSE : 0;
-            $conclusion |= ($last_routed_duration > $LONG_RESPONSE_HOURS) ? $IS_LONG_NO_RESPONSE : 0;
-            $conclusion |= ($last_routed_duration > $SENDING_RESPONSE_HOURS && $data['status'] == '派送中') ? $IS_SENDING_NO_RESPONSE : 0;
-            return $conclusion;
-        })();
-        switch ($conclusion) {
-            case $IS_IN_VALID_TIME:
-                $data['exception_type'] = '疑似库内丢件';
-                break;
-            case $IS_IN_VALID_TIME | $IS_WEIGHED:
-                $data['exception_type'] = '揽件异常';
-                break;
-            case $IS_ROUTED | $IS_IN_VALID_TIME | $IS_SHORT_NO_RESPONSE:
-            case $IS_ROUTED | $IS_IN_VALID_TIME | $IS_SHORT_NO_RESPONSE | $IS_WEIGHED:
-                $data['exception_type'] = '中转异常';
-                break;
-            case $IS_ROUTED | $IS_IN_VALID_TIME | $IS_LONG_NO_RESPONSE:
-            case $IS_ROUTED | $IS_IN_VALID_TIME | $IS_LONG_NO_RESPONSE | $IS_WEIGHED:
-                $data['exception_type'] = '疑似丢件';
-                break;
-            default:
-                break;
-        }
-        if ($conclusion
-            == ($conclusion | $IS_ROUTED | $IS_IN_VALID_TIME | $IS_SENDING | $IS_SENDING_NO_RESPONSE)) {
-            $data['exception_type'] = '派件异常';
-        }
-        switch ($conclusion) {
-            case $IS_IN_VALID_TIME:
-            case $IS_IN_VALID_TIME | $IS_WEIGHED:
-            case $IS_ROUTED | $IS_SHORT_NO_RESPONSE:
-            case $IS_LONG_NO_RESPONSE:
-                $data['exception'] = '是';
-                break;
-            default:
-                break;
-        }
-        return $data;
-    }
-
     /**
      * 正常的状态与签收时间
      * @param $lastRoute
@@ -332,7 +181,7 @@ class LogisticZopSync implements ShouldQueue
         $request->setUrl($url);
         $request->setBody(json_encode([
             'billCode' => $this->logistic_number,
-        ]));
+        ],JSON_UNESCAPED_UNICODE));
         return json_decode($client->execute($request));
     }
 }

+ 1 - 1
app/Jobs/ResetInstantBill.php

@@ -176,7 +176,7 @@ class ResetInstantBill implements ShouldQueue
                 /** @var \stdClass $store */
                 $store = Store::query()->find($this->detail->outer_id);
                 if (!$store || $store->status != "已入库") break;
-                $store->loadMissing(["storeItems","warehouse"]);
+                $store->loadMissing(["storeItems.commodity","warehouse"]);
 
                 /** @var OwnerPriceOperationService $service */
                 $service = app("OwnerPriceOperationService");

+ 5 - 1
app/Listeners/AddOrUpdateOrderIssuesListener.php

@@ -3,6 +3,7 @@
 namespace App\Listeners;
 
 use App\Events\AddOrUpdateOrderIssues;
+use App\Events\UpdateOrderPackageExceptionListenerEvent;
 use App\OrderIssue;
 use App\OrderPackage;
 use Illuminate\Contracts\Queue\ShouldQueue;
@@ -28,7 +29,7 @@ class AddOrUpdateOrderIssuesListener implements ShouldQueue
     public function handle(AddOrUpdateOrderIssues $event)
     {
         $order_ids = OrderIssue::query()->select('order_id')->whereIn('order_id', $event->order_ids)->whereIn('order_issue_type_id', function ($query) {
-            $query->from('order_issue_types')->select('id')->whereNotIn('name', ['拦截', '信息更改', '其他', '错漏发', '仓库问题', '二次加工', '全检问题', '系统问题', '快递方式更改']);
+            $query->from('order_issue_types')->select('id')->whereNotIn('name', ['拦截', '信息更改', '其他', '错漏发', '仓库问题', '二次加工', '全检问题', '系统问题', '快递方式更改', '无记录']);
         })->pluck('order_id');
         OrderPackage::query()->whereIn('order_id',
             $order_ids)
@@ -36,5 +37,8 @@ class AddOrUpdateOrderIssuesListener implements ShouldQueue
                 'exception_type' => '其他',
                 'exception' => '是',
             ]);
+        //更新统计数据
+        $orderPackageIds = OrderPackage::query()->whereIn('order_id', $order_ids)->pluck('id');
+        event(new UpdateOrderPackageExceptionListenerEvent($orderPackageIds));
     }
 }

+ 5 - 1
app/Listeners/UpdateOrderPackageExceptionListener.php

@@ -3,6 +3,7 @@
 namespace App\Listeners;
 
 use App\Events\OrderIssueProcessLogCreateEvent;
+use App\Events\UpdateOrderPackageExceptionListenerEvent;
 use App\OrderPackage;
 use Illuminate\Contracts\Queue\ShouldQueue;
 use Illuminate\Queue\InteractsWithQueue;
@@ -37,10 +38,13 @@ class UpdateOrderPackageExceptionListener implements ShouldQueue
             default:
                 $status = '无';
         }
-        OrderPackage::query()->whereIn('id', $event->orderPackageIds)->update([
+        $orderPackageIds = $event->orderPackageIds;
+        OrderPackage::query()->whereIn('id', $orderPackageIds)->update([
             'exception_type' => '无',
             'exception' => '否',
             'status' => $status,
         ]);
+        //更新统计数据
+        event(new UpdateOrderPackageExceptionListenerEvent($orderPackageIds));
     }
 }

+ 42 - 0
app/Listeners/UpdateOrderPackageExceptionTypeCountingRecordListener.php

@@ -0,0 +1,42 @@
+<?php
+
+namespace App\Listeners;
+
+use App\Events\UpdateOrderPackageExceptionListenerEvent;
+use App\OrderPackage;
+use App\Services\OrderPackageExceptionTypeCountingRecordService;
+use Illuminate\Contracts\Queue\ShouldQueue;
+use Illuminate\Queue\InteractsWithQueue;
+use Illuminate\Support\Facades\DB;
+
+class UpdateOrderPackageExceptionTypeCountingRecordListener implements ShouldQueue
+{
+    /**
+     * Create the event listener.
+     *
+     * @return void
+     */
+    public function __construct()
+    {
+        //
+    }
+
+    /**
+     * Handle the event.
+     *
+     * @param UpdateOrderPackageExceptionListenerEvent $event
+     * @return void
+     */
+    public function handle(UpdateOrderPackageExceptionListenerEvent $event)
+    {
+        $order_package_ids = $event->order_package_ids;
+        $dates = OrderPackage::query()->select(DB::raw("DATE_FORMAT( sent_at, '%Y-%m-%d' ) AS sent_at_date "))->whereIn('id', $order_package_ids)->get();
+        /**
+         * @var $service OrderPackageExceptionTypeCountingRecordService
+         */
+        $service = app('OrderPackageExceptionTypeCountingRecordService');
+        foreach ($dates as $date) {
+            $service->updateOrCreateByDate($date->sent_at_date);
+        }
+    }
+}

+ 5 - 0
app/OracleDOCOrderHeader.php

@@ -9,6 +9,7 @@ use App\Traits\ModelTimeFormat;
 use Illuminate\Database\Eloquent\Model;
 
 use App\Traits\ModelLogChanging;
+use Illuminate\Database\Eloquent\Relations\BelongsTo;
 
 class OracleDOCOrderHeader extends Model
 {
@@ -66,6 +67,10 @@ class OracleDOCOrderHeader extends Model
         return $this->hasOne('App\OracleBasCode','code','ordertype')->where('codeid','SO_TYP');
     }
 
+    public function oracleDOCWaveDetail(): BelongsTo
+    {
+        return $this->belongsTo(OracleDOCWaveDetails::class,'orderno','orderno');
+    }
     public function getLogistic()
     {
         /** @var LogisticService $logistic_service */

+ 17 - 0
app/OrderPackageExceptionTypeCountingRecord.php

@@ -0,0 +1,17 @@
+<?php
+
+namespace App;
+
+use Illuminate\Database\Eloquent\Model;
+
+use App\Traits\ModelLogChanging;
+
+class OrderPackageExceptionTypeCountingRecord extends Model
+{
+    use ModelLogChanging;
+    public $timestamps = false;
+
+
+    //
+    public $fillable = ["sent_at_date", 'exception_type', 'exception_type_count', 'owner_id',];
+}

+ 4 - 0
app/Providers/AppServiceProvider.php

@@ -111,6 +111,8 @@ use Ramsey\Uuid\Uuid;
 use Illuminate\Support\Facades\Validator;
 use App\Services\SupplierService;
 use App\Services\OrderPackageCommoditySerialNumberService;
+use App\Services\OrderPackageExceptionTypeCountingRecordService;
+use App\Services\LogisticYDService;
 
 class AppServiceProvider extends ServiceProvider
 {
@@ -184,6 +186,7 @@ class AppServiceProvider extends ServiceProvider
         app()->singleton('LaborReportsCountingRecordService',LaborReportsCountingRecordService::class);
         app()->singleton('LogService',LogService::class);
         app()->singleton('LogisticService',LogisticService::class);
+        app()->singleton('LogisticYDService',LogisticYDService::class);
         app()->singleton('MaterialBoxService',MaterialBoxService::class);
         app()->singleton('OracleActAllocationDetailService',OracleActAllocationDetailService::class);
         app()->singleton('OracleBasCustomerService',OracleBasCustomerService::class);
@@ -201,6 +204,7 @@ class AppServiceProvider extends ServiceProvider
         app()->singleton('OrderIssueWorkLoadService',OrderIssueWorkLoadService::class);
         app()->singleton('OrderPackageCommoditiesService',OrderPackageCommoditiesService::class);
         app()->singleton('OrderPackageCommoditySerialNumberService',OrderPackageCommoditySerialNumberService::class);
+        app()->singleton('OrderPackageExceptionTypeCountingRecordService',OrderPackageExceptionTypeCountingRecordService::class);
         app()->singleton('OrderPackageReceivedSyncService',OrderPackageReceivedSyncService::class);
         app()->singleton('OrderPackageService',OrderPackageService::class);
         app()->singleton('OrderService',OrderService::class);

+ 0 - 1
app/Providers/AuthServiceProvider.php

@@ -40,7 +40,6 @@ class AuthServiceProvider extends ServiceProvider
     public function boot()
     {
         $this->registerPolicies();
-
         $isSuperAdmin = null;
         if(!Schema::hasTable('users')){return;}
         /** @var CacheService $cacheService */

+ 7 - 4
app/Providers/EventServiceProvider.php

@@ -35,11 +35,14 @@ class EventServiceProvider extends ServiceProvider
         'App\Events\SendEmailEvent' => [
             'App\Listeners\SendEmailListener'
         ],
-        'App\Events\AddOrUpdateOrderIssues' => [
-            'App\Listeners\AddOrUpdateOrderIssuesListener',
+        'App\Events\AddOrUpdateOrderIssues' => [//问题件新增或更新
+            'App\Listeners\AddOrUpdateOrderIssuesListener',//将对应的order_packages的数据的异常装变更
         ],
-        'App\Events\OrderIssueProcessLogCreateEvent' => [
-            'App\Listeners\UpdateOrderPackageExceptionListener',
+        'App\Events\OrderIssueProcessLogCreateEvent' => [//orderIssue增添日志时
+            'App\Listeners\UpdateOrderPackageExceptionListener',//将对应的order_packages的数据的异常装变更为无
+        ],
+        'App\Events\UpdateOrderPackageExceptionListenerEvent' => [//order_packages的数据的异常数据变更时
+            'App\Listeners\UpdateOrderPackageExceptionTypeCountingRecordListener',//更新OrderPackageExceptionTypeCountingRecord的统计信息
         ],
     ];
 

+ 210 - 60
app/Services/CacheShelfService.php

@@ -2,47 +2,63 @@
 
 namespace App\Services;
 
+use App\Events\BroadcastToStation;
 use App\Exceptions\ErrorException;
 use App\MaterialBox;
 use App\Station;
-use App\StationCacheShelfGrid;
+use App\StationTask;
 use App\StationTaskMaterialBox;
+use App\StationType;
 use App\Traits\ServiceAppAop;
 use Illuminate\Support\Facades\Http;
+use Illuminate\Database\Eloquent\Builder;
+use Illuminate\Database\Eloquent\Collection;
 
-class CacheShelfService
+class   CacheShelfService
 {
     use ServiceAppAop;
 
     protected $modelClass = Station::class;
+
+    /** @var StationService $stationService */
+    private $stationService;
     /** @var StationTaskMaterialBoxService $stationTaskMaterialBoxService */
     private $stationTaskMaterialBoxService;
-    /** @var StationCacheShelfGridService $stationCacheShelfGridService */
-    private $stationCacheShelfGridService;
     /** @var ForeignHaiRoboticsService $foreignHaiRoboticsService */
     private $foreignHaiRoboticsService;
+    /** @var StationTaskService $stationTaskService */
+    private $stationTaskService;
+    /** @var StationTaskChildService $stationTaskChildService */
+    private $stationTaskChildService;
 
     /**
-     * 获取现有的缓存架任务
-     * @param Station $station
+     * 获取缓存架上子货架当前任务
+     * @param $id
+     * @return Builder[]|Collection
      */
-    public function getTasks(Station $station)
+    public function getChildStation($id)
     {
-        $grids = StationCacheShelfGrid::query()->with('materialBox')->where('station_id', $station['id'])->where('status', 1)->orderBy('grid_id')->get();
-        $station->setRelation('grids', $grids);
+        return Station::query()->where('parent_id',$id)->with('parent','pendingStationTask.stationTaskMaterialBoxes.materialBox')->get();
     }
 
+
+    /**
+     * 拍灯触发任务
+     * @param $locCode
+     * @param $PTLAction
+     * @return array|bool[]
+     */
     public function lightOffTask($locCode, $PTLAction): array
     {
-        $this->instant($this->stationCacheShelfGridService, 'StationCacheShelfGridService');
-        list($stationCode, $gridId, $row, $col) = StationCacheShelfGrid::getGridByCode($locCode);
-        $station = Station::query()->where('code', $stationCode)->first();
-        $grid = StationCacheShelfGrid::query()->where('station_id', $station['id'])->where('grid_id', $gridId)->first();
-        $materialBox = MaterialBox::query()->where('id', $grid['material_box_id'])->first();
+        $station = Station::query()->where('code', $locCode)->first();
         try {
-            $bool = $this->putBinToStore($station, $materialBox, $grid);                    // 推送任务
-            if($bool)$this->stationCacheShelfGridService->lightOff($locCode, $PTLAction);    // 灭灯广播
-            return ['success' => $bool];
+            $bool = $this->putBinToStore($station);                         // 推送任务
+            if($bool){
+                LogService::log(__CLASS__,'lightOffTask','code' .' true'. $locCode.json_encode($station));
+                return ['success' => true];
+            }else{
+                return ['success' => false,'errMsg' => '机器人推送失败'];
+            }
         } catch (ErrorException $e) {
             LogService::log(__FUNCTION__,'缓存架推送任务失败',json_encode($e->getMessage()));
             return ['success' => false,'errMsg' => $e->getMessage()];
@@ -50,59 +66,193 @@ class CacheShelfService
     }
 
     /**
-     * 推任务
+     * 推任务至海柔机器人
      * @param  $station
-     * @param  $materialBox
-     * @param  $grid
      * @return bool
      * @throws ErrorException
      */
-    public function putBinToStore($station, $materialBox, $grid): bool
+    public function putBinToStore($station): bool
     {
         $this->instant($this->stationTaskMaterialBoxService, 'StationTaskMaterialBoxService');
-        $this->instant($this->stationCacheShelfGridService, 'StationCacheShelfGridService');
         $this->instant($this->foreignHaiRoboticsService, 'ForeignHaiRoboticsService');
+        $this->instant($this->stationService, 'StationService');
+        $this->instant($this->stationTaskService, 'StationTaskService');
+        $this->instant($this->stationTaskChildService, 'StationTaskChildService');
+
+        /** @var StationTaskMaterialBox $takeStationTaskMaterialBox */
+        $takeStationTaskMaterialBox = $station['pendingStationTask']['stationTaskMaterialBoxes']->first();
+
+        $formStation = $this->stationService->getStation_byType('立库');
+
+        // 创建入立库任务
+        $stationTask = $this->stationTaskService->create(1);               // 生成站任务
+        $this->stationTaskService->registerStations($stationTask,[$formStation['id']]);   // 注册站任务站
+        /** @var StationTaskMaterialBox $putStationTaskMaterialBox */
+        $putStationTaskMaterialBox = $this->stationTaskMaterialBoxService->create([
+            'station_id' => $formStation['id'],
+            'material_box_id' => $takeStationTaskMaterialBox['material_box_id'],
+            'status' => '待处理',
+        ]);
+        $putStationTaskMaterialBox['station_task_id'] = $stationTask->first()['id'];
+        $putStationTaskMaterialBox['type'] = '放';
+        $putStationTaskMaterialBox->update();
+
+        $params = [[
+            'station_task_id'=>$stationTask->first()['id'],
+            'station_taskable_type'=>StationTaskMaterialBox::class,
+            'station_taskable_id'=>$putStationTaskMaterialBox['id']
+        ]];
+
+        $this->stationTaskChildService->insert($params);    // 任务任务注册
+        // 标记站任务为处理中
+        $this->stationTaskMaterialBoxService->set($takeStationTaskMaterialBox,[
+            'status' => '处理中'
+        ]);
+
+        // 推立库任务
+        return $this->foreignHaiRoboticsService->putBinToStore_fromCacheShelf($putStationTaskMaterialBox,$station['code']);
+    }
 
-        /** @var StationTaskMaterialBox $stationTaskMaterialBox */
-        $stationTaskMaterialBox = $this->stationTaskMaterialBoxService->createByStationAndMaterialBox($station, $materialBox);
-        $this->stationCacheShelfGridService->processGrid($grid, $station, $materialBox);
+    /**
+     * 创建站任务和料箱任务
+     * @param $stationCode
+     * @param $materialBoxCode
+     * @return array
+     */
+    public function createStationTask($stationCode,$materialBoxCode): array
+    {
+        $this->instant($this->stationTaskService, 'StationTaskService');
+        $this->instant($this->stationTaskMaterialBoxService,'StationTaskMaterialBoxService');
+        $this->instant($this->stationTaskChildService,'StationTaskChildService');
 
-        $station->setRelation('grids', $grid);
-        $stationTaskMaterialBox->setRelation('station', $station);
-        $stationTaskMaterialBox->setRelation('materialBox', $materialBox);
+        $station = Station::query()->where('code' , $stationCode)->first();
+        if(!$station){
+            $arr = [];
+            preg_match('/^HAI([\w]+)/',$stationCode,$arr);
+            $parentCode = $arr[1] ?? '';
+            $stationType = StationType::query()->where('name','缓存架')->first();
+            $parentStation = Station::query()->firstOrCreate(['code'=>$parentCode],['station_type_id'=>$stationType['id']]);
+            $station = Station::query()->firstOrCreate(['code' => $stationCode,'parent_id'=>$parentStation['id']],['name'=>$stationCode,'station_type_id' => $stationType['id']]);
+        }
+
+        $materialBox = MaterialBox::query()->firstOrCreate(['code' => $materialBoxCode]);
 
-        return $this->foreignHaiRoboticsService->putBinToStore_fromCacheShelf($stationTaskMaterialBox);
+        if($station['pendingStationTask'] ?? false){
+            return ['success' => false,'message' => '当前已有未完成的站任务'];
+        }
+        $stationTask = $this->stationTaskService->create(1);                                                    // 生成站任务
+        $stationTaskMaterialBox = $this->stationTaskMaterialBoxService->createByStationAndMaterialBox($station,$materialBox);     // 创建料箱任务
+        $this->stationTaskService->registerStations($stationTask,[$station['id']]);                                            // 注册站任务站
+        $stationTaskMaterialBox['station_task_id'] = $stationTask->first()['id'];
+        $stationTaskMaterialBox->update();
+        $params = [[
+                'station_task_id'=>$stationTask->first()['id'],
+                'station_taskable_type'=>StationTaskMaterialBox::class,
+                'station_taskable_id'=>$stationTaskMaterialBox['id']
+            ]];
+        $this->stationTaskChildService->insert($params);                                                                        // 任务任务注册
+
+        $body = $this->_stationCacheLightOn($stationCode,$materialBoxCode);
+
+        if($body->code == 200)return ['success'=>true];
+        return ['success' => false,'message' => '机器人亮灯异常'];
     }
 
-//    /**
-//     * 入库任务完成
-//     * @param $params
-//     */
-//    public function putBinToStoreFinish($params)
-//    {
-//        $this->instant($this->stationTaskMaterialBoxService,'StationTaskMaterialBoxService');
-//
-//        $locCode = $params['locCode'];
-//
-//        list($stationCode, $gridId) = StationCacheShelfGrid::getGridByCode($locCode);
-//        $station = Station::query()->where('code', $stationCode)->first();
-//
-//        $stationCacheShelfGrid = StationCacheShelfGrid::query()->with('materialBox')->where('station_id', $station)->where('grid_id', $gridId)->first();
-//        $stationCacheShelfGrid->update(['status' => '0', 'material_box_id' => null]);
-//
-//        $StationTaskMaterialBox = StationTaskMaterialBox::query()->where('station_id', $station['id'])->where('material_box_id', $stationCacheShelfGrid['$stationCacheShelfGrid'])->first();
-//        $this->stationTaskMaterialBoxService->set($StationTaskMaterialBox, ['status' => '已完成']);
-//    }
-
-//    /**
-//     * 取消格口任务
-//     * @param Station $station
-//     * @param array $girds
-//     */
-//    public function cancelTask(Station $station, array $girds = [])
-//    {
-//        $gridQuery = StationCacheShelfGrid::query()->where('station_id', $station['id']);
-//        if (count($girds) > 0) $gridQuery->whereIn('grid_id', $girds);
-//        $this->stationCacheShelfGridService->cancelTask($gridQuery->get());
-//    }
+    /**
+     * 控制格口亮灯
+     * @param $locCode
+     * @param string $title
+     * @param null $materialCode
+     * @return mixed
+     */
+    public function _stationCacheLightOn($locCode,$materialCode = null,$title = 'title')
+    {
+        $params = [
+            "areaCode" => "1004",
+            'locCode' => $locCode,
+            'PTLAction' => 1,
+            'PTLSettings' => [
+                'color'=> 1,
+                'frequency'  =>1
+                ],
+            "displayInfo" => [
+                "detail01" => $materialCode,
+                "detail02" => "detail02",
+                "detail03" => "detail03",
+                "qrCode" => "qrCode",
+                "qty00" => "11",
+                "qty01" => 1,
+                "qty02" => 2,
+                "title" => $title,
+                "uomDesc01" => "uo",
+                "uomDesc02" => "uo"
+            ],
+        ];
+        $response = Http::post(config('api.haiq.storage.light'), $params);
+        return json_decode($response->body());
+    }
+
+    /**
+     * 控制格口灭灯
+     * @param $locCode
+     * @return mixed
+     */
+    public function _stationCacheLightOff($locCode){
+        if(!$locCode)return null;
+        $params = [
+            "areaCode" => "1004",
+            'locCode' => $locCode,
+            'PTLAction' => 0,
+        ];
+        $response = Http::post(config('api.haiq.storage.light'), $params);
+        return json_decode($response->body());
+    }
+
+    /**
+     * 广播 通知货物被取走
+     * @param $locCode
+     * @param $PTLAction
+     */
+    public function _stationCacheBroadCast($locCode,$PTLAction)
+    {
+        if($PTLAction == 0){
+            $station = Station::query()->with('parent')->where('code',$locCode)->first();
+
+            $json = json_encode( [
+                'station_id' => $station['parent']['id'],
+                'code'  => $station['parent']['code'],
+                'gird_id' => $station['id'],
+                'grid_code' => $station['code'],
+            ]);
+            broadcast(new BroadcastToStation($station['parent_id'],$json));
+        }
+    }
+
+    /**
+     * 根据立库任务完成 缓存架任务 和 入立架任务
+     * @param StationTaskMaterialBox $putStationTaskMaterial
+     */
+    public function putStationTaskMaterialBoxProcess(StationTaskMaterialBox $putStationTaskMaterial)
+    {
+        $this->instant($this->stationTaskMaterialBoxService,'StationTaskMaterialBoxService');
+
+        $takeStationTaskMaterialBox = StationTaskMaterialBox::query()->with('station','stationTask')->where('material_box_id',$putStationTaskMaterial['material_box_id'])->whereIn('station_id',function($query){
+            $query->from('stations')->selectRaw('id')->whereIn('station_type_id',function($query){
+                $query->from('station_types')->selectRaw('id')->where('name','缓存架');
+            });
+        })->where('status','处理中')->first();
+
+        if(!$takeStationTaskMaterialBox)return ;
+        $this->stationTaskMaterialBoxService->set($takeStationTaskMaterialBox, [
+            'status' => '完成'
+        ]);
+
+        // 缓存架任务
+        if($takeStationTaskMaterialBox->stationTask)$takeStationTaskMaterialBox->stationTask->update(['status' => '完成']);
+        // 入立架任务
+        if($putStationTaskMaterial->stationTask)$putStationTaskMaterial->stationTask->update(['status' => '完成']);
+
+        $this->_stationCacheLightOff($takeStationTaskMaterialBox->station->code ?? null);
+        $this->_stationCacheBroadCast($takeStationTaskMaterialBox->station->code,0);
+    }
 }

+ 1 - 1
app/Services/CityService.php

@@ -34,7 +34,7 @@ class CityService
         if(isset($city))return $city;
         if(!$name)return null;
         foreach (CityService::$cities as $city) {
-            if(strstr($city,$name) != null){
+            if(strstr($city,$name) != null || strstr($name,$city)){
                return City::query()->where('name','like',$city.'%')->first();
             }
         }

+ 10 - 15
app/Services/ForeignHaiRoboticsService.php

@@ -13,6 +13,7 @@ use Illuminate\Support\Collection;
 use Illuminate\Support\Facades\DB;
 use Illuminate\Support\Facades\Http;
 use App\Traits\ServiceAppAop;
+use Illuminate\Support\Facades\Log;
 
 
 class ForeignHaiRoboticsService
@@ -257,45 +258,39 @@ class ForeignHaiRoboticsService
         LogService::log('海柔请求','putBinToStore3',
             json_encode($dataToPost));
         $controlSuccess = $this->controlHaiRobot($dataToPost);
-        if($controlSuccess){
-        }
+
         return $controlSuccess;
     }
 
     /** 缓存架入立架 料箱 任务
      * @param StationTaskMaterialBox|null $stationTaskMaterialBox
+     * @param string|null $formLocation
      * @return bool
      * @throws ErrorException
      */
-    public function putBinToStore_fromCacheShelf(?StationTaskMaterialBox $stationTaskMaterialBox): bool
+    public function putBinToStore_fromCacheShelf(?StationTaskMaterialBox $stationTaskMaterialBox,
+                                                 string $formLocation): bool
     {
         LogService::log('海柔请求','putBinToStore_fromCacheShelf1', '');
         LogService::log('海柔请求','putBinToStore_fromCacheShelf2', json_encode($stationTaskMaterialBox));
 
-        $this->instant($this->stationService,'StationService');
-
-        // 缓存架格口
-        $formLocation = StationCacheShelfGrid::getLocation($stationTaskMaterialBox['station'],$stationTaskMaterialBox['station']['grids']->first());
-
-        /** 创建料箱 从缓存架 到 立架任务 */
         $dataToPost=$this->makeJson_move(
             collect([$stationTaskMaterialBox]),
             '缓存架入立架',
-            $formLocation,              //TODO:通过计算StationCacheShelfGrid 的 Grid_id 获取格口的编号
+            $formLocation,
             ''
         );
-
         LogService::log('海柔请求','putBinToStore_fromCacheShelf3', json_encode($dataToPost));
 
-        /** 控制海柔机器人执行任务 */
         $controlSuccess = $this->controlHaiRobot($dataToPost);
+        LogService::log('海柔请求','putBinToStore_fromCacheShelf4', 'controlHaiRobot '. json_encode($controlSuccess));
+
         if($controlSuccess){
             $this->instant($this->stationTaskMaterialBoxService,'StationTaskMaterialBoxService');
             $this->stationTaskMaterialBoxService->set($stationTaskMaterialBox,[
-                'id' => $stationTaskMaterialBox['id'],
-                'status' => $stationTaskMaterialBox['status']='处理中',
-                'station_id' => $stationTaskMaterialBox['station']['id']?? '',
+                'status' => '处理中',
             ]);
+            LogService::log('海柔请求','putBinToStore_fromCacheShelf5', 'controlHaiRobot '. json_encode($stationTaskMaterialBox));
         }
         return $controlSuccess;
     }

+ 134 - 120
app/Services/LogisticSFService.php

@@ -101,7 +101,10 @@ xml;
             $data = $this->switchOpCodeToStatus($lastRoute, $data);
             $data['transfer_status'] = $this->transformRoutes($routeResponse['Route']);
             if (!array_key_exists('exception', $data)) {//当顺丰返回异常时,不需要再根据时间判断是否异常,直接用顺丰的异常就好
-                $data = $this->setExceptionType($data, $lastRoute['accept_time']);
+                $orderPackageReceivedSyncService = app('OrderPackageReceivedSyncService');
+                $exceptionData = $orderPackageReceivedSyncService->setExceptionType($data, array_key_exists('accept_time',$lastRoute) ? $lastRoute['accept_time'] : null);
+                $data['exception_type'] = $exceptionData['exception_type'];
+                $data['exception'] = $exceptionData['exception'];
             }
             //如果没有发现额外的异常,且查询到物流轨迹,将异常置为无
             if (!array_key_exists('exception', $data)
@@ -114,18 +117,22 @@ xml;
         } catch (Exception $e) {
             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;
         }
     }
 
     /**
      * 转换快递路由信息
-     * @param array $routs 快递路由
+     * @param  $routs 快递路由
      * @return array
      */
-    public function transformRoutes(array $routs): array
+    public function transformRoutes($routs): array
     {
         $result = [];
+        if (!is_array($routs)) {
+            $routs = [$routs];
+        }
         foreach ($routs as $route) {
             $route = get_object_vars($route)['@attributes'];
             $data['accept_time'] = $route['accept_time'];
@@ -155,7 +162,6 @@ xml;
                 case 36:
                     $data['status'] = '在途';
                     break;
-                case 70:
                 case 33:
                     $data['status'] = '派送异常';
                     $data['exception_type'] = '派件异常';
@@ -178,6 +184,11 @@ xml;
                 case 99:
                     $data['status'] = '返回中';
                     break;
+                case 70:
+                    $data['status'] = '无';
+                    $data['exception'] = '是';
+                    $data['exception_type'] = '其他';
+                    break;
                 default:
                     throw new WarningException("未知的丰桥状态码: {$lastRoute['opcode']}->{json_encode($lastRoute)}");
             }
@@ -225,120 +236,123 @@ xml;
     }
 
 
-    /**
-     * @param array $data
-     * @param $lastRouteDate
-     * @return array
-     */
-    private function setExceptionType(array $data, $lastRouteDate = null): array
-    {
-        $logistic_number = $data['logistic_number'];
-        /** @var OrderPackage $orderPackage */
-        $orderPackage = OrderPackage::query()->with('order')->where('logistic_number', $logistic_number)->first();
-        $delivered_duration = now()->diffInHours(Carbon::parse($orderPackage['sent_at']));
-        $last_routed_duration = now()->diffInHours(Carbon::parse($lastRouteDate));
-        $VALID_HOURS = 4;
-        $SHORT_RESPONSE_HOURS = 24;
-        $LONG_RESPONSE_HOURS = (function ($province) {
-            switch ($province) {
-                case '浙江省':
-                case '江苏省':
-                case '上海':
-                case '安徽省':
-                    return 72;
-                case '北京':
-                case '天津':
-                case '江西省':
-                case '湖北省':
-                case '湖南省':
-                case '广东省':
-                case '福建省':
-                case '山东省':
-                case '河北省':
-                case '河南省':
-                case '山西省':
-                case '四川省':
-                case '陕西省':
-                case '重庆':
-                case '广西壮族自治区':
-                case '贵州省':
-                case '云南省':
-                case '海南省':
-                case '吉林省':
-                case '黑龙江省':
-                case '辽宁省':
-                    return 120;
-                case '青海省':
-                case '宁夏回族自治区':
-                case '甘肃省':
-                case '内蒙古自治区':
-                case '新疆维吾尔自治区':
-                case '西藏自治区':
-                    return 168;
-                default:
-                    break;
-            }
-        })($orderPackage->order->province);
-        $SENDING_RESPONSE_HOURS = 48;
-        $IS_ROUTED = 1;               //0000 0001 有路由信息
-        $IS_IN_VALID_TIME = 2;        //0000 0010 大于4小时
-        $IS_WEIGHED = 4;              //0000 0100 称重过
-        $IS_RECEIVED = 8;          //0000 1000 已经收货
-        $IS_SENDING = 16;             //0001 0000 正在派送
-        $IS_SHORT_NO_RESPONSE = 32;     //0010 0000 中转异常
-        $IS_LONG_NO_RESPONSE = 64;     //0010 0000 疑似丢件
-        $IS_SENDING_NO_RESPONSE = 128;     //0010 0000 派送异常
-        $conclusion = (function () use (
-            $data, $delivered_duration, $last_routed_duration,
-            $VALID_HOURS, $IS_ROUTED, $IS_IN_VALID_TIME, $IS_WEIGHED, $IS_RECEIVED, $IS_SENDING, $IS_SHORT_NO_RESPONSE, $IS_LONG_NO_RESPONSE, $IS_SENDING_NO_RESPONSE,
-            $SHORT_RESPONSE_HOURS, $LONG_RESPONSE_HOURS, $SENDING_RESPONSE_HOURS,
-            $orderPackage
-        ) {
-            $conclusion = 0;
-            $conclusion |= !empty($data['transfer_status']) ? $IS_ROUTED : 0;
-            $conclusion |= ($delivered_duration > $VALID_HOURS) ? $IS_IN_VALID_TIME : 0;
-            $conclusion |= ($orderPackage->weighed_at) ? $IS_WEIGHED : 0;
-            $conclusion |= ($data['status'] == '已收件') ? $IS_RECEIVED : 0;
-            $conclusion |= ($data['status'] == '派送中') ? $IS_SENDING : 0;//
-            $conclusion |= ($last_routed_duration > $SHORT_RESPONSE_HOURS && $last_routed_duration < $LONG_RESPONSE_HOURS) ? $IS_SHORT_NO_RESPONSE : 0;
-            $conclusion |= ($last_routed_duration > $LONG_RESPONSE_HOURS) ? $IS_LONG_NO_RESPONSE : 0;
-            $conclusion |= ($last_routed_duration > $SENDING_RESPONSE_HOURS && $data['status'] == '派送中') ? $IS_SENDING_NO_RESPONSE : 0;
-            return $conclusion;
-        })();
-        switch ($conclusion) {
-            case $IS_IN_VALID_TIME:
-                $data['exception_type'] = '疑似库内丢件';
-                break;
-            case $IS_IN_VALID_TIME | $IS_WEIGHED:
-                $data['exception_type'] = '揽件异常';
-                break;
-            case $IS_ROUTED | $IS_IN_VALID_TIME | $IS_SHORT_NO_RESPONSE:
-            case $IS_ROUTED | $IS_IN_VALID_TIME | $IS_SHORT_NO_RESPONSE | $IS_WEIGHED:
-                $data['exception_type'] = '中转异常';
-                break;
-            case $IS_ROUTED | $IS_IN_VALID_TIME | $IS_LONG_NO_RESPONSE:
-            case $IS_ROUTED | $IS_IN_VALID_TIME | $IS_LONG_NO_RESPONSE | $IS_WEIGHED:
-                $data['exception_type'] = '疑似丢件';
-                break;
-            default:
-                break;
-        }
-
-        if($conclusion
-            ==($conclusion | $IS_ROUTED | $IS_IN_VALID_TIME | $IS_SENDING | $IS_SENDING_NO_RESPONSE)){
-            $data['exception_type'] = '派件异常';
-        }
-
-        switch ($conclusion) {
-            case $IS_IN_VALID_TIME:
-            case $IS_IN_VALID_TIME | $IS_WEIGHED:
-            case $IS_ROUTED | $IS_SHORT_NO_RESPONSE:
-            case $IS_LONG_NO_RESPONSE:
-                $data['exception'] = '是';
-                break;
-            default:
-                break;
-        }
-        return $data;
-    }
+//    /**
+//     * @param array $data
+//     * @param $lastRouteDate
+//     * @return array
+//     */
+//    private function setExceptionType(array $data, $lastRouteDate): array
+//    {
+//        $logistic_number = $data['logistic_number'];
+//        /** @var OrderPackage $orderPackage */
+//        $orderPackage = OrderPackage::query()->with('order')->where('logistic_number', $logistic_number)->first();
+//        $delivered_duration = now()->diffInHours(Carbon::parse($orderPackage['sent_at']));
+//        $last_routed_duration = now()->diffInHours(Carbon::parse($lastRouteDate));
+//        $VALID_HOURS = 4;
+//        $SHORT_RESPONSE_HOURS = 24;
+//        $LONG_RESPONSE_HOURS = (function ($province) {
+//            switch ($province) {
+//                case '浙江省':
+//                case '江苏省':
+//                case '上海':
+//                case '安徽省':
+//                    return 72;
+//                case '北京':
+//                case '天津':
+//                case '江西省':
+//                case '湖北省':
+//                case '湖南省':
+//                case '广东省':
+//                case '福建省':
+//                case '山东省':
+//                case '河北省':
+//                case '河南省':
+//                case '山西省':
+//                case '四川省':
+//                case '陕西省':
+//                case '重庆':
+//                case '广西壮族自治区':
+//                case '贵州省':
+//                case '云南省':
+//                case '海南省':
+//                case '吉林省':
+//                case '黑龙江省':
+//                case '辽宁省':
+//                    return 120;
+//                case '青海省':
+//                case '宁夏回族自治区':
+//                case '甘肃省':
+//                case '内蒙古自治区':
+//                case '新疆维吾尔自治区':
+//                case '西藏自治区':
+//                    return 168;
+//                default:
+//                    break;
+//            }
+//        })($orderPackage->order->province);
+//        $SENDING_RESPONSE_HOURS = 48;
+//        $IS_ROUTED = 1;               //0000 0001 有路由信息
+//        $IS_IN_VALID_TIME = 2;        //0000 0010 大于4小时
+//        $IS_WEIGHED = 4;              //0000 0100 称重过
+//        $IS_RECEIVED = 8;          //0000 1000 已经收货
+//        $IS_SENDING = 16;             //0001 0000 正在派送
+//        $IS_SHORT_NO_RESPONSE = 32;     //0010 0000 中转异常
+//        $IS_LONG_NO_RESPONSE = 64;     //0010 0000 疑似丢件
+//        $IS_SENDING_NO_RESPONSE = 128;     //0010 0000 派送异常
+//        $conclusion = (function () use (
+//            $data, $delivered_duration, $last_routed_duration,
+//            $VALID_HOURS, $IS_ROUTED, $IS_IN_VALID_TIME, $IS_WEIGHED, $IS_RECEIVED, $IS_SENDING, $IS_SHORT_NO_RESPONSE, $IS_LONG_NO_RESPONSE, $IS_SENDING_NO_RESPONSE,
+//            $SHORT_RESPONSE_HOURS, $LONG_RESPONSE_HOURS, $SENDING_RESPONSE_HOURS,
+//            $orderPackage
+//        ) {
+//            $conclusion = 0;
+//            $conclusion |= !empty($data['transfer_status']) ? $IS_ROUTED : 0;
+//            $conclusion |= ($delivered_duration > $VALID_HOURS) ? $IS_IN_VALID_TIME : 0;
+//            $conclusion |= ($orderPackage->weighed_at) ? $IS_WEIGHED : 0;
+//            $conclusion |= ($data['status'] == '已收件') ? $IS_RECEIVED : 0;
+//            $conclusion |= ($data['status'] == '派送中') ? $IS_SENDING : 0;//
+//            $conclusion |= ($last_routed_duration > $SHORT_RESPONSE_HOURS && $last_routed_duration < $LONG_RESPONSE_HOURS) ? $IS_SHORT_NO_RESPONSE : 0;
+//            $conclusion |= ($last_routed_duration > $LONG_RESPONSE_HOURS) ? $IS_LONG_NO_RESPONSE : 0;
+//            $conclusion |= ($last_routed_duration > $SENDING_RESPONSE_HOURS && $data['status'] == '派送中') ? $IS_SENDING_NO_RESPONSE : 0;
+//            return $conclusion;
+//        })();
+//        switch ($conclusion) {
+//            case $IS_IN_VALID_TIME:
+//                $data['exception_type'] = '疑似库内丢件';
+//                break;
+//            case $IS_IN_VALID_TIME | $IS_WEIGHED:
+//                $data['exception_type'] = '揽件异常';
+//                break;
+//            case $IS_ROUTED | $IS_IN_VALID_TIME | $IS_SHORT_NO_RESPONSE:
+//            case $IS_ROUTED | $IS_IN_VALID_TIME | $IS_SHORT_NO_RESPONSE | $IS_WEIGHED:
+//                $data['exception_type'] = '中转异常';
+//                break;
+//            case $IS_ROUTED | $IS_IN_VALID_TIME | $IS_LONG_NO_RESPONSE:
+//            case $IS_ROUTED | $IS_IN_VALID_TIME | $IS_LONG_NO_RESPONSE | $IS_WEIGHED:
+//                $data['exception_type'] = '疑似丢件';
+//                break;
+//            default:
+//                break;
+//        }
+//
+//        if($conclusion
+//            ==($conclusion | $IS_ROUTED | $IS_IN_VALID_TIME | $IS_SENDING | $IS_SENDING_NO_RESPONSE)){
+//            $data['exception_type'] = '派件异常';
+//        }
+//
+//        switch ($conclusion) {
+//            case $IS_IN_VALID_TIME:
+//            case $IS_IN_VALID_TIME | $IS_WEIGHED:
+//            case $IS_ROUTED | $IS_SHORT_NO_RESPONSE:
+//            case $IS_LONG_NO_RESPONSE:
+//                $data['exception'] = '是';
+//                break;
+//            default:
+//                break;
+//        }
+//        return [
+//            'exception_type' => array_key_exists('exception_type', $data) ? $data['exception_type'] : null,
+//            'exception' => array_key_exists('exception', $data) ? $data['exception'] : null,
+//        ];
+//    }
 }

+ 178 - 0
app/Services/LogisticYDService.php

@@ -0,0 +1,178 @@
+<?php
+
+namespace App\Services;
+
+use App\OrderPackage;
+use App\Traits\ServiceAppAop;
+use Carbon\Carbon;
+use Illuminate\Support\Facades\Http;
+
+class LogisticYDService
+{
+    use ServiceAppAop;
+
+    private $app_key;
+    private $app_secret;
+    private $url;
+
+
+    /**
+     * 批量订阅接口
+     * @param $logistic_numbers array
+     * @return mixed
+     */
+    public function registerApi(array $logistic_numbers)
+    {
+        $this->app_key = config('api_logistic.YD.prod.app-key', '999999');
+        $this->app_secret = config('api_logistic.YD.prod.app-secret', '04d4ad40eeec11e9bad2d962f53dda9d');
+        $this->url = config('api_logistic.YD.prod.register.url');
+        $sender = [
+            "address" => "上海市松江区泗泾镇泗砖公路351号",
+            "city" => "上海市",
+            "county" => "松江区",
+            "name" => "施尧",
+            "phone" => '13761413262',
+            "province" => "上海市"
+        ];
+        $body = [
+            "orders" => [],
+        ];
+        $order_packages = OrderPackage::query()
+            ->with('order')
+            ->whereIn('logistic_number', $logistic_numbers)->get();
+        foreach ($order_packages as $order_package) {
+            $order = $order_package->order;
+            $body['orders'][] = [
+                'orderid' => $order->client_code,
+                "mailno" => $order_package->logistic_number,
+                "receiver" => [
+                    "address" => $order->address,
+                    "city" => $order->city,
+                    "county" => $order->district,
+                    "name" => $order->consignee_name,
+                    "phone" => $order->consignee_phone,
+                    "province" => $order->province
+                ],
+                "sender" => $sender
+            ];
+        }
+        $json_body = json_encode($body, JSON_UNESCAPED_UNICODE);
+        $sign = md5($json_body . '_' . $this->app_secret);
+        $headers = [
+            'app-key' => $this->app_key,
+            'sign' => $sign,
+            'req-time' => now()->timestamp,
+            "Content-Type" => "application/json"
+        ];
+        $response = Http::withHeaders($headers)->withBody($json_body, 'application/json')->post($this->url);
+        return json_decode($response);
+    }
+
+    public function query($logistic_number)
+    {
+        $this->app_key = config('api_logistic.YD.prod.app-key', '999999');
+        $this->app_secret = config('api_logistic.YD.prod.app-secret', '04d4ad40eeec11e9bad2d962f53dda9d');
+        $this->url = config('api_logistic.YD.prod.search.url');
+        $body = [
+            "mailno" => $logistic_number
+        ];
+        $sign = md5(json_encode($body, JSON_UNESCAPED_UNICODE) . '_' . $this->app_secret);
+        $headers = [
+            'app-key' => $this->app_key,
+            'sign' => $sign,
+            'req-time' => now()->timestamp,
+            "Content-Type" => "application/json"
+        ];
+        $response = Http::withHeaders($headers)->withBody(json_encode($body, JSON_UNESCAPED_UNICODE), 'application/json')->post($this->url);
+        return json_decode($response->body());
+    }
+
+    public function format($nativeResponse)
+    {
+        $result = [];
+        if ($nativeResponse->code != '0000') {
+            return [];
+        } else {
+            $nativeData = $nativeResponse->data;
+            $result['logistic_number'] = $nativeData->mailno;
+            $nativeRoutes = $nativeData->steps;
+            if (!empty($nativeRoutes)) {
+                $lastNativeRoute = $nativeRoutes[count($nativeRoutes) - 1];
+                $result['status'] = $this->getStatus($nativeData);
+                if ($result['status'] == '已收件') {
+                    $result['received_at'] = $lastNativeRoute->time;
+                }
+                $result['transfer_status'] = $this->getTransferStatus($nativeRoutes);
+                $orderPackageReceivedSyncService = app('OrderPackageReceivedSyncService');
+                $exceptionData = $orderPackageReceivedSyncService->setExceptionType($result, $lastNativeRoute ? $lastNativeRoute->time : null);
+                $result['exception_type'] = $exceptionData['exception_type'];
+                $result['exception'] = $exceptionData['exception'];
+
+            } else {
+                $result['status'] = null;
+                $result['transfer_status'] = [];
+            }
+
+            if (!array_key_exists('status', $result)) {
+                $result['status'] = null;
+                $result['transfer_status'] = [];
+            }
+            //如果没有发现额外的异常,且查询到物流轨迹,将异常置为无
+            if (!array_key_exists('exception', $result)
+                && !array_key_exists('exception_type', $result)
+                && array_key_exists('transfer_status', $result)
+            ) {
+                $result['exception_type'] = '无';
+                $result['exception'] = '否';
+            }
+            $result['routes_length'] = array_key_exists('transfer_status', $result) ? count($result['transfer_status']) : 0;
+            return $result;
+        }
+    }
+
+    /**
+     * @param $nativeData
+     * @return string
+     */
+    private function getStatus($nativeData): string
+    {
+        $status = null;
+        switch ($nativeData->status) {
+            case 'GOT':
+                $status = '已揽收';
+                break;
+            case 'TRANSIT':
+                $status = '在途';
+                break;
+            case 'SIGNED':
+                $status = '已收件';
+                break;
+            case 'RETURN':
+                $status = '返回中';
+                break;
+            case 'SIGNFAIL':
+                $status = '无';
+                break;
+            default:
+                $status = '无';
+        }
+        return $status;
+    }
+
+    /**
+     * @param $nativeRoutes
+     * @return array
+     */
+    private function getTransferStatus($nativeRoutes): array
+    {
+        $transferStatus = [];
+        foreach ($nativeRoutes as $nativeRoute) {
+            $item = [];
+            $item['accept_time'] = $nativeRoute->time;
+            $item['accept_address'] = $nativeRoute->description;
+            $item['remark'] = "";
+            $transferStatus[] = $item;
+        }
+        return $transferStatus;
+    }
+}

+ 4 - 2
app/Services/OracleDocWaveDetailService.php

@@ -92,6 +92,7 @@ class OracleDocWaveDetailService
         $start_time = Carbon::now();
 
         if (isset($last_start_at) && empty($last_end_at) && $start_time->diffInMinutes(Carbon::parse($last_start_at)) < $restart) return;
+
         if (isset($last_start_at) && isset($last_end_at)
             && Carbon::parse($last_end_at)->lt(Carbon::parse($last_start_at))
             && $start_time->diffInMinutes(Carbon::parse($last_start_at)) < $restart)
@@ -99,10 +100,11 @@ class OracleDocWaveDetailService
 
         $orderHeaders = OracleDOCOrderHeader::query()
             ->selectRaw('orderno,waveno,editTime')
-            ->where('EDITTIME', '>=', Carbon::parse($sync_at)->subSeconds(1))
+            ->where('EDITTIME', '>', Carbon::parse($sync_at))
             ->where('ERPCANCELFLAG', 'Y')
             ->orderByDesc('editTime')->get();
-        $orderHeaderList = $orderHeaders->chunk(3000);
+
+        $orderHeaderList = $orderHeaders->chunk(50);
         $update_at = Carbon::now();
         if(count($orderHeaders)>0){
             foreach ($orderHeaderList as $items) {

+ 71 - 0
app/Services/OrderPackageExceptionTypeCountingRecordService.php

@@ -0,0 +1,71 @@
+<?php
+
+namespace App\Services;
+
+use App\Traits\ServiceAppAop;
+use App\OrderPackageExceptionTypeCountingRecord;
+use Carbon\Carbon;
+use Illuminate\Support\Collection;
+use Illuminate\Support\Facades\DB;
+
+class OrderPackageExceptionTypeCountingRecordService
+{
+    use ServiceAppAop;
+
+    protected $modelClass = OrderPackageExceptionTypeCountingRecord::class;
+
+    /**
+     * 同步当前日期多少天前数据
+     */
+    public function updateOrCreate($days)
+    {
+        DB::table("order_packages")
+            ->select(['exception_type',
+                DB::raw('count( * ) AS exception_type_count'),
+                DB::raw("DATE_FORMAT( sent_at, '%Y-%m-%d' ) AS sent_at_date "),
+                'owner_id',
+            ])
+            ->where('sent_at', '>=', now()->subDays($days)->startOfDay())
+            ->whereNotNull(['owner_id', 'sent_at'])
+            ->where('exception_type','!=','无')
+            ->groupBy(['exception_type',
+                'sent_at_date',
+                'owner_id'])->orderBy('sent_at_date')->chunk(1000, function ($items) {
+                foreach ($items as $item) {
+                    OrderPackageExceptionTypeCountingRecord::query()->updateOrCreate((array)$item);
+                }
+            });
+    }
+
+    public function updateOrCreateByDate($date)
+    {
+        DB::table("order_packages")
+            ->select(['exception_type',
+                DB::raw('count( * ) AS exception_type_count'),
+                DB::raw("DATE_FORMAT( sent_at, '%Y-%m-%d' ) AS sent_at_date "),
+                'owner_id',
+            ])
+            ->where('sent_at', '>=', Carbon::parse($date)->startOfDay())
+            ->where('sent_at', '<=', Carbon::parse($date)->endOfDay())
+            ->whereNotNull(['owner_id', 'sent_at'])
+            ->where('exception_type','!=','无')
+            ->groupBy(['exception_type',
+                'sent_at_date',
+                'owner_id'])->orderBy('sent_at_date')->chunk(1000, function ($items) {
+                foreach ($items as $item) {
+                    OrderPackageExceptionTypeCountingRecord::query()->updateOrCreate((array)$item);
+                }
+            });
+    }
+
+    public function get(array $kvPairs): ?Collection
+    {
+        return OrderPackageExceptionTypeCountingRecord::query()
+            ->select(['exception_type', DB::raw('sum(exception_type_count) as count')])
+            ->where('sent_at_date', '>=', Carbon::parse($kvPairs['start_date'])->startOfDay())
+            ->where('sent_at_date', '<=', Carbon::parse($kvPairs['end_date'])->endOfDay())
+            ->where('exception_type','!=','无')
+            ->whereIn('owner_id', $kvPairs['owner_ids'])
+            ->groupBy('exception_type')->get();
+    }
+}

+ 183 - 9
app/Services/OrderPackageReceivedSyncService.php

@@ -4,6 +4,7 @@
 namespace App\Services;
 
 
+use App\Jobs\LogisticYDSync;
 use App\Jobs\LogisticZopSync;
 use App\OrderPackage;
 use Carbon\Carbon;
@@ -30,6 +31,11 @@ class OrderPackageReceivedSyncService
         foreach ($ZTOLogisticNumbers as $logisticNumber) {
             LogisticZopSync::dispatch($logisticNumber);
         }
+        //更新韵达
+        $YDLogisticNumbers = $logisticNumbers['YUNDA'];
+        foreach ($YDLogisticNumbers as $logistic_number) {
+            LogisticYDSync::dispatch($logistic_number);
+        }
     }
 
     /**
@@ -102,32 +108,33 @@ class OrderPackageReceivedSyncService
     {
         //初始化时间 2020-12-31 23:59:59
         $initDate = Carbon::parse(config('api_logistic.init_date'));
-        $data = [];
         $query = OrderPackage::query()
             ->with(['order' => function ($query) {
                 return $query->with('logistic');
             }]);
         if (Carbon::now()->lte($initDate)) {//当前时间小于等于初始化时间
             //初始化查询一个月的数据,exception为否
-            $query = $query->where('created_at', '>=', $initDate->subDays((int)config('api_logistic.days'))->toDateTimeString())
-//                ->where('exception', '否')
+            $query = $query->where('sent_at', '>=', $initDate->subDays((int)config('api_logistic.days'))->toDateTimeString())
                 ->whereNull('received_at');
-        } else {//当前时间大于初始化时间,exception为否且未收货
-            $query = $query->where('created_at', '>=', $initDate->toDateTimeString())
-//                ->where('exception', '否')
+        } else {//查询20天以内的数据
+            $query = $query->where('sent_at', '>=', now()->subDays(20))
                 ->whereNull('received_at');
         }
-        return $this->buildData($query->get(), $data);
+        $result = [];
+        $query->chunk(200, function ($orderPackages) use (&$result) {
+            return $result = array_merge($result, $this->buildData($orderPackages));
+        });
+        return $result;
     }
 
     /**
      * 将orderPackage集合分类并摘取指定数据
      * @param Collection $orderPackages
-     * @param array $data
      * @return array
      */
-    private function buildData(Collection $orderPackages, array $data): array
+    private function buildData(Collection $orderPackages): array
     {
+        $data = [];
         foreach ($orderPackages as $orderPackage) {
             try {
                 $logisticCode = $orderPackage->order->logistic->code;
@@ -142,4 +149,171 @@ class OrderPackageReceivedSyncService
         }
         return $data;
     }
+
+
+    /**
+     * @param array $data
+     * @param $lastRouteDate
+     * @return array
+     */
+    public function setExceptionType(array $data, $lastRouteDate): array
+    {
+        $logistic_number = $data['logistic_number'];
+        /** @var OrderPackage $orderPackage */
+        $orderPackage = OrderPackage::query()->with('order')->where('logistic_number', $logistic_number)->first();
+        $delivered_duration = now()->diffInHours(Carbon::parse($orderPackage['sent_at']));
+        $last_routed_duration = now()->diffInHours(Carbon::parse($lastRouteDate));
+        $VALID_HOURS = 4;
+        $SHORT_RESPONSE_HOURS = (function ($province) {
+            switch ($province) {
+                case '浙江省':
+                case '江苏省':
+                case '上海':
+                case '安徽省':
+                    return 24;
+                case '北京':
+                case '天津':
+                case '江西省':
+                case '湖北省':
+                case '湖南省':
+                case '广东省':
+                case '福建省':
+                case '山东省':
+                case '河北省':
+                case '河南省':
+                case '山西省':
+                case '四川省':
+                case '陕西省':
+                case '重庆':
+                case '广西壮族自治区':
+                case '贵州省':
+                case '云南省':
+                case '海南省':
+                case '吉林省':
+                case '黑龙江省':
+                case '辽宁省':
+                    return 72;
+                case '青海省':
+                case '宁夏回族自治区':
+                case '甘肃省':
+                case '内蒙古自治区':
+                case '新疆维吾尔自治区':
+                case '西藏自治区':
+                    return 120;
+                default:
+                    return 24;
+            }
+        })($orderPackage->order->province);
+        $LONG_RESPONSE_HOURS = (function ($province) {
+            switch ($province) {
+                case '浙江省':
+                case '江苏省':
+                case '上海':
+                case '安徽省':
+                    return 72;
+                case '北京':
+                case '天津':
+                case '江西省':
+                case '湖北省':
+                case '湖南省':
+                case '广东省':
+                case '福建省':
+                case '山东省':
+                case '河北省':
+                case '河南省':
+                case '山西省':
+                case '四川省':
+                case '陕西省':
+                case '重庆':
+                case '广西壮族自治区':
+                case '贵州省':
+                case '云南省':
+                case '海南省':
+                case '吉林省':
+                case '黑龙江省':
+                case '辽宁省':
+                    return 120;
+                case '青海省':
+                case '宁夏回族自治区':
+                case '甘肃省':
+                case '内蒙古自治区':
+                case '新疆维吾尔自治区':
+                case '西藏自治区':
+                    return 168;
+                default:
+                    return 72;
+            }
+        })($orderPackage->order->province);
+        $SENDING_RESPONSE_HOURS = 48;
+        $HAVEN_SECOND_GOT_HOURS = 24;
+        $IS_ROUTED = 1;               //0000 0001 有路由信息
+        $IS_IN_VALID_TIME = 2;        //0000 0010 大于4小时
+        $IS_WEIGHED = 4;              //0000 0100 称重过
+        $IS_RECEIVED = 8;          //0000 1000 已经收货
+        $IS_SENDING = 16;             //0001 0000 正在派送
+        $IS_SHORT_NO_RESPONSE = 32;     //0010 0000 中转异常
+        $IS_LONG_NO_RESPONSE = 64;     //0010 0000 疑似丢件
+        $IS_SENDING_NO_RESPONSE = 128;     //0010 0000 派送异常
+        $IS_SECOND_ROUTE_HAVE = 256;     //0100 0000 揽件异常
+        $conclusion = (function () use (
+            $data, $delivered_duration, $last_routed_duration,
+            $VALID_HOURS, $IS_ROUTED, $IS_IN_VALID_TIME, $IS_WEIGHED, $IS_RECEIVED, $IS_SENDING, $IS_SHORT_NO_RESPONSE, $IS_LONG_NO_RESPONSE, $IS_SENDING_NO_RESPONSE,
+            $SHORT_RESPONSE_HOURS, $LONG_RESPONSE_HOURS, $SENDING_RESPONSE_HOURS, $HAVEN_SECOND_GOT_HOURS, $IS_SECOND_ROUTE_HAVE,
+            $orderPackage
+        ) {
+            $conclusion = 0;
+            $conclusion |= !empty($data['transfer_status']) ? $IS_ROUTED : 0;
+            $conclusion |= ($delivered_duration > $VALID_HOURS) ? $IS_IN_VALID_TIME : 0;
+            $conclusion |= ($orderPackage->weighed_at) ? $IS_WEIGHED : 0;
+            $conclusion |= ($data['status'] == '已收件') ? $IS_RECEIVED : 0;
+            $conclusion |= ($data['status'] == '派送中') ? $IS_SENDING : 0;//
+            $conclusion |= ($last_routed_duration > $SHORT_RESPONSE_HOURS && $last_routed_duration < $LONG_RESPONSE_HOURS) ? $IS_SHORT_NO_RESPONSE : 0;
+            $conclusion |= ($last_routed_duration > $LONG_RESPONSE_HOURS) ? $IS_LONG_NO_RESPONSE : 0;
+            $conclusion |= ($last_routed_duration > $SENDING_RESPONSE_HOURS && $data['status'] == '派送中') ? $IS_SENDING_NO_RESPONSE : 0;
+            $conclusion |= ($delivered_duration > $HAVEN_SECOND_GOT_HOURS && $data['routes_length'] < 2) ? $IS_SECOND_ROUTE_HAVE : 0;//超过指定时间,路由信息小于两条
+            return $conclusion;
+        })();
+        switch ($conclusion) {
+            case $IS_IN_VALID_TIME:
+                $data['exception_type'] = '疑似库内丢件';
+                break;
+            case $IS_IN_VALID_TIME | $IS_WEIGHED:
+                $data['exception_type'] = '揽件异常';
+                break;
+            case $IS_ROUTED | $IS_IN_VALID_TIME | $IS_SHORT_NO_RESPONSE:
+            case $IS_ROUTED | $IS_IN_VALID_TIME | $IS_SHORT_NO_RESPONSE | $IS_WEIGHED:
+                $data['exception_type'] = '中转异常';
+                break;
+            case $IS_ROUTED | $IS_IN_VALID_TIME | $IS_LONG_NO_RESPONSE:
+            case $IS_ROUTED | $IS_IN_VALID_TIME | $IS_LONG_NO_RESPONSE | $IS_WEIGHED:
+                $data['exception_type'] = '疑似丢件';
+                break;
+            default:
+                break;
+        }
+        if ($conclusion
+            == ($conclusion | $IS_ROUTED | $IS_IN_VALID_TIME | $IS_SENDING | $IS_SENDING_NO_RESPONSE)) {
+            $data['exception_type'] = '派件异常';
+        }
+        if ($conclusion
+            == ($conclusion | $IS_SECOND_ROUTE_HAVE)) {
+            $data['exception_type'] = '派件异常';
+            $data['exception'] = '是';
+
+        }
+        switch ($conclusion) {
+            case $IS_IN_VALID_TIME:
+            case $IS_IN_VALID_TIME | $IS_WEIGHED:
+            case $IS_ROUTED | $IS_SHORT_NO_RESPONSE:
+            case $IS_LONG_NO_RESPONSE:
+                $data['exception'] = '是';
+                break;
+            default:
+                break;
+        }
+        return [
+            'exception_type' => array_key_exists('exception_type', $data) ? $data['exception_type'] : null,
+            'exception' => array_key_exists('exception', $data) ? $data['exception'] : null,
+        ];
+    }
 }

+ 7 - 5
app/Services/OwnerPriceOperationService.php

@@ -439,11 +439,13 @@ class OwnerPriceOperationService
 
             if ($rule->strategy=='起步'){
                 $startNumber = $rule->amount;
-                $money = $startNumber ? $startNumber*$rule->unit_price : $rule->unit_price;
-
+                $money = 0;
                 if ($unitName && $startNumber && $unitName != $units[$rule->unit_id])return -3; //校验单位是否一致
-                if ($startNumber)$matchObject=$this->settingCount($matchObject,$columnMapping[8],$startNumber);
-                if ($matchObject)foreach ($matchObject as $package)$money += $package[$columnMapping[8]] * $package["price"];
+                if ($startNumber){
+                    $money = $rule->unit_price;
+                    $matchObject=$this->settingCount($matchObject,$columnMapping[8],$startNumber);
+                }
+                if ($matchObject)foreach ($matchObject as $package)if ($package["price"] ?? false)$money += $package[$columnMapping[8]] * $package["price"];
                 if (!$startNumber && $money<$rule->unit_price)$money = $rule->unit_price;
                 return $money+$surcharge;
             }
@@ -473,7 +475,7 @@ class OwnerPriceOperationService
         }
         if ($matchObject){
             $money = $surcharge;
-            foreach ($matchObject as $package)if ($package["price"])$money += $package[$columnMapping[8]] * $package["price"];
+            foreach ($matchObject as $package)if ($package["price"] ?? false)$money += $package[$columnMapping[8]] * $package["price"];
         }
         return $money ?? -7;
     }

+ 12 - 0
app/Services/PackageService.php

@@ -5,6 +5,7 @@ namespace App\Services;
 use App\OrderPackage;
 use App\Package;
 use App\Services\common\QueryService;
+use Illuminate\Database\Eloquent\Builder;
 use Illuminate\Http\Request;
 use Illuminate\Support\Arr;
 use Illuminate\Support\Facades\Auth;
@@ -36,6 +37,17 @@ class PackageService
             $packages->whereNotNull('weighed_at');
             Arr::forget($params, 'is_weighed');
         }
+        if ($params["batch_number"] ?? false){
+            $codes = preg_split('/[,, ]+/is', $params["batch_number"]);
+            $packages->whereHas("order",function ($query)use($codes){
+                /** @var Builder $query */
+                $query->whereHas("batch",function ($query)use($codes){
+                    /** @var Builder $query */
+                    $query->whereIn("code",$codes);
+                });
+            });
+            unset($params["batch_number"]);
+        }
         $columnQueryRules=[
             'batch_number' => ['batch' => ''],
             'weighed_at_start' => ['alias' => 'weighed_at', 'startDate' => ':00'],

+ 2 - 2
app/Services/PackageStatisticsService.php

@@ -26,8 +26,8 @@ class PackageStatisticsService
                 ->selectRaw('orders.owner_id,logistic_id');
 
         $columnQueryRules=[
-            'created_at_start' => ['alias' => 'created_at','startDate' => ":00"],
-            'created_at_end' => ['alias' => 'created_at','endDate' => ":59"],
+            'created_at_start' => ['alias' => 'order_packages.created_at','startDate' => ":00"],
+            'created_at_end' => ['alias' => 'order_packages.created_at','endDate' => ":59"],
             'logistic_id' => ['multi' => ','],
             'owner_id' => ['multi' => ','],
         ];

+ 1 - 1
app/Services/ProvinceService.php

@@ -21,7 +21,7 @@ class ProvinceService
         if(isset($province))return $province;
 
         foreach (ProvinceService::$provinces as $province) {
-            if(strstr($province,$name) != null){
+            if(strstr($province,$name) != null || strstr($name,$province) != null){
                 return Province::query()->where('name',$province)->first();
             }
         }

+ 1 - 0
app/Services/RejectedBillService.php

@@ -333,6 +333,7 @@ class RejectedBillService
             $order_package = OrderPackage::query()->where('order_id',$order->id)->first();
             $order = $order->toArray();
             $order['logistic_number'] = $order_package['logistic_number'] ?? '';
+            $order['logistic_id'] = null;
             return $order;
         }
         return null;

+ 0 - 1
app/Services/StationCacheShelfGridService.php

@@ -63,7 +63,6 @@ class StationCacheShelfGridService
                 'grid_id' => $gridId,
             ]);
             broadcast(new BroadcastToStation($station['id'] ?? '', $json));
-            StationCacheShelfGrid::query()->where('station_id',$station['id'])->where('grid_id', $gridId)->update(['material_box_id' => null, 'status' => 0]);
         }
     }
 

+ 12 - 15
app/Services/StationTaskMaterialBoxService.php

@@ -39,8 +39,8 @@ class StationTaskMaterialBoxService
     private $orderCommodityService;
     /** @var MaterialBoxService $materialBoxService */
     private $materialBoxService;
-    /** @var StationCacheShelfGridService $stationCacheShelfGridService */
-    private $stationCacheShelfGridService;
+    /** @var CacheShelfService $cacheShelfService */
+    private $cacheShelfService;
     public function __construct(){
         $this->stationService=null;
         $this->stationTypeService=null;
@@ -150,6 +150,7 @@ class StationTaskMaterialBoxService
         $this->instant($this->stationTaskCommodityService,'StationTaskCommodityService');
         $this->instant($this->stationTaskService,'StationTaskService');
         $this->instant($this->stationService,'StationService');
+        $this->instant($this->cacheShelfService,'CacheShelfService');
         try{
             LogService::log('海柔请求','markHasTaken1','');
             $taskType=$this->getServingTaskType($stationTaskMaterialBox);
@@ -170,6 +171,8 @@ class StationTaskMaterialBoxService
                         'id' => $stationTaskMaterialBox['station_id'],
                         'status' => '完成',
                     ]);
+
+                    $this->cacheShelfService->putStationTaskMaterialBoxProcess($stationTaskMaterialBox);
                     break;
                 case '入缓存架':break;
                 default:;
@@ -179,25 +182,19 @@ class StationTaskMaterialBoxService
         }
     }
 
+    // TODO 料箱处理
     function markHasTaken($stationTaskMaterialBox)
     {
         //TODO: 标记 料箱位置(需要其字段存在)$stationTaskMaterialBox['materialBox']['position']
-
-        $this->instant($this->stationCacheShelfGridService,'StationCacheShelfGridService');
+        $this->instant($this->cacheShelfService,'CacheShelfService');
 
         // 料箱从缓存架上拿走
         if($stationTaskMaterialBox['station']['stationType']['name']=='缓存架'){
-            $stationTaskMaterialBox['status'] = '完成';
 
-            $json = json_encode([
-                'station_id'=>$stationTaskMaterialBox['station_id'],
-                'code' => $stationTaskMaterialBox['materialBox']['code'],
-                'status' => '完成'
-            ]);
-            $grids = StationCacheShelfGrid::query()->where(['station_id'=>$stationTaskMaterialBox['station_id'],'material_box_id'=>$stationTaskMaterialBox['material_box_id']])->get();
-            $this->stationCacheShelfGridService->cancelTask($grids);
-            broadcast(new BroadcastToStation($stationTaskMaterialBox['station_id'], $json));
-            $this->markProcessed($stationTaskMaterialBox);
+            $stationTaskMaterialBox['status'] = '完成';
+            $result = $this->cacheShelfService->lightOffTask($stationTaskMaterialBox['station']['code'],0);
+            if($result['success'])
+                $this->markProcessed($stationTaskMaterialBox);
         }
     }
 
@@ -216,7 +213,7 @@ class StationTaskMaterialBoxService
 
     function markProcessed(StationTaskMaterialBox $stationTaskMaterialBox){
         $stationTaskMaterialBox['status'] = '完成';
-        $stationTaskMaterialBox->update();
+        $stationTaskMaterialBox->save();
     }
     function getNotProcessedSiblings($stationTaskMaterialBox){
         return StationTaskMaterialBox::query()

+ 134 - 2
app/Services/StoreService.php

@@ -383,9 +383,12 @@ class StoreService
      */
     private function storeAmountCompensationLogic($owner)
     {
-        $query = DB::raw("SELECT sum(amount) total FROM `store_items` WHERE created_at LIKE ?");
+        $query = DB::raw(<<<sql
+SELECT sum(amount) total FROM `store_items` LEFT JOIN stores ON store_items.store_id=stores.id WHERE stores.owner_id = ? AND (stores.status='已入库' OR stores.status='ASN关闭') AND store_items.updated_at LIKE ?
+sql
+        );
         $statistics = DB::selectOne($query,[$owner,date("Y-m")."%"]);
-        Cache::put(date("Y-m")."|A|".$owner,$statistics->total,2764800);
+        Cache::put(date("Y-m")."|A|".$owner,$statistics->total ? $statistics->total : 0,2764800);
     }
 
     /**
@@ -414,4 +417,133 @@ class StoreService
         if (!Cache::has($date."|A|".$owner))$this->storeAmountCompensationLogic($owner);
         return Cache::get($date."|A|".$owner);
     }
+
+    public function warehousing(array $params)
+    {
+        $conn = oci_connect(config('database.connections.oracle.username'),
+            config('database.connections.oracle.password'),
+            config('database.connections.oracle.host'). '/' . config('database.connections.oracle.service_name'),"utf8");
+        $sp = "begin SPASN_Receiving_Process(:IN_Warehouse, :In_Process_Action, :In_ASNNo_C, :In_ASNLineNo_C, :In_FMTraceID_C, :In_New_TraceID_C, :In_ProductStatus," .
+            ":In_ProductStatus_Descr, :In_HoldRejectCode_C, :In_HoldRejectReason_C, :In_PONo_C, :In_CustomerID, :In_SKU, :In_ReceivedQty, :In_RejectedQty,:In_UOM, :In_PackID," .
+            " :In_ContainerID, :In_LotAtt01_C, :In_LotAtt02_C, :In_LotAtt03_C, :In_LotAtt04_C, :In_LotAtt05_C, :In_LotAtt06_C," .
+            ":In_LotAtt07_C, :In_LotAtt08_C, :In_LotAtt09_C, :In_LotAtt10_C, :In_LotAtt11_C, :In_LotAtt12_C," .
+            ":In_TotalCubic, :In_TotalGrossWeight, :In_TotalNetWeight, :In_TotalPrice, :In_UserDefine1, :In_UserDefine2,:In_UserDefine3, :In_UserDefine4, :In_UserDefine5, :In_FMLocation," .
+            ":In_TOLocation_C,:In_QC_Type_C, :In_PlanToLoc_C,:In_ReceivingTime, :In_LPN, :In_Operator, :IN_RCVModule, :IN_RCVStation, :In_Language, :In_UserID, :OUT_Return_Code); end;";
+        $inParams = array(
+            "IN_Warehouse"=>"",
+            "In_Process_Action"=>"",
+            "In_ASNNo_C"=>"",
+            "In_ASNLineNo_C"=>"",
+            "In_FMTraceID_C"=>"",
+            "In_New_TraceID_C"=>"",
+            "In_ProductStatus"=>"00",
+            "In_ProductStatus_Descr"=>"正常",
+            "In_HoldRejectCode_C"=>"OK",
+            "In_HoldRejectReason_C"=>"正常",
+            "In_PONo_C"=>"",
+            "In_CustomerID"=>"",
+            "In_SKU"=>"",
+            "In_ReceivedQty"=>"",
+            "In_RejectedQty"=>"",
+            "In_UOM"=>"EA",
+            "In_PackID"=>"",
+            "In_ContainerID"=>"",
+            "In_LotAtt01_C"=>"",
+            "In_LotAtt02_C"=>"",
+            "In_LotAtt03_C"=>"",
+            "In_LotAtt04_C"=>"",
+            "In_LotAtt05_C"=>"",
+            "In_LotAtt06_C"=>"",
+            "In_LotAtt07_C"=>"",
+            "In_LotAtt08_C"=>"",
+            "In_LotAtt09_C"=>"",
+            "In_LotAtt10_C"=>"",
+            "In_LotAtt11_C"=>"",
+            "In_LotAtt12_C"=>"",
+            "In_TotalCubic"=>"0.00",
+            "In_TotalGrossWeight"=>"0.00",
+            "In_TotalNetWeight"=>"0.00",
+            "In_TotalPrice"=>"0.00",
+            "In_UserDefine1"=>"",
+            "In_UserDefine2"=>"",
+            "In_UserDefine3"=>"",
+            "In_UserDefine4"=>"",
+            "In_UserDefine5"=>"",
+            "In_FMLocation"=>"",
+            "In_TOLocation_C"=>"",
+            "In_QC_Type_C"=>"OK",
+            "In_PlanToLoc_C"=>"",
+            "In_ReceivingTime"=>"",
+            "In_LPN"=>"*",
+            "In_Operator"=>"WCS",
+            "IN_RCVModule"=>"",
+            "IN_RCVStation"=>"",
+            "In_Language"=>"cn",
+            "In_UserID"=>"WCS",
+            "result"=>""
+        );
+        foreach ($params as $key=>$val)$inParams[$key] = $val;
+        list($IN_Warehouse,$In_Process_Action,$In_ASNNo_C,$In_ASNLineNo_C,$In_FMTraceID_C,$In_New_TraceID_C,$In_ProductStatus,
+            $In_ProductStatus_Descr,$In_HoldRejectCode_C,$In_HoldRejectReason_C,$In_PONo_C,$In_CustomerID,$In_SKU,$In_ReceivedQty,
+            $In_RejectedQty,$In_UOM,$In_PackID,$In_ContainerID,$In_LotAtt01_C,$In_LotAtt02_C,$In_LotAtt03_C,$In_LotAtt04_C,$In_LotAtt05_C,
+            $In_LotAtt06_C,$In_LotAtt07_C,$In_LotAtt08_C,$In_LotAtt09_C,$In_LotAtt10_C,$In_LotAtt11_C,$In_LotAtt12_C,$In_TotalCubic,
+            $In_TotalGrossWeight,$In_TotalNetWeight,$In_TotalPrice,$In_UserDefine1,$In_UserDefine2,$In_UserDefine3,$In_UserDefine4,
+            $In_UserDefine5,$In_FMLocation,$In_TOLocation_C,$In_QC_Type_C,$In_PlanToLoc_C,$In_ReceivingTime,$In_LPN,$In_Operator,
+            $IN_RCVModule,$IN_RCVStation,$In_Language,$In_UserID,$result) = array_values($inParams);
+        $stmt = oci_parse($conn, $sp);
+        oci_bind_by_name($stmt, ':IN_Warehouse', $IN_Warehouse);
+        oci_bind_by_name($stmt, ':In_Process_Action', $In_Process_Action);
+        oci_bind_by_name($stmt, ':In_ASNNo_C', $In_ASNNo_C);
+        oci_bind_by_name($stmt, ':In_ASNLineNo_C', $In_ASNLineNo_C);
+        oci_bind_by_name($stmt, ':In_FMTraceID_C', $In_FMTraceID_C);
+        oci_bind_by_name($stmt, ':In_New_TraceID_C', $In_New_TraceID_C);
+        oci_bind_by_name($stmt, ':In_ProductStatus', $In_ProductStatus);
+        oci_bind_by_name($stmt, ':In_ProductStatus_Descr', $In_ProductStatus_Descr);
+        oci_bind_by_name($stmt, ':In_HoldRejectCode_C', $In_HoldRejectCode_C);
+        oci_bind_by_name($stmt, ':In_HoldRejectReason_C', $In_HoldRejectReason_C);
+        oci_bind_by_name($stmt, ':In_PONo_C', $In_PONo_C);
+        oci_bind_by_name($stmt, ':In_CustomerID', $In_CustomerID);
+        oci_bind_by_name($stmt, ':In_SKU', $In_SKU);
+        oci_bind_by_name($stmt, ':In_ReceivedQty', $In_ReceivedQty);
+        oci_bind_by_name($stmt, ':In_RejectedQty', $In_RejectedQty);
+        oci_bind_by_name($stmt, ':In_UOM', $In_UOM);
+        oci_bind_by_name($stmt, ':In_PackID', $In_PackID);
+        oci_bind_by_name($stmt, ':In_ContainerID', $In_ContainerID);
+        oci_bind_by_name($stmt, ':In_LotAtt01_C', $In_LotAtt01_C);
+        oci_bind_by_name($stmt, ':In_LotAtt02_C', $In_LotAtt02_C);
+        oci_bind_by_name($stmt, ':In_LotAtt03_C', $In_LotAtt03_C);
+        oci_bind_by_name($stmt, ':In_LotAtt04_C', $In_LotAtt04_C);
+        oci_bind_by_name($stmt, ':In_LotAtt05_C', $In_LotAtt05_C);
+        oci_bind_by_name($stmt, ':In_LotAtt06_C', $In_LotAtt06_C);
+        oci_bind_by_name($stmt, ':In_LotAtt07_C', $In_LotAtt07_C);
+        oci_bind_by_name($stmt, ':In_LotAtt08_C', $In_LotAtt08_C);
+        oci_bind_by_name($stmt, ':In_LotAtt09_C', $In_LotAtt09_C);
+        oci_bind_by_name($stmt, ':In_LotAtt10_C', $In_LotAtt10_C);
+        oci_bind_by_name($stmt, ':In_LotAtt11_C', $In_LotAtt11_C);
+        oci_bind_by_name($stmt, ':In_LotAtt12_C', $In_LotAtt12_C);
+        oci_bind_by_name($stmt, ':In_TotalCubic', $In_TotalCubic);
+        oci_bind_by_name($stmt, ':In_TotalGrossWeight', $In_TotalGrossWeight);
+        oci_bind_by_name($stmt, ':In_TotalNetWeight', $In_TotalNetWeight);
+        oci_bind_by_name($stmt, ':In_TotalPrice', $In_TotalPrice);
+        oci_bind_by_name($stmt, ':In_UserDefine1', $In_UserDefine1);
+        oci_bind_by_name($stmt, ':In_UserDefine2', $In_UserDefine2);
+        oci_bind_by_name($stmt, ':In_UserDefine3', $In_UserDefine3);
+        oci_bind_by_name($stmt, ':In_UserDefine4', $In_UserDefine4);
+        oci_bind_by_name($stmt, ':In_UserDefine5', $In_UserDefine5);
+        oci_bind_by_name($stmt, ':In_FMLocation', $In_FMLocation);
+        oci_bind_by_name($stmt, ':In_TOLocation_C', $In_TOLocation_C);
+        oci_bind_by_name($stmt, ':In_QC_Type_C', $In_QC_Type_C);
+        oci_bind_by_name($stmt, ':In_PlanToLoc_C', $In_PlanToLoc_C);
+        oci_bind_by_name($stmt, ':In_ReceivingTime', $In_ReceivingTime);
+        oci_bind_by_name($stmt, ':In_LPN', $In_LPN);
+        oci_bind_by_name($stmt, ':In_Operator', $In_Operator);
+        oci_bind_by_name($stmt, ':IN_RCVModule', $IN_RCVModule);
+        oci_bind_by_name($stmt, ':IN_RCVStation', $IN_RCVStation);
+        oci_bind_by_name($stmt, ':In_Language', $In_Language);
+        oci_bind_by_name($stmt, ':In_UserID', $In_UserID);
+        oci_bind_by_name($stmt, ':OUT_Return_Code', $result,300);
+        oci_execute($stmt);
+        oci_close($conn);
+        return $result;
+    }
 }

+ 10 - 0
app/Services/WaybillService.php

@@ -100,6 +100,10 @@ class WaybillService
             unset($param["recipient_mobile"]);
         }
 
+        if (($param["updated_at_start"] ?? false) || ($param["updated_at_end"] ?? false)){
+            $waybills->whereIn("waybills.status",['已完结','无模型']);
+        }
+
 //        if($param['carrier_bill'] ?? false){    // 承运商单号
 //            $this->searchWay($waybills,$param['carrier_bill'],'waybills.carrier_bill');
 //            unset($param['carrier_bill']);
@@ -125,9 +129,15 @@ class WaybillService
             'car_owner_info' => ['batch' => ''],
             'created_at_start' => ['alias' => 'created_at' , 'startDate' => ':00'],
             'created_at_end' => ['alias' => 'created_at' , 'endDate' => ':59'],
+            'updated_at_start' => ['alias' => 'updated_at' , 'startDate' => ':00'],
+            'updated_at_end' => ['alias' => 'updated_at' , 'endDate' => ':59'],
+            'deliver_at_start' => ['alias' => 'deliver_at' , 'startDate' => ':00'],
+            'deliver_at_end' => ['alias' => 'deliver_at' , 'endDate' => ':59'],
             'uriType' => ['alias' => 'type'],
             'id' => ['multi' => ','],
             'logistic_id' => ['multi' => ','],
+            'mileage' => ['like' => ''],
+            'carrier_weight_other' => ['like' => ''],
         ];
         $waybills = app(QueryService::class)->query($param,$waybills,$columnQueryRules,"waybills");
         return $waybills;

+ 5 - 3
app/Station.php

@@ -4,7 +4,7 @@ namespace App;
 
 use App\Traits\ModelTimeFormat;
 use Illuminate\Database\Eloquent\Model;
-use Illuminate\Database\Eloquent\Relations\HasMany;
+use Illuminate\Database\Eloquent\Relations\HasOne;
 use App\Traits\ModelLogChanging;
 
 class Station extends Model
@@ -31,8 +31,10 @@ class Station extends Model
         return $this->hasOne(StationTypeBinMonitor::class);
     }
 
-    public function grids(): HasMany
+    public function pendingStationTask(): HasOne
     {
-        return $this->hasMany(StationCacheShelfGrid::class);
+        return $this->hasOne(StationTask::class)
+            ->where('status','=','待处理');
     }
+
 }

+ 0 - 61
app/StationCacheShelfGrid.php

@@ -1,61 +0,0 @@
-<?php
-
-namespace App;
-
-use Illuminate\Database\Eloquent\Model;
-use Illuminate\Database\Eloquent\Relations\BelongsTo;
-use App\Traits\ModelLogChanging;
-
-class StationCacheShelfGrid extends Model
-{
-    use ModelLogChanging;
-
-    protected $fillable = ['station_id', 'material_box_id', 'grid_id', 'status'];
-
-    public static $status = [
-        '0' => '无',
-        '1' => '待处理',
-    ];
-
-    public function station(): BelongsTo
-    {
-        return $this->belongsTo(Station::class);
-    }
-
-    public function materialBox(): BelongsTo
-    {
-        return $this->belongsTo(MaterialBox::class);
-    }
-
-    /**
-     * 根据格口计算位置
-     * @param Station $station
-     * @param StationCacheShelfGrid $grid
-     * @return string
-     */
-    public static function getLocation(Station $station, StationCacheShelfGrid $grid): string
-    {
-        $code = $station['code'];
-        $grid_id = $grid['grid_id'];
-        $row = 2 - round($grid_id / 3) + 1;
-        $col = 2 - ($grid_id % 3) + 1;
-        return 'HAI' . $code . '-0' . $col . '-0' . $row;
-    }
-
-    /**
-     * 根据位置计算 grid_id 和 station code
-     * @param $code
-     * @return array|false[]
-     */
-    public static function getGridByCode($code): array
-    {
-        $arr = [];
-        preg_match('/^HAI([\w\.\ ]+)-0([0-9]+)-0([0-9]+)/',$code,$arr);
-        if(count($arr)==0)return [false,false,null,null];
-        $stationCode =$arr[1] ?? false;
-        $col = $arr[2] ?? 0;  // 列
-        $row = $arr[3] ?? 0;  // 行
-        $gridId = ($row-1)*3 + (3-$col);
-        return [$stationCode,$gridId,$row,$col];
-    }
-}

+ 1 - 1
app/Warehouse.php

@@ -12,7 +12,7 @@ class Warehouse extends Model
     use ModelLogChanging;
 
     use ModelTimeFormat;
-    protected $fillable=['name','code',"production_capacity","reduced_production_capacity_coefficient"];
+    protected $fillable=['name','code',"production_capacity","reduced_production_capacity_coefficient","address","principal","phone"];
 
     public function userWorkgroups(){
         return $this->hasMany('App\UserWorkgroup');

+ 10 - 11
app/library/zop/ZopClient.php

@@ -3,6 +3,7 @@
 
 namespace App\library\zop;
 use App\library\zop\ZopHttpUtil;
+use Illuminate\Support\Facades\Http;
 
 class ZopClient
 {
@@ -40,22 +41,20 @@ class ZopClient
             $data_digest = base64_encode(md5($str_to_digest, TRUE));
             $headers = array(
                 "Content-Type: application/x-www-form-urlencoded; charset=UTF-8",
-                "x-companyid: " .$this->zopProperties->getCompanyid(),
-                "x-datadigest: " .$data_digest
+                "x-companyid: " . $this->zopProperties->getCompanyid(),
+                "x-datadigest: " . $data_digest
             );
             return $this->httpClient->post($url, $headers, http_build_query($fixedParams), 2000);
-        } else{
+        } else {
             $url = $zopRequest->getUrl();
             $body = $zopRequest->getBody();
-            $str_to_digest = $body.$this->zopProperties->getKey();
+            $str_to_digest = $body . $this->zopProperties->getKey();
             $data_digest = base64_encode(md5($str_to_digest, TRUE));
-            $headers = array(
-                "Content-Type: application/json; charset=UTF-8",
-                "x-companyid: ".$this->zopProperties->getCompanyid(),
-                "x-datadigest: ".$data_digest
-            );
-            return $this->httpClient->post($url, $headers, $body, 2000);
-
+            return Http::withHeaders([
+                'Content-Type' => 'application/json; charset=UTF-8',
+                'x-companyid' => $this->zopProperties->getCompanyid(),
+                'x-datadigest' => $data_digest,
+            ])->withBody(json_encode((array)json_decode($body), JSON_UNESCAPED_UNICODE), 'application/json')->post($url)->body();
         }
     }
 }

+ 29 - 7
config/api_logistic.php

@@ -1,6 +1,6 @@
 <?php
 return [
-    'logistic'=>[
+    'logistic' => [
         'ZTO' => 'ZTO',
         'SF' => 'SF',
         'YUNDA' => 'YUNDA',
@@ -77,9 +77,9 @@ return [
     ],
     //丰桥
     'SF' => [
-        'url' =>  'https://bspsw.sf-express.com/sfexpressService',
-        'head' =>  'BSGYLGL',
-        'check_word' =>  'DcauTQEavq5qqpFaYmltzR7gzVCTjvtz',
+        'url' => 'https://bspsw.sf-express.com/sfexpressService',
+        'head' => 'BSGYLGL',
+        'check_word' => 'DcauTQEavq5qqpFaYmltzR7gzVCTjvtz',
         'max_size' => 10,
         'op_code_map' => [
             30 => '快件在【XXX营业点】已装车,准备发往 【XXX集散中心】',
@@ -102,10 +102,32 @@ return [
     ],
     //中通 https://op.zto.cn/#/Console?type=API
     'ZTO' => [
-        'url' =>  'https://japi.zto.com/zto.open.getRouteInfo',
+        'url' => 'https://japi.zto.com/zto.open.getRouteInfo',
         'x-appKey' => 'c51c718eb899e9f706979',
         'appSecret' => '9f664e3ab08049874aa417720840161a',
     ],
-    'init_date' => '2021-04-14 23:59:59',
-    'days' => 4,
+    'YD' => [
+        'test' => [
+            'app-key' => '999999',
+            'app-secret' => '04d4ad40eeec11e9bad2d962f53dda9d',
+            'search' => [
+                'url' => 'https://u-openapi.yundasys.com/openapi/outer/logictis/query',
+            ],
+            'register' => [
+                'url' => 'https://u-openapi.yundasys.com/openapi/outer/logictis/subscribe',
+            ],
+        ],
+        'prod'=>[
+            'app-key' => '000638',
+            'app-secret' => '0b941e746e3e4a5687c11f11f32ef9a3',
+            'search' => [
+                'url' => 'https://openapi.yundaex.com/openapi/outer/logictis/query',
+            ],
+            'register' => [
+                'url' => 'https://openapi.yundaex.com/openapi/outer/logictis/subscribe',
+            ],
+        ]
+    ],
+    'init_date' => '2021-05-17 23:59:59',
+    'days' => 2,
 ];

+ 12 - 0
database/factories/OrderPackageExceptionTypeCountingRecordFactory.php

@@ -0,0 +1,12 @@
+<?php
+
+/** @var \Illuminate\Database\Eloquent\Factory $factory */
+
+use App\OrderPackageExceptionTypeCountingRecord;
+use Faker\Generator as Faker;
+
+$factory->define(OrderPackageExceptionTypeCountingRecord::class, function (Faker $faker) {
+    return [
+        //
+    ];
+});

+ 24 - 1
database/factories/OrderPackageFactory.php

@@ -2,11 +2,34 @@
 
 /** @var \Illuminate\Database\Eloquent\Factory $factory */
 
+use App\Order;
 use App\OrderPackage;
 use Faker\Generator as Faker;
 
 $factory->define(OrderPackage::class, function (Faker $faker) {
+    $statuses = ['无', '已称重', '已揽收', '在途', '在途异常', '派送中', '派送异常', '返回中', '返回异常', '返回派件', '其他异常', '已收件',];
+    $exceptions = ['是', '否'];
+    $exception_types = ['疑似库内丢件','揽件异常','中转异常','疑似丢件','派件异常','其他','无'];
     return [
-        'logistic_number' => $faker->uuid
+        'logistic_number' => $faker->uuid,
+        'order_id' => random_int(1, 10000),
+        'batch_number' => random_int(1, 100),
+        'batch_rule' => null,
+        'bulk' => null,
+        'weight' => null,
+        'height' => null,
+        'paper_box_id' => random_int(1, 100),
+        'measuring_machine_id' => random_int(1, 100),
+        'weighed_at' => now()->subHours(3),
+        'status' => $faker->randomElement($statuses),
+        'sent_at' => now()->subHours(1),
+        'received_at' => null,
+        'exception' => $faker->randomElement($exceptions),
+        'transfer_status' => null,
+        'remark' => null,
+        'owner_id' => random_int(1, 100),
+        'uploaded_to_wms' => '是',
+        'exception_message' => $faker->name,
+        'exception_type' => $faker->randomElement($exception_types),
     ];
 });

+ 28 - 0
database/migrations/2021_04_29_133306_drop_station_cache_shelf_grips_table.php

@@ -0,0 +1,28 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+class DropStationCacheShelfGripsTable extends Migration
+{
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        Schema::dropIfExists('station_cache_shelf_grids');
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        //
+    }
+}

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

@@ -0,0 +1,32 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+class AddIndexExceptionTypeSentAtOwnerIdOrderPackagesTable extends Migration
+{
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        Schema::table('order_packages', function (Blueprint $table) {
+            $table->index(['sent_at', 'exception_type', 'owner_id']);
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        Schema::table('order_packages', function (Blueprint $table) {
+            $table->dropIndex(['sent_at', 'exception_type', 'owner_id']);
+        });
+    }
+}

+ 35 - 0
database/migrations/2021_05_07_141912_create_order_package_exception_type_counting_records_table.php

@@ -0,0 +1,35 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+class CreateOrderPackageExceptionTypeCountingRecordsTable extends Migration
+{
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        Schema::create('order_package_exception_type_counting_records', function (Blueprint $table) {
+            $table->id();
+            $table->date("sent_at_date")->comment("发出日期");
+            $table->string('exception_type')->comment('异常名称');
+            $table->integer('exception_type_count')->comment('异常类型的统计数量');
+            $table->unsignedBigInteger('owner_id')->comment('货主ID');
+            $table->index(['sent_at_date', 'exception_type_count', 'owner_id'],'order_packages_s_et_o_index');
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        Schema::dropIfExists('order_package_exception_type_counting_records');
+    }
+}

+ 44 - 0
database/migrations/2021_05_11_101611_exception_message_able_null_order_packages_table.php

@@ -0,0 +1,44 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+class ExceptionMessageAbleNullOrderPackagesTable extends Migration
+{
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        Schema::table('order_packages', function (Blueprint $table) {
+            $table->dropIndex('order_packages_logistic_number_unique');
+        });
+        Schema::table('order_packages', function (Blueprint $table) {
+            $table->string('exception_message')->nullable()->change();
+        });
+        Schema::table('order_packages', function (Blueprint $table) {
+            $table->unique('logistic_number','order_packages_logistic_number_unique');
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        Schema::table('order_packages', function (Blueprint $table) {
+            $table->dropIndex('order_packages_logistic_number_unique');
+        });
+        Schema::table('order_packages', function (Blueprint $table) {
+            $table->string('exception_message')->nullable(false)->change();
+        });
+        Schema::table('order_packages', function (Blueprint $table) {
+            $table->unique('logistic_number','order_packages_logistic_number_unique');
+        });
+    }
+}

+ 36 - 0
database/migrations/2021_05_14_100303_change_warehouses_table_add_column_address_column.php

@@ -0,0 +1,36 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+class ChangeWarehousesTableAddColumnAddressColumn extends Migration
+{
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        Schema::table("warehouses",function (Blueprint $table){
+            $table->text("address")->nullable()->comment("仓库地址");
+            $table->string("principal")->nullable()->comment('负责人');
+            $table->string("phone")->nullable()->comment('电话');
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        Schema::table("warehouses",function (Blueprint $table){
+            $table->dropColumn("address");
+            $table->dropColumn("principal");
+            $table->dropColumn("phone");
+        });
+    }
+}

+ 30 - 0
database/migrations/2021_05_18_151348_add_authority_order_package_remark.php

@@ -0,0 +1,30 @@
+<?php
+
+use App\Authority;
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+class AddAuthorityOrderPackageRemark extends Migration
+{
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        Authority::query()->firstOrCreate(["name" => "包裹管理-快递-客服备注"],["alias_name"=>"包裹管理-快递-客服备注"]);
+
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        Authority::query()->where('name', '包裹管理-快递-客服备注')->delete();
+    }
+}

+ 16 - 0
database/seeds/OrderPackageExceptionTypeCountingRecordSeeder.php

@@ -0,0 +1,16 @@
+<?php
+
+use Illuminate\Database\Seeder;
+
+class OrderPackageExceptionTypeCountingRecordSeeder extends Seeder
+{
+    /**
+     * Run the database seeds.
+     *
+     * @return void
+     */
+    public function run()
+    {
+        //
+    }
+}

+ 4 - 5
resources/js/queryForm/header.js

@@ -4,10 +4,10 @@ window.Header = function getHeader(object) {
     let _targetDom = object.el ? document.getElementById(object.el) : document.getElementsByTagName("table")[0];//基点元素
     let _columns = object.column;   //列名
     let _fixedTop = object.fixedTop || 0;  //同级浮动元素高度,使当前元素追加该元素高度浮动
-    let _isCheckAllBox = object.isCheckAllBox || true;//是否开启全选框
+    let _isCheckAllBox = object.isCheckAllBox!==false;//是否开启全选框
     let _data = object.data || [];   //被排序数据
     let _restorationColumn = object.restorationColumn || 'id'; //恢复原数据基准字段
-    let _is_restorationColumn_asc = object.is_restorationColumn_asc || false;    //恢复原数据基准字段的排序类型 true:asc false:desc
+    let _isRestorationColumnAsc = object.isRestorationColumnAsc || false;    //恢复原数据基准字段的排序类型 true:asc false:desc
     let _before = object.before;//前置元素
     let _name = "header:"+(object.name ? object.name+"." : "");//唯一名称 用于区别模块 本地存储
     let _isForbidDrag = object.isForbidDrag;
@@ -61,7 +61,6 @@ window.Header = function getHeader(object) {
         let firstTr = _targetDom.getElementsByTagName("tr")[0];
         let tds = [];
         if (firstTr)tds = firstTr.children;
-
         if (_isCheckAllBox){//是否开启全选
             let div = document.createElement("div");
             let check = document.createElement("input");
@@ -77,7 +76,7 @@ window.Header = function getHeader(object) {
             let div = document.createElement("div");
             let th = appendFloat(div);
             let column = _columns[(_isCheckAllBox && firstTr) ? i-1 : i];
-            let wid = localStorage.getItem(_name+column.name);
+            let wid = column ? localStorage.getItem(_name+column.name) : null;
             if (wid){
                 div.style.width = wid+"px";
                 th.style.minWidth = wid+"px";
@@ -175,7 +174,7 @@ window.Header = function getHeader(object) {
                         for(let i = gap; i < len; i++) {
                             let j = i;
                             let current = arr[i];
-                            if (_is_restorationColumn_asc){
+                            if (_isRestorationColumnAsc){
                                 while(j - gap >= 0 && Number(current[_restorationColumn]) < Number(arr[j - gap][_restorationColumn])) {
                                     arr[j] = arr[j - gap];
                                     j = j - gap;

+ 8 - 6
resources/js/queryForm/queryForm.js

@@ -97,14 +97,14 @@ const query = function getQueryForm(data) {
     }
 
     function getToggleBtn(){
-        _toggle_btn = $("<button  type='button' class='btn btn-sm btn-success position-fixed' style='left:-5px;top:290px;z-index:10;width: 25px;'>展开</button>")
+        _toggle_btn = $("<button  type='button' class='btn btn-sm btn-success position-fixed' style='left:-5px;top:290px;z-index:10;width: 28px;'>展开筛选</button>")
         _toggle_btn.click(function(){
-            if(_toggle_btn.text() === "展开"){
+            if(_toggle_btn.text() === "展开筛选"){
                 _toggle_btn.text("收缩");
                 _table.removeClass("d-none")
                 _table.css("z-index",9);
             }else if(_toggle_btn.text() === "收缩"){
-                _toggle_btn.text("展开");
+                _toggle_btn.text("展开筛选");
                 _table.addClass("d-none")
             }
         });
@@ -633,9 +633,11 @@ const query = function getQueryForm(data) {
             _data[condition.name].select = [];
             if (check[0].checked === true) {
                 condition.data.forEach(function (data) {
-                    _data[condition.name].value.push(data.name);
-                    if (_data[condition.name].select) _data[condition.name].select.push(data.name);
-                    else _data[condition.name].select = [data.name];
+                    if (data.value.indexOf(input.val())!==-1){
+                        _data[condition.name].value.push(data.name);
+                        if (_data[condition.name].select) _data[condition.name].select.push(data.name);
+                        else _data[condition.name].select = [data.name];
+                    }
                 });
             } else {
                 let dom = {

+ 93 - 0
resources/views/control/panel.blade.php

@@ -364,7 +364,35 @@
                     </div>
                 </div>
                 @endcan
+                <div class="col-6">
+                    <div class="card">
+                        <div class="card-header">
+                            <div class="flex-column">
+                                <el-date-picker size="small" class="col-6 date" @blur="loadExceptionTypeInfo()"
+                                                type="daterange" align="right"
+                                                v-model="searchOption.exceptionTypeDate" unlink-panels range-separator="-"
+                                                start-placeholder="开始日期" end-placeholder="结束日期"
+                                                value-format="yyyy-MM-dd">
+                                </el-date-picker>
+                                <el-select class="col-3"  placeholder="请选择对应货主" multiple v-model="selectExceptionTypeOwners" size="small" style="width: 20%"  @change="loadExceptionTypeInfo()">
+                                    <el-option label="选择所有" value="all"></el-option>
+                                    <el-option v-for="item in owners" :label="item.name" :value="item.id" :key="item.id"></el-option>
+                                </el-select>
+                                <label class="col-3 ">
+                                    <select class="form-control rounded" v-model="searchOption.exceptionTypeSelect"
+                                            @change="switchExceptionTypeDate()">
+                                        <option v-for="(date,i) in dateOptions" :value="i">@{{ date.text }}</option>
+                                    </select>
+                                </label>
+                            </div>
+                        </div>
+                        <div class="card-body row">
+                            <div id="exceptionType" class="col-12" style="min-height: 500px"></div>
+                        </div>
+                    </div>
+                </div>
             </div>
+
         </div>
     </div>
 @endsection
@@ -380,6 +408,7 @@
                 owners:{!! $owners !!},
                 selectOrderOwners: [],
                 selectLogisticsOwners: [],
+                selectExceptionTypeOwners: [],
                 warehousesOrders:{!! $warehousesOrders !!},
                 orderCountingRecords:{},
                 logisticsCountingRecords:{},
@@ -481,7 +510,9 @@
                 cardPool:{},
                 searchOption:{
                     weightDate:[],
+                    exceptionTypeDate: [],
                     weightSelect:"",
+                    exceptionTypeSelect:"",
                 },
             },
             watch:{
@@ -506,7 +537,9 @@
                 $('#list').removeClass('d-none');
                 let index = 4;
                 this.searchOption.weightSelect = index;
+                this.searchOption.exceptionTypeSelect = index;
                 this.searchOption.weightDate = [this.dateOptions[index].start, this.dateOptions[index].end];
+                this.searchOption.exceptionTypeDate = [this.dateOptions[index].start, this.dateOptions[index].end];
                 let _this = this;
                 this.warehousesOrders.forEach(function (item) {
                     _this.totalOrders.total += parseInt(item.total);
@@ -543,6 +576,8 @@
                 this.cardPool.weight = echarts.init(document.getElementById("weight"));
                 this.loadWeightInfo();
                 @endcan
+                this.cardPool.exceptionType = echarts.init(document.getElementById("exceptionType"));
+                this.loadExceptionTypeInfo();
             },
             methods: {
                 switchDataPanel_forOrderCountingRecords(fromUnit, toUnit) {
@@ -898,11 +933,34 @@
                         this.cardPool.weight.setOption(this._setWeightData(res.title,res.data));
                     });
                 },
+                loadExceptionTypeInfo() {
+                    window.tempTip.setDuration(3000);
+                    if (!this.searchOption.exceptionTypeDate[0]){
+                        window.tempTip.show("开始时间未选择");
+                        return;
+                    }
+                    if (!this.searchOption.exceptionTypeDate[1]){
+                        window.tempTip.show("结束时间未选择");
+                        return;
+                    }
+                    this.cardPool.exceptionType.showLoading('default',{text:"加 载 中",color:'#C0C0C0'});
+                    let url = "{{url('apiLocal/control/panel/menu/exceptionTypeApi')}}";
+                    let params = {start:this.searchOption.exceptionTypeDate[0],end:this.searchOption.exceptionTypeDate[1],owner_ids:this.selectExceptionTypeOwners};
+                    window.tempTip.postBasicRequest(url,params,res=>{
+                        this.cardPool.exceptionType.hideLoading();
+                        this.cardPool.exceptionType.setOption(this._setExceptionTypeData(res.data));
+                    });
+                },
                 switchWeightDate(){
                     let obj = this.dateOptions[this.searchOption.weightSelect];
                     this.searchOption.weightDate = [obj.start,obj.end];
                     this.loadWeightInfo();
                 },
+                switchExceptionTypeDate(){
+                    let obj = this.dateOptions[this.searchOption.exceptionTypeSelect];
+                    this.searchOption.exceptionTypeDate = [obj.start,obj.end];
+                    this.loadExceptionTypeInfo();
+                },
                 _setWeightData(title, data){
                     return {
                         title: {
@@ -937,6 +995,41 @@
                         }]
                     };
                 },
+                _setExceptionTypeData(data) {
+                    let resData = [];
+                    data.forEach(item => {
+                        resData.push({
+                            value:item.count,
+                            name:item.exception_type
+                        })
+                    })
+                    return {
+                        title: {
+                            text: '异常分布',
+                            left: 'left'
+                        },
+                        tooltip: {
+                            trigger: 'item',
+                            formatter: '{a} <br/>{b} : {c} ({d}%)'
+                        },
+                        series: [
+                            {
+                                name: '异常分布',
+                                type: 'pie',
+                                radius: '55%',
+                                center: ['50%', '60%'],
+                                data: resData,
+                                emphasis: {
+                                    itemStyle: {
+                                        shadowBlur: 10,
+                                        shadowOffsetX: 0,
+                                        shadowColor: 'rgba(0, 0, 0, 0.5)'
+                                    }
+                                }
+                            }
+                        ]
+                    }
+                }
             }
         });
     </script>

+ 3 - 3
resources/views/customer/project/create.blade.php

@@ -782,7 +782,7 @@
                         }else{
                             this.model.storage.amount_interval.forEach((amount,i)=>{
                                 if (amount==="")error["amount_interval."+i] = ["未设定数量区间"];
-                                else if (i!==0 && amount<=this.model.storage.amount_interval[i-1])
+                                else if (i!==0 && Number(amount)<=Number(this.model.storage.amount_interval[i-1]))
                                     error["amount_interval."+i] = ["阶梯区间应大于上一区间值"];
                                 this.model.storage.amount_interval[i] = parseFloat(this.model.storage.amount_interval[i]);
                             });
@@ -998,12 +998,12 @@
                     if (this.model.express.isInterval){
                         this.model.express.amount_interval.forEach((amount,i)=>{
                             if (amount==="") error["amount_interval."+i] = ["区间值不得为空"];
-                            else if (i!==0 && amount<=this.model.express.amount_interval[i-1])error["amount_interval."+i] = ["阶梯区间应大于上一区间值"];
+                            else if (i!==0 && Number(amount)<=Number(this.model.express.amount_interval[i-1]))error["amount_interval."+i] = ["阶梯区间应大于上一区间值"];
                             if (this.model.express.weight_interval[i].length>0){
                                 this.model.express.weight_interval[i].forEach((weight,j)=>{
                                     this.model.express.weight_interval[i][j] = parseFloat(this.model.express.weight_interval[i][j]);
                                     if (weight==="") error["weight_interval."+i+"."+j] = ["区间值不得为空"];
-                                    else if (j!==0 && weight<=this.model.express.weight_interval[j-1])error["weight_interval."+i+"."+j] = ["阶梯区间应大于上一区间值"];
+                                    else if (j!==0 && Number(weight)<=Number(this.model.express.weight_interval[j-1]))error["weight_interval."+i+"."+j] = ["阶梯区间应大于上一区间值"];
                                 })
                             }
                         });

+ 1 - 0
resources/views/customer/project/part/_three.blade.php

@@ -98,6 +98,7 @@
                                         <div class="col-10">
                                             <label>@{{ item.strategy }} <span v-if="item.strategy!='起步'">续费</span></label>:
                                             <b>@{{ item.amount }}</b>&nbsp;@{{ poolMapping.units ? poolMapping.units[item.unit_id] : '' }} / <b>@{{ item.unit_price }}</b>元
+                                            <span class="badge badge-secondary" v-if="item.odd_price">零头价:@{{ item.odd_price }}元</span>
                                             <span v-if="operation.isDiscount">&nbsp;(满减单价:<b>@{{ item.discount_price }}元</b>)</span>
                                         </div>
                                         <div class="col-1">

+ 0 - 1
resources/views/demand/search/index.blade.php

@@ -215,7 +215,6 @@
                 },
                 /** 问题认领 */
                 claimDemand(demand, index) {
-                    console.log(demand);
                     let url = '{{url('apiLocal/demand/claim')}}';
                     window.tempTip.setDuration(3000);
                     window.axios.post(url, {id: demand['id']}).then(res => {

+ 1 - 1
resources/views/inventory/statement/changeInventory.blade.php

@@ -139,7 +139,7 @@
                     column: column,
                     data: this.oracleActTransactingLogs,
                     restorationColumn: 'rn',
-                    is_restorationColumn_asc:true,
+                    isRestorationColumnAsc:true,
                     fixedTop:($('#form_div').height())+2,
                 }).init();
 

+ 2 - 3
resources/views/inventory/stockInventory/mission.blade.php

@@ -36,7 +36,7 @@
         <div id="form_div" class="mt-2"></div>
         <div class=" pt-1">
             <table class="table table-sm text-nowrap table-striped table-bordered m-0 td-min-width-80" id="table">
-                <tr v-for="(inventory,i) in inventoryAccounts" @click="selectedColor(inventory.id,$event)" :style="{'font-weight': inventory.id==selectedStyle?'bold':''}">
+                <tr v-for="(inventory,i) in inventoryAccounts" @click="selectedColor(inventory.id,$event)" :style="{'font-weight': inventory.id===selectedStyle?'bold':''}" :class="selectedStyle === inventory.id ? 'focusing':''">
                     <td>
                         <input class="checkItem" type="checkbox" :value="inventory.id">
                     </td>
@@ -176,12 +176,11 @@
             methods:{
                 selectedColor(id,e){
                     $('#headerParent tr[class=focusing]').removeClass('focusing')
-                    if (id==this.selectedStyle){
+                    if (id===this.selectedStyle){
                         this.selectedStyle='';
                         return;
                     }
                     this.selectedStyle=id;
-                    $(e.target).parent('tr').addClass('focusing')
                 },
                 inventoryExport(checkAllSign){
                     let url = '{{url('inventory/stockInventoryExport')}}';

+ 1 - 0
resources/views/maintenance/role/index.blade.php

@@ -85,6 +85,7 @@
                     column: column,
                     data: this.roles,
                     fixedTop: ($('#form_div').height())+2,
+                    isCheckAllBox:false,
                 }).init();
             },
             methods:{

+ 2 - 1
resources/views/maintenance/user/index.blade.php

@@ -101,7 +101,8 @@
                     column: column,
                     data: this.users,
                     fixedTop: ($('#form_div').height())+2,
-                    is_restorationColumn_asc:true,
+                    isRestorationColumnAsc:true,
+                    isCheckAllBox:false,
                 }).init();
             },
             methods:{

+ 36 - 0
resources/views/maintenance/warehouse/create.blade.php

@@ -68,6 +68,42 @@
                             @enderror
                         </div>
                     </div>
+                    <div class="form-group row">
+                        <label for="principal" class="col-2 col-form-label text-right">联系人</label>
+                        <div class="col-8">
+                            <input id="principal" type="text" class="form-control @error('principal') is-invalid @enderror"
+                                   name="principal" autocomplete="off" value="{{ old('principal') }}">
+                            @error('principal')
+                            <span class="invalid-feedback" role="alert">
+                                <strong>{{ $message }}</strong>
+                            </span>
+                            @enderror
+                        </div>
+                    </div>
+                    <div class="form-group row">
+                        <label for="phone" class="col-2 col-form-label text-right">联系电话</label>
+                        <div class="col-8">
+                            <input id="phone" type="text" class="form-control @error('phone') is-invalid @enderror"
+                                   name="phone" autocomplete="off" value="{{ old('phone') }}">
+                            @error('phone')
+                            <span class="invalid-feedback" role="alert">
+                                <strong>{{ $message }}</strong>
+                            </span>
+                            @enderror
+                        </div>
+                    </div>
+                    <div class="form-group row">
+                        <label for="address" class="col-2 col-form-label text-right">地址</label>
+                        <div class="col-8">
+                            <input id="address" type="text" class="form-control @error('address') is-invalid @enderror"
+                                   name="address" autocomplete="off" value="{{ old('address') }}">
+                            @error('address')
+                            <span class="invalid-feedback" role="alert">
+                                <strong>{{ $message }}</strong>
+                            </span>
+                            @enderror
+                        </div>
+                    </div>
                     <div class="form-group row">
                         <div class="col-8 offset-2">
                             <input type="submit" class="btn btn-success form-control">

+ 37 - 1
resources/views/maintenance/warehouse/edit.blade.php

@@ -56,7 +56,7 @@
                             </span>
                             @enderror
                         </div>
-                    </div>F
+                    </div>
                     <div class="form-group row">
                         <label for="reduced_production_capacity_coefficient" class="col-2 col-form-label text-right">SKU减产系数</label>
                         <div class="col-8 input-group">
@@ -74,6 +74,42 @@
                             <div class="text-muted">当SKU的数量多到可以影响产能时,每个SKU增加百分之几的产能需求(如填5,那每个原来1产能完成的,需要105%完成)</div>
                         </div>
                     </div>
+                    <div class="form-group row">
+                        <label for="principal" class="col-2 col-form-label text-right">联系人</label>
+                        <div class="col-8">
+                            <input id="principal" type="text" class="form-control @error('principal') is-invalid @enderror"
+                                   name="principal" autocomplete="off" value="{{ old('principal') ?? $warehouse->principal }}">
+                            @error('principal')
+                            <span class="invalid-feedback" role="alert">
+                                <strong>{{ $message }}</strong>
+                            </span>
+                            @enderror
+                        </div>
+                    </div>
+                    <div class="form-group row">
+                        <label for="phone" class="col-2 col-form-label text-right">联系电话</label>
+                        <div class="col-8">
+                            <input id="phone" type="text" class="form-control @error('phone') is-invalid @enderror"
+                                   name="phone" autocomplete="off" value="{{ old('phone') ?? $warehouse->phone }}">
+                            @error('phone')
+                            <span class="invalid-feedback" role="alert">
+                                <strong>{{ $message }}</strong>
+                            </span>
+                            @enderror
+                        </div>
+                    </div>
+                    <div class="form-group row">
+                        <label for="address" class="col-2 col-form-label text-right">地址</label>
+                        <div class="col-8">
+                            <input id="address" type="text" class="form-control @error('address') is-invalid @enderror"
+                                   name="address" autocomplete="off" value="{{ old('address') ?? $warehouse->address }}">
+                            @error('address')
+                            <span class="invalid-feedback" role="alert">
+                                <strong>{{ $message }}</strong>
+                            </span>
+                            @enderror
+                        </div>
+                    </div>
                     <div class="form-group row">
                         <div class="col-8 offset-2">
                             <input type="submit" class="btn btn-outline-dark form-control">

+ 9 - 0
resources/views/maintenance/warehouse/index.blade.php

@@ -19,6 +19,9 @@
                         <th>仓库代码</th>
                         <th>产能</th>
                         <th>SKU减产系数</th>
+                        <th>联系人</th>
+                        <th>联系电话</th>
+                        <th>地址</th>
                         <th>创建时间</th>
                         <th>操作</th>
                     </tr>
@@ -28,6 +31,9 @@
                         <td>@{{warehouse.code}}</td>
                         <td>@{{warehouse.production_capacity}}</td>
                         <td>@{{warehouse.reduced_production_capacity_coefficient}}%</td>
+                        <td>@{{warehouse.principal}}</td>
+                        <td>@{{warehouse.phone}}</td>
+                        <td>@{{warehouse.address}}</td>
                         <td class="text-muted">@{{warehouse.created_at}}</td>
                         <td>
                             @can('仓库-编辑')
@@ -52,6 +58,9 @@
                     @foreach( $warehouses as $warehouse )
                     {id:'{{$warehouse->id}}',name:'{{$warehouse->name}}',
                         production_capacity:"{{$warehouse->production_capacity}}",
+                        principal:"{{$warehouse->principal}}",
+                        phone:"{{$warehouse->phone}}",
+                        address:"{{$warehouse->address}}",
                         reduced_production_capacity_coefficient:"{{$warehouse->reduced_production_capacity_coefficient}}",
                         code:'{{$warehouse->code}}',created_at:'{{$warehouse->created_at}}'},
                     @endforeach

+ 0 - 1
resources/views/order/index/delivering.blade.php

@@ -487,7 +487,6 @@
                             tempTip.show('标记勾选内容取消分配失败,错误:'+response.data.fail_info);
                         }
                     }).catch(function (e) {
-                        alert('网络连接错误:'+e);
                         tempTip.setDuration(2500);
                         tempTip.show('标记勾选内容取消分配失败,网络连接错误:'+e);
                     })

+ 2 - 2
resources/views/order/issue/index.blade.php

@@ -356,7 +356,7 @@
                                 </button>
                             </div>
                         </td>
-                        <td class="td-yellow p-0 m-0 child-layer-2 w-50" v-if="index===0" :rowspan="orderIssues.length">
+                        <td class="td-yellow p-0 m-0 child-layer-2 w-50"  style="width:50px;" v-if="index===0" :rowspan="orderIssues.length">
                             <span class="btn" :class="isShowOrderInfo ? 'btn-outline-secondary':'btn-outline-info'"
                                   @click="toggleOrderInfo" :style="{'min-height':toggleBtnHeight+'px'}">
                                 @{{ isShowOrderInfo ? '隐藏运单列' : '展开运单列'}}
@@ -1202,7 +1202,7 @@
                 })
                 this.form.init();
                 let order = $('.table-head-warning')[0];
-                $('.top').css('min-width', $(order).outerWidth(true));
+                $('.top').css('min-width', $(order).outerWidth(true)-50);
                 this._initializePage();
             },
             watch: {

+ 49 - 16
resources/views/package/logistic/index.blade.php

@@ -8,7 +8,7 @@
     <div id="list" class="d-none">
         <div class="container-fluid">
             <div id="form_div"></div>
-            <div class="ml-3 form-inline" id="btn">
+            <div class="form-inline" id="btn">
                 @can('包裹管理-快递-异常类型-编辑')
                     <select class="form-control-sm" v-model="batchExceptionType">
                         <option v-for="(value,index) in exception_types" :value="value"
@@ -18,6 +18,14 @@
                     <button @click="batchExceptionTypeUpdate()" type="button"
                             class="btn btn-sm ml-2 btn-outline-primary">批量异常状态修改
                     </button>
+                    <select class="form-control-sm ml-2" v-model="batchStatus">
+                        <option v-for="(value,index) in statuses" :value="value"
+                                :name="value" :key="index">@{{ value }}
+                        </option>
+                    </select>
+                    <button @click="batchStatusUpdate()" type="button"
+                            class="btn btn-sm ml-2 btn-outline-danger">批量状态修改
+                    </button>
                 @endcan
             </div>
             <table class="table table-striped table-sm text-nowrap table-hover" id="table">
@@ -67,16 +75,18 @@
                         </div>
                     </td>
                     <td @mouseover="remarkHover = package.id" @mouseleave="remarkHover=null;remark=null;isShowRemarkInput = false">
+                        @can('包裹管理-快递-客服备注')
                         <button @click="isShowRemarkInput = true" v-if="remarkHover===package.id">新增</button>
                         <input @keydown.enter="submitRemark(package)" v-if="isShowRemarkInput && remarkHover===package.id" type="text" v-model="remark">
-                        <div v-if="package.remark && package.remark.length>0"
-                             class="text-overflow-warp-200 up" :id="'remark-'+i">
-                            <p v-for="remark_item in package.remark">
-                                @{{ remark_item }}
-                            </p>
-                        </div>
-                        <div class="text-overflow-warp-200 " v-if=" package.remark && !showRemarkList[i] && package.remark.length > 0">
-                            @{{ package.remark[0] }}
+                        <div v-if="package.remark && package.remark.length>0" :id="'remark-'+i">
+                            <div v-if="showRemarkList[i]" class="text-overflow-warp-200 up" >
+                                <p v-for="remark_item in package.remark">
+                                    @{{ remark_item }}
+                                </p>
+                            </div>
+                            <div class="text-overflow-warp-200" v-else>
+                                @{{ package.remark[0] }}
+                            </div>
                         </div>
                         <div @click="showRemarkItem(i)" v-if="package.remark && package.remark.length > 1">
                             <label class="text-center mt-0 p-0 cursor-pointer pull-left">
@@ -86,6 +96,7 @@
                                     v-else>展开</span>&nbsp;@{{ package.remark.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>
@@ -147,9 +158,14 @@
                     '其他',
                     '无',
                 ],
+                statuses: [
+                  '已揽收',
+                  '无',
+                ],
                 exception_editable: @can('包裹管理-快递-异常类型-编辑') true @else false  @endcan,
                 selectedExceptionType: '修改异常类型',
                 batchExceptionType: null,
+                batchStatus: null,
                 remarkHover: null,
                 remark: null,
                 isShowRemarkInput: false
@@ -199,7 +215,8 @@
 
 
                         {name: 'sent_at_start', type: 'dateTime', tip: '选择显示发出时间的起始时间'},
-                        {name: 'received_at_start', type: 'dateTime', tip: '选择显示收货时间的起始时间'},
+                        {name: 'sent_at_end', type: 'dateTime', tip: '选择显示发出时间的截止时间'},
+
 
 
                         {
@@ -226,9 +243,8 @@
                             placeholder: ['货主', '定位或多选货主'],
                             data: _this.owners
                         },
-                        {name: 'sent_at_end', type: 'dateTime', tip: '选择显示发出时间的截止时间'},
+                        {name: 'received_at_start', type: 'dateTime', tip: '选择显示收货时间的起始时间'},
                         {name: 'received_at_end', type: 'dateTime', tip: '选择显示收货时间的截止时间'},
-
                         {
                             name: 'is_exception',
                             type: 'select',
@@ -288,7 +304,6 @@
             },
             methods: {
                 showRoute(id) {
-                    // item.isShowTransferStatus = true;
                     if (this.showList[id]) {
                         this.$set(this.showList, id, false);
                         $("#route-" + id).slideUp();
@@ -299,7 +314,6 @@
                     this.$forceUpdate();
                 },
                 showRemarkItem(id) {
-                    // item.isShowTransferStatus = true;
                     if (this.showRemarkList[id]) {
                         this.$set(this.showRemarkList, id, false);
                         $("#remark-" + id).slideUp();
@@ -327,7 +341,21 @@
                         logistic_numbers: checkData
                     }).then(() => {
                         tempTip.setDuration(1000);
-                        tempTip.showSuccess('批量更新异常类型成功');
+                        tempTip.showSuccess('批量更新异常状态成功');
+                    })
+                },
+                batchStatusUpdate() {
+                    let _this = this;
+                    if (checkData.length === 0) {
+                        tempTip.show('没有勾选记录');
+                        return
+                    }
+                    axios.put('{{url('package/logistic/batchUpdate')}}', {
+                        status: this.batchStatus,
+                        logistic_numbers: checkData
+                    }).then(() => {
+                        tempTip.setDuration(1000);
+                        tempTip.showSuccess('批量状态成功');
                     })
                 },
                 submitRemark(orderPackage) {
@@ -349,7 +377,12 @@
                         tempTip.setDuration(3000);
                         tempTip.show("网络错误:"+err)
                     });
-                }
+                },
+                {{--orderPackageExport(checkAllSign){--}}
+                {{--    let url = '{{url('package/logistic/export')}}';--}}
+                {{--    let token='{{ csrf_token() }}';--}}
+                {{--    excelExport(checkAllSign,checkData,url,this.packages.length,token,{is_merge : this.is_merge});--}}
+                {{--},--}}
             },
             filters: {
                 toObjected: function (value) {

+ 10 - 4
resources/views/personnel/discharge/task/_table.blade.php

@@ -1,6 +1,6 @@
 <table class="table table-sm table-striped table-bordered table-hover card-body p-0 m-0">
     <tr class="text-center">
-        <th><input type="checkbox" class="form-check" name="selectAll" id="selectAll" @click="checkAll"></th>
+        <th><label for="selectAll"></label><input type="checkbox" class="form-check" name="selectAll" id="selectAll" @click="checkAll"></th>
         <th>序号</th>
         <th>预约时间</th>
         <th>客户名称</th>
@@ -17,8 +17,10 @@
         <th>创建时间</th>
     </tr>
     <template v-if="dischargeTasks.length > 0">
-        <tr v-for="(dischargeTask,index) in dischargeTasks" :key="index" class="text-center"  @click="selectTr===index+1?selectTr=0:selectTr=index+1" :class="selectTr===index+1?'focusing' : ''">
-            <td><input type="checkbox" class="form-check" :value="dischargeTask.id" v-model="checkData"></td>
+        <tr v-for="(dischargeTask,index) in dischargeTasks" :key="index" class="text-center"  @click.self="selectTr===index+1?selectTr=0:selectTr=index+1" :class="selectTr===index+1?'focusing' : ''">
+            <td><label>
+                    <input type="checkbox" class="form-check" :value="dischargeTask.id" v-model="checkData">
+                </label></td>
             <td>
                 @{{index+1}}
                 <template v-if="dischargeTask.status===0">
@@ -34,7 +36,10 @@
                     <span class="badge badge-pill badge-success">完成</span>
                 </template>
             </td>
-            <td>@{{ dischargeTask.income_at }}</td>
+            <td><template v-if="dischargeTask.status === 3">
+                    <button class="btn btn-sm btn-success" style="opacity: 0.7" @click="showReceipt(dischargeTask)"
+                            @mouseenter="dischargeTask.btnText = '查看'" @mouseleave="dischargeTask.btnText = '查'">@{{ dischargeTask.btnText }}</button>
+                </template>@{{ dischargeTask.income_at }}</td>
             <td>@{{ dischargeTask.owner ? dischargeTask.owner.name : '' }}</td>
             <td>
                 @can('人事管理-卸货-编辑')
@@ -101,6 +106,7 @@
                 <button class="btn btn-sm btn-outline-danger" @click="deleteTask(index,dischargeTask)">删除</button>
                 @endcan
             </td>
+
             <td>@{{ dischargeTask.created_at }}</td>
         </tr>
     </template>

+ 12 - 0
resources/views/personnel/discharge/task/index.blade.php

@@ -86,6 +86,9 @@
                 });
                 this.ownerFilter = JSON.parse(JSON.stringify(this.owners));
                 this.facilitatorsFilter = JSON.parse(JSON.stringify(this.facilitators));
+                this.dischargeTasks.forEach(function(task,index,self){
+                    self[index]['btnText'] = '查';
+                });
             },
             mounted() {
                 $('#list').removeClass('d-none');
@@ -110,6 +113,7 @@
                     paginations:[ 50, 100, 200, 500,1000,20],
                 })
                 this.form.init();
+                this.$forceUpdate();
             },
             watch: {
                 checkData: {
@@ -272,6 +276,7 @@
                     data[column] = value;
                     window.axios.put(url, data).then(res => {
                         if (res.data.success) {
+                            if(res.data.data.status === 3)res.data.data.btnText = '查';
                             this.$set(this.dischargeTasks, index, res.data.data);
                             tempTip.showSuccess("修改成功")
                             this.addTask = {};
@@ -342,8 +347,15 @@
                             this.executingTack.facilitator_id =this.facilitatorsFilter[0]['id'];
                         }
                     }
+                },
+                getReceiptUrl(id){
+                    return '{{url('personnel/discharge/task/receipt')}}'+'/?id='+id;
+                },
+                showReceipt(task){
+                    window.open(this.getReceiptUrl(task.id));
                 }
 
+
             }
         })
     </script>

+ 6 - 1
resources/views/personnel/discharge/task/menu.blade.php

@@ -3,9 +3,14 @@
         <ul class="nav nav-pills">
             @can('人事管理-卸货-查询')
             <li class="nav-item">
-                <a target="personnel/discharge/task" class="nav-link" href="{{url('personnel/discharge/task/index')}}" :class="{active:isActive('task',3)}">查询</a>
+                <a target="personnel/discharge/task" class="nav-link" href="{{url('personnel/discharge/task/index')}}" :class="{active:isActive('index',4)}">查询</a>
             </li>
             @endcan
+            @can('人事管理-卸货-查询')
+                <li class="nav-item">
+                    <a target="personnel/discharge/task/receipt" class="nav-link" href="{{url('personnel/discharge/task/index')}}" :class="{active:isActive('receipt',4)}">卸货回执</a>
+                </li>
+            @endcan
         </ul>
     </div>
 </div>

+ 54 - 0
resources/views/personnel/discharge/task/receipt.blade.php

@@ -0,0 +1,54 @@
+@extends('layouts.app')
+
+@section('title','卸货回执单')
+
+
+@section('content')
+    <div id="nav2">
+        @component('personnel.menu')@endcomponent
+        @component('personnel.discharge.menu')@endcomponent
+        @component('personnel.discharge.task.menu')@endcomponent
+    </div>
+    <div class="card card-body container-fluid text-nowrap d-none mt-5" id="list">
+        <div class="row mb-2">
+            <div class="col-sm-12 h3 text-center">回执单</div>
+        </div>
+
+        <div class="row h4">
+            <div class="col-sm-3">客户名称:<span class="text-bold ">@{{ task.owner ? task.owner.name : '' }}</span></div>
+            <div class="col-sm-3">作业类型:<span class="text-break ">@{{ task.type }}</span></div>
+            <div class="col-sm-3">入库单号:<span class="text-bold ">@{{ task.numbers }}</span></div>
+        </div>
+
+        <div class="row h4">
+            <div class="col-sm-3">数量:@{{ task.expenditure_amount }}</div>
+            <div class="col-sm-3">单位:@{{ task.expenditure_unit }}</div>
+            <div class="col-sm-3">单价:@{{ task.expenditure_unit_price }}</div>
+            <div class="col-sm-3">费用:@{{ task.expenditure_total_cost }}</div>
+        </div>
+
+        <div class="row h4">
+            <div class="col-sm-3">装卸队:<span class="text-bold ">@{{ task.facilitator ? task.facilitator.name : '' }}</span></div>
+        </div>
+        <div class="row h4">
+            <div class="col-sm-3 offset-sm-8">签名:</div>
+        </div>
+        <div class="row h4" >
+            <div class="col-sm-3 offset-sm-8">日期:</div>
+        </div>
+    </div>
+@endsection
+
+@section('lastScript')
+    <script>
+        let list = new Vue({
+            el:'#list',
+            data:{
+                task:{!! $task->toJson() !!},
+            },
+            mounted() {
+                $('#list').removeClass('d-none');
+            }
+        });
+    </script>
+@endsection

+ 1 - 1
resources/views/process/index.blade.php

@@ -587,7 +587,7 @@
                     data: this.processes,
                     restorationColumn: 'serial_number',
                     fixedTop:($('#form_div').height())+2,
-                    is_restorationColumn_asc :true,
+                    isRestorationColumnAsc :true,
                     isForbidDrag:true,
                 }).init();
             },

+ 0 - 2
resources/views/rejected/recycle.blade.php

@@ -428,7 +428,6 @@
                             tempTip.show('修改勾选记录的入库状态失败,错误:'+response.data.fail_info);
                         }
                     }).catch(function (e) {
-                        alert('网络连接错误:'+e);
                         tempTip.setDuration(2500);
                         tempTip.show('审核勾选内容失败,网络连接错误:'+e);
                     });
@@ -472,7 +471,6 @@
                             tempTip.show('恢复勾选内容失败,错误:'+response.data.fail_info);
                         }
                     }).catch(function (e) {
-                        alert('网络连接错误:'+e);
                         tempTip.setDuration(2500);
                         tempTip.show('恢复勾选内容失败,网络连接错误:'+e);
                     })

+ 0 - 2
resources/views/rejected/search/general.blade.php

@@ -417,7 +417,6 @@
                             tempTip.show('修改勾选记录的入库状态失败,错误:'+response.data.fail_info);
                         }
                     }).catch(function (e) {
-                        alert('网络连接错误:'+e);
                         tempTip.setDuration(2500);
                         tempTip.show('审核勾选内容失败,网络连接错误:'+e);
 
@@ -448,7 +447,6 @@
                             tempTip.show('审核勾选内容失败,错误:'+response.data.fail_info);
                         }
                     }).catch(function (e) {
-                        alert('网络连接错误:'+e);
                         tempTip.setDuration(2500);
                         tempTip.show('审核勾选内容失败,网络连接错误:'+e);
                     })

+ 7 - 15
resources/views/station/cachingShelf/list/_fillBox.blade.php

@@ -16,21 +16,13 @@
                 </div>
                 <hr>
                 <div class="container">
-                    <template v-if="currentStation.data ">
-                        <div class="row mt-1 mb-1" v-for="(rows,rowI) in currentStation.data">
-                            <template v-if="rows.length !== 0">
-                                <div class="col" v-for="(item,colI) in rows" :y="item.row" :x="item.col">
-                                    <textarea class="form-control font-weight-bold"
-                                              style="font-size: 35px"
-                                              @keyup.enter="pushBoxToStation(item.row,item.col,$event)"
-                                              :value="item.code"
-                                              :placeholder="item.index"
-                                              :class="item.code? 'border-success ':''"
-                                        ></textarea>
-                                </div>
-                            </template>
-                        </div>
-                    </template>
+                    <div class="row">
+                        <template v-for="(grid,i) in currentStation.grids">
+                            <div class="col-4">
+                                <textarea class="form-control" @keyup.enter="pushMaterialBox(grid,$event)" :placeholder="grid.index" :value="grid.materialBoxCode" :class="grid.materialBoxCode ?  'border-success ':''"></textarea>
+                            </div>
+                        </template>
+                    </div>
                 </div>
                 <div class="modal-footer">
                     <button class="btn btn-primary" data-dismiss="modal">关闭</button>

+ 0 - 9
resources/views/station/cachingShelf/list/_table.blade.php

@@ -48,14 +48,5 @@
                 </td>
             </tr>
         </template>
-        <template v-else>
-            <tr>
-                <td colspan="2">
-                    <div class="alert alert-info">
-                        查询数据为空
-                    </div>
-                </td>
-            </tr>
-        </template>
     </thead>
 </table>

+ 85 - 82
resources/views/station/cachingShelf/list/index.blade.php

@@ -24,9 +24,12 @@
                 materialBoxCode: null,      // 料箱编码
                 currentStation: {           // 当前Station
                     id: null,               // Station->id
-                    data: [[], [], []],     // 格口
+                    code:'',
+                    grids: {},     // 格口
+                    gridCodes:new Array(9),
                 },
                 boxClass: 'modal-sm',
+                fontSize: {},
                 broadcastName: null,
                 channelName: ".App\\Events\\BroadcastToStation",
 
@@ -39,29 +42,52 @@
             methods: {
                 /** 1初始化缓存架格口 */
                 initCacheShelfBox() {
-                    this.currentStation.data.forEach(function (item, index, self) {
-                        let boxRow = new Array(3);
-                        for (let i = 0; i < boxRow.length; i++) {
-                            let row =  2 - index + 1;
-                            let col =  2 - i + 1;
-                            let myIndex = index * 3 + i + 1;
-                            boxRow[i] = {x: index, y: i, row: row, col: col, code: null, index: myIndex};
+                    let code = this.currentStation.code;
+                    this.currentStation.grids = {};
+                    this.currentStation.gridCodes = new Array(9);
+                    if(code === null)return;
+                    for (let index = 0; index < this.currentStation.gridCodes.length; index++) {
+                        let row = Math.ceil( (index+1) / 3);
+                        let col = (index+1) % 3 === 0 ? 3 : (index+1) % 3 ;
+                        let stationCode =  'HAI'+code+'-0'+col+'-0'+row;
+                        this.currentStation.gridCodes[index] = stationCode;
+                        this.currentStation.grids[stationCode] = {
+                            index:index+1,
+                            parentStationCode:code,
+                            stationCode:stationCode,
+                            materialBoxCode:null,
+                            row:row,
+                            col:col
                         }
-                        self[index] = boxRow;
-                    });
+                    }
                 },
                 /** 2初始化modal大小 */
                 initModalBox() {
-                    if (window.screen.width >= 520) this.boxClass = 'modal-sm';
-                    if (window.screen.width >= 720) this.boxClass = 'modal-md';
-                    if (window.screen.width >= 960) this.boxClass = 'modal-lg';
-                    if (window.screen.width >= 1200) this.boxClass = 'modal-xl';
+                    if (window.screen.width >= 520) {
+                        this.boxClass = 'modal-sm';
+                        this.fontSize = {'font-size': '25px'}
+                    }
+                    if (window.screen.width >= 720){
+                        this.boxClass = 'modal-md';
+                        this.fontSize = {'font-size': '25px'}
+                    }
+                    if (window.screen.width >= 960){
+                        this.boxClass = 'modal-lg';
+                        this.fontSize = {'font-size': '30px'}
+                    }
+                    if (window.screen.width >= 1200) {
+                        this.boxClass = 'modal-xl';
+                        this.fontSize = {'font-size': '35px'}
+                    }
                 },
                 /** 展示modal */
                 showFeedBox(station) {
-                    this.currentStation.id = station['id'];
+                    this.currentStation.id = station.id;
+                    this.currentStation.code = station.code;
+                    this.initCacheShelfBox()
                     this.broadcastName = "{{config('database.redis.options.prefix')}}" + 'station-' + station['id'];
                     this.initCacheGrid();
+                    this._listenBroadcast();
                     $('#box').modal('show');
                 },
                 /** 清空格口号 */
@@ -80,15 +106,14 @@
                     window.tempTip.setDuration(3000);
                     window.axios.get(url).then(res => {
                         if (res.data.data) {
-                            if (res.data.data.length === 0) return;
-                            for (let i = 0; i < res.data.data.length; i++) {
-                                if(res.data.data.length === i)break;
-                                let grid = res.data.data[i];
-                                let gridIndex = grid['grid_id'];
-                                let row = Math.round(gridIndex / 3);
-                                let col = gridIndex % 3 -1;
-                                let code = grid['material_box'] ? grid['material_box']['code'] : null;
-                                if(grid['status'] === 1) this.$set(this.currentStation.data[row][col], 'code', code);
+                            for (let index = 0; index < res.data.data.length; index++) {
+                                let stationCode = res.data.data[index]['code'];
+                                if(!res.data.data[index]['pending_station_task'])continue;
+                                if(!res.data.data[index]['pending_station_task']['station_task_material_boxes'])continue;
+                                if(!res.data.data[index]['pending_station_task']['station_task_material_boxes'][0])continue;
+                                if(!res.data.data[index]['pending_station_task']['station_task_material_boxes'][0]['material_box'])continue;
+                                let materialBoxCode = res.data.data[index]['pending_station_task']['station_task_material_boxes'][0]['material_box']['code'] ?? null;
+                                this.$set(this.currentStation.grids[stationCode],'materialBoxCode',materialBoxCode);
                             }
                             this.$forceUpdate();
                             return;
@@ -99,88 +124,66 @@
                     });
                 },
                 /** 扫码 1、料箱扫码 */
-                pushMaterialBox($e) {
-                    let code = this.materialBoxCode;
-                    if (code === null) {
-                        $('#material-box').focus();
-                    }
-                    // 自动排号
-                    this.pushBoxToStation(null,null,$e);
-                },
-                /** 扫码 2、填写九宫格 */
-                pushBoxToStation(x = null, y = null, $e = null) {
-                    let index = null;
-                    // 自动排号和自动发送
-                    // 选排
-                    if (x !== null && y !== null) {
-                        let code = $($e.target).val();
-                        index = this.currentStation.data[x][y]['index'];
-                        this.fillBox(code,index,x,y);
+                pushMaterialBox(grid = null,$e = null) {
+                    // 从格口输入
+                    if(grid) {
+                        let materialBoxCode = $($e.target).val();
+                        let stationCode = grid['stationCode'];
+                        this.lightOn(stationCode,materialBoxCode);
                         return;
                     }
-                    // 自动排号
-                    let arr = [];
-                    this.currentStation.data.forEach(function (items) {
-                        items.forEach(function (item) {
-                            if (item['code'] === null) {
-                                arr.push(item);
-                            }
-                        });
-                    })
-                    x = arr[0]['x'];
-                    y = arr[0]['y'];
-                    index = arr[0]['index'];
-                    this.fillBox(this.materialBoxCode,index,x,y);
-                },
-                /** 扫码 4:填充页面 */
-                fillBox(code,index,x,y){
-                    this.$set(this.currentStation.data[x][y], 'code', this.materialBoxCode);
-                    this.lightOn(this.currentStation.id,code,index,x,y);
-                    this.$forceUpdate();
+                    for (const key in this.currentStation.grids) {
+                        if(this.currentStation.grids[key]['materialBoxCode'] === null){
+                            this.lightOn(this.currentStation.grids[key]['stationCode'],this.materialBoxCode);
+                            return ;
+                        }
+                    }
                 },
-                /** 扫码 3、亮灯 */
-                lightOn(id,code,index,x,y) {
+                /** 扫码 2、亮灯 */
+                lightOn(stationCode,materialBoxCode) {
+                    if(!stationCode || !materialBoxCode)return ;
                     let url = '{{url('apiLocal/station/cacheShelf/lightOn')}}';
-                    let data = {id:id, code:code, index:index, x:x, y:y};
+                    let data = {stationCode:stationCode, materialBoxCode:materialBoxCode};
+
                     window.tempTip.setDuration(2000);
                     window.tempTip.setIndex(1999);
+
+                    if(this.checkMaterialBoxCodeExist(materialBoxCode)){
+                        window.tempTip.show('料箱已被占用');
+                        return ;
+                    }
                     window.axios.post(url,data).then(res=>{
                         if(res.data.success){
-                            window.tempTip.showSuccess(res.data.data);
+                            window.tempTip.showSuccess(res.data.message ? res.data.message : '成功');
+                            this.$set(this.currentStation.grids[stationCode],'materialBoxCode',materialBoxCode);
                             this.materialBoxCode = null;
+                            this.$forceUpdate();
+                            $('#material-box').focus();
                             return ;
                         }
-                        window.tempTip.show('亮灯异常:'+res.data.data);
+                        window.tempTip.show('亮灯异常:'+res.data.message);
                     }).catch(err=>{
                         window.tempTip.show(err);
                     });
                 },
                 /** 校验是否存在 */
-                checkMaterialBoxCodeExist(code) {
-                    let bool = false;
-                    for (let x = 0; x < this.currentStation.data.length; x++) {
-                        if (!isArray(this.currentStation.data[x])) {
-                            continue;
-                        }
-                        if (this.currentStation.data[x].length > 0) {
-                            for (let y = 0; y < this.currentStation.data[y].length; y++) {
-                                if (this.currentStation.data[x][y]['code'] === code) return true;
-                            }
-                        }
+                checkMaterialBoxCodeExist(materialBoxCode) {
+                    for (const key in this.currentStation.grids) {
+                        if(this.currentStation.grids[key]['materialBoxCode'] === materialBoxCode)return true;
                     }
-                    return bool;
-                },
-                removeMaterialBox(x,y){
-                    this.$set(this.currentStation.data[x][y],'code',null);
+                    return false;
                 },
                 /** 监听 【灭灯】 */
                 _listenBroadcast() {
                     initEcho();
-                    if(this.currentEcho)this.currentEcho.disconnect();
                     this.currentEcho = window.Echo.channel(this.broadcastName).listen(this.channelName, (msg) => {
                         let json = JSON.parse(msg.json);
                         if (!json || json.length === 0) return;
-                        this.removeMaterialBox(json['x'],json['y']);
+                        if(json['code'] !== this.currentStation.code)return ;
+                        if(json['grid_code']){
+                            this.$set(this.currentStation.grids[json['grid_code']],'materialBoxCode',null);
+                            this.$forceUpdate();
+                        }
                     });
                 },
             }

+ 95 - 0
resources/views/store/deliveryAppointment/_printBody.blade.php

@@ -0,0 +1,95 @@
+<div class="container" id="printContent" v-show="infoShow">
+    <div class="row">
+        <div class="col-5">
+            <a href="{{ url('/control/panel/menu') }}" style="vertical-align: text-bottom">
+                <img src="{{asset('icon/logo100b.png')}}" height="30">
+            </a>
+        </div>
+        <div class="col-6 font-weight-bold h3">
+            宝时云仓入库预约单
+        </div>
+    </div>
+    <table class="table table-bordered border border-2 border-dark h5 text-nowrap">
+        <tr>
+            <td colspan="6" class="text-white bg-secondary font-weight-bold">预约信息</td>
+        </tr>
+        <tr>
+            <th>预约单号</th>
+            <td>@{{ printInfo.id }}</td>
+            <th>收货日期</th>
+            <td>@{{ printInfo.appointment_date }}</td>
+            <th>货主</th>
+            <td>@{{ poolMapping.owners ? poolMapping.owners[printInfo.owner_id] : '' }}</td>
+        </tr>
+        <tr>
+            <th>车辆信息</th>
+            <td>@{{ printInfo.cars ? (printInfo.cars[0] ?  printInfo.cars[0].appointment_number : '') : '' }}</td>
+            <th>司机姓名</th>
+            <td>@{{ printInfo.cars ? (printInfo.cars[0] ?  printInfo.cars[0].driver_name : '') : '' }}</td>
+            <th>联系电话</th>
+            <td>@{{ printInfo.cars ? (printInfo.cars[0] ?  printInfo.cars[0].driver_phone : '') : '' }}</td>
+        </tr>
+        <tr>
+            <th>入库单号</th>
+            <td>@{{ printInfo.asn_number }}</td>
+            <th>备注</th>
+            <td colspan="3" class="text-overflow-warp-200">@{{ printInfo.remark }}</td>
+        </tr>
+        <tr>
+            <th>总体积</th>
+            <td>@{{ printInfo.cubic_meter ? printInfo.cubic_meter+'M³' : '' }}</td>
+            <th>总重量</th>
+            <td>@{{ printInfo.tonne ? printInfo.tonne+'T' : '' }}</td>
+            <th>总件数</th>
+            <td>@{{ printInfo.box_amount }}</td>
+        </tr>
+    </table>
+
+    <table class="table table-bordered border border-2 border-dark h5 text-nowrap mt-5">
+        <tr>
+            <td colspan="6" class="text-white bg-secondary font-weight-bold">仓库信息</td>
+        </tr>
+        <tr>
+            <th>仓库</th>
+            <td>@{{ printInfo.warehouse ? printInfo.warehouse.name : '' }}</td>
+            <th>仓库地址</th>
+            <td colspan="3" class="text-overflow-warp-200">@{{ printInfo.warehouse ? printInfo.warehouse.address : '' }}</td>
+        </tr>
+        <tr>
+            <th>仓库联系人</th>
+            <td>@{{ printInfo.warehouse ? printInfo.warehouse.principal : '' }}</td>
+            <th>联系电话</th>
+            <td>@{{ printInfo.warehouse ? printInfo.warehouse.phone : '' }}</td>
+            <th>签收人</th>
+            <td>@{{ printInfo.signer }}</td>
+        </tr>
+        <tr>
+            <th>预约时间</th>
+            <td>@{{ printInfo.appointment_date+' '+printInfo.period }}</td>
+            <th>到场时间</th>
+            <td>@{{ printInfo.cars ? (printInfo.cars[0] ?  printInfo.cars[0].delivery_time : '') : '' }}</td>
+            <th>打印时间</th>
+            <td>@{{ printInfo.print_date }}</td>
+        </tr>
+    </table>
+
+    <table class="table table-bordered border border-2 border-dark h5 text-nowrap mt-5">
+        <tr>
+            <td colspan="6" class="text-white bg-secondary font-weight-bold">商品明细</td>
+        </tr>
+        <tr>
+            <th>编号</th>
+            <th>商品名称</th>
+            <th>商品编码</th>
+            <th>条码</th>
+            <th>数量</th>
+        </tr>
+        <tr v-for="(detail,i) in printInfo.details">
+            <td>@{{ i+1 }}</td>
+            <td>@{{ detail.commodity_id ? (detail.commodity ? detail.commodity.name : '') : detail.name }}</td>
+            <td>@{{ detail.commodity_id ? (detail.commodity ? detail.commodity.sku : '') : '' }}</td>
+            <td>@{{ detail | getCommodity }}</td>
+            <td>@{{ detail.amount }}</td>
+        </tr>
+    </table>
+</div>

+ 18 - 0
resources/views/store/deliveryAppointment/_printInfo.blade.php

@@ -0,0 +1,18 @@
+<div class="modal fade" id="printModal" 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">
+                    <input class="form-control" id="signer" v-model="printInfo.signer" type="text" placeholder="签收人姓名">
+                </div>
+            </div>
+            <div class="modal-footer">
+                <button class="col-12 btn btn-success" @click="exePrint()">确定</button>
+            </div>
+        </div>
+    </div>
+</div>

+ 6 - 5
resources/views/store/deliveryAppointment/appointment.blade.php

@@ -20,9 +20,9 @@
                                 <label class="col-2">车型</label>
                                 <label class="col-2">司机姓名</label>
                                 <label class="col-3">司机电话</label>
-                                <label class="col-1">
+                                {{--<label class="col-1">
                                     <span class="fa fa-plus cursor-pointer text-primary" @click="addCar()">增加</span>
-                                </label>
+                                </label>--}}
                             </div>
                         </div>
                         <div class="card-body">
@@ -46,9 +46,9 @@
                                 <label class="col-3">
                                     <input type="text" class="form-control" v-model="car.driver_phone">
                                 </label>
-                                <label class="col-1" v-if="i!==0">
+                                {{--<label class="col-1" v-if="i!==0">
                                     <span class="h4 font-weight-bold cursor-pointer text-danger" @click="delCar(i)">&times;</span>
-                                </label>
+                                </label>--}}
                                 <label v-if="errors['cars.'+i+'.license_plate_number']" class="col-2 offset-2 text-danger font-weight-bold small">
                                     @{{ errors['cars.'+i+'.license_plate_number'][0] }}
                                 </label>
@@ -71,7 +71,8 @@
                     </div>
                     <div class="row mt-2 ml-1">
                         <label class="col-2" for="asnNumber">ASN单号</label>
-                        <input class="col-6 form-control" @blur="verifyASN()" type="text" id="asnNumber" v-model="model.asn_number" :class="errors.asn_number ? 'is-invalid' : ''">
+                        <input class="col-6 form-control" placeholder="可以输入多个,使用空格或逗号分隔" @blur="verifyASN()"
+                               type="text" id="asnNumber" v-model="model.asn_number" :class="errors.asn_number ? 'is-invalid' : ''">
                     </div>
                     <div class="row mt-2 ml-1">
                         <label class="col-2" for="logistic_number">快递单号</label>

+ 1 - 1
resources/views/store/deliveryAppointment/delivery.blade.php

@@ -105,7 +105,7 @@
 <div class="center">
     <div>
         <div class="label">下方填写您的预约码</div>
-        <label><input type="number" class="input" id="appointment_number" oninput="if(value.length>6)value=value.slice(0,6)"></label>
+        <label><input type="text" class="input" id="appointment_number" oninput="if(value.length>10)value=value.slice(0,10)"></label>
     </div>
     <div>
         <button type="button" class="btn" onclick="submit()"> 确 认 </button>

+ 90 - 70
resources/views/store/deliveryAppointment/exhibition.blade.php

@@ -18,15 +18,8 @@
         .h-90{
             height: 90%;
         }
-        .h-5{
-            height: 5%;
-        }
-        .h-9{
-            height: 9%;
-        }
-        .text-line{
-            line-height: 1;
-            font-size: 1.5em;
+        .h-10{
+            height: 10%;
         }
         #msg{
             width:266px;
@@ -100,11 +93,17 @@
             margin-left:10%;
             width: 80%;
         }
+        .br-1{
+            border-right:2px solid #aaaaaa;
+        }
+        table{
+            border-top: 3px solid #1b1e21;
+        }
     </style>
 </head>
 <body onload="initLoad()" class="h-100">
     <div class="container-fluid h-100 d-none" id="container">
-        <div class="offset-1 h1 font-weight-bold h-100">
+        <div class="ml-5 h1 font-weight-bold mt-2 mb-0 h-10">
             <div class="h-5"></div>
             <div class="h-5 h6">
                 <div class="font-weight-bold row">
@@ -119,63 +118,56 @@
                 </div>
                 <hr class="font-weight-bold">
             </div>
-            <div class="w-100 h-90">
-                <div class="h-9 mt-1 row" v-for="(data,i) in list" :class="data.status==1 ? 'text-primary' : (data.status==2 ? 'text-success' : 'text-dark')" v-if="i<5">
-                    <div class="col-3 text-line">@{{ data.license_plate_number }}
-                        <span class="badge" :class="data.status==1 ? 'badge-primary' : (data.status==2 ? 'badge-success' : 'badge-secondary')" style="font-size: 20px" v-if="data.tonne || data.cubic_meter">
-                            <span v-if="data.tonne">吨&nbsp;&nbsp;&nbsp;:@{{ data.tonne }}<br></span>
-                            <span v-if="data.cubic_meter">立方:@{{ data.cubic_meter }}</span>
-                        </span>
-                        <small class="h3 m-0"><span class="badge badge-pill badge-primary">质检</span></small>
-                    </div>
-                    <div class="col-2 text-line">@{{ data.driver_name }}</div>
-                    <div class="col-3 text-line">@{{ data.driver_phone }}</div>
-                    <div class="col-2 text-line">
-                        <span class="badge badge-pill badge-primary" {{--v-if="data.is_delivery"--}} v-if="data.status == 1">{{--已送达--}}作业中</span>
-                    </div>
-                </div>
-                <div class="row h-50">
-                    <div class="col-5">
-                        <div class="row" style="height: 20%" v-for="(data,i) in list" :class="data.status==1 ? 'text-primary' : (data.status==2 ? 'text-success' : 'text-dark')" v-if="i>5">
-                            <div class="col-8 text-line">@{{ data.license_plate_number }}
-                                <span class="badge" :class="data.status==1 ? 'badge-primary' : (data.status==2 ? 'badge-success' : 'badge-secondary')" style="font-size: 20px" v-if="data.tonne || data.cubic_meter">
-                                    <span v-if="data.tonne">吨&nbsp;&nbsp;&nbsp;:@{{ data.tonne }}<br></span>
-                                    <span v-if="data.cubic_meter">立方:@{{ data.cubic_meter }}</span>
-                                </span>
-                                <small class="h3 m-0"><span class="badge badge-pill badge-primary">质检</span></small>
-                            </div>
-                            <div class="col-4 text-line">@{{ data.driver_name }}</div>
-                        </div>
-                    </div>
-                    <div class="col-7" style="border: 3px solid #6c757d;border-radius: 5px">
-                        <div class="w-100 text-center h1 font-weight-bold">次日预约</div>
-                        <div class="mt-2 text-muted row" v-for="(data,i) in nextList">
-                            <div class="col-5">@{{ data.license_plate_number }}
-                                <span class="badge badge-secondary" style="font-size: 14px" v-if="data.tonne || data.cubic_meter">
-                                    <span v-if="data.tonne">吨&nbsp;&nbsp;&nbsp;:@{{ data.tonne }}<br></span>
-                                    <span v-if="data.cubic_meter">立方:@{{ data.cubic_meter }}</span>
-                                </span>
-                                <small class="h3 m-0"><span class="badge badge-pill badge-primary">质检</span></small>
-                            </div>
-                            <div class="col-3">@{{ data.driver_name }}</div>
-                            <div class="col-3">@{{ data.driver_phone }}</div>
-                        </div>
-                    </div>
+        </div>
+        <div class="row h-90 mt-0">
+            <div class="col-8 br-1">
+                <div class="w-100 text-center">
+                    <h1 class="font-weight-bold">当日预约</h1>
                 </div>
+                <table class="table w-100 h3">
+                    <tr>
+                        <th>货主</th>
+                        <th>车牌/预约号</th>
+                        <th>吨位/立方</th>
+                        <th>特殊要求</th>
+                        <th>预约时间</th>
+                        <th>到场时间</th>
+                        <th>状态</th>
+                    </tr>
+                    <tr v-for="data in list">
+                        <td class="text-secondary">@{{ data.owner_name }}</td>
+                        <td class="text-danger">@{{ data.license_plate_number }}</td>
+                        <td class="text-secondary"><i v-if="data.tonne">@{{ data.tonne }}吨</i><br><i v-if="data.cubic_meter">@{{ data.cubic_meter }}立方</i></td>
+                        <td class="text-primary">@{{ data.type }}</td>
+                        <td class="text-secondary">@{{ data.period }}</td>
+                        <td class="text-secondary">@{{ data.delivery_time }}</td>
+                        <td :class="data.status == '未送达' ? 'text-dark' : (data.status=='作业中' ? 'text-primary' : 'text-success')">@{{ data.status }}</td>
+                    </tr>
+                </table>
             </div>
-            {{--<div class="row h-40 mt-0">
-                <div class="col-5">
-                    <div class="h-20 mt-0 row" v-for="(data,i) in list" :class="data.is_delivery ? 'text-success' : 'text-primary'" v-if="i>4">
-                        <div class="col-7 text-line">@{{ data.license_plate_number }}</div>
-                        <div class="col-5 text-line">
-                            <span class="ml-3">@{{ data.driver_name }}</span>
-                        </div>
-                    </div>
-                </div>
-                <div class="col-6">
-                    <div class="mt-4" id="code"></div>
+            <div class="col-4">
+                <div class="w-100 text-center">
+                    <h2 class="font-weight-bold">次日预约</h2>
                 </div>
-            </div>--}}
+                <table class="table w-100 h4">
+                    <tr>
+                        <th>货主</th>
+                        <th>车牌/预约号</th>
+                        <th>吨位/立方</th>
+                        <th>特殊要求</th>
+                        <th>预约时间</th>
+                    </tr>
+                    <tr v-for="data in nextList">
+                        <td class="text-secondary">@{{ data.owner_name }}</td>
+                        <td class="text-danger">@{{ data.license_plate_number }}</td>
+                        <td class="text-secondary"><i v-if="data.tonne">@{{ data.tonne }}吨</i><br><i v-if="data.cubic_meter">@{{ data.cubic_meter }}立方</i></td>
+                        <td class="text-primary">@{{ data.type }}</td>
+                        <td class="text-secondary">@{{ data.period }}</td>
+                        <td class="text-secondary">@{{ data.delivery_time }}</td>
+                        <td :class="data.status == '未送达' ? 'text-dark' : (data.status=='作业中' ? 'text-primary' : 'text-success')">@{{ data.status }}</td>
+                    </tr>
+                </table>
+            </div>
         </div>
         <div class="modal fade" id="modal" tabindex="-1" role="dialog" aria-hidden="true" data-backdrop="static">
             <div class="modal-dialog modal-dialog-centered modal-xl" role="document">
@@ -236,6 +228,7 @@
     function selectedWarehouse() {
         if (!selected) return;
         warehouse = document.getElementById(selected).dataset.id;
+        vue._initData();
         history.pushState(null,null,window.location.href+"?warehouse="+warehouse);
         $("#modal").modal('hide');
         alert("是否需要开启全屏?");
@@ -261,7 +254,7 @@
             element.msRequestFullscreen();
         }
     }
-    new Vue({
+    let vue = new Vue({
         el:"#container",
         data:{
             list:[],
@@ -278,8 +271,8 @@
         },
         mounted(){
             $("#container").removeClass("d-none");
-            this._initData();
-            //this._broadcast();
+            if (warehouse) this._initData();
+            this._broadcast();
             /*this._getKey();
             setTimeout(()=>{
                 //刷新密匙
@@ -294,10 +287,33 @@
                 initEcho();
                 window.Echo.channel('{{config('database.redis.options.prefix')}}delivery').listen('.car',(res)=>{this._sortData(res.delivery)})
             },
+            _countChange(oldStatus,newStatus){
+                switch (oldStatus) {
+                    case '未送达':
+                        this.count.notReached--;
+                        break;
+                    case '作业中':
+                        this.count.work--;
+                        break;
+                }
+                if (!oldStatus && newStatus)this.count.total++;
+                switch (newStatus) {
+                    case '未送达':
+                        this.count.notReached++;
+                        break;
+                    case '作业中':
+                        this.count.work++;
+                        break;
+                    case '已完成':
+                        this.count.success++;
+                        break;
+                }
+            },
             _sortData(res){
                 if (res.warehouse!=warehouse)return;
                 if (this.list.every((data,i)=>{
                     if (data.id === res.id){
+                        this._countChange(data.status,res.status);
                         //this.$set(this.list[i],"is_delivery",true);
                         data.status = res.status;
                         this.list.splice(i,1);
@@ -314,14 +330,19 @@
                     }
                     return true;
                 })){
+                    this._countChange(null,res.status);
                     if (this.list.length>=10) this.list = this.list.splice(0,9);
                     let obj = {
                         "id"                    : res.id,
                         "license_plate_number"  : res.license_plate_number,
                         "driver_name"           : res.driver_name,
                         "driver_phone"          : res.driver_phone,
-                        "cubic_meter"           : res.driver_phone,
-                        "tonne"                 : res.driver_phone,
+                        "cubic_meter"           : res.cubic_meter,
+                        "tonne"                 : res.tonne,
+                        "owner_name"            : res.owner_name,
+                        "type"                  : res.type,
+                        "period"                : res.period,
+                        "delivery_time"         : res.delivery_time,
                         "status"                : res.status,
                         /*"is_delivery"           : true,*/
                     };
@@ -343,7 +364,6 @@
                         }
                     });
                 },1800000);*/
-                this.count.success++;
             },
             //初始化数据
             _initData(){

+ 81 - 17
resources/views/store/deliveryAppointment/list.blade.php

@@ -56,7 +56,7 @@
                     <div class="row">
                         <div class="col-12 text-center">明细单</div>
                     </div>
-                    <div class="row" style="min-width: 300px">
+                    <div class="row" style="min-width: 500px">
                         <div class="col-5 text-center">商品名称</div>
                         <div class="col-4 text-center">条码</div>
                         <div class="col-2 text-center">数量</div>
@@ -77,16 +77,25 @@
                         <button type="button" @click="cancel(info.id,i)" class="btn btn-sm btn-outline-danger">取消预约</button><br>
                         <button type="button" @click="updateDeliveryDate(info,i)" class="btn btn-sm btn-outline-primary">修改预约</button>
                     </span>
+                    <span v-if="info.status==2">
+                        <button type="button" @click="printReceipt(info)" class="btn btn-sm btn-outline-success"><i class="fa fa-print"></i>&nbsp;打印</button>
+                    </span>
                 </td>
                 <td>
-                    <label v-if="!poolMapping.status">
-                        <span class="fa fa-circle text-secondary">未知</span>
-                    </label>
-                    <label v-else>
-                        <small><span class="fa fa-circle" :class="info.status==0 ? 'text-info' : (info.status==2 ? 'text-success' : 'text-danger')"></span></small>
-                        @{{ poolMapping.status[info.status] }}
-                        <span v-if="info.type_mark==0" class="badge badge-primary">质检单</span>
-                    </label>
+                    <span v-if="info.status==0 && info.cars.length>0 && info.cars[0].status==1">
+                        <span class="fa fa-circle text-primary">作业中</span>
+                    </span>
+                    <span v-else>
+                        <label v-if="!poolMapping.status">
+                            <span class="fa fa-circle text-secondary">未知</span>
+                        </label>
+                        <label v-else>
+                            <small><span class="fa fa-circle" :class="info.status==0 ? 'text-info' : (info.status==2 ? 'text-success' : 'text-danger')"></span></small>
+                            @{{ poolMapping.status[info.status] }}
+                            <span v-if="info.type_mark==0" class="badge badge-primary">质检单</span>
+                        </label>
+                    </span>
+
                 </td>
                 <td>
                     <label v-if="!poolMapping.owners"></label>
@@ -135,19 +144,19 @@
                 <td>@{{ info.box_amount>0 ? info.box_amount : '-' }}</td>
                 <td>@{{ info.logistic ? info.logistic.name : '' }}</td>
                 <td>@{{ info.logistic_number }}</td>
-                <td>@{{ info.procurement_number }}</td>
-                <td>@{{ info.asn_number }}</td>
+                <td><span v-html="warpText(info.procurement_number)"></span></td>
+                <td><span v-html="warpText(info.asn_number)"></span></td>
                 <td>
                     <div v-if="info.details.length>0">
                         <div class="row">
-                            <div class="col-5 font-weight-bold">@{{ info.details[0].commodity_id ? (info.details[0].commodity ? info.details[0].commodity.name : '') : info.details[0].name }}</div>
-                            <div class="col-4 text-secondary">@{{ info.details[0] | getCommodity }}</div>
+                            <div class="col-5 font-weight-bold text-overflow-warp">@{{ info.details[0].commodity_id ? (info.details[0].commodity ? info.details[0].commodity.name : '') : info.details[0].name }}</div>
+                            <div class="col-4 text-secondary text-overflow-warp">@{{ info.details[0] | getCommodity }}</div>
                             <div class="col-2 text-secondary">@{{ info.details[0].amount }}</div>
                         </div>
                         <div class="up" :id="'detail-'+info.id" v-show="info.details.length>1">
                             <div class="row" v-for="(detail,i) in info.details" v-if="i!==0">
-                                <div class="col-5 font-weight-bold">@{{ detail.commodity_id ? (detail.commodity ? detail.commodity.name : '') : detail.name }}</div>
-                                <div class="col-4 text-secondary">@{{ detail | getCommodity }}</div>
+                                <div class="col-5 font-weight-bold text-overflow-warp">@{{ detail.commodity_id ? (detail.commodity ? detail.commodity.name : '') : detail.name }}</div>
+                                <div class="col-4 text-secondary text-overflow-warp">@{{ detail | getCommodity }}</div>
                                 <div class="col-2 text-secondary">@{{ detail.amount }}</div>
                             </div>
                         </div>
@@ -163,6 +172,8 @@
             </tr>
         </table>
         @include("store.deliveryAppointment._selectDate")
+        @include("store.deliveryAppointment._printBody")
+        @include("store.deliveryAppointment._printInfo")
     </div>
 @stop
 
@@ -187,6 +198,8 @@
                 index:"",
                 selectDate:{},
                 periods:@json(\App\DeliveryAppointment::PERIOD),
+                printInfo:{},
+                infoShow:false,
             },
             mounted(){
                 let status = [];
@@ -224,13 +237,41 @@
             watch:{
                 checkData:{
                     handler(){
-                        if (this.checkData.length === this.list.length) document.querySelector('#all').checked = true;
-                        else document.querySelector('#all').checked = false;
+                        document.querySelector('#all').checked = this.checkData.length === this.list.length;
                     },
                     deep:true
                 },
             },
             methods: {
+                exePrint(){
+                    this.infoShow = true;
+                    if (!this.printInfo.signer){
+                        window.tempTip.setIndex(1099);
+                        window.tempTip.show("请填写签收人");
+                        return;
+                    }
+                    $("#printModal").modal('hide');
+                    let iframe=document.getElementById("print-iframe");
+                    if(!iframe){
+                        let el = document.getElementById("printContent");
+                        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);
+                        let doc = iframe.contentWindow.document;
+                        doc.write('<LINK rel="stylesheet" type="text/css" href="{{ asset(mix("css/app.css")) }}">');
+                        doc.write('<div>' + 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);
+                },
                 _renderingForm(){
                     let data=[
                         [
@@ -370,6 +411,29 @@
                         return "标记质检成功";
                     });
                 },
+                printReceipt(info){
+                    let d = new Date();
+                    let str = '';
+                    str += d.getFullYear() + '年';
+                    str += d.getMonth() + 1 + '月';
+                    str += d.getDate() + '日';
+                    str += d.getHours() + '时';
+                    str += d.getMinutes() + '分';
+                    str += d.getSeconds() + '秒';
+
+                    this.printInfo = info;
+                    this.printInfo.print_date = str;
+                    $("#printModal").modal("show");
+                },
+                warpText(code){
+                    if (!code)return code;
+                    code = code.split(/[,, ]+/is);
+                    let str = "";
+                    for (let i=0;i<code.length;i++){
+                        str += code[i]+"<br>";
+                    }
+                    return str;
+                }
             },
             filters:{
                 getCommodity(detail){

+ 2 - 4
resources/views/store/fast/index.blade.php

@@ -15,8 +15,8 @@
                     </td>
                     <td><span>@{{ i+1  }}</span></td>
                     <td class="text-muted"><span>@{{store.asn_code}}</span></td>
-                    <td><span>@{{store.warehouse.name}}</span></td>
-                    <td class="text-muted"><span>@{{store.owner.name}}</span></td>
+                    <td><span>@{{store.warehouse ? store.warehouse.name : ''}}</span></td>
+                    <td class="text-muted"><span>@{{store.owner ? store.owner.name : ''}}</span></td>
                     <td class="text-muted"><span>@{{store.stored_method}}</span></td>
                     <td class="text-muted"><span>@{{store.status}}</span></td>
                     <td><span>@{{store.remark}}</span></td>
@@ -45,8 +45,6 @@
             mounted:function(){
                 $('#fast').removeClass('d-none');
                 let column = [
-                    {name:'cloneCheckAll',customization:true,type:'checkAll',column:'id',
-                        dom:$('#cloneCheckAll').removeClass('d-none'), neglect: true},
                     {name:'index',value: '序号', neglect: true},
                     {name:'asn_code',value: 'ASN编号'},
                     {name:'warehouse_name',value: '仓库'},

+ 137 - 0
resources/views/store/inStorage/cacheRackStorage.blade.php

@@ -0,0 +1,137 @@
+@extends('layouts.app')
+@section('title')缓存架入库-入库管理@endsection
+
+@section('content')
+    <span id="nav2">
+        @component('store.menu')@endcomponent
+        @component('store.inStorage.menu')@endcomponent
+    </span>
+    <div class="container-fluid" id="container">
+        <div class="row">
+            <div class="card offset-md-3 col-md-6 col-sm-12">
+                <div class="card-body">
+                    <div class="form-group text-center font-weight-bold h4">
+                        入库信息
+                    </div>
+                    <div class="form-group row">
+                        <label for="asn" class="col-sm-2 col-3 text-right">ASN号:</label>
+                        <input type="text" class="form-control col-8" :class="errors.asn ? 'is-invalid' : ''" id="asn" v-model="info.asn" @blur="checkAsn()" placeholder="只需填写后几位,自动补充">
+                        <span class="invalid-feedback offset-2" role="alert" v-if="errors.asn">
+                            <strong>@{{ errors.asn[0] }}</strong>
+                        </span>
+                    </div>
+                    <div class="form-group row">
+                        <label for="ide" class="col-sm-2 col-3 text-right">料箱号:</label>
+                        <input type="text" class="form-control col-8" :class="errors.ide ? 'is-invalid' : ''" id="ide" v-model="info.ide" @blur="checkIde()" placeholder="只需填写后几位,自动补充">
+                        <span class="invalid-feedback offset-2" role="alert" v-if="errors.ide">
+                            <strong>@{{ errors.ide[0] }}</strong>
+                        </span>
+                    </div>
+                    <div class="input-group row">
+                        <label for="barCode" class="col-sm-2 col-3 text-right">条码:</label>
+                        <input type="text" class="form-control rounded col-sm-5 col-8 ml-sm-1 ml-2" :class="errors.barCode ? 'is-invalid' : ''" id="barCode" @blur="codeBlur()" @keydown.enter="checkInfo()" v-model="info.barCode">
+                        <div class="input-group-append mt-sm-0 mt-4">
+                            <span class="input-group-text d-none d-sm-block">@数量</span>
+                            <label class="d-sm-none col-4 text-right">数量:</label>
+                            <span class="input-group-text p-0 border-0">
+                                <input class="form-control" type="number" :class="errors.amount ? 'is-invalid' : ''" step="1" min="1" id="amount" v-model="info.amount">
+                            </span>
+                        </div>
+                        <span class="invalid-feedback offset-2" role="alert" v-if="errors.barCode">
+                            <strong>@{{ errors.barCode[0] }}</strong>
+                        </span>
+                    </div>
+                    <div class="input-group row mt-5">
+                        <button type="submit" class="btn btn-success offset-2 col-9" @click="checkInfo()">提交</button>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+@stop
+
+@section('lastScript')
+    <script type="text/javascript">
+        new Vue({
+            el:"#container",
+            data:{
+                permissionList:[ //允许聚焦许可列表
+                    "asn","ide","amount"
+                ],
+                info:{},
+                mount:false,
+                before:{
+                    asn:"",
+                    ide:"",
+                },
+                errors:{},
+            },
+            mounted(){
+                this.codeFocus();
+                this.globalClick();
+                this.createBefore();
+            },
+            methods:{
+                //聚焦 白名单
+                codeFocus(){
+                    if (!this.permissionList.includes(document.activeElement.id)) document.getElementById("barCode").focus();
+                },
+                //全局点击聚焦
+                globalClick(turn = true){
+                    if (turn===this.mount)return;
+                    this.mount = turn;//防止重复挂载事件
+                    if (turn) window.addEventListener("click",this.codeFocus);
+                    else window.removeEventListener("click",this.codeFocus);
+                },
+                codeBlur(){
+                    if (this.info.asn && this.info.ide && !this.info.amount){
+                        this.globalClick(false);
+                        window.tempTip.inputVal('请输入数量:',(amount)=>{
+                            this.info.amount = amount;
+                            if (this.info.asn && this.info.ide && this.info.barCode && this.info.amount)this.checkInfo();
+                            this.globalClick();
+                        });
+                    }
+                },
+                checkInfo(){
+                    let error = {};
+                    if (!this.info.asn)error.asn = ["ASN号必填"];
+                    if (this.info.asn && this.info.asn.length!==13)error.asn = ["非法ASN号"];
+                    if (!this.info.ide)error.ide = ["料箱号必填"];
+                    if (this.info.ide && this.info.ide.length!==10)error.ide = ["非法料箱号"];
+                    if (!this.info.barCode)error.barCode = ["商品条码必填"];
+                    if (!this.info.amount)error.amount = ["数量必填"];
+                    if (JSON.stringify(error)!=='{}'){this.errors = error;return;}
+                    this._exeTask();
+                },
+                _exeTask(){
+                    console.log("ok");
+                    //入库成功
+                    this.info = {};
+                    this.errors = {};
+                },
+                createBefore(){
+                    let now = new Date();
+                    let yy = now.getFullYear().toString().substr(2, 2);
+                    let mm = now.getMonth() + 1;
+                    mm = mm <10 ? '0'+mm : mm.toString();
+                    let dd = now.getDate();
+                    dd = dd <10 ? '0'+dd : dd.toString();
+                    this.before.asn = 'ASN'+yy+mm+dd+'000';
+                    this.before.ide = 'IDE000000';
+                },
+                checkAsn(){
+                    if(!this.info.asn)return;
+                    let len = this.info.asn.length;
+                    if (len<13)this.info.asn = this.before.asn.substr(0,13-len)+this.info.asn;
+                    if (!this.info.ide)document.getElementById("ide").focus();
+                },
+                checkIde(){
+                    if(!this.info.ide)return;
+                    let len = this.info.ide.length;
+                    if (len<10)this.info.ide = this.before.ide.substr(0,10-len)+this.info.ide;
+                }
+            },
+        });
+    </script>
+@stop

+ 4 - 0
resources/views/store/inStorage/menu.blade.php

@@ -6,6 +6,10 @@
                     <li class="nav-item">
                         <a target="store/inStorage/index" class="nav-link" href="{{url('store/inStorage/index')}}" :class="{active:isActive('index',3)}">查询</a>
                     </li> @endcan
+                @can('入库管理-入库-缓存架入库')
+                <li class="nav-item">
+                    <a target="store/inStorage/index" class="nav-link" href="{{url('store/inStorage/cacheRackStorage')}}" :class="{active:isActive('cacheRackStorage',3)}">缓存架入库</a>
+                </li> @endcan
             </ul>
         </div>
     </div>

+ 14 - 2
resources/views/transport/waybill/index.blade.php

@@ -356,6 +356,11 @@
                     {name:'{{$owner->id}}',value:'{{$owner->name}}'},
                     @endforeach
                 ],
+                carTypes:[
+                        @foreach($carTypes as $carType)
+                    {name:'{{$carType->id}}',value:'{{$carType->name}}'},
+                    @endforeach
+                ],
                 logistics:[
                         @foreach($logistics as $logistic)
                     {name:"{{$logistic->id}}",value:'{{$logistic->name}}'},
@@ -391,23 +396,30 @@
                     [
                         {name:'owner_id',type:'select_multiple_select',tip:['输入关键词快速定位下拉列表,回车确定','选择要显示的客户'],
                             placeholder:['货主','定位或多选货主'],data:this.owners},
-                        {name:'created_at_start',type:'time',tip:['选择显示指定日期的起始时间','选择显示指定日期的起始时间']},
+                        {name:'created_at_start',type:'time',tip:['选择显示创建日期的起始时间','选择显示创建日期的起始时间']},
+                        {name:'updated_at_start',type:'time',tip:['选择显示完结日期的起始时间','选择显示完结日期的起始时间']},
+                        {name:'deliver_at_start',type:'time',tip:['选择显示发货日期的起始时间','选择显示发货日期的起始时间']},
                         {name:'origination',type:'input',tip:'始发地:可在左侧增加百分号(%)进行模糊搜索',placeholder: '始发地'},
                         {name:'carrier_bill',type:'input',tip:'可支持多承运商单号:可在左侧增加百分号(%)进行模糊搜索',placeholder: '承运商单号'},
                         {name:'status',type:'select',placeholder: '运单状态',data:this.status},
                         {name:'source_bill',type:'input',tip: '可支持多上游单号:可在左侧增加百分号(%)进行模糊搜索',placeholder: '上游单号'},
                         {name:'recipient',type:'input',tip: '可支持多收货人姓名:可在左侧增加百分号(%)进行模糊搜索',placeholder: '收货人姓名'},
                         {name:'car_owner_info',type:'input',tip: '车辆信息:可在左侧增加百分号(%)进行模糊搜索',placeholder: '车辆信息'},
+                        {name:'mileage',type:'input',tip: '里程:可在左侧增加百分号(%)进行模糊搜索',placeholder: '里程'},
                     ],
                     [
                         {name:'wms_bill_number',type:'input',tip:'可支持多WMS单号:可在两侧增加百分号(%)进行模糊搜索',placeholder: 'WMS单号'},
-                        {name:'created_at_end',type:'time',tip:['选择显示指定日期的结束时间','选择显示指定日期的结束时间']},
+                        {name:'created_at_end',type:'time',tip:['选择显示创建日期的结束时间','选择显示创建日期的结束时间']},
+                        {name:'updated_at_end',type:'time',tip:['选择显示完结日期的结束时间','选择显示完结日期的结束时间']},
+                        {name:'deliver_at_end',type:'time',tip:['选择显示发货日期的结束时间','选择显示发货日期的结束时间']},
                         {name:'destination',type:'input',tip:'目的地:可在两侧增加百分号(%)进行模糊搜索',placeholder: '目的地'},
                         {name:'waybill_number',type:'input',tip:'运单号:可在两侧增加百分号(%)进行模糊搜索',placeholder: '运单号'},
                         // {name:'logistic_id',type:'select',placeholder: '承运商',data:this.logistics},
                         {name:'logistic_id',type:'select_multiple_select',tip:['输入关键词快速定位下拉列表,回车确定','选择要显示的承运商'],
                             placeholder:['承运商','定位或多选承运商'],data:this.logistics},
                         {name:'recipient_mobile',type:'input',tip: '可支持多收货人电话:可在左侧增加百分号(%)进行模糊搜索',placeholder: '收货人电话'},
+                        {name:'carrier_weight_other',type:'input',tip: '仓库计重:可在左侧增加百分号(%)进行模糊搜索',placeholder: '仓库计重'},
+                        {name:'carType_id',type:'select',placeholder: '车型',data:this.carTypes},
                     ],
                 ];
                 let param=[];

+ 0 - 21
resources/views/unauthorized.blade.php/defaultException.blade.php

@@ -1,21 +0,0 @@
-@extends('layouts.app')
-@section('title')
-    页面出现错误,错误代码:{{$code}}
-@endsection
-@section('content')
-    <div class="container-fluid">
-        <div class="row justify-content-center">
-            <div class="col-md-8">
-                <div class="card">
-                    <div class="card-body">
-
-                        <h2 class="text-danger">页面出现错误,请刷新重试或联系管理员,错误代码:{{$code}}</h2>
-                        <a href="{{url('/')}}">
-                            <button class="btn btn-info">前往首页</button>
-                        </a>
-                    </div>
-                </div>
-            </div>
-        </div>
-    </div>
-@endsection

+ 1 - 0
routes/apiLocal.php

@@ -126,6 +126,7 @@ Route::group(['prefix'=>'control'],function () {
     Route::post('panel/menu/laborReportsCountingRecordApi','ControlPanelController@laborReportsCountingRecordApi');
     Route::post('panel/menu/laborReportsUserGroupsCountApi','ControlPanelController@laborReportsUserGroupsCountApi');
     Route::post('panel/menu/weightApi','ControlPanelController@weightApi');
+    Route::post('panel/menu/exceptionTypeApi','ControlPanelController@exceptionTypeApi');
 });
 
 /** 耗材 */

+ 3 - 1
routes/web.php

@@ -404,9 +404,10 @@ Route::resource('package','WeighController');
 Route::group(['prefix'=>'store'],function(){
     Route::group(['prefix'=>'inStorage'],function() {
         Route::get('index','StoreController@storage');
+        Route::get('cacheRackStorage','StoreController@cacheRackStorage');
     });
     Route::group(['prefix'=>'fast'],function() {
-        Route::resource('storeItem','StoreItemsController');
+        Route::resource('storeItem','StoreItemController');
     });
     Route::resource('fast',"StoreController");
 
@@ -552,6 +553,7 @@ Route::group(['prefix'=>'personnel'],function(){
         Route::group(['prefix'=>'task'],function(){
             Route::get('index','DischargeTaskController@index');
             Route::any('export','DischargeTaskController@export');
+            Route::any('receipt','DischargeTaskController@receipt');
         });
         /** 结算报表 */
         Route::group(['prefix'=>'statement'],function(){

+ 1 - 1
tests/Feature/LogisticZopSyncTest.php

@@ -39,7 +39,7 @@ class LogisticZopSyncTest extends TestCase
 
     public function test_get()
     {
-        LogisticZopSync::dispatch('73228204974140');
+        LogisticZopSync::dispatch('75600023806455');
     }
 
 

+ 100 - 0
tests/Services/CacheShelfService/CreateStationTask.php

@@ -0,0 +1,100 @@
+<?php
+
+
+namespace Tests\Services\CacheShelfService;
+
+
+use App\MaterialBox;
+use App\Services\CacheShelfService;
+use App\Services\ForeignHaiRoboticsService;
+use App\Services\StationTaskMaterialBoxService;
+use App\Services\StationTaskService;
+use App\Station;
+use App\StationTask;
+use App\StationTaskMaterialBox;
+use App\Traits\TestMockSubServices;
+use Tests\TestCase;
+
+class CreateStationTask extends TestCase
+{
+    use TestMockSubServices;
+
+    /** @var CacheShelfService $service */
+    protected $service;
+    /** @var StationTaskService $stationTaskService */
+    protected $stationTaskService;
+
+    protected $data = [];
+
+    /**
+     * createStationTask
+     * 注册站任务
+     * 注册站料箱任务
+     * 注册站任务子任务
+     */
+    protected function setUp(): void
+    {
+        parent::setUp();
+        $this->service = $this->subMock([
+            'class' => CacheShelfService::class,
+            'methods' => [
+                '_stationCacheLightOn' => new MaterialBox(['code' => 200])
+            ],
+            'subService' => [[
+                'serviceName' => 'foreignHaiRoboticsService',
+                'class' => ForeignHaiRoboticsService::class,
+                'methods' => [
+                    'controlHaiRobot' => true
+                ]
+            ], [
+                'serviceName' => 'stationTaskService',
+                'class' => StationTaskService::class
+            ], [
+                'serviceName' => 'stationTaskMaterialBoxService',
+                'class' => StationTaskMaterialBoxService::class,
+            ]
+            ]
+        ]);
+        $this->stationTaskService = $this->subMock([
+            'class' => StationTaskService::class,
+        ]);
+        $this->data['parentStation'] = factory(Station::class)->create();
+        $this->data['station'] = factory(Station::class)->create(['parent_id' => $this->data['parentStation']['id']]);
+        $this->data['materialBox'] = factory(MaterialBox::class)->create();
+    }
+
+    public function testCreatStationTask()
+    {
+        $data = $this->service->createStationTask($this->data['station']['code'], $this->data['materialBox']['code']);
+        $this->assertTrue($data['success']);
+
+        $stationTask = StationTask::query()->where('station_id', $this->data['station']['id'])->with('stationTaskMaterialBoxes')->first();
+        $stationTaskMaterialBox = StationTaskMaterialBox::query()->with('materialBox')->where('station_id', $this->data['station']['id'])->first();
+        $this->assertEquals($stationTask['status'], '待处理');
+        $this->assertEquals($stationTaskMaterialBox['materialBox']['code'], $this->data['materialBox']['code']);
+
+        $station = Station::query()->with(['pendingStationTask.stationTaskMaterialBoxes'])->where('id', $this->data['station']['id'])->first();
+        $this->assertEquals($station['pendingStationTask']['stationTaskMaterialBoxes']->first()['station_id'], $stationTask['station_id']);
+    }
+
+    public function testStationTaskIsExists()
+    {
+        $this->data['stationTask'] = $this->stationTaskService->create(1);
+        $this->stationTaskService->registerStations($this->data['stationTask'], [$this->data['station']['id']]);
+
+        $data = $this->service->createStationTask($this->data['station']['code'], $this->data['materialBox']['code']);
+        $this->assertFalse($data['success']);
+    }
+
+
+    protected function tearDown(): void
+    {
+        Station::query()->where('id', $this->data['station']['id'])->delete();
+        Station::query()->where('id', $this->data['parentStation']['id'])->delete();
+        StationTask::query()->where('station_id', $this->data['station']['id'])->delete();
+        MaterialBox::query()->where('id', $this->data['materialBox']['id'])->delete();
+        StationTaskMaterialBox::query()->where('station_id', $this->data['station']['id'])->delete();
+        if ($this->data['stationTask'] ?? false) StationTask::query()->whereIn('id', data_get($this->data['stationTask'], '*.id'))->delete();
+        parent::tearDown();
+    }
+}

+ 77 - 0
tests/Services/CacheShelfService/GetChildStationTest.php

@@ -0,0 +1,77 @@
+<?php
+
+
+namespace Tests\Services\CacheShelfService;
+
+use App\MaterialBox;
+use App\Services\CacheShelfService;
+use App\Station;
+use App\StationTask;
+use App\StationTaskChildren;
+use App\StationTaskMaterialBox;
+use App\StationType;
+use Faker\Factory;
+use Illuminate\Database\Eloquent\Collection;
+use Tests\TestCase;
+
+class GetChildStationTest extends TestCase
+{
+    /** @var CacheShelfService $service */
+    protected $service;
+
+    protected $data = [];
+
+    protected function setup(): void
+    {
+        parent::setup();
+        $this->service = app(CacheShelfService::class);
+
+        $stationType = StationType::query()->firstOrCreate(['name'=> '缓存架']);
+
+        $this->data['parentStation'] = factory(Station::class)->create(['station_type_id' => $stationType['id']]);
+        $this->data['station'] = factory(Station::class)->create(['parent_id'=>$this->data['parentStation']['id']]);
+        $this->data['materialBox'] = factory(MaterialBox::class)->create();
+        $this->data['stationTask'] = factory(StationTask::class)->create();
+        $this->data['stationTask']['station_id'] = $this->data['station']['id'];
+        $this->data['stationTask']->save();
+
+        $this->data['stationTaskMaterialBox'] = factory(StationTaskMaterialBox::class)->create([
+            'station_id' => $this->data['station']['id'],
+            'material_box_id' => $this->data['materialBox']['id'],
+            'status' => '待处理'
+        ]);
+
+        $this->data['stationTaskMaterialBox']['station_task_id'] = $this->data['stationTask']['id'];
+        $this->data['stationTaskMaterialBox']->save();
+
+        $this->data['stationTaskChildren']  = StationTaskChildren::query()->create([
+            "station_task_id" => $this->data['stationTask']['id'],
+        ]);
+    }
+
+    public function testGetTasks()
+    {
+        $grids = $this->service->getChildStation($this->data['station']['id']);
+        $this->assertTrue($grids ? true : false);
+    }
+
+
+    protected function tearDown(): void
+    {
+        $materialBox = MaterialBox::query()->where('id', $this->data['materialBox']['id'])->first();
+        if ($materialBox) {
+            $stationTaskMaterialBoxes = StationTaskMaterialBox::query()->where('material_box_id', $materialBox['id'])->get();
+            foreach ($stationTaskMaterialBoxes as $stationTaskMaterialBox) {
+                if($stationTaskMaterialBox->station->parent)$stationTaskMaterialBox->station->parent->delete();
+                if ($stationTaskMaterialBox->station) $stationTaskMaterialBox->station->delete();
+                if ($stationTaskMaterialBox->stationTask) $stationTaskMaterialBox->stationTask->delete();
+                $stationTaskMaterialBox->delete();
+            }
+            $materialBox->delete();
+        }
+        if($this->data['stationTaskChildren'])StationTaskChildren::query()->where('id',$this->data['stationTaskChildren']['id'])->delete();
+        parent::tearDown(); // TODO: Change the autogenerated stub
+    }
+
+
+}

Неке датотеке нису приказане због велике количине промена