Prechádzať zdrojové kódy

Merge branch 'master' into zzd

dream 5 rokov pred
rodič
commit
fff4bae4aa
32 zmenil súbory, kde vykonal 768 pridanie a 362 odobranie
  1. 11 47
      app/Http/Controllers/CacheShelfController.php
  2. 11 1
      app/Http/Controllers/DischargeTaskController.php
  3. 1 1
      app/Services/BatchService.php
  4. 137 58
      app/Services/CacheShelfService.php
  5. 2 3
      app/Services/ForeignHaiRoboticsService.php
  6. 1 1
      app/Services/OracleDocWaveDetailService.php
  7. 2 2
      app/Services/PackageStatisticsService.php
  8. 1 0
      app/Services/RejectedBillService.php
  9. 0 1
      app/Services/StationCacheShelfGridService.php
  10. 8 14
      app/Services/StationTaskMaterialBoxService.php
  11. 5 3
      app/Station.php
  12. 0 61
      app/StationCacheShelfGrid.php
  13. 28 0
      database/migrations/2021_04_29_133306_drop_station_cache_shelf_grips_table.php
  14. 180 0
      horizon.conf
  15. 0 1
      resources/views/demand/search/index.blade.php
  16. 10 4
      resources/views/personnel/discharge/task/_table.blade.php
  17. 12 0
      resources/views/personnel/discharge/task/index.blade.php
  18. 6 1
      resources/views/personnel/discharge/task/menu.blade.php
  19. 54 0
      resources/views/personnel/discharge/task/receipt.blade.php
  20. 7 15
      resources/views/station/cachingShelf/list/_fillBox.blade.php
  21. 0 9
      resources/views/station/cachingShelf/list/_table.blade.php
  22. 85 82
      resources/views/station/cachingShelf/list/index.blade.php
  23. 0 21
      resources/views/unauthorized.blade.php/defaultException.blade.php
  24. 1 0
      routes/web.php
  25. 0 1
      runServes.sh
  26. 92 0
      tests/Services/CacheShelfService/CreateStationTask.php
  27. 4 13
      tests/Services/CacheShelfService/GetTasksTest.php
  28. 6 13
      tests/Services/CacheShelfService/LightOffTaskTest.php
  29. 1 10
      tests/Services/CacheShelfService/PutBinToStoreTest.php
  30. 37 0
      tests/Services/CacheShelfService/StationCacheBroadCastTest.php
  31. 33 0
      tests/Services/CacheShelfService/StationCacheLightOffTest.php
  32. 33 0
      tests/Services/CacheShelfService/StationCacheLightOnTest.php

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

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

+ 1 - 1
app/Services/BatchService.php

@@ -106,7 +106,7 @@ class BatchService
                 $batchesJson.=json_encode($batch);
                 Cache::tags(['波次防重叠'.$batch['id']])->flush();
             }
-            throw new ErrorException('注册任务失败: '. $batchesJson . $e->getMessage().$e->getTrace());
+            throw new ErrorException('注册任务失败: '. $batchesJson . $e->getMessage().json_encode($e->getTrace()));
         }
     }
 

+ 137 - 58
app/Services/CacheShelfService.php

@@ -2,13 +2,16 @@
 
 namespace App\Services;
 
+use App\Events\BroadcastToStation;
 use App\Exceptions\ErrorException;
 use App\MaterialBox;
 use App\Station;
