Просмотр исходного кода

称重二期需求(广播与语音合成未做)

Zhouzhendong 6 лет назад
Родитель
Сommit
1e65356447
49 измененных файлов с 2371 добавлено и 352 удалено
  1. 35 12
      app/Http/Controllers/MeasureMonitorController.php
  2. 102 11
      app/Http/Controllers/PackageController.php
  3. 28 0
      app/Http/Controllers/PaperBoxController.php
  4. 119 0
      app/Http/Controllers/WeighExceptedController.php
  5. 135 0
      app/Http/Controllers/api-speech/AipSpeech.php
  6. 1 0
      app/Http/Controllers/api-speech/lib/2d7933431e76f4dd9eeb4e604e68bcb5
  7. 367 0
      app/Http/Controllers/api-speech/lib/AipBCEUtil.php
  8. 343 0
      app/Http/Controllers/api-speech/lib/AipBase.php
  9. 192 0
      app/Http/Controllers/api-speech/lib/AipHttpClient.php
  10. 36 0
      app/Http/Controllers/api-speech/lib/AipImageUtil.php
  11. 130 0
      app/Imports/PaperBoxesImport.php
  12. 8 8
      app/Imports/WaybillPriceModelsImport.php
  13. 28 4
      app/Package.php
  14. 1 1
      app/WaybillPriceModel.php
  15. 31 0
      database/migrations/2020_02_09_080123_add_weigh_excepted_authority.php
  16. 48 0
      database/migrations/2020_02_10_103905_change_package_column.php
  17. BIN
      public/audio.mp3
  18. 0 0
      public/images/measuringMachine/off.png
  19. 0 0
      public/images/measuringMachine/on.png
  20. 4 1
      public/mix-manifest.json
  21. BIN
      public/off.png
  22. BIN
      public/on.png
  23. BIN
      resources/audio.mp3
  24. BIN
      resources/images/measuringMachine/off.png
  25. BIN
      resources/images/measuringMachine/on.png
  26. 2 2
      resources/views/layouts/menu.blade.php
  27. 1 1
      resources/views/maintenance/paperBox/create.blade.php
  28. 1 1
      resources/views/maintenance/paperBox/edit.blade.php
  29. 57 0
      resources/views/maintenance/paperBox/import.blade.php
  30. 5 1
      resources/views/maintenance/paperBox/menu.blade.php
  31. 1 1
      resources/views/maintenance/waybillPriceModel/index.blade.php
  32. 0 6
      resources/views/weigh/index.blade.php
  33. 0 103
      resources/views/weigh/measureMonitor/index.blade.php
  34. 0 20
      resources/views/weigh/menu.blade.php
  35. 0 169
      resources/views/weigh/package/index.blade.php
  36. 135 0
      resources/views/weight/measureMonitor/index.blade.php
  37. 26 0
      resources/views/weight/menu.blade.php
  38. 1 1
      resources/views/weight/menuWeight.blade.php
  39. 85 0
      resources/views/weight/package/create.blade.php
  40. 235 0
      resources/views/weight/package/index.blade.php
  41. 1 1
      resources/views/weight/package/menu.blade.php
  42. 180 0
      resources/views/weight/weightExcepted/index.blade.php
  43. 14 0
      resources/views/weight/weightExcepted/menu.blade.php
  44. 12 5
      routes/web.php
  45. 2 2
      tests/Unit/MeasureMonitorTest.php
  46. 2 2
      tests/Unit/PackageTest.php
  47. 0 0
      tests/codeCoverage/.js/d3.min.js
  48. 0 0
      tests/codeCoverage/.js/jquery.min.js
  49. 3 0
      webpack.mix.js

+ 35 - 12
app/Http/Controllers/MeasureMonitorController.php

@@ -7,9 +7,13 @@ use App\Package;
 use Illuminate\Http\Request;
 use Illuminate\Support\Facades\DB;
 use Illuminate\Support\Facades\Gate;
-
+require_once 'api-speech/AipSpeech.php';
 class MeasureMonitorController extends Controller
 {
+
+    const APP_ID='18433903';
+    const API_KEY='3pfojF55BI9LFfXdaI8wRyV2';
+    const SECRET_KEY='ZRSZWUPNgRNrdm4gBQ5Gf0c1oANN4mnd';
     /**
      * Display a listing of the resource.
      *
@@ -27,8 +31,7 @@ class MeasureMonitorController extends Controller
         dd($measuring_machine_id);*/
         $measuring_machine_id=$request->input('id');
         $measuringMachines=MeasuringMachine::select('id','name','code')->get();
-        if (empty($measuringMachines)){
-            dd($measuringMachines);
+        if ($measuringMachines){
             if (!$measuring_machine_id){
                 $package=Package::with('owner','paperBox','measuringMachine')->where('measuring_machine_id',$measuringMachines[0]->id)->orderBy('id','DESC')->first();
             }else{
@@ -40,17 +43,37 @@ class MeasureMonitorController extends Controller
                 }
             }
         }
-        return view('weigh.measureMonitor.index',['package'=>isset($package)?$package:null,'measuringMachines'=>$measuringMachines]);
+        return view('weight.measureMonitor.index',['package'=>isset($package)?$package:null,'measuringMachines'=>$measuringMachines]);
     }
 
-    /**
-     * Show the form for creating a new resource.
-     *
-     * @return \Illuminate\Http\Response
-     */
-    public function create()
-    {
-        //
+
+    public function flush(Request $request){
+        $measuring_machine_id=$request->input('id');
+        if ($measuring_machine_id){
+            $package=Package::with('owner','paperBox','measuringMachine')->where('measuring_machine_id',$measuring_machine_id)->orderBy('id','DESC')->first();
+            if (!$package){
+                $measuringMachine=MeasuringMachine::where('id',$measuring_machine_id)->first();
+                $package=new Package();
+                if ($measuringMachine)$package->measuringMachine=$measuringMachine;
+            }
+            return $package;
+        }
+            return false;
+    }
+
+
+    public function speech(){
+        $client=new \AipSpeech(self::APP_ID,self::API_KEY,self::SECRET_KEY);
+        $client->setConnectionTimeoutInMillis('180000');
+        $client->setSocketTimeoutInMillis('180000');
+        $result = $client->synthesis('你好百度', 'zh', 1, array(
+            'vol' => 5,
+        ));
+
+        // 识别正确返回语音二进制 错误则返回json 参照下面错误码
+        if(!is_array($result)){
+            file_put_contents('audio.mp3', $result);
+        }
     }
 
     /**

+ 102 - 11
app/Http/Controllers/PackageController.php

@@ -2,10 +2,15 @@
 
 namespace App\Http\Controllers;
 
+use App\Exports\WaybillExport;
 use App\Owner;
 use App\Package;
+use App\PaperBox;
+use Carbon\Carbon;
 use Illuminate\Http\Request;
 use Illuminate\Support\Facades\Gate;
+use Illuminate\Support\Facades\Validator;
+use Maatwebsite\Excel\Facades\Excel;
 
 class PackageController extends Controller
 {
@@ -18,26 +23,30 @@ class PackageController extends Controller
     {
         if(!Gate::allows('包裹信息-查询')){ return redirect(url('/'));  }
         if ($request->input()){
-            $packages=Package::with('owner','paperBox','measuringMachine')->orderBy('id','DESC');
+            $packages=Package::orderBy('id','DESC');
+            $today=Carbon::now()->subDays(15);
             if ($request->input('logistic_number')){
-                $packages=$packages->where('logistic_number',$request->input('logistic_number'));
+                $packages=$packages->where('logistic_number','like','%'.$request->input('logistic_number').'%')->where('created_at','>',$today->format('Y-m-d'));
             }
-            if ($request->input('type')){
-                $packages=$packages->where('type',$request->input('type'));
+            if ($request->input('delivery_number')){
+                $packages=$packages->where('delivery_number','like','%'.$request->input('delivery_number').'%')->where('created_at','>',$today->format('Y-m-d'));
             }
-            if ($request->input('status')){
-                $packages=$packages->where('status',$request->input('status'));
+            if ($request->input('created_at_start')){
+                $packages=$packages->where('created_at','>=',$request->input('created_at_start'));
+            }
+            if ($request->input('created_at_end')){
+                $packages=$packages->where('created_at','<=',$request->input('created_at_end'));
             }
             if ($request->input('owner_id')){
                 $packages=$packages->where('owner_id',$request->input('owner_id'));
             }
             $packages=$packages->paginate($request->input('paginate')?$request->input('paginate'):50);
             $owners=Owner::select('id','name')->get();
-            return view('weigh.package.index',['packages'=>$packages,'owners'=>$owners]);
+            return view('weight.package.index',['packages'=>$packages,'owners'=>$owners]);
         }
-        $packages=Package::with('owner','paperBox','measuringMachine')->orderBy('id','DESC')->paginate(50);
+        $packages=Package::orderBy('id','DESC')->paginate(50);
         $owners=Owner::select('id','name')->get();
-        return view('weigh.package.index',['packages'=>$packages,'owners'=>$owners]);
+        return view('weight.package.index',['packages'=>$packages,'owners'=>$owners]);
     }
 
     /**
@@ -47,7 +56,9 @@ class PackageController extends Controller
      */
     public function create()
     {
-        //
+        if(!Gate::allows('包裹信息-录入')){ return redirect(url('/'));  }
+        $paperBoxes=PaperBox::select('id','model')->get();
+        return view('weight.package.create',['paperBoxes'=>$paperBoxes]);
     }
 
     /**
@@ -58,7 +69,18 @@ class PackageController extends Controller
      */
     public function store(Request $request)
     {
-        //
+        if(!Gate::allows('包裹信息-录入')){ return redirect(url('/'));  }
+        $this->validator($request)->validate();
+        $logistic_number=$request->input('logistic_number');
+        $weight=$request->input('weight');
+        $paper_box_id=$request->input('paper_box_id');
+        $package=new Package([
+            'logistic_number'=>$logistic_number,
+            'weight'=>$weight,
+            'paper_box_id'=>$paper_box_id
+        ]);
+        $package->save();
+        return redirect('weight/package/create')->with('successTip','新记录“'.$logistic_number.'”录入成功');
     }
 
     /**
@@ -105,4 +127,73 @@ class PackageController extends Controller
     {
         //
     }
+
+    public function export($id){
+        $id = explode( ',',$id);
+        $row=[[
+            'id'=>'ID',
+            'owner_name'=>'货主',
+            'logistic_number'=>'快递单号',
+            'delivery_number'=>'发货单号',
+            'batch_number'=>'波次号',
+            'batch_rule'=>'波次规则',
+            'created_at'=>'操作时间',
+            'recipient'=>'收件人',
+            'recipient_mobile'=>'收件人电话',
+            'logistic_name'=>'承运商',
+            'measuringMachine_name'=>'设备',
+            'weight'=>'重量(KG)',
+            'length'=>'长(CM)',
+            'width'=>'宽(CM)',
+            'height'=>'高(CM)',
+            'bulk'=>'体积(CM³)',
+            'paperBox_name'=>'纸箱',
+            'status'=>'状态',
+        ]];
+        $list=[];
+        for ($i=0; $i<count($id);$i++){
+            $package=Package::find($id[$i]);
+            $w=[
+                'id'=>isset($package->id)?$package->id:'',
+                'owner_name'=>isset($package->owner_name)?$package->owner_name:'',
+                'logistic_number'=>isset($package->logistic_number)?$package->logistic_number:'',
+                'delivery_number'=>isset($package->delivery_number)?$package->delivery_number:'',
+                'batch_number'=>isset($package->batch_number)?$package->batch_number:'',
+                'batch_rule'=>isset($package->batch_rule)?$package->batch_rule:'',
+                'created_at'=>isset($package->created_at)?$package->created_at:'',
+                'recipient'=>isset($package->recipient)?$package->recipient:'',
+                'recipient_mobile'=>isset($package->recipient_mobile)?$package->recipient_mobile:'',
+                'logistic_name'=>isset($package->logistic_name)?$package->logistic_name:'',
+                'measuringMachine_name'=>isset($package->measuringMachine_name)?$package->measuringMachine_name:'',
+                'weight'=>isset($package->weight)?$package->weight:'',
+                'length'=>isset($package->length)?$package->length:'',
+                'width'=>isset($package->width)?$package->width:'',
+                'height'=>isset($package->height)?$package->height:'',
+                'bulk'=>isset($package->bulk)?$package->bulk:'',
+                'paperBox_name'=>isset($package->paperBox_name)?$package->paperBox_name:'',
+                'status'=>isset($package->status)?$package->status:''
+            ];
+            $list[$i]=$w;
+        }
+        return Excel::download(new WaybillExport($row,$list),date('YmdHis', time()).'-称重记录单.xls');
+    }
+    protected function validator(Request $request){
+        $validator=Validator::make($request->input(),[
+            'logistic_number'=>['required','max:50','unique:packages,logistic_number'],
+            'weight'=>'required|min:0|max:999999|numeric',
+            'paper_box_id'=>'required|integer',
+        ],[
+            'required'=>':attribute 为必填项',
+            'max'=>':attribute 字符过多或输入值过大',
+            'integer'=>':attribute 选择有误',
+            'min'=>':attribute 不得为负',
+            'numeric'=>':attribute 应为数字',
+            'unique'=>':attribute 已存在',
+        ],[
+            'logistic_number'=>'快递单号',
+            'weight'=>'重量',
+            'paper_box_id'=>'纸箱',
+        ]);
+        return $validator;
+    }
 }

+ 28 - 0
app/Http/Controllers/PaperBoxController.php

@@ -3,12 +3,15 @@
 namespace App\Http\Controllers;
 
 
+use App\Imports\PaperBoxesImport;
 use App\Owner;
 use App\PaperBox;
 use Illuminate\Http\Request;
 use Illuminate\Support\Facades\Auth;
+use Illuminate\Support\Facades\Cache;
 use Illuminate\Support\Facades\Gate;
 use Illuminate\Support\Facades\Validator;
+use Maatwebsite\Excel\Facades\Excel;
 
 class PaperBoxController extends Controller
 {
@@ -154,6 +157,31 @@ class PaperBoxController extends Controller
         }
     }
 
+    public function import(Request $request){
+        if(!Gate::allows('纸箱-录入')){ return redirect(url('/'));  }
+        $fileSuffix=$request->file('file')->getClientOriginalExtension();
+        if ($fileSuffix=='xlsx'||$fileSuffix=='xlsm'||$fileSuffix=='xltx'||$fileSuffix=='xltm'||$fileSuffix=='xls'||$fileSuffix=='xlt'||$fileSuffix=='ods'||$fileSuffix=='ots'||$fileSuffix=='slk'
+            ||$fileSuffix=='xml'||$fileSuffix=='gnumeric'||$fileSuffix=='htm'||$fileSuffix=='html'||$fileSuffix=='csv'||$fileSuffix=='tsv'){
+            $isOverride = $request->input('isOverride');
+            ini_set('max_execution_time',2100);
+            ini_set('memory_limit','512M');
+            $extension=$request->file()['file']->getClientOriginalExtension();
+            $extension[0] = strtoupper($extension[0]);
+            Excel::import(new PaperBoxesImport($isOverride),$request->file()['file']->path(),null,$extension);
+            if (Cache::has('error')){
+                return '<h1 class="text-danger">导入Excel失败<br><p style="color: red">'.Cache::pull('error').'</p></h1>';
+            }else{
+                $exception=Cache::get('exception');
+                $a='';
+                for ($i=0;$i<count($exception);$i++){$a.=implode(',',$exception[$i]).'&#10'; };
+                $this->log(__METHOD__,__FUNCTION__,json_encode($request->toArray()),Auth::user()['id']);
+                return '<h1 class="text-danger">导入Excel成功<br><textarea style="width: 50%;height: 50%">'.$a.'</textarea></h1>';
+            }
+        }else{
+            return '<h1 class="text-danger">失败<br><p style="color: red">不支持该文件类型</p></h1>';
+        }
+    }
+
     public function validator(Request $request,$id){
         if ($id){$model=$id;}
         $validator=Validator::make($request->input(),[

+ 119 - 0
app/Http/Controllers/WeighExceptedController.php

@@ -0,0 +1,119 @@
+<?php
+
+namespace App\Http\Controllers;
+
+use App\Exports\WaybillExport;
+use App\Package;
+use Illuminate\Http\Request;
+use Illuminate\Support\Facades\Auth;
+use Illuminate\Support\Facades\Gate;
+use Maatwebsite\Excel\Facades\Excel;
+
+class WeighExceptedController extends Controller
+{
+    /**
+     * Display a listing of the resource.
+     *
+     * @return \Illuminate\Http\Response
+     */
+    public function indexCreate(Request $request)
+    {
+        $paginate=$request->input('paginate');
+        if ($paginate){
+            $weightExcepteds=Package::select('id','logistic_number','logistic_id','measuring_machine_id','created_at','weight','length','width','height','bulk','paper_box_id')->
+            where('status','上传异常')->orderBy('created_at','DESC')->paginate($paginate);
+        }else{
+            $weightExcepteds=Package::select('id','logistic_number','logistic_id','measuring_machine_id','created_at','weight','length','width','height','bulk','paper_box_id')->
+            where('status','上传异常')->orderBy('created_at','DESC')->paginate(50);
+        };
+        return view('weight.weightExcepted.index',['weightExcepteds'=>$weightExcepteds,'view'=>'indexCreate']);
+    }
+
+    public function indexIssued(Request $request)
+    {
+        $paginate=$request->input('paginate');
+        if ($paginate){
+            $weightExcepteds=Package::select('id','owner_id','logistic_number','created_at','delivery_number','batch_number','batch_rule','recipient','recipient_mobile','logistic_id')->
+            where('status','下发异常')->orderBy('created_at','DESC')->paginate($paginate);
+        }else{
+            $weightExcepteds=Package::select('id','owner_id','logistic_number','created_at','delivery_number','batch_number','batch_rule','recipient','recipient_mobile','logistic_id')->
+            where('status','下发异常')->orderBy('created_at','DESC')->paginate(50);
+        };
+        return view('weight.weightExcepted.index',['weightExcepteds'=>$weightExcepteds,'view'=>'indexIssued']);
+    }
+
+   public function export($id){
+       $id = explode( ',',$id);
+       $weighExcepted=Package::find($id[0]);
+       if ($weighExcepted->status=="上传异常"){
+           $row=[[
+               'id'=>'ID',
+               'logistic_number'=>'快递单号',
+               'logistic_name'=>'承运商',
+               'measuringMachine_name'=>'设备',
+               'weigh_time'=>'称重时间',
+               'weight'=>'重(KG)',
+               'length'=>'长(CM)',
+               'width'=>'宽(CM)',
+               'height'=>'高(CM)',
+               'bulk'=>'体积(CM³)',
+               'paperBox_name'=>'纸箱',
+               'genre'=>'异常类型',
+               'created_at'=>'称重时间',
+               'status'=>'异常类型',
+           ]];
+           $list=[];
+           for ($i=0; $i<count($id);$i++){
+               $weighExcepted=Package::find($id[$i]);
+               $w=[
+                   'id'=>isset($weighExcepted->id)?$weighExcepted->id:'',
+                   'logistic_number'=>isset($weighExcepted->logistic_number)?$weighExcepted->logistic_number:'',
+                   'logistic_name'=>isset($weighExcepted->logistic_name)?$weighExcepted->logistic_name:'',
+                   'measuringMachine_name'=>isset($weighExcepted->measuringMachine_name)?$weighExcepted->measuringMachine_name:'',
+                   'weigh_time'=>isset($weighExcepted->weigh_time)?$weighExcepted->weigh_time:'',
+                   'weight'=>isset($weighExcepted->weight)?$weighExcepted->weight:'',
+                   'length'=>isset($weighExcepted->length)?$weighExcepted->length:'',
+                   'width'=>isset($weighExcepted->width)?$weighExcepted->width:'',
+                   'bulk'=>isset($weighExcepted->bulk)?$weighExcepted->bulk:'',
+                   'height'=>isset($weighExcepted->height)?$weighExcepted->height:'',
+                   'paperBox_name'=>isset($weighExcepted->paperBox_name)?$weighExcepted->paperBox_name:'',
+                   'genre'=>isset($weighExcepted->genre)?$weighExcepted->genre:'',
+                   'created_at'=>isset($weighExcepted->created_at)?$weighExcepted->created_at:'',
+                   'status'=>isset($weighExcepted->status)?$weighExcepted->status:''
+               ];
+               $list[$i]=$w;
+           }
+       }else{
+           $row=[[
+               'id'=>'ID',
+               'logistic_number'=>'快递单号',
+               'created_at'=>'下发时间',
+               'delivery_number'=>'发货单号',
+               'batch_number'=>'波次号',
+               'batch_rule'=>'波次规则',
+               'recipient'=>'收件人',
+               'recipient_mobile'=>'收件人电话',
+               'logistic_name'=>'承运商',
+               'status'=>'异常类型',
+           ]];
+           $list=[];
+           for ($i=0; $i<count($id);$i++){
+               $weighExcepted=Package::find($id[$i]);
+               $w=[
+                   'id'=>isset($weighExcepted->id)?$weighExcepted->id:'',
+                   'logistic_number'=>isset($weighExcepted->logistic_number)?$weighExcepted->logistic_number:'',
+                   'logistic_name'=>isset($weighExcepted->logistic_name)?$weighExcepted->logistic_name:'',
+                   'created_at'=>isset($weighExcepted->created_at)?$weighExcepted->created_at:'',
+                   'delivery_number'=>isset($weighExcepted->delivery_number)?$weighExcepted->delivery_number:'',
+                   'batch_number'=>isset($weighExcepted->batch_number)?$weighExcepted->batch_number:'',
+                   'batch_rule'=>isset($weighExcepted->batch_rule)?$weighExcepted->batch_rule:'',
+                   'recipient'=>isset($weighExcepted->recipient)?$weighExcepted->recipient:'',
+                   'recipient_mobile'=>isset($weighExcepted->recipient_mobile)?$weighExcepted->recipient_mobile:'',
+                   'status'=>isset($weighExcepted->status)?$weighExcepted->status:'',
+               ];
+               $list[$i]=$w;
+           }
+       }
+       return Excel::download(new WaybillExport($row,$list), date('YmdHis', time()). '称重异常单.xls');
+   }
+}

