Ver código fonte

Merge branch 'master' into LD

# Conflicts:
#	app/Http/Controllers/TestController.php
#	tests/Unit/CustomerLogTest.php
LD 5 anos atrás
pai
commit
89c50b5762
89 arquivos alterados com 2622 adições e 748 exclusões
  1. 1 1
      app/Console/Commands/TestMakeCommand.php
  2. 1 1
      app/Console/Commands/WasSyncWmsAsnInformation.php
  3. 4 1
      app/Console/Kernel.php
  4. 1 1
      app/CustomerTag.php
  5. 116 0
      app/Filters/LogFilters.php
  6. 1 1
      app/Http/Controllers/CitiesController.php
  7. 8 4
      app/Http/Controllers/ControlPanelController.php
  8. 29 9
      app/Http/Controllers/CustomerBaseController.php
  9. 4 1
      app/Http/Controllers/CustomerLogController.php
  10. 9 58
      app/Http/Controllers/LogController.php
  11. 9 7
      app/Http/Controllers/LogisticController.php
  12. 18 0
      app/Http/Controllers/OrderIssueController.php
  13. 2 3
      app/Http/Controllers/OwnerController.php
  14. 34 15
      app/Http/Controllers/PriceModelController.php
  15. 50 13
      app/Http/Controllers/StoreController.php
  16. 37 10
      app/Http/Controllers/TestController.php
  17. 1 0
      app/Http/Controllers/WaybillController.php
  18. 1 1
      app/Http/Controllers/api/thirdPart/jianshang/RejectedController.php
  19. 36 4
      app/Imports/ExpressImport.php
  20. 46 5
      app/Imports/OwnerPriceDirectLogisticDetailImport.php
  21. 74 11
      app/Imports/OwnerPriceLogisticDetailImport.php
  22. 4 3
      app/Imports/WaybillPriceModelsImport.php
  23. 4 0
      app/Log.php
  24. 8 0
      app/Observers/OwnerObserver.php
  25. 4 0
      app/Providers/AppServiceProvider.php
  26. 6 6
      app/Services/CommodityService.php
  27. 1 1
      app/Services/LogisticService.php
  28. 53 11
      app/Services/NewOrderCountingRecordService.php
  29. 7 2
      app/Services/OrderIssueService.php
  30. 21 6
      app/Services/OrderService.php
  31. 32 1
      app/Services/OwnerService.php
  32. 3 4
      app/Services/RejectedBillService.php
  33. 6 5
      app/Services/StoreService.php
  34. 4 1
      app/StoreItems.php
  35. 3 0
      app/Waybill.php
  36. 1 1
      composer.json
  37. 1 0
      config/cache.php
  38. 3 0
      database/migrations/2020_12_14_103401_create_customerlogstatuses_table.php
  39. 44 0
      database/migrations/2020_12_31_115716_change_log_index_all.php
  40. 29 0
      database/migrations/2021_01_06_105043_change_order_issues_table_final_status.php
  41. 32 0
      database/migrations/2021_01_06_170342_add_column_count_table_customer_tags.php
  42. 31 0
      database/migrations/2021_01_07_144845_add_authorities_order_issue_batch_archive.php
  43. 1 1
      package-lock.json
  44. 6 1
      resources/js/queryForm/queryForm.js
  45. 27 1
      resources/sass/text.scss
  46. 276 211
      resources/views/control/panel.blade.php
  47. 13 32
      resources/views/customer/customer/_customerLog.blade.php
  48. 256 109
      resources/views/customer/customer/index.blade.php
  49. 0 55
      resources/views/customer/project/_three.blade.php
  50. 545 41
      resources/views/customer/project/create.blade.php
  51. 8 5
      resources/views/customer/project/part/_addFeature.blade.php
  52. 58 0
      resources/views/customer/project/part/_directLogistic.blade.php
  53. 64 0
      resources/views/customer/project/part/_express.blade.php
  54. 75 0
      resources/views/customer/project/part/_logistic.blade.php
  55. 91 0
      resources/views/customer/project/part/_logisticDetail.blade.php
  56. 0 0
      resources/views/customer/project/part/_one.blade.php
  57. 55 54
      resources/views/customer/project/part/_operation.blade.php
  58. 0 0
      resources/views/customer/project/part/_storage.blade.php
  59. 276 0
      resources/views/customer/project/part/_three.blade.php
  60. 0 0
      resources/views/customer/project/part/_two.blade.php
  61. 12 4
      resources/views/maintenance/log/index.blade.php
  62. 1 1
      resources/views/maintenance/owner/recycle.blade.php
  63. 1 1
      resources/views/maintenance/priceModel/logistic/index.blade.php
  64. 1 1
      resources/views/maintenance/priceModel/waybillPriceModel/index.blade.php
  65. 5 8
      resources/views/order/index/delivering.blade.php
  66. 40 6
      resources/views/order/issue/index.blade.php
  67. 1 1
      resources/views/waybill/index.blade.php
  68. 1 1
      resources/views/waybill/recycle.blade.php
  69. 1 1
      routes/apiLocal.php
  70. 6 0
      routes/web.php
  71. 0 2
      tests/Services/BatchService/TestGetBatchByCodes.php
  72. 0 2
      tests/Services/CityService/FindByNameTest.php
  73. 0 2
      tests/Services/LogisticService/GetLogisticByCodeTest.php
  74. 0 2
      tests/Services/LogisticService/GetLogisticByCodesTest.php
  75. 0 2
      tests/Services/LogisticTimingService/FindByParamsTest.php
  76. 2 1
      tests/Services/NewOrderCountingRecordService/OrderCountingRecordsTest.php
  77. 2 1
      tests/Services/NewOrderCountingRecordService/TransfersToConditionsTest.php
  78. 0 1
      tests/Services/OracleDOCOrderHeaderService/GetWMSOrderOnEditDateTest.php
  79. 0 1
      tests/Services/OracleDOCOrderHeaderService/GetWMSOrderOnStartDateTest.php
  80. 0 2
      tests/Services/OracleDOCOrderHeaderService/GetWmsOrderOnStartDateEditTest.php
  81. 0 1
      tests/Services/OracleDOCOrderHeaderService/GetWmsOrderOnstartDateCreateTest.php
  82. 0 2
      tests/Services/OrderCommodityService/GetReGroupActAllocationDetailsTest.php
  83. 0 2
      tests/Services/OrderCommodityService/SyncOrderCommodityTest.php
  84. 0 1
      tests/Services/OrderIssueService/GetRecycleBinPaginateTest.php
  85. 0 1
      tests/Services/OrderIssueService/OrderIssueTagTest.php
  86. 0 1
      tests/Services/OrderIssueService/RecoverOrderIssueTest.php
  87. 0 2
      tests/Services/OrderPackageCommoditiesService/RegroupOrderCommoditiesTest.php
  88. 0 1
      tests/Services/StoreService/CreateStoreTest.php
  89. 19 0
      tests/Unit/CustomerLogTest.php

+ 1 - 1
app/Console/Commands/TestMakeCommand.php

@@ -52,7 +52,7 @@ class TestMakeCommand extends \Illuminate\Foundation\Console\TestMakeCommand
     protected function getMethodName()
     {
         $input= trim($this->argument('name'));
-        return '\Test'.ucfirst(explode(':',$input)[1]);
+        return ucfirst(explode(':',$input)[1]).'Test';
     }
 
     protected function getStub()

+ 1 - 1
app/Console/Commands/WasSyncWmsAsnInformation.php

@@ -54,7 +54,7 @@ class WasSyncWmsAsnInformation extends Command
     {
         $this->init();
         if($this->is_enabled==false)return;
-        sleep(rand(10,25));
+        sleep(rand(1,2));
         $start_time =  Cache::remember($this->task_start_at,null,function (){
             return ValueStore::query()->firstOrCreate(['name'=>$this->task_start_at])->first()->value;
         });

+ 4 - 1
app/Console/Kernel.php

@@ -13,6 +13,7 @@ use App\Console\Commands\SyncUserVisitMenuLogsCacheTask;
 use App\Console\Commands\SyncWmsCommoditiesInformation;
 use App\Console\Commands\SyncWMSOrderTask;
 use App\Console\Commands\TestTemp;
+use App\Console\Commands\WasSyncWmsAsnInformation;
 use App\Console\Commands\WASSyncWMSOrderInformation;
 use Illuminate\Console\Scheduling\Schedule;
 use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
@@ -37,7 +38,8 @@ class Kernel extends ConsoleKernel
         SyncBatchTask::class,
         SyncWMSOrderTask::class,
         SyncWmsCommoditiesInformation::class,
-        ClearCancelledOrderTask::class
+        ClearCancelledOrderTask::class,
+        WasSyncWmsAsnInformation::class,
     ];
 
     /**
@@ -60,6 +62,7 @@ class Kernel extends ConsoleKernel
         $schedule->command('sync:order')->everyMinute();
         $schedule->command('SyncWmsCommoditiesInformation')->everyMinute();
         $schedule->command('clear:cancelledOrder')->everyTenMinutes();
+        $schedule->command('WasSyncWmsAsnInformation')->everyMinute();
     }
 
     /**

+ 1 - 1
app/CustomerTag.php

@@ -14,6 +14,6 @@ class CustomerTag extends Model
     use ModelTimeFormat;
 
     protected $fillable=[
-        "name","explanation"
+        "name","explanation","count"
     ];
 }

+ 116 - 0
app/Filters/LogFilters.php

@@ -0,0 +1,116 @@
+<?php
+
+
+namespace App\Filters;
+
+
+use Carbon\Carbon;
+use Illuminate\Http\Request;
+use Illuminate\Support\Arr;
+
+class LogFilters
+{
+    protected $request;
+    protected $queryBuilder;
+    protected $filters = ['username', 'type', 'description',
+        'created_at_start', 'created_at_end', 'is_exception'];
+    protected $array_filter;
+
+    public function __construct(Request $request)
+    {
+        $this->request = $request;
+        $this->array_filter = array_filter($this->request->only($this->filters));
+    }
+
+    public function apply($builder)
+    {
+        $this->queryBuilder = $builder;
+        foreach ($this->array_filter as $filter => $value) {
+            if (method_exists($this, $filter)) {
+                $this->$filter($value, $this->queryBuilder);
+            }
+        }
+        return $this->afterApply($this->queryBuilder);
+    }
+
+    /**
+     * 后置处理,解决查询条件之间的关联关系,方法名后缀’_after‘
+     * @param $builder
+     * @return mixed
+     */
+    public function afterApply($builder)
+    {
+        $this->queryBuilder = $builder;
+        foreach ($this->array_filter as $filter => $value) {
+            $filter .= '_after';
+            if (method_exists($this, $filter)) {
+                $this->$filter($value, $this->queryBuilder);
+            }
+        }
+        if (!Arr::hasAny($this->array_filter, ['created_at_start', 'created_at_end'])) {
+            $start = Carbon::now()->toDateString();
+            $end = Carbon::tomorrow()->toDateString();
+            $this->queryBuilder = $this->queryBuilder->where('created_at', '>=', $start)->where('created_at', '<', $end);
+        }
+        return $this->queryBuilder;
+    }
+
+    private function created_at_start($created_at_start)
+    {
+        $this->queryBuilder->where('created_at', '>=', $created_at_start);
+    }
+
+    private function created_at_end($created_at_end)
+    {
+        $this->queryBuilder->where('created_at', '<', Carbon::parse($created_at_end)->addDay()->toDateString());
+    }
+
+    /**
+     * 如果中传入开始时间,默认结束时间为开始时间的下一天
+     * @param $created_at_start
+     */
+    private function created_at_start_after($created_at_start)
+    {
+        if (!Arr::has($this->array_filter, 'created_at_end')) {
+            $endDay = Carbon::parse($created_at_start)->addDay()->toDateString();
+            $this->queryBuilder->where('created_at', '<', $endDay);
+        }
+    }
+
+    /**
+     * 如果只传入截止时间,只查询截止时间这一天的数据
+     * @param $created_at_end
+     */
+    private function created_at_end_after($created_at_end)
+    {
+        if (!Arr::has($this->array_filter, 'created_at_start')) {
+            $startDay = Carbon::parse($created_at_end)->toDateString();
+            $this->queryBuilder->where('created_at', '>=', $startDay);
+        }
+    }
+
+    private function description($description)
+    {
+        $this->queryBuilder->where("description", 'like', $description . '%');
+    }
+
+    private function type($type)
+    {
+        $types = array_filter(preg_split('/[,, ]+/is', $type));
+        $this->queryBuilder->whereIn("type", $types);
+    }
+
+    private function username($username)
+    {
+        $this->queryBuilder->whereIn("id_user", function ($query) use ($username) {
+            return $query->from("users")->select("id")->where("name", 'like', $username . '%');
+        });
+    }
+
+    private function is_exception()
+    {
+        $this->queryBuilder->where(function ($query) {
+            $query->where("method", "like", "ERROR%")->orWhere("method", "like", "EXCEPTION%");
+        });
+    }
+}

+ 1 - 1
app/Http/Controllers/CitiesController.php

@@ -83,6 +83,6 @@ class CitiesController extends Controller
     }
 
     public function get(){
-        return City::query()->select("id","name","province_id")->get();
+        return ["success"=>true,"data"=>City::query()->select("id","name","province_id")->get()];
     }
 }

+ 8 - 4
app/Http/Controllers/ControlPanelController.php

@@ -2,6 +2,7 @@
 
 namespace App\Http\Controllers;
 
+use App\Owner;
 use App\Services\CheckActiveMenuService;
 use App\Services\LaborReportsCountingRecordService;
 use App\Services\NewOrderCountingRecordService;
@@ -40,15 +41,16 @@ class ControlPanelController extends Controller
         $start = (new Carbon())->subMonth()->toDateString();
         $end = (new Carbon())->toDateString();
         $ownerIds = $this->getCountingOwnerIds(null);
+        $owners=Owner::query()->whereIn('id',$ownerIds)->get();
         $unit = '日';
-        $orderCountingRecords = $orderCountingRecordService->orderCountingRecords($start, $end, $unit, $ownerIds);
+        $orderCountingRecords = $orderCountingRecordService->orderCountingRecordsFromCache($start, $end, $unit, $ownerIds);
         $logisticsCountingRecords = $orderCountingRecordService->logisticsCountingRecords($start, $end, $ownerIds);
         $warehouseCountingRecords = $orderCountingRecordService->warehouseCountingRecords($start, $end, $ownerIds);
 
         $laborReportsCountingRecordService = app(LaborReportsCountingRecordService::class);
         $laborReportsCountingRecords = $laborReportsCountingRecordService->get($start, $end, $unit);
         $laborReportsUserGroupsCount = $laborReportsCountingRecordService->userGroupsCount($start, $end);
-        return view('control.panel', compact('menus', 'warehousesOrders', 'orderCountingRecords', 'logisticsCountingRecords', 'warehouseCountingRecords', 'laborReportsCountingRecords', 'laborReportsUserGroupsCount'));
+        return view('control.panel', compact('owners','menus', 'warehousesOrders', 'orderCountingRecords', 'logisticsCountingRecords', 'warehouseCountingRecords', 'laborReportsCountingRecords', 'laborReportsUserGroupsCount'));
     }
 
     public function orderCountingRecordsApi(Request $request)
@@ -59,7 +61,8 @@ class ControlPanelController extends Controller
         $orderCountingRecordService = app(NewOrderCountingRecordService::class);
         $start = Carbon::parse($request->start)->gt(Carbon::now()) ? Carbon::now()->toDateString() : $request->start;
         $end = Carbon::parse($request->end)->gt(Carbon::now()) ? Carbon::now()->toDateString() : $request->end;
-        $ownerIds = $this->getCountingOwnerIds(null);
+        $ownerIds=$request->owner_ids;
+        if (!$ownerIds || in_array('all',$ownerIds)) $ownerIds = $this->getCountingOwnerIds(null);
         $orderCountingRecords = $orderCountingRecordService->orderCountingRecords($start, $end, $request->unit, $ownerIds);
         return compact('orderCountingRecords');
     }
@@ -72,7 +75,8 @@ class ControlPanelController extends Controller
         $orderCountingRecordService = app(NewOrderCountingRecordService::class);
         $start = Carbon::parse($request->start)->gt(Carbon::now()) ? Carbon::now()->toDateString() : $request->start;
         $end = Carbon::parse($request->end)->gt(Carbon::now()) ? Carbon::now()->toDateString() : $request->end;
-        $ownerIds = $this->getCountingOwnerIds(null);
+        $ownerIds=$request->input('owner_ids');
+        if (!$ownerIds || in_array('all',$ownerIds)) $ownerIds = $this->getCountingOwnerIds(null);
         $logisticsCountingRecords = $orderCountingRecordService->logisticsCountingRecords($start, $end, $ownerIds);
         return compact('logisticsCountingRecords');
     }

+ 29 - 9
app/Http/Controllers/CustomerBaseController.php

@@ -4,11 +4,14 @@ namespace App\Http\Controllers;
 
 use App\Components\SyncResponse;
 use App\Customer;
+use App\CustomerLog;
 use App\CustomerTag;
 use App\Owner;
 use App\Services\LogService;
+use Illuminate\Database\Eloquent\Builder;
 use Illuminate\Http\Request;
 use Illuminate\Http\Response;
+use Illuminate\Support\Facades\DB;
 use Illuminate\Support\Facades\Gate;
 use Illuminate\Support\Facades\Validator;
 
@@ -24,9 +27,12 @@ class CustomerBaseController extends Controller
     public function index(Request $request)
     {
         $this->gate("客户-查询");
-        $customers = app('CustomerService')->paginate($request->input(),["owners.contracts.files","tags:id,name"]);
+        $customers = app('CustomerService')->paginate($request->input(),["owners.contracts.files","tags:id,name","customerLogs"=>function($query){
+            /** @var Builder $query */
+            $query->with(["status:id,name,created_at","user:id,name"])->orderByDesc('id');
+        }]);
         $owners = app("OwnerService")->getIntersectPermitting(['id','name','customer_id']);
-        $tags = CustomerTag::query()->get(["id","name"]);
+        $tags = CustomerTag::query()->orderByDesc('count')->get(["id","name"]);
         return response()->view('customer.customer.index',compact("customers","owners","tags"));
     }
 
@@ -149,13 +155,27 @@ class CustomerBaseController extends Controller
 
     public function addTag(Request $request)
     {
-        $tags = $request->input("tags");
+        $tag = $request->input("tag");
         $id = $request->input("id");
-        /** @var Customer $customer */
-        $customer = app("CustomerService")->find($id);
-        if (!$customer)return ["success"=>false,"data"=>"客户不存在"];
-        $customer->tags()->sync($tags);
-        $customer->load("tags");
-        return ["success"=>true,"data"=>$customer->tags];
+        DB::transaction(function ()use ($id,$tag){
+            DB::insert(DB::raw("INSERT INTO customer_tag_customer VALUES (?,?)"),[$id,$tag]);
+            CustomerTag::query()->where("id",$tag)->increment("count");
+            DB::commit();
+        });
+        return ["success"=>true];
+    }
+
+    public function delTag(Request $request)
+    {
+        $tag = $request->input("tag");
+        $id = $request->input("id");
+        DB::delete(DB::raw("DELETE FROM customer_tag_customer WHERE customer_id = ? AND customer_tag_id = ?"),[$id,$tag]);
+        return ["success"=>true];
+    }
+
+    public function destroyLog(Request $request)
+    {
+        CustomerLog::destroy($request->input("id"));
+        return ["success"=>true];
     }
 }

+ 4 - 1
app/Http/Controllers/CustomerLogController.php

@@ -20,7 +20,10 @@ class CustomerLogController extends Controller
     {
         $id = $request->input("id");
         if (!$id) return ["success"=>false,"data"=>"非法参数"];
-        return ["success"=>true,"data"=>app("CustomerLogService")->update(["id"=>$id],["description"=>$request->input("description")])];
+        $params = [];
+        if ($request->has("description"))$params["description"] = $request->input("description");
+        if ($request->has("customer_log_status_id"))$params["customer_log_status_id"] = $request->input("customer_log_status_id");
+        return ["success"=>true,"data"=>app("CustomerLogService")->update(["id"=>$id],$params)];
     }
 
     public function store(Request $request)

+ 9 - 58
app/Http/Controllers/LogController.php

@@ -2,87 +2,38 @@
 
 namespace App\Http\Controllers;
 
+use App\Filters\LogFilters;
 use App\Log;
 use App\Services\LogService;
-use Exception;
 use Illuminate\Contracts\Foundation\Application;
 use Illuminate\Contracts\Pagination\LengthAwarePaginator;
-use Illuminate\Database\Eloquent\Builder;
-use Illuminate\Http\RedirectResponse;
+use Illuminate\Contracts\View\Factory;
 use Illuminate\Http\Request;
 use Illuminate\Http\Response;
-use Illuminate\Routing\Redirector;
-use Illuminate\Support\Facades\Auth;
 use Illuminate\Support\Facades\Gate;
-use Illuminate\Support\Facades\Validator;
-use function GuzzleHttp\Psr7\str;
+use Illuminate\View\View;
 
 class LogController extends Controller
 {
     /**
-     * Display a listing of the resource.
-     *
      * @param Request $request
-     * @return Application|LengthAwarePaginator|\Illuminate\Contracts\View\Factory|\Illuminate\View\View
+     * @param LogFilters $filters
+     * @return Application|LengthAwarePaginator|Factory|View
      */
-    public function index(Request $request)
+    public function index(Request $request, LogFilters $filters)
     {
         if (!Gate::allows('日志-查询')) {
             return redirect(url('/'));
         }
-        //没有查询条件,默认展示最近50条
-        if (!$request->has('created_at_start') &&
-            !$request->has('created_at_end') &&
-            !$request->has('class') &&
-            !$request->has('method') &&
-            !$request->has('description') &&
-            !$request->has("is_exception")
-        ) {
-            $logs = Log::query()
-                ->with('user:id,name')
-                ->orderBy('id', 'desc')
-                ->paginate(50);
-            return view('maintenance.log.index', ['logs' => $logs]);
-        }
-        //不传开始时间提示错误信息并返回
-        if (!$request->has('created_at_start')) {
-            session()->flash('warning', '请选择开始时间');
-            return view('maintenance.log.index', ['logs' => null]);
-        }
-        $query = Log::query()->with('user:id,name');
-        if ($request->has('class')) {
-            $query->where('class', 'like', $request['class'] . '%');
-        }
-        if ($request->has('method')) {
-            $query->where('method', 'like', $request['method'] . '%');
-        }
-        if ($request->has('description')) {
-            $str = $request->description;
-            $str = trim($str, '\\');
-            $str = str_replace('\\', '\\\\', $str);
-            $query->where('description', 'like', '%' . $str . '%');
-        }
-        if ($request->has('created_at_start')) {
-            $query->where('created_at', '>=', $request->created_at_start." 00:00:00");
-        }
-        if ($request->has('created_at_end')) {
-            $query->where('created_at', '<=', $request->created_at_end." 23:59:59");
-        }
-        if ($request->has("is_exception")){
-            $query->where(function(Builder $query){
-                $query->where("method","like","ERROR%")->orWhere("method","like","EXCEPTION%");
-            });
-        }
-        $query->orderByDesc('id');
-        $logs = $query->with('user:id,name')->paginate($request->paginate??50);
-        return view('maintenance.log.index', ['logs' => $logs]);
+        $logs = Log::query()->filter($filters)->orderByDesc('id')->with('user:id,name')->paginate($request->input('paginate')??50);
+        return view('maintenance.log.index', compact('logs'));
     }
 
     /**
      * Display the specified resource.
      *
      * @param Log $log
-     * @return Application|\Illuminate\Contracts\View\Factory|Response|\Illuminate\View\View
+     * @return Application|Factory|Response|View
      */
     public function show(Log $log)
     {

+ 9 - 7
app/Http/Controllers/LogisticController.php

@@ -92,13 +92,6 @@ class LogisticController extends Controller
         return view('maintenance.logistic.edit',['logistic'=>$logistic]);
     }
 
-    /**
-     * Update the specified resource in storage.
-     *
-     * @param Request $request
-     * @param Logistic $logistic
-     * @return Response
-     */
     public function update(Request $request, Logistic $logistic)
     {
         if(!Gate::allows('物流公司-编辑')){ return redirect(url('/'));  }
@@ -123,4 +116,13 @@ class LogisticController extends Controller
         $re=$logistic->delete();
         return ['success'=>$re];
     }
+
+    public function get()
+    {
+        $type = \request("type");
+        $column = ['id','name'];
+        if (!$type)$column[] = "type";
+        $logistics = app("LogisticService")->getSelection($column,$type);
+        return ["success"=>true,"data"=>$logistics];
+    }
 }

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

@@ -769,4 +769,22 @@ class OrderIssueController extends Controller
             return ['success'=>false,'error'=>$e->getMessage()];
         }
     }
+
+    public function archiveOrderIssueApi(Request $request)
+    {
+        if (!Gate::allows('订单管理-问题件-编辑')) return ['success'=>false,'error'=>'没有对应权限'];
+        if(!$request->has('ids'))return ['success'=>false,'error'=>'没有勾选问题件'];
+        $orderIssues = OrderIssue::query()->whereIn('id',$request['ids'])->get();
+        $archiveOrderIssues = $orderIssues->where('final_status','已归档');
+        if($archiveOrderIssues->count() > 0){
+            $archiveIds = $archiveOrderIssues->map(function($archiveOrderIssue){
+                return $archiveOrderIssue->id;
+            });
+            return ['success' =>false,'error' => "选中问题件Id{$archiveIds}已有归档信息,请取消选中或刷新页面重试"];
+        }
+        $orderIssues->each(function($orderIssue){
+            $orderIssue->update(['final_status'=>'已归档']);
+        });
+        return ['success' =>true];
+    }
 }

+ 2 - 3
app/Http/Controllers/OwnerController.php

@@ -164,9 +164,8 @@ class OwnerController extends Controller
             return ['success' => 'false', 'fail_info' => "没有权限"];
         }
         $id = $request->input('id');
-        $owner = Owner::query()->whereNotNull('deleted_at')->where('id', $id)->update([
-            "deleted_at" => null,
-        ]);
+        $owner = Owner::query()->whereNotNull('deleted_at')->where('id', $id)->first();
+        $owner->update(["deleted_at" => null]);
         app('LogService')->log(__METHOD__, __FUNCTION__, json_encode($request->toArray()), Auth::user()['id']);
         return ['success' => 'true', 'owner' => $owner];
     }

+ 34 - 15
app/Http/Controllers/PriceModelController.php

@@ -2,16 +2,17 @@
 
 namespace App\Http\Controllers;
 
+use App\Components\AsyncResponse;
 use App\Imports\ExpressImport;
 use App\Imports\OwnerPriceDirectLogisticDetailImport;
 use App\Imports\OwnerPriceLogisticDetailImport;
 use App\Owner;
-use App\OwnerOutStorageRule;
 use App\OwnerPriceDirectLogistic;
 use App\OwnerPriceExpress;
 use App\OwnerPriceExpressProvince;
 use App\OwnerPriceLogistic;
 use App\OwnerPriceOperation;
+use App\OwnerPriceOperationItemOut;
 use App\Services\common\ExportService;
 use App\Services\LogService;
 use App\Services\OwnerOutStorageRuleService;
@@ -26,6 +27,7 @@ use Maatwebsite\Excel\Facades\Excel;
 
 class PriceModelController extends Controller
 {
+    use AsyncResponse;
     public function storageIndex(Request $request)
     {
         if(!Gate::allows('计费模型-仓储')){ return redirect('denied');  }
@@ -187,7 +189,7 @@ class PriceModelController extends Controller
         $row = app('OwnerOutStorageRuleService')->update(["id"=>$id],["feature"=>$feature]);
         if ($row != 1)return ["success"=>false,"data"=>"影响了“".$row."”行"];
         LogService::log(__METHOD__,"计费模型-修改出库特征",json_encode($request->input()));
-        OwnerOutStorageRule::$features = $result["map"];
+        OwnerPriceOperationItemOut::$features = $result["map"];
         $rule = app('OwnerOutStorageRuleService')->find($id)->append("featureFormat");
         return ["success"=>true,"data"=>["featureFormat"=>$rule->featureFormat,"feature"=>$feature]];
     }
@@ -208,7 +210,8 @@ class PriceModelController extends Controller
             }
         }
         if (count($stack) > 0)return ["success"=>false,"data"=>"组标记错误,起始与结束标记必须对应"];
-        return ["success"=>true,"data"=>$feature];
+        if ($request->has("isFormat"))$this->success(["feature"=>$feature,"featureFormat"=>app("FeatureService")->formatFeature($result["map"], $feature)]);
+        $this->success($feature);
     }
 
     public function operationDestroy($id)
@@ -434,11 +437,16 @@ class PriceModelController extends Controller
         ini_set('max_execution_time',2500);
         ini_set('memory_limit','1526M');
         $fileSuffix = ucwords($fileSuffix);