-use App\StationCacheShelfGrid;
 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
 {
@@ -17,32 +20,43 @@ class CacheShelfService
     protected $modelClass = Station::class;
     /** @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){
+                $this->_stationCacheLightOff($locCode);                     // 格口灭灯
+                $this->_stationCacheBroadCast($locCode,$PTLAction);         // 灭灯广播
+                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 +64,124 @@ 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');
 
         /** @var StationTaskMaterialBox $stationTaskMaterialBox */
-        $stationTaskMaterialBox = $this->stationTaskMaterialBoxService->createByStationAndMaterialBox($station, $materialBox);
-        $this->stationCacheShelfGridService->processGrid($grid, $station, $materialBox);
+        $stationTaskMaterialBox = $station['pendingStationTask']['stationTaskMaterialBoxes']->first();
+        return $this->foreignHaiRoboticsService->putBinToStore_fromCacheShelf($stationTaskMaterialBox);
+    }
+
+    /**
+     * 创建站任务和料箱任务
+     * @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]);
+        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']]);                                            // 注册站任务站
+        $params = [[
+                'station_task_id'=>$stationTask->first()['id'],
+                'station_taskable_type'=>StationTaskMaterialBox::class,
+                'station_taskable_id'=>$stationTaskMaterialBox['id']
+            ]];
+        $this->stationTaskChildService->insert($params);                                                                        // 任务任务注册
+        return['success'=>true];
+    }
 
-        return $this->foreignHaiRoboticsService->putBinToStore_fromCacheShelf($stationTaskMaterialBox);
+    /**
+     * 控制格口亮灯
+     * @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){
+        $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 $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());
-//    }
 }

+ 2 - 3
app/Services/ForeignHaiRoboticsService.php

@@ -272,10 +272,8 @@ class ForeignHaiRoboticsService
         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());
+        $formLocation = $stationTaskMaterialBox['station']['code'];
 
         /** 创建料箱 从缓存架 到 立架任务 */
         $dataToPost=$this->makeJson_move(
@@ -296,6 +294,7 @@ class ForeignHaiRoboticsService
                 'status' => $stationTaskMaterialBox['status']='处理中',
                 'station_id' => $stationTaskMaterialBox['station']['id']?? '',
             ]);
+            $stationTaskMaterialBox->stationTask()->update(['status' => '完成']);
         }
         return $controlSuccess;
     }

+ 1 - 1
app/Services/OracleDocWaveDetailService.php

@@ -99,7 +99,7 @@ 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);

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

+ 8 - 14
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;
@@ -179,25 +179,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);
         }
     }
 

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

+ 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()
+    {
+        //
+    }
+}

+ 180 - 0
horizon.conf