+ 135 - 0
app/Http/Controllers/api-speech/AipSpeech.php

@@ -0,0 +1,135 @@
+<?php
+/*
+* Copyright (c) 2017 Baidu.com, Inc. All Rights Reserved
+*
+* Licensed under the Apache License, Version 2.0 (the "License"); you may not
+* use this file except in compliance with the License. You may obtain a copy of
+* the License at
+*
+* Http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+* License for the specific language governing permissions and limitations under
+* the License.
+*/
+
+require_once 'lib/AipBase.php';
+
+/**
+ * 百度语音
+ */
+class AipSpeech extends AipBase{
+
+    /**
+     * url
+     * @var string
+     */
+    public $asrUrl = 'http://vop.baidu.com/server_api';
+
+    /**
+     * url
+     * @var string
+     */
+    public $ttsUrl = 'http://tsn.baidu.com/text2audio';
+
+    /**
+     * 判断认证是否有权限
+     * @param  array   $authObj 
+     * @return boolean          
+     */
+    protected function isPermission($authObj)
+    {
+        return true;
+    }
+
+    /**
+     * 处理请求参数
+     * @param string $url
+     * @param array $params
+     * @param array $data
+     * @param array $headers
+     */
+    protected function proccessRequest($url, &$params, &$data, $headers){
+
+        $token = isset($params['access_token']) ? $params['access_token'] : '';
+        $data['cuid'] = md5($token);
+
+        if($url === $this->asrUrl){
+            $data['token'] = $token;
+            $data = json_encode($data);
+        }else{
+            $data['tok'] = $token;
+        }
+
+        unset($params['access_token']);
+    }
+
+    /**
+     * 格式化结果
+     * @param $content string
+     * @return mixed
+     */
+    protected function proccessResult($content){
+        $obj = json_decode($content, true);
+
+        if($obj === null){
+            $obj = array(
+                'content' => $content
+            );
+        }
+
+        return $obj;
+    }
+
+    /**
+     * @param  string $speech
+     * @param  string $format
+     * @param  int $rate
+     * @param  array $options
+     * @return array
+     */
+    public function asr($speech, $format, $rate, $options=array()){
+        $data = array();
+
+        if(!empty($speech)){
+            $data['speech'] = base64_encode($speech);
+            $data['len'] = strlen($speech);
+        }
+
+        $data['format'] = $format;
+        $data['rate'] = $rate;
+        $data['channel'] = 1;
+
+        $data = array_merge($data, $options);  
+
+        return $this->request($this->asrUrl, $data, array());
+    }
+
+    /**
+     * @param  string $text
+     * @param  string $lang
+     * @param  int $ctp
+     * @param  array $options
+     * @return array
+     */
+    public function synthesis($text, $lang='zh', $ctp=1, $options=array()){
+        $data = array();
+
+        $data['tex'] = $text;
+        $data['lan'] = $lang;
+        $data['ctp'] = $ctp;
+
+        $data = array_merge($data, $options);  
+
+        $result = $this->request($this->ttsUrl, $data, array());
+
+        if(!isset($result['err_no'])){
+            return $result['content'];
+        }
+
+        return $result;
+    }
+
+}

+ 1 - 0
app/Http/Controllers/api-speech/lib/2d7933431e76f4dd9eeb4e604e68bcb5

@@ -0,0 +1 @@
+{"refresh_token":"25.eeec2920c4570672b5576afb09b84541.315360000.1896687196.282335-18433903","expires_in":2592000,"session_key":"9mzdX+7jU7Gg2Qa0kT2WcY262oXOdCHJK1JJ6xc358dRvTEgzYmlSy8MY2J7k8i6SzILlbrddNB7oR9CWKJEQNk8lo1d4w==","access_token":"24.d42d9fbc247dee820fc92347acb080e5.2592000.1583919196.282335-18433903","scope":"audio_voice_assistant_get brain_enhanced_asr audio_tts_post public brain_all_scope picchain_test_picchain_api_scope wise_adapt lebo_resource_base lightservice_public hetu_basic lightcms_map_poi kaidian_kaidian ApsMisTest_Test\u6743\u9650 vis-classify_flower lpq_\u5f00\u653e cop_helloScope ApsMis_fangdi_permission smartapp_snsapi_base iop_autocar oauth_tp_app smartapp_smart_game_openapi oauth_sessionkey smartapp_swanid_verify smartapp_opensource_openapi smartapp_opensource_recapi fake_face_detect_\u5f00\u653eScope vis-ocr_\u865a\u62df\u4eba\u7269\u52a9\u7406 idl-video_\u865a\u62df\u4eba\u7269\u52a9\u7406","session_secret":"ffead248a50db54cc23adb7b48e9fa21","time":1581327194,"is_cloud_user":false}

+ 367 - 0
app/Http/Controllers/api-speech/lib/AipBCEUtil.php

