diff --git a/app/Admin/Controllers/Plan/PlanController.php b/app/Admin/Controllers/Plan/PlanController.php
index 02f10a4..7314f26 100644
--- a/app/Admin/Controllers/Plan/PlanController.php
+++ b/app/Admin/Controllers/Plan/PlanController.php
@@ -5,6 +5,7 @@ namespace App\Admin\Controllers\Plan;
use App\Admin\Controllers\AdminController;
use App\Admin\Services\Plan\PlanService;
use App\Enums\PlanStatus;
+use App\Enums\TaskHygieneStatus;
use App\Enums\TaskLedgerStatus;
use App\Enums\TaskPerformanceStatus;
use App\Enums\TaskStatus;
@@ -246,12 +247,10 @@ class PlanController extends AdminController
amis('reload')->align('right'),
])
->columns([
- // amis()->TableColumn('id', __('plan.task.id')),
- // amis()->TableColumn('name', __('plan.task.name')),
amis()->TableColumn('taskable.month', __('plan.task_hygiene.month')),
amis()->TableColumn('taskable.store.title', __('plan.task_hygiene.store')),
amis()->TableColumn('taskable.store_master.name', __('plan.task_hygiene.store_master')),
- amis()->TableColumn('task_status', __('plan.task.status'))->type('mapping')->map(TaskStatus::labelMap()),
+ amis()->TableColumn('taskable.task_status', __('plan.task_hygiene.status'))->type('mapping')->map(TaskHygieneStatus::labelMap()),
amis()->TableColumn('completed_at', __('plan.task.completed_at')),
amis()->TableColumn('created_at', __('plan.task.created_at')),
$this->rowActions([
diff --git a/app/Admin/Controllers/Plan/TaskController.php b/app/Admin/Controllers/Plan/TaskController.php
index d089015..799da74 100644
--- a/app/Admin/Controllers/Plan/TaskController.php
+++ b/app/Admin/Controllers/Plan/TaskController.php
@@ -27,7 +27,7 @@ class TaskController extends AdminController
$morphTo->morphWith([
TaskLedger::class => ['store', 'storeMaster'],
TaskPerformance::class => ['store', 'storeMaster'],
- TaskHygiene::class => ['store', 'storeMaster'],
+ TaskHygiene::class => ['store', 'storeMaster', 'workflow'],
]);
},
])
diff --git a/app/Enums/TaskHygieneStatus.php b/app/Enums/TaskHygieneStatus.php
new file mode 100644
index 0000000..f044a2d
--- /dev/null
+++ b/app/Enums/TaskHygieneStatus.php
@@ -0,0 +1,42 @@
+value];
+ }
+
+ public static function options(): array
+ {
+ return [
+ self::None->value => '未开始',
+ self::Pending->value => '待完成',
+ self::Checking->value => '审核中',
+ self::Unpassed->value => '未通过',
+ self::Success->value => '已完成',
+ self::Failed->value => '未完成',
+ ];
+ }
+
+ public static function labelMap(): array
+ {
+ return [
+ self::None->value => ''.self::None->text().'',
+ self::Pending->value => ''.self::Pending->text().'',
+ self::Checking->value => ''.self::Checking->text().'',
+ self::Unpassed->value => ''.self::Unpassed->text().'',
+ self::Success->value => ''.self::Success->text().'',
+ self::Failed->value => ''.self::Failed->text().'',
+ ];
+ }
+}
diff --git a/app/Enums/TaskLedgerStatus.php b/app/Enums/TaskLedgerStatus.php
index 3bc9abe..3b3da0b 100644
--- a/app/Enums/TaskLedgerStatus.php
+++ b/app/Enums/TaskLedgerStatus.php
@@ -27,7 +27,7 @@ enum TaskLedgerStatus: int
public static function labelMap(): array
{
return [
- self::None->value => ''.self::None->text().'',
+ self::None->value => ''.self::None->text().'',
self::Pending->value => ''.self::Pending->text().'',
self::Success->value => ''.self::Success->text().'',
self::Failed->value => ''.self::Failed->text().'',
diff --git a/app/Enums/TaskPerformanceStatus.php b/app/Enums/TaskPerformanceStatus.php
index ca6b218..e819028 100644
--- a/app/Enums/TaskPerformanceStatus.php
+++ b/app/Enums/TaskPerformanceStatus.php
@@ -27,7 +27,7 @@ enum TaskPerformanceStatus: int
public static function labelMap(): array
{
return [
- self::None->value => ''.self::None->text().'',
+ self::None->value => ''.self::None->text().'',
self::Pending->value => ''.self::Pending->text().'',
self::Success->value => ''.self::Success->text().'',
self::Failed->value => ''.self::Failed->text().'',
diff --git a/app/Http/Controllers/Api/TaskController.php b/app/Http/Controllers/Api/TaskController.php
index 46a20e6..67117d9 100644
--- a/app/Http/Controllers/Api/TaskController.php
+++ b/app/Http/Controllers/Api/TaskController.php
@@ -2,13 +2,19 @@
namespace App\Http\Controllers\Api;
+use App\Admin\Services\WorkFlowService;
+use App\Enums\TaskHygieneStatus;
+use App\Exceptions\RuntimeException;
use App\Http\Resources\TaskResource;
use App\Models\Task;
use App\Models\TaskHygiene;
use App\Models\TaskLedger;
use Illuminate\Contracts\Database\Eloquent\Builder;
+use Illuminate\Database\Eloquent\Relations\MorphTo;
+use Illuminate\Database\Eloquent\Relations\Relation;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
+use Throwable;
class TaskController extends Controller
{
@@ -25,7 +31,14 @@ class TaskController extends Controller
MySQL;
/** @var \Illuminate\Database\Eloquent\Collection */
- $tasks = Task::with(['taskable'])
+ $tasks = Task::with([
+ 'taskable' => function (MorphTo $morphTo) {
+ $morphTo->morphWith([
+ TaskHygiene::class => ['task', 'workflow'],
+ TaskLedger::class => ['task'],
+ ]);
+ },
+ ])
->whereHasMorph(
'taskable',
[TaskHygiene::class, TaskLedger::class],
@@ -49,4 +62,66 @@ MySQL;
return TaskResource::collection($tasks);
}
+
+ public function submit($id, Request $request)
+ {
+ $task = Task::findOrFail($id);
+
+ try {
+ DB::beginTransaction();
+
+ $this->handleTaskSubmit($task, $request);
+
+ DB::commit();
+ } catch (Throwable $th) {
+ DB::rollBack();
+ throw tap($th, fn ($th) => report($th));
+ }
+
+ return response()->json();
+ }
+
+ protected function handleTaskSubmit(Task $task, Request $request): void
+ {
+ /** @var \App\Models\Employee */
+ $user = $request->user();
+
+ switch (Relation::getMorphedModel($task->taskable_type)) {
+ case TaskHygiene::class:
+ $request->validate(
+ rules: [
+ 'task_hygiene.description' => ['bail', 'required', 'max:255'],
+ 'task_hygiene.photos' => ['bail', 'required', 'array'],
+ ],
+ attributes: [
+ 'task_hygiene.description' => '清洁范围',
+ 'task_hygiene.photos' => '清洁结果',
+ ],
+ );
+
+ switch ($task->taskable->task_status) {
+ case TaskHygieneStatus::None:
+ throw new RuntimeException('任务未开始');
+ break;
+
+ case TaskHygieneStatus::Checking:
+ throw new RuntimeException('任务审核中');
+ break;
+
+ case TaskHygieneStatus::Success:
+ throw new RuntimeException('任务已完成');
+ break;
+ }
+
+ $task->taskable->update($request->input('task_hygiene'));
+
+ (new WorkFlowService())->apply($task->taskable->workflow, $user);
+
+ break;
+
+ default:
+ throw new RuntimeException('任务不可提交');
+ break;
+ }
+ }
}
diff --git a/app/Http/Resources/TaskHygieneResource.php b/app/Http/Resources/TaskHygieneResource.php
index dd69d58..1d7c8a0 100644
--- a/app/Http/Resources/TaskHygieneResource.php
+++ b/app/Http/Resources/TaskHygieneResource.php
@@ -20,6 +20,7 @@ class TaskHygieneResource extends JsonResource
'store' => StoreResource::make($this->whenLoaded('store')),
'description' => $this->resource->description,
'photos' => $this->resource->photos,
+ 'status' => $this->resource->task_status,
'created_at' => $this->resource->created_at->timestamp,
];
}
diff --git a/app/Models/TaskHygiene.php b/app/Models/TaskHygiene.php
index b76213d..3864cf9 100644
--- a/app/Models/TaskHygiene.php
+++ b/app/Models/TaskHygiene.php
@@ -2,6 +2,7 @@
namespace App\Models;
+use App\Enums\TaskHygieneStatus;
use App\Traits\HasCheckable;
use App\Traits\HasDateTimeFormatter;
use Illuminate\Database\Eloquent\Casts\Attribute;
@@ -14,6 +15,10 @@ class TaskHygiene extends Model
{
use HasCheckable, HasFactory, HasDateTimeFormatter;
+ protected $appends = [
+ 'task_status',
+ ];
+
protected $fillable = [
'month',
'store_id',
@@ -50,4 +55,38 @@ class TaskHygiene extends Model
set: fn (mixed $value) => json_encode(is_array($value) ? $value : []),
);
}
+
+ /**
+ * 任务状态
+ */
+ protected function taskStatus(): Attribute
+ {
+ return Attribute::make(
+ get: function (mixed $value) {
+ $datetime = now();
+
+ if ($datetime->lt($this->task->start_at)) {
+ return TaskHygieneStatus::None;
+ }
+
+ if ($this->task->isSuccess() || $this->checkSuccess()) {
+ return TaskHygieneStatus::Success;
+ }
+
+ if ($this->checkProcessing()) {
+ return TaskHygieneStatus::Checking;
+ }
+
+ if ($this->checkFail()) {
+ return TaskHygieneStatus::Unpassed;
+ }
+
+ if ($datetime->lt($this->task->end_at)) {
+ return TaskHygieneStatus::Pending;
+ }
+
+ return TaskHygieneStatus::Failed;
+ },
+ );
+ }
}
diff --git a/app/Models/TaskLedger.php b/app/Models/TaskLedger.php
index 4fcc565..358ff31 100644
--- a/app/Models/TaskLedger.php
+++ b/app/Models/TaskLedger.php
@@ -45,22 +45,22 @@ class TaskLedger extends Model
protected function taskStatus(): Attribute
{
return Attribute::make(
- get: function (mixed $value, array $attributes) {
- /** @var \App\Models\Task */
- $task = $this->task;
+ get: function (mixed $value) {
+ $datetime = now();
- if ($task->isSuccess()) {
+ if ($datetime->lt($this->task->start_at)) {
+ return TaskLedgerStatus::None;
+ }
+
+ if ($this->task->isSuccess()) {
return TaskLedgerStatus::Success;
}
- $datetime = now();
-
- if ($datetime->lt($task->start_at)) {
- return TaskLedgerStatus::None;
- } elseif ($datetime->gte($task->end_at)) {
- return TaskLedgerStatus::Failed;
+ if ($datetime->lt($this->task->end_at)) {
+ return TaskLedgerStatus::Pending;
}
- return TaskLedgerStatus::Pending;
+
+ return TaskLedgerStatus::Failed;
},
);
}
diff --git a/app/Models/TaskPerformance.php b/app/Models/TaskPerformance.php
index 1a7b6a9..d0becad 100644
--- a/app/Models/TaskPerformance.php
+++ b/app/Models/TaskPerformance.php
@@ -55,20 +55,22 @@ class TaskPerformance extends Model
protected function taskStatus(): Attribute
{
return Attribute::make(
- get: function (mixed $value, array $attributes) {
- if ($this->isSuccess()) {
- return TaskPerformanceStatus::Success;
- }
-
- // 当前时间
+ get: function (mixed $value) {
$datetime = now();
if ($datetime->lt($this->task->start_at)) {
return TaskPerformanceStatus::None;
- } elseif ($datetime->gte($this->task->end_at)) {
- return TaskPerformanceStatus::Failed;
}
- return TaskPerformanceStatus::Pending;
+
+ if ($this->isSuccess()) {
+ return TaskPerformanceStatus::Success;
+ }
+
+ if ($datetime->lt($this->task->end_at)) {
+ return TaskPerformanceStatus::Pending;
+ }
+
+ return TaskPerformanceStatus::Failed;
},
);
}
diff --git a/app/Traits/HasCheckable.php b/app/Traits/HasCheckable.php
index 51f7c69..2bd9cc4 100644
--- a/app/Traits/HasCheckable.php
+++ b/app/Traits/HasCheckable.php
@@ -34,28 +34,36 @@ trait HasCheckable
return Str::snake(class_basename(__CLASS__));
}
+ /**
+ * 审核中
+ */
+ public function checkProcessing(): bool
+ {
+ return $this->workflow->check_status === CheckStatus::Processing;
+ }
+
/**
* 审核通过
*/
- public function checkSuccess()
+ public function checkSuccess(): bool
{
-
+ return $this->workflow->check_status === CheckStatus::Success;
}
/**
* 审核未通过
*/
- public function checkFail()
+ public function checkFail(): bool
{
-
+ return $this->workflow->check_status === CheckStatus::Fail;
}
/**
* 取消申请
*/
- public function checkCancel()
+ public function checkCancel(): bool
{
-
+ return $this->workflow->check_status === CheckStatus::Cancel;
}
public function canUpdate(): bool
diff --git a/database/seeders/WorkflowSeeder.php b/database/seeders/WorkflowSeeder.php
index 4a5cb3f..527259e 100644
--- a/database/seeders/WorkflowSeeder.php
+++ b/database/seeders/WorkflowSeeder.php
@@ -27,6 +27,7 @@ class WorkflowSeeder extends Seeder
['key' => 'store_master_commission', 'name' => '店长提成', 'config' => $config, 'created_at' => now(), 'updated_at' => now()],
['key' => 'employee_promotion', 'name' => '升职申请', 'config' => $config, 'created_at' => now(), 'updated_at' => now()],
['key' => 'agreement', 'name' => '合同审核', 'config' => $config, 'created_at' => now(), 'updated_at' => now()],
+ ['key' => 'task_hygiene', 'name' => '清洁卫生', 'config' => $config, 'created_at' => now(), 'updated_at' => now()],
]);
}
}
diff --git a/lang/zh_CN/plan.php b/lang/zh_CN/plan.php
index 8fc94ab..46b6ea6 100644
--- a/lang/zh_CN/plan.php
+++ b/lang/zh_CN/plan.php
@@ -32,7 +32,7 @@ return [
'name' => '任务名称',
'status' => '状态',
'completed_at' => '完成时间',
- 'created_at' => '创建时间',
+ 'created_at' => '发布时间',
],
'task_ledger' => [
diff --git a/routes/api.php b/routes/api.php
index 938c6cf..afd0fb6 100644
--- a/routes/api.php
+++ b/routes/api.php
@@ -55,8 +55,10 @@ Route::group([
// 数据上报
Route::apiResource('/ledgers', LedgerController::class)->only(['store', 'show']);
- // 任务列表
+ // 我的任务 - 任务列表
Route::get('tasks', [TaskController::class, 'index']);
+ // 我的任务 - 提交任务
+ Route::post('tasks/{task}/submit', [TaskController::class, 'submit']);
// 举报投诉
Route::post('complaints', [ComplaintController::class, 'store']);