-        /** @var OwnerPriceExpress $model */
-        $model = app('OwnerPriceExpressService')->find($request->input("id"),["details"]);
-        Excel::import(new ExpressImport($model),$request->file('file')->path(),null,$fileSuffix);
-        if (Cache::has('express'))return Cache::pull('express');
 
+        if (!$request->has("id")){
+            Excel::import(new ExpressImport(null),$request->file('file')->path(),null,$fileSuffix);
+        }else{
+            /** @var OwnerPriceExpress $model */
+            $model = app('OwnerPriceExpressService')->find($request->input("id"),["details"]);
+            Excel::import(new ExpressImport($model),$request->file('file')->path(),null,$fileSuffix);
+        }
+
+        if (Cache::has('express'))return Cache::pull('express');
         return ["success"=>false,"data"=>"导入发生错误,数据无响应"];
     }
 
@@ -651,9 +659,15 @@ class PriceModelController extends Controller
         ini_set('max_execution_time',2500);
         ini_set('memory_limit','1526M');
         $fileSuffix = ucwords($fileSuffix);
-        /** @var OwnerPriceLogistic $model */
-        $model = app('OwnerPriceLogisticService')->find($request->input("id"),["unit","otherUnit","details"]);
-        Excel::import(new OwnerPriceLogisticDetailImport($model),$request->file('file')->path(),null,$fileSuffix);
+
+        if (!$request->has("id")){
+            Excel::import(new OwnerPriceLogisticDetailImport(null),$request->file('file')->path(),null,$fileSuffix);
+        }else{
+            /** @var OwnerPriceLogistic $model */
+            $model = app('OwnerPriceLogisticService')->find($request->input("id"),["unit","otherUnit","details"]);
+            Excel::import(new OwnerPriceLogisticDetailImport($model),$request->file('file')->path(),null,$fileSuffix);
+        }
+
         if (Cache::has('logistic'))return Cache::pull('logistic');
 
         return ["success"=>false,"data"=>"导入发生错误,数据无响应"];
@@ -883,12 +897,17 @@ class PriceModelController extends Controller
         ini_set('max_execution_time',2500);
         ini_set('memory_limit','1526M');
         $fileSuffix = ucwords($fileSuffix);
-        $model = new OwnerPriceDirectLogistic();
-        $model->id = $request->input("id");
-        $model->load("details");
-        Excel::import(new OwnerPriceDirectLogisticDetailImport($model),$request->file('file')->path(),null,$fileSuffix);
-        if (Cache::has('directLogistic'))return Cache::pull('directLogistic');
 
+        if (!$request->has("id")){
+            Excel::import(new OwnerPriceDirectLogisticDetailImport(null),$request->file('file')->path(),null,$fileSuffix);
+        }else{
+            $model = new OwnerPriceDirectLogistic();
+            $model->id = $request->input("id");
+            $model->load("details");
+            Excel::import(new OwnerPriceDirectLogisticDetailImport($model),$request->file('file')->path(),null,$fileSuffix);
+        }
+
+        if (Cache::has('directLogistic'))return Cache::pull('directLogistic');
         return ["success"=>false,"data"=>"导入发生错误,数据无响应"];
     }
 

+ 50 - 13
app/Http/Controllers/StoreController.php

@@ -4,6 +4,7 @@ namespace App\Http\Controllers;
 
 use App\Depository;
 use App\Owner;
+use App\Services\common\BatchUpdateService;
 use App\Services\StoreService;
 use App\Store;
 use App\StoreItems;
@@ -241,20 +242,56 @@ class StoreController extends Controller
         oci_close($conn);
         $warehouse = app('WarehouseService')->firstOrCreate(["code"=>$asn->warehouseid],["code"=>$asn->warehouseid,"name"=>$asn->warehouseid]);
         $owner = app('OwnerService')->firstOrCreate(['code'=>$asn->customerid],['code'=>$asn->customerid,"name"=>$asn->customerid]);
-        $store = app('StoreService')->create([
-            'asn_code'=>$asnno,
-            'warehouse_id'=>$warehouse->id,
-            'owner_id'=>$owner->id,
-            'stored_method'=>'快速入库',
-            'status'=>'已入库',
-            'remark'=>$asn->notes,
-        ]);
-        app('LogService')->log(__METHOD__,"快速入库",json_encode($store));
-        foreach ($items as &$item){
-            $item["store_id"] = $store->id;
+        $store = Store::query()->with("storeItems")->where("asn_code",$asnno)->first();
+        if (!$store){
+            $store = app('StoreService')->create([
+                'asn_code'=>$asnno,
+                'warehouse_id'=>$warehouse->id,
+                'owner_id'=>$owner->id,
+                'stored_method'=>'快速入库',
+                'status'=>'已入库',
+                'remark'=>$asn->notes,
+            ]);
+            app('LogService')->log(__METHOD__,"快速入库",json_encode($store));
+            foreach ($items as &$item){
+                $item["store_id"] = $store->id;
+            }
+            app('StoreItemService')->insert($items);
+            app('LogService')->log(__METHOD__,"快速录入子项",json_encode($items));
+        }else{
+            $store->update([
+                'asn_code'=>$asnno,
+                'warehouse_id'=>$warehouse->id,
+                'owner_id'=>$owner->id,
+                'stored_method'=>'快速入库',
+                'status'=>'已入库',
+                'remark'=>$asn->notes,
+            ]);
+            $insertItem = [];
+            if ($store->storeItems){
+                $updateItem = [["id","asn_line_code","name","sku","barcode","amount","quality","status"]];
+                $existItem = [];
+                $store->storeItems->each(function ($item)use(&$existItem){
+                    $existItem[$item->asn_line_code] = $item->id;
+                });
+                foreach ($items as $item){
+                    if (isset($existItem[$item['asn_line_code']])){
+                        $item["id"] = $existItem[$item['asn_line_code']];
+                        $updateItem[] = $item;
+                    }else {
+                        $item["store_id"] = $store->id;
+                        $insertItem[] = $item;
+                    }
+                }
+                if (count($updateItem) > 1) app(BatchUpdateService::class)->batchUpdate("store_items",$updateItem);
+            }else{
+                foreach ($items as $item){
+                    $item["store_id"] = $store->id;
+                    $insertItem[] = $item;
+                }
+            }
+            if ($insertItem)app('StoreItemService')->insert($items);
         }
-        app('StoreItemService')->insert($items);
-        app('LogService')->log(__METHOD__,"快速录入子项",json_encode($items));
         return ['success'=>true,"data"=>"已成功将“".$asnno."”入库"];
     }
 

+ 37 - 10
app/Http/Controllers/TestController.php

@@ -25,6 +25,7 @@ use App\Log;
 use App\Logistic;
 use App\Menu;
 use App\OracleActAllocationDetails;
+use App\OracleBasCustomer;
 use App\OracleBasSKU;
 use App\OracleDOCASNHeader;
 use App\OracleDOCOrderHeader;
@@ -88,6 +89,7 @@ use Illuminate\Http\Request;
 use Illuminate\Support\Facades\DB;
 use Illuminate\Support\Facades\Hash;
 use Illuminate\Support\Facades\Http;
+use Illuminate\Support\Facades\Redis;
 use Illuminate\Support\Facades\Storage;
 use Illuminate\Support\Str;
 use Maatwebsite\Excel\Facades\Excel;
@@ -158,7 +160,7 @@ sql;
     }
     public function zzd()
     {
-        $this->disposeDetail();
+        dd(env("DB_HOST"));
     }
 
     public function zzd1()
@@ -281,7 +283,40 @@ sql;
 
     function t1(Request $request)
     {
-        var_dump(is_array(collect([1])));
+        $times=12345;
+        $start_at = microtime(true);
+        for($i=0;$i<$times;$i++){
+            Cache::put(md5('k_delme'.$i), 'a');
+        }
+        echo microtime(true)-$start_at, '<br>';
+
+        $start_at = microtime(true);
+        for($i=0;$i<$times;$i++){
+            Cache::get(md5('k_delme'.$i));
+        }
+        echo microtime(true)-$start_at, '<br>';
+
+        $start_at = microtime(true);
+        for($i=0;$i<$times;$i++){
+            Cache::pull(md5('k_delme'.$i));
+        }
+        echo microtime(true)-$start_at, '<br>';
+        for($i=0;$i<$times;$i++){
+            Redis::set(md5('k_delme'.$i), 'a');
+        }
+        echo microtime(true)-$start_at, '<br>';
+
+        $start_at = microtime(true);
+        for($i=0;$i<$times;$i++){
+            Redis::get(md5('k_delme'.$i));
+        }
+        echo microtime(true)-$start_at, '<br>';
+
+        $start_at = microtime(true);
+        for($i=0;$i<$times;$i++){
+            Redis::del(md5('k_delme'.$i));
+        }
+        echo microtime(true)-$start_at, '<br>';
     }
 
     function packageT(Request $request)
@@ -1254,14 +1289,6 @@ where (commodities.owner_id,commodity_barcodes.code) in (select commodities.owne
 //        return view('test');
     }
 
-    public function testSyncCommodity()
-    {
-        dump('start' . (string)Carbon::now());
-        $syncCommodityTask=new SyncWmsCommoditiesInformation();
-        $syncCommodityTask->handle();
-        dump('end' . (string)Carbon::now());
-    }
-
     public function editOrderSyncAt()
     {
         ValueStore::query()->where('name','order_last_created_sync_at')->update(['value'=>'2020-12-22 09:00:00']);

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

@@ -88,6 +88,7 @@ class WaybillController extends Controller
         if(!Gate::allows('运输管理-编辑')){ return redirect(url('/'));  }
         /** @var WaybillService */
         $waybill = app('waybillService')->find($id);
+        if (!$waybill)return view("exception.default",["code"=>"500","message"=>"数据已被删除或丢失"]);
         if ($waybill->deliver_at){
             $waybill->deliver_at_date=Carbon::parse($waybill->deliver_at)->format('Y-m-d');
             $waybill->deliver_at_time=Carbon::parse($waybill->deliver_at)->format('H:i:s');

+ 1 - 1
app/Http/Controllers/api/thirdPart/jianshang/RejectedController.php

@@ -221,7 +221,7 @@ class RejectedController extends Controller
             $response=false;
         }
         if(!$response){
-            app('LogService')->log(__METHOD__,'笕尚接口返回异常!!:',$response->body());
+            app('LogService')->log(__METHOD__,'笕尚接口返回异常!!:',"沒有返回");
             return false;
         }
         app('LogService')->log(__METHOD__,'笕尚接口返回:',$response->body());

+ 36 - 4
app/Imports/ExpressImport.php

@@ -28,10 +28,6 @@ class ExpressImport implements ToCollection,WithHeadingRow
     */
     public function collection(Collection $collection)
     {
-        if (!$this->express){
-            Cache::put("express",["success"=>false, "data"=>"不存在父级"],86400);
-            return false;
-        }
         $row = $collection->first();
         $header = [
             "省","首重价格","续重价格"
@@ -50,6 +46,10 @@ class ExpressImport implements ToCollection,WithHeadingRow
             $map[$province->name] = $province->id;
         }
 
+        if (!$this->express){
+            return $this->readonly($collection,$map);
+        }
+
         //已存在的计费
         $existDetails = [];
         foreach ($this->express->details as $detail){
@@ -105,4 +105,36 @@ class ExpressImport implements ToCollection,WithHeadingRow
         Cache::put("express",["success"=>true,"data"=>$this->express->details,"errors"=>$errors],86400);
         return true;
     }
+
+    private function readonly(Collection $collection, array $map)
+    {
+        $errors = [];
+        $data = [];
+        foreach ($collection as $index => $item){
+            if (!isset($map[$item["省"]])){
+                foreach ($map as $name=>$id){
+                    if (mb_strpos($item["省"],$name) !== false)$item["省"] = $name;
+                }
+                if (!isset($map[$item["省"]])){
+                    $errors[] = "第“".($index+2)."”行未知省份";
+                    continue;
+                }
+            }
+            if (!is_numeric($item["首重价格"]) || $item["首重价格"] <= 0){
+                $errors[] = "第“".($index+2)."”行非法首重价格";
+                continue;
+            }
+            if (!is_numeric($item["续重价格"]) || $item["续重价格"] <= 0){
+                $errors[] = "第“".($index+2)."”行非法续重价格";
+                continue;
+            }
+            $data[] = [
+                "province_id" => $map[$item["省"]],
+                "initial_weight_price" => $item["首重价格"],
+                "additional_weight_price" => $item["续重价格"],
+            ];
+        }
+        Cache::put("express",["success"=>true,"data"=>$data,"errors"=>$errors],86400);
+        return true;
+    }
 }

+ 46 - 5
app/Imports/OwnerPriceDirectLogisticDetailImport.php

@@ -18,7 +18,7 @@ class OwnerPriceDirectLogisticDetailImport implements ToCollection,WithHeadingRo
 {
     protected $model;
 
-    public function __construct(OwnerPriceDirectLogistic $model)
+    public function __construct($model)
     {
         $this->model = $model;
     }
@@ -29,10 +29,6 @@ class OwnerPriceDirectLogisticDetailImport implements ToCollection,WithHeadingRo
     */
     public function collection(Collection $collection)
     {
-        if (!$this->model){
-            Cache::put("directLogistic",["success"=>false, "data"=>"不存在父级"],86400);
-            return false;
-        }
         $row = $collection->first();
         $additional = "续费";
 
@@ -61,6 +57,10 @@ class OwnerPriceDirectLogisticDetailImport implements ToCollection,WithHeadingRo
             $map[$carType->name] = $carType->id;
         }
 
+        if (!$this->model){
+            return $this->readonly($collection, $map, $additional);
+        }
+
         //已存在的计费
         $existDetails = [];
         foreach ($this->model->details as $detail){
@@ -133,4 +133,45 @@ class OwnerPriceDirectLogisticDetailImport implements ToCollection,WithHeadingRo
         Cache::put("directLogistic",["success"=>true,"data"=>$this->model->details,"errors"=>$errors],86400);
         return true;
     }
+
+    private function readonly(Collection $collection, array $map, $additional)
+    {
+        $errors = [];
+        $data = [];
+        $existInsert = [];
+        foreach ($collection as $index => $item){
+            /* 数据校验 */
+            if (!$item["车型"]){
+                $errors[] = "第“".($index+2)."”行车型为空";
+                continue;
+            }else{
+                if (!isset($map[$item["车型"]])){
+                    $errors[] = "第“".($index+2)."”行未知车型";
+                    continue;
+                }
+                $item["车型"] = $map[$item["车型"]];
+            }
+            if (!$item["起步费"] || !is_numeric($item["起步费"]) || $item["起步费"] <= 0){
+                $errors[] = "第“".($index+2)."”行非法起步费";
+                continue;
+            }
+            if (!$item[$additional] || !is_numeric($item[$additional]) || $item[$additional] <= 0){
+                $errors[] = "第“".($index+2)."”行非法续费";
+                continue;
+            }
+
+            if (isset($existInsert[$item["车型"]])){
+                $errors[] = "第“".($index+2)."”行与第“".$existInsert[$item["车型"]]."”行重复";
+                continue;
+            }
+            $data[] = [
+                "car_type_id" => $item["车型"],
+                "base_fee" => $item["起步费"],
+                "additional_fee" => $item[$additional],
+            ];
+            $existInsert[$item["车型"]] = $index+2;
+        }
+        Cache::put("directLogistic",["success"=>true,"data"=>$data,"errors"=>$errors],86400);
+        return true;
+    }
 }

+ 74 - 11
app/Imports/OwnerPriceLogisticDetailImport.php

@@ -3,7 +3,6 @@
 namespace App\Imports;
 
 use App\City;
-use App\OwnerPriceLogistic;
 use App\OwnerPriceLogisticDetail;
 use App\Province;
 use App\Services\common\BatchUpdateService;
@@ -19,7 +18,7 @@ HeadingRowFormatter::default('none');
 class OwnerPriceLogisticDetailImport implements ToCollection,WithHeadingRow
 {
     protected $logistic;
-    public function __construct(OwnerPriceLogistic $logistic)
+    public function __construct($logistic)
     {
         $this->logistic = $logistic;
     }
@@ -30,10 +29,6 @@ class OwnerPriceLogisticDetailImport implements ToCollection,WithHeadingRow
     */
     public function collection(Collection $collection)
     {
-        if (!$this->logistic){
-            Cache::put("logistic",["success"=>false, "data"=>"不存在父级"],86400);
-            return false;
-        }
         $row = $collection->first();
         $header = [
             "计数单位","计数区间","省份","市","单价","送货费","起始计费","起始计数","费率"
@@ -61,6 +56,9 @@ class OwnerPriceLogisticDetailImport implements ToCollection,WithHeadingRow
             $cityMappingProvince[$city->id] = $city->province_id;
         }
 
+        if (!$this->logistic)
+            return $this->readonly($collection, $map, $cityMap, $cityMappingProvince);
+
         //对比单位
         $unit = $this->logistic->unit ? strtoupper($this->logistic->unit->name) : '';
         $otherUnit = $this->logistic->otherUnit ? strtoupper($this->logistic->otherUnit->name) : '';
@@ -99,14 +97,10 @@ class OwnerPriceLogisticDetailImport implements ToCollection,WithHeadingRow
                 if (isset($map[mb_substr($item["省份"], 0,-1)]))$item["省份"] = mb_substr($item["省份"], 0,-1);
             }
             if (!$item["计数单位"] || (strtoupper($item["计数单位"]) != $unit && strtoupper($item["计数单位"]) != $otherUnit)){
-                //$errors[] = "第“".($index+2)."”行单位不符合";
-                //continue;
                 Cache::put("logistic",["success"=>false, "data"=>"第“".($index+2)."”行单位不符合"],86400);
                 return false;
             }
             if (!$item["计数区间"] || array_search($item["计数区间"],$range[strtoupper($item["计数单位"])]) === false){
-                //$errors[] = "第“".($index+2)."”行非法首重价格";
-                //continue;
                 Cache::put("logistic",["success"=>false, "data"=>"第“".($index+2)."”行区间不符合"],86400);
                 return false;
             }
@@ -135,8 +129,8 @@ class OwnerPriceLogisticDetailImport implements ToCollection,WithHeadingRow
                 continue;
             }
             $item["省份"] = $map[$item["省份"]];
-            $item["计数单位"] = strtoupper($item["计数单位"]) == $unit ? $this->logistic->unit_id : $this->logistic->other_unit_id;
             $item["市"] = $cityMap[$item["市"]];
+            $item["计数单位"] = strtoupper($item["计数单位"]) == $unit ? $this->logistic->unit_id : $this->logistic->other_unit_id;
             $key = $item["计数单位"]."_".$item["计数区间"]."_".$item["省份"]."_".$item["市"];
             if (isset($existInsert[$key])){
                 $errors[] = "第“".($index+2)."”行与第“".$existInsert[$key]."”行重复";
@@ -183,4 +177,73 @@ class OwnerPriceLogisticDetailImport implements ToCollection,WithHeadingRow
         Cache::put("logistic",["success"=>true,"data"=>$this->logistic->details,"errors"=>$errors],86400);
         return true;
     }
+
+    public function readonly(Collection $collection, array $map, array $cityMap, array $cityMappingProvince)
+    {
+        //生成列表内的重复条目
+        $existInsert = [];
+        //符合数据
+        $data = [];
+        //错误信息
+        $errors = [];
+        foreach ($collection as $index => $item){
+            /* 数据校验 */
+            if (!$item["省份"]){
+                $errors[] = "第“".($index+2)."”行省份为空";
+                continue;
+            }else{
+                if ((!isset($map[$item["省份"]]) && !isset($map[mb_substr($item["省份"], 0,-1)]))){
+                    $errors[] = "第“".($index+2)."”行未知省份";
+                    continue;
+                }
+                if (isset($map[mb_substr($item["省份"], 0,-1)]))$item["省份"] = mb_substr($item["省份"], 0,-1);
+            }
+            if (!isset($cityMap[$item["市"]])){
+                $errors[] = "第“".($index+2)."”行未知城市";
+                continue;
+            }
+            if (!$item["单价"] || !is_numeric($item["单价"]) || $item["单价"] <= 0){
+                $errors[] = "第“".($index+2)."”行非法单价";
+                continue;
+            }
+            $numeric = ["送货费","起始计费","起始计数","费率"];
+            $sign = false;
+            foreach ($numeric as $column){
+                if ($item[$column] && (!is_numeric($item[$column]) || $item[$column] <= 0)){
+                    $errors[] = "第“".($index+2)."”行非法".$column;
+                    $sign = true;
+                    break;
+                }
+            }
+            if ($sign)continue;
+
+            /* 数据转换及存在校验 */
+            if ($cityMappingProvince[$cityMap[$item["市"]]] != $map[$item["省份"]]){
+                $errors[] = "第“".($index+2)."”行城市不属于该省份";
+                continue;
+            }
+            $item["省份"] = $map[$item["省份"]];
+            $item["市"] = $cityMap[$item["市"]];
+            $key = $item["计数单位"]."_".$item["计数区间"]."_".$item["省份"]."_".$item["市"];
+            if (isset($existInsert[$key])){
+                $errors[] = "第“".($index+2)."”行与第“".$existInsert[$key]."”行重复";
+                continue;
+            }
+
+            $data[] = [
+                "unit_id" => $item["计数单位"],
+                "range" => $item["计数区间"],
+                "province_id" => $item["省份"],
+                "city_id" => $item["市"],
+                "unit_price" => $item["单价"],
+                "delivery_fee" => $item["送货费"],
+                "initial_fee" => $item["起始计费"],
+                "initial_amount" => $item["起始计数"],
+                "rate" => $item["费率"],
+            ];
+            $existInsert[$key] = $index+2;
+        }
+        Cache::put("logistic",["success"=>true,"data"=>$data,"errors"=>$errors],86400);
+        return true;
+    }
 }

+ 4 - 3
app/Imports/WaybillPriceModelsImport.php

@@ -41,7 +41,7 @@ class WaybillPriceModelsImport implements ToCollection,WithHeadingRow
         $sum=2;
         if ($endIs) {
             foreach ($collection as $row) {
-                if ($row['承运商'] && $row['计数单位'] && $row['省份'] && $row['单价']) {
+                if ($row['承运商'] && $row['计数单位'] && $row['省份'] && $row['单价']!=='') {
                     if (strstr($row['省份'], '省')){$row['省份']=str_replace('省','',$row['省份']);};
                     $logistic = Logistic::query()->where('name', $row['承运商'])->first();
                     $unit = Unit::query()->where('name', $row['计数单位'])->first();
@@ -52,7 +52,8 @@ class WaybillPriceModelsImport implements ToCollection,WithHeadingRow
                         $billing = $billing->where('unit_id', $unit->id);
                         $billing = $billing->where('province_id', $province->id);
                         if ($row['市']) {
-                            $billing = $billing->where('city_id', $city->id);
+                            if ($city) $billing = $billing->where('city_id', $city->id);
+                            else $billing->whereNull("city_id");
                         }
                         if ($row['计数区间'] && !strstr($row['计数区间'], '∞')) {
                             $str = explode('-', $row['计数区间']);
@@ -63,7 +64,7 @@ class WaybillPriceModelsImport implements ToCollection,WithHeadingRow
                         }
                         $billing = $billing->first();
                         if (!$billing) {
-                            if (isset($waybillPriceModel['city_id'])){
+                            if ($row['市']){
                                 $waybillPriceModelProvince=WaybillPriceModel::query()->whereRaw('logistic_id = ? AND province_id = ? AND city_id IS NULL',[$logistic->id,$province->id])->first();
                                 if ($waybillPriceModelProvince){
                                     $cityIs=false;

+ 4 - 0
app/Log.php

@@ -32,4 +32,8 @@ class Log extends Model
 //            ' ',
 //            $value);
 //    }
+    public function scopeFilter($query, $filters)
+    {
+        return $filters->apply($query);
+    }
 }

+ 8 - 0
app/Observers/OwnerObserver.php

@@ -17,4 +17,12 @@ class OwnerObserver
         if(env('APP_ENV')=='production')
             app("OwnerService")->syncPush($owner);
     }
+
+    public function updated(Owner $owner)
+    {
+        if(env('APP_ENV')=='production'){
+            app("OwnerService")->syncUpdate($owner);
+        }
+    }
+
 }

+ 4 - 0
app/Providers/AppServiceProvider.php

@@ -10,6 +10,8 @@ use App\Services\CommodityService;
 use App\Services\common\BatchUpdateService;
 use App\Services\CommodityBarcodeService;
 use App\Services\common\DataHandlerService;
+use App\Services\CustomerLogService;
+use App\Services\CustomerLogStatusService;
 use App\Services\CustomerService;
 use App\Services\DepositoryService;
 use App\Services\FeatureService;
@@ -211,6 +213,8 @@ class AppServiceProvider extends ServiceProvider
         app()->singleton('WarehouseService',WarehouseService::class);
         app()->singleton('WaybillFinancialService',WaybillFinancialService::class);
         app()->singleton('WeighExceptedService',WeighExceptedService::class);
+        app()->singleton('CustomerLogService',CustomerLogService::class);
+        app()->singleton('CustomerLogStatusService',CustomerLogStatusService::class);
     }
 
 

+ 6 - 6
app/Services/CommodityService.php

@@ -401,7 +401,7 @@ Class CommodityService
         $create_key = config('sync.commodity_sync.cache_prefix.create');
         /** @var OracleBasSkuService $oracleBasSkuService */
         $oracleBasSkuService = app(OracleBasSkuService::class);
-        $last_time = $this->getAsnLastSyncAt($created_at, 'create');
+        $last_time = $this->getCommodityLastSyncAt($created_at, 'create');
         $basSkus = $oracleBasSkuService->getWmsCreatedCommodities($last_time);
         $last_time = $basSkus->first()['addtime'];
         $last_records = $basSkus->where('addtime', $last_time);
@@ -409,7 +409,7 @@ Class CommodityService
         $this->syncCreateCommodity($basSkus);
         $this->deleteCacheKey($create_set, $create_keys);
         $this->setLastRecordsByRedis($create_key, $create_set, $create_keys, $last_records);
-        $this->setAsnLastSyncAt($created_at, $last_time);
+        $this->setCommodityLastSyncAt($created_at, $last_time);
     }
 
     public function syncCommodityUpdated()
@@ -420,7 +420,7 @@ Class CommodityService
         $update_key = config('sync.commodity_sync.cache_prefix.update');
         /** @var OracleBasSkuService $oracleBasSkuService */
         $oracleBasSkuService = app(OracleBasSkuService::class);
-        $last_time = $this->getAsnLastSyncAt($updated_at, 'update');
+        $last_time = $this->getCommodityLastSyncAt($updated_at, 'update');
         $basSkus = $oracleBasSkuService->getWmsUpdatedCommodities($last_time);
         $last_time = $basSkus->first()['edittime'];
         $last_records = $basSkus->where('edittime', $last_time);
@@ -428,7 +428,7 @@ Class CommodityService
         $this->syncUpdateCommodity($basSkus);
         $this->deleteCacheKey($update_set, $update_keys);
         $this->setLastRecordsByRedis($update_key, $update_set, $update_keys, $last_records);
-        $this->setAsnLastSyncAt($updated_at, $last_time);
+        $this->setCommodityLastSyncAt($updated_at, $last_time);
     }
 
     public function syncCreateCommodity($addBasSkus)
@@ -658,7 +658,7 @@ Class CommodityService
         }
     }
 
-    public function getAsnLastSyncAt($key, $type)
+    public function getCommodityLastSyncAt($key, $type)
     {
         $last_time = ValueStore::query()->where('name', $key)->value('value');
         if ($last_time) return $last_time;
@@ -672,7 +672,7 @@ Class CommodityService
         return Carbon::now()->subSeconds(65);
     }
 
