taskable->setRelation('task', $task->withoutRelations()); } return $task; } public function store($data): bool { if (! isset($data['plan_id'])) { admin_abort('任务计划未找到'); } /** @var \App\Models\Plan */ $plan = Plan::findOrFail($data['plan_id']); if (! $plan->isPublished()) { admin_abort('任务计划未发布'); } switch (get_class($planable = $plan->planable)) { // 业绩指标 case PlanPerformance::class: $payload = $data['task_performance'] ?? []; Validator::validate( data: $payload, rules: [ 'store_id' => ['bail', 'required'], 'expected_performance' => ['bail', 'required', 'numeric', 'min:0'], ], attributes: [ 'store_id' => __('plan.task_performance.store'), 'expected_performance' => __('plan.task_performance.expected_performance'), ], ); /** @var \App\Models\Store */ $store = Store::findOrFail($payload['store_id']); if (TaskPerformance::where('store_id', $store->id)->where('month', $planable->month)->exists()) { admin_abort('门店已有业绩指标任务'); } // 开始时间 $startAt = Carbon::createFromFormat('Y-m-d H:i:s', "{$planable->month}-01 00:00:00"); // 结束时间 $endAt = $startAt->copy()->endOfMonth(); // 门店实际业绩 $actualPerformance = Ledger::where('store_id', $store->id) ->whereBetween('date', [$startAt->format('Y-m-d'), $endAt->format('Y-m-d')]) ->sum('sales'); /** @var \App\Models\TaskPerformance */ $taskable = TaskPerformance::create([ 'month' => $planable->month, 'store_id' => $store->id, 'store_master_id' => $store->master_id, 'actual_performance' => $actualPerformance, 'expected_performance' => $payload['expected_performance'], ]); $task = new Task([ 'plan_id' => $plan->id, 'name' => '业绩指标', 'start_at' => $startAt, 'end_at' => $endAt, 'task_status' => TaskStatus::Pending, ]); if ($taskable->isSuccess()) { $task->task_status = TaskStatus::Success; $task->completed_at = now(); } $taskable->task()->save($task); break; // 清洁卫生 case PlanHygiene::class: $payload = $data['task_hygiene'] ?? []; Validator::validate( data: $payload, rules: [ 'store_id' => ['bail', 'required'], ], attributes: [ 'store_id' => __('plan.task_hygiene.store'), ], ); /** @var \App\Models\Store */ $store = Store::findOrFail($payload['store_id']); if (TaskHygiene::where('store_id', $store->id)->where('month', $planable->month)->exists()) { admin_abort('门店已有清洁卫生任务'); } $taskable = TaskHygiene::create([ 'month' => $planable->month, 'store_id' => $store->id, 'store_master_id' => $store->master_id, ]); // 开始时间 $startAt = Carbon::createFromFormat('Y-m-d H:i:s', "{$planable->month}-01 00:00:00"); // 结束时间 $endAt = $startAt->copy()->endOfMonth(); $taskable->task()->create([ 'plan_id' => $plan->id, 'name' => '清洁卫生', 'start_at' => $startAt, 'end_at' => $endAt, 'task_status' => TaskStatus::Pending, ]); break; default: admin_abort('任务计划不可新增任务'); break; } return true; } public function update($primaryKey, $data): bool { /** @var \App\Models\Task */ $task = Task::findOrFail($primaryKey); if (in_array($task->task_status, [TaskStatus::Success, TaskStatus::Failed])) { admin_abort("[{$task->task_status->text()}]任务不可修改"); } switch (get_class($taskable = $task->taskable)) { // 业绩指标 case TaskPerformance::class: $payload = $data['task_performance'] ?? []; Validator::validate( data: $payload, rules: [ 'expected_performance' => ['bail', 'required', 'numeric', 'min:0'], ], attributes: [ 'expected_performance' => __('plan.task_performance.expected_performance'), ], ); $taskable->update([ 'expected_performance' => $payload['expected_performance'], ]); if (! $task->isSuccess() && $taskable->isSuccess()) { $task->markAsSuccess(); } break; default: admin_abort('任务不可修改'); break; } return true; } public function preDelete(array $ids): void { /** @var \Illuminate\Database\Eloquent\Collection */ $tasks = Task::findMany($ids); $tasks->each(fn (Task $task) => $task->taskable->delete()); } public function addRelations($query, string $scene = 'list') { if (in_array($scene, ['edit', 'detail'])) { $query->with([ 'taskable' => function (MorphTo $morphTo) { $morphTo->morphWith([ TaskLedger::class => ['store', 'storeMaster'], TaskPerformance::class => ['store', 'storeMaster'], TaskHygiene::class => ['store', 'storeMaster', 'workflow'], ]); }, ]); } } }