@@ -0,0 +1,367 @@
+<?php
+/*
+* Copyright (c) 2017 Baidu.com, Inc. All Rights Reserved
+*
+* Licensed under the Apache License, Version 2.0 (the "License"); you may not
+* use this file except in compliance with the License. You may obtain a copy of
+* the License at
+*
+* Http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+* License for the specific language governing permissions and limitations under
+* the License.
+*/
+
+/**
+ * BCE Util
+ */
+class AipHttpUtil
+{
+    // 根据RFC 3986,除了:
+    //   1.大小写英文字符
+    //   2.阿拉伯数字
+    //   3.点'.'、波浪线'~'、减号'-'以及下划线'_'
+    // 以外都要编码
+    public static $PERCENT_ENCODED_STRINGS;
+
+    //填充编码数组
+    public static function __init()
+    {
+        AipHttpUtil::$PERCENT_ENCODED_STRINGS = array();
+        for ($i = 0; $i < 256; ++$i) {
+            AipHttpUtil::$PERCENT_ENCODED_STRINGS[$i] = sprintf("%%%02X", $i);
+        }
+
+        //a-z不编码
+        foreach (range('a', 'z') as $ch) {
+            AipHttpUtil::$PERCENT_ENCODED_STRINGS[ord($ch)] = $ch;
+        }
+
+        //A-Z不编码
+        foreach (range('A', 'Z') as $ch) {
+            AipHttpUtil::$PERCENT_ENCODED_STRINGS[ord($ch)] = $ch;
+        }
+
+        //0-9不编码
+        foreach (range('0', '9') as $ch) {
+            AipHttpUtil::$PERCENT_ENCODED_STRINGS[ord($ch)] = $ch;
+        }
+
+        //以下4个字符不编码
+        AipHttpUtil::$PERCENT_ENCODED_STRINGS[ord('-')] = '-';
+        AipHttpUtil::$PERCENT_ENCODED_STRINGS[ord('.')] = '.';
+        AipHttpUtil::$PERCENT_ENCODED_STRINGS[ord('_')] = '_';
+        AipHttpUtil::$PERCENT_ENCODED_STRINGS[ord('~')] = '~';
+    }
+
+    /**
+     * 在uri编码中不能对'/'编码
+     * @param  string $path
+     * @return string
+     */
+    public static function urlEncodeExceptSlash($path)
+    {
+        return str_replace("%2F", "/", AipHttpUtil::urlEncode($path));
+    }
+
+    /**
+     * 使用编码数组编码
+     * @param  string $path
+     * @return string
+     */
+    public static function urlEncode($value)
+    {
+        $result = '';
+        for ($i = 0; $i < strlen($value); ++$i) {
+            $result .= AipHttpUtil::$PERCENT_ENCODED_STRINGS[ord($value[$i])];
+        }
+        return $result;
+    }
+
+    /**
+     * 生成标准化QueryString
+     * @param  array $parameters
+     * @return array
+     */
+    public static function getCanonicalQueryString(array $parameters)
+    {
+        //没有参数,直接返回空串
+        if (count($parameters) == 0) {
+            return '';
+        }
+
+        $parameterStrings = array();
+        foreach ($parameters as $k => $v) {
+            //跳过Authorization字段
+            if (strcasecmp('Authorization', $k) == 0) {
+                continue;
+            }
+            if (!isset($k)) {
+                throw new \InvalidArgumentException(
+                    "parameter key should not be null"
+                );
+            }
+            if (isset($v)) {
+                //对于有值的,编码后放在=号两边
+                $parameterStrings[] = AipHttpUtil::urlEncode($k)
+                    . '=' . AipHttpUtil::urlEncode((string) $v);
+            } else {
+                //对于没有值的,只将key编码后放在=号的左边,右边留空
+                $parameterStrings[] = AipHttpUtil::urlEncode($k) . '=';
+            }
+        }
+        //按照字典序排序
+        sort($parameterStrings);
+
+        //使用'&'符号连接它们
+        return implode('&', $parameterStrings);
+    }
+
+    /**
+     * 生成标准化uri
+     * @param  string $path
+     * @return string
+     */
+    public static function getCanonicalURIPath($path)
+    {
+        //空路径设置为'/'
+        if (empty($path)) {
+            return '/';
+        } else {
+            //所有的uri必须以'/'开头
+            if ($path[0] == '/') {
+                return AipHttpUtil::urlEncodeExceptSlash($path);
+            } else {
+                return '/' . AipHttpUtil::urlEncodeExceptSlash($path);
+            }
+        }
+    }
+
+    /**
+     * 生成标准化http请求头串
+     * @param  array $headers
+     * @return array
+     */
+    public static function getCanonicalHeaders($headers)
+    {
+        //如果没有headers,则返回空串
+        if (count($headers) == 0) {
+            return '';
+        }
+
+        $headerStrings = array();
+        foreach ($headers as $k => $v) {
+            //跳过key为null的
+            if ($k === null) {
+                continue;
+            }
+            //如果value为null,则赋值为空串
+            if ($v === null) {
+                $v = '';
+            }
+            //trim后再encode,之后使用':'号连接起来
+            $headerStrings[] = AipHttpUtil::urlEncode(strtolower(trim($k))) . ':' . AipHttpUtil::urlEncode(trim($v));
+        }
+        //字典序排序
+        sort($headerStrings);
+
+        //用'\n'把它们连接起来
+        return implode("\n", $headerStrings);
+    }
+}
+AipHttpUtil::__init();
+
+
+class AipSignOption
+{
+    const EXPIRATION_IN_SECONDS = 'expirationInSeconds';
+
+    const HEADERS_TO_SIGN = 'headersToSign';
+
+    const TIMESTAMP = 'timestamp';
+
+    const DEFAULT_EXPIRATION_IN_SECONDS = 1800;
+
+    const MIN_EXPIRATION_IN_SECONDS = 300;
+
+    const MAX_EXPIRATION_IN_SECONDS = 129600;
+}
+
+
+class AipSampleSigner
+{
+
+    const BCE_AUTH_VERSION = "bce-auth-v1";
+    const BCE_PREFIX = 'x-bce-';
+
+    //不指定headersToSign情况下,默认签名http头,包括:
+    //    1.host
+    //    2.content-length
+    //    3.content-type
+    //    4.content-md5
+    public static $defaultHeadersToSign;
+
+    public static function  __init()
+    {
+        AipSampleSigner::$defaultHeadersToSign = array(
+            "host",
+            "content-length",
+            "content-type",
+            "content-md5",
+        );
+    }
+
+    /**
+     * 签名
+     * @param  array $credentials
+     * @param  string $httpMethod
+     * @param  string $path
+     * @param  array  $headers
+     * @param  string $params
+     * @param  array  $options
+     * @return string
+     */
+    public static function sign(
+        array $credentials,
+        $httpMethod,
+        $path,
+        $headers,
+        $params,
+        $options = array()
+    ) {
+        //设定签名有效时间
+        if (!isset($options[AipSignOption::EXPIRATION_IN_SECONDS])) {
+            //默认值1800秒
+            $expirationInSeconds = AipSignOption::DEFAULT_EXPIRATION_IN_SECONDS;
+        } else {
+            $expirationInSeconds = $options[AipSignOption::EXPIRATION_IN_SECONDS];
+        }
+
+        //解析ak sk
+        $accessKeyId = $credentials['ak'];
+        $secretAccessKey = $credentials['sk'];
+
+        //设定时间戳,注意:如果自行指定时间戳需要为UTC时间
+        if (!isset($options[AipSignOption::TIMESTAMP])) {
+            //默认值当前时间
+            $timestamp = gmdate('Y-m-d\TH:i:s\Z');
+        } else {
+            $timestamp = $options[AipSignOption::TIMESTAMP];
+        }
+
+        //生成authString
+        $authString = AipSampleSigner::BCE_AUTH_VERSION . '/' . $accessKeyId . '/'
+            . $timestamp . '/' . $expirationInSeconds;
+
+        //使用sk和authString生成signKey
+        $signingKey = hash_hmac('sha256', $authString, $secretAccessKey);
+
+        //生成标准化URI
+        $canonicalURI = AipHttpUtil::getCanonicalURIPath($path);
+
+        //生成标准化QueryString
+        $canonicalQueryString = AipHttpUtil::getCanonicalQueryString($params);
+
+        //填充headersToSign,也就是指明哪些header参与签名
+        $headersToSign = null;
+        if (isset($options[AipSignOption::HEADERS_TO_SIGN])) {
+            $headersToSign = $options[AipSignOption::HEADERS_TO_SIGN];
+        }
+
+        //生成标准化header
+        $canonicalHeader = AipHttpUtil::getCanonicalHeaders(
+            AipSampleSigner::getHeadersToSign($headers, $headersToSign)
+        );
+
+        //整理headersToSign,以';'号连接
+        $signedHeaders = '';
+        if ($headersToSign !== null) {
+            $signedHeaders = strtolower(
+                trim(implode(";", $headersToSign))
+            );
+        }
+
+        //组成标准请求串
+        $canonicalRequest = "$httpMethod\n$canonicalURI\n"
+            . "$canonicalQueryString\n$canonicalHeader";
+
+        //使用signKey和标准请求串完成签名
+        $signature = hash_hmac('sha256', $canonicalRequest, $signingKey);
+
+        //组成最终签名串
+        $authorizationHeader = "$authString/$signedHeaders/$signature";
+
+        return $authorizationHeader;
+    }
+
+    /**
+     * 根据headsToSign过滤应该参与签名的header
+     * @param  array $headers
+     * @param  array $headersToSign
+     * @return array
+     */
+    public static function getHeadersToSign($headers, $headersToSign)
+    {
+
+        //value被trim后为空串的header不参与签名
+        $filter_empty = function($v) {
+            return trim((string) $v) !== '';
+        };
+        $headers = array_filter($headers, $filter_empty);
+
+        //处理headers的key:去掉前后的空白并转化成小写
+        $trim_and_lower = function($str){
+            return strtolower(trim($str));
+        };
+        $temp = array();
+        $process_keys = function($k, $v) use(&$temp, $trim_and_lower) {
+            $temp[$trim_and_lower($k)] = $v;
+        };
+        array_map($process_keys, array_keys($headers), $headers);
+        $headers = $temp;
+
+        //取出headers的key以备用
+        $header_keys = array_keys($headers);
+
+        $filtered_keys = null;
+        if ($headersToSign !== null) {
+            //如果有headersToSign,则根据headersToSign过滤
+
+            //预处理headersToSign:去掉前后的空白并转化成小写
+            $headersToSign = array_map($trim_and_lower, $headersToSign);
+
+            //只选取在headersToSign里面的header
+            $filtered_keys = array_intersect_key($header_keys, $headersToSign);
+
+        } else {
+            //如果没有headersToSign,则根据默认规则来选取headers
+            $filter_by_default = function($k) {
+                return AipSampleSigner::isDefaultHeaderToSign($k);
+            };
+            $filtered_keys = array_filter($header_keys, $filter_by_default);
+        }
+
+        //返回需要参与签名的header
+        return array_intersect_key($headers, array_flip($filtered_keys));
+    }
+
+    /**
+     * 检查header是不是默认参加签名的:
+     * 1.是host、content-type、content-md5、content-length之一
+     * 2.以x-bce开头
+     * @param  array $header
+     * @return boolean
+     */
+    public static function isDefaultHeaderToSign($header)
+    {
+        $header = strtolower(trim($header));
+        if (in_array($header, AipSampleSigner::$defaultHeadersToSign)) {
+            return true;
+        }
+        return substr_compare($header, AipSampleSigner::BCE_PREFIX, 0, strlen(AipSampleSigner::BCE_PREFIX)) == 0;
+    }
+}
+AipSampleSigner::__init();

+ 343 - 0
app/Http/Controllers/api-speech/lib/AipBase.php

