Prechádzať zdrojové kódy

Merge branch 'work_order_dev' into zengjun

# Conflicts:
#	app/Providers/AppServiceProvider.php
ajun 4 rokov pred
rodič
commit
a671807741

+ 122 - 0
app/Filters/WorkOrderFilters.php

@@ -0,0 +1,122 @@
+<?php
+
+
+namespace App\Filters;
+
+use App\WorkOrder;
+use App\WorkOrderChildType;
+use Illuminate\Http\Request;
+
+class WorkOrderFilters
+{
+    protected $request;
+    protected $queryBuilder;
+    protected $filters = [
+        'ids','creator','name','remake','created_at_start','created_at_end','review_at_start','review_at_end','reviewer','word_order_types','word_order_child_types'
+    ];
+    protected $array_filter;
+    protected $params = [
+        'ids','creator','name','remake','created_at_start','created_at_end','review_at_start','review_at_end','reviewer','word_order_types','word_order_child_types'
+    ];
+
+    protected $workOrderTypeQuery;
+
+    protected $workOrderChildQuery;
+
+    public function __construct(Request $request)
+    {
+        $this->request = $request;
+        $this->params = $request->all();
+        $this->array_filter = array_filter($this->request->only($this->filters));
+    }
+
+    public function apply($builder)
+    {
+        $this->queryBuilder = $builder;
+        $this->afterApply();
+        foreach ($this->array_filter as $filter => $value) {
+            if (method_exists($this, $filter)) {
+                $this->$filter($value, $this->queryBuilder);
+            }
+        }
+        $this->beforeApply();
+        return $this->queryBuilder;
+    }
+
+    public function afterApply()
+    {
+        if(isset($this->params['data']))
+            $this->id(explode(',',$this->params['data']));
+    }
+
+    public function beforeApply()
+    {
+        if($this->workOrderChildQuery)
+            $this->queryBuilder->whereIn('work_order_type_id',$this->workOrderChildQuery);
+
+        if ($this->workOrderTypeQuery)
+            $this->queryBuilder->whereIn('work_order_child_id',$this->workOrderChildQuery);
+    }
+
+    public function id($id)
+    {
+        if(is_array($id))$this->queryBuilder->whereIn('work_orders.id',$id);
+        else $this->queryBuilder->where('work_orders.id',$id);
+    }
+
+    // 创建开始时间
+    public function created_at_start($create_at_start)
+    {
+        $this->queryBuilder->where('work_orders.created_at','>=',$create_at_start);
+    }
+    // 创建结束时间
+    public function created_at_end($created_at_end)
+    {
+        $this->queryBuilder->where('work_orders.created_at','<=',$created_at_end);
+    }
+    // 审核开始时间
+    public function review_at_start($review_at_start)
+    {
+        $this->queryBuilder->where('work_orders.review_at','>=',$review_at_start);
+    }
+    // 审核结束时间
+    public function review_at_end($review_at_end)
+    {
+        $this->queryBuilder->where('work_orders.review_at','<=',$review_at_end);
+    }
+    // 创建人
+    public function creator($id)
+    {
+        if (is_array($id))
+            $this->queryBuilder->whereIn('work_orders.creator_id',$id);
+        else
+            $this->queryBuilder->where('work_orders.creator_id',$id);
+    }
+    // 审核人
+    public function reviewer($id)
+    {
+        if (is_array($id))
+            $this->queryBuilder->whereIn('work_orders.reviewer_id',$id);
+        else
+            $this->queryBuilder->where('work_orders.reviewer_id',$id);
+    }
+
+    // 类型
+    public function word_order_types($word_order_types)
+    {
+        if(!$this->workOrderTypeQuery)
+            $this->workOrderTypeQuery = WorkOrder::query()->select('id');
+        if (is_array($word_order_types))
+            $this->workOrderTypeQuery->whereIn('id',$word_order_types);
+        else $this->workOrderTypeQuery->where('id',$word_order_types);
+    }
+    // 子类型
+    public function word_order_child_types($word_order_child_types)
+    {
+        if(!$this->workOrderTypeQuery)
+            $this->workOrderChildQuery = WorkOrderChildType::query()->select('id');
+        if (is_array($word_order_child_types))
+            $this->workOrderChildQuery->whereIn('id',$word_order_child_types);
+        else $this->workOrderChildQuery->where('id',$word_order_child_types);
+    }
+}

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

@@ -44,8 +44,6 @@ class OrderIssueController extends Controller
         }
         $owners = app(OwnerService::class)->getAuthorizedOwners();
         $orderIssues = OrderIssue::query()->filter($filter)->defaultWith()->paginate($request['paginate'] ?? 50);
-//        $orderIssues = OrderIssue::query()->filter($filter)->defaultWith()->toSql();
-//        dd($orderIssues);
         $orderIssueType = OrderIssueType::all();
         $qualityLabel = QualityLabel::all();
         $logistics = Logistic::all();