@@ -0,0 +1,180 @@
+; Sample supervisor config file.
+;
+; For more information on the config file, please see:
+; http://supervisord.org/configuration.html
+;
+; Notes:
+;  - Shell expansion ("~" or "$HOME") is not supported.  Environment
+;    variables can be expanded using this syntax: "%(ENV_HOME)s".
+;  - Quotes around values are not supported, except in the case of
+;    the environment= options as shown below.
+;  - Comments must have a leading space: "a=b ;comment" not "a=b;comment".
+;  - Command will be truncated if it looks like a config file comment, e.g.
+;    "command=bash -c 'foo ; bar'" will truncate to "command=bash -c 'foo ".
+;
+; Warning:
+;  Paths throughout this example file use /tmp because it is available on most
+;  systems.  You will likely need to change these to locations more appropriate
+;  for your system.  Some systems periodically delete older files in /tmp.
+;  Notably, if the socket file defined in the [unix_http_server] section below
+;  is deleted, supervisorctl will be unable to connect to supervisord.
+
+[unix_http_server]
+file=/tmp/supervisor.sock   ; the path to the socket file
+;chmod=0700                 ; socket file mode (default 0700)
+;chown=nobody:nogroup       ; socket file uid:gid owner
+;username=user              ; default is no username (open server)
+;password=123               ; default is no password (open server)
+
+; Security Warning:
+;  The inet HTTP server is not enabled by default.  The inet HTTP server is
+;  enabled by uncommenting the [inet_http_server] section below.  The inet
+;  HTTP server is intended for use within a trusted environment only.  It
+;  should only be bound to localhost or only accessible from within an
+;  isolated, trusted network.  The inet HTTP server does not support any
+;  form of encryption.  The inet HTTP server does not use authentication
+;  by default (see the username= and password= options to add authentication).
+;  Never expose the inet HTTP server to the public internet.
+
+;[inet_http_server]         ; inet (TCP) server disabled by default
+;port=127.0.0.1:9001        ; ip_address:port specifier, *:port for all iface
+;username=user              ; default is no username (open server)
+;password=123               ; default is no password (open server)
+
+[supervisord]
+logfile=/tmp/supervisord.log ; main log file; default $CWD/supervisord.log
+logfile_maxbytes=50MB        ; max main logfile bytes b4 rotation; default 50MB
+logfile_backups=10           ; # of main logfile backups; 0 means none, default 10
+loglevel=info                ; log level; default info; others: debug,warn,trace
+pidfile=/tmp/supervisord.pid ; supervisord pidfile; default supervisord.pid
+nodaemon=false               ; start in foreground if true; default false
+silent=false                 ; no logs to stdout if true; default false
+minfds=1024                  ; min. avail startup file descriptors; default 1024
+minprocs=200                 ; min. avail process descriptors;default 200
+;umask=022                   ; process file creation umask; default 022
+;user=supervisord            ; setuid to this UNIX account at startup; recommended if root
+;identifier=supervisor       ; supervisord identifier, default is 'supervisor'
+;directory=/tmp              ; default is not to cd during start
+;nocleanup=true              ; don't clean up tempfiles at start; default false
+;childlogdir=/tmp            ; 'AUTO' child log dir, default $TEMP
+;environment=KEY="value"     ; key value pairs to add to environment
+;strip_ansi=false            ; strip ansi escape codes in logs; def. false
+
+; The rpcinterface:supervisor section must remain in the config file for
+; RPC (supervisorctl/web interface) to work.  Additional interfaces may be
+; added by defining them in separate [rpcinterface:x] sections.
+
+[rpcinterface:supervisor]
+supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface
+
+; The supervisorctl section configures how supervisorctl will connect to
+; supervisord.  configure it match the settings in either the unix_http_server
+; or inet_http_server section.
+
+[supervisorctl]
+serverurl=unix:///tmp/supervisor.sock ; use a unix:// URL  for a unix socket
+;serverurl=http://127.0.0.1:9001 ; use an http:// url to specify an inet socket
+;username=chris              ; should be same as in [*_http_server] if set
+;password=123                ; should be same as in [*_http_server] if set
+;prompt=mysupervisor         ; cmd line prompt (default "supervisor")
+;history_file=~/.sc_history  ; use readline history if available
+
+; The sample program section below shows all possible program subsection values.
+; Create one or more 'real' program: sections to be able to control them under
+; supervisor.
+
+[program:artisan]
+process_name=%(program_name)s
+command=php /var/www/was/artisan horizon
+autostart=true
+autorestart=true
+user=baoshi
+redirect_stderr=true
+stdout_logfile=/var/www/was/storage/horizon.log
+stopwaitsecs=3600
+
+;[program:theprogramname]
+;command=/bin/cat              ; the program (relative uses PATH, can take args)
+;process_name=%(program_name)s ; process_name expr (default %(program_name)s)
+;numprocs=1                    ; number of processes copies to start (def 1)
+;directory=/tmp                ; directory to cwd to before exec (def no cwd)
+;umask=022                     ; umask for process (default None)
+;priority=999                  ; the relative start priority (default 999)
+;autostart=true                ; start at supervisord start (default: true)
+;startsecs=1                   ; # of secs prog must stay up to be running (def. 1)
+;startretries=3                ; max # of serial start failures when starting (default 3)
+;autorestart=unexpected        ; when to restart if exited after running (def: unexpected)
+;exitcodes=0                   ; 'expected' exit codes used with autorestart (default 0)
+;stopsignal=QUIT               ; signal used to kill process (default TERM)
+;stopwaitsecs=10               ; max num secs to wait b4 SIGKILL (default 10)
+;stopasgroup=false             ; send stop signal to the UNIX process group (default false)
+;killasgroup=false             ; SIGKILL the UNIX process group (def false)
+;user=chrism                   ; setuid to this UNIX account to run the program
+;redirect_stderr=true          ; redirect proc stderr to stdout (default false)
+;stdout_logfile=/a/path        ; stdout log path, NONE for none; default AUTO
+;stdout_logfile_maxbytes=1MB   ; max # logfile bytes b4 rotation (default 50MB)
+;stdout_logfile_backups=10     ; # of stdout logfile backups (0 means none, default 10)
+;stdout_capture_maxbytes=1MB   ; number of bytes in 'capturemode' (default 0)
+;stdout_events_enabled=false   ; emit events on stdout writes (default false)
+;stdout_syslog=false           ; send stdout to syslog with process name (default false)
+;stderr_logfile=/a/path        ; stderr log path, NONE for none; default AUTO
+;stderr_logfile_maxbytes=1MB   ; max # logfile bytes b4 rotation (default 50MB)
+;stderr_logfile_backups=10     ; # of stderr logfile backups (0 means none, default 10)
+;stderr_capture_maxbytes=1MB   ; number of bytes in 'capturemode' (default 0)
+;stderr_events_enabled=false   ; emit events on stderr writes (default false)
+;stderr_syslog=false           ; send stderr to syslog with process name (default false)
+;environment=A="1",B="2"       ; process environment additions (def no adds)
+;serverurl=AUTO                ; override serverurl computation (childutils)
+
+; The sample eventlistener section below shows all possible eventlistener
+; subsection values.  Create one or more 'real' eventlistener: sections to be
+; able to handle event notifications sent by supervisord.
+
+;[eventlistener:theeventlistenername]
+;command=/bin/eventlistener    ; the program (relative uses PATH, can take args)
+;process_name=%(program_name)s ; process_name expr (default %(program_name)s)
+;numprocs=1                    ; number of processes copies to start (def 1)
+;events=EVENT                  ; event notif. types to subscribe to (req'd)
+;buffer_size=10                ; event buffer queue size (default 10)
+;directory=/tmp                ; directory to cwd to before exec (def no cwd)
+;umask=022                     ; umask for process (default None)
+;priority=-1                   ; the relative start priority (default -1)
+;autostart=true                ; start at supervisord start (default: true)
+;startsecs=1                   ; # of secs prog must stay up to be running (def. 1)
+;startretries=3                ; max # of serial start failures when starting (default 3)
+;autorestart=unexpected        ; autorestart if exited after running (def: unexpected)
+;exitcodes=0                   ; 'expected' exit codes used with autorestart (default 0)
+;stopsignal=QUIT               ; signal used to kill process (default TERM)
+;stopwaitsecs=10               ; max num secs to wait b4 SIGKILL (default 10)
+;stopasgroup=false             ; send stop signal to the UNIX process group (default false)
+;killasgroup=false             ; SIGKILL the UNIX process group (def false)
+;user=chrism                   ; setuid to this UNIX account to run the program
+;redirect_stderr=false         ; redirect_stderr=true is not allowed for eventlisteners
+;stdout_logfile=/a/path        ; stdout log path, NONE for none; default AUTO
+;stdout_logfile_maxbytes=1MB   ; max # logfile bytes b4 rotation (default 50MB)
+;stdout_logfile_backups=10     ; # of stdout logfile backups (0 means none, default 10)
+;stdout_events_enabled=false   ; emit events on stdout writes (default false)
+;stdout_syslog=false           ; send stdout to syslog with process name (default false)
+;stderr_logfile=/a/path        ; stderr log path, NONE for none; default AUTO
+;stderr_logfile_maxbytes=1MB   ; max # logfile bytes b4 rotation (default 50MB)
+;stderr_logfile_backups=10     ; # of stderr logfile backups (0 means none, default 10)
+;stderr_events_enabled=false   ; emit events on stderr writes (default false)
+;stderr_syslog=false           ; send stderr to syslog with process name (default false)
+;environment=A="1",B="2"       ; process environment additions
+;serverurl=AUTO                ; override serverurl computation (childutils)
+
+; The sample group section below shows all possible group values.  Create one
+; or more 'real' group: sections to create "heterogeneous" process groups.
+
+;[group:thegroupname]
+;programs=progname1,progname2  ; each refers to 'x' in [program:x] definitions
+;priority=999                  ; the relative start priority (default 999)
+
+; The [include] section can just contain the "files" setting.  This
+; setting can list multiple files (separated by whitespace or
+; newlines).  It can also contain wildcards.  The filenames are
+; interpreted as relative to this file.  Included files *cannot*
+; include files themselves.
+
+;[include]
+;files = relative/directory/*.ini

+ 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 => {

+ 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

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

+ 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/web.php

@@ -551,6 +551,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(){

+ 0 - 1
runServes.sh

@@ -5,7 +5,6 @@ sudo ps -aux|grep goExport |grep -v grep|awk '{print $2}'|sudo xargs kill
 
 cd /var/www/was
 nohup sudo su root -c "laravel-echo-server start" >/dev/null 2>&1 &
-cd /var/www/was
 nohup sudo su baoshi -c "sudo supervisord -c /var/www/was/horizon.conf" >/dev/null 2>&1 &
 #nohup sudo su baoshi -c "php artisan queue:work --tries=2 --delay=2" >/dev/null 2>&1 &
 nohup sudo ./serves/goExports >/dev/null 2>&1 &

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

@@ -0,0 +1,92 @@
+<?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,
+            'subService' => [[
+                    'serviceName' => 'foreignHaiRoboticsService',
+                    'class' => ForeignHaiRoboticsService::class,
+                ], [
+                    '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'])StationTask::query()->whereIn('id',data_get($this->data['stationTask'],'*.id'))->delete();
+        parent::tearDown();
+    }
+}

+ 4 - 13
tests/Services/CacheShelfService/GetTasksTest.php

@@ -3,9 +3,9 @@
 
 namespace Tests\Services\CacheShelfService;
 
+use App\MaterialBox;
 use App\Services\CacheShelfService;
 use App\Station;
-use App\StationCacheShelfGrid;
 use Tests\TestCase;
 
 class GetTasksTest extends TestCase
@@ -20,28 +20,19 @@ class GetTasksTest extends TestCase
         parent::setup();
 
         $this->service = app(CacheShelfService::class);
-        $this->data['station'] = factory(Station::class)->create();
-        $collect = collect();
-        for ($i = 1; $i <= 8; $i++) {
-            $collect->push(StationCacheShelfGrid::query()->create([
-                'station_id' => $this->data['station']['id'] ?? '',
-                'grid_id' => $i,
-                'status' => 1,
-            ]));
-        }
-        $this->data['grids'] = $collect;
+        $this->data['parentStation'] = factory(Station::class)->create(['code' => '']);
+        $this->data['station'] = factory(Station::class)->create(['code'=>'','parent_id'=>$this->data['parentStation']['id']]);
+        $this->data['materialBox']=factory(MaterialBox::class)->create(['code'=> '']);
     }
 
     public function testGetTasks()
     {
         $grids = $this->service->getTasks($this->data['station']);
-        $this->assertEquals(count($grids), count($this->data['grids']));
     }
 
     protected function tearDown(): void
     {
         Station::query()->where('id', $this->data['station']['id'])->delete();
-        StationCacheShelfGrid::query()->where('station_id', $this->data['station']['id'])->delete();
         parent::tearDown(); // TODO: Change the autogenerated stub
     }
 

+ 6 - 13
tests/Services/CacheShelfService/LightOffTaskTest.php

@@ -6,9 +6,7 @@ namespace Tests\Services\CacheShelfService;
 use App\MaterialBox;
 use App\Services\CacheShelfService;
 use App\Services\ForeignHaiRoboticsService;
-use App\Services\StationCacheShelfGridService;
 use App\Station;
-use App\StationCacheShelfGrid;
 use App\StationTaskMaterialBox;
 use App\Traits\TestMockSubServices;
 use Tests\TestCase;
@@ -40,31 +38,26 @@ class LightOffTaskTest extends TestCase
         ]);
         $row = 2;
         $col = 1;
-        $gridIndex = ($row-1)*3 + (3-$col);
-        $this->data['station'] = factory(Station::class)->create();
-        $this->data['materialBox'] = factory(MaterialBox::class)->create();
-        $this->data['stationCacheShelfGrid'] = factory(StationCacheShelfGrid::class)
-            ->create(['station_id' => $this->data['station']['id'],'grid_id'=>$gridIndex,'material_box_id'=>$this->data['materialBox']['id']]);
+        $this->data['parentStation'] = factory(Station::class)->create(['code' => 'testParent']);
         $this->data['locCode'] = 'HAI'.$this->data['station']['code'].'-0'.$col.'-0'.$row;
+        $this->data['station'] = factory(Station::class)->create(['parent_id'=>$this->data['parentStation']['id'],'code' => $this->data['locCode']]);
+        $this->data['materialBox'] = factory(MaterialBox::class)->create(['code'=>'testMaterialBox']);
         $this->data['PTLAction'] = 0;
     }
 
     public function testLightOffTask()
     {
         $this->service->lightOffTask($this->data['locCode'],$this->data['PTLAction']);
-        $grid = StationCacheShelfGrid::query()->where('id',$this->data['stationCacheShelfGrid']['id'])->first();
         $task = StationTaskMaterialBox::query()->where('station_id',$this->data['station']['id'])->where('material_box_id',$this->data['materialBox']['id'])->first();
         $this->assertNotEmpty($task);
         $this->assertEquals($task['status'],'处理中');
-        $this->assertEquals($grid['material_id'],null);
     }
 
     protected function tearDown(): void
     {
-        Station::query()->where('id',$this->data['station']['id'])->delete();
-        StationCacheShelfGrid::query()->where('id',$this->data['stationCacheShelfGrid']['id'])->delete();
-        MaterialBox::query()->where('id',$this->data['materialBox']['id'])->delete();
+        Station::query()->whereIn('id',[$this->data['station']['id'],$this->data['parentStation']['id']])->delete();
+        MaterialBox::query()->whereIn('id',$this->data['materialBox']['id'])->delete();
         StationTaskMaterialBox::query()->where('station_id',$this->data['station']['id'])->where('material_box_id',$this->data['materialBox'])->delete();
-        parent::tearDown(); // TODO: Change the autogenerated stub
+        parent::tearDown();
     }
 }

+ 1 - 10
tests/Services/CacheShelfService/PutBinToStoreTest.php

@@ -6,9 +6,7 @@ use App\MaterialBox;
 use App\Services\CacheShelfService;
 use App\Services\ForeignHaiRoboticsService;
 use App\Services\StationCacheShelfGridService;
-use App\Services\StationTaskMaterialBoxService;
 use App\Station;
-use App\StationCacheShelfGrid;
 use App\StationTaskMaterialBox;
 use App\Traits\TestMockSubServices;
 use Tests\TestCase;
@@ -30,12 +28,6 @@ class PutBinToStoreTest extends TestCase
             'material_box_id' => $this->data['materialBox']['id'],
             'status' => 1
         ]);
-        $this->data['stationCacheShelfGrid'] = factory(StationCacheShelfGrid::class)->create([
-            'station_id'=>$this->data['station']['id'],
-            'material_box_id'=>$this->data['materialBox']['id'],
-            'status' => 1
-        ]);
-
 
 
         $this->cacheShelfService = $this->subMock([
@@ -69,7 +61,7 @@ class PutBinToStoreTest extends TestCase
 
     public function testPutBinToStore()
     {
-        $bool = $this->cacheShelfService->putBinToStore($this->data['station'],$this->data['materialBox'],$this->data['stationCacheShelfGrid']);
+        $bool = $this->cacheShelfService->putBinToStore($this->data['station'],);
         $boxTask = StationTaskMaterialBox::query()->where('station_id',$this->data['station']['id'])->where('material_box_id',$this->data['materialBox']['id'])->first();
         $this->assertTrue($bool);
         $this->assertNotEmpty($boxTask);
@@ -80,7 +72,6 @@ class PutBinToStoreTest extends TestCase
     {
         Station::query()->where('id',$this->data['station']['id'])->delete();
         MaterialBox::query()->where('id',$this->data['materialBox']['id'])->delete();
-        StationCacheShelfGrid::query()->where('id',$this->data['stationCacheShelfGrid']['id'])->delete();
         StationTaskMaterialBox::query()->where('id',$this->data['stationTaskMaterialBox']['id'])->delete();
         parent::tearDown();
     }

+ 37 - 0
tests/Services/CacheShelfService/StationCacheBroadCastTest.php

@@ -0,0 +1,37 @@
+<?php
+
+
+namespace Tests\Services\CacheShelfService;
+
+
+use App\MaterialBox;
+use App\Services\CacheShelfService;
+use App\Station;
+use Tests\TestCase;
+
+class StationCacheBroadCastTest extends TestCase
+{
+    /** @var CacheShelfService $service */
+    protected $service;
+    protected $data = [];
+
+    protected function setUp(): void
+    {
+        parent::setUp();
+        $this->service = app(CacheShelfService::class);
+        $this->data['parentStation'] = factory(Station::class)->create(['code'=>'testParent']);
+        $this->data['station']  = factory(Station::class)->create(['code' => 'test','parent_id' => $this->data['parentStation']]);
+        $this->data['materialBox'] = factory(MaterialBox::class)->create(['code'=>'testCode']);
+        $this->service->createStationTask($this->data['station']['code'],$this->data['materialBox']);
+    }
+
+    public function test(){
+        $this->service->_stationCacheBroadCast($this->data['station']['code'],0);
+    }
+
+    protected function tearDown(): void
+    {
+        Station::query()->whereIn('id',[$this->data['station']['id'],$this->data['parentStation']['0']]);
+        parent::tearDown();
+    }
+}