-    public function setAsnLastSyncAt($key, $last_time)
+    public function setCommodityLastSyncAt($key, $last_time)
     {
         $asnLastSyncAt = ValueStore::query()->updateOrCreate([
             'name' => $key,

+ 1 - 1
app/Services/LogisticService.php

@@ -19,7 +19,7 @@ Class LogisticService
         $this->cacheService=app('CacheService');
     }
     public function getSelection($column = ['id','name'], $type = '快递'){
-        return $this->cacheService->getOrExecute('LogisticAll_idName'.Str::studly($type),function()use($column,$type){
+        return $this->cacheService->getOrExecute('LogisticAll_'.implode("",$column).Str::studly($type),function()use($column,$type){
             $query = Logistic::query()->select($column);
             if ($type)$query->where(function ($query)use($type){
                 /** @var Builder $query */

+ 53 - 11
app/Services/NewOrderCountingRecordService.php

@@ -9,10 +9,30 @@ use App\Order;
 use App\OrderCountingRecord;
 use App\Warehouse;
 use Carbon\Carbon;
+use Illuminate\Support\Arr;
+use Illuminate\Support\Collection;
 use Illuminate\Support\Facades\Cache;
 
 class NewOrderCountingRecordService
 {
+    public function orderCountingRecordsFromCache($start, $end, $unit, $ownerIds)
+    {
+        $dataList = collect();
+        if (count($ownerIds) == 1) return $this->orderCountingRecords($start, $end, $unit, $ownerIds);//当前用户只有一个货主权限,只需执行旧方法即可
+        $queryCondition = $this->transfersToCondition($start, $end, $unit, $ownerIds);//根据条件获取查询条件
+        $md5OwnerIds = md5(join(Arr::sortRecursive($ownerIds)));//将$ownerIds排序,保证md5加密后结果一致  将当前用户拥有的ownerIds进行md5加密
+        foreach ($queryCondition['data'] as $dateStr => $ownerIds) {
+            $key = 'new_order_counting_records_' . $dateStr . '_' . $md5OwnerIds . '_' . $queryCondition['unit'];
+            $data = cache()->remember($key, $this->getTtl($dateStr, $unit), function () use ($dateStr, $unit, $ownerIds) {
+                //如果缓存不存在,则将$dateStr作为查询条件,使用之前的接口查询改日的订单量统计结果,由于接口返回collect,去其中的第一个
+                //因为查询条件仅为一天
+                return $this->orderCountingRecords($dateStr, $dateStr, $unit, $ownerIds)->first();
+            });
+            $dataList->push($data);
+        }
+        return $dataList;
+    }
+
     public function orderCountingRecords($start, $end, $unit, $ownerIds)
     {
         $orders = $this->get($start, $end, $unit, $ownerIds);
@@ -148,6 +168,12 @@ class NewOrderCountingRecordService
         return [$orderCountingRecords_fromSelfTable, $lackingCondition];
     }
 
+    /**
+     * 根据$queryCondition从多种数据源中查询数据
+     * 并将结果插入中间表或者缓存
+     * @param $queryCondition
+     * @return Collection|mixed|\Tightenco\Collect\Support\Collection
+     */
     public function getOrderCountingRecords($queryCondition)
     {
         list($orderCountingRecords_fromCache, $lackingCondition)
@@ -167,7 +193,7 @@ class NewOrderCountingRecordService
          */
         if ($lackingCondition['unit'] != '日') {//日为最低粒度,不用进入此方法
             $orderCountingRecords_combinedByLower = $this->getFromLowerUnit($lackingCondition);
-        }else{
+        } else {
             $orderCountingRecords_FromOrder = $this->dataFromOrder($lackingCondition);
         }
         $result = collect();
@@ -207,7 +233,7 @@ class NewOrderCountingRecordService
                 $orderCountingRecords_days = $this->getOrderCountingRecords($conditionClone);
                 $orderCountingRecords_combinedByLower = $this->turnGradingUpToLow($orderCountingRecords_days, $lowUnit, 'year');
                 $this->insertIntoMiddleTable($orderCountingRecords_combinedByLower, '年');
-                $this->insertIntoCache(collect($orderCountingRecords_combinedByLower),'年');
+                $this->insertIntoCache(collect($orderCountingRecords_combinedByLower), '年');
                 break;
             case '月':
                 $lowUnit = '日';
@@ -226,7 +252,7 @@ class NewOrderCountingRecordService
                 $orderCountingRecords_days = $this->getOrderCountingRecords($conditionClone);
                 $orderCountingRecords_combinedByLower = $this->turnGradingUpToLow($orderCountingRecords_days, $lowUnit, 'month');
                 $this->insertIntoMiddleTable($orderCountingRecords_combinedByLower, '月');
-                $this->insertIntoCache(collect($orderCountingRecords_combinedByLower),'月');
+                $this->insertIntoCache(collect($orderCountingRecords_combinedByLower), '月');
 
                 break;
             case '日':
@@ -238,6 +264,7 @@ class NewOrderCountingRecordService
 
     public function transfersToCondition($start, $end, $unit, $ownerIds): array
     {
+        if (Carbon::parse($end)->gt(now())) $end = now()->toDateString();//如果$end超过当前时间,将end置为当前时间
         $condition = [
             'data' => [],
             'unit' => $unit,];
@@ -309,12 +336,7 @@ class NewOrderCountingRecordService
         });
 
         foreach ($map as $key => $orders) {
-
-            $ttl = config('cache.expirations.forever');
-            if (!$this->isNotCurrentDate($orders[0]['date_target'], $unit)) {
-                $ttl = config('cache.expirations.oftenChange');
-            }
-            Cache::put($key, collect($orders), $ttl);
+            Cache::put($key, collect($orders), $this->getTtl($orders[0]['date_target'], $unit));
         }
     }
 
@@ -411,8 +433,18 @@ class NewOrderCountingRecordService
                     break;
             }
             $item['amount'] = $amount;
-
-            return $result->push($item);
+            return $result->push(new OrderCountingRecord([
+                'owner_id' => $item->owner_id,
+                'shop_id' => $item->shop_id,
+                'warehouse_id' => $item->warehouse_id,
+                'logistic_id' => $item->logistic_id,
+                'date_target' => $item->date_target,
+                'counting_unit' => $item->counting_unit,
+                'amount' => $item->amount,
+                'year' => $item->year,
+                'month' => $item->month,
+                'week' => $item->week
+            ]));
         }
         return $result;
     }
@@ -454,4 +486,14 @@ class NewOrderCountingRecordService
             }
         }
     }
+
+    private function getTtl($dateStr, $unit)
+    {
+        if ($this->isNotCurrentDate($dateStr, $unit)) {
+            $ttl = config('cache.expirations.forever');//非当前日期的缓存为永久
+        } else {
+            $ttl = config('cache.expirations.orderCountingRecord');//当前日期缓存为1800s
+        }
+        return $ttl;
+    }
 }

+ 7 - 2
app/Services/OrderIssueService.php

@@ -12,6 +12,7 @@ use App\Order;
 use App\RejectedBill;
 use App\RejectedBillItem;
 use Carbon\Carbon;
+use Illuminate\Database\Query\Builder;
 use Illuminate\Http\Request;
 use Illuminate\Support\Facades\Auth;
 use Illuminate\Support\Facades\Validator;
@@ -151,10 +152,10 @@ class OrderIssueService
 
     public function getConditionQuery(array $arr, array $condition = null)
     {
+        /** @var Builder $query */
         $query = $this->getQuery($arr, $condition);
         $query = $this->getOrderQuery($condition ?? $arr, $query);
         $query = $this->getRejectedBillQuery($condition ?? $arr, $query);
-
         if (!isset($condition)) {
             $condition = $arr;
         }
@@ -181,7 +182,7 @@ class OrderIssueService
         if (!($condition['is_handle'] ?? false) && !($condition['final_status'] ?? false)) {
             if (!(isset($condition['settlement_at_start']) || isset($condition['settlement_at_end']))) {
                 $query->where(function ($query) {
-                    $query->where('final_status', '<>', '已解决')->orWhereNull('final_status');
+                    $query->whereNotIn('final_status',['已解决','已归档'])->orWhereNull('final_status');
                 });
             }
         }
@@ -509,6 +510,10 @@ class OrderIssueService
     public function updateSecondLogisticNumber($id, $logisticNumber)
     {
         $orderIssue = OrderIssue::query()->where('id', $id)->first();
+        if(!$orderIssue->second_client_no){
+            $orderIssue->update(['second_logistic_number'=>$logisticNumber]);
+            return ['success' => true,'second_logistic_number' => $logisticNumber];
+        }
         $order = app(OrderService::class)->getOrderByLogisticNumber($logisticNumber);
         if (!$order) {
             $orderIssue->update(['second_logistic_number' => $logisticNumber]);

+ 21 - 6
app/Services/OrderService.php

@@ -323,6 +323,7 @@ class OrderService
         $commodities=[];
         $orderNos = "(''";
         $picktotraceids=[];
+        $count = 1;
         /*
          * 第二种扁平化方式(节省空间): 使用快慢指针,因拿到数据正常为顺序数据,自下标1开始与上一条对比orderno唯一标识,不同则更新慢指针下标,
          *  相同则为指定下标map类型数组追加一个键值对属性来记录同类数量,如N条,每次追加属性时先看属性是否存在,存在+1
@@ -330,10 +331,12 @@ class OrderService
         foreach ($orders as $index=>$order){
             $key = $order->orderno;
             if (isset($commodities[$key])){
-                if (!isset($signs[$order->orderlineno]))
+                if (!isset($signs[$order->orderlineno])){
+                    $signs[$order->orderlineno] = true;
                     array_push($commodities[$key],
                         ["sku"=>$order->sku,"alternate_sku1"=>$order->alternate_sku1,"descr_c"=>$order->descr_c,"qtyordered"=>$order->qtyordered
                             ,"lotnum"=>$order->lotnum,"checktime"=>$order->checktime,"orderdetailcodename"=>$order->orderdetailcodename]);
+                }
                 unset($orders[$index]);
                 continue;
             }
@@ -342,12 +345,24 @@ class OrderService
             $commodities[$key]=[["sku"=>$order->sku,"alternate_sku1"=>$order->alternate_sku1,
                 "descr_c"=>$order->descr_c,"qtyordered"=>$order->qtyordered,"lotnum"=>$order->lotnum,"checktime"=>$order->checktime,"orderdetailcodename"=>$order->orderdetailcodename]];
             $orderNos .= ",'".$order->orderno."'";
+            if ($count % 500 == 0){
+                $orderNos .= ")";
+                $allocations = DB::connection("oracle")->select(DB::raw("SELECT DROPID,ORDERNO FROM ACT_ALLOCATION_DETAILS WHERE orderno IN ".$orderNos." GROUP BY (DROPID,ORDERNO)"));
+                foreach ($allocations as $allocation){
+                    if (isset($picktotraceids[$allocation->orderno])) $picktotraceids[$allocation->orderno][] = $allocation->dropid;
+                    else $picktotraceids[$allocation->orderno] = [$allocation->dropid];
+                }
+                $orderNos = "(''";
+            }
+            $count++;
         }
-        $orderNos .= ")";
-        $allocations = DB::connection("oracle")->select(DB::raw("SELECT DROPID,ORDERNO FROM ACT_ALLOCATION_DETAILS WHERE orderno IN ".$orderNos." GROUP BY (DROPID,ORDERNO)"));
-        foreach ($allocations as $allocation){
-            if (isset($picktotraceids[$allocation->orderno])) $picktotraceids[$allocation->orderno][] = $allocation->dropid;
-            else $picktotraceids[$allocation->orderno] = [$allocation->dropid];
+        if ($orderNos !== "(''"){
+            $orderNos .= ")";
+            $allocations = DB::connection("oracle")->select(DB::raw("SELECT DROPID,ORDERNO FROM ACT_ALLOCATION_DETAILS WHERE orderno IN ".$orderNos." GROUP BY (DROPID,ORDERNO)"));
+            foreach ($allocations as $allocation){
+                if (isset($picktotraceids[$allocation->orderno])) $picktotraceids[$allocation->orderno][] = $allocation->dropid;
+                else $picktotraceids[$allocation->orderno] = [$allocation->dropid];
+            }
         }
         $picktotraceids=json_encode($picktotraceids);
         $orders=array_values($orders);

+ 32 - 1
app/Services/OwnerService.php

@@ -235,7 +235,11 @@ Class OwnerService
             if($owner) return $owner;
              $basCustomer = app('OracleBasCustomerService')->first(['Customer_Type'=>'OW','CustomerID'=>$code]);
             if(!$basCustomer)return null;
-            return Owner::query()->create(['name'=>$basCustomer['descr_c'],'code'=>$basCustomer['customerid']]);
+            if($basCustomer && $basCustomer['active_flag']=='Y') return Owner::query()
+                ->create(['name'=>$basCustomer['descr_c'],'code'=>$basCustomer['customerid']]);
+            $deleted_at=Carbon::now()->toDateTimeString();
+            if($basCustomer && $basCustomer['active_flag']=='N') return Owner::query()
+                ->create(['name'=>$basCustomer['descr_c'],'code'=>$basCustomer['customerid'],'deleted_at'=>$deleted_at]);
         });
     }
     public function codeGetOwner($code)
@@ -275,4 +279,31 @@ sql
         }
         return true;
     }
+
+
+    public function syncUpdate($owner)
+    {
+        if (is_array($owner)){
+            $owner = new Owner();
+            foreach ($owner as $column=>$value){
+                $owner[$column] = $value;
+            }
+        }
+        if (is_numeric($owner)){
+            $owner = Owner::query()->find($owner);
+            if (!$owner)return false;
+        }
+        $sql = DB::raw(<<<sql
+    update BAS_CUSTOMER set ACTIVE_FLAG = ?,EDITTIME = TO_DATE(?,'yyyy-mm-dd hh24:mi:ss'),EDITWHO = ? where CUSTOMERID = ? and CUSTOMER_TYPE = ? 
+sql
+        );
+        $date = date('Y-m-d H:i:s');
+        if ($owner && $owner->deleted_at){
+            DB::connection("oracle")->update($sql,['N',$date,'WAS-'.(Auth::user() ? Auth::user()['name'] : 'SYSTEM'),$owner->code,'OW']);
+        }
+       if ($owner && $owner->deleted_at==null) {
+            DB::connection("oracle")->update($sql,['Y',$date,'WAS-'.(Auth::user() ? Auth::user()['name'] : 'SYSTEM'),$owner->code,'OW']);
+        }
+        return true;
+    }
 }

+ 3 - 4
app/Services/RejectedBillService.php

@@ -122,10 +122,9 @@ Class RejectedBillService
     {
         $updateCollect = collect();
         foreach ($asnHerders as $asnHerder) {
-            if (($asnHerder->asnType->codename_c == '退货入库'
-                    || $asnHerder->asnType->codename_c == '其他入库')
-                && ($asnHerder->asnStatus->codename_c == '已入库'
-                    ||$asnHerder->asnStatus->codename_c == 'ASN关闭')) {
+            if ($asnHerder->asnType && $asnHerder->asnStatus &&
+                ($asnHerder->asnType->codename_c == '退货入库' || $asnHerder->asnType->codename_c == '其他入库')
+                && ($asnHerder->asnStatus->codename_c == '完全收货' ||$asnHerder->asnStatus->codename_c == 'ASN关闭')) {
                 $updateCollect->add($asnHerder);
             }
         }

+ 6 - 5
app/Services/StoreService.php

@@ -51,7 +51,7 @@ Class StoreService
         $oracleDocAsnHerderService = app(OracleDocAsnHerderService::class);
         $last_time = $this->getAsnLastSyncAt($created_at, 'create');
         $asnHerders = $oracleDocAsnHerderService->getWmsAsnOnStartDateCreate($last_time);
-        if (!$asnHerders) return;
+        if (count($asnHerders)<1) return;
         $last_time = $asnHerders->first()['addtime'];
         $last_records = $asnHerders->where('addtime', $last_time);
         $this->createStore($asnHerders);
@@ -71,7 +71,7 @@ Class StoreService
         $oracleDocAsnHerderService = app(OracleDocAsnHerderService::class);
         $last_time = $this->getAsnLastSyncAt($updated_at, 'update');
         $asnHerders = $oracleDocAsnHerderService->getWmsAsnOnStartDateEdit($last_time);
-        if (!$asnHerders) return;
+        if (count($asnHerders)<1) return;
         $last_time = $asnHerders->first()['edittime'];
         $last_records = $asnHerders->where('edittime', $last_time);
         $this->createStore($asnHerders);
@@ -196,9 +196,10 @@ Class StoreService
             if ($store->asn_code != $asnHerder->asnno ||
                 $store->warehouse_id != $warehouse_id ||
                 $store->owner_id != $owner_id ||
-                $store->stored_method != $asnHerder->asnType->codename_c ||
-                $store->status != $asnHerder->asnStatus->codename_c ||
-                $store->remark != $asnHerder->notes) {
+                $store->stored_method != ($asnHerder->asnType->codename_c ??'')||
+                $store->status != ($asnHerder->asnStatus->codename_c ?? '')||
+                $store->remark != $asnHerder->notes ||
+                $store->updated_at != $asnHerder->edittime) {
                 $updateParams[] = [
                     'id' => $store->id,
                     'asn_code' => $asnHerder->asnno,

+ 4 - 1
app/StoreItems.php

@@ -14,7 +14,7 @@ class StoreItems extends Model
     use ModelTimeFormat;
     protected $fillable=[
         'store_id','asn_line_code','name',
-        'sku','barcode','depository_id','amount','quality','status',
+        'sku','barcode','depository_id','amount','quality','status','commodity_id'
     ];
     protected $appends=[
         'store_asn_code',
@@ -27,6 +27,9 @@ class StoreItems extends Model
     public function store(){
         return $this->belongsTo('App\Store','store_id','id');
     }
+    public function commodity(){
+        return $this->hasOne('App\Commodity','id','commodity_id');
+    }
 
 
     public function getStoreASNCodeAttribute()

+ 3 - 0
app/Waybill.php

@@ -66,6 +66,9 @@ class Waybill extends Model
     public function uploadFile(){
         return $this->hasOne('App\UploadFile','table_id','id')->where('table_name','waybills');
     }
+//    public function getOrderingRemarkAttribute($val){
+//        return
+//    }
 
 
     static public function setWeightByOrderCode($orderCode,$weight){

+ 1 - 1
composer.json

@@ -81,4 +81,4 @@
             "@php artisan key:generate --ansi"
         ]
     }
-}
+}

+ 1 - 0
config/cache.php

@@ -13,6 +13,7 @@ return [
         'forever' =>null,       //永久
 
         'owners'=>20,           //模型Owner
+        'orderCountingRecord'=>1800,           //模型Owner
     ],
     /*
     |--------------------------------------------------------------------------

+ 3 - 0
database/migrations/2020_12_14_103401_create_customerlogstatuses_table.php

@@ -14,6 +14,9 @@ class CreateCustomerLogStatusesTable extends Migration
             $table->text('description');
             $table->timestamps();
         });
+		\App\CustomerLogStatus::query()->create([
+		    "name"=>"日志"
+        ]);
 	}
 
 	public function down()

+ 44 - 0
database/migrations/2020_12_31_115716_change_log_index_all.php

@@ -0,0 +1,44 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+class ChangeLogIndexAll extends Migration
+{
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+
+        Schema::table('logs', function (Blueprint $table) {
+            $table->index('created_at','index_logs_created_at');
+            $table->index(['method','created_at'],'index_logs_m_c');
+            $table->index(['type','created_at'],'index_logs_t_c');
+//            $table->index(['id_user','created_at'],'index_logs_i_c');
+//            $table->dropIndex('index_logs_i_c');
+            $table->dropIndex('index_logs_c_c');
+            $table->dropIndex('index_logs_c_t');
+//            $table->dropIndex('index_logs_c_m');
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        Schema::table('logs', function (Blueprint $table) {
+            $table->dropIndex('index_logs_created_at');
+            $table->dropIndex('index_logs_m_c');
+            $table->dropIndex('index_logs_t_c');
+            $table->index(['type','created_at'],'index_logs_t_c');
+            $table->index(['created_at','type'],'index_logs_c_t');
+        });
+    }
+}

+ 29 - 0
database/migrations/2021_01_06_105043_change_order_issues_table_final_status.php

@@ -0,0 +1,29 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\DB;
+use Illuminate\Support\Facades\Schema;
+
+class ChangeOrderIssuesTableFinalStatus extends Migration
+{
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        DB::statement("ALTER TABLE order_issues MODIFY COLUMN final_status enum ('已解决','待退回','退回中','已归档') default null");
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        DB::statement("ALTER TABLE order_issues MODIFY COLUMN final_status enum ('已解决','待退回','退回中') default null");
+    }
+}

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

@@ -0,0 +1,32 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+class AddColumnCountTableCustomerTags extends Migration
+{
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        Schema::table('customer_tags', function (Blueprint $table) {
+            $table->integer("count")->default(0);
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        Schema::table('customer_tags', function (Blueprint $table) {
+            $table->dropColumn("count");
+        });
+    }
+}

+ 31 - 0
database/migrations/2021_01_07_144845_add_authorities_order_issue_batch_archive.php

@@ -0,0 +1,31 @@
+<?php
+
+use App\Authority;
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+class AddAuthoritiesOrderIssueBatchArchive extends Migration
+{
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+       if(!Authority::query()->where('name','订单管理-问题件-批量归档')->first()){
+           (new Authority(['name'=>'订单管理-问题件-批量归档','alias_name'=>'订单管理-问题件-批量归档']))->save();
+       }
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        Authority::query()->where('name','订单管理-问题件-批量归档')->delete();
+    }
+}

+ 1 - 1
package-lock.json

@@ -8845,7 +8845,7 @@
         },
         "socket.io-client": {
             "version": "2.3.0",
-            "resolved": "https://registry.npm.taobao.org/socket.io-client/download/socket.io-client-2.3.0.tgz",
+            "resolved": "https://registry.npm.taobao.org/socket.io-client/download/socket.io-client-2.3.0.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsocket.io-client%2Fdownload%2Fsocket.io-client-2.3.0.tgz",
             "integrity": "sha1-FNW6LgC5vNFFrkQ6uWs/hsvMG7Q=",
             "requires": {
                 "backo2": "1.0.2",

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

@@ -32,6 +32,7 @@ const query = function getQueryForm(data) {
             let form = $("<form method='" + _this.method +"'></form>");
             for (const key in _data) {
                 let map = _data[key];
+                if(map['required'] == true && (map.value === '' || map.value===null || map.value === undefined))return;
                 if (["string", "number"].includes(fetchJsType(map.value)) && map.value !== '') {
                     // if(map.value){
                     //     let string = new String(map.value);
@@ -473,7 +474,9 @@ const query = function getQueryForm(data) {
         let min = $("<input id='" + condition.name + "_min' class='form-control form-control-sm ml-2' style='max-width: 100px;' placeholder='00:00' data-toggle='tooltip' data-placement='top' >");
         min.attr('title', controlJsType(condition.tip[1], 'undefined') ? '' : condition.tip[1]);
         dateTime.bind('input propertychange', function () {
-            modifyData({name: condition.name, type: 'dateTime', value: this.value, mold: 'dateTime'});
+            let value = this.value !== '' ? this.value + ' ' +(!!min.val() ?  min.val() :'00:00' ) : '';
+            modifyData( {name: condition.name, type: 'time', value: value, mold: 'time'});
+            // modifyData({name: condition.name, type: 'dateTime', value: this.value, mold: 'dateTime'});
         });
         min.bind('input propertychange', function () {
             if (['null', 'undefined', ''].includes(dateTime.val()))return;
@@ -1146,6 +1149,7 @@ const query = function getQueryForm(data) {
                         data:condition.data,
                         killings:condition.killings,
                         rules:condition.rules,
+                        required:condition.required,
                     }
                     if (condition.type === 'search_select') {
                         data.mold = 'select';
@@ -1171,6 +1175,7 @@ const query = function getQueryForm(data) {
                             mold: ['input', 'dateTime'].includes(types[index]) ? 'input' : types[index],
                             killings:condition.killings,
                             rules:condition.rules,
+                            required:condition.required,
                         }
                         if(condition.killings&&Array.isArray(condition.killings)){
                             data.killings=condition.killings[index];

+ 27 - 1
resources/sass/text.scss

@@ -65,7 +65,33 @@
     overflow: hidden;
     white-space: nowrap;
     text-overflow: ellipsis;
-    pointer-events: none
+    pointer-events: none;
+}
+.text-overflow-replace-100{
+    overflow: hidden;
+    white-space: nowrap;
+    text-overflow: ellipsis;
+    pointer-events: none;
+    max-width: 100px;
+}
+.text-overflow-replace-200{
+    overflow: hidden;
+    white-space: nowrap;
+    text-overflow: ellipsis;
+    pointer-events: none;
+    max-width: 200px;
+}
+//文本溢出换行展示
+.text-overflow-warp{
+    white-space: normal;
+}
+.text-overflow-warp-100{
+    max-width: 100px;
+    white-space: normal;
+}
+.text-overflow-warp-200{
+    max-width: 200px;
+    white-space: normal;
 }
 //输入框font标签图
 .form-font{

+ 276 - 211
resources/views/control/panel.blade.php

@@ -23,7 +23,7 @@
                 </div>
             </div>
             <div class="row my-3">
-                <div class="col-sm col-lg-2 col-xl-2 col-md-2">
+                <div class="col-sm-3 col-lg-3 col-xl-3 col-md-3">
                     <div class="card">
                         <div class="card-header text-dark h5">
                             <p>实时待处理订(总):@{{ totalOrders.total }}</p>
@@ -37,7 +37,7 @@
                         </div>
                     </div>
                 </div>
-                <div class="col-sm col-lg-2 col-xl-2 col-md-2" v-for="(warehousesOrder,index) in warehousesOrders">
+                <div class="col-sm-2 col-lg-2 col-xl-2 col-md-2" v-for="(warehousesOrder,index) in warehousesOrders">
                     <div class="card">
                         <div class="card-header text-success h5">
                             <p>@{{ getWareHouse(warehousesOrder.code) }}:@{{ warehousesOrder.total }}</p>
@@ -53,160 +53,183 @@
                 </div>
             </div>
             <div class="row my-3">
-                <div class="col-sm col-lg-5  col-xl-5 col-md-5">
+                <div class="col-sm-6 col-lg-6  col-xl-6 col-md-6">
                     <div class="card">
                         <div class="card-header">
-                            <div class="block">
-                                <span v-show="orderCountingRecordsDayShow" class="demonstration">起始日期</span>
-                                <el-date-picker
-                                    @blur="orderCountingRecordApi('')"
-                                    v-show="orderCountingRecordsDayShow"
-                                    v-model="orderCountingRecordsStart"
-                                    type="date"
-                                    value-format="yyyy-MM-dd"
-                                    placeholder="选起始日期">
-                                </el-date-picker>
+                            <div class="block row">
+                                <div>
+                                    <span v-show="orderCountingRecordsDayShow" class="demonstration mt-1">起始日期:</span>
+                                    <el-date-picker
+                                        size="small"
+                                        @blur="orderCountingRecordApi('')"
+                                        v-show="orderCountingRecordsDayShow"
+                                        v-model="orderCountingRecordsStart"
+                                        type="date"
+                                        value-format="yyyy-MM-dd"
+                                        placeholder="选起始日期">
+                                    </el-date-picker>
 
-                                <span v-show="orderCountingRecordsDayShow" class="demonstration">结束日期</span>
-                                <el-date-picker
-                                    @blur="orderCountingRecordApi('')"
-                                    v-show="orderCountingRecordsDayShow"
-                                    v-model="orderCountingRecordsEnd"
-                                    type="date"
-                                    value-format="yyyy-MM-dd"
-                                    placeholder="选择结束日期">
-                                </el-date-picker>
+                                    <span v-show="orderCountingRecordsDayShow" class="demonstration mt-1">结束日期:</span>
+                                    <el-date-picker
+                                        size="small"
+                                        @blur="orderCountingRecordApi('')"
+                                        v-show="orderCountingRecordsDayShow"
+                                        v-model="orderCountingRecordsEnd"
+                                        type="date"
+                                        value-format="yyyy-MM-dd"
+                                        placeholder="选择结束日期">
+                                    </el-date-picker>
 
-                                <span v-show="orderCountingRecordsMonthShow" class="demonstration">起始月</span>
-                                <el-date-picker
-                                    @blur="orderCountingRecordApi('')"
-                                    v-show="orderCountingRecordsMonthShow"
-                                    v-model="orderCountingRecordsStart"
-                                    type="month"
-                                    value-format="yyyy-MM-dd"
-                                    placeholder="选择起始月">
-                                </el-date-picker>
+                                    <span v-show="orderCountingRecordsMonthShow" class="demonstration mt-1">起始月:</span>
+                                    <el-date-picker
+                                        size="small"
+                                        @blur="orderCountingRecordApi('')"
+                                        v-show="orderCountingRecordsMonthShow"
+                                        v-model="orderCountingRecordsStart"
+                                        type="month"
+                                        value-format="yyyy-MM-dd"
+                                        placeholder="选择起始月">
+                                    </el-date-picker>
 
-                                <span v-show="orderCountingRecordsMonthShow" class="demonstration">结束月</span>
-                                <el-date-picker
-                                    @blur="orderCountingRecordApi('')"
-                                    v-show="orderCountingRecordsMonthShow"
-                                    v-model="orderCountingRecordsEnd"
-                                    type="month"
-                                    value-format="yyyy-MM-dd"
-                                    placeholder="选择结束月">
-                                </el-date-picker>
+                                    <span v-show="orderCountingRecordsMonthShow" class="demonstration mt-1">结束月:</span>
+                                    <el-date-picker
+                                        size="small"
+                                        @blur="orderCountingRecordApi('')"
+                                        v-show="orderCountingRecordsMonthShow"
+                                        v-model="orderCountingRecordsEnd"
+                                        type="month"
+                                        value-format="yyyy-MM-dd"
+                                        placeholder="选择结束月">
+                                    </el-date-picker>
 
-                                <span v-show="orderCountingRecordsYearShow" class="demonstration">起始年</span>
-                                <el-date-picker
-                                    @blur="orderCountingRecordApi('')"
-                                    v-show="orderCountingRecordsYearShow"
-                                    v-model="orderCountingRecordsStart"
-                                    type="year"
-                                    value-format="yyyy-MM-dd"
-                                    placeholder="选择年">
-                                </el-date-picker>
+                                    <span v-show="orderCountingRecordsYearShow" class="demonstration mt-1">起始年:</span>
+                                    <el-date-picker
+                                        size="small"
+                                        @blur="orderCountingRecordApi('')"
+                                        v-show="orderCountingRecordsYearShow"
+                                        v-model="orderCountingRecordsStart"
+                                        type="year"
+                                        value-format="yyyy-MM-dd"
+                                        placeholder="选择年">
+                                    </el-date-picker>
 
-                                <span v-show="orderCountingRecordsYearShow" class="demonstration">结束年</span>
-                                <el-date-picker
-                                    @blur="orderCountingRecordApi('')"
-                                    v-show="orderCountingRecordsYearShow"
-                                    v-model="orderCountingRecordsEnd"
-                                    type="year"
-                                    value-format="yyyy-MM-dd"
-                                    placeholder="选择年">
-                                </el-date-picker>
+                                    <span v-show="orderCountingRecordsYearShow" class="demonstration mt-1">结束年:</span>
+                                    <el-date-picker
+                                        size="small"
+                                        @blur="orderCountingRecordApi('')"
+                                        v-show="orderCountingRecordsYearShow"
+                                        v-model="orderCountingRecordsEnd"
+                                        type="year"
+                                        value-format="yyyy-MM-dd"
+                                        placeholder="选择年">
+                                    </el-date-picker>
+                                </div>
+                                <div class="btn-group btn-group-sm ml-2" role="group" >
+                                    <el-button type="primary" value="日" @click="orderCountingRecordApi('日')"
+                                               class="btn btn-secondary"
+                                               v-model="orderCountingRecordsUnit">日
+                                    </el-button>
+                                    <el-button type="primary" value="月" @click="orderCountingRecordApi('月')"
+                                               class="btn btn-secondary "
+                                               v-model="orderCountingRecordsUnit">月
+                                    </el-button>
+                                    <el-button type="primary" value="年" @click="orderCountingRecordApi('年')"
+                                               class="btn btn-secondary"
+                                               v-model="orderCountingRecordsUnit">年
+                                    </el-button>
+                                </div>
+                                <div class="ml-2">
+                                    <el-select  placeholder="请选择对应货主" multiple v-model="selectOrderOwners" size="small"  @change="orderCountingRecordApi('')">
+                                        <el-option label="选择所有" value="all"></el-option>
+                                        <el-option v-for="item in owners" :label="item.name" :value="item.id" :key="item.id"></el-option>
+                                    </el-select>
+                                </div>
                             </div>
-
-                            <el-button type="primary" value="日" @click="orderCountingRecordApi('日')"
-                                       v-model="orderCountingRecordsUnit">日
-                            </el-button>
-                            <el-button type="primary" value="月" @click="orderCountingRecordApi('月')"
-                                       v-model="orderCountingRecordsUnit">月
-                            </el-button>
-                            <el-button type="primary" value="年" @click="orderCountingRecordApi('年')"
-                                       v-model="orderCountingRecordsUnit">年
-                            </el-button>
                         </div>
-                        <div class="card-body row">
-                            <div v-show="orderCountingRecordsShow" id="orderCountingRecords" class="col"
-                                 style="width:600px;height:600px;"></div>
+                        <div class="card-body">
+                            <div v-show="orderCountingRecordsShow" id="orderCountingRecords"
+                                 style="width: 100%;height:500px;"></div>
                         </div>
                         <div v-show="!orderCountingRecordsShow" class="text-center">
                             <h3>正在加载...</h3>
                         </div>
                     </div>
                 </div>
-                <div class="col-sm col-lg-7  col-xl-7 col-md-7">
-                    <div class="row">
-                        <div class="col-sm col-lg-5  col-xl-5 col-md-5">
-                            <div class="card">
-                                <div class="card-header">
-                                    <div class="col-5 row">
-                                        <div class="block">
-                                            <span class="demonstration"></span>
-                                            <el-date-picker @blur="logisticsCountingRecordsApi()"
-                                                            v-model="logisticsCountingRecordsData"
-                                                            type="daterange"
-                                                            align="right"
-                                                            unlink-panels
-                                                            range-separator="-"
-                                                            start-placeholder="开始日期"
-                                                            end-placeholder="结束日期"
-                                                            value-format="yyyy-MM-dd"
-                                                            :picker-options="pickerOptions">
-                                            </el-date-picker>
-                                        </div>
-                                    </div>
-                                </div>
-                                <div class="card-body row">
-                                    <div v-show="logisticsCountingRecordsShow" id="logisticsCountingRecords" class="col"
-                                         style="width: 600px;height:600px;"></div>
-                                    <div v-show="!logisticsCountingRecordsShow" class="text-center">
-                                        <h3>正在加载...</h3>
-                                    </div>
-                                </div>
+                <div class="col-sm-3 col-lg-3 col-xl-3 col-md-3">
+                    <div class="card">
+                        <div class="card-header">
+                            <div class="block row">
+                                    <span class="demonstration"></span>
+                                    <el-date-picker
+                                        size="small"
+                                        style="width: 60%;"
+                                        @blur="logisticsCountingRecordsApi()"
+                                        v-model="logisticsCountingRecordsData"
+                                        type="daterange"
+                                        align="right"
+                                        unlink-panels
+                                        range-separator="-"
+                                        start-placeholder="开始日期"
+                                        end-placeholder="结束日期"
+                                        value-format="yyyy-MM-dd"
+                                        :picker-options="pickerOptions">
+                                    </el-date-picker>
+                                    <el-select  placeholder="请选择对应货主" multiple v-model="selectLogisticsOwners" size="small" style="width: 50%"  @change="logisticsCountingRecordsApi('')">
+                                        <el-option label="选择所有" value="all"></el-option>
+                                        <el-option v-for="item in owners" :label="item.name" :value="item.id" :key="item.id"></el-option>
+                                    </el-select>
                             </div>
                         </div>
-                        <div class="col-sm col-lg-5  col-xl-5 col-md-5">
-                            <div class="card">
-                                <div class="card-header">
-                                    <div class="col-5 row">
-                                        <div class="block">
-                                            <span class="demonstration"></span>
-                                            <el-date-picker @blur="warehouseCountingRecordsApi()"
-                                                            v-model="warehouseCountingRecordsData"
-                                                            type="daterange"
-                                                            align="right"
-                                                            unlink-panels
-                                                            range-separator="-"
-                                                            start-placeholder="开始日期"
-                                                            end-placeholder="结束日期"
-                                                            value-format="yyyy-MM-dd"
-                                                            :picker-options="pickerOptions">
-                                            </el-date-picker>
-                                        </div>
-                                    </div>
-                                </div>
-                                <div class="card-body row">
-                                    <div v-show="warehouseCountingRecordsShow" id="warehouseCountingRecords" class="col"
-                                         style="width: 600px;height:600px;"></div>
-                                    <div v-show="!warehouseCountingRecordsShow">
-                                        正在加载
-                                    </div>
-                                </div>
+                        <div class="card-body row">
+                            <div v-show="logisticsCountingRecordsShow" id="logisticsCountingRecords" class="col"
+                                 style="width: 100%;height:500px;"></div>
+                            <div v-show="!logisticsCountingRecordsShow" class="text-center">
+                                <h3>正在加载...</h3>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+                <div class="col-sm-3 col-lg-3 col-xl-3 col-md-3">
+                    <div class="card">
+                        <div class="card-header">
+                            <div class="block">
+                                <span class="demonstration"></span>
+                                <el-date-picker
+                                    size="small"
+                                    style="width: 80%;"
+                                    @blur="warehouseCountingRecordsApi()"
+                                    v-model="warehouseCountingRecordsData"
+                                    type="daterange"
+                                    align="right"
+                                    unlink-panels
+                                    range-separator="-"
+                                    start-placeholder="开始日期"
+                                    end-placeholder="结束日期"
+                                    value-format="yyyy-MM-dd"
+                                    :picker-options="pickerOptions">
+                                </el-date-picker>
+                            </div>
+                        </div>
+                        <div class="card-body row">
+                            <div v-show="warehouseCountingRecordsShow" id="warehouseCountingRecords" class="col"
+                                 style="width: 100%;height:500px;"></div>
+                            <div v-show="!warehouseCountingRecordsShow">
+                                <h3>正在加载...</h3>
                             </div>
                         </div>
                     </div>
                 </div>
+            </div>
+            <div class="row my-3">
                 @can('人事管理-临时工报表-可见全部组')
-                    <div class="col-sm col-lg-5  col-xl-5 col-md-5">
+                    <div class="col-sm-6 col-lg-6  col-xl-6 col-md-6">
                         <div class="card">
                             <div class="card-header">
-                                <span class="demonstration"></span>
-                                <div class="block">
-                                    <span v-show="laborReportsCountingRecordsDayShow" class="demonstration">起始日期</span>
+                                <div class="block row">
+                                    <span class="demonstration"></span>
+                                    <span v-show="laborReportsCountingRecordsDayShow" class="demonstration mt-1">起始日期:</span>
                                     <el-date-picker
+                                        size="small"
                                         @blur="laborReportsCountingRecordApi('')"
                                         v-show="laborReportsCountingRecordsDayShow"
                                         v-model="laborReportsCountingRecordsStart"
@@ -214,9 +237,9 @@
                                         value-format="yyyy-MM-dd"
                                         placeholder="选起始日期">
                                     </el-date-picker>
-
-                                    <span v-show="laborReportsCountingRecordsDayShow" class="demonstration">结束日期</span>
+                                    <span v-show="laborReportsCountingRecordsDayShow" class="demonstration mt-1">结束日期:</span>
                                     <el-date-picker
+                                        size="small"
                                         @blur="laborReportsCountingRecordApi('')"
                                         v-show="laborReportsCountingRecordsDayShow"
                                         v-model="laborReportsCountingRecordsEnd"
@@ -224,9 +247,9 @@
                                         value-format="yyyy-MM-dd"
                                         placeholder="选择结束日期">
                                     </el-date-picker>
-
-                                    <span v-show="laborReportsCountingRecordsMonthShow" class="demonstration">起始月</span>
+                                    <span v-show="laborReportsCountingRecordsMonthShow" class="demonstration mt-1">起始月:</span>
                                     <el-date-picker
+                                        size="small"
                                         @blur="laborReportsCountingRecordApi('')"
                                         v-show="laborReportsCountingRecordsMonthShow"
                                         v-model="laborReportsCountingRecordsStart"
@@ -235,8 +258,9 @@
                                         placeholder="选择起始月">
                                     </el-date-picker>
 
-                                    <span v-show="laborReportsCountingRecordsMonthShow" class="demonstration">结束月</span>
+                                    <span v-show="laborReportsCountingRecordsMonthShow" class="demonstration mt-1">结束月:</span>
                                     <el-date-picker
+                                        size="small"
                                         @blur="laborReportsCountingRecordApi('')"
                                         v-show="laborReportsCountingRecordsMonthShow"
                                         v-model="laborReportsCountingRecordsEnd"
@@ -245,8 +269,9 @@
                                         placeholder="选择结束月">
                                     </el-date-picker>
 
-                                    <span v-show="laborReportsCountingRecordsYearShow" class="demonstration">起始年</span>
+                                    <span v-show="laborReportsCountingRecordsYearShow" class="demonstration mt-1">起始年:</span>
                                     <el-date-picker
+                                        size="small"
                                         @blur="laborReportsCountingRecordApi('')"
                                         v-show="laborReportsCountingRecordsYearShow"
                                         v-model="laborReportsCountingRecordsStart"
@@ -255,8 +280,9 @@
                                         placeholder="选择年">
                                     </el-date-picker>
 
-                                    <span v-show="laborReportsCountingRecordsYearShow" class="demonstration">结束年</span>
+                                    <span v-show="laborReportsCountingRecordsYearShow" class="demonstration mt-1">结束年:</span>
                                     <el-date-picker
+                                        size="small"
                                         @blur="laborReportsCountingRecordApi('')"
                                         v-show="laborReportsCountingRecordsYearShow"
                                         v-model="laborReportsCountingRecordsEnd"
@@ -264,50 +290,56 @@
                                         value-format="yyyy-MM-dd"
                                         placeholder="选择年">
                                     </el-date-picker>
+                                    <div class="btn-group btn-group-sm ml-2" role="group">
+                                        <el-button type="primary" value="日" @click="laborReportsCountingRecordApi('日')"
+                                                   class="btn btn-secondary"
+                                                   v-model="laborReportsCountingRecordUnit">日
+                                        </el-button>
+                                        <el-button type="primary" value="月" @click="laborReportsCountingRecordApi('月')"
+                                                   class="btn btn-secondary"
+                                                   v-model="laborReportsCountingRecordUnit">月
+                                        </el-button>
+                                        <el-button type="primary" value="年" @click="laborReportsCountingRecordApi('年')"
+                                                   class="btn btn-secondary"
+                                                   v-model="laborReportsCountingRecordUnit">年
+                                        </el-button>
+                                    </div>
                                 </div>
-
-                                <el-button type="primary" value="日" @click="laborReportsCountingRecordApi('日')"
-                                           v-model="laborReportsCountingRecordUnit">日
-                                </el-button>
-                                <el-button type="primary" value="月" @click="laborReportsCountingRecordApi('月')"
-                                           v-model="laborReportsCountingRecordUnit">月
-                                </el-button>
-                                <el-button type="primary" value="年" @click="laborReportsCountingRecordApi('年')"
-                                           v-model="laborReportsCountingRecordUnit">年
-                                </el-button>
                             </div>
                             <div class="card-body row">
                                 <div v-show="laborReportsCountingRecordsShow" id="laborReportsCountingRecords"
                                      class="col"
-                                     style="width:600px;height:600px;"></div>
+                                     style="width: 100%;height:500px;"></div>
                                 <div v-show="!laborReportsCountingRecordsShow">
-                                    正在加载
+                                    <h3>正在加载...</h3>
                                 </div>
                             </div>
                         </div>
                     </div>
-                    <div class="col-sm col-lg-7  col-xl-5 col-md-5">
+                    <div class="col-sm-6 col-lg-6  col-xl-6 col-md-6">
                         <div class="card">
                             <div class="card-header">
                                 <span class="demonstration"></span>
-                                <el-date-picker @blur="laborReportsUserGroupsCountApi('')"
-                                                v-model="laborReportsUserGroupsCountDate"
-                                                type="daterange"
-                                                align="right"
-                                                unlink-panels
-                                                range-separator="-"
-                                                start-placeholder="开始日期"
-                                                end-placeholder="结束日期"
-                                                value-format="yyyy-MM-dd"
-                                                :picker-options="pickerOptions">
+                                <el-date-picker
+                                    size="small"
+                                    @blur="laborReportsUserGroupsCountApi('')"
+                                    v-model="laborReportsUserGroupsCountDate"
+                                    type="daterange"
+                                    align="right"
+                                    unlink-panels
+                                    range-separator="-"
+                                    start-placeholder="开始日期"
+                                    end-placeholder="结束日期"
+                                    value-format="yyyy-MM-dd"
+                                    :picker-options="pickerOptions">
                                 </el-date-picker>
                             </div>
                             <div class="card-body row">
                                 <div v-show="laborReportsUserGroupsCountShow" id="laborReportsUserGroupsCount"
                                      class="col"
-                                     style="width:600px;height:600px;"></div>
+                                     style="width: 100%;height:500px;"></div>
                                 <div v-show="!laborReportsUserGroupsCountShow">
-                                    正在加载
+                                    <h3>正在加载...</h3>
                                 </div>
                             </div>
                         </div>
@@ -328,6 +360,9 @@
             data: {
                 myChart: null,
                 menus:{!! $menus !!},
+                owners:{!! $owners !!},
+                selectOrderOwners:[],
+                selectLogisticsOwners:[],
                 warehousesOrders:{!! $warehousesOrders !!},
                 orderCountingRecords:{!! $orderCountingRecords !!},
                 logisticsCountingRecords:{!! $logisticsCountingRecords !!},
@@ -395,7 +430,7 @@
                 orderCountingRecordsStart: moment().subtract('1', 'month').format('yyyy-MM-DD'),
                 orderCountingRecordsEnd: moment(new Date()).format('yyyy-MM-DD'),
                 orderCountingUnit: '日',
-                orderUnitsData:{
+                orderUnitsData: {
                     start_day: moment().subtract('1', 'month').format('yyyy-MM-DD'),
                     end_day: moment(new Date()).format('yyyy-MM-DD'),
                     start_month: moment().subtract('12', 'month').format('yyyy-MM-DD'),
@@ -405,7 +440,7 @@
                 },
 
                 laborReportsUnit: '日',
-                laborReportsData:{
+                laborReportsData: {
                     start_day: moment().subtract('1', 'month').format('yyyy-MM-DD'),
                     end_day: moment(new Date()).format('yyyy-MM-DD'),
                     start_month: moment().subtract('12', 'month').format('yyyy-MM-DD'),
@@ -420,6 +455,24 @@
                 laborReportsCountingRecordsStart: moment().subtract('1', 'month').format('yyyy-MM-DD'),
                 laborReportsCountingRecordsEnd: moment(new Date()).format('yyyy-MM-DD'),
             },
+            watch:{
+                selectOrderOwners:function(val,oldval){
+                    let newindex =  val.indexOf('all');
+                    let   oldindex =  oldval.indexOf('all');
+                    if(newindex!=-1 && oldindex==-1 && val.length>1)
+                        this.selectOrderOwners=['all'];
+                    else if(newindex!=-1 && oldindex!=-1 && val.length>1)
+                        this.selectOrderOwners.splice(val.indexOf('all'),1)
+                },
+                selectLogisticsOwners:function(val,oldval){
+                    let newindex =  val.indexOf('all');
+                    let   oldindex =  oldval.indexOf('all');
+                    if(newindex!=-1 && oldindex==-1 && val.length>1)
+                        this.selectLogisticsOwners=['all'];
+                    else if(newindex!=-1 && oldindex!=-1 && val.length>1)
+                        this.selectLogisticsOwners.splice(val.indexOf('all'),1)
+                }
+            },
             mounted: function () {
                 $('#list').removeClass('d-none');
                 let _this = this;
@@ -455,63 +508,63 @@
 
             },
             methods: {
-                switchDataPanel_forOrderCountingRecords(fromUnit,toUnit){
-                    switch (fromUnit){
+                switchDataPanel_forOrderCountingRecords(fromUnit, toUnit) {
+                    switch (fromUnit) {
                         case '日':
-                            this.orderUnitsData.start_day=this.orderCountingRecordsStart;
-                            this.orderUnitsData.end_day=this.orderCountingRecordsEnd;
+                            this.orderUnitsData.start_day = this.orderCountingRecordsStart;
+                            this.orderUnitsData.end_day = this.orderCountingRecordsEnd;
                             break;
                         case '月':
-                            this.orderUnitsData.start_month=this.orderCountingRecordsStart;
-                            this.orderUnitsData.end_month=this.orderCountingRecordsEnd;
+                            this.orderUnitsData.start_month = this.orderCountingRecordsStart;
+                            this.orderUnitsData.end_month = this.orderCountingRecordsEnd;
                             break;
                         case '年':
-                            this.orderUnitsData.start_year=this.orderCountingRecordsStart;
-                            this.orderUnitsData.end_year=this.orderCountingRecordsEnd;
+                            this.orderUnitsData.start_year = this.orderCountingRecordsStart;
+                            this.orderUnitsData.end_year = this.orderCountingRecordsEnd;
                             break;
                     }
-                    switch (toUnit){
+                    switch (toUnit) {
                         case '日':
-                            this.orderCountingRecordsStart=this.orderUnitsData.start_day;
-                            this.orderCountingRecordsEnd=this.orderUnitsData.end_day;
+                            this.orderCountingRecordsStart = this.orderUnitsData.start_day;
+                            this.orderCountingRecordsEnd = this.orderUnitsData.end_day;
                             break;
                         case '月':
-                            this.orderCountingRecordsStart=this.orderUnitsData.start_month;
-                            this.orderCountingRecordsEnd=this.orderUnitsData.end_month;
+                            this.orderCountingRecordsStart = this.orderUnitsData.start_month;
+                            this.orderCountingRecordsEnd = this.orderUnitsData.end_month;
                             break;
                         case '年':
-                            this.orderCountingRecordsStart=this.orderUnitsData.start_year;
-                            this.orderCountingRecordsEnd=this.orderUnitsData.end_year;
+                            this.orderCountingRecordsStart = this.orderUnitsData.start_year;
+                            this.orderCountingRecordsEnd = this.orderUnitsData.end_year;
                             break;
                     }
                 },
-                switchDataPanel_forLaborReports(fromUnit,toUnit){
-                    switch (fromUnit){
+                switchDataPanel_forLaborReports(fromUnit, toUnit) {
+                    switch (fromUnit) {
                         case '日':
-                            this.laborReportsData.start_day=this.laborReportsCountingRecordsStart;
-                            this.laborReportsData.end_day=this.laborReportsCountingRecordsEnd;
+                            this.laborReportsData.start_day = this.laborReportsCountingRecordsStart;
+                            this.laborReportsData.end_day = this.laborReportsCountingRecordsEnd;
                             break;
                         case '月':
-                            this.laborReportsData.start_month=this.laborReportsCountingRecordsStart;
-                            this.laborReportsData.end_month=this.laborReportsCountingRecordsEnd;
+                            this.laborReportsData.start_month = this.laborReportsCountingRecordsStart;
+                            this.laborReportsData.end_month = this.laborReportsCountingRecordsEnd;
                             break;
                         case '年':
-                            this.laborReportsData.start_year=this.laborReportsCountingRecordsStart;
-                            this.laborReportsData.end_year=this.laborReportsCountingRecordsEnd;
+                            this.laborReportsData.start_year = this.laborReportsCountingRecordsStart;
+                            this.laborReportsData.end_year = this.laborReportsCountingRecordsEnd;
                             break;
                     }
-                    switch (toUnit){
+                    switch (toUnit) {
                         case '日':
-                            this.laborReportsCountingRecordsStart=this.laborReportsData.start_day;
-                            this.laborReportsCountingRecordsEnd=this.laborReportsData.end_day;
+                            this.laborReportsCountingRecordsStart = this.laborReportsData.start_day;
+                            this.laborReportsCountingRecordsEnd = this.laborReportsData.end_day;
                             break;
                         case '月':
-                            this.laborReportsCountingRecordsStart=this.laborReportsData.start_month;
-                            this.laborReportsCountingRecordsEnd=this.laborReportsData.end_month;
+                            this.laborReportsCountingRecordsStart = this.laborReportsData.start_month;
+                            this.laborReportsCountingRecordsEnd = this.laborReportsData.end_month;
                             break;
                         case '年':
-                            this.laborReportsCountingRecordsStart=this.laborReportsData.start_year;
-                            this.laborReportsCountingRecordsEnd=this.laborReportsData.end_year;
+                            this.laborReportsCountingRecordsStart = this.laborReportsData.start_year;
+                            this.laborReportsCountingRecordsEnd = this.laborReportsData.end_year;
                             break;
                     }
                 },
@@ -524,9 +577,10 @@
                         this.orderCountingRecordsData.push(this.orderCountingRecords[key].counter);
                     }
                 },
-                initOrderCountingRecordsChart() {
+                initOrderCountingRecordsChart(text) {
+                    if (text==null ||text==''||text==undefined) text='默认显示权限下所有货主订单数量';
                     this.orderCountingRecordsChart.setOption({
-                        title: {text: '订单量趋势'},
+                        title: {text: '订单量趋势',subtext: text,},
                         tooltip: {},
                         legend: {data: ['订单数']},
                         xAxis: {
@@ -558,10 +612,12 @@
                         }]
                     });
                 },
-                initLogisticsCountingRecordsChart() {
+                initLogisticsCountingRecordsChart(text) {
+                    if (text==null ||text==''||text==undefined) text='默认显示权限下所有货主快递分布';
                     this.logisticsCountingRecordsChart.setOption({
                         title: {
                             text: '快递分布',
+                            subtext:text,
                             left: 'left'
                         },
                         tooltip: {
@@ -655,7 +711,7 @@
                         orderCountingRecordsUnit = this.orderCountingRecordsUnit;
                     }
                     this.switchDataPanel_forOrderCountingRecords(this.orderCountingUnit, orderCountingRecordsUnit);
-                    this.orderCountingUnit=orderCountingRecordsUnit;
+                    this.orderCountingUnit = orderCountingRecordsUnit;
                     switch (orderCountingRecordsUnit) {
                         case '日':
                             this.orderCountingRecordsDayShow = true;
@@ -674,33 +730,42 @@
                             break;
                     }
                     this.orderCountingRecordsUnit = orderCountingRecordsUnit;
-                    let formData = new FormData();
-                    formData.append('start', this.orderCountingRecordsStart);
-                    formData.append('end', this.orderCountingRecordsEnd);
-                    formData.append('unit', orderCountingRecordsUnit);
+                    // let formData = new FormData();
+                    // formData.append('start', this.orderCountingRecordsStart);
+                    // formData.append('end', this.orderCountingRecordsEnd);
+                    // formData.append('unit', orderCountingRecordsUnit);
+                    // formData.append('owner_ids',this.selectOwners);
                     this.orderCountingRecordsShow = false;
                     let _this = this;
-                    axios.post('{{url('apiLocal/control/panel/menu/orderCountingRecordApi')}}', formData).then(function (res) {
+                    let text = null;
+                    axios.post('{{url('apiLocal/control/panel/menu/orderCountingRecordApi')}}',{
+                        'start':this.orderCountingRecordsStart,'end':this.orderCountingRecordsEnd,
+                        'unit':orderCountingRecordsUnit,'owner_ids':this.selectOrderOwners}).then(function (res) {
                         if (res.status === 200) {
                             _this.orderCountingRecords = res.data.orderCountingRecords;
                             _this.orderCountingRecordsDateTarget = [];
                             _this.orderCountingRecordsData = [];
                             _this.initOrderCountingRecords();
-                            _this.initOrderCountingRecordsChart();
+                            if (_this.selectOrderOwners.length>0) text='当前选中货主订单数量';
+                            _this.initOrderCountingRecordsChart(text);
                             _this.orderCountingRecordsShow = true;
                         }
                     });
                 },
                 logisticsCountingRecordsApi() {
+                    let text = null;
                     this.logisticsCountingRecordsShow = false;
-                    let formData = new FormData();
-                    formData.append('start', this.logisticsCountingRecordsData[0]);
-                    formData.append('end', this.logisticsCountingRecordsData[1]);
+                    // let formData = new FormData();
+                    // formData.append('start', this.logisticsCountingRecordsData[0]);
+                    // formData.append('end', this.logisticsCountingRecordsData[1]);
                     let _this = this;
-                    axios.post('{{url('apiLocal/control/panel/menu/logisticsCountingRecordsApi')}}', formData).then(function (res) {
+                    axios.post('{{url('apiLocal/control/panel/menu/logisticsCountingRecordsApi')}}',{
+                        'start':this.logisticsCountingRecordsData[0],'end':this.logisticsCountingRecordsData[1],'owner_ids':this.selectLogisticsOwners
+                    }).then(function (res) {
                         if (res.status === 200) {
                             _this.logisticsCountingRecords = res.data.logisticsCountingRecords;
-                            _this.initLogisticsCountingRecordsChart();
+                            if (_this.selectLogisticsOwners.length>0) text='当前选中货主快递分布';
+                            _this.initLogisticsCountingRecordsChart(text);
                             _this.logisticsCountingRecordsShow = true;
                         }
                     });
@@ -728,7 +793,7 @@
                         laborReportsCountingRecordUnit = this.laborReportsCountingRecordUnit;
                     }
                     this.switchDataPanel_forLaborReports(this.laborReportsUnit, laborReportsCountingRecordUnit);
-                    this.laborReportsUnit=laborReportsCountingRecordUnit;
+                    this.laborReportsUnit = laborReportsCountingRecordUnit;
                     this.laborReportsCountingRecordUnit = laborReportsCountingRecordUnit;
                     switch (laborReportsCountingRecordUnit) {
                         case '日':

+ 13 - 32
resources/views/customer/customer/_customerLog.blade.php

@@ -1,43 +1,24 @@
 <div class="modal fade" tabindex="-1" role="dialog" id="modal">
-    <div class="modal-dialog modal-xl modal-dialog-centered modal-dialog-scrollable">
+    <div class="modal-dialog modal-lg modal-dialog-centered modal-dialog-scrollable">
         <div class="modal-content">
             <div class="modal-header">
-                <button type="button" class="btn btn-outline-info pull-left" @click="addLog()">新增</button>
+                <h4 class="modal-title text-primary">新增日志信息</h4>
                 <button type="button" class="close" data-dismiss="modal">&times;</button>
             </div>
             <div class="modal-body">
-                <table class="table table-sm table-hover table-striped" v-if="index !== ''">
-                    <tr>
-                        <th>状态</th>
-                        <th>操作者</th>
-                        <th>说明</th>
-                        <th>操作时间</th>
-                    </tr>
-                    <tr v-for="(log,i) in customerLogs[customers[index]['id']]">
-                        <td>
-                            <select id="logStatusName" v-if="!log.id" class="form-control form-control-sm" :id="'logStatus-'+log.id">
-                                <option v-for="logStatus in logStatuses" :value="logStatus.id">@{{ logStatus.name }}</option>
-                            </select>
-                            <label v-else for="logStatusName">
-                                @{{ log.status.name }}
-                            </label>
-                        </td>
-                        <td>@{{ log.user.name }}</td>
-                        <td style="max-width: 100px" class="cursor-pointer" @mouseenter="textClass($event,true)" @mouseleave="textClass($event,false)">
-                            <div class="text-overflow-replace" v-if="currentLogIndex !== i" @click="edit(i,log.user)">
-                                @{{ log.description }}
-                            </div>
-                            <div v-if="currentLogIndex === i && i===0">
-                                <textarea class="form-control form-control-sm" v-text="log.description" :id="'description-'+log.id"></textarea>
-                            </div>
-                        </td>
-                        <td>@{{ log.created_at }}</td>
-                    </tr>
-                </table>
+                <div class="row">
+                    <label for="status" class="col-3">客户状态</label>
+                    <select id="status" class="form-control form-control-sm col-5">
+                        <option v-for="status in logStatuses" :value="status.id">@{{ status.name }}</option>
+                    </select>
+                </div>
+                <div class="row mt-2">
+                    <label for="description" class="col-3">说明</label>
+                    <textarea id="description" class="form-control form-control-sm col-7"></textarea>
+                </div>
             </div>
             <div class="modal-footer">
-                <button type="button" class="btn btn-success" v-if="currentLogIndex !== ''" @click="editLog()">保存</button>
-                <button type="button" class="btn btn-danger" v-if="currentLogIndex !== ''" @click="closeEditLog()">取消</button>
+                <button type="button" class="btn btn-success" @click="addLog()">提交</button>
                 <button type="button" class="btn btn-secondary" data-dismiss="modal">关闭</button>
             </div>
         </div>

+ 256 - 109
resources/views/customer/customer/index.blade.php

@@ -18,50 +18,125 @@
             <table class="table table-striped table-hover text-nowrap">
                 <tr>
                     <th>序号</th>
-                    <th>代码</th>
                     <th>名称</th>
+                    <th>标签</th>
+                    <th></th>
                     <th>客户全称</th>
-                    <th>发票地址</th>
                     <th>联系人</th>
                     <th>联系电话</th>
                     <th>公司备注</th>
-                    <th>日志</th>
+                    <th class="text-center" style="min-width: 700px">
+                        <div class="row">
+                            <label class="col-12">日志</label>
+                        </div>
+                        <div class="row">
+                            <div class="row text-secondary offset-1 col-11">
+                                <label class="col-4">说明</label>
+                                <label class="col-2">状态</label>
+                                <label class="col-2">操作者</label>
+                                <label class="col-3">操作时间</label>
+                                <label class="col-1"></label>
+                            </div>
+                        </div>
+                    </th>
                     <th>合同</th>
+                    <th>发票地址</th>
                     <th>创建时间</th>
-                    <th>标签</th>
                     <th>操作</th>
                 </tr>
                 <tr v-for="(customer,i) in customers" :id="'model-'+customer.id">
                     <td>@{{ i+1 }}</td>
-                    <td>@{{ customer.code }}</td>
                     <td>@{{ customer.name }}</td>
+                    <td>
+                        <div class="text-overflow-warp-200 row">
+                            <span class="badge badge-pill badge-primary ml-1" v-for="(tag,i) in customer.tags">@{{ tag.name }}</span>
+                        </div>
+                    </td>
+                    <td class="cursor-pointer text-dark font-weight-bold">
+                        <div class="dropdown">
+                            <span class="fa fa-plus" :id="'tag-'+i" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"></span>
+                            <div class="dropdown-menu" :aria-labelledby="'tag-'+i">
+                                <div @click="$event.stopPropagation();" style="min-width: 250px">
+                                    <label class="w-75 ml-2"><input class="form-control form-control-sm" @keydown="submitTag(i,$event)" type="text" @input="search($event)"></label>
+                                    <span v-if="searchTag.length>0">
+                                        <a class="dropdown-item text-nowrap" v-for="tag in searchTag" @click="selected(i,tag)">
+                                            @{{ tag.value }}
+                                            <span class="fa fa-check text-info pull-right" style="top: 0.3rem" v-if="selectedTag[customer.id][tag.name]"></span>
+                                        </a>
+                                    </span>
+                                    <span v-else>
+                                        <a class="dropdown-item text-nowrap" v-for="tag in defaultTag" @click="selected(i,tag)">
+                                            <span class="fa fa-fire text-danger"></span>
+                                            &nbsp;@{{ tag.value }}
+                                            <span class="fa fa-check text-info pull-right" style="top: 0.3rem" v-if="selectedTag[customer.id][tag.name]"></span>
+                                        </a>
+                                    </span>
+                                </div>
+                            </div>
+                        </div>
+                    </td>
                     <td>@{{ customer.company_name }}</td>
-                    <td>@{{ customer.invoice_address }}</td>
                     <td>@{{ customer.contact_man }}</td>
                     <td>@{{ customer.phone }}</td>
                     <td>@{{ customer.remark }}</td>
-                    <td><span class="cursor-pointer" @click="showCustomerLog(customer.id,i)">查看</span></td>
-                    <td v-if="customer.contractQuantity>0" class="cursor-pointer" @click="showContract(customer.id)"><span class="fa" :class="contractIds['_'+customer.id] === true ? 'fa-angle-double-down' : 'fa-angle-double-right'"></span>@{{ customer.contractQuantity }}份合同</td>
-                    <td v-else>#</td>
-                    <td>@{{ customer.created_at }}</td>
                     <td>
-                        <div v-show="tagIndexes[i]">
-                            <select :id="'sel-'+i" class="selectpicker" multiple data-live-search="true" title="标签(多选)">
-                                <option v-for="tag in tags" :value="tag.name">@{{ tag.value }}</option>
-                            </select><br>
-                            <button class="btn btn-sm btn-success" @click="addTag(i)">确定</button>
-                            <button class="btn btn-sm btn-danger" @click="cancelTag(i)">取消</button>
-                        </div>
-                        <div v-if="!tagIndexes[i]">
-                            <span v-for="(tag,i) in customer.tags">
-                                <span class="badge badge-primary m-1" >@{{ tag.name }}</span><br v-if="(i+1)%2 === 0">
-                            </span>
+                        <div class="bg-white row">
+                            <div class="col-1"><button class="btn btn-sm btn-outline-info" @click="addCustomerLog(i)">添加</button></div>
+                            <div class="col-11">
+                                <div class="w-100">
+                                    <div class="text-center mb-0 row" v-for="(log,j) in customer.customer_logs" v-if="j<2" @click="edit(i,j,log.user)">
+                                        <div @mouseenter="textClass($event,true)" @mouseleave="textClass($event,false)" class="col-4">
+                                            <div class="text-overflow-replace cursor-pointer text-secondary" v-if="log.id && (editCustomer!=customer.id || j!=0)">
+                                                @{{ log.description }}
+                                            </div>
+                                            <label v-if="!log.id">
+                                                <textarea class="form-control form-control-sm" @blur="addLog(i,j)" v-model="log.description"></textarea>
+                                            </label>
+                                            <label v-if="editCustomer == customer.id && j==0">
+                                                <textarea @blur="editLog(i,$event)" class="form-control form-control-sm">@{{ log.description }}</textarea>
+                                            </label>
+                                        </div>
+                                        <div class="col-2">
+                                            <span v-if="log.id && (editCustomer!=customer.id || j!=0)">@{{ log.status ? log.status.name : '' }}</span>
+                                            <label v-if="!log.id"><select class="form-control form-control-sm" @change="addLog(i,j)" @click="editLogEvent(log)">
+                                                <option v-for="status in logStatuses" :value="status.id">@{{ status.name }}</option>
+                                            </select></label>
+                                            <label v-if="editCustomer == customer.id && j==0">
+                                                <select class="form-control form-control-sm" @change="editLogStatus(i,log)" v-model="log.customer_log_status_id">
+                                                    <option v-for="status in logStatuses" :value="status.id">@{{ status.name }}</option>
+                                                </select>
+                                            </label>
+                                        </div>
+                                        <div class="col-2 text-secondary">@{{ log.user ? log.user.name : '' }}</div>
+                                        <div class="col-3 text-secondary">@{{ log.created_at }}</div>
+                                        @can("客户-编辑")<div class="col-1 font-weight-bold text-danger h4 cursor-pointer" @click="delLog(i,j)">&times;</div>@endcan
+                                    </div>
+                                </div>
+                                <div class="w-100 up" :id="'log-'+customer.id">
+                                    <div class="text-center mb-0 row" v-for="(log,j) in customer.customer_logs" v-if="j>1">
+                                        <div @mouseenter="textClass($event,true)" @mouseleave="textClass($event,false)" class="col-4"><div class="text-overflow-replace cursor-pointer text-secondary">@{{ log.description }}</div></div>
+                                        <div class="col-2">@{{ log.status ? log.status.name : '' }}</div>
+                                        <div class="col-2 text-secondary">@{{ log.user ? log.user.name : '' }}</div>
+                                        <div class="col-3 text-secondary">@{{ log.created_at }}</div>
+                                        @can("客户-编辑")<div class="col-1 font-weight-bold text-danger h4 cursor-pointer" @click="delLog(i,j)">&times;</div>@endcan
+                                    </div>
+                                </div>
+                                <div class="row" @click="showLog(i)" v-if="customer.customer_logs.length > 2">
+                                    <label class="text-center mt-0 p-0 cursor-pointer offset-5">
+                                        <span class="fa" :class="customer.isShowLog ? 'fa-angle-double-down' : 'fa-angle-double-right'"></span>
+                                        &nbsp;<span v-if="customer.isShowLog">收起</span><span v-if="!customer.isShowLog">展开</span>&nbsp;@{{ customer.customer_logs.length }} 条日志
+                                    </label>
+                                </div>
+                            </div>
                         </div>
                     </td>
+                    <td v-if="customer.contractQuantity>0" class="cursor-pointer" @click="showContract(customer.id)"><span class="fa" :class="contractIds['_'+customer.id] === true ? 'fa-angle-double-down' : 'fa-angle-double-right'"></span>@{{ customer.contractQuantity }}份合同</td>
+                    <td v-else>#</td>
+                    <td>@{{ customer.invoice_address }}</td>
+                    <td>@{{ customer.created_at }}</td>
                     <td>
                         @can("客户-编辑")
                             <button class="btn btn-sm btn-outline-success" @click="addContract(i)">新建合同</button>
-                            <button v-if="!tagIndexes[i]" class="btn btn-sm btn-info text-white" @click="setTag(i)">设定标签</button>
                             <button class="btn btn-sm btn-outline-primary" @click="relatedOwner(i)">关联项目</button>
                             <a :href="'{{url('customer/customer')}}/'+customer.id+'/edit'"><button class="btn btn-sm btn-outline-info">改</button></a>
                         @endcan
@@ -80,10 +155,8 @@
             el:"#container",
             data:{
                 customers :  {!!  $customers->toJson() !!}['data'],
-                customerLogs : [],
                 index:'',
-                currentLogIndex:"",
-                logStatuses:[],
+                logStatuses:null,
                 contractIds:[],
                 customerOwners:[],
                 files:[],
@@ -94,15 +167,20 @@
                 ],
                 ownerIds:[],
                 ownerNames:[],
-                tagIndexes : [],
                 tags:[
                     @foreach($tags as $tag)
                     {name:"{{$tag->id}}",value:"{{$tag->name}}"},
                     @endforeach
                 ],
+                defaultTag:[],
+                selectedTag:[],
+                searchTag:[],
+                editCustomer:"",
+                addCustomerLogIndex:"",
             },
             mounted(){
                 this._formatOwner();
+                $(".up").slideUp();
                 $('#container').removeClass('d-none');
                 this.rendering();
                 let data=[
@@ -118,40 +196,138 @@
                     el:"#form_div",
                     condition:data,
                 }).init();
+                this.defaultTag = this.tags.slice(0,3);
+                this.customers.forEach(customer=>{
+                    let selectedTag = {};
+                    if (customer.tags)
+                        customer.tags.forEach(tag=>{
+                            selectedTag[tag.id] = tag.name;
+                        });
+                    this.selectedTag[customer.id] = selectedTag;
+                });
             },
             methods:{
-                addTag(index){
-                    let val = $("#sel-"+index).selectpicker('val');
-                    let url = "{{url('customer/customer/addTag')}}";
-                    let params = {id:this.customers[index]['id'],tags:val};
-                    window.tempTip.postBasicRequest(url,params,(res)=>{
-                        this.customers[index].tags = res;
-                        this.tagIndexes[index] = false;
+                submitTag(index,e){
+                    if (e.keyCode === 9)window.event.returnValue = false;
+                    if (e.keyCode === 13 || e.keyCode === 9){
+                        let val = e.target.value;
+                        if (this.searchTag.length>0){
+                            let sign = this.searchTag.every(tag=> {
+                                if (tag.value === val){
+                                    this.selected(index,tag);
+                                    return false;
+                                }
+                                return true;
+                            });
+                            if (!sign)return;
+                        }
+                        window.tempTip.postBasicRequest("{{url('customer/customer/customerTag/save')}}",{name:val},res=>{
+                            let tag = {name:res.id,value:res.name};
+                            this.tags.unshift(tag);
+                            this.selected(index,tag);
+                            e.target.value = "";
+                        });
+                    }
+                },
+                selected(index,tag){
+                    let id = this.customers[index].id;
+                    if (!this.selectedTag[id])this.selectedTag[id] = {};
+                    if (this.selectedTag[id][tag.name]){
+                        window.tempTip.postBasicRequest("{{url('customer/customer/delTag')}}",{id:id,tag:tag.name},res=>{
+                            this.$delete(this.selectedTag[id],tag.name);
+                            this.customers[index].tags.some((t,i)=>{
+                                if (t.id == tag.name){
+                                    this.$delete(this.customers[index].tags,i);
+                                    return true;
+                                }
+                            });
+                            this.$forceUpdate();
+                        });
+                    }else window.tempTip.postBasicRequest("{{url('customer/customer/addTag')}}",{id:id,tag:tag.name},res=>{
+                        this.selectedTag[id][tag.name] = tag.value;
+                        let obj = {id:tag.name,name:tag.value};
+                        if (this.customers[index].tags) this.customers[index].tags.unshift(obj);
+                        else this.customers[index].tags = [obj];
                         this.$forceUpdate();
-                        return "设定标签成功";
                     });
                 },
-                cancelTag(index){
-                    this.tagIndexes[index] = false;
-                    this.$forceUpdate();
+                search(e){
+                    let val = e.target.value;
+                    if (!val){
+                        this.searchTag = [];
+                        return;
+                    }
+                    let arr = [];
+                    this.tags.forEach(tag=>{
+                        if (tag.value.indexOf(val) !== -1)arr.push(tag);
+                    });
+                    this.searchTag = arr;
+                },
+                editLogEvent(log){
+                    log.isEdit = true;
                 },
-                setTag(index) {
-                    this.tagIndexes[index] = true;
-                    let defaults = [];
-                    if (this.customers[index].tags){
-                        this.customers[index].tags.forEach(tag=>{
-                            defaults.push(tag.id);
+                textClass(event,isOver){
+                    event = event.target.children[0];
+                    if (isOver) event.className = "text-overflow-warp";
+                    else event.className = "cursor-pointer text-overflow-replace text-secondary";
+                },
+                editLog(customer_index,event){
+                    let description = event.target.value;
+                    if (description ===this.customers[customer_index].customer_logs[0].description){
+                        this.editCustomer = "";
+                        return;
+                    }
+                    let url="{{url('customer/customer/editLog')}}";
+                    let params = {id:this.customers[customer_index].customer_logs[0].id,description:description};
+                    window.tempTip.confirm("确定要提交该条日志的修改信息吗?",()=>{
+                        window.tempTip.postBasicRequest(url,params,(res)=> {
+                            this.customers[customer_index].customer_logs[0].description = description;
+                            this.editCustomer = "";
+                            this.$forceUpdate();
+                            return "修改说明成功!";
+                        });
+                    });
+                },
+                editLogStatus(customer_index,log){
+                    let url="{{url('customer/customer/editLog')}}";
+                    let params = {id:log.id,customer_log_status_id:log.customer_log_status_id};
+                    window.tempTip.confirm("确定要提交该条日志的修改信息吗?",()=>{
+                        window.tempTip.postBasicRequest(url,params,(res)=> {
+                            this.customers[customer_index].customer_logs[0].customer_log_status_id = log.customer_log_status_id;
+                            this.logStatuses.some(status=> {
+                                if (status.id === log.customer_log_status_id){
+                                    this.customers[customer_index].customer_logs[0].status = status;
+                                    return true;
+                                }
+                            });
+                            this.editCustomer = "";
+                            this.$forceUpdate();
+                            return "修改状态成功!";
                         });
+                    });
+                },
+                showLog(index){
+                    if(this.customers[index].isShowLog){
+                        this.customers[index].isShowLog = false;
+                        $("#log-"+this.customers[index].id).slideUp();
+                    } else{
+                        this.customers[index].isShowLog = true;
+                        $("#log-"+this.customers[index].id).slideDown();
                     }
                     this.$forceUpdate();
-                    /*if (this.tags.length<1){
-                        window.tempTip.postBasicRequest("{{--{{url('customer/customer/customerTag/get')}}--}}",{},(res)=>{
-                            this.tags = res;
+                },
+                delLog(customer_index,log_index){
+                    let id = this.customers[customer_index].customer_logs[log_index].id;
+                    if (!id){
+                        this.$delete(this.customers[customer_index].customer_logs,log_index);
+                        return;
+                    }
+                    window.tempTip.confirm("确定要删除该条日志吗?",()=>{
+                        window.tempTip.postBasicRequest("{{url('customer/customer/destroyLog')}}",{id:id},res=>{
+                            this.$delete(this.customers[customer_index].customer_logs,log_index);
+                            return "已成功删除该条日志记录";
                         });
-                    }*/
-                    //setTimeout(()=>{
-                        $(".selectpicker").selectpicker('refresh').selectpicker('val',defaults);
-                    //},500);
+                    })
                 },
                 _formatOwner(){
                     let ownerIds=[];
@@ -227,77 +403,48 @@
                         })
                     })
                 },
-                showCustomerLog(id,index){
-                    this.index = index;
-                    if (this.customerLogs[id]){
-                        $("#modal").modal('show');
-                        return;
-                    }
-                    let url="{{url('customer/customer/getLog')}}";
-                    let params = {customer_id:id};
-                    window.tempTip.postBasicRequest(url,params,(res)=> {
-                        this.customerLogs[id] = res;
-                        this.$forceUpdate();
-                        $("#modal").modal('show');
+                addCustomerLog(index){
+                    if (this.customers[index].customer_logs[0] && !this.customers[index].customer_logs[0].id)return;
+                    if (!this.logStatuses)window.tempTip.postBasicRequest("{{url('customer/customer/getLogStatus')}}",{},(res)=>{
+                        this.logStatuses = res;
+                    },true);
+                    this.customers[index].customer_logs.unshift({
+                        id:"",
+                        status:"1",
+                        description:"",
                     });
                 },
-                textClass(event,isOver){
-                    event = event.target.children[0];
-                    if (isOver){event.classList.remove("text-overflow-replace");}
-                    else {event.classList.add("text-overflow-replace");}
-                },
-                edit(index,user){
+                edit(index,logIndex,user){
+                    if (logIndex!==0)return;
+                    if (!user)return;
                     let id = "{{\Illuminate\Support\Facades\Auth::id()}}";
                     if (id != user.id) return;
-                    if (index === 0)this.currentLogIndex=index;
-                    else this.currentLogIndex='';
-                },
-                closeEditLog(){
-                    this.currentLogIndex = '';
-                    if (this.customerLogs[this.customers[this.index]['id']][0].id === ''){
-                        this.$delete(this.customerLogs[this.customers[this.index]['id']],0);
-                    }
+                    if (!this.logStatuses)window.tempTip.postBasicRequest("{{url('customer/customer/getLogStatus')}}",{},(res)=>{
+                        this.logStatuses = res;
+                    });
+                    this.editCustomer = this.customers[index].id;
                 },
-                editLog(){
-                    let log = this.customerLogs[this.customers[this.index]['id']][this.currentLogIndex];
-                    if (log.id === ''){
-                        let description = $("#description-"+log.id)[0].value;
-                        let logStatus = $("#logStatus-"+log.id)[0].value;
+                addLog(index,logIndex){
+                    let exe = ()=>{
                         let url="{{url('customer/customer/storeLog')}}";
-                        let params = {customer_id:this.customers[this.index]['id'],description:description,customer_log_status_id:logStatus};
+                        let params = {customer_id:this.customers[index].id,description:this.customers[index].customer_logs[logIndex].description,customer_log_status_id:this.customers[index].customer_logs[logIndex].status};
                         window.tempTip.postBasicRequest(url,params,(res)=>{
-                            this.customerLogs[this.customers[this.index]['id']][0] = res;
-                            this.currentLogIndex = '';
+                            this.customers[index].customer_logs[logIndex] = res;
                             this.$forceUpdate();
+                            $("#modal").modal('hide');
                             return "成功创建客户日志";
                         },true);
+                    };
+                    if (!this.customers[index].customer_logs[logIndex].description || !this.customers[index].customer_logs[logIndex].status)return;
+                    if (this.customers[index].customer_logs[logIndex].isEdit){
+                        exe();
                         return;
                     }
-                    let url="{{url('customer/customer/editLog')}}";
-                    let description = $("#description-"+log.id)[0].value;
-                    let params = {id:log.id,description:description};
-                    window.tempTip.postBasicRequest(url,params,(res)=> {
-                        this.customerLogs[this.customers[this.index]['id']][this.currentLogIndex].description = description;
-                        this.currentLogIndex = '';
-                        this.$forceUpdate();
-                        return "修改说明成功!";
-                    },true);
-                },
-                addLog(){
-                    if (this.logStatuses.length < 1)window.tempTip.postBasicRequest("{{url('customer/customer/getLogStatus')}}",{},(res)=>{
-                        this.logStatuses = res;
-                    },true);
-                    let logs = this.customerLogs[this.customers[this.index]['id']];
-                    if (logs.length > 0 && logs[0].id === "")return;
-                    logs.unshift({
-                        id:"",
-                        status:{name:""},
-                        user:{name:"{{\Illuminate\Support\Facades\Auth::user()->name}}"},
-                        description:"",
-                        created_at:"",
-                    });
-                    this.currentLogIndex = 0;
-                    this.$forceUpdate();
+                    setTimeout(()=>{
+                        if (this.customers[index].customer_logs[logIndex].isEdit) return;
+                        exe();
+                        this.customers[index].customer_logs[logIndex].isEdit = false;
+                    },500);
                 },
                 showContract(id){
                     if (this.contractIds['_'+id] &&  this.contractIds['_'+id]===true){

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

@@ -1,55 +0,0 @@
-<div class="row">
-    <div class="col-6">
-        <div class="card">
-            <div class="card-header bg-light-info">
-                <span class="pull-left font-weight-bold cursor-pointer" @click="show('storage')"><span class="fa fa-cubes"></span>&nbsp;仓储</span>
-            </div>
-            <div class="card-body" id="storage">
-                <table class="table table-sm">
-                    <tr>
-                        <th>计费类型</th>
-                        <th>用仓类型</th>
-                        <th>起租面积</th>
-                        <th>单价</th>
-                        <th>单位</th>
-                        <th>减免类型</th>
-                        <th>减免值</th>
-                    </tr>
-                    <tr v-for="item in selectedModel.storage">
-                        <td>@{{ item.counting_type }}</td>
-                        <td>@{{ item.using_type }}</td>
-                        <td>@{{ item.minimum_area }}</td>
-                        <td>@{{ item.price }}</td>
-                        <td>@{{ item.discount_type }}</td>
-                        <td>@{{ item.discount_value }}</td>
-                        <td>@{{ poolMapping.units[item.unit_id] }}</td>
-                    </tr>
-                </table>
-            </div>
-        </div>
-    </div>
-    <div class="col-6">
-        <div class="card">
-            <div class="card-header bg-light-info">
-                <button type="button" class="btn mr-1" :class="type == 'storage' ? 'btn-primary text-white' : 'btn-outline-primary'" @click="switchType('storage')">仓储</button>
-                <button type="button" class="btn mr-1" :class="type == 'operation' ? 'btn-primary text-white' : 'btn-outline-primary'" @click="switchType('operation')">作业</button>
-                <button type="button" class="btn mr-1" :class="type == 'express' ? 'btn-primary text-white' : 'btn-outline-primary'" @click="switchType('express')">快递</button>
-                <button type="button" class="btn mr-1" :class="type == 'logistic' ? 'btn-primary text-white' : 'btn-outline-primary'" @click="switchType('logistic')">物流</button>
-                <button type="button" class="btn mr-1" :class="type == 'directLogistic' ? 'btn-primary text-white' : 'btn-outline-primary'" @click="switchType('directLogistic')">直发</button>
-            </div>
-            <div class="card-body">
-                <div v-if="type == 'storage'">
-                    @include("customer.project._storage")
-                </div>
-                <div v-show="type == 'operation'">
-                    @include("customer.project._operation")
-                    @include("customer.project._addFeature")
-                </div>
-                <div class="row mt-3" v-if="base=='three'">
-                    <div class="col-3"></div>
-                    <button type="button" class="btn btn-success ml-1 col-6" @click="saveModel()">保存</button>
-                </div>
-            </div>
-        </div>
-    </div>
-</div>

+ 545 - 41
resources/views/customer/project/create.blade.php

@@ -56,13 +56,13 @@
             <form method="POST" action="{{url('customer/project/store')}}" class="mt-5">
                 @csrf
                 <div v-if="base == 'one'">
-                    @include("customer.project._one")
+                    @include("customer.project.part._one")
                 </div>
                 <div v-if="base == 'two'">
-                    @include("customer.project._two")
+                    @include("customer.project.part._two")
                 </div>
                 <div v-if="base == 'three'">
-                    @include("customer.project._three")
+                    @include("customer.project.part._three")
                 </div>
                 <div class="row mt-3">
                     <div class="pull-right offset-7">
@@ -82,7 +82,7 @@
         new Vue({
             el:"#container",
             data:{
-                base:"one",
+                base:"three",
                 owner : {
                     id:"{{old('id') ?? ($owner->id ?? '') }}",
                     name : "{{old('name') ?? ($owner->name ?? '')}}",
@@ -140,6 +140,10 @@
                     storage : false,
                 },
                 type:"storage",//当前编辑类型 仓储,作业,物流...
+
+                currentInputting:{
+                    edittingOperation:null,
+                },
                 model:{ //编辑元素绑定值
                     storage:{
                         counting_type : "",
@@ -161,6 +165,22 @@
                             {strategy:"特征"},
                         ],
                     },
+                    express:{
+                        name:"",
+                        initial_weight:"",
+                        additional_weight:"",
+                        items:[],
+                        logistics:[],
+                    },
+                    logistic:{
+                        items:[],
+                        other_ranges:[],
+                        ranges:[],
+                        logistics:[],
+                    },
+                    directLogistic:{
+                        items:[],
+                    },
                 },
                 pool:{//基础数据选择池,以方便异步懒加载而非即时加载 例:units,owners等
                     counting_type:[
@@ -172,17 +192,26 @@
                     discount_type:[
                         "无减免","按单减免","固定减免"
                     ],
+                    feature_type:['商品名称','订单类型','承运商','店铺类型'],
+                    logic : ['包含','不包含','等于'],
                 },
                 poolMapping:{//基础数据选择池的映射对象 供展示使用
 
                 },
                 selectedModel:{//已选定的计费模型
                     storage:[],
+                    operation:[],
+                    express:[],
+                    logistic:[],
+                    directLogistic:{},
                 },
                 thisOperationItemIndex:-1,//当前选中的作业费子项下标,用以唤起特征模态框
-                oldFeature:"",//上一个特征,如果与当前特征一致则无需再次转换特征
+                operationItems:{},//控制作业费子项的渐入展开
+                importError:[],//导入时的错误数据原因
+                isShowError:false,//是否展开导入错误信息
             },
             mounted(){
+                $('[data-toggle="tooltip"]').tooltip();
                 if (this.errors.length===0 && this.owner.id){
                     this.display = true;
                 }
@@ -193,6 +222,7 @@
                     if (this.upList[id])$("#"+id).slideDown();
                     else $("#"+id).slideUp();
                     this.upList[id] = !this.upList[id];
+                    this.$forceUpdate();
                 },
                 //切换选项
                 switchBase(base){
@@ -203,12 +233,27 @@
                 //切换类型
                 switchType(type){
                     if (type === this.type)return;//相同终止是为了减少重复加载动作
+                    let parent = $("#parent");
                     switch (type) {
                         case "storage":
                             this._loadStorage();
+                            parent.prepend($("#storage-card"));
                             break;
                         case "operation":
                             this._loadOperation();
+                            parent.prepend($("#operation-card"));
+                            break;
+                        case "express":
+                            this._loadExpress();
+                            parent.prepend($("#express-card"));
+                            break;
+                        case "logistic":
+                            this._loadLogistic();
+                            parent.prepend($("#logistic-card"));
+                            break;
+                        case "directLogistic":
+                            this._loadDirectLogistic();
+                            parent.prepend($("#directLogistic-card"));
                             break;
                     }
                     this.type = type;
@@ -251,12 +296,6 @@
                         this.errors["owner_group_id"] = ["必须选择项目小组"];
                         this.$forceUpdate();
                     }
-/*                    this._requestRequest({
-                        customer_id:this.owner.customer_id,
-                        owner_group_id:this.owner.owner_group_id,
-                        tax_rate:this.owner.tax_rate,
-                        waring_line_on:this.owner.waring_line_on,
-                    },"three")*/
                 },
                 //上一步
                 back(){
@@ -290,6 +329,32 @@
                 _loadOperation(){
                     if (!this.pool.units)this._getUnits();
                 },
+                //加载快递
+                _loadExpress(){
+                    if (!this.pool.provinces)this._getProvinces();
+                    if (!this.pool.logistics){
+                        this._getLogistics();
+                        setTimeout(()=>{
+                            $(".selectpicker").selectpicker('refresh');
+                        },500);
+                    }
+                },
+                //加载物流
+                _loadLogistic(){
+                    if (!this.pool.units) this._getUnits();
+                    if (!this.pool.provinces)this._getProvinces();
+                    if (!this.pool.cities)this._getCities();
+                    if (!this.pool.logistics){
+                        this._getLogistics();
+                        setTimeout(()=>{
+                            $(".selectpicker").selectpicker('refresh');
+                        },500);
+                    }
+                },
+                //加载直发车
+                _loadDirectLogistic(){
+                    if (!this.pool.cars)this._getCars();
+                },
                 //获取单位
                 _getUnits(){
                     let url = "{{url('maintenance/unit/getUnits')}}";
@@ -303,12 +368,76 @@
                         this.$forceUpdate();
                     });
                 },
+                //获取省份
+                _getProvinces(){
+                    let url = "{{url('maintenance/province/get')}}";
+                    window.tempTip.postBasicRequest(url,{},res=>{
+                        this.pool.provinces = res;
+                        let mapping = [];
+                        res.forEach(province=>{
+                            mapping[province.id] = province.name;
+                        });
+                        this.poolMapping.provinces = mapping;
+                        this.$forceUpdate();
+                    });
+                },
+                //获取城市
+                _getCities(){
+                    let url = "{{url('maintenance/city/get')}}";
+                    window.tempTip.postBasicRequest(url,{},res=>{
+                        this.pool.cities = res;
+                        let mapping = [];
+                        res.forEach(city=>{
+                            mapping[city.id] = city.name;
+                        });
+                        this.poolMapping.cities = mapping;
+                        this.$forceUpdate();
+                    });
+                },
+                //获取承运商
+                _getLogistics(){
+                    let url = "{{url('maintenance/logistic/get')}}";
+                    window.tempTip.postBasicRequest(url,{type:''},res=>{
+                        this.pool.logistics = res;
+                        let mapping = [];
+                        res.forEach(logistic=>{
+                            mapping[logistic.id] = logistic.name;
+                        });
+                        this.poolMapping.logistics = mapping;
+                        this.$forceUpdate();
+                    });
+                },
+                //获取车型
+                _getCars(){
+                    let url = "{{url('maintenance/carType/get')}}";
+                    window.axios.post(url).then(res=>{
+                        this.pool.cars = res.data;
+                        let mapping = [];
+                        res.data.forEach(car=>{
+                            mapping[car.id] = car.name;
+                        });
+                        this.poolMapping.cars = mapping;
+                        this.$forceUpdate();
+                    });
+                },
                 //保存模型
                 saveModel(){
                     switch (this.type) {
                         case "storage":
                             this._verifyStorage();
                             break;
+                        case "operation":
+                            this._verifyOperation();
+                            break;
+                        case "express":
+                            this._verifyExpress();
+                            break;
+                        case "logistic":
+                            this._verifyLogistic();
+                            break;
+                        case "directLogistic":
+                            this._verifyDirectLogistic();
+                            break;
                     }
                 },
                 _verifyStorage(){
@@ -344,6 +473,126 @@
                     };
                     this.errors = [];
                 },
+                _verifyOperation() {
+                    if (this.selectedModel.operation.length>0){
+                        this.selectedModel.operation.forEach(operation=>{
+                            if (operation.operation_type === this.model.operation.operation_type && operation.strategy === this.model.operation.strategy){
+                                this.errors["operation_type"] = ["已存在同类型的"+operation.operation_type+"作业计费模型"];
+                                this.$forceUpdate();
+                                return;
+                            }
+                        });
+                    }
+                    if (!this.model.operation.name){
+                        this.errors["name"] = ["名称不得为空"];
+                        this.$forceUpdate();
+                        return;
+                    }
+                    if ((this.model.operation.operation_type === '出库' && this._verifyOperationItem(0)) || this._verifyOperationItem(1))return;
+                    if (this.model.operation.items.length>2){
+                        for (let i=2;i<this.model.operation.items.length;i++){
+                            if (this._verifyOperationItem(i))return;
+                        }
+                    }
+                    if (this.model.operation.operation_type === '入库')this.$delete(this.model.operation.items,0);//入库时干掉起步子项
+                    this.selectedModel.operation.push(this.model.operation);
+                    this.model.operation = {
+                        operation_type:"入库",
+                        strategy:"默认",
+                        name:"",
+                        feature:"",
+                        items : [
+                            {strategy:"起步"},
+                            {strategy:"默认"},
+                            {strategy:"特征"},
+                        ],
+                    };
+                    this.errors = [];
+                },
+                _verifyOperationItem(itemIndex){//验证作业费子项信息完整
+                    let obj = this.model.operation.items[itemIndex];
+                    let sign = false;
+                    if (!obj.amount){
+                        this.errors['items.'+itemIndex+'.amount'] = ["数量不得为空"];
+                        sign = true;
+                    }
+                    if (!obj.unit_id){
+                        this.errors['items.'+itemIndex+'.unit_id'] = ["必须选择单位"];
+                        sign = true;
+                    }
+                    if (!obj.unit_price){
+                        this.errors['items.'+itemIndex+'.unit_price'] = ["单价不得为空"];
+                    }
+                    if (sign)this.$forceUpdate();
+                    return sign;
+                },
+                _verifyExpress(){
+                    let error = {};
+                    if (!this.model.express.name)error.name = ["名称不得为空"];
+                    if (!this.model.express.initial_weight)error.initial_weight = ["首重不得为空"];
+                    if (!this.model.express.additional_weight)error.additional_weight = ["续重不得为空"];
+                    if (this.model.express.items.length>0){
+                        this.model.express.items.forEach((item,index)=>{
+                            if (!item.province_id)error["item."+index+".province_id"] = ["不存在"];
+                            if (!item.initial_weight_price)error["item."+index+".initial_weight_price"] = ["不存在"];
+                            if (!item.additional_weight_price)error["item."+index+".additional_weight_price"] = ["不存在"];
+                        });
+                    }
+                    if (JSON.stringify(error) !== "{}"){
+                        this.errors = error;
+                        this.$forceUpdate();
+                        return;
+                    }
+                    this.selectedModel.express.unshift(this.model.express);
+                    this.model.express = {
+                        name:"",
+                        logistics:[],
+                        initial_weight:"",
+                        additional_weight:"",
+                        items:[],
+                    };
+                    this.errors = [];
+                    this.importError = [];
+                    $(".selectpicker").filter('.express').selectpicker('val',[]);
+                },
+                _verifyLogistic(){
+                    let error = {};
+                    if (!this.model.logistic.name) error.name = ["名称不得为空"];
+                    if (!this.model.logistic.unit_id) error.unit_id = ["单位一不得为空"];
+                    if (!this.model.logistic.unit_range) error.unit_range = ["区间值不得为空"];
+                    if (!this.model.logistic.other_unit_id) error.other_unit_id = ["单位二不得为空"];
+                    if (!this.model.logistic.other_unit_range) error.other_unit_range = ["区间值不得为空"];
+                    if (JSON.stringify(error) !== "{}"){
+                        this.errors = error;
+                        this.$forceUpdate();
+                        return;
+                    }
+                    this.selectedModel.logistic.unshift(this.model.logistic);
+                    this.model.logistic = {
+                            items:[],
+                            other_ranges:[],
+                            ranges:[],
+                    };
+                    this.errors = [];
+                    this.importError = [];
+                    $(".selectpicker").filter('.logistic').selectpicker('val',[]);
+                },
+                _verifyDirectLogistic(){
+                    let error = {};
+                    if (!this.model.directLogistic.name) error.name = ["名称不得为空"];
+                    if (!this.model.directLogistic.base_km) error.base_km = ["起步公里数不得为空"];
+                    if (JSON.stringify(error) !== "{}"){
+                        this.errors = error;
+                        this.$forceUpdate();
+                        return;
+                    }
+                    this.selectedModel.directLogistic = this.model.directLogistic;
+                    this.model.directLogistic = {
+                        items:[],
+                    };
+                    this.errors = [];
+                    this.importError = [];
+                },
                 //增加作业费特征子项
                 addOperationItem(){
                     this.model.operation.items.push({
@@ -355,45 +604,300 @@
                     this.$delete(this.model.operation.items,index);
                 },
                 //显示特征选择modal
-                showAddFeatureModal(index,feature){
-                    if (!feature){
-                        this.model.operation.items[index].features = [{
-                            "strategyGroupStartSign": false,
-                            "calculation" : "",
-                            "type" : "",
-                            "id" : "",
-                            "logic" : "",
-                            "describe" : "",
-                            "strategyGroupEndSign" : false,
-                        }];
+                showAddFeatureModal(index){
+                    if (index === -1){
+                        if (!this.model.operation.feature){
+                            this.model.operation.features = this._createFeature();
+                            this.thisOperationItemIndex = index;
+                            this.$forceUpdate();
+                            $("#addFeatureModal").modal("show");
+                            return;
+                        }
+                        if (this.model.operation.features) {
+                            this.thisOperationItemIndex = index;
+                            $("#addFeatureModal").modal("show");
+                            return;
+                        }
+                    }else{
+                        if (!this.model.operation.items[index].feature){
+                            this.model.operation.items[index].features = this._createFeature();
+                            this.thisOperationItemIndex = index;
+                            $("#addFeatureModal").modal("show");
+                            return;
+                        }
+                        if (this.model.operation.items[index].features) {
+                            this.thisOperationItemIndex = index;
+                            $("#addFeatureModal").modal("show");
+                            return;
+                        }
+                    }
+                    let url = "{{url('maintenance/priceModel/operation/getFeatures')}}";
+                    let feature = index===-1 ? this.model.operation.feature : this.model.operation.items[index].feature;
+                    window.tempTip.postBasicRequest(url,{feature:feature},res=>{
+                        if (!res.data.data || res.data.data.length === 0){
+                            res.data.data = this._createFeature();
+                        }
+                        if (index === -1) this.model.operation.features = res.data.data;
+                        else this.model.operation.items[index].features = res.data.data;
                         this.thisOperationItemIndex = index;
                         $("#addFeatureModal").modal("show");
+                    });
+                },
+                //增加特征
+                addFeature(){
+                    let obj = {
+                        "strategyGroupStartSign": false,
+                        "calculation" : "",
+                        "type" : "",
+                        "id" : "",
+                        "logic" : "",
+                        "describe" : "",
+                        "strategyGroupEndSign" : false,
+                    };
+                    if (this.thisOperationItemIndex === -1)this.model.operation.features.push(obj);
+                    else this.model.operation.items[this.thisOperationItemIndex].features.push(obj);
+                    this.$forceUpdate();
+                },
+                _createFeature(){
+                    return [{
+                        "strategyGroupStartSign": false,
+                        "calculation" : "",
+                        "type" : "",
+                        "id" : "",
+                        "logic" : "",
+                        "describe" : "",
+                        "strategyGroupEndSign" : false,
+                    }];
+                },
+                //删除特征
+                delFeature(index) {
+                    if (this.thisOperationItemIndex === -1)this.$delete(this.model.operation.features,index);
+                    else this.$delete(this.model.operation.items[this.thisOperationItemIndex].features,index);
+                    this.$forceUpdate();
+                },
+                //提交特征更新现有
+                submitFeature(){
+                    let url = "{{url('maintenance/priceModel/operation/getFeature')}}";
+                    let features = this.thisOperationItemIndex === -1 ? this.model.operation.features : this.model.operation.items[this.thisOperationItemIndex].features;
+                    window.tempTip.postBasicRequest(url,{features:features,isFormat:true},res=>{
+                        if (this.thisOperationItemIndex === -1){
+                            this.model.operation.feature = res.feature;
+                            this.model.operation.featureFormat = res.featureFormat;
+                        } else {
+                            this.model.operation.items[this.thisOperationItemIndex].feature = res.feature;
+                            this.model.operation.items[this.thisOperationItemIndex].featureFormat = res.featureFormat;
+                            this.$forceUpdate();
+                        }
+                        $("#addFeatureModal").modal("hide");
+                        return "已更新特征";
+                    },true);
+                },
+                /*//渲染作业费子项
+                _renderingOperationItem(index){
+                    let domId = "operation-"+index;
+                    let trId = "operation-tr-"+index;
+                    let itemId = "operation-item-"+index;
+                    let html = "<tr class='d-none' id='"+trId+"'><td></td><td colspan='5'>"+
+                        "<div id='"+itemId+"'><table class='table table-sm'>"+
+                        "<th>子策略</th><th>数量</th><th>单位</th><th>单价</th><th>特征</th></th>";
+                    this.selectedModel.operation[index].items.forEach(item=> {
+                        html = this._createOperationItemList(html,item.strategy,item.amount,this.poolMapping.units[item.unit_id],item.unit_price,item.featureFormat ? item.featureFormat : '');
+                    });
+                    html += "</table></div></td></tr>";
+                    $("#"+domId).after(html);
+                    $("#"+itemId).slideUp();
+                },
+                _createOperationItemList(html,strategy,amount,unit,unit_price,feature){
+                    html += "<tr><td>"+strategy+"</td><td>"+amount+"</td><td>"+unit+"</td><td>"+unit_price+"</td><td><div class='text-overflow-warp-100'>"+feature+"</div></td></tr>";
+                    return html;
+                },*/
+                //移入移出时更改长文本显示效果
+                textClass(event,isOver){
+                    event = event.target.children[0];
+                    if (isOver) event.className = "text-overflow-warp-100";
+                    else event.className = "cursor-pointer text-overflow-replace-100";
+                },
+                //展开子策略
+                showOperationItem(index){
+                    let trId = "operation-tr-"+index;
+                    let itemId = "operation-item-"+index;
+                    if (this.operationItems['_'+index] &&  this.operationItems['_'+index]===true){
+                        this.operationItems['_'+index] = false;
+                        $("#"+itemId).slideUp(undefined,function () {
+                            $("#"+trId).addClass("d-none");
+                        });
+                    }else {
+                        $("#"+trId).removeClass("d-none");
+                        this.operationItems['_'+index] = true;
+                        $("#"+itemId).slideDown();
+                    }
+                    this.$forceUpdate();
+                },
+                //新增快递子项
+                addExpressItem(){
+                    this.model.express.items.unshift({
+                        province_id : "",
+                        initial_weight_price:"",
+                        additional_weight_price:"",
+                    });
+                },
+                //删除快递子项
+                delExpressItem(index){
+                    this.$delete(this.model.express.items,index);
+                },
+                //选择文件
+                selectFile(id){
+                    this.importError = [];
+                    $("#"+id).click();
+                },
+                //导入快递子项
+                importExpress(e){
+                    let file=e.target.files[0];
+                    if (!file){
+                        tempTip.setDuration(3000);
+                        tempTip.show("未选择文件");
                         return;
                     }
-                    if (this.oldFeature === feature) {
-                        this.thisOperationItemIndex = index;
-                        $("#addFeatureModal").modal("show");
+                    let formData = new FormData();
+                    formData.append("file",file);
+                    axios.post('{{url('maintenance/priceModel/express/import')}}',formData,{
+                        'Content-Type':'multipart/form-data'
+                    }).then(res=>{
+                            if (res.data.success) {
+                                res.data.data.forEach(data=>{
+                                    let unique = this.model.express.items.every(item=>{
+                                        if (data.province_id === item.province_id)return false;
+                                        return true;
+                                    });
+                                    if (unique)this.model.express.items.push(data);
+                                });
+                                this.importError = res.data.errors;
+                                tempTip.setDuration(3000);
+                                tempTip.showSuccess("导入成功!");
+                                return;
+                            }
+                            tempTip.setDuration(3000);
+                            tempTip.show(res.data.data);
+                        }).catch(err=> {
+                        tempTip.setDuration(3000);
+                        tempTip.show("网络错误:"+err);
+                    })
+                },
+                //物流详情列表modal
+                showDetailModal() {
+                    $("#logisticModal").modal("show");
+                },
+                //新增物流详情
+                addLogisticDetail(){
+                    this.model.logistic.items.unshift({
+
+                    });
+                },
+                //导入物流详情
+                importLogistic(e){
+                    tempTip.setIndex(1099);
+                    let file=e.target.files[0];
+                    if (!file){
+                        tempTip.setDuration(3000);
+                        tempTip.show("未选择文件");
                         return;
                     }
-                    let url = "{{url('maintenance/priceModel/operation/getFeatures')}}";
-                    window.tempTip.postBasicRequest(url,{feature:feature},res=>{
-                        this.features = res.data.data;
-                        this.oldFeature = feature;
-                        if (!this.features || this.features.length === 0){
-                            this.features = [{
-                                "strategyGroupStartSign": false,
-                                "calculation" : "",
-                                "type" : "",
-                                "id" : "",  //特征ID
-                                "logic" : "",  //特征逻辑
-                                "describe" : "",  //特征信息
-                                "strategyGroupEndSign" : false,
-                            }];
+                    let formData = new FormData();
+                    formData.append("file",file);
+                    axios.post('{{url('maintenance/priceModel/logistic/import')}}',formData,{
+                        'Content-Type':'multipart/form-data'
+                    }).then(res=>{
+                        if (res.data.success) {
+                            res.data.data.forEach(data=>{
+                                //过滤非已选择单位的数据
+                                let id = "";
+                                if (data.unit_id === this.poolMapping.units[this.model.logistic.unit_id]) id = this.model.logistic.unit_id;
+                                if (data.unit_id === this.poolMapping.units[this.model.logistic.other_unit_id]) id = this.model.logistic.other_unit_id;
+                                if (id){
+                                    //过滤重复数据
+                                    let unique = this.model.logistic.items.every(item=>{
+                                        if (id === item.unit_id && data.range === item.range
+                                        && data.province_id === item.province_id && data.city_id === item.city_id)return false;
+                                        return true;
+                                    });
+                                    if (unique){
+                                        data.unit_id = id;
+                                        this.model.logistic.items.push(data);
+                                    }
+                                }
+                            });
+                            this.importError = res.data.errors;
+                            tempTip.setDuration(3000);
+                            tempTip.showSuccess("导入成功!");
+                            return;
                         }
-                        this.thisOperationItemIndex = index;
-                        $("#addFeatureModal").modal("show");
+                        tempTip.setDuration(3000);
+                        tempTip.show(res.data.data);
+                    }).catch(err=> {
+                        tempTip.setDuration(3000);
+                        tempTip.show("网络错误:"+err);
+                    })
+                },
+                //删除物流子项
+                delLogisticItem(index){
+                    this.$delete(this.model.logistic.items,index);
+                },
+                //改变物流区间时改变可选择项
+                changeRange(type){
+                    if (type === 'ranges'){
+                        this.model.logistic.ranges = this.model.logistic.unit_range.split(",");
+                    }else{
+                        this.model.logistic.other_ranges = this.model.logistic.other_unit_range.split(",");
+                    }
+                },
+                //增加直发车子项
+                addDirectLogisticItem(){
+                    this.model.directLogistic.items.unshift({
+                        car_type_id : "",
+                        base_fee:"",
+                        additional_fee:"",
                     });
                 },
+                //导入直发车子项
+                importDirectLogistic(e){
+                    tempTip.setIndex(1099);
+                    let file=e.target.files[0];
+                    if (!file){
+                        tempTip.setDuration(3000);
+                        tempTip.show("未选择文件");
+                        return;
+                    }
+                    let formData = new FormData();
+                    formData.append("file",file);
+                    axios.post('{{url('maintenance/priceModel/directLogistic/import')}}',formData,{
+                        'Content-Type':'multipart/form-data'
+                    }).then(res=>{
+                        if (res.data.success) {
+                            if (this.model.directLogistic.items.length > 0){
+                                res.data.data.forEach(data=>{
+                                    let unique = this.model.directLogistic.items.every(item=>{
+                                        if (item.car_type_id === data.car_type_id)return false;
+                                        return true;
+                                    });
+                                    if (unique) this.model.directLogistic.items.unshift(data);
+                                });
+                            }else this.model.directLogistic.items = res.data.data;
+                            this.importError = res.data.errors;
+                            tempTip.setDuration(3000);
+                            tempTip.showSuccess("导入成功!");
+                            return;
+                        }
+                        tempTip.setDuration(3000);
+                        tempTip.show(res.data.data);
+                    }).catch(err=> {
+                        tempTip.setDuration(3000);
+                        tempTip.show("网络错误:"+err);
+                    })
+                },
+                //删除直发车子项
+                delDirectLogisticItem(index){
+                    this.$delete(this.model.directLogistic.items,index);
+                },
             },
         });
     </script>

+ 8 - 5
resources/views/customer/project/_addFeature.blade.php → resources/views/customer/project/part/_addFeature.blade.php

@@ -11,9 +11,11 @@
                         <label class="col-4">特征内容</label>
                         <label class="col-1"></label>
                     </div>
-                    <div class="row" v-for="(feature,i) in features">
+                    <div class="row" v-for="(feature,i) in (thisOperationItemIndex===-1 ? model.operation.features : (model.operation.items[thisOperationItemIndex] ? model.operation.items[thisOperationItemIndex].features : []))">
                         <div class="col-1">
-                            <span class="fa fa-minus-square pull-right mt-1" v-if="features.length > 1" style="cursor: pointer" @click="delFeature(i)"></span>
+                            <span class="fa fa-minus-square pull-right mt-1"
+                                  v-if="(thisOperationItemIndex===-1 ? model.operation.features : (model.operation.items[thisOperationItemIndex] ? model.operation.items[thisOperationItemIndex].features : [])).length > 1"
+                                  style="cursor: pointer" @click="delFeature(i)"></span>
                         </div>
                         <label class="col-2">
                             <select class="form-control form-control-sm" v-if="i != 0" v-model="feature.calculation">
@@ -23,19 +25,20 @@
                         </label>
                         <label class="col-2">
                             <select class="form-control form-control-sm" v-model="feature.type">
-                                <option v-for="t in type" :value="t" v-if="(thisIndex == '-1' && t != '商品名称') || (thisIndex != '-1' && t=='商品名称')">@{{ t }}</option>
+                                <option v-for="t in pool.feature_type" :value="t">@{{ t }}</option>
                             </select>
                         </label>
                         <label class="col-2">
                             <select class="form-control form-control-sm" v-model="feature.logic">
-                                <option v-for="l in logic" :value="l" v-if="thisIndex == '-1' || l != '不包含'">@{{ l }}</option>
+                                <option v-for="l in pool.logic" :value="l">@{{ l }}</option>
                             </select>
                         </label>
                         <label class="col-4">
                             <input class="form-control form-control-sm" v-model="feature.describe">
                         </label>
                         <div class="col-1">
-                            <span v-if="i == (features.length-1)" class="fa fa-plus-square pull-right mt-1" style="cursor: pointer" @click="addFeature()"></span>
+                            <span v-if="i == ((thisOperationItemIndex===-1 ? model.operation.features : (model.operation.items[thisOperationItemIndex] ? model.operation.items[thisOperationItemIndex].features : [])).length-1)"
+                                  class="fa fa-plus-square pull-right mt-1" style="cursor: pointer" @click="addFeature()"></span>
                         </div>
                     </div>
                 </div>

+ 58 - 0
resources/views/customer/project/part/_directLogistic.blade.php

@@ -0,0 +1,58 @@
+<div class="row">
+    <label class="col-3"><b class="text-danger">* </b>价格名称</label>
+    <label class="col-6"><input v-model="model.directLogistic.name" type="text" class="form-control form-control-sm"
+           :class="errors.name ? 'is-invalid' : ''"></label>
+    <span class="small text-danger mt-0 offset-3 ml-1" role="alert" v-if="errors.name">
+        <strong>@{{ errors.name[0] }}</strong>
+    </span>
+</div>
+<div class="row mt-3">
+    <label class="col-3"><b class="text-danger">* </b>起步公里数</label>
+    <label class="col-6"><input v-model="model.directLogistic.base_km" type="number" min="0" step="0.01" class="form-control form-control-sm"
+           :class="errors.base_km ? 'is-invalid' : ''"></label>
+    <span class="small text-danger mt-0 offset-3 ml-1" role="alert" v-if="errors.base_km">
+        <strong>@{{ errors.base_km[0] }}</strong>
+    </span>
+</div>
+<div class="row mt-3">
+    <label class="col-3">详情</label>
+    <div class="col-9">
+        <div class="w-100 form-inline">
+            <input id="directLogisticFile" type="file" class="d-none" accept=".csv, .xlsx, .xls" @change="importDirectLogistic($event)"/>
+            <button type="button" class="btn btn-sm btn-outline-info w-25" @click="addDirectLogisticItem()">新增</button>
+            <button type="button" class="btn btn-sm btn-outline-primary w-25 ml-2" @click="selectFile('directLogisticFile')">导入</button>
+            <h5><span class="ml-0 fa fa-question-circle-o cursor-pointer" data-toggle="tooltip" data-placement="top" title="导入与保存时自动过滤重复数据"></span></h5>
+        </div>
+        <div class="w-100 text-center mb-1 mt-1" v-if="importError.length > 0">
+            <button type="button" class="btn btn-sm btn-danger mb-1" @click="isShowError = true" v-if="!isShowError">@{{ importError.length }}条错误,点击展开</button>
+            <button type="button" class="btn btn-sm btn-dark mb-1" @click="isShowError = false" v-else>收起错误展示</button>
+            <div v-if="isShowError" class="container-fluid text-danger font-weight-bolder">
+                <div class="row text-left">
+                    <div class="col-6" v-for="error in importError">@{{ error }}</div>
+                </div>
+            </div>
+        </div>
+        <div class="row font-weight-bold" v-if="model.directLogistic.items.length>0">
+            <label class="col-3">车型</label>
+            <label class="col-3">起步费</label>
+            <label class="col-4">续费(元/KM)</label>
+            <label class="col-2"></label>
+        </div>
+        <div class="row" v-for="(item,i) in model.directLogistic.items">
+            <label class="col-3">
+                <select class="form-control form-control-sm" v-model="item.car_type_id" :class="errors['item.'+i+'.car_type_id'] ? 'is-invalid' : ''">
+                    <option v-for="car in pool.cars" :value="car.id">@{{ car.name }}</option>
+                </select>
+            </label>
+            <label class="col-3">
+                <input type="number" step="0.01" class="form-control form-control-sm" v-model="item.base_fee" :class="errors['item.'+i+'.base_fee'] ? 'is-invalid' : ''">
+            </label>
+            <label class="col-4">
+                <input type="number" step="0.01" class="form-control form-control-sm" v-model="item.additional_fee" :class="errors['item.'+i+'.additional_fee'] ? 'is-invalid' : ''">
+            </label>
+            <label class="col-2 cursor-pointer h3 font-weight-bold text-danger" @click="delDirectLogisticItem(i)">
+                &times;
+            </label>
+        </div>
+    </div>
+</div>

+ 64 - 0
resources/views/customer/project/part/_express.blade.php

@@ -0,0 +1,64 @@
+<div class="row">
+    <label class="col-3"><b class="text-danger">* </b>价格名称</label>
+    <label class="col-7"><input type="text" class="form-control"
+           v-model="model.express.name" :class="errors.name ? 'is-invalid' : ''"></label>
+</div>
+<div class="row mt-3">
+    <label class="col-3">承运商</label>
+    <label class="col-5"><select class="selectpicker express" multiple data-live-search="true" title="承运商(多选)"
+            v-model="model.express.logistics" :class="errors.logistics ? 'is-invalid' : ''">
+        <option v-for="logistic in pool.logistics" :value="logistic.id" v-if="logistic.type != '物流'">@{{ logistic.name }}</option>
+    </select></label>
+</div>
+<div class="row mt-3">
+    <label class="col-3"><b class="text-danger">* </b>首重值(KG)</label>
+    <label class="col-7"><input type="number" min="0" step="0.01" class="form-control"
+           v-model="model.express.initial_weight" :class="errors.initial_weight ? 'is-invalid' : ''"></label>
+</div>
+<div class="row mt-3">
+    <label class="col-3"><b class="text-danger">* </b>续重值(KG)</label>
+    <label class="col-7"><input type="number" min="0" step="0.01" class="form-control"
+           v-model="model.express.additional_weight" :class="errors.additional_weight ? 'is-invalid' : ''"></label>
+</div>
+<div class="row mt-3">
+    <label class="col-3">详情</label>
+    <div class="col-9">
+        <div class="w-100 form-inline">
+            <input id="expressFile" type="file" class="d-none" accept=".csv, .xlsx, .xls" @change="importExpress($event)"/>
+            <button type="button" class="btn btn-sm btn-outline-info w-25" @click="addExpressItem()">新增</button>
+            <button type="button" class="btn btn-sm btn-outline-primary w-25 ml-2" @click="selectFile('expressFile')">导入</button>
+            <h5><span class="ml-0 fa fa-question-circle-o cursor-pointer" data-toggle="tooltip" data-placement="top" title="导入与保存时自动过滤重复数据"></span></h5>
+        </div>
+        <div class="w-100 text-center mb-1 mt-1" v-if="importError.length > 0">
+            <button type="button" class="btn btn-sm btn-danger mb-1" @click="isShowError = true" v-if="!isShowError">@{{ importError.length }}条错误,点击展开</button>
+            <button type="button" class="btn btn-sm btn-dark mb-1" @click="isShowError = false" v-else>收起错误展示</button>
+            <div v-if="isShowError" class="container-fluid text-danger font-weight-bolder">
+                <div class="row text-left">
+                    <div class="col-6" v-for="error in importError">@{{ error }}</div>
+                </div>
+            </div>
+        </div>
+        <div class="row font-weight-bold" v-if="model.express.items.length>0">
+            <label class="col-3">省</label>
+            <label class="col-3">首重价格</label>
+            <label class="col-3">续重价格</label>
+            <label class="col-3"></label>
+        </div>
+        <div class="row" v-for="(item,i) in model.express.items">
+            <label class="col-3">
+                <select class="form-control form-control-sm" v-model="item.province_id" :class="errors['item.'+i+'.province_id'] ? 'is-invalid' : ''">
+                    <option v-for="province in pool.provinces" :value="province.id">@{{ province.name }}</option>
+                </select>
+            </label>
+            <label class="col-3">
+                <input type="number" step="0.01" class="form-control form-control-sm" v-model="item.initial_weight_price" :class="errors['item.'+i+'.initial_weight_price'] ? 'is-invalid' : ''">
+            </label>
+            <label class="col-3">
+                <input type="number" step="0.01" class="form-control form-control-sm" v-model="item.additional_weight_price" :class="errors['item.'+i+'.additional_weight_price'] ? 'is-invalid' : ''">
+            </label>
+            <label class="col-3 cursor-pointer h3 font-weight-bold text-danger" @click="delExpressItem(i)">
+                &times;
+            </label>
+        </div>
+    </div>
+</div>

+ 75 - 0
resources/views/customer/project/part/_logistic.blade.php

@@ -0,0 +1,75 @@
+<div class="row">
+    <label for="logistic_name" class="col-2"><b class="text-danger">* </b>价格名称</label>
+    <input id="logistic_name" type="text" class="col-6 form-control"
+           :class="errors.name ? 'is-invalid' : ''" v-model="model.logistic.name">
+    <span class="invalid-feedback mt-0 offset-2" role="alert" v-if="errors.name">
+        <strong>@{{ errors.name[0] }}</strong>
+    </span>
+</div>
+<div class="row mt-3">
+    <label class="col-2" for="logistic_id">承运商</label>
+    <select id="logistic_id" class="selectpicker logistic" multiple data-live-search="true" title="承运商(多选)"
+            v-model="model.logistic.logistics" :class="errors.logistics ? 'is-invalid' : ''">
+        <option v-for="logistic in pool.logistics" :value="logistic.id" v-if="logistic.type != '快递'">@{{ logistic.name }}</option>
+    </select>
+</div>
+<div class="row mt-3">
+    <label for="logistic_pick_up_price" class="col-2">提货费</label>
+    <input id="logistic_pick_up_price" type="number" min="0" step="0.01" class="col-3 form-control"
+           :class="errors.pick_up_price ? 'is-invalid' : ''" v-model="model.logistic.pick_up_price">
+    <span class="invalid-feedback mt-0 offset-2" role="alert" v-if="errors.pick_up_price">
+        <strong>@{{ errors.pick_up_price[0] }}</strong>
+    </span>
+</div>
+<div class="row mt-3">
+    <label for="logistic_fuel_price" class="col-2">燃油附加费</label>
+    <input id="logistic_fuel_price" type="number" min="0" step="0.01" class="col-3 form-control"
+           :class="errors.fuel_price ? 'is-invalid' : ''" v-model="model.logistic.fuel_price">
+    <span class="invalid-feedback mt-0 offset-2" role="alert" v-if="errors.fuel_price">
+        <strong>@{{ errors.fuel_price[0] }}</strong>
+    </span>
+</div>
+<div class="row mt-3">
+    <label for="logistic_service_price" class="col-2">信息服务费</label>
+    <input id="logistic_service_price" type="number" min="0" step="0.01" class="col-3 form-control"
+           :class="errors.service_price ? 'is-invalid' : ''" v-model="model.logistic.service_price">
+    <span class="invalid-feedback mt-0 offset-2" role="alert" v-if="errors.service_price">
+        <strong>@{{ errors.service_price[0] }}</strong>
+    </span>
+</div>
+<div class="row mt-3 mb-0">
+    <label for="logistic_unit_id" class="col-2"><b class="text-danger">* </b>单位一</label>
+    <select id="logistic_unit_id" class="col-2 form-control"
+            v-model="model.logistic.unit_id" :class="errors.unit_id ? 'is-invalid' : ''">
+        <option v-for="unit in pool.units" :value="unit.id">@{{ unit.name }}</option>
+    </select>
+    <label for="logistic_unit_range" class="col-2 text-right"><b class="text-danger">*</b>区间值</label>
+    <input id="logistic_unit_range" type="text" placeholder="文字描述区间逗号(,)间隔,示例:0-5,10-30,30-"
+           v-model="model.logistic.unit_range" class="col-3 form-control" :class="errors.unit_range ? 'is-invalid' : ''" @change="changeRange('ranges')">
+</div>
+<div class="row mt-0">
+    <label class="offset-2 mt-0 col-3 small text-danger" v-if="errors.unit_id">@{{ errors.unit_id[0] }}</label>
+    <label class="offset-1 mt-0 col-5 small text-danger" v-if="errors.unit_range">@{{ errors.unit_range[0] }}</label>
+</div>
+<div class="row mt-3 mb-0">
+    <label for="logistic_other_unit_id" class="col-2"><b class="text-danger">* </b>单位二</label>
+    <select id="logistic_other_unit_id" class="col-2 form-control"
+            v-model="model.logistic.other_unit_id" :class="errors.other_unit_id ? 'is-invalid' : ''">
+        <option v-for="unit in pool.units" :value="unit.id">@{{ unit.name }}</option>
+    </select>
+    <label for="logistic_other_unit_range" class="col-2 text-right"><b class="text-danger">*</b>区间值</label>
+    <input id="logistic_other_unit_range" type="text" placeholder="文字描述区间逗号(,)间隔,示例:0-5,10-30,30-"
+           v-model="model.logistic.other_unit_range" class="col-3 form-control" :class="errors.other_unit_range ? 'is-invalid' : ''" @change="changeRange('other_ranges')">
+</div>
+<div class="row mt-0">
+    <label class="offset-2 mt-0 col-3 small text-danger" v-if="errors.other_unit_id">@{{ errors.other_unit_id[0] }}</label>
+    <label class="offset-1 mt-0 col-5 small text-danger" v-if="errors.other_unit_range">@{{ errors.other_unit_range[0] }}</label>
+</div>
+<div class="row mt-3">
+    <label class="col-2">详情</label>
+    <div class="col-10">
+        <div class="row">
+            <button type="button" class="btn btn-sm btn-outline-info col-4" @click="showDetailModal()">详情列表</button>
+        </div>
+    </div>
+</div>

+ 91 - 0
resources/views/customer/project/part/_logisticDetail.blade.php

@@ -0,0 +1,91 @@
+<div class="modal fade" tabindex="-1" role="dialog" id="logisticModal">
+    <div class="modal-dialog modal-xl modal-dialog-centered modal-dialog-scrollable">
+        <div class="modal-content">
+            <div class="modal-header">
+                <div class="row w-100">
+                    <button type="button" class="btn btn-sm btn-outline-dark col-1" @click="addLogisticDetail()">新增</button>
+                    <input id="logisticFile" type="file" style="display:none" accept=".csv, .xlsx, .xls" @change="importLogistic($event)"/>
+                    <button type="button" class="btn btn-sm btn-outline-info col-1" @click="selectFile('logisticFile')">导入</button>
+                    <h5><span class="ml-0 fa fa-question-circle-o cursor-pointer" data-toggle="tooltip" data-placement="top" title="导入与保存时自动过滤重复数据和与当前选择单位不一致数据"></span></h5>
+                    <div class="font-weight-bolder offset-3">物流收费标准</div>
+                </div>
+            </div>
+            <div class="modal-body">
+                <div class="w-100 text-center mb-1" v-if="importError.length > 0">
+                    <button type="button" class="btn btn-sm btn-danger mb-1" @click="isShowError = true" v-if="!isShowError">@{{ importError.length }}条错误,点击展开</button>
+                    <button type="button" class="btn btn-sm btn-dark mb-1" @click="isShowError = false" v-else>收起错误展示</button>
+                    <div v-if="isShowError" class="container-fluid text-danger font-weight-bolder">
+                        <div class="row text-left">
+                            <div class="col-6" v-for="err in importError">@{{ err }}</div>
+                        </div>
+                    </div>
+                </div>
+                <div class="w-100 text-primary text-center mt-0" v-else>
+                    <div class="small"><b class="text-dark font-weight-bold">导入表头示例:</b>计数单位,计数区间,省份,市,单价,送货费,起始计费,起始计数,费率</div>
+                </div>
+                <table class="table table-sm table-bordered">
+                    <tr class="text-success">
+                        <th>计价单位</th>
+                        <th>计价区间</th>
+                        <th style="min-width: 100px">省份</th>
+                        <th style="min-width: 100px">市</th>
+                        <th>单价</th>
+                        <th>送货费</th>
+                        <th>起始计费</th>
+                        <th>起始计数</th>
+                        <th>费率(%)</th>
+                        <th>操作</th>
+                    </tr>
+                    <tr v-for="(detail,i) in model.logistic.items">
+                        <td>
+                            <label>
+                                <select class="form-control form-control-sm col-6" style="min-width: 80px" v-model="detail.unit_id">
+                                    <option v-for="unit in pool.units" :value="unit.id" v-if="unit.id == model.logistic.unit_id || unit.id == model.logistic.other_unit_id">@{{ unit.name }}</option>
+                                </select>
+                            </label>
+                        </td>
+                        <td>
+                            <label>
+                                <select class="form-control form-control-sm col-6" style="min-width: 80px" v-model="detail.range">
+                                    <option v-for="range in (detail.unit_id == model.logistic.unit_id ? model.logistic.ranges : model.logistic.other_ranges)" :value="range">@{{ range }}</option>
+                                </select>
+                            </label>
+                        </td>
+                        <td>
+                            <label>
+                                <select class="form-control form-control-sm" v-model="detail.province_id">
+                                    <option v-for="province in pool.provinces" :value="province.id">@{{ province.name }}</option>
+                                </select>
+                            </label>
+                        </td>
+                        <td>
+                            <label>
+                                <select class="form-control form-control-sm" v-model="detail.city_id">
+                                    <option v-for="city in pool.cities" v-if="detail.province_id === city.province_id" :value="city.id">@{{ city.name }}</option>
+                                </select>
+                            </label>
+                        </td>
+                        <td>
+                            <label><input type="number" min="0" step="0.001" class="form-control form-control-sm" v-model="detail.unit_price" :data="detail.unit_price"></label>
+                        </td>
+                        <td>
+                            <label><input type="number" min="0" step="0.001" class="form-control form-control-sm" v-model="detail.delivery_fee" :data="detail.delivery_fee"></label>
+                        </td>
+                        <td>
+                            <label><input type="number" min="0" step="0.001" class="form-control form-control-sm" v-model="detail.initial_fee" :data="detail.initial_fee"></label>
+                        </td>
+                        <td>
+                            <label><input type="number" min="0" class="form-control form-control-sm" v-model="detail.initial_amount" :data="detail.initial_amount"></label>
+                        </td>
+                        <td>
+                            <label><input type="number" min="0" step="0.001" class="form-control form-control-sm" v-model="detail.rate" :data="detail.rate"></label>
+                        </td>
+                        <td>
+                            <button type="button" class="btn btn-sm btn-outline-danger" @click="delLogisticItem(i)">删</button>
+                        </td>
+                    </tr>
+                </table>
+            </div>
+        </div>
+    </div>
+</div>

+ 0 - 0
resources/views/customer/project/_one.blade.php → resources/views/customer/project/part/_one.blade.php


+ 55 - 54
resources/views/customer/project/_operation.blade.php → resources/views/customer/project/part/_operation.blade.php

@@ -27,7 +27,7 @@
 </div>
 <div class="row mt-3">
     <label class="col-2">特征:</label>
-    <label v-if="model.operation.feature">@{{ model.operation.feature }}</label>
+    <label v-if="model.operation.feature">@{{ model.operation.featureFormat }}</label><br>
     <button type="button" class="btn btn-dark col-2 ml-2" @click="showAddFeatureModal(-1,model.operation.feature)">调整特征</button>
 </div>
 <div class="row mt-3">
@@ -37,33 +37,33 @@
             <div class="row">
                 <label class="col-3">子策略:</label>
                 <label class="col-5"><select disabled v-model="model.operation.items[0].strategy" class="form-control">
-                        <option>起步</option>
-                    </select></label>
+                    <option>起步</option>
+                </select></label>
             </div>
             <div class="row mt-2">
                 <label class="col-3">起步数</label>
-                <label class="col-5"><input id="amount" type="number" :class="errors['items.0.amount'] ? 'is-invalid' : ''"
+                <label class="col-5 mb-0"><input id="amount" type="number" :class="errors['items.0.amount'] ? 'is-invalid' : ''"
                        v-model="model.operation.items[0].amount" class="form-control" step="1"></label>
-                <span class="invalid-feedback mt-0 offset-2" role="alert" v-if="errors['items.0.amount']">
-                    <strong>@{{ errors['items.0.amount'][0] }}</strong>
-                </span>
+            </div>
+            <div class="row mt-0" v-if="errors['items.0.amount']">
+                <div class="offset-3"><small class="text-danger font-weight-bold ml-3">@{{ errors['items.0.amount'][0] }}</small></div>
             </div>
             <div class="row mt-2">
                 <label class="col-3">单位</label>
-                <label class="col-5"><select v-model="model.operation.items[0].unit_id" class="form-control" :class="errors['items.0.unit_id'] ? 'is-invalid' : ''">
+                <label class="col-5 mb-0"><select v-model="model.operation.items[0].unit_id" class="form-control" :class="errors['items.0.unit_id'] ? 'is-invalid' : ''">
                         <option v-for="unit in pool.units" :value="unit.id">@{{ unit.name }}</option>
                 </select></label>
-                <span class="invalid-feedback mt-0 offset-2" role="alert" v-if="errors['items.0.unit_id']">
-                    <strong>@{{ errors['items.0.unit_id'][0] }}</strong>
-                </span>
+            </div>
+            <div class="row mt-0" v-if="errors['items.0.unit_id']">
+                <div class="offset-3"><small class="text-danger font-weight-bold ml-3">@{{ errors['items.0.unit_id'][0] }}</small></div>
             </div>
             <div class="row mt-2">
                 <label class="col-3">单价</label>
-                <label class="col-5"><input type="number" min="0" step="0.001" class="form-control" v-model="model.operation.items[0].unit_price"
+                <label class="col-5 mb-0"><input type="number" min="0" step="0.001" class="form-control" v-model="model.operation.items[0].unit_price"
                            :class="errors['items.0.unit_price'] ? 'is-invalid' : ''"></label>
-                <span class="invalid-feedback mt-0 offset-2" role="alert" v-if="errors['items.0.unit_price']">
-                    <strong>@{{ errors['items.0.unit_price'][0] }}</strong>
-                </span>
+            </div>
+            <div class="row mt-0" v-if="errors['items.0.unit_price']">
+                <div class="offset-3"><small class="text-danger font-weight-bold ml-3">@{{ errors['items.0.unit_price'][0] }}</small></div>
             </div>
         </div>
     </div>
@@ -75,36 +75,37 @@
         </div>
         <div class="card-body">
             <div class="row">
+                <label class="col-3">子策略:</label>
+                <label class="col-5"><select disabled v-model="model.operation.items[1].strategy" class=" form-control">
+                    <option>默认</option>
+                </select></label>
+            </div>
+            <div class="row mt-2">
                 <label class="col-3">数量</label>
-                <label class="col-5"><input id="amount" type="number" :class="errors['items.1.amount'] ? 'is-invalid' : ''"
-                                            v-model="model.operation.items[1].amount" class="form-control" step="1">
+                <label class="col-5 mb-0"><input id="amount" type="number" :class="errors['items.1.amount'] ? 'is-invalid' : ''"
+                       v-model="model.operation.items[1].amount" class="form-control" step="1">
                 </label>
-                <span class="invalid-feedback mt-0 offset-2" role="alert" v-if="errors['items.1.amount']">
-                    <strong>@{{ errors['items.1.amount'][0] }}</strong>
-                </span>
+                <div class="col-4"></div>
+            </div>
+            <div class="row mt-0" v-if="errors['items.1.amount']">
+                <div class="offset-3"><small class="text-danger font-weight-bold ml-3">@{{ errors['items.1.amount'][0] }}</small></div>
             </div>
             <div class="row mt-2">
                 <label class="col-3">单位</label>
-                <label class="col-5"><select v-model="model.operation.items[1].unit_id" class="form-control" :class="errors['items.1.unit_id'] ? 'is-invalid' : ''">
-                        <option v-for="unit in pool.units" :value="unit.id">@{{ unit.name }}</option>
-                    </select></label>
-                <span class="invalid-feedback mt-0 offset-2" role="alert" v-if="errors['items.1.unit_id']">
-                     <strong>@{{ errors['items.1.unit_id'][0] }}</strong>
-                </span>
+                <label class="col-5 mb-0"><select v-model="model.operation.items[1].unit_id" class="form-control" :class="errors['items.1.unit_id'] ? 'is-invalid' : ''">
+                    <option v-for="unit in pool.units" :value="unit.id">@{{ unit.name }}</option>
+                </select></label>
+            </div>
+            <div class="row mt-0" v-if="errors['items.1.unit_id']">
+                <div class="offset-3"><small class="text-danger font-weight-bold ml-3">@{{ errors['items.1.unit_id'][0] }}</small></div>
             </div>
             <div class="row mt-2">
                 <label class="col-3">单价</label>
-                <label class="col-5"><input type="number" min="0" step="0.001" class="form-control" v-model="model.operation.items[1].unit_price"
+                <label class="col-5 mb-0"><input type="number" min="0" step="0.001" class="form-control" v-model="model.operation.items[1].unit_price"
                            :class="errors['items.1.unit_price'] ? 'is-invalid' : ''"></label>
-                <span class="invalid-feedback mt-0 offset-2" role="alert" v-if="errors['items.1.unit_price']">
-                    <strong>@{{ errors['items.1.unit_price'][0] }}</strong>
-                </span>
             </div>
-            <div class="row mt-2">
-                <label class="col-3">子策略:</label>
-                <label class="col-5"><select disabled v-model="model.operation.items[1].strategy" class=" form-control">
-                    <option>默认</option>
-                </select></label>
+            <div class="row mt-0" v-if="errors['items.1.unit_price']">
+                <div class="offset-3"><small class="text-danger font-weight-bold ml-3">@{{ errors['items.1.unit_price'][0] }}</small></div>
             </div>
         </div>
     </div>
@@ -117,40 +118,40 @@
         </div>
         <div class="card-body">
             <div class="row">
+                <label class="col-3">子策略</label>
+                <label class="col-5"><select disabled v-model="item.strategy" class="form-control">
+                    <option>特征</option>
+                </select></label>
+            </div>
+            <div class="row mt-2">
                 <label class="col-3">数量</label>
-                <label class="col-5"><input type="number" step="1" :class="errors['items.'+i+'.amount'] ? 'is-invalid' : ''" v-model="item.amount" class="form-control"></label>
-                <span class="invalid-feedback mt-0 offset-2" role="alert" v-if="errors['items.'+i+'.amount']">
-                    <strong>@{{ errors['items.'+i+'.amount'][0] }}</strong>
-                </span>
+                <label class="col-5 mb-0"><input type="number" step="1" min="0" :class="errors['items.'+i+'.amount'] ? 'is-invalid' : ''" v-model="item.amount" class="form-control"></label>
+            </div>
+            <div class="row mt-0" v-if="errors['items.'+i+'.amount']">
+                <div class="offset-3"><small class="text-danger font-weight-bold ml-3">@{{ errors['items.'+i+'.amount'][0] }}</small></div>
             </div>
             <div class="row mt-2">
                 <label class="col-3">单位</label>
-                <label class="col-5"><select v-model="item.unit_id" class="form-control" :class="errors['items.'+i+'.unit_id'] ? 'is-invalid' : ''">
+                <label class="col-5 mb-0"><select v-model="item.unit_id" class="form-control" :class="errors['items.'+i+'.unit_id'] ? 'is-invalid' : ''">
                     <option v-for="unit in pool.units" :value="unit.id">@{{ unit.name }}</option>
                 </select></label>
-                <span class="invalid-feedback mt-0 offset-2" role="alert" v-if="errors['items.'+i+'.unit_id']">
-                    <strong>@{{ errors['items.'+i+'.unit_id'][0] }}</strong>
-                </span>
+            </div>
+            <div class="row mt-0" v-if="errors['items.'+i+'.unit_id']">
+                <div class="offset-3"><small class="text-danger font-weight-bold ml-3">@{{ errors['items.'+i+'.unit_id'][0] }}</small></div>
             </div>
             <div class="row mt-2">
                 <label class="col-3">单价</label>
-                <label class="col-5"><input type="number" min="0" step="0.001" class="form-control" v-model="item.unit_price"
+                <label class="col-5 mb-0"><input type="number" min="0" step="0.001" class="form-control" v-model="item.unit_price"
                        :class="errors['items.'+i+'.unit_price'] ? 'is-invalid' : ''"></label>
-                <span class="invalid-feedback mt-0 offset-2" role="alert" v-if="errors['items.'+i+'.unit_price']">
-                    <strong>@{{ errors['items.'+i+'.unit_price'][0] }}</strong>
-                </span>
             </div>
-            <div class="row mt-2">
-                <label class="col-3">子策略</label>
-                <label class="col-5"><select disabled v-model="item.strategy" class="form-control">
-                    <option>特征</option>
-                </select></label>
+            <div class="row mt-0" v-if="errors['items.'+i+'.unit_price']">
+                <div class="offset-3"><small class="text-danger font-weight-bold ml-3">@{{ errors['items.'+i+'.unit_price'][0] }}</small></div>
             </div>
             <div class="row mt-2">
                 <label class="col-3">特征:</label>
                 <label class="col-5">
-                    <label v-if="item.feature">@{{ item.feature }}</label><br>
-                    <button type="button" class="btn btn-dark ml-2" @click="showAddFeatureModal(i,item.feature)">调整特征</button>
+                    <label v-if="item.feature">@{{ item.featureFormat }}</label><br>
+                    <button type="button" class="btn btn-dark ml-2" @click="showAddFeatureModal(i)">调整特征</button>
                 </label>
             </div>
         </div>

+ 0 - 0
resources/views/customer/project/_storage.blade.php → resources/views/customer/project/part/_storage.blade.php


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

@@ -0,0 +1,276 @@
+<div class="row">
+    <div class="col-6" id="parent">
+        <div class="card">
+            <div class="card-header bg-light-info">
+                <span class="pull-left font-weight-bold cursor-pointer" @click="show('storage')"><span class="fa fa-cubes"></span>&nbsp;仓储</span>
+            </div>
+            <div class="card-body" id="storage">
+                <table class="table table-sm">
+                    <tr>
+                        <th>计费类型</th>
+                        <th>用仓类型</th>
+                        <th>起租面积</th>
+                        <th>单价</th>
+                        <th>单位</th>
+                        <th>减免类型</th>
+                        <th>减免值</th>
+                    </tr>
+                    <tr v-for="item in selectedModel.storage">
+                        <td>@{{ item.counting_type }}</td>
+                        <td>@{{ item.using_type }}</td>
+                        <td>@{{ item.minimum_area }}</td>
+                        <td>@{{ item.price }}</td>
+                        <td>@{{ item.discount_type }}</td>
+                        <td>@{{ item.discount_value }}</td>
+                        <td>@{{ poolMapping.units[item.unit_id] }}</td>
+                    </tr>
+                </table>
+            </div>
+        </div>
+        <div class="card" id="operation-card">
+            <div class="card-header bg-light-info">
+                <span class="pull-left font-weight-bold cursor-pointer" @click="show('operation')"><span class="fa fa-suitcase"></span>&nbsp;作业</span>
+            </div>
+            <div class="card-body" id="operation">
+                <div class="container-fluid">
+                    <div class="row font-weight-bold">
+                        <div class="cursor-pointer" @click="show('operation-list-in')"><span class="fa" :class="upList['operation-list-in'] ? 'fa-caret-right' : 'fa-caret-down'"></span> 入库</div>
+                    </div>
+                    <div class="container-fluid" v-for="(operation,i) in selectedModel.operation" v-if="operation.operation_type === '入库'" id="operation-list-in">
+                        <div class="row offset-1">
+                            <label class="font-weight-bold cursor-pointer" @click="show('operation-item-'+i)">
+                                <span class="fa" :class="upList['operation-item-'+i] ? 'fa-caret-right' : 'fa-caret-down'"></span>
+                                &nbsp;@{{ operation.strategy }}:
+                            </label>
+                            <label>@{{ operation.name }}</label>
+                            <label v-if="operation.remark" class="text-secondary">&nbsp;&nbsp;(@{{ operation.remark }})</label>
+                        </div>
+                        <div class="row offset-1 small mt-0" style="background-color: RGB(248,248,248)" v-if="operation.strategy === '特征'">
+                            @{{ operation.featureFormat }}
+                        </div>
+                        <div class="container-fluid offset-2" :id="'operation-item-'+i">
+                            <div v-for="item in operation.items" class="container-fluid">
+                                <div class="row"><label>@{{ item.strategy }}</label>:
+                                    <b>@{{ item.amount }}</b>/@{{ poolMapping.units[item.unit_id] }} (<b>@{{ item.unit_price }}</b>元)
+                                </div>
+                                <div class="row small mt-0" style="background-color: RGB(248,248,248)">
+                                    @{{ item.featureFormat }}
+                                </div>
+                            </div>
+                        </div>
+                    </div>
+                    <div class="row font-weight-bold">
+                        <div class="cursor-pointer" @click="show('operation-list-out')"><span class="fa" :class="upList['operation-list-out'] ? 'fa-caret-right' : 'fa-caret-down'"></span> 出库</div>
+                    </div>
+                    <div class="container-fluid" v-for="(operation,i) in selectedModel.operation" v-if="operation.operation_type === '出库'" id="operation-list-out">
+                        <div class="row offset-1">
+                            <label class="font-weight-bold cursor-pointer" @click="show('operation-item-'+i)">
+                                <span class="fa" :class="upList['operation-item-'+i] ? 'fa-caret-right' : 'fa-caret-down'"></span>
+                                &nbsp;@{{ operation.strategy }}:
+                            </label>
+                            <label>@{{ operation.name }}</label>
+                            <label v-if="operation.remark" class="text-secondary">&nbsp;&nbsp;(@{{ operation.remark }})</label>
+                        </div>
+                        <div class="row offset-1 small mt-0" style="background-color: RGB(248,248,248)" v-if="operation.strategy === '特征'">
+                            @{{ operation.featureFormat }}
+                        </div>
+                        <div class="container-fluid offset-2" :id="'operation-item-'+i">
+                            <div v-for="item in operation.items" class="container-fluid">
+                                <div class="row"><label>@{{ item.strategy }}</label>:
+                                    <b>@{{ item.amount }}</b>/@{{ poolMapping.units[item.unit_id] }} (<b>@{{ item.unit_price }}</b>元)
+                                </div>
+                                <div class="row small mt-0" style="background-color: RGB(248,248,248)">
+                                    @{{ item.featureFormat }}
+                                </div>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </div>
+        <div class="card" id="express-card">
+            <div class="card-header bg-light-info">
+                <span class="pull-left font-weight-bold cursor-pointer" @click="show('express')"><span class="fa fa-cube"></span>&nbsp;快递</span>
+            </div>
+            <div class="card-body" id="express">
+                <table class="table table-sm">
+                    <tr>
+                        <th>承运商</th>
+                        <th>名称</th>
+                        <th>首重值(KG)</th>
+                        <th>续重值(KG)</th>
+                        <th>详情</th>
+                    </tr>
+                    <tbody v-for="(express,i) in selectedModel.express">
+                        <tr>
+                            <td>
+                                <div class="text-overflow-warp-100 small">
+                                    <label v-for="(logistic,j) in express.logistics" class="m-0">@{{ poolMapping.logistics[logistic] }}</label>
+                                </div>
+                            </td>
+                            <td>@{{ express.name }}</td>
+                            <td>@{{ express.initial_weight }}</td>
+                            <td>@{{ express.additional_weight }}</td>
+                            <td @click="show('express-item-'+i)" class="cursor-pointer">
+                                <span class="fa" :class="upList['express-item-'+i] ? 'fa-angle-double-right' : 'fa-angle-double-down'"></span>
+                                &nbsp;@{{ express.items.length }} 省份</td>
+                        </tr>
+                        <tr>
+                            <td colspan="5">
+                                <div :id="'express-item-'+i" class="offset-3">
+                                    <table class="table table-sm col-10">
+                                        <tr>
+                                            <th>省份</th>
+                                            <th>首重价格</th>
+                                            <th>续重价格</th>
+                                        </tr>
+                                        <tr v-for="(item,i) in express.items">
+                                            <td>@{{ poolMapping.provinces[item.province_id] }}</td>
+                                            <td>@{{ item.initial_weight_price }}</td>
+                                            <td>@{{ item.additional_weight_price }}</td>
+                                        </tr>
+                                    </table>
+                                </div>
+                            </td>
+                        </tr>
+                    </tbody>
+                </table>
+            </div>
+        </div>
+        <div class="card" id="logistic-card">
+            <div class="card-header bg-light-info">
+                <span class="pull-left font-weight-bold cursor-pointer" @click="show('logistic')"><span class="fa fa-truck"></span>&nbsp;物流</span>
+            </div>
+            <div class="card-body" id="logistic">
+                <table class="table table-sm">
+                    <tr>
+                        <th>承运商</th>
+                        <th>名称</th>
+                        <th>单位一</th>
+                        <th>一区间值</th>
+                        <th>单位二</th>
+                        <th>二区间值</th>
+                        <th>提货费</th>
+                        <th>燃油附加费</th>
+                        <th>信息服务费</th>
+                        <th>详情</th>
+                    </tr>
+                    <tbody v-for="(logistic,i) in selectedModel.logistic">
+                        <tr>
+                            <td>
+                                <div class="text-overflow-warp-100 small">
+                                    <label v-for="(logistic,j) in logistic.logistics" class="m-0">@{{ poolMapping.logistics[logistic] }}</label>
+                                </div>
+                            </td>
+                            <td>@{{ logistic.name }}</td>
+                            <td>@{{ poolMapping.units[logistic.unit_id] }}</td>
+                            <td>@{{ logistic.unit_range }}</td>
+                            <td>@{{ poolMapping.units[logistic.other_unit_id] }}</td>
+                            <td>@{{ logistic.other_unit_range }}</td>
+                            <td>@{{ logistic.pick_up_price }}</td>
+                            <td>@{{ logistic.fuel_price }}</td>
+                            <td>@{{ logistic.service_price }}</td>
+                            <td @click="show('logistic-item-'+i)" class="cursor-pointer">
+                                <span class="fa" :class="upList['logistic-item-'+i] ? 'fa-angle-double-right' : 'fa-angle-double-down'"></span>
+                                &nbsp;@{{ logistic.items.length }} 地区
+                            </td>
+                        </tr>
+                        <tr>
+                            <td colspan="9">
+                                <div :id="'logistic-item-'+i" class="offset-1">
+                                    <table class="table table-sm">
+                                        <tr>
+                                            <th>省份</th>
+                                            <th>市区</th>
+                                            <th>单位</th>
+                                            <th>区间</th>
+                                            <th>单价</th>
+                                            <th>送货费</th>
+                                            <th>起始计费</th>
+                                            <th>起始计数</th>
+                                            <th>费率(%)</th>
+                                        </tr>
+                                        <tr v-for="item in logistic.items">
+                                            <td class="font-weight-bold">@{{ poolMapping.provinces[item.province_id] }}</td>
+                                            <td class="font-weight-bold">@{{ poolMapping.cities[item.city_id] }}</td>
+                                            <td>@{{ poolMapping.units[item.unit_id] }}</td>
+                                            <td>@{{ item.range }}</td>
+                                            <td>@{{ item.unit_price }}</td>
+                                            <td>@{{ item.delivery_fee }}</td>
+                                            <td>@{{ item.initial_fee }}</td>
+                                            <td>@{{ item.initial_amount }}</td>
+                                            <td>@{{ item.rate }}<span v-if="item.rate" class="font-weight-bold">&nbsp;%</span></td>
+                                        </tr>
+                                    </table>
+                                </div>
+                            </td>
+                        </tr>
+                    </tbody>
+                </table>
+            </div>
+        </div>
+        <div class="card" id="directLogistic-card">
+            <div class="card-header bg-light-info">
+                <span class="pull-left font-weight-bold cursor-pointer" @click="show('directLogistic')"><span class="fa fa-rocket"></span>&nbsp;直发</span>
+            </div>
+            <div class="card-body" id="directLogistic">
+                <div class="row">
+                    <label class="col-4">名称:<b>@{{ selectedModel.directLogistic.name }}</b></label>
+                    <label class="col-4">起步数(KM):<b>@{{ selectedModel.directLogistic.base_km }}</b></label>
+                </div>
+                <div class="row">
+                    <div class="cursor-pointer text-primary col-2" @click="show('directLogistic-item')">
+                        <span class="fa" :class="upList['directLogistic-item'] ? 'fa-angle-double-right' : 'fa-angle-double-down'"></span>&nbsp;详情</div>
+                    <div class="col-10" id="directLogistic-item">
+                        <table class="table table-sm">
+                            <tr>
+                                <th>车型</th>
+                                <th>起步费</th>
+                                <th>续费(元/KM)</th>
+                            </tr>
+                            <tr v-for="(item,i) in selectedModel.directLogistic.items">
+                                <td>@{{ poolMapping.cars[item.car_type_id] }}</td>
+                                <td>@{{ item.base_fee }}</td>
+                                <td>@{{ item.additional_fee }}</td>
+                            </tr>
+                        </table>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+    <div class="col-6">
+        <div class="card">
+            <div class="card-header bg-light-info">
+                <button type="button" class="btn mr-1" :class="type == 'storage' ? 'btn-primary text-white' : 'btn-outline-primary'" @click="switchType('storage')">仓储</button>
+                <button type="button" class="btn mr-1" :class="type == 'operation' ? 'btn-primary text-white' : 'btn-outline-primary'" @click="switchType('operation')">作业</button>
+                <button type="button" class="btn mr-1" :class="type == 'express' ? 'btn-primary text-white' : 'btn-outline-primary'" @click="switchType('express')">快递</button>
+                <button type="button" class="btn mr-1" :class="type == 'logistic' ? 'btn-primary text-white' : 'btn-outline-primary'" @click="switchType('logistic')">物流</button>
+                <button type="button" class="btn mr-1" :class="type == 'directLogistic' ? 'btn-primary text-white' : 'btn-outline-primary'" @click="switchType('directLogistic')">直发</button>
+            </div>
+            <div class="card-body">
+                <div v-if="type == 'storage'">
+                    @include("customer.project.part._storage")
+                </div>
+                <div v-show="type == 'operation'">
+                    @include("customer.project.part._operation")
+                    @include("customer.project.part._addFeature")
+                </div>
+                <div v-show="type == 'express'">
+                    @include("customer.project.part._express")
+                </div>
+                <div v-show="type == 'logistic'">
+                    @include("customer.project.part._logistic")
+                    @include("customer.project.part._logisticDetail")
+                </div>
+                <div v-show="type == 'directLogistic'">
+                    @include("customer.project.part._directLogistic")
+                </div>
+                <div class="row mt-3" v-if="base=='three'">
+                    <div class="col-3"></div>
+                    <button type="button" class="btn btn-success ml-1 col-6" @click="saveModel()">保存</button>
+                </div>
+            </div>
+        </div>
+    </div>
+</div>

+ 0 - 0
resources/views/customer/project/_two.blade.php → resources/views/customer/project/part/_two.blade.php


+ 12 - 4
resources/views/maintenance/log/index.blade.php

@@ -64,11 +64,19 @@
             mounted: function () {
                 let data = [
                     [
-                        {name: 'operation', type: 'input', tip: '操作', placeholder: '操作'},
-                        {name: 'type', type: 'input', tip: '操作', placeholder: '类型'},
+                        {name: 'username', type: 'input', tip: '操作者', placeholder: '操作者'},
+                        {name: 'type',
+                            type: 'select_multiple_select',
+                            tip: ['输入关键词快速定位下拉列表,回车确定', '选择要显示的类型'],
+                            placeholder: ['类型', '定位或多选类型'],
+                            data: [{'name': 'log', 'value': 'log'},
+                                {'name': 'warning', 'value': 'warning'},
+                                {'name': 'error', 'value': 'error'},
+                                {'name': 'panic', 'value': 'panic'},
+                                {'name': 'fatal', 'value': 'fatal'}],},
                         {name: 'description', type: 'input', tip: '详情:可在两侧添加百分号(%)进行模糊搜索', placeholder: '详情'},
-                        {name:'created_at_start',type:'dateTime',tip:'选择显示指定日期的起始时间'},
-                        {name:'created_at_end',type:'dateTime',tip:'选择显示指定日期的截止'},
+                        {name:'created_at_start',type:'dateTime',tip:'选择显示指定日期的起始时间,只选一个或者不选,则查询当天'},
+                        {name:'created_at_end',type:'dateTime',tip:'选择显示指定日期的截止,只选一个或者不选,则查询当天'},
                         {name:'is_exception',type:'checkbox',tip:'仅显示异常', data: [{name: 'true', value: '仅显示异常'}]}
                     ]
                 ];

+ 1 - 1
resources/views/maintenance/owner/recycle.blade.php

@@ -52,7 +52,7 @@
                 restoreSelected:function(owner){
                     let _this=this;
                     confirm('确定要恢复停用货主“' + owner.name + '”吗?');
-                    let ajaxUrl='{{url("apiLocal/owner/restoreSelected")}}';
+                    let ajaxUrl='{{url("maintenance/owners/restoreSelected")}}';
                     axios.post(ajaxUrl,{id:owner.id}).then(function(response){
                         if(response.data.success){
                             tempTip.setDuration(1000);

+ 1 - 1
resources/views/maintenance/priceModel/logistic/index.blade.php

@@ -122,7 +122,7 @@
                         window.axios.post('{{url('maintenance/city/get')}}')
                             .then(res=>{
                                 let cities = [];
-                                res.data.forEach(function (city) {
+                                res.data.data.forEach(function (city) {
                                     if (city.province_id){
                                         if (cities[city.province_id]){
                                             cities[city.province_id].push(city)

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

@@ -10,7 +10,7 @@
     <div class="container-fluid">
         <div class="card">
             <div>
-                <form  method="GET" action="{{url('maintenance/waybillPriceModel')}}" id="optionSubmit">
+                <form  method="GET" action="{{url('maintenance/priceModel/waybillPriceModel')}}" id="optionSubmit">
                     <table class="table  table-sm table-bordered table-hover text-nowrap ">
                         <tr>
                             <td  > <label style="margin-left: 2%" class="form-inline">页显示条数:

+ 5 - 8
resources/views/order/index/delivering.blade.php

@@ -858,25 +858,22 @@
                 copyLogisticNumber(){
                     let text="";
                     this.checkData.forEach((code,i)=>{
-                        if (this.picktotraceidMap[code] && this.picktotraceidMap[code].length>1){console.log(1);
+                        if(this.picktotraceidMap[code] && this.picktotraceidMap[code].length>1){
                             this.picktotraceidMap[code].forEach((number,j)=>{
-                                text += number;
-                                if (i!==this.checkData.length-1 && j!==this.picktotraceidMap[code].length-1){
-                                    text += ",";
-                                }
+                                text += number+"\r\n";
                             });
-                        }else{
+                        }else {
                             this.orders.some(order=>{
                                 if (order.orderno == code){
                                     if (order.soreference5) {
-                                        text += order.soreference5;
-                                        if(i!==this.checkData.length-1)text += "\r\n";
+                                        text += order.soreference5+"\r\n";
                                     }
                                     return true;
                                 }
                             });
                         }
                     });
+                    text.substring(0,text.lastIndexOf("\r\n",text));
                     if (!text)text = " ";
                     this.copyText(text)
                 },

+ 40 - 6
resources/views/order/issue/index.blade.php

@@ -20,11 +20,18 @@
                         </div>
                     </span>
                     @cannot('订单管理-问题件-客户不可见')
-                        <span class="ml-1">
-                        <button type="button" class="btn btn-outline-dark btn-sm form-control-sm   tooltipTarget" @click="endOrderIssue" :class="[checkData.length>0?'btn-dark text-light':'']">
+                    <span class="ml-1">
+                        <button type="button" class="btn btn-outline-dark btn-sm form-control-sm tooltipTarget" @click="endOrderIssue" :class="[checkData.length>0?'btn-dark text-light':'']">
                             批量完结
                         </button>
                     </span>
+                    @can('订单管理-问题件-批量归档')
+                    <span class="ml-1">
+                        <button type="button" class="btn btn-outline-primary btn-sm form-control-sm tooltipTarget" @click="archiveOrderIssue" v-show="checkData.length>0" >
+                            批量归档
+                        </button>
+                    </span>
+                    @endcan
                     @endcannot
                     @can('订单管理-问题件-删除')
                         <span class="ml-1">
@@ -257,8 +264,8 @@
                             <span v-if='orderIssue.order.logistic'>@{{ orderIssue.order.logistic.name }}</span>
                         </td>
                         <td class=" hide-content p-0 td-yellow child-layer-2" valign="middle" align="center">
-                            <span :id="'logisticNumbers'+orderIssue.id" :class="orderIssue.order.logisticNumbers.length > 1 ?'collapse ':''">
-                                <span v-for="logisticNumber in orderIssue.order.logisticNumbers" >@{{ logisticNumber }}&nbsp;&nbsp;</span>
+                            <span  :class="orderIssue.order.logisticNumbers.length > 1 ?'collapse ':''" :id="'logisticNumbers'+orderIssue.id" >
+                                <span class="m-0 p-0 d-inline-block" v-for="logisticNumber in orderIssue.order.logisticNumbers" >@{{ logisticNumber }}&nbsp;&nbsp;</span>
                             </span>
                             <button v-if="orderIssue.order.logisticNumbers.length > 1" type="button" class="btn btn-sm btn-outline-primary align-middle mt-1"
                                     :id="'logisticNumbersBtn'+orderIssue.id" data-toggle="collapse" :data-target="'#logisticNumbers'+orderIssue.id"
@@ -707,7 +714,7 @@
                 expressRemission:['原单减免', '补发减免', '全部减免'],
                 checkData: [],
                 from: '',
-                finalStatus: [{value:'',name:""},{value:'已解决',name:"已解决"},{value:'待退回',name:"待退回"},{value:'退回中',name:"退回中"},],//['无','已解决', '待退回', '退回中'],
+                finalStatus: [{value:'',name:""},{value:'已解决',name:"已解决"},{value:'待退回',name:"待退回"},{value:'退回中',name:"退回中"},{value:'已归档',name:"已归档"},],//['无','已解决', '待退回', '退回中','已归档'],
                 selectedStyle: '',
                 deleteId: '',
                 total: {!!  $orderIssues->toJson() !!}['total'],
@@ -738,7 +745,9 @@
                     {name: 'null', value: '无'},
                     {name: '已解决', value: '已解决'},
                     {name: '待退回', value: '待退回'},
-                    {name: '退回中', value: '退回中'}];
+                    {name: '退回中', value: '退回中'},
+                    {name: '已归档', value: '已归档'},
+                ];
                 let imported_status = [{name:'导入未处理',value:'导入未处理'},{name:'导入已梳理',value:'导入已处理'}]
                 let data = [[
                     {name: 'created_at_start', type: 'dateTime', tip: '登记开始日期'},
@@ -1491,6 +1500,31 @@
                             item[column] = value;
                         }
                     });
+                },
+                archiveOrderIssue(){
+                    if (this.checkData.length === 0) {
+                        tempTip.show('没有勾选订单');
+                        return;
+                    }
+                    let _this = this;
+                    let ids = _this.checkData;
+                    let data = {ids:ids};
+                    axios.post('{{url('apiLocal/order/issue/archiveOrderIssue')}}',data)
+                        .then(function(response){
+                            if(response.data.success){
+                                tempTip.setDuration(2000);
+                                tempTip.showSuccess('确认成功');
+                                _this.orderIssuesEdit(data.ids,'final_status','已归档');
+                                return;
+                            }
+                            tempTip.setDuration(2000);
+                            tempTip.show(response.data.error);
+                        })
+                        .catch(function(error){
+                            tempTip.cancelWaitingTip();
+                            tempTip.setDuration(2000);
+                            tempTip.show(error);
+                        });
                 }
             }
         })

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

@@ -277,7 +277,7 @@
                         recipient:'{{$waybill->recipient}}',
                         recipient_mobile:'{{$waybill->recipient_mobile}}',
                         charge:'{{$waybill->charge}}',
-                        ordering_remark:'{{$waybill->ordering_remark}}',
+                        ordering_remark:'{{preg_replace("/[\n\s]/",' ',($waybill->ordering_remark??""))}}',
                         carrier:'{{$waybill->logistic ? $waybill->logistic->name : ''}}',
                         carrier_bill:'{{$waybill->carrier_bill}}',
                         origination_city:'{{$waybill->origination_city ? $waybill->origination_city->name : ''}}',

+ 1 - 1
resources/views/waybill/recycle.blade.php

@@ -146,7 +146,7 @@
                         recipient:'{{$waybill->recipient}}',
                         recipient_mobile:'{{$waybill->recipient_mobile}}',
                         charge:'{{$waybill->charge}}',
-                        ordering_remark:'{{$waybill->ordering_remark}}',
+                        ordering_remark:'{{preg_replace("/[\n\s]/",' ',($waybill->ordering_remark??""))}}',
                         carrier:'{{$waybill->carrier ? $waybill->carrier->name : ''}}',
                         carrier_bill:'{{$waybill->carrier_bill}}',
                         origination_city:'{{$waybill->origination_city ? $waybill->origination_city->name : ''}}',

+ 1 - 1
routes/apiLocal.php

@@ -7,7 +7,6 @@ use Illuminate\Support\Facades\Route;
 地址前缀:/apiLocal/
 */
 Route::post('rejected/recoverSelected', 'RejectedController@apiRecoverSelected');
-Route::post('owner/restoreSelected', 'OwnerController@restoreSelected');
 Route::post('rejectedBillItem/store', 'RejectedBillItemController@apiStore');
 Route::post('rejectedBillItem/update', 'RejectedBillItemController@apiUpdate');
 Route::post('rejectedBillItem/apiGet', 'RejectedBillItemController@apiGet');
@@ -52,6 +51,7 @@ Route::group(['prefix' => 'order'], function () {
         Route::post('endOrderIssues','OrderIssueController@endOrderIssuesApi');
         Route::post('editSecondLogisticNumber','OrderIssueController@editSecondLogisticNumberApi');
         Route::post('importPasteData','OrderIssueController@importPasteDataApi');
+        Route::post('archiveOrderIssue','OrderIssueController@archiveOrderIssueApi');
         Route::match(['get','post'],'disposeImport','OrderIssueController@disposeImportApi');
         Route::post('financeConfirm','OrderIssueController@financeConfirmApi');
 

+ 6 - 0
routes/web.php

@@ -47,6 +47,7 @@ Route::group(['prefix'=>'maintenance'],function(){
     /** 货主 */
     Route::group(['prefix'=>'owners'],function(){
         Route::get('recycle','OwnerController@recycle');
+        Route::post('restoreSelected', 'OwnerController@restoreSelected');
     });
     Route::group(['prefix'=>'owner'],function (){
         Route::post("get","OwnerController@get");
@@ -165,6 +166,9 @@ Route::group(['prefix'=>'maintenance'],function(){
     Route::group(['prefix'=>"log"],function (){
         Route::get("exception",'LogController@exception');
     });
+    Route::group(['prefix'=>"logistic"],function (){
+        Route::post("get",'LogisticController@get');
+    });
 
     Route::get('syncRedisLogs','LogController@syncRedisLogs');
     Route::resource('log', 'LogController');
@@ -607,6 +611,8 @@ Route::group(['prefix'=>'customer'],function(){
         Route::post('storeLog', 'CustomerLogController@store');
         Route::post('relatedOwner', 'CustomerBaseController@relatedOwner');
         Route::post('addTag', 'CustomerBaseController@addTag');
+        Route::post('delTag', 'CustomerBaseController@delTag');
+        Route::post('destroyLog', 'CustomerBaseController@destroyLog');
         Route::group(['prefix' => 'customerLogStatus'], function () {
             Route::post('save', 'CustomerLogStatusController@save');
             Route::post('destroy', 'CustomerLogStatusController@destroy');

+ 0 - 2
tests/Services/BatchService/TestGetBatchByCodes.php

@@ -8,8 +8,6 @@ use Tests\TestCase;
 
 class TestGetBatchByCodes extends TestCase
 {
-//    use RefreshDatabase;
-
     /** @var BatchService $service */
     private $service;
     private $data = [];

+ 0 - 2
tests/Services/CityService/FindByNameTest.php

@@ -9,8 +9,6 @@ use Tests\TestCase;
 
 class FindByNameTest extends TestCase
 {
-    use RefreshDatabase;
-
     /** @var CityService $cityService */
     public $cityService;
 

+ 0 - 2
tests/Services/LogisticService/GetLogisticByCodeTest.php

@@ -10,8 +10,6 @@ use Tests\TestCase;
 
 class GetLogisticByCodeTest extends TestCase
 {
-    use RefreshDatabase;
-
     /** @var LogisticService $service */
     private $service;
     private $data = [];

+ 0 - 2
tests/Services/LogisticService/GetLogisticByCodesTest.php

@@ -11,8 +11,6 @@ use Tests\TestCase;
 
 class GetLogisticByCodesTest extends TestCase
 {
-    use RefreshDatabase;
-
     /** @var LogisticService $service */
     private $service;
     private $data;

+ 0 - 2
tests/Services/LogisticTimingService/FindByParamsTest.php

@@ -11,8 +11,6 @@ use Tests\TestCase;
 
 class FindByParamsTest extends TestCase
 {
-    use RefreshDatabase;
-
     /**
      * @var LogisticTimingService $logisticTimingService
      */

+ 2 - 1
tests/Services/NewOrderCountingRecordService/OrderCountingRecordsTest.php

@@ -33,7 +33,8 @@ class OrderCountingRecordsTest extends TestCase
         parent::setUp(); // TODO: Change the autogenerated stub
         cache()->flush();
         $this->newOrderCountingRecordService = new NewOrderCountingRecordService();
-        $this->actingAs(factory(User::class)->create(['name' => 'yang']));
+        $user = User::query()->where('name', 'yang')->first();
+        $this->actingAs($user);
         $owners = factory(Owner::class)->times(2)->create();
         $this->ownerIds = array_column($owners->toArray(), 'id');
         $this->queryConditionDay = $this->newOrderCountingRecordService->transfersToCondition(Carbon::now()->subDays($this->step_length)->toDateString(), Carbon::now()->toDateString(), '日', $this->ownerIds);

+ 2 - 1
tests/Services/NewOrderCountingRecordService/TransfersToConditionsTest.php

@@ -22,7 +22,8 @@ class TransfersToConditionsTest extends TestCase
         parent::setUp(); // TODO: Change the autogenerated stub
         cache()->flush();
         $this->newOrderCountingRecordService = new NewOrderCountingRecordService();
-        $this->actingAs(factory(User::class)->create(['name' => 'yang']));
+        $user = User::query()->where('name', 'yang')->first();
+        $this->actingAs($user);
         $this->data['dates'] = [
             'right'=>[
                 ['startAt'=>Carbon::now()->subDays(2),'endAt'=>Carbon::now()->addDays(2)],

+ 0 - 1
tests/Services/OracleDOCOrderHeaderService/GetWMSOrderOnEditDateTest.php

@@ -12,7 +12,6 @@ use Tests\TestCase;
 
 class GetWMSOrderOnEditDateTest extends TestCase
 {
-    use RefreshDatabase;
     /** @var OracleDOCOrderHeaderService $service */
     private $service;
 

+ 0 - 1
tests/Services/OracleDOCOrderHeaderService/GetWMSOrderOnStartDateTest.php

@@ -12,7 +12,6 @@ use Tests\TestCase;
 
 class GetWMSOrderOnStartDateTest extends TestCase
 {
-    use RefreshDatabase;
     /** @var OracleDOCOrderHeaderService $service */
     public $service;
 

+ 0 - 2
tests/Services/OracleDOCOrderHeaderService/GetWmsOrderOnStartDateEditTest.php

@@ -12,8 +12,6 @@ use Tests\TestCase;
 
 class GetWmsOrderOnStartDateEditTest extends TestCase
 {
-    use RefreshDatabase;
-
     /** @var OracleDOCOrderHeaderService $service */
     public $service;
 

+ 0 - 1
tests/Services/OracleDOCOrderHeaderService/GetWmsOrderOnstartDateCreateTest.php

@@ -13,7 +13,6 @@ use Tests\TestCase;
 
 class GetWmsOrderOnstartDateCreateTest extends TestCase
 {
-    use RefreshDatabase;
     /** @var OracleDOCOrderHeaderService $service */
     public $service;
 

+ 0 - 2
tests/Services/OrderCommodityService/GetReGroupActAllocationDetailsTest.php

@@ -12,8 +12,6 @@ use Tests\TestCase;
 
 class GetReGroupActAllocationDetailsTest extends TestCase
 {
-//    use RefreshDatabase;
-
     /** @var OrderCommodityService  $service */
     private $service;
     private $data;

+ 0 - 2
tests/Services/OrderCommodityService/SyncOrderCommodityTest.php

@@ -17,8 +17,6 @@ use Tests\TestCase;
 
 class SyncOrderCommodityTest extends TestCase
 {
-//    use RefreshDatabase;
-
     /** @var OrderCommodityService $service */
     private $service;
     private $data = [];

+ 0 - 1
tests/Services/OrderIssueService/GetRecycleBinPaginateTest.php

@@ -9,7 +9,6 @@ use Tests\TestCase;
 
 class GetRecycleBinPaginateTest extends TestCase
 {
-    use RefreshDatabase;
     /**
      * @var OrderIssueService $service
      */

+ 0 - 1
tests/Services/OrderIssueService/OrderIssueTagTest.php

@@ -13,7 +13,6 @@ use Tests\TestCase;
 
 class OrderIssueTagTest extends TestCase
 {
-    use RefreshDatabase;
     /** @var OrderIssueService $service */
     public $service;
     public function setUp(): void

+ 0 - 1
tests/Services/OrderIssueService/RecoverOrderIssueTest.php

@@ -10,7 +10,6 @@ use Tests\TestCase;
 
 class RecoverOrderIssueTest extends TestCase
 {
-    use RefreshDatabase;
     /**
      * @var OrderIssueService $service
      */

+ 0 - 2
tests/Services/OrderPackageCommoditiesService/RegroupOrderCommoditiesTest.php

@@ -20,8 +20,6 @@ use Tests\TestCase;
 
 class RegroupOrderCommoditiesTest extends TestCase
 {
-    use RefreshDatabase;
-
     /**
      * @var OrderPackageCommoditiesService $service
      */

+ 0 - 1
tests/Services/StoreService/CreateStoreTest.php

@@ -16,7 +16,6 @@ use Tests\TestCase;
 
 class CreateStoreTest extends TestCase
 {
-//    use RefreshDatabase;
     /** @var StoreService $service */
     public $service;
     public $asnHeaders;

+ 19 - 0
tests/Unit/CustomerLogTest.php

@@ -0,0 +1,19 @@
+<?php
+
+
+use App\CustomerLog;
+use Illuminate\Database\Eloquent\Relations\BelongsTo;
+use Illuminate\Foundation\Testing\RefreshDatabase;
+use Tests\TestCase;
+
+class CustomerLogTest extends TestCase
+{
+    /**
+     * @test
+     */
+    public function customerLog_belongsTo_customerLogStatus()
+    {
+        $customerLog =  factory(CustomerLog::class)->create();
+        $this->assertInstanceOf(BelongsTo::class, $customerLog->customerLogStatus());
+    }
+}