@@ -0,0 +1,343 @@
+<?php
+/*
+* Copyright (c) 2017 Baidu.com, Inc. All Rights Reserved
+*
+* Licensed under the Apache License, Version 2.0 (the "License"); you may not
+* use this file except in compliance with the License. You may obtain a copy of
+* the License at
+*
+* Http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+* License for the specific language governing permissions and limitations under
+* the License.
+*/
+
+require_once 'AipHttpClient.php';
+require_once 'AipBCEUtil.php';
+require_once 'AipImageUtil.php';
+
+/**
+ * Aip Base 基类
+ */
+class AipBase {
+
+    /**
+     * 获取access token url
+     * @var string
+     */
+    protected $accessTokenUrl = 'https://aip.baidubce.com/oauth/2.0/token';
+
+    /**
+     * appId
+     * @var string
+     */
+    protected $appId = '';
+
+    /**
+     * apiKey
+     * @var string
+     */
+    protected $apiKey = '';
+    
+    /**
+     * secretKey
+     * @var string
+     */
+    protected $secretKey = '';
+
+    /**
+     * 权限
+     * @var array
+     */
+    protected $scope = 'brain_all_scope';
+
+    /**
+     * @param string $appId 
+     * @param string $apiKey
+     * @param string $secretKey
+     */
+    public function __construct($appId, $apiKey, $secretKey){
+        $this->appId = trim($appId);
+        $this->apiKey = trim($apiKey);
+        $this->secretKey = trim($secretKey);
+        $this->isCloudUser = null;
+        $this->client = new AipHttpClient();
+        $this->version = '1_6_0';
+    }
+
+    /**
+     * 连接超时
+     * @param int $ms 毫秒
+     */
+    public function setConnectionTimeoutInMillis($ms){
+        $this->client->setConnectionTimeoutInMillis($ms);
+    }
+
+    /**
+     * 响应超时
+     * @param int $ms 毫秒
+     */
+    public function setSocketTimeoutInMillis($ms){
+        $this->client->setSocketTimeoutInMillis($ms);
+    }
+
+    /**
+     * 处理请求参数
+     * @param  string $url
+     * @param array $params
+     * @param array $data
+     * @param array $headers
+     */
+    protected function proccessRequest($url, &$params, &$data, $headers){
+        $params['aipSdk'] = 'php';
+        $params['aipSdkVersion'] = $this->version;
+    }
+
+    /**
+     * Api 请求
+     * @param  string $url
+     * @param  mixed $data
+     * @return mixed
+     */
+    protected function request($url, $data, $headers=array()){
+        try{
+            $result = $this->validate($url, $data);
+            if($result !== true){
+                return $result;
+            }
+
+            $params = array();
+            $authObj = $this->auth();
+
+            if($this->isCloudUser === false){
+                $params['access_token'] = $authObj['access_token'];
+            }
+
+            // 特殊处理
+            $this->proccessRequest($url, $params, $data, $headers);
+ 
+            $headers = $this->getAuthHeaders('POST', $url, $params, $headers);
+            $response = $this->client->post($url, $data, $params, $headers);
+ 
+            $obj = $this->proccessResult($response['content']);
+
+            if(!$this->isCloudUser && isset($obj['error_code']) && $obj['error_code'] == 110){
+                $authObj = $this->auth(true);
+                $params['access_token'] = $authObj['access_token'];
+                $response = $this->client->post($url, $data, $params, $headers);
+                $obj = $this->proccessResult($response['content']);
+            }
+
+            if(empty($obj) || !isset($obj['error_code'])){
+                $this->writeAuthObj($authObj);
+            }
+        }catch(Exception $e){
+            return array(
+                'error_code' => 'SDK108',
+                'error_msg' => 'connection or read data timeout',
+            );
+        }
+
+        return $obj;
+    }
+
+    /**
+     * Api 多个并发请求
+     * @param  string $url
+     * @param  mixed $data
+     * @return mixed
+     */
+    protected function multi_request($url, $data){
+        try{
+            $params = array();
+            $authObj = $this->auth();
+            $headers = $this->getAuthHeaders('POST', $url);
+
+            if($this->isCloudUser === false){
+                $params['access_token'] = $authObj['access_token'];
+            }
+
+            $responses = $this->client->multi_post($url, $data, $params, $headers);
+
+            $is_success = false;
+            foreach($responses as $response){
+                $obj = $this->proccessResult($response['content']);
+
+                if(empty($obj) || !isset($obj['error_code'])){
+                    $is_success = true;
+                }
+
+                if(!$this->isCloudUser && isset($obj['error_code']) && $obj['error_code'] == 110){
+                    $authObj = $this->auth(true);
+                    $params['access_token'] = $authObj['access_token'];
+                    $responses = $this->client->post($url, $data, $params, $headers);
+                    break;
+                }
+            }
+
+            if($is_success){
+                $this->writeAuthObj($authObj);
+            }
+
+            $objs = array();
+            foreach($responses as $response){
+                $objs[] = $this->proccessResult($response['content']);
+            }
+
+        }catch(Exception $e){
+            return array(
+                'error_code' => 'SDK108',
+                'error_msg' => 'connection or read data timeout',
+            );
+        }
+
+        return $objs;
+    }
+
+    /**
+     * 格式检查
+     * @param  string $url
+     * @param  array $data
+     * @return mix
+     */
+    protected function validate($url, &$data){
+        return true;
+    }
+
+    /**
+     * 格式化结果
+     * @param $content string
+     * @return mixed
+     */
+    protected function proccessResult($content){
+        return json_decode($content, true);
+    }
+
+    /**
+     * 返回 access token 路径
+     * @return string
+     */
+    private function getAuthFilePath(){
+        return dirname(__FILE__) . DIRECTORY_SEPARATOR . md5($this->apiKey);
+    }
+
+    /**
+     * 写入本地文件
+     * @param  array $obj
+     * @return void
+     */
+    private function writeAuthObj($obj){
+        if($obj === null || (isset($obj['is_read']) && $obj['is_read'] === true)){
+            return;
+        }
+
+        $obj['time'] = time();
+        $obj['is_cloud_user'] = $this->isCloudUser;
+        @file_put_contents($this->getAuthFilePath(), json_encode($obj));
+    }
+
+    /**
+     * 读取本地缓存
+     * @return array
+     */
+    private function readAuthObj(){
+        $content = @file_get_contents($this->getAuthFilePath());
+        if($content !== false){
+            $obj = json_decode($content, true);
+            $this->isCloudUser = $obj['is_cloud_user'];
+            $obj['is_read'] = true;
+            if($this->isCloudUser || $obj['time'] + $obj['expires_in'] - 30 > time()){
+                return $obj;
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * 认证
+     * @param bool $refresh 是否刷新
+     * @return array
+     */
+    private function auth($refresh=false){
+
+        //非过期刷新
+        if(!$refresh){
+            $obj = $this->readAuthObj();
+            if(!empty($obj)){
+                return $obj;
+            }
+        }
+
+        $response = $this->client->get($this->accessTokenUrl, array(
+            'grant_type' => 'client_credentials',
+            'client_id' => $this->apiKey,
+            'client_secret' => $this->secretKey,
+        ));
+
+        $obj = json_decode($response['content'], true);
+
+        $this->isCloudUser = !$this->isPermission($obj);
+        return $obj;
+    }
+
+    /**
+     * 判断认证是否有权限
+     * @param  array   $authObj 
+     * @return boolean          
+     */
+    protected function isPermission($authObj)
+    {
+        if(empty($authObj) || !isset($authObj['scope'])){
+            return false;
+        }
+
+        $scopes = explode(' ', $authObj['scope']);
+
+        return in_array($this->scope, $scopes);
+    }
+
+    /**
+     * @param  string $method HTTP method
+     * @param  string $url
+     * @param  array $param 参数
+     * @return array
+     */
+    private function getAuthHeaders($method, $url, $params=array(), $headers=array()){
+        
+        //不是云的老用户则不用在header中签名 认证
+        if($this->isCloudUser === false){
+            return $headers;
+        }
+
+        $obj = parse_url($url);
+        if(!empty($obj['query'])){        
+            foreach(explode('&', $obj['query']) as $kv){
+                if(!empty($kv)){
+                    list($k, $v) = explode('=', $kv, 2);
+                    $params[$k] = $v;
+                }
+            }
+        }
+
+        //UTC 时间戳
+        $timestamp = gmdate('Y-m-d\TH:i:s\Z');
+        $headers['Host'] = isset($obj['port']) ? sprintf('%s:%s', $obj['host'], $obj['port']) : $obj['host'];
+        $headers['x-bce-date'] = $timestamp;
+
+        //签名
+        $headers['authorization'] = AipSampleSigner::sign(array(
+            'ak' => $this->apiKey,
+            'sk' => $this->secretKey,
+        ), $method, $obj['path'], $headers, $params, array(
+            'timestamp' => $timestamp,
+            'headersToSign' => array_keys($headers),
+        ));
+
+        return $headers;
+    }
+
+}

+ 192 - 0
app/Http/Controllers/api-speech/lib/AipHttpClient.php

@@ -0,0 +1,192 @@
+<?php
+/*
+* Copyright (c) 2017 Baidu.com, Inc. All Rights Reserved
+*
+* Licensed under the Apache License, Version 2.0 (the "License"); you may not
+* use this file except in compliance with the License. You may obtain a copy of
+* the License at
+*
+* Http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+* License for the specific language governing permissions and limitations under
+* the License.
+*/
+
+/**
+ * Http Client
+ */
+class AipHttpClient{
+
+    /**
+     * HttpClient
+     * @param array $headers HTTP header
+     */
+    public function __construct($headers=array()){
+        $this->headers = $this->buildHeaders($headers);
+        $this->connectTimeout = 60000;
+        $this->socketTimeout = 60000;
+    }
+
+    /**
+     * 连接超时
+     * @param int $ms 毫秒
+     */
+    public function setConnectionTimeoutInMillis($ms){
+        $this->connectTimeout = $ms;
+    }
+
+    /**
+     * 响应超时
+     * @param int $ms 毫秒
+     */
+    public function setSocketTimeoutInMillis($ms){
+        $this->socketTimeout = $ms;
+    }    
+
+    /**
+     * @param  string $url
+     * @param  array $data HTTP POST BODY
+     * @param  array $param HTTP URL
+     * @param  array $headers HTTP header
+     * @return array
+     */
+    public function post($url, $data=array(), $params=array(), $headers=array()){
+        $url = $this->buildUrl($url, $params);
+        $headers = array_merge($this->headers, $this->buildHeaders($headers));
+
+        $ch = curl_init();
+        curl_setopt($ch, CURLOPT_URL, $url);
+        curl_setopt($ch, CURLOPT_POST, 1);
+        curl_setopt($ch, CURLOPT_HEADER, false);
+        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
+        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
+        curl_setopt($ch, CURLOPT_POSTFIELDS, is_array($data) ? http_build_query($data) : $data);
+        curl_setopt($ch, CURLOPT_TIMEOUT_MS, $this->socketTimeout);
+        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT_MS, $this->connectTimeout);
+        $content = curl_exec($ch);
+        $code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
+
+        if($code === 0){
+            throw new Exception(curl_error($ch));
+        }
+
+        curl_close($ch);
+        return array(
+            'code' => $code,
+            'content' => $content,
+        );
+    }
+
+    /**
+     * @param  string $url
+     * @param  array $datas HTTP POST BODY
+     * @param  array $param HTTP URL
+     * @param  array $headers HTTP header
+     * @return array
+     */
+    public function multi_post($url, $datas=array(), $params=array(), $headers=array()){
+        $url = $this->buildUrl($url, $params);
+        $headers = array_merge($this->headers, $this->buildHeaders($headers));
+
+        $chs = array();
+        $result = array();
+        $mh = curl_multi_init();
+        foreach($datas as $data){        
+            $ch = curl_init();
+            $chs[] = $ch;
+            curl_setopt($ch, CURLOPT_URL, $url);
+            curl_setopt($ch, CURLOPT_POST, 1);
+            curl_setopt($ch, CURLOPT_HEADER, false);
+            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
+            curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
+            curl_setopt($ch, CURLOPT_POSTFIELDS, is_array($data) ? http_build_query($data) : $data);
+            curl_setopt($ch, CURLOPT_TIMEOUT_MS, $this->socketTimeout);
+            curl_setopt($ch, CURLOPT_CONNECTTIMEOUT_MS, $this->connectTimeout);
+            curl_multi_add_handle($mh, $ch);
+        }
+
+        $running = null;
+        do{
+            curl_multi_exec($mh, $running);
+            usleep(100);
+        }while($running);
+
+        foreach($chs as $ch){        
+            $content = curl_multi_getcontent($ch);
+            $code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
+            $result[] = array(
+                'code' => $code,
+                'content' => $content,
+            );
+            curl_multi_remove_handle($mh, $ch);
+        }
+        curl_multi_close($mh);
+        
+        return $result;
+    }
+
+    /**
+     * @param  string $url
+     * @param  array $param HTTP URL
+     * @param  array $headers HTTP header
+     * @return array
+     */
+    public function get($url, $params=array(), $headers=array()){
+        $url = $this->buildUrl($url, $params);
+        $headers = array_merge($this->headers, $this->buildHeaders($headers));
+
+        $ch = curl_init();
+        curl_setopt($ch, CURLOPT_URL, $url);
+        curl_setopt($ch, CURLOPT_HEADER, false);
+        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
+        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
+        curl_setopt($ch, CURLOPT_TIMEOUT_MS, $this->socketTimeout);
+        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT_MS, $this->connectTimeout);
+        $content = curl_exec($ch);
+        $code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
+
+        if($code === 0){
+            throw new Exception(curl_error($ch));
+        }
+        
+        curl_close($ch);
+        return array(
+            'code' => $code,
+            'content' => $content,
+        );
+    }
+
+    /**
+     * 构造 header
+     * @param  array $headers
+     * @return array
+     */
+    private function buildHeaders($headers){
+        $result = array();
+        foreach($headers as $k => $v){
+            $result[] = sprintf('%s:%s', $k, $v);
+        }
+        return $result;
+    }
+
+    /**
+     * 
+     * @param  string $url
+     * @param  array $params 参数
+     * @return string
+     */
+    private function buildUrl($url, $params){
+        if(!empty($params)){
+            $str = http_build_query($params);
+            return $url . (strpos($url, '?') === false ? '?' : '&') . $str;
+        }else{
+            return $url;
+        }
+    }
+}

+ 36 - 0
app/Http/Controllers/api-speech/lib/AipImageUtil.php

@@ -0,0 +1,36 @@
+<?php
+/*
+* Copyright (c) 2017 Baidu.com, Inc. All Rights Reserved
+*
+* Licensed under the Apache License, Version 2.0 (the "License"); you may not
+* use this file except in compliance with the License. You may obtain a copy of
+* the License at
+*
+* Http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+* License for the specific language governing permissions and limitations under
+* the License.
+*/
+
+class AipImageUtil{
+
+    /**
+     * 获取图片信息
+     * @param  $content string
+     * @return array
+     */
+    public static function getImageInfo($content){
+        $info = getimagesizefromstring($content);
+
+        return array(
+            'mime' => $info['mime'],
+            'width' => $info[0],
+            'height' => $info[1],
+        );
+    }
+}
+
+// var_dump(AipUtil::getImageInfo(file_get_contents('../test/general.png')));

+ 130 - 0
app/Imports/PaperBoxesImport.php

@@ -0,0 +1,130 @@
+<?php
+
+namespace App\Imports;
+
+use App\Owner;
+use App\PaperBox;
+use App\WaybillPriceModel;
+use App\Carrier;
+use App\City;
+use App\Events\WaybillPriceModelEvent;
+use App\Province;
+use App\Unit;
+use Illuminate\Support\Collection;
+use Illuminate\Support\Facades\Cache;
+use Maatwebsite\Excel\Concerns\ToCollection;
+use Maatwebsite\Excel\Concerns\WithHeadingRow;
+use Maatwebsite\Excel\Imports\HeadingRowFormatter;
+
+HeadingRowFormatter::default('none');
+class PaperBoxesImport implements ToCollection,WithHeadingRow
+{
+    protected $isOverride;
+    public function __construct($isOverride)
+    {
+        if ($isOverride==1){
+            $this->isOverride=true;
+        }
+    }
+
+
+    /**
+     * @param Collection $collection
+     */
+    public function Collection(Collection $collection)
+    {
+        $endIs=false;
+        $cityIs=true;
+        if (isset($collection->toArray()[0]['货主'])&&isset($collection->toArray()[0]['纸箱名称'])&&isset($collection->toArray()[0]['长'])
+            &&isset($collection->toArray()[0]['宽'])&&isset($collection->toArray()[0]['高'])){
+                $endIs=true;
+        }else{
+                Cache::put('error','请检查您第一行标题是否存在货主,纸箱名称,长,宽,高',86400);
+                $endIs=false;
+        }
+        $exception=[];
+        $sum=2;
+        if ($endIs) {
+            foreach ($collection as $row) {
+                if (!$row['货主']) {
+                    array_push($exception, ['第' . $sum . '行数据货主为空!']);
+                    $sum++;
+                    continue;
+                }
+                if (!$row['纸箱名称']) {
+                    array_push($exception, ['第' . $sum . '行数据纸箱名称为空!']);
+                    $sum++;
+                    continue;
+                }
+                if (!$row['长'] || preg_match('/^[1-9]\d*\,\d*|[1-9]\d*$/', $row['长']) == 0) {
+                    array_push($exception, ['第' . $sum . '行数据长为空或不为数字!']);
+                    $sum++;
+                    continue;
+                }
+                if (!$row['宽'] || preg_match('/^[1-9]\d*\,\d*|[1-9]\d*$/', $row['宽']) == 0) {
+                    array_push($exception, ['第' . $sum . '行数据宽为空或不为数字!']);
+                    $sum++;
+                    continue;
+                }
+                if (!$row['高'] || preg_match('/^[1-9]\d*\,\d*|[1-9]\d*$/', $row['高']) == 0) {
+                    array_push($exception, ['第' . $sum . '行数据高为空或不为数字!']);
+                    $sum++;
+                    continue;
+                }
+                $owner = Owner::where("name", $row['货主'])->first();
+                if (!$owner) {
+                    array_push($exception, ['第' . $sum . '行数据货主在系统中未找到!']);
+                    $sum++;
+                    continue;
+                }
+                $length = $row['长'];
+                $width = $row['宽'];
+                $height = $row['高'];
+                $max = ($length >= ($width >= $height ? $width : $height) ? $length : ($width >= $height ? $width : $height));
+                if ($max == $length) {
+                    $centre = $width >= $height ? $width : $height;
+                    $min = $width < $height ? $width : $height;
+                } elseif ($max == $width) {
+                    $centre = $length >= $height ? $length : $height;
+                    $min = $length < $height ? $length : $height;
+                } else {
+                    $centre = $width >= $length ? $width : $length;
+                    $min = $width < $length ? $width : $length;
+                }
+                $paperBox = PaperBox::with('owners')->where('model', $row['纸箱名称'])->first();
+                if ($paperBox) {
+                    if ($this->isOverride) {
+                        $paperBox->length = $max;
+                        $paperBox->width = $centre;
+                        $paperBox->height = $min;
+                        $paperBox->save();
+                        array_push($exception, ['第' . $sum . '行数据已覆盖!']);
+                    } else {
+                        array_push($exception, ['第' . $sum . '行数据已存在!']);
+                    }
+                    if ($paperBox->owners){
+                        $isOwner = true;
+                        foreach ($paperBox->owners as $o){
+                            if ($o->id == $owner->id){
+                                $isOwner = false;
+                                break;
+                            }
+                        }
+                        if ($isOwner) $paperBox->owners()->syncWithoutDetaching($owner->id);
+                    }
+                } else {
+                    $paperBox = new PaperBox([
+                        'model' => $row['纸箱名称'],
+                        'length' => $max,
+                        'width' => $centre,
+                        'height' => $min,
+                    ]);
+                    $paperBox->save();
+                    $paperBox->owners()->sync($owner->id);
+                }
+                $sum++;
+            }
+            Cache::put('exception', $exception, 86400);
+        }
+    }
+}

+ 8 - 8
app/Imports/WaybillPriceModelsImport.php

@@ -83,8 +83,8 @@ class WaybillPriceModelsImport implements ToCollection,WithHeadingRow
                                 $waybillPriceModel = ['carrier_id' => $carrier->id, 'unit_id' => $unit->id, 'province_id' => $province->id, 'unit_price' => $row['单价']];
                                 if ($row['计数区间']) {
                                     $str = explode('-', $row['计数区间']);
-                                    if (preg_match('/^([0-9]\d*(\.\d*[1-9])?)|(0\.\d*[1-9])$/', $str[0]) >= 0
-                                        && preg_match('/^([0-9]\d*(\.\d*[1-9])?)|(0\.\d*[1-9])$/', $str[1]) > 0
+                                    if (preg_match('/^[1-9]\d*\,\d*|[1-9]\d*$/', $str[0]) >= 0
+                                        && preg_match('/^[1-9]\d*\,\d*|[1-9]\d*$/', $str[1]) > 0
                                         && $str[0] < $str[1] && count($str) == 2
                                     ) {
                                         $waybillPriceModel = array_merge($waybillPriceModel, ['range_min' => $str[0], 'range_max' => $str[1]]);
@@ -97,13 +97,13 @@ class WaybillPriceModelsImport implements ToCollection,WithHeadingRow
                                         $waybillPriceModel = array_merge($waybillPriceModel, ['city_id' => $city->id]);
                                     }
                                 }
-                                if ($row['起步费'] && preg_match('/^([0-9]\d*(\.\d*[1-9])?)|(0\.\d*[1-9])$/', $row['起步费']) > 0) {
+                                if ($row['起步费'] && preg_match('/^[1-9]\d*\,\d*|[1-9]\d*$/', $row['起步费']) > 0) {
                                     $waybillPriceModel = array_merge($waybillPriceModel, ['base_fee' => $row['起步费']]);
                                 } else {
                                     $waybillPriceModel = array_merge($waybillPriceModel, ['base_fee' => 0]);
                                     array_push($exception, ['第' . $sum . '行数据起步费为空,或为负,已默认设为0']);
                                 }
-                                if ($row['最低计数'] && preg_match('/^([0-9]\d*(\.\d*[1-9])?)|(0\.\d*[1-9])$/', $row['最低计数']) > 0) {
+                                if ($row['最低计数'] && preg_match('/^[1-9]\d*\,\d*|[1-9]\d*$/', $row['最低计数']) > 0) {
                                     $waybillPriceModel = array_merge($waybillPriceModel, ['initial_weight' => $row['最低计数']]);
                                 } else {
                                     $waybillPriceModel = array_merge($waybillPriceModel, ['initial_weight' => 0]);
@@ -117,8 +117,8 @@ class WaybillPriceModelsImport implements ToCollection,WithHeadingRow
                                 $waybillPriceModel = ['carrier_id' => $carrier->id, 'unit_id' => $unit->id, 'province_id' => $province->id, 'unit_price' => $row['单价']];
                                 if ($row['计数区间']&& !strstr($row['计数区间'], '∞')) {
                                     $str = explode('-', $row['计数区间']);
-                                    if (preg_match('/^([0-9]\d*(\.\d*[1-9])?)|(0\.\d*[1-9])$/', $str[0]) > 0
-                                        && preg_match('/^([0-9]\d*(\.\d*[1-9])?)|(0\.\d*[1-9])$/', $str[1]) > 0
+                                    if (preg_match('/^[1-9]\d*\,\d*|[1-9]\d*$/', $str[0]) > 0
+                                        && preg_match('/^[1-9]\d*\,\d*|[1-9]\d*$/', $str[1]) > 0
                                         && $str[0] < $str[1] && count($str) == 2
                                     ) {
                                         $waybillPriceModel = array_merge($waybillPriceModel, ['range_min' => $str[0], 'range_max' => $str[1]]);
@@ -131,13 +131,13 @@ class WaybillPriceModelsImport implements ToCollection,WithHeadingRow
                                         $waybillPriceModel = array_merge($waybillPriceModel, ['city_id' => $city->id]);
                                     }
                                 }
-                                if ($row['起步费'] && preg_match('/^([0-9]\d*(\.\d*[1-9])?)|(0\.\d*[1-9])$/', $row['起步费']) > 0) {
+                                if ($row['起步费'] && preg_match('/^[1-9]\d*\,\d*|[1-9]\d*$/', $row['起步费']) > 0) {
                                     $waybillPriceModel = array_merge($waybillPriceModel, ['base_fee' => $row['起步费']]);
                                 } else {
                                     $waybillPriceModel = array_merge($waybillPriceModel, ['base_fee' => 0]);
                                     array_push($exception, ['第' . $sum . '行数据起步费为空,或为负,已默认设为0']);
                                 }
-                                if ($row['最低计数'] && preg_match('/^([0-9]\d*(\.\d*[1-9])?)|(0\.\d*[1-9])$/', $row['最低计数']) > 0) {
+                                if ($row['最低计数'] && preg_match('/^[1-9]\d*\,\d*|[1-9]\d*$/', $row['最低计数']) > 0) {
                                     $waybillPriceModel = array_merge($waybillPriceModel, ['initial_weight' => $row['最低计数']]);
                                 } else {
                                     $waybillPriceModel = array_merge($waybillPriceModel, ['initial_weight' => 0]);

+ 28 - 4
app/Package.php

@@ -7,19 +7,43 @@ use Illuminate\Database\Eloquent\Model;
 class Package extends Model
 {
     protected $fillable=[
-        'logistic_number','type','weight','length','width','height','owner_id','paper_box_id',
-        'measuring_machine_id','recipient','status'
+        'owner_id','logistic_number','delivery_number','batch_number','batch_rule','recipient','recipient_mobile','logistics_id',
+        'measuring_machine_id','weight','length','width','height','bulk','paper_box_id','status'
+    ];
+    protected $appends=[
+        'owner_name',
+        'logistic_name',
+        'measuringMachine_name',
+        'paperBox_name'
     ];
 
     public function owner(){
         return $this->belongsTo('App\Owner','owner_id','id');
     }
 
+    public function logistic(){
+        return $this->belongsTo('App\Logistic','logistic_id','id');
+    }
+
+    public function measuringMachine(){
+        return $this->belongsTo('App\MeasuringMachine','measuring_machine_id','id');
+    }
+
     public function paperBox(){
         return $this->belongsTo('App\paperBox','paper_box_id','id');
     }
 
-    public function measuringMachine(){
-        return $this->belongsTo('App\measuringMachine','measuring_machine_id','id');
+    public function getOwnerNameAttribute()
+    {
+        return $this['owner']? $this['owner']['name']:null;
+    }
+    public function getLogisticNameAttribute(){
+        return $this['logistic']? $this['logistic']['name']:null;
+    }
+    public function getMeasuringMachineNameAttribute(){
+        return $this['measuringMachine']? $this['measuringMachine']['name']:null;
+    }
+    public function getPaperBoxNameAttribute(){
+        return $this['paperBox']? $this['paperBox']['model']:null;
     }
 }

+ 1 - 1
app/WaybillPriceModel.php

@@ -12,7 +12,7 @@ class WaybillPriceModel extends Model
     ];
 
     protected $appends=[
-        'carrier_name',
+        'logistic_name',
         'province_name',
         'city_name',
         'unit_name',

+ 31 - 0
database/migrations/2020_02_09_080123_add_weigh_excepted_authority.php

@@ -0,0 +1,31 @@
+<?php
+
+use App\Authority;
+use Illuminate\Support\Facades\Schema;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Database\Migrations\Migration;
+
+class AddWeighExceptedAuthority extends Migration
+{
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        (new Authority(['name'=>'包裹信息-查看异常','alias_name'=>'包裹信息-查看异常']))->save();
+        (new Authority(['name'=>'包裹信息-录入','alias_name'=>'包裹信息-查看异常']))->save();
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        Authority::where('name','包裹信息-查看异常')->delete();
+        Authority::where('name','包裹信息-录入')->delete();
+    }
+}

+ 48 - 0
database/migrations/2020_02_10_103905_change_package_column.php

@@ -0,0 +1,48 @@
+<?php
+
+use Illuminate\Support\Facades\Schema;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Database\Migrations\Migration;
+
+class ChangePackageColumn extends Migration
+{
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        Schema::dropIfExists('packages');
+        Schema::create('packages', function (Blueprint $table) {
+            $table->bigIncrements('id');
+            $table->bigInteger('owner_id')->nullable()->index()->comment('外键货主');
+            $table->string('logistic_number')->unique()->comment('快递单号');
+            $table->string('delivery_number')->nullable()->unique()->comment('发货单号');
+            $table->string('batch_number')->nullable()->comment('波次号');
+            $table->string('batch_rule')->nullable()->comment('波次规则');
+            $table->string('recipient')->nullable()->comment('收件人');
+            $table->string('recipient_mobile')->nullable()->comment('收件人电话');
+            $table->bigInteger('logistics_id')->nullable()->index()->comment('外键物流公司');
+            $table->bigInteger('measuring_machine_id')->nullable()->index()->comment('外键设备');
+            $table->decimal('weight')->nullable()->comment('重KG');
+            $table->decimal('length')->nullable()->index()->comment('长(cm)');
+            $table->decimal('width')->nullable()->index()->comment('宽(cm)');
+            $table->decimal('height')->nullable()->index()->comment('高(cm)');
+            $table->decimal('bulk')->nullable()->comment('体积(cm³)');
+            $table->bigInteger('paper_box_id')->nullable()->index()->comment('外键纸箱');
+            $table->enum('status',['无','未上传','已上传','未测量','已测量','上传异常','下发异常'])->default('无')->comment('包裹信息状态');
+            $table->timestamps();
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        Schema::dropIfExists('packages');
+    }
+}

BIN
public/audio.mp3


+ 0 - 0
public/icon/off.png → public/images/measuringMachine/off.png


+ 0 - 0
public/icon/on.png → public/images/measuringMachine/on.png


+ 4 - 1
public/mix-manifest.json

@@ -2,5 +2,8 @@
     "/js/app.js": "/js/app.js",
     "/css/app.css": "/css/app.css",
     "/js/singles/rejectedIndex.js": "/js/singles/rejectedIndex.js",
-    "/favicon.ico": "/favicon.ico"
+    "/favicon.ico": "/favicon.ico",
+    "/off.png": "/off.png",
+    "/on.png": "/on.png",
+    "/audio.mp3": "/audio.mp3"
 }

BIN
public/off.png



BIN
resources/audio.mp3


BIN
resources/images/measuringMachine/off.png


BIN
resources/images/measuringMachine/on.png


+ 2 - 2
resources/views/layouts/menu.blade.php

@@ -8,8 +8,8 @@
             <li class="nav-item"><a href="{{url("waybill/index")}}" class="nav-link"
                                     :class="{active:isActive('waybill',1)}">运输管理</a></li> @endcan
         @can('称重管理')
-            <li class="nav-item"><a href="{{url("weigh")}}" class="nav-link"
-                                    :class="{active:isActive('weigh',1)}">称重管理</a></li> @endcan
+            <li class="nav-item"><a href="{{url("weight/package")}}" class="nav-link"
+                                    :class="{active:isActive('weight',1)}">称重管理</a></li> @endcan
         @can('基础设置')
         <li class="nav-item"><a href="{{url("maintenance/")}}" class="nav-link"
                                 :class="{active:isActive('maintenance',1)}">基础设置</a></li> @endcan

+ 1 - 1
resources/views/maintenance/paperBox/create.blade.php

@@ -77,7 +77,7 @@
                             </div>
                         </div>
                         <div class="col-5">
-                            <div style="max-height: 130px;overflow-y: scroll;border: solid 1px #ddd;border-radius:5px;text-align: center;" v-if="owners.length>0">
+                            <div style="max-height: 130px;overflow-y: scroll;border: solid 1px #ddd;border-radius:5px;text-align: center;" v-if="selectedOwners.length>0">
                                 <ul class="list-group">
                                     <li v-for="selectedOwner in selectedOwners" title="双击删除货主"  @dblclick="owner(selectedOwner)" style="list-style: none">
                                         <a>@{{ selectedOwner.name }}</a>

+ 1 - 1
resources/views/maintenance/paperBox/edit.blade.php

@@ -82,7 +82,7 @@
                             </div>
                         </div>
                         <div class="col-5">
-                            <div style="max-height: 130px;overflow-y: scroll;border: solid 1px #ddd;border-radius:5px;text-align: center;" v-if="owners.length>0">
+                            <div style="max-height: 130px;overflow-y: scroll;border: solid 1px #ddd;border-radius:5px;text-align: center;" v-if="selectedOwners.length>0">
                                 <ul class="list-group ">
                                     <li v-for="selectedOwner in selectedOwners" class="tooltipTarget" @dblclick="owner(selectedOwner)" title="双击删除货主"  style="list-style: none">
                                         <a>@{{ selectedOwner.name }}</a>

+ 57 - 0
resources/views/maintenance/paperBox/import.blade.php

@@ -0,0 +1,57 @@
+@extends('layouts.app')
+
+@section('content')
+    <div id="nav2">
+        @component('maintenance.menu')@endcomponent
+        @component('maintenance.paperBox.menu')@endcomponent
+    </div>
+    <div class="container mt-3">
+        <div class="card col-md-8 offset-md-2">
+            <div class="card-body">
+                <form method="POST" action="{{ url('maintenance/paperBox/excel/import') }}" enctype="multipart/form-data" target="_blank">
+                    @csrf
+                    <div class="form-group row text-center">
+                        <div class="col-12 text-danger">
+
+                            注意:请保证表第一行有以下对应的字段名<br>(可不按顺序):<br>
+                            货主,纸箱名称,长,宽,高<br>
+                        </div>
+                        <div class="col-12 text-info ">
+                            导入时间随文件大小可能达数十分钟以上,请耐心等候
+                            <hr>
+                        </div>
+                    </div>
+                    <div class="form-group row">
+                        <label for="sku" class="col-2 col-form-label text-right">选择EXCEL</label>
+                        <div class="col-8">
+                            <div class="form-control">
+                                <input type="file" class="form-control-file @error('file') is-invalid @enderror"
+                                       name="file" value="{{ old('file') }}" required>
+                                @error('file')
+                                <span class="invalid-feedback" role="alert">
+                                <strong>{{ $message }}</strong>
+                            </span>
+                                @enderror
+                            </div>
+                        </div>
+                    </div>
+                    <div class="form-group row">
+                        <label for="sku" class="col-2 col-form-label text-right">是否覆盖</label>
+                        <div class="col-8">
+                            <select name="isOverride" id="isOverride" class="form-control" >
+                                <option value="0">仅新增</option>
+                                <option value="1">新增且覆盖</option>
+                            </select>
+                            <p class="text-muted">覆盖会以货主,纸箱名称为依据,覆盖其余字段</p>
+                        </div>
+                    </div>
+                    <div class="form-group row">
+                        <div class="col-8 offset-2">
+                            <input type="submit" class="btn btn-success form-control" value="执行导入">
+                        </div>
+                    </div>
+                </form>
+            </div>
+        </div>
+    </div>
+@endsection

+ 5 - 1
resources/views/maintenance/paperBox/menu.blade.php

@@ -9,7 +9,11 @@
             @can('纸箱-录入')
                 <li class="nav-item">
                     <a class="nav-link" href="{{url('maintenance/paperBox/create')}}" :class="{active:isActive('create',3)}">录入</a>
-                </li> @endcan
+                </li>
+                <li class="nav-item">
+                    <a class="nav-link" href="{{url('maintenance/paperBox/excel/goImport')}}" :class="{active:isActive('goImport',4)}">导入</a>
+                </li>
+            @endcan
             {{$slot}}
         </ul>
     </div>

+ 1 - 1
resources/views/maintenance/waybillPriceModel/index.blade.php

@@ -89,7 +89,7 @@
             data:{
                 waybillPriceModels:[
                     @foreach( $waybillPriceModels as $waybillPriceModel )
-                        {id:'{{$waybillPriceModel->id}}',carrier:'{{$waybillPriceModel->carrier_name}}',
+                        {id:'{{$waybillPriceModel->id}}',carrier:'{{$waybillPriceModel->logistic_name}}',
                         province:'{{$waybillPriceModel->province_name}}',city:'{{$waybillPriceModel->city_name}}',
                         unit:'{{$waybillPriceModel->unit_name}}',range_min:'{{$waybillPriceModel->range_min}}',range_max:'{{$waybillPriceModel->range_max}}',
                         unit_price:'{{$waybillPriceModel->unit_price}}',base_fee:'{{$waybillPriceModel->base_fee}}',initial_weight:'{{$waybillPriceModel->initial_weight}}',

+ 0 - 6
resources/views/weigh/index.blade.php

@@ -1,6 +0,0 @@
-@extends('layouts.app')
-
-@section('content')
-    @component('weigh.menu')@endcomponent
-@endsection
-

+ 0 - 103
resources/views/weigh/measureMonitor/index.blade.php

@@ -1,103 +0,0 @@
-@extends('layouts.app')
-
-@section('content')
-    @component('weigh.menu')@endcomponent
-    <div class="page-holder w-100 d-flex flex-wrap" id="list">
-        <div class="container-fluid px-xl-5">
-            <section class="py-5">
-                <div class="row">
-                    <div class="col-lg-12 mb-4">
-                        <div class="card">
-                            <div class="card-header">
-                                <div class="form-inline">
-                                <img src="@if($package&&$package->measuringMachine->status=='在线'){{asset('icon/on.png')}}@else{{asset('icon/off.png')}}@endif"/>
-                                <h6 class="text-uppercase mb-0 dropdown-toggle" data-toggle="dropdown">@{{package.measuringMachine}}</h6>
-                                    <div class="dropdown-menu" id="selected">
-                                        <a class="dropdown-item" v-for="measuringMachine in measuringMachines" @click="selectedMachine(measuringMachine.id)">@{{measuringMachine.name}}</a>
-                                    </div>
-                                </div>
-
-                            </div>
-                            <div class="card-body">
-                                <table class="table card-text">
-                                    <tr>
-                                        <th scope="row">快递单号</th>
-                                        <td >@{{package.logistic_number}}</td>
-                                    </tr>
-                                    <tr>
-                                        <th scope="row">类型</th>
-                                        <td>@{{package.type}}</td>
-                                    </tr>
-                                    <tr>
-                                        <th scope="row">重(KG)</th>
-                                        <td>@{{package.weight}}</td>
-                                    </tr>
-                                    <tr>
-                                        <th scope="row">长(CM)</th>
-                                        <td>@{{package.length}}</td>
-                                    </tr>
-                                    <tr>
-                                        <th scope="row">宽(CM)</th>
-                                        <td>@{{package.width}}</td>
-                                    </tr>
-                                    <tr>
-                                        <th scope="row">高(CM)</th>
-                                        <td>@{{package.height}}</td>
-                                    </tr>
-                                    <tr>
-                                        <th scope="row">货主</th>
-                                        <td>@{{package.owner}}</td>
-                                    </tr>
-                                    <tr>
-                                        <th scope="row">纸箱</th>
-                                        <td>@{{package.paperBox}}</td>
-                                    </tr>
-                                    <tr>
-                                        <th scope="row">状态</th>
-                                        <td>@{{package.status}}</td>
-                                    </tr>
-                                    <tr>
-                                        <th scope="row">称重时间</th>
-                                        <td>@{{package.created_at}}</td>
-                                    </tr>
-                                </table>
-                            </div>
-                        </div>
-                    </div>
-                </div>
-            </section>
-        </div>
-    </div>
-@endsection
-
-@section('lastScript')
-    <style>
-        #selected a:hover{background-color: #4aa0e6;display: block;cursor:pointer}
-    </style>
-    <script>
-        let vue=new Vue({
-            el:'#list',
-            data:{
-                package:
-                    {@if($package)id:'{{$package->id}}',logistic_number:'{{$package->logistic_number}}',type:'{{$package->type}}',
-                    weight:'{{$package->weight}}',length:'{{$package->length}}',width:'{{$package->width}}',
-                    height:'{{$package->height}}',owner:'{{$package->owner?$package->owner->name:''}}',paperBox:'{{$package->paperBox?$package->paperBox->model:''}}',
-                    measuringMachine:'{{$package->measuringMachine?$package->measuringMachine->name:''}}',recipient:'{{$package->recipient}}',
-                    status:'{{$package->status}}',created_at:'{{$package->created_at}}'@endif},
-                measuringMachines:[
-                    @foreach($measuringMachines as $measuringMachine)
-                        @if($package&&$measuringMachine->name!=$package->measuringMachine->name)
-                            {id:'{{$measuringMachine->id}}',name:'{{$measuringMachine->name}}',code:'{{$measuringMachine->code}}'},
-                        @endif
-                    @endforeach
-                ]
-            },
-            methods:{
-                selectedMachine(id){
-                    let url='{{url('weigh/measureMonitor')}}';
-                    location.href=url+'?id='+id;
-                },
-            },
-        });
-    </script>
-@endsection

+ 0 - 20
resources/views/weigh/menu.blade.php

@@ -1,20 +0,0 @@
-
-<div class="container mt-3" id="nav2">
-    <div class="card">
-        <ul class="nav nav-pills">
-            @can('测量机监视界面-查询')
-                <li class="nav-item">
-                    <a class="nav-link" href="{{url('weigh/measureMonitor')}}" :class="{active:isActive('measureMonitor',2)}">测量机监视界面</a>
-                </li> @endcan
-            @can('测量记录管理-查询')
-                <li class="nav-item">
-                    <a class="nav-link" href="{{url('weigh/package')}}" :class="{active:isActive('package',2)}">测量记录管理</a>
-                </li>
-                <li class="nav-item">
-                    <a class="nav-link text-dark" href="{{url('weigh/relating')}}" :class="{active:isActive('relating',2)}">相关设置</a>
-                </li>
-                @endcan
-
-        </ul>
-    </div>
-</div>

+ 0 - 169
resources/views/weigh/package/index.blade.php

@@ -1,169 +0,0 @@
-
-@extends('layouts.app')
-
-@section('content')
-    <span id="nav2">
-        @component('weigh.menu')@endcomponent
-        @component('weigh.package.menu')@endcomponent
-    </span>
-    <div id="list">
-        <div class="container mt-3">
-            <div class="card">
-                <div>
-                    <form  method="GET" action="{{url('weigh/package')}}" style="margin-top: 1%" id="optionSubmit">
-                        <table class="table  table-sm table-bordered table-hover text-nowrap ">
-                            <tr>
-                                <td colspan="4"><div class="col" v-if="isBeingFilterConditions" style="padding:0">
-                                        <a  href="{{url('weigh/package')}}"><span class="btn btn-warning text-dark">清除过滤条件</span></a>
-                                    </div></td>
-                            </tr>
-                            <tr>
-                                <td  style="width:200px;"> <label style="margin-left: 2%" class="form-inline">页显示条数:
-                                    <select name="paginate" v-model="filterData.paginate" class="form-control" @change="setPaginate">
-                                        <option value="50">50行</option>
-                                        <option value="100">100行</option>
-                                        <option value="200">200行</option>
-                                        <option value="500">500行</option>
-                                        <option value="1000">1000行</option>
-                                    </select></label></td>
-                                <td style="width:300px;"> <label class="form-inline" style="margin-left: 2%">快递单号:
-                                        <input type="text" name="logistic_number" class="form-control  " v-model="filterData.logistic_number" style="vertical-align: middle"></label></td>
-                                <td style="width:200px;"> <label class="form-inline" style="margin-left: 2%">波次类型:
-                                    <select name="type" v-model="filterData.type" class="form-control"  @change="setType">
-                                        <option >    </option>
-                                        <option value="普通波次">普通波次</option>
-                                        <option value="活动波次">活动波次</option>
-
-                                    </select></label></td>
-                                <td style="width:200px;"><label class="form-inline" style="margin-left: 2%">状态:
-                                    <select name="status" v-model="filterData.status" class="form-control" @change="setStatus">
-                                        <option>  </option>
-                                        <option value="无">无</option>
-                                        <option value="未上传">未上传</option>
-                                        <option value="已上传">已上传</option>
-                                        <option value="异常">异常</option>
-                                    </select></label></td>
-                                <td style="width:200px;"> <label class="form-inline" style="margin-left: 2%">货主:
-                                        <select name="owner_id" v-model="filterData.owner_id" class="form-control"  @change="setOwner">
-                                            <option >    </option>
-                                            @foreach($owners as $owner)
-                                                <option value="{{$owner->id}}">{{$owner->name}}</option>
-                                            @endforeach
-                                        </select></label><input hidden type="submit" value="kk"></td>
-                                <td></td>
-                            </tr>
-                        </table>
-                    </form>
-                </div>
-            <div class="card-body">
-                <table class="table table-striped table-sm">
-                    <tr>
-                        <th>ID</th>
-                        <th>快递单号</th>
-                        <th>波次类型</th>
-                        <th>当前状态</th>
-                        <th>重(KG)</th>
-                        <th>长(CM)</th>
-                        <th>宽(CM)</th>
-                        <th>高(CM)</th>
-                        <th>货主</th>
-                        <th>纸箱</th>
-                        <th>设备</th>
-                        <th>收件人</th>
-                        <th>称重时间</th>
-                    </tr>
-                    <tr v-for="package in packages">
-                        <td class="text-muted">@{{package.id}}</td>
-                        <td>@{{package.logistic_number}}</td>
-                        <td>@{{package.type}}</td>
-                        <td>@{{package.status}}</td>
-                        <td>@{{package.weight}}</td>
-                        <td>@{{package.length}}</td>
-                        <td>@{{package.width}}</td>
-                        <td>@{{package.height}}</td>
-                        <td>@{{package.owner}}</td>
-                        <td>@{{package.paperBox}}</td>
-                        <td>@{{package.measuringMachine}}</td>
-                        <td>@{{package.recipient}}</td>
-                        <td class="text-muted">@{{package.created_at}}</td>
-                    </tr>
-                </table>
-                {{$packages->links()}}
-            </div>
-        </div>
-    </div>
-    </div>
-@endsection
-
-@section('lastScript')
-    <script>
-        new Vue({
-            el:"#list",
-            data:{
-                packages:[
-                    @foreach($packages as $package)
-                        {id:'{{$package->id}}',logistic_number:'{{$package->logistic_number}}',type:'{{$package->type}}',
-                        weight:'{{$package->weight}}', length:'{{$package->length}}',width:'{{$package->width}}',height:'{{$package->height}}',
-                        owner:'{{$package->owner?$package->owner->name:''}}',paperBox:'{{$package->paperBox?$package->paperBox->name:''}}',
-                        measuringMachine:'{{$package->measuringMachine?$package->measuringMachine->name:''}}',recipient:'{{$package->recipient}}',
-                        status:'{{$package->status}}',created_at:'{{$package->created_at}}'},
-                    @endforeach
-                ],
-                filterData:
-                    {paginate:'50',logistic_number:'',type: '',status: '',owner_id: ''},
-            },
-            mounted:function(){
-                this.initInputs();
-            },
-            computed:{
-                isBeingFilterConditions:function(){
-
-                    for(let key in this.filterData){
-                        if(this.filterData[key]){
-                            if(key==='paginate')continue;
-                            return true
-                        }
-                    }
-                    return false;
-                },
-
-            },
-            methods:{
-                initInputs:function(){
-                    let data=this;
-                    let uriParts =decodeURI(location.href).split("?");
-                    if(uriParts.length>1){
-                        let params = uriParts[1].split('&');
-                        params.forEach(function(paramPair){
-                            let pair=paramPair.split('=');
-                            let key = pair[0], val = pair[1];
-                            $('input[name="'+key+'"]').val(val);
-                            $('select[name="'+key+'"]').val(val);
-                            decodeURI(data.filterData[key]=val);
-                        });
-                    }
-                },
-                setPaginate:function(e){
-                    this.filterData.paginate=e.target.value;
-                    var form = document.getElementById("optionSubmit");
-                    form.submit();
-                },
-                setType:function (e){
-                    this.filterData.type=e.target.value;
-                    var form = document.getElementById("optionSubmit");
-                    form.submit();
-                },
-                setStatus:function (e){
-                    this.filterData.status=e.target.value;
-                    var form = document.getElementById("optionSubmit");
-                    form.submit();
-                },
-                setOwner:function (e){
-                    this.filterData.owner_id=e.target.value;
-                    var form = document.getElementById("optionSubmit");
-                    form.submit();
-                },
-            }
-        });
-    </script>
-@endsection

+ 135 - 0
resources/views/weight/measureMonitor/index.blade.php

@@ -0,0 +1,135 @@
+@extends('layouts.app')
+
+@section('content')
+    @component('weight.menu')@endcomponent
+    <div class="page-holder w-100 d-flex flex-wrap" id="list">
+        <div class="container-fluid px-xl-5">
+            <section class="py-5">
+                <div class="row">
+                    <div class="col-lg-12 mb-4">
+                        <audio id="audio" src="{{asset('audio.mp3')}}" controls  autoplay></audio>
+                        <div class="card">
+                            <div class="card-header">
+                                <div class="form-inline">
+                                <img src="@if($package&&$package->measuringMachine->status=='在线'){{asset('icon/on.png')}}@else{{asset('icon/off.png')}}@endif"/>
+                                <h6 class="text-uppercase mb-0 dropdown-toggle" data-toggle="dropdown">@{{package.measuringMachine}}</h6>
+                                    <div class="dropdown-menu" id="selected">
+                                        <a class="dropdown-item" v-for="measuringMachine in measuringMachines" @click="selectedMachine(measuringMachine.id)">@{{measuringMachine.name}}</a>
+                                    </div>
+                                </div>
+
+                            </div>
+                            <div class="card-body">
+                                <h1>
+                                <table class="table card-text " style="height: 800px">
+                                    <tr>
+                                        <th scope="row">货主</th>
+                                        <td style="border-right:thick double #aaaaaa;">@{{package.owner}}</td>
+                                        <th scope="row">重量(KG)</th>
+                                        <td>@{{package.weight}}</td>
+                                    </tr>
+                                    <tr>
+                                        <th scope="row">发货单号</th>
+                                        <td style="border-right:thick double #aaaaaa;">@{{package.delivery_number}}</td>
+                                        <th scope="row">收件人</th>
+                                        <td>@{{package.recipient}}</td>
+                                    </tr>
+                                    <tr>
+                                        <th scope="row">承运商</th>
+                                        <td style="border-right:thick double #aaaaaa;">@{{package.logistic}}</td>
+                                        <th scope="row">快递单号</th>
+                                        <td>@{{package.logistic_number}}</td>
+                                    </tr>
+                                    <tr>
+                                        <th scope="row">纸箱名称</th>
+                                        <td style="border-right:thick double #aaaaaa;">@{{package.paperBox}}</td>
+                                        <th scope="row">体积(CM³)</th>
+                                        <td>@{{package.bulk}}</td>
+                                    </tr>
+                                    <tr>
+                                        <th scope="row">状态</th>
+                                        <td style="border-right:thick double #aaaaaa;">@{{package.status}}</td>
+                                        <th scope="row">操作时间</th>
+                                        <td>@{{package.created_at}}</td>
+                                    </tr>
+                                </table>
+                                </h1>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+            </section>
+        </div>
+    </div>
+@endsection
+
+@section('lastScript')
+    <style>
+        #selected a:hover{background-color: #4aa0e6;display: block;cursor:pointer}
+        th {color: @if($package&&$package->measuringMachine->status=='在线') green text-success @else red @endif}
+    </style>
+    <script>
+        let vue=new Vue({
+            el:'#list',
+            data:{
+                package:
+                    {@if($package)id:'{{$package->id}}',logistic_number:'{{$package->logistic_number}}',delivery_number:'{{$package->delivery_number}}',
+                    weight:'{{$package->weight}}',owner:'{{$package->owner_name}}',paperBox:'{{$package->paperBox_name}}',
+                    measuringMachine:'{{$package->measuringMachine_name}}',recipient:'{{$package->recipient}}',measuringMachine_id:'{{$package->measuring_machine_id}}',
+                    status:'{{$package->status}}',created_at:'{{$package->created_at}}',bulk:'{{$package->bulk}}',logistic:'{{$package->logistic_name}}'@endif},
+                measuringMachines:[
+                    @foreach($measuringMachines as $measuringMachine)
+                        @if($package&&$measuringMachine->name!=$package->measuringMachine->name)
+                            {id:'{{$measuringMachine->id}}',name:'{{$measuringMachine->name}}',code:'{{$measuringMachine->code}}'},
+                        @endif
+                    @endforeach
+                ]
+            },
+            mounted(){
+                if(this.timer){
+                    clearInterval(this.timer);
+                }else {
+                    this.timer=setInterval(()=>{this.flushData();},18000);
+                }
+            },
+            methods:{
+                selectedMachine(id){
+                    let url='{{url('weight/measureMonitor')}}';
+                    location.href=url+'?id='+id;
+                },
+                flushData(){
+                    let _this=this;
+                    let id=this.package.measuringMachine_id;
+                    axios.post('/weight/measureMonitor/flush',{id:id})
+                        .then(function (response) {
+                            let package=response.data;
+                            if (package){
+                                if (package.id===_this.package.id){
+                                    tempTip.setDuration(4000);
+                                    tempTip.showSuccess('暂无新数据');
+                                    //保留 测试自动播放
+                                    document.getElementById('audio').play();
+                                }else {
+                                    _this.package.id=package.id; _this.package.id=package.id;
+                                    _this.package.logistic_number=package.logistic_number;_this.package.delivery_number=package.delivery_number;
+                                    _this.package.weight=package.weight;_this.package.owner=package.owner_name;
+                                    _this.package.paperBox=package.paperBox_name;_this.package.measuringMachine=package.measuringMachine_name;
+                                    _this.package.recipient=package.recipient;_this.package.status=package.status;
+                                    _this.package.created_at=package.created_at;_this.package.bulk=package.bulk;
+                                    _this.package.logistic=package.logistic_name;
+                                    tempTip.setDuration(4000);
+                                    tempTip.showSuccess('刷新成功!');
+                                }
+                            }
+                        }).catch(function (err) {
+                            tempTip.setDuration(4000);
+                            tempTip.showSuccess('请求异常!');
+                        });
+                }
+            },
+            destroyed(){
+                clearInterval(this.timer);
+            }
+        });
+    </script>
+@endsection

+ 26 - 0
resources/views/weight/menu.blade.php

@@ -0,0 +1,26 @@
+
+<div class="container mt-3" id="nav2">
+    <div class="card">
+        <ul class="nav nav-pills">
+            @can('测量机监视界面-查询')
+                <li class="nav-item">
+                    <a class="nav-link" href="{{url('weight/package/index')}}" :class="{active:isActive('index',3)}">记录</a>
+                </li> @endcan
+            @can('测量记录管理-查询')
+                <li class="nav-item">
+                    <a class="nav-link" href="{{url('weight/measureMonitor')}}" :class="{active:isActive('measureMonitor',2)}">设备</a>
+                </li>
+                <li class="nav-item">
+                    <a class="nav-link text-dark" href="{{url('weight/package/create')}}" :class="{active:isActive('create',3)}">手动录入</a>
+                </li>
+                <li class="nav-item">
+                    <a class="nav-link text-dark" href="{{url('weight/weightExcepted/indexCreate')}}" :class="{active:isActive('weightExcepted',2)}">异常记录</a>
+                </li>
+                <li class="nav-item">
+                    <a class="nav-link text-dark" href="{{url('weight/relating')}}" :class="{active:isActive('relating',2)}">相关设置</a>
+                </li>
+                @endcan
+
+        </ul>
+    </div>
+</div>

+ 1 - 1
resources/views/weigh/menuWeigh.blade.php → resources/views/weight/menuWeight.blade.php

@@ -2,7 +2,7 @@
 
 @section('content')
     <div id="nav2">
-        @component('weigh.menu')
+        @component('weight.menu')
         @endcomponent
         <div class="container">
             <div class="card menu-third" style="background: #f9f0f0;transform: scale(0.95)">

+ 85 - 0
resources/views/weight/package/create.blade.php

@@ -0,0 +1,85 @@
+@extends('layouts.app')
+
+@section('content')
+    <div id="nav2">
+        @component('weight.menu')@endcomponent
+    </div>
+    <div class="container mt-3" id="package">
+        <div class="card col-md-8 offset-md-2">
+            <div class="card-body">
+                <form method="POST" action="{{ url('weight/package') }}">
+                    @csrf
+                    @if(Session::has('successTip'))
+                        <div class="alert alert-success h1">{{Session::get('successTip')}}</div>
+                    @endif
+                    <div class="form-group row">
+                        <label for="name" class="col-2 col-form-label text-right">快递单号</label>
+                        <div class="col-8">
+                            <input type="text" class="form-control @error('logistic_number') is-invalid @enderror"
+                                   name="logistic_number" autocomplete="off" value="{{ old('logistic_number')}}" required>
+                            @error('logistic_number')
+                            <span class="invalid-feedback" role="alert">
+                                    <strong>{{ $errors->first('logistic_number') }}</strong>
+                            </span>
+                            @enderror
+                        </div>
+                    </div>
+                    <div class="form-group row">
+                        <label for="weight" class="col-2 col-form-label text-right">重量</label>
+                        <div class="col-8">
+                            <input type="text" class="form-control @error('weight') is-invalid @enderror"
+                                   name="weight" autocomplete="off" value="{{ old('weight')}}" required>
+                            @error('weight')
+                            <span class="invalid-feedback" role="alert">
+                                    <strong>{{ $errors->first('weight') }}</strong>
+                            </span>
+                            @enderror
+                        </div>
+                    </div>
+                    <div class="form-group row">
+                        <label for="paper_box_id" class="col-2 col-form-label text-right">纸箱</label>
+                        <div class="col-8 form-inline">
+                            <select name="paper_box_id" class="form-control @error('paper_box_id') is-invalid @enderror" v-model="paperBox_id" style="width: 30%;">
+                                <option v-for="paperBox in paperBoxes" :value="paperBox.id">@{{paperBox.model}}</option>
+                            </select>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+                            <input class="form-control-sm" style="width: 150px" placeholder="搜索定位" @input="paperBox_seek">&nbsp;&nbsp;&nbsp;
+                        </div>
+                    </div>
+                    <div class="form-group row">
+                        <div class="col-8 offset-2">
+                            <input type="submit" class="btn btn-success form-control">
+                        </div>
+                    </div>
+                </form>
+            </div>
+        </div>
+    </div>
+@endsection
+@section('lastScript')
+    <script>
+        let vue=new Vue({
+            el:"#package",
+            data:{
+                paperBoxes:[
+                    @foreach($paperBoxes as $paperBox)
+                    {id:'{{$paperBox->id}}',model:'{{$paperBox->model}}'},
+                    @endforeach
+                ],
+                paperBox_id:'',
+            },
+            methods:{
+                paperBox_seek:function (e) {
+                    let _this=this;
+                    let $val=e.target.value;
+                    if($val==='')_this.paperBox_id='';
+                    else
+                        _this.paperBoxes.forEach(function (paperBox) {
+                            if (paperBox.model.includes($val)){
+                                _this.paperBox_id=paperBox.id;
+                            }
+                        });
+                },
+            },
+        });
+    </script>
+@endsection

+ 235 - 0
resources/views/weight/package/index.blade.php

@@ -0,0 +1,235 @@
+
+@extends('layouts.app')
+
+@section('content')
+    <span id="nav2">
+        @component('weight.menu')@endcomponent
+        @component('weight.package.menu')@endcomponent
+    </span>
+    <div id="list">
+        <div class="container mt-3">
+            <div class="card" style="width: 1300px;">
+                <div>
+                    <form  method="GET" action="{{url('weight/package')}}" style="margin-top: 1%" id="optionSubmit">
+                        <table class="table  table-sm table-bordered table-hover text-nowrap ">
+                            <tr>
+                                <td colspan="10"><div class="col" v-if="isBeingFilterConditions" style="padding:0">
+                                        <a  href="{{url('weight/package')}}"><span class="btn btn-warning text-dark">清除过滤条件</span></a>
+                                    </div></td>
+                            </tr>
+                            <tr>
+                                <td>
+                                    <span class="text-muted">每页显示记录:</span>
+                                </td>
+                                <td  colspan="9">
+                                    <select name="paginate" v-model="filterData.paginate" class="tooltipTarget form-control-sm" style="vertical-align: middle" @change="setPaginate">
+                                        <option value="50">50行</option>
+                                        <option value="100">100行</option>
+                                        <option value="200">200行</option>
+                                        <option value="500">500行</option>
+                                        <option value="1000">1000行</option>
+                                    </select></td>
+                            </tr>
+                            <tr>
+                                <td>
+                                    <span class="text-muted">根据条件过滤:</span>
+                                </td>
+                                <td >
+                                    <label class="form-inline" style="width: 350px">时间:
+                                        <input style="width: 150px" name="created_at_start" type="date" v-model="filterData.created_at_start" class="form-control-sm">
+                                        <input style="width: 150px" type="date" name="created_at_end" v-model="filterData.created_at_end" class="form-control-sm">
+                                    </label>
+                                </td>
+                                <td > <label class="form-inline" style="width:200px;margin-left: 2%">货主:
+                                        <input class="form-control-sm" style="width: 80px" placeholder="搜索定位" @input="owner_seek">&nbsp;&nbsp;&nbsp;
+                                        <select name="owner_id" v-model="filterData.owner_id" class="form-control-sm"  @change="setOwner">
+                                            <option >    </option>
+                                            @foreach($owners as $owner)
+                                                <option value="{{$owner->id}}">{{$owner->name}}</option>
+                                            @endforeach
+                                        </select></label><input hidden type="submit" value="kk"></td>
+                                <td > <label class="form-inline" style="width:250px;margin-left: 2%">快递单号:
+                                        <input type="text" name="logistic_number" class="form-control-sm  " v-model="filterData.logistic_number" style="vertical-align: middle"></label></td>
+                                <td > <label  class="form-inline" style="width:250px;margin-left: 2%">发货单号:
+                                        <input type="text" name="delivery_number" class="form-control-sm  " v-model="filterData.delivery_number" style="vertical-align: middle"></label></td>
+                                <td colspan="5"></td>
+                            </tr>
+                            <tr>
+                                <td>
+                                    <span class="text-muted">操作选定记录:</span>
+                                </td>
+                                <td colspan="9">
+                                    <span class="btn btn-sm" @click="packageExport" style="cursor: pointer"
+                                          :class="[checkData>0?'btn-dark':'btn-outline-dark']">导出Excel</span>
+                                    <input hidden type="submit" value="kk">
+                                </td>
+                            </tr>
+                        </table>
+                    </form>
+                </div>
+            <div class="card-body">
+                <table class="table table-striped table-sm text-nowrap">
+                    <tr>
+                        <th>
+                            <label for="all">
+                                <input id="all" type="checkbox" @click="checkAll($event)">全选
+                            </label>
+                        </th>
+                        <th>ID</th>
+                        <th>货主</th>
+                        <th>快递单号</th>
+                        <th>发货单号</th>
+                        <th>波次号</th>
+                        <th>波次规则</th>
+                        <th>操作时间</th>
+                        <th>收件人</th>
+                        <th>收件人电话</th>
+                        <th>物流公司</th>
+                        <th>设备</th>
+                        <th>重(KG)</th>
+                        <th>长*宽*高(cm)</th>
+                        <th>体积(cm³)</th>
+                        <th>纸箱</th>
+                        <th>状态</th>
+                    </tr>
+                    <tr v-for="package in packages">
+                        <td>
+                            <input class="checkItem" type="checkbox" :value="package.id" v-model="checkData">
+                        </td>
+                        <td class="text-muted">@{{package.id}}</td>
+                        <td>@{{package.ownerName}}</td>
+                        <td>@{{package.logisticNumber}}</td>
+                        <td>@{{package.wmsNumber}}</td>
+                        <td>@{{package.batchNumber}}</td>
+                        <td>@{{package.batchRule}}</td>
+                        <td class="text-muted">@{{package.created_at}}</td>
+                        <td>@{{package.recipient}}</td>
+                        <td>@{{package.recipientMobile}}</td>
+                        <td>@{{package.logisticName}}</td>
+                        <td>@{{package.measuringMachineName}}</td>
+                        <td>@{{package.weight}}</td>
+                        <td>@{{package.length}}<a v-if="package.length" class="text-primary">*</a>@{{package.width}}<a class="text-primary" v-if="package.width">*</a>@{{package.height}}</td>
+                        <td>@{{package.bulk}}</td>
+                        <td>@{{package.paperBoxName}}</td>
+                        <td>@{{package.status}}</td>
+                    </tr>
+                </table>
+                {{$packages->links()}}
+            </div>
+        </div>
+    </div>
+    </div>
+@endsection
+
+@section('lastScript')
+    <script>
+        new Vue({
+            el:"#list",
+            data:{
+                packages:[
+                    @foreach($packages as $package)
+                        {id:'{{$package->id}}',ownerName:'{{$package->owner_name}}',logisticNumber:'{{$package->logistic_number}}'
+                        ,wmsNumber:'{{$package->delivery_number}}',batchNumber:'{{$package->batch_number}}',batchRule:'{{$package->batch_rule}}'
+                        ,recipient:'{{$package->recipient}}',recipientMobile:'{{$package->recipient_mobile}}',logisticName:'{{$package->logistic_name}}'
+                        ,measuringMachineName:'{{$package->measuringMachine_name}}',
+                        weight:'{{$package->weight}}', length:'{{$package->length}}',width:'{{$package->width}}',height:'{{$package->height}}',
+                        bulk:'{{$package->bulk}}',paperBoxName:'{{$package->paperBox_name}}',
+                        status:'{{$package->status}}',created_at:'{{$package->created_at}}'},
+                    @endforeach
+                ],
+                owners:[
+                    @foreach($owners as $owner)
+                        {id:'{{$owner->id}}',name:'{{$owner->name}}'},
+                    @endforeach
+                ],
+                filterData:
+                    {paginate:'50',created_at_start:'',created_at_end:'',logistic_number:'',delivery_number:'',owner_id: ''},
+                checkData:[]
+            },
+            mounted:function(){
+                this.initInputs();
+            },
+            watch:{
+                checkData:{
+                    handler(){
+                        if (this.checkData.length === this.packages.length){
+                            document.querySelector('#all').checked = true;
+                        }else {
+                            document.querySelector('#all').checked = false;
+                        }
+                    },
+                    deep:true
+                }
+            },
+            computed:{
+                isBeingFilterConditions:function(){
+
+                    for(let key in this.filterData){
+                        if(this.filterData[key]){
+                            if(key==='paginate')continue;
+                            return true
+                        }
+                    }
+                    return false;
+                },
+
+            },
+            methods:{
+                initInputs:function(){
+                    let data=this;
+                    let uriParts =decodeURI(location.href).split("?");
+                    if(uriParts.length>1){
+                        let params = uriParts[1].split('&');
+                        params.forEach(function(paramPair){
+                            let pair=paramPair.split('=');
+                            let key = pair[0], val = pair[1];
+                            $('input[name="'+key+'"]').val(val);
+                            $('select[name="'+key+'"]').val(val);
+                            decodeURI(data.filterData[key]=val);
+                        });
+                    }
+                },
+                setPaginate:function(e){
+                    this.filterData.paginate=e.target.value;
+                    var form = document.getElementById("optionSubmit");
+                    form.submit();
+                },
+                setOwner:function (e){
+                    this.filterData.owner_id=e.target.value;
+                    var form = document.getElementById("optionSubmit");
+                    form.submit();
+                },
+                checkAll(e){
+                    if (e.target.checked){
+                        this.packages.forEach((el,i)=>{
+                            if (this.checkData.indexOf(el.id) == '-1'){
+                                this.checkData.push(el.id);
+                            }
+                        });
+                    }else {
+                        this.checkData = [];
+                    }
+                },
+                packageExport(){
+                    if (this.checkData&&this.checkData.length<=0){
+                        tempTip.setDuration(4000);
+                        tempTip.showSuccess('没有勾选任何记录');
+                    }else{
+                        location.href="{{url('weight/package/export').'/'}}"+this.checkData;
+                    }
+                },
+                owner_seek:function (e) {
+                    let _this=this;
+                    let $val=e.target.value;
+                    if($val==='')_this.filterData.owner_id='';
+                    else
+                        _this.owners.forEach(function (owner) {
+                            if (owner.name.includes($val)){
+                                _this.filterData.owner_id=owner.id;
+                            }
+                        });
+                },
+            }
+        });
+    </script>
+@endsection

+ 1 - 1
resources/views/weigh/package/menu.blade.php → resources/views/weight/package/menu.blade.php

@@ -3,7 +3,7 @@
         <ul class="nav nav-pills">
             @can('包裹信息-查询')
                 <li class="nav-item">
-                    <a class="nav-link" href="{{url('weigh/package')}}" :class="{active:isActive('',3)}">查询</a>
+                    <a class="nav-link" href="{{url('weight/package/index')}}" :class="{active:isActive('index',3)}">查询</a>
                 </li> @endcan
         </ul>
     </div>

+ 180 - 0
resources/views/weight/weightExcepted/index.blade.php

@@ -0,0 +1,180 @@
+
+@extends('layouts.app')
+
+@section('content')
+    <span id="nav2">
+        @component('weight.menu')@endcomponent
+        @component('weight.weightExcepted.menu')@endcomponent
+    </span>
+    <div id="list">
+        <div class="container mt-3">
+            <div class="card">
+                <div>
+                    <form  method="GET" action="{{url('weight/weightExcepted/'.$view)}}" style="margin-top: 1%" id="optionSubmit">
+                        <table class="table  table-sm table-bordered table-hover text-nowrap ">
+                            <tr>
+                                <td  style="width:200px;"> <label style="margin-left: 2%" class="form-inline">页显示条数:
+                                    <select name="paginate" v-model="filterData.paginate" class="form-control" @change="setPaginate">
+                                        <option value="50">50行</option>
+                                        <option value="100">100行</option>
+                                        <option value="200">200行</option>
+                                        <option value="500">500行</option>
+                                        <option value="1000">1000行</option>
+                                    </select></label></td>
+                                <td colspan="5">
+                                    <label style="margin-left: 5px"> 操作选定记录:</label>
+                                    <span class="btn btn-sm" @click="weightExport" style="cursor: pointer"
+                                          :class="[checkData>0?'btn-dark':'btn-outline-dark']">导出Excel</span>
+                                    <input hidden type="submit" value="kk">
+                                </td>
+                            </tr>
+                        </table>
+                    </form>
+                </div>
+            <div class="card-body">
+                <table class="table table-striped table-sm">
+                    <tr style="color: red">
+                        <th>
+                            <label for="all">
+                                <input id="all" type="checkbox" @click="checkAll($event)">全选
+                            </label>
+                        </th>
+                        <th>ID</th>
+                        <th>快递单号</th>
+                        <th>物流公司</th>
+                        @if($view=="indexIssued")
+                            <th>货主</th>
+                            <th>发货单号</th>
+                            <th>下发时间</th>
+                            <th>波次号</th>
+                            <th>波次规则</th>
+                            <th>收件人</th>
+                            <th>收件人电话</th>
+                        @else
+                            <th>设备</th>
+                            <th>称重时间</th>
+                            <th>重(KG)</th>
+                            <th>长(CM)</th>
+                            <th>宽(CM)</th>
+                            <th>高(CM)</th>
+                            <th>体积(CM³)</th>
+                            <th>纸箱</th>
+                        @endif
+                    </tr>
+                    <tr v-for="weightExcepted in weightExcepteds">
+                        <td>
+                            <input class="checkItem" type="checkbox" :value="weightExcepted.id" v-model="checkData">
+                        </td>
+                        <td class="text-muted">@{{weightExcepted.id}}</td>
+                        <td>@{{weightExcepted.logisticNumber}}</td>
+                        <td>@{{weightExcepted.carrierName}}</td>
+                        @if($view=="indexIssued")
+                            <td>@{{weightExcepted.ownerName}}</td>
+                            <td>@{{weightExcepted.deliveryNumber}}</td>
+                            <td class="text-muted">@{{weightExcepted.createdAt}}</td>
+                            <td>@{{weightExcepted.batchNumber}}</td>
+                            <td>@{{weightExcepted.batchRule}}</td>
+                            <td>@{{weightExcepted.recipient}}</td>
+                            <td>@{{weightExcepted.recipientMobile}}</td>
+                        @else
+                            <td>@{{weightExcepted.measuringMachineName}}</td>
+                            <td class="text-muted">@{{weightExcepted.createdAt}}</td>
+                            <td>@{{weightExcepted.weight}}</td>
+                            <td>@{{weightExcepted.length}}</td>
+                            <td>@{{weightExcepted.width}}</td>
+                            <td>@{{weightExcepted.height}}</td>
+                            <td>@{{weightExcepted.bulk}}</td>
+                            <td>@{{weightExcepted.paperBoxName}}</td>
+                        @endif
+                    </tr>
+                </table>
+                {{$weightExcepteds->links()}}
+            </div>
+        </div>
+    </div>
+    </div>
+@endsection
+
+@section('lastScript')
+    <script>
+        new Vue({
+            el:"#list",
+            data:{
+
+
+                weightExcepteds:[
+                    @foreach($weightExcepteds as $weightExcepted)
+                        @if($view=="indexIssued")
+                            {id:'{{$weightExcepted->id}}',ownerName:'{{$weightExcepted->owner_name}}',logisticNumber:'{{$weightExcepted->logistic_number}}',
+                            deliveryNumber:'{{$weightExcepted->delivery_number}}',createdAt:'{{$weightExcepted->created_at}}',
+                            batchNumber:'{{$weightExcepted->batch_number}}', batchRule:'{{$weightExcepted->batch_rule}}',recipient:'{{$weightExcepted->recipient}}',
+                            recipientMobile:'{{$weightExcepted->recipient_mobile}}',carrierName:'{{$weightExcepted->logistic_name}}'},
+                        @else
+                            {id:'{{$weightExcepted->id}}',logisticNumber:'{{$weightExcepted->logistic_number}}',carrierName:'{{$weightExcepted->logistic_name}}',
+                            measuringMachineName:'{{$weightExcepted->measuringMachine_name}}',createdAt:'{{$weightExcepted->created_at}}',
+                            weight:'{{$weightExcepted->weight}}', length:'{{$weightExcepted->length}}',width:'{{$weightExcepted->width}}',height:'{{$weightExcepted->height}}',
+                            bulk:'{{$weightExcepted->bulk}}',paperBoxName:'{{$weightExcepted->paperBox_name}}',},
+                        @endif
+                    @endforeach
+                ],
+                filterData:{paginate:50},
+                checkData:[]
+            },
+           mounted:function(){
+                this.initInputs();
+            },
+            watch:{
+                checkData:{
+                    handler(){
+                        if (this.checkData.length === this.weightExcepteds.length){
+                            document.querySelector('#all').checked = true;
+                        }else {
+                            document.querySelector('#all').checked = false;
+                        }
+                    },
+                    deep:true
+                }
+            },
+            methods:{
+                initInputs:function(){
+                    let data=this;
+                    let uriParts =decodeURI(location.href).split("?");
+                    if(uriParts.length>1){
+                        let params = uriParts[1].split('&');
+                        params.forEach(function(paramPair){
+                            let pair=paramPair.split('=');
+                            let key = pair[0], val = pair[1];
+                            $('input[name="'+key+'"]').val(val);
+                            $('select[name="'+key+'"]').val(val);
+                            decodeURI(data.filterData[key]=val);
+                        });
+                    }
+                },
+                setPaginate:function(e){
+                    this.filterData.paginate=e.target.value;
+                    var form = document.getElementById("optionSubmit");
+                    form.submit();
+                },
+                checkAll(e){
+                    if (e.target.checked){
+                        this.weightExcepteds.forEach((el,i)=>{
+                            if (this.checkData.indexOf(el.id) == '-1'){
+                                this.checkData.push(el.id);
+                            }
+                        });
+                    }else {
+                        this.checkData = [];
+                    }
+                },
+                weightExport(){
+                    if (this.checkData.length<=0){
+                        tempTip.setDuration(4000);
+                        tempTip.showSuccess('没有勾选任何记录');
+                    }else{
+                        location.href="{{url('weight/weightExcepted/export').'/'}}"+this.checkData;
+                    }
+                }
+            }
+        });
+    </script>
+@endsection

+ 14 - 0
resources/views/weight/weightExcepted/menu.blade.php

@@ -0,0 +1,14 @@
+<div class="container">
+    <div class="card menu-third" style="background: #f9f0f0;transform: scale(0.95)">
+        <ul class="nav nav-pills">
+            @can('包裹信息-查看异常')
+                <li class="nav-item">
+                    <a class="nav-link" href="{{url('weight/weightExcepted/indexCreate')}}" :class="{active:isActive('indexCreate',3)}">录入异常</a>
+                </li>
+                <li class="nav-item">
+                    <a class="nav-link" href="{{url('weight/weightExcepted/indexIssued')}}" :class="{active:isActive('indexIssued',3)}">下发异常</a>
+                </li>
+            @endcan
+        </ul>
+    </div>
+</div>

+ 12 - 5
routes/web.php

@@ -42,7 +42,9 @@ Route::resource('maintenance/measuringMachine', 'MeasuringMachineController');
 
 Route::get('maintenance/paperBox/index/model', 'PaperBoxController@indexModel');
 Route::get('maintenance/paperBox/index/owner', 'PaperBoxController@indexOwner');
+Route::post('maintenance/paperBox/excel/import','PaperBoxController@import');
 Route::resource('maintenance/paperBox', 'PaperBoxController');
+Route::get('maintenance/paperBox/excel/goImport',function (){return view('maintenance.paperBox.import');});
 
 Route::get('waybill/relating',function (){return view('waybill.menuWaybill');});
 Route::resource('maintenance/waybillPriceModel','WaybillPriceModelsController');
@@ -75,10 +77,6 @@ Route::any('waybillFinancialSnapshot/export/{id}','WaybillFinancialSnapshotsCont
 Route::post('waybillPriceModel/excel/import','WaybillPriceModelsController@import');
 
 
-Route::resource('weigh/measureMonitor','MeasureMonitorController');
-Route::resource('weigh/package','PackageController');
-Route::get('weigh/relating', function () {return view('weigh.menuWeigh');});
-
 Route::post('rejectedBill/{rejectedBill}/edit', 'RejectedBillController@edit');
 Route::resource('rejectedBill', 'RejectedBillController');
 Route::get('rejected/import', 'RejectedController@import');
@@ -93,7 +91,16 @@ Route::post('rejected/exportExcelOnFilterParams', 'RejectedController@exportExce
 Route::resource('rejected', 'RejectedController');
 
 Route::get('maintenance/', function () {return view('maintenance.index');});
-Route::get('weigh/', function () {return view('weigh.index');});
+Route::post('weight/measureMonitor/flush','MeasureMonitorController@flush');
+Route::get('weight/measureMonitor/speech','MeasureMonitorController@speech');
+Route::resource('weight/measureMonitor','MeasureMonitorController');
+Route::get('weight/package/index','PackageController@index');
+Route::resource('weight/package','PackageController');
+Route::get('weight/package/export/{id}','PackageController@export');
+Route::get('weight/relating', function () {return view('weight.menuWeight');});
+Route::get('weight/weightExcepted/indexCreate','WeighExceptedController@indexCreate');
+Route::get('weight/weightExcepted/indexIssued','WeighExceptedController@indexIssued');
+Route::get('weight/weightExcepted/export/{id}','WeighExceptedController@export');
 
 
 Route::any('test/{method}', 'TestController@method'); //测试

+ 2 - 2
tests/Unit/MeasureMonitorTest.php

@@ -45,9 +45,9 @@ class MeasureMonitorTest extends TestCase
      * @depends testUser
      */
     public function testIndex(User $userMark,User $user){
-        $response=$this->actingAs($user)->get('weigh/measureMonitor');
+        $response=$this->actingAs($user)->get('weight/measureMonitor');
         $response->assertOk();
-        $response=$this->actingAs($userMark)->get('weigh/measureMonitor');
+        $response=$this->actingAs($userMark)->get('weight/measureMonitor');
         $response->assertStatus(302)->assertRedirect('/');
     }
 }

+ 2 - 2
tests/Unit/PackageTest.php

@@ -65,9 +65,9 @@ class PackageTest extends TestCase
      * @depends testAddPackage
      */
     public function testIndex(User $user,User $userMark,Package $package){
-        $response=$this->actingAs($user)->get('weigh/package');
+        $response=$this->actingAs($user)->get('weight/package');
         $response->assertOk()->assertSee('Test浏览量');
-        $response=$this->actingAs($userMark)->get('weigh/package');
+        $response=$this->actingAs($userMark)->get('weight/package');
         $response->assertStatus(302)->assertRedirect('/');
     }
 

Разница между файлами не показана из-за своего большого размера
+ 0 - 0
tests/codeCoverage/.js/d3.min.js


Разница между файлами не показана из-за своего большого размера
+ 0 - 0
tests/codeCoverage/.js/jquery.min.js


+ 3 - 0
webpack.mix.js

@@ -18,3 +18,6 @@ mix.copy('resources/sass/fonts/','public/fonts');
 mix.copy('resources/icon','public/icon');
 mix.copy('resources/images','public/images');
 mix.copy('resources/icon/favicon.ico','public/favicon.ico');
+mix.copy('resources/images/measuringMachine/off.png','public/off.png');
+mix.copy('resources/images/measuringMachine/on.png','public/on.png');
+mix.copy('resources/audio.mp3','public/audio.mp3');

Некоторые файлы не были показаны из-за большого количества измененных файлов