+ 33 - 0
tests/Services/CacheShelfService/StationCacheLightOffTest.php

@@ -0,0 +1,33 @@
+<?php
+
+
+namespace Tests\Services\CacheShelfService;
+
+
+use App\Services\CacheShelfService;
+use Tests\TestCase;
+
+class StationCacheLightOffTest extends TestCase
+{
+    /** @var CacheShelfService $service */
+    protected $service;
+    public $data = [];
+
+    protected function setUp(): void
+    {
+        parent::setUp();
+        $this->data['code'] = 'HAIB1-01-01';    // 修改此处可进行测试
+        $this->service = app(CacheShelfService::class);
+    }
+
+    public function testLightOff()
+    {
+        $body = $this->service->_stationCacheLightOff($this->data['code']);
+        $this->assertEquals($body->code,200);
+    }
+
+    protected function tearDown(): void
+    {
+        parent::tearDown();
+    }
+}

+ 33 - 0
tests/Services/CacheShelfService/StationCacheLightOnTest.php

@@ -0,0 +1,33 @@
+<?php
+
+
+namespace Tests\Services\CacheShelfService;
+
+use App\Services\CacheShelfService;
+use Tests\TestCase;
+
+class StationCacheLightOnTest extends TestCase
+{
+    /** @var CacheShelfService $service */
+    protected $service;
+    public $data = [];
+
+    protected function setUp(): void
+    {
+        parent::setUp(); // TODO: Change the autogenerated stub
+        $this->data['code'] = 'HAIB1-01-01';                // 修改此处可进行测试
+        $this->data['materialCode'] = 'IDE0005665';         // 修改此处可进行测试
+        $this->service = app(CacheShelfService::class);
+    }
+
+    public function testLightOn()
+    {
+        $body = $this->service->_stationCacheLightOn($this->data['code'], $this->data['materialCode']);
+        $this->assertEquals($body->code, 200);
+    }
+
+    protected function tearDown(): void
+    {
+        parent::tearDown(); // TODO: Change the autogenerated stub
+    }
+}