+ 9 - 0
app/Http/Controllers/WorkOrderChildTypeController.php

@@ -0,0 +1,9 @@
+<?php
+
+namespace App\Http\Controllers;
+
+
+class WorkOrderChildTypeController extends Controller
+{
+
+}

+ 122 - 0
app/Http/Controllers/WorkOrderController.php

@@ -0,0 +1,122 @@
+<?php
+
+namespace App\Http\Controllers;
+
+use App\Filters\WorkOrderFilters;
+use App\Order;
+use App\Services\OrderService;
+use App\Services\WorkOrderService;
+use App\WorkOrder;
+use App\WorkOrderChildType;
+use App\WorkOrderType;
+use Carbon\Carbon;
+use Illuminate\Http\Request;
+use Illuminate\Support\Facades\Auth;
+use Illuminate\Support\Facades\Gate;
+
+class WorkOrderController extends Controller
+{
+    public function index(Request $request, WorkOrderFilters $filters)
+    {
+        if(!Gate::allows('订单管理-工单处理-查询'))return redirect('/');
+
+        $workOrders = WorkOrder::query()->filter($filters)->with('type', 'childType', 'creator', 'order.packages','reviewer')->orderByDesc('created_at','grad','status')->paginate($request['paginate'] ?? 50);
+        return view('order.workOrder.index', compact('workOrders'));
+    }
+
+    public function create()
+    {
+        if(!Gate::allows('订单管理-工单处理-创建'))return redirect('/');
+        $workOrderTypes = WorkOrderType::query()->with('childTypes')->get();
+        $grads = WorkOrder::$enums['grad'];
+        array_shift($grads);
+        return view('order.workOrder.create', compact('workOrderTypes', 'grads'));
+    }
+
+
+    public function store(Request $request, WorkOrderService $service)
+    {
+        if(!Gate::allows('订单管理-工单处理-创建'))return redirect('/');
+        $result = $service->createWordOrder($request->all());
+        $workOrderTypes = WorkOrderType::query()->with('childTypes')->get();
+        $grads = WorkOrder::$enums['grad'];
+        array_shift($grads);
+        return view('order.workOrder.create', compact('workOrderTypes', 'result', 'grads'));
+    }
+
+    // 创建
+    public function storeApi(Request $request): array
+    {
+        if(!Gate::allows('订单管理-订单-生成工单'))return ['success' => false,'message' => '没有对应的创建权限'];
+        $order_nos = $request['order_nos'];
+
+        app(OrderService::class)->syncOrderInfoByWmsOrderNos($order_nos);
+
+        $orders = Order::query()->whereIn('code', $order_nos)->get();
+
+        $work_orders = WorkOrder::query()->with('order')->where('outer_table_name', 'orders')->whereIn('outer_table_id', $orders->map(function($item){
+            return $item['id'];
+        }))->get();
+        $exists_nos = $work_orders->map(function ($item) {
+            return $item->order->code;
+        });
+        if (count($exists_nos) > 0)
+            return ['success' => false, 'message' => join(',',$exists_nos->toArray()) . '  已有对应的工单'];
+
+        $inner_params = [];
+
+        $creator_id = Auth::user()['id'];
+
+        $work_order_type = WorkOrderType::query()->firstOrCreate(['name'=> '订单']);
+
+        $work_order_child_type= WorkOrderChildType::query()->firstOrCreate(['name' => '拦截','work_order_type_id' => $work_order_type['id'],'table_name' => 'orders']);
+        $datetime = Carbon::now();
+        foreach ($orders as $order) {
+            $inner_params[] = [
+                'work_order_type_id' => $work_order_type['id'],
+                'work_order_child_type_id' => $work_order_child_type['id'],
+                'outer_table_name' => $work_order_child_type['table_name'],
+                'outer_table_id' => $order['id'],
+                'remark' => "拦截订单:{$order['code']}",
+                'creator_id' => $creator_id,
+                'grad' => $request['grad'] ?? 1,
+                'status' => 1,
+                'updated_at' => $datetime,
+                'created_at' => $datetime,
+            ];
+        }
+        WorkOrder::query()->insert($inner_params);
+        return ['success' => true];
+    }
+
+    // 审核
+    public function reviewApi(Request $request, WorkOrderService $service): array
+    {
+        if(!Gate::allows('订单管理-工单处理-审核'))return ['success' => false,'message' => '没有对应的编辑权限'];
+        $workOrder = WorkOrder::query()->find($request['id']);
+        return $service->reviewWordOrder($workOrder);
+    }
+
+    public function show(WorkOrder $workOrder)
+    {
+        //
+    }
+
+
+    public function edit(WorkOrder $workOrder)
+    {
+        //
+    }
+
+
+    public function update(Request $request, WorkOrder $workOrder)
+    {
+        //
+    }
+
+
+    public function destroy(WorkOrder $workOrder)
+    {
+        //
+    }
+}

+ 9 - 0
app/Http/Controllers/WorkOrderTypeController.php

@@ -0,0 +1,9 @@
+<?php
+
+namespace App\Http\Controllers;
+
+
+class WorkOrderTypeController extends Controller
+{
+
+}

+ 6 - 0
app/Providers/AppServiceProvider.php

@@ -164,6 +164,9 @@ use App\Services\MaterialBoxModelService;
 use App\Services\HandInStorageService;
 use App\Services\RequirementService;
 use App\Services\RequirementUserService;
+use App\Services\WorkOrderService;
+use App\Services\WorkOrderTypeService;
+use App\Services\WorkOrderChildTypeService;
 
 class AppServiceProvider extends ServiceProvider
 {
@@ -380,6 +383,9 @@ class AppServiceProvider extends ServiceProvider
         app()->singleton('WaybillFinancialService', WaybillFinancialService::class);
         app()->singleton('WeighExceptedService', WeighExceptedService::class);
         app()->singleton('WaybillService', WaybillService::class);
+        app()->singleton('WorkOrderChildTypeService',WorkOrderChildTypeService::class);
+        app()->singleton('WorkOrderService',WorkOrderService::class);
+        app()->singleton('WorkOrderTypeService',WorkOrderTypeService::class);
     }
 
     private function registerObserver()

+ 13 - 0
app/Services/WorkOrderChildTypeService.php

@@ -0,0 +1,13 @@
+<?php 
+
+namespace App\Services;
+
+use App\Traits\ServiceAppAop;
+use App\WorkOrderChildType;
+
+class WorkOrderChildTypeService
+{
+    use ServiceAppAop;
+    protected $modelClass=WorkOrderChildType::class;
+
+}

+ 38 - 0
app/Services/WorkOrderService.php

@@ -0,0 +1,38 @@
+<?php
+
+namespace App\Services;
+
+use App\Traits\ServiceAppAop;
+use App\WorkOrder;
+use Illuminate\Support\Carbon;
+use Illuminate\Support\Facades\Auth;
+
+class WorkOrderService
+{
+    use ServiceAppAop;
+    protected $modelClass=WorkOrder::class;
+
+    // 创建工单
+    public function createWordOrder($params): array
+    {
+        $params['status'] = 1;
+        $params['creator_id'] = Auth::user()['id'];
+        $params['grad']  ?? $params['grad'] = 1;
+        $workOrder = WorkOrder::query()->create($params);
+        return ['success' => false,'data' => $workOrder];
+    }
+
+    // 审核工单
+    public function reviewWordOrder($wordOrder): array
+    {
+        $wordOrder->update([
+            'reviewer_id' =>Auth::user()['id'],
+            'review_at' => Carbon::now(),
+            'status' => 2,
+        ]);
+        $wordOrder = WorkOrder::query()->with('type', 'childType', 'creator', 'order.packages','reviewer')->find($wordOrder['id']);
+        return ['success' => true,'data' => $wordOrder];
+    }
+
+
+}

+ 14 - 0
app/Services/WorkOrderTypeService.php

@@ -0,0 +1,14 @@
+<?php
+
+namespace App\Services;
+
+use App\Traits\ServiceAppAop;
+use App\WorkOrderType;
+
+class WorkOrderTypeService
+{
+    use ServiceAppAop;
+    protected $modelClass=WorkOrderType::class;
+
+
+}

+ 111 - 0
app/WorkOrder.php

@@ -0,0 +1,111 @@
+<?php
+
+namespace App;
+
+use App\Traits\ModelTimeFormat;
+use Illuminate\Database\Eloquent\Model;
+
+use App\Traits\ModelLogChanging;
+use Illuminate\Database\Eloquent\Relations\BelongsTo;
+use Illuminate\Database\Eloquent\SoftDeletes;
+
+class WorkOrder extends Model
+{
+    use ModelLogChanging;
+    use ModelTimeFormat;
+    use SoftDeletes;
+
+    // 工单 信息
+    protected $fillable = ['status', 'creator_id', 'reviewer_id', 'work_order_type_id', 'work_order_child_type_id', 'grad', 'remark', 'outer_table_name', 'outer_table_id', 'review_at'];
+
+    static public $enums = [
+        'status' => [
+            '' => 0,
+            '待审核' => 1,
+            '已处理' => 2,
+        ],
+        'grad' => [
+            '' => 0,
+            '一般' => 1,
+            '重要' => 2,
+            '紧急' => 3,
+            '重要且紧急' => 4,
+        ],
+    ];
+
+    function __construct(array $attributes = [])
+    {
+        foreach (self::$enums as &$enum) {
+            $enum = $enum + array_flip($enum);
+        }
+        parent::__construct($attributes);
+    }
+
+    public function getStatusAttribute($value)
+    {
+        if (!$value) return '';
+        return self::$enums['status'][$value];
+    }
+
+    public function setStatusAttribute($value)
+    {
+        if (!$value) return 0;
+        if (is_numeric($value)) {
+            $this->attributes['status'] = $value;
+        } else {
+            $this->attributes['status'] = self::$enums['status'][$value];
+        }
+    }
+
+    public function getGradAttribute($value)
+    {
+        if (!$value) return '';
+        return self::$enums['grad'][$value];
+    }
+
+    public function setGradAttribute($value)
+    {
+        if (!$value) return 0;
+        if (is_numeric($value)) {
+            $this->attributes['grad'] = $value;
+        } else {
+            $this->attributes['grad'] = self::$enums['grad'][$value];
+        }
+    }
+
+    // 创建人
+    public function creator(): BelongsTo
+    {
+        return $this->belongsTo(User::class, 'creator_id');
+    }
+
+    // 审核人
+    public function reviewer(): BelongsTo
+    {
+        return $this->belongsTo(User::class, 'reviewer_id');
+    }
+
+    // 关联订单
+    public function order(): BelongsTo
+    {
+        return $this->belongsTo(Order::class, 'outer_table_id');
+    }
+
+    // 类型
+    public function type(): BelongsTo
+    {
+        return $this->belongsTo(WorkOrderType::class, 'work_order_type_id', 'id');
+    }
+
+    // 子类型
+    public function childType(): BelongsTo
+    {
+        return $this->belongsTo(WorkOrderChildType::class, 'work_order_child_type_id', 'id');
+    }
+
+    public function scopeFilter($query, $filters)
+    {
+        return $filters->apply($query);
+    }
+
+}

+ 16 - 0
app/WorkOrderChildType.php

@@ -0,0 +1,16 @@
+<?php
+
+namespace App;
+
+use Illuminate\Database\Eloquent\Model;
+
+use App\Traits\ModelLogChanging;
+
+class WorkOrderChildType extends Model
+{
+    use ModelLogChanging;
+
+    // 工单类型 子 类型
+    protected $fillable = ['work_order_type_id','name','table_name'];
+
+}

+ 21 - 0
app/WorkOrderType.php

@@ -0,0 +1,21 @@
+<?php
+
+namespace App;
+
+use Illuminate\Database\Eloquent\Model;
+
+use App\Traits\ModelLogChanging;
+use Illuminate\Database\Eloquent\Relations\HasMany;
+
+class WorkOrderType extends Model
+{
+    use ModelLogChanging;
+
+    // 工单 类型
+    protected $fillable = ['name'];
+
+    public function childTypes(): HasMany
+    {
+        return $this->hasMany(WorkOrderChildType::class);
+    }
+}

+ 14 - 0
database/factories/WorkOrderChildTypeFactory.php

@@ -0,0 +1,14 @@
+<?php
+
+/** @var \Illuminate\Database\Eloquent\Factory $factory */
+
+use App\WorkOrderChildType;
+use Faker\Generator as Faker;
+
+$factory->define(WorkOrderChildType::class, function (Faker $faker) {
+    return [
+        'work_order_type_id' =>rand(1,10),
+        'name' => $faker->name(),
+        'table_name' => $faker->name(),
+    ];
+});

+ 11 - 0
database/factories/WorkOrderFactory.php

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

+ 12 - 0
database/factories/WorkOrderTypeFactory.php

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

+ 42 - 0
database/migrations/2021_08_04_093716_create_work_orders_table.php

@@ -0,0 +1,42 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+class CreateWorkOrdersTable extends Migration
+{
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        Schema::create('work_orders', function (Blueprint $table) {
+            $table->id();
+            $table->integer('creator_id')->comment('创建人');
+            $table->integer('reviewer_id')->nullable()->comment('审核人');
+            $table->integer('work_order_type_id')->comment('类型');
+            $table->integer('work_order_child_type_id')->comment('子类型');
+            $table->string('outer_table_name')->comment('关联表名');
+            $table->integer('outer_table_id')->comment('关联表id');
+            $table->tinyInteger('grad')->comment('工单等级');
+            $table->tinyInteger('status')->comment('工单状态');
+            $table->string('remark')->comment('描述信息');
+            $table->dateTime('review_at')->default(null)->nullable()->comment('审核时间');
+            $table->softDeletes();
+            $table->timestamps();
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        Schema::dropIfExists('work_orders');
+    }
+}

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

@@ -0,0 +1,32 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+class CreateWorkOrderTypesTable extends Migration
+{
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        Schema::create('work_order_types', function (Blueprint $table) {
+            $table->id();
+            $table->string('name')->comment('工单类型');
+            $table->timestamps();
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        Schema::dropIfExists('work_order_types');
+    }
+}

+ 34 - 0
database/migrations/2021_08_04_101906_create_work_order_child_types_table.php

@@ -0,0 +1,34 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+class CreateWorkOrderChildTypesTable extends Migration
+{
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        Schema::create('work_order_child_types', function (Blueprint $table) {
+            $table->id();
+            $table->tinyInteger('work_order_type_id')->comment('工单类型');
+            $table->string('name')->comment('子类型名称');
+            $table->string('table_name')->comment('关联表');
+            $table->timestamps();
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        Schema::dropIfExists('work_order_child_types');
+    }
+}

+ 18 - 0
database/seeds/WorkOrderChildTypeSeeder.php

@@ -0,0 +1,18 @@
+<?php
+
+use App\WorkOrderChildType;
+use Illuminate\Database\Seeder;
+
+class WorkOrderChildTypeSeeder extends Seeder
+{
+    /**
+     * Run the database seeds.
+     *
+     * @return void
+     */
+    public function run()
+    {
+        $params = factory(WorkOrderChildType::class)->times(30)->make()->toArray();
+        WorkOrderChildType::query()->insert($params);
+    }
+}

+ 16 - 0
database/seeds/WorkOrderSeeder.php

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

+ 18 - 0
database/seeds/WorkOrderTypeSeeder.php

@@ -0,0 +1,18 @@
+<?php
+
+use App\WorkOrderType;
+use Illuminate\Database\Seeder;
+
+class WorkOrderTypeSeeder extends Seeder
+{
+    /**
+     * Run the database seeds.
+     *
+     * @return void
+     */
+    public function run()
+    {
+        $params = factory(WorkOrderType::class)->times(10)->make()->toArray();
+        WorkOrderType::query()->insert($params);
+    }
+}

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

@@ -34,7 +34,11 @@
                         <button class="btn btn-sm btn-outline-dark ml-1"@click="isRejectedBillExist()"
                             style="opacity: 0.7">生成退货单</button>
                     @endcan
+
                     <button class="btn btn-sm ml-1 btn-primary" @click="copyLogisticNumber()">复制快递单号</button>
+                    @can('订单管理-订单-生成工单')
+                    <button class="btn btn-sm ml-1 btn-outline-secondary" @click="showInterceptModel()">订单拦截</button>
+                    @endcan
                 </div>
                 <div class="modal fade " style="top: 20%" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
                     <div class="modal-dialog">
@@ -219,6 +223,39 @@
                         </div>
                     </div>
                 </div>
+
+                <div class="modal fade " id="intercept-modal" tabindex="-1" role="dialog" aria-labelledby="checkModalLabel" aria-hidden="true">
+                    <div class="modal-dialog modal-dialog-centered">
+                        <div class="modal-content">
+                            <div class="modal-header">
+                                <h5 class="modal-title" id="checkModalLabel">拦截工单生成提示</h5>
+                                <button type="button" class="close" data-dismiss="modal" aria-label="Close"  >
+                                    <span aria-hidden="true">&times;</span>
+                                </button>
+                            </div>
+                            <div class="modal-body">
+                                <div class="form-group">
+                                    <label for="grad" class="">任务紧急程度</label>
+                                    <div class="pl-1">
+                                        <div v-for="(item,i) in grads">
+                                            <input type="radio" :id="'grad'+i" name="grad" :value="item.value" v-model="grad">
+                                            <label :for="'grad'+i">@{{ item.name }}</label>
+                                        </div>
+                                    </div>
+                                </div>
+                            </div>
+                            <div class="modal-footer">
+                                <button type="button" class="btn btn-secondary" data-dismiss="modal">关闭
+                                </button>
+                                <button type="button" class="btn btn-outline-primary" @click="interceptOrder">
+                                    提交
+                                </button>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+
+
                 <textarea  id="clipboardDiv" style="opacity:0"></textarea>
             </div>
         </div>
@@ -272,6 +309,13 @@
                     merchantInfo:'',
                 },
                 upList:{},
+                grad:1,
+                grads:[
+                    {name:'一般',value:'1'},
+                    {name:'重要',value:'2'},
+                    {name:'紧急',value:'3'},
+                    {name:'重要且紧急',value:'4'},
+                ]
             },
             mounted:function () {
                 this.initData();
@@ -880,6 +924,34 @@
                         });
                     }else {char+=order.soreference5}
                     return char;
+                },
+                showInterceptModel(){
+                    this.grad = 1;
+                    if(checkData.length === 0){
+                        tempTip.show('选中订单在进行操作');
+                        return;
+                    }
+                    $('#intercept-modal').modal('show');
+                },
+                interceptOrder(){    // 订单拦截
+                    let url = '{{url('apiLocal/workOrder/store')}}';
+                    let data = {
+                        work_order_type:'订单',
+                        work_order_child_type:'拦截',
+                        order_nos:checkData,
+                        grad:this.grad,
+                    }
+                    window.tempTip.setIndex(1999);
+                    window.axios.post(url,data).then(res=>{
+                        if (res.data.success){
+                            window.tempTip.showSuccess('生成订单拦截成功');
+                            $('#intercept-modal').modal('hide');
+                        }else{
+                            window.tempTip.show(res.data.message);
+                        }
+                    }).catch(err=>{
+                        window.tempTip.show(err);
+                    });
                 }
             },
         });

+ 198 - 0
resources/views/order/workOrder/create.blade.php

@@ -0,0 +1,198 @@
+@extends("layouts.app")
+
+@section("content")
+    <div class="container-fluid d-none card" id="list">
+        @if(isset($reslut))
+            <div @if($reslut['success']) class="alert-success" @else class="alert-warning" @endif>
+                {{ $reslut['message'] }}
+            </div>
+        @endif
+
+        <div class="card-body bg-light">
+            <div class="col-8 offset-2 row bg-white">
+                <span class="btn col-4 left" @click="changeStep(1)">
+                    <!-- 三种:选中,未选,编辑后-->
+                    <span class="fa-stack fa-lg">
+                        <template v-if="step === 1">
+                            <i class="fa fa-circle-thin fa-stack-2x" style="color: #269dec"></i>
+                            <span class="fa" style="color:#269dec">1</span>
+                        </template>
+                        <template v-if="step > 1">
+                            <i class="fa fa-check-circle-o fa-stack-2x" style="color: #269dec"></i>
+                        </template>
+                    </span>
+                    选择工单类型
+                </span>
+                <!--  fa-check-circle-o 选中-->
+                <span class="btn col-4 left" @click="changeStep(2)">
+                    <span class="fa-stack fa-lg">
+                        <template v-if="step === 2">
+                            <i class="fa fa-circle-thin fa-stack-2x" style="color: #269dec"></i>
+                            <span style="color:#269dec">2</span>
+                        </template>
+                        <template v-if="step < 2">
+                             <i class="fa fa-circle-thin fa-stack-2x" style="color: #888"></i>
+                             <span style="color:#888">2</span>
+                        </template>
+                        <template v-if="step > 2">
+                            <i class="fa fa-check-circle-o fa-stack-2x" style="color: #269dec"></i>
+                        </template>
+                    </span>
+                    选择工单子类型
+                </span>
+                <span class="btn col-4 left" @click="changeStep(3)">
+                       <span class="fa-stack fa-lg">
+                            <template v-if="step === 3">
+                                <i class="fa fa-circle-thin fa-stack-2x" style="color: #269dec"></i>
+                                <span style="color:#269dec">3</span>
+                            </template>
+                            <template v-if="step < 3">
+                                <i class="fa fa-circle-thin fa-stack-2x" style="color: #888"></i>
+                                <span style="color: #888">3</span>
+                            </template>
+                        </span>
+                    创建工单
+                </span>
+            </div>
+            <hr class="">
+            <div class="card-body bg-light">
+
+                <div class="col-8 offset-2 row bg-white card" v-if="step === 1">
+                    <div class="card-body">
+                        <div v-for="(item) in workOrderTypes" class="col-4  d-inline-block ">
+                            <div class="p-3 m-2 bg-light text-break" @click="selectWorkOrderType(item)">
+                                <strong> @{{ item.name }}</strong>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+
+                <div class="col-8 offset-2 row bg-white card" v-if="step === 2">
+                    <div class="card-body">
+                        <div v-for="(item) in workOrderChildTypes" class="col-4 d-inline-block">
+                            <div class="p-3 m-2 bg-light text-break" @click="selectWorkOrderChildType(item)">
+                                <strong> @{{ item.name }}</strong>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+                <div class="col-8 offset-2 row bg-white card" v-if="step === 3">
+                    <form action="{{url("order/workOrder/store")}}" method="post" id="store_form">
+                        @csrf
+                        @method('POST')
+                        <input type="text" class="d-none" name="work_order_type_id" :value="workOrder.work_order_type_id">
+                        <input type="text" class="d-none" name="work_order_child_type_id"
+                               :value="workOrder.work_order_child_type_id">
+                        <div class="card-body">
+                            <div class="form-group">
+                                <label for="grad" class="">任务紧急程度</label>
+                                <div class="pl-1">
+                                    <div v-for="(item,i) in grads">
+                                        <input type="radio" :id="'grad'+i" name="grad" :value="item.value" v-model="workOrder.grad">
+                                        <label :for="'grad'+i">@{{ item.name }}</label>
+                                    </div>
+                                </div>
+                            </div>
+                            <div class="form-group">
+                                <label for="remark">详细内容</label>
+                                <textarea class="form-control" name="remark" id="remark" v-model="workOrder.remark">
+                            </textarea>
+                            </div>
+                            <div class="form-group">
+                                <button class="btn btn-md btn-outline-primary" type="button" @click="checkSubmit">提交</button>
+                            </div>
+
+                        </div>
+                    </form>
+                </div>
+            </div>
+        </div>
+    </div>
+
+@endsection()
+
+@section("lastScript")
+    <script>
+        let list = new Vue({
+            el: "#list",
+            data: {
+                step: 1,
+                workOrderTypes: [
+                        @foreach($workOrderTypes as $workOrderType)
+                    {
+                        id: '{{$workOrderType->id}}',
+                        name: '{{$workOrderType->name}}',
+                        child_types: [
+                                @foreach($workOrderType->childTypes  as $type)
+                            {
+                                id: '{{$type->id}}', name: '{{$type->name}}',
+                            },
+                            @endforeach
+                        ],
+                    },
+                    @endforeach],
+                workOrderChildTypes: [],
+                grads: [
+                        @foreach($grads as $key=>$item)
+                    {
+                        name: '{{$key}}', value: '{{$item}}'
+                    },
+                    @endforeach
+                ],
+                workOrder: {
+                    work_order_type_id: null,
+                    work_order_child_type_id: null,
+                    grad: 1,
+                    remark:null,
+                },
+            },
+            watch: {
+                step: function (newValue, OldValue) {
+                    if (newValue === 1) {
+                        this.workOrder.work_order_child_type_id = null;
+                        this.workOrder.grad = 1;
+                    } else if (newValue === 2) {
+                        this.workOrder.grad = 1;
+                    }
+                },
+            },
+            created() {
+                $("#list").removeClass("d-none");
+            },
+            methods: {
+                changeStep(step) {
+                    if (step < this.step) {
+                        this.step = step;
+                        return;
+                    }
+                    if (step === 2) {
+                        if (this.workOrder.work_order_type_id === null) return;
+                        else this.step = step;
+                    } else if (step === 3) {
+                        if (this.workOrder.work_order_child_type_id === null) return;
+                        else this.step = step;
+                    }
+                },
+                selectWorkOrderType(item) {
+                    this.workOrder.work_order_type_id = item.id;
+                    this.workOrderChildTypes = item['child_types'];
+                    this.changeStep(2);
+                },
+                selectWorkOrderChildType(item) {
+                    this.workOrder.work_order_child_type_id = item.id;
+                    this.changeStep(3);
+                },
+                checkSubmit(){
+                    if (this.workOrder.grad === null){
+                        return false;
+                    }
+                    if (this.workOrder.remark === null){
+                        window.tempTip.show("详细内容未必填项!");
+                        return false;
+                    }
+                    document.getElementById('store_form').submit();
+                },
+            }
+        });
+    </script>
+@endsection

+ 156 - 0
resources/views/order/workOrder/index.blade.php

@@ -0,0 +1,156 @@
+@extends("layouts.app")
+@section('title','处理工单')
+@section("content")
+    <div class="container-fluid d-none" id="list">
+        <div id="form_div" style="min-width: 2250px;"></div>
+        <table class="table table-striped table-md">
+            <thead>
+            <tr class="text-center">
+                <th>序号</th>
+                <th>工单编号</th>
+                <th>工单等级</th>
+                <th>相关类型</th>
+                <th>问题描述</th>
+                <th>状态</th>
+                <th>创建人</th>
+                <th>提交时间</th>
+                <th>物流跟踪信息</th>
+                <th>审核人</th>
+                <th>审核时间</th>
+                <th>操作</th>
+            </tr>
+            </thead>
+            <tbody class="text-center">
+            <template v-for="(item,i) in workOrders">
+                <tr @click="selectTr===i+1?selectTr=0:selectTr=i+1" :class="selectTr===i+1?'focusing' : ''">
+                    <td>@{{i+1}}</td>
+                    <td>@{{item.id}}</td>
+                    <td>
+                        <template v-if="item.status === '已处理'">
+                            <span class="badge badge-secondary">@{{ item.grad }}</span>
+                        </template>
+                        <template v-else>
+                            <span class="badge badge-light" v-if="item.grad === '一般'">@{{ item.grad }}</span>
+                            <span class="badge badge-info" v-if="item.grad === '重要'">@{{ item.grad }}</span>
+                            <span class="badge badge-warning" v-if="item.grad === '紧急'">@{{ item.grad }}</span>
+                        </template>
+                    </td>
+                    <td>@{{item.type ? item.type.name : '' }} - @{{ item.child_type ? item.child_type.name : '' }}</td>
+                    <td>@{{ item.remark }}</td>
+                    <td>
+                        @{{ item.status }}
+                    </td>
+                    <td>@{{ item.creator.name }}</td>
+                    <td>@{{ item.created_at }}</td>
+                    <td>
+                        <template v-if="item.review_at">
+                            <div v-if="item.order && item.order.packages">
+                                <template v-for="package in item.order.packages">
+                                    <template v-if="package.transfer_status && package.transfer_status.length > 0">
+                                        <div v-if="selectOrderPackage === package.id">
+                                            <template v-for="transfer in package.transfer_status">
+                                                <p>@{{ transfer['accept_time']+':'+transfer['accept_address'] }}</p>
+                                            </template>
+                                        </div>
+                                        <div v-else>
+                                            @{{ package.transfer_status[0]['accept_time']+':'+package.transfer_status[0]['accept_address'] }}
+                                        </div>
+                                        <button class="btn btn-sm btn-outline-primary" v-if="selectOrderPackage !== package.id" @click="selectOrderPackage = package.id">展开</button>
+                                        <button class="btn btn-sm btn-outline-primary" v-else @click="selectOrderPackage = null">收起</button>
+                                    </template>
+                                </template>
+                            </div>
+                        </template>
+                    </td>
+                    <td>@{{ item.reviewer ? item.reviewer.name : ''}}</td>
+                    <td>@{{ item.review_at }}</td>
+                    <td>
+                        @can('订单管理-工单处理-审核')
+                            <button class="btn btn-sm btn-outline-primary" v-if="item.status !== '已处理'"
+                                    @click="reviewWorkOrder(item,i)">审核
+                            </button>
+                        @endcan()
+                    </td>
+                </tr>
+            </template>
+            </tbody>
+            {{ $workOrders->withQueryString()->links() }}
+        </table>
+    </div>
+@endsection()
+
+@section("lastScript")
+    <script type="text/javascript" src="{{mix('js/queryForm/queryForm.js')}}"></script>
+    <script>
+        let list = new Vue({
+            el: "#list",
+            data: {
+                workOrders: {!! $workOrders->toJson() !!}['data'],
+                selectTr: null,
+                form:null,
+                selectOrderPackage:null,
+            },
+            mounted() {
+                let data = [[
+                    {name: 'created_at_start', type: 'time', tip:['工单创建开始日期','时间']},
+                    {name: 'created_at_end', type: 'time', tip:['工单创建结束日期','时间']},
+                    {name: 'review_at_start', type: 'time', tip:['工单审核开始日期','时间']},
+                    {name: 'review_at_end', type: 'time', tip:['工单审核结束日期','时间']},
+                ]];
+                this.form = new query({
+                    el: '#form_div',
+                    condition: data,
+                    appendDom: "btn",
+                    paginations: [50, 100, 200, 500, 1000, 20],
+                })
+                this.form.init();
+                $("#list").removeClass("d-none");
+            },
+            created() {
+                let self = this;
+                $.each(this.workOrders, function (index, workOrder) {
+                    if (!workOrder.order) return ;
+                    if (!workOrder.order.packages) return ;
+                    self.sortOrder(workOrder);
+                });
+            },
+            methods: {
+                sortOrder(workOrder){
+                    let self = this;
+                    if (!workOrder.order) return ;
+                    if (!workOrder.order.packages) return ;
+                    $.each(workOrder.order.packages,function(i,item){
+                        self.sortTransfer(item);
+                    })
+                },
+                sortTransfer(item){
+                    if (!("transfer_status"  in item))return ;
+                    if (item.transfer_status == null ||  !(item.transfer_status instanceof Array)) return ;
+                    item.transfer_status.sort(function (item1, item2) {
+                        let date1 = new Date(item1['accept_time']);
+                        let date2 = new Date(item2['accept_time']);
+                        if (date1 - date2 > 0) return -1;
+                        if (date1 - date2 < 0) return 1;
+                        return 0;
+                    });
+                },
+                // todo 审核工单
+                reviewWorkOrder(item, i) {
+                    let url = '{{url('apiLocal/workOrder/review')}}';
+                    let data = {id: item.id};
+                    window.axios.post(url, data).then(res => {
+                        if (res.data.success) {
+                            this.$set(this.workOrders, i, res.data.data);
+                            this.sortOrder(res.data.data);
+                            window.tempTip.showSuccess("审核完成");
+                        } else {
+                            window.tempTip.show(res.data.message ?  res.data.message : '审核异常');
+                        }
+                    }).catch(err => {
+                        window.tempTip.show(err)
+                    })
+                },
+            },
+        });
+    </script>
+@endsection

+ 5 - 0
routes/apiLocal.php

@@ -227,3 +227,8 @@ Route::group(['prefix' => 'package'], function () {
 Route::group(['prefix' => 'print'],function (){
     Route::post('template/store','PrintTemplateController@storeAi');
 });
+
+Route::prefix('workOrder')->group(function(){
+    Route::post('store','WorkOrderController@storeApi');
+    Route::post('review','WorkOrderController@reviewApi');
+});

+ 5 - 0
routes/web.php

@@ -777,6 +777,10 @@ Route::group(['middleware'=>'auth'],function ($route){
         Route::post('resetInterfaceReturnMark','OrderController@resetInterfaceReturnMark');
         Route::post('createRejectedBill','OrderController@createRejectedBill');
         Route::post('isRejectedBillExist','OrderController@isRejectedBillExist');
+        /** 工单 */
+        Route::prefix('workOrder')->group(function(){
+            Route::get('index','WorkOrderController@index');
+        });
     });
     /** 结算 */
     $route->group(['prefix'=>'finance'],function(){
@@ -1010,3 +1014,4 @@ Route::group(['middleware'=>'auth'],function ($route){
     });
 
 });
+