Browse Source

feat:技师端-更改工作状态(休息、工作)

刘学玺 4 months ago
parent
commit
7b816bc518

+ 40 - 0
app/Http/Controllers/Coach/AccountController.php

@@ -277,4 +277,44 @@ class AccountController extends Controller
             $this->service->setSchedule(Auth::user()->id, $validated['time_ranges'])
         );
     }
+
+    /**
+     * [账户]更改技师工作状态
+     *
+     * @description 更改技师的工作状态(休息中/工作中),工作状态会自动判断为空闲或忙碌
+     *
+     * @authenticated
+     *
+     * @bodyParam status int required 状态(1:休息中 2:工作中) Example: 2
+     *
+     * @response {
+     *   "status": true,
+     *   "message": "状态更新成功",
+     *   "data": {
+     *     "work_status": 2,
+     *     "work_status_text": "空闲中",
+     *     "updated_at": "2024-03-20 10:00:00"
+     *   }
+     * }
+     * @response 400 {
+     *   "message": "无效的状态值"
+     * }
+     * @response 422 {
+     *   "message": "当前状态不能更改为休息状态"
+     * }
+     */
+    public function updateWorkStatus(Request $request)
+    {
+        $validated = $request->validate([
+            'status' => 'required|integer|in:1,2',
+        ], [
+            'status.required' => '状态不能为空',
+            'status.integer' => '状态必须是整数',
+            'status.in' => '无效的状态值',
+        ]);
+
+        return $this->success(
+            $this->service->updateWorkStatus(Auth::user()->id, $validated['status'])
+        );
+    }
 }

+ 208 - 2
app/Services/Coach/AccountService.php

@@ -2,8 +2,10 @@
 
 namespace App\Services\Coach;
 
+use App\Enums\OrderStatus;
 use App\Enums\TechnicianAuthStatus;
 use App\Enums\TechnicianLocationType;
+use App\Enums\TechnicianWorkStatus;
 use App\Models\CoachSchedule;
 use App\Models\MemberUser;
 use Illuminate\Support\Facades\Cache;
@@ -465,7 +467,7 @@ class AccountService
                 ];
 
             } catch (\Exception $e) {
-                Log::error('技师排班设置败', [
+                Log::error('技师排班设置���败', [
                     'user_id' => $userId,
                     'time_ranges' => $timeRanges,
                     'error' => $e->getMessage(),
@@ -492,7 +494,7 @@ class AccountService
             // 验证时间格式
             foreach (['start_time', 'end_time'] as $field) {
                 abort_if(! preg_match('/^([01][0-9]|2[0-3]):[0-5][0-9]$/', $range[$field]),
-                    400, '时间格式错,应为HH:mm格式');
+                    400, '时间格式错,应为HH:mm格式');
             }
 
             // 转换为分钟数便于比较
@@ -586,4 +588,208 @@ class AccountService
             ]);
         }
     }
+
+    /**
+     * 更改技师工作状态
+     *
+     * @param  int  $userId  用户ID
+     * @param  int  $status  状态(1:休息中 2:工作中)
+     */
+    public function updateWorkStatus(int $userId, int $status): array
+    {
+        DB::beginTransaction();
+        try {
+            // 获取技师信息
+            $user = MemberUser::with(['coach', 'coach.infoRecords', 'coach.qualRecords', 'coach.realRecords'])
+                ->findOrFail($userId);
+            $coach = $user->coach;
+            abort_if(! $coach, 404, '技师信息不存在');
+
+            // 验证状态值
+            abort_if(! in_array($status, [1, 2]), 400, '无效的状态值');
+
+            // 验证技师认证状态
+            $this->validateCoachStatus($coach);
+
+            // 获取当前时间是否在排班时间内
+            $isInSchedule = $this->checkScheduleTime($coach->id);
+
+            $currentStatus = $coach->work_status;
+            $newStatus = $status;
+
+            // 如果要切换到休息状态
+            if ($status === 1) {
+                // 验证当前状态是否允许切换到休息
+                $this->validateRestStatus($currentStatus);
+                $newStatus = TechnicianWorkStatus::REST->value;
+            }
+            // 如果要切换到工作状态
+            elseif ($status === 2) {
+                // 验证是否在排班时间内
+                abort_if(! $isInSchedule, 422, '当前时间不在排班时间内,无法切换到工作状态');
+
+                // 检查是否有进行中的订单
+                $hasActiveOrder = $coach->orders()
+                    ->whereIn('state', [
+                        OrderStatus::ACCEPTED->value,   // 已接单
+                        OrderStatus::DEPARTED->value,   // 已出发
+                        OrderStatus::ARRIVED->value,    // 已到达
+                        OrderStatus::SERVING->value,    // 服务中
+                    ])
+                    ->exists();
+
+                // 根据是否有进行中订单决定状态
+                $newStatus = $hasActiveOrder ?
+                    TechnicianWorkStatus::BUSY->value :
+                    TechnicianWorkStatus::FREE->value;
+            }
+
+            // 如果状态没有变化,则不需要更新
+            if ($currentStatus === $newStatus) {
+                DB::rollBack();
+
+                return [
+                    'status' => true,
+                    'message' => '状态未发生变化',
+                    'data' => [
+                        'work_status' => $newStatus,
+                        'work_status_text' => TechnicianWorkStatus::fromValue($newStatus)->label(),
+                        'updated_at' => now()->toDateTimeString(),
+                    ],
+                ];
+            }
+
+            // 更新状态
+            $coach->work_status = $newStatus;
+            $coach->save();
+
+            // 更新Redis缓存
+            $this->updateWorkStatusCache($coach->id, $newStatus);
+
+            DB::commit();
+
+            // 记录日志
+            Log::info('技师工作状态更新成功', [
+                'coach_id' => $coach->id,
+                'old_status' => $currentStatus,
+                'new_status' => $newStatus,
+                'updated_at' => now()->toDateTimeString(),
+                'in_schedule' => $isInSchedule,
+            ]);
+
+            return [
+                'status' => true,
+                'message' => '状态更新成功',
+                'data' => [
+                    'work_status' => $newStatus,
+                    'work_status_text' => TechnicianWorkStatus::fromValue($newStatus)->label(),
+                    'updated_at' => now()->toDateTimeString(),
+                ],
+            ];
+
+        } catch (\Exception $e) {
+            DB::rollBack();
+            Log::error('技师工作状态更新失败', [
+                'user_id' => $userId,
+                'status' => $status,
+                'error' => $e->getMessage(),
+                'trace' => $e->getTraceAsString(),
+            ]);
+            throw $e;
+        }
+    }
+
+    /**
+     * 验证技师认证状态
+     */
+    private function validateCoachStatus($coach): void
+    {
+        // 验证基本信息认证
+        $baseInfo = $coach->info;
+        abort_if(! $baseInfo || $baseInfo->state !== TechnicianAuthStatus::PASSED->value,
+            422, '基本信息未认证通过');
+
+        // 验证资质认证
+        $qualification = $coach->qual;
+        abort_if(! $qualification || $qualification->state !== TechnicianAuthStatus::PASSED->value,
+            422, '资质信息未认证通过');
+
+        // 验证实名认证
+        $realName = $coach->real;
+        abort_if(! $realName || $realName->state !== TechnicianAuthStatus::PASSED->value,
+            422, '实名信息未认证通过');
+    }
+
+    /**
+     * 验证是否可以切换到休息状态
+     */
+    private function validateRestStatus(int $currentStatus): void
+    {
+        // 只有在空闲或忙碌状态下才能更改为休息状态
+        abort_if(! in_array($currentStatus, [
+            TechnicianWorkStatus::FREE->value,
+            TechnicianWorkStatus::BUSY->value,
+        ]), 422, '当前状态不能更改为休息状态');
+    }
+
+    /**
+     * 检查当前时间是否在排班时间内
+     */
+    private function checkScheduleTime(int $coachId): bool
+    {
+        try {
+            $schedule = CoachSchedule::where('coach_id', $coachId)
+                ->where('state', 1)
+                ->first();
+
+            if (! $schedule) {
+                return false;
+            }
+
+            $timeRanges = json_decode($schedule->time_ranges, true);
+            if (empty($timeRanges)) {
+                return false;
+            }
+
+            $currentTime = now()->format('H:i');
+
+            foreach ($timeRanges as $range) {
+                if ($currentTime >= $range['start_time'] && $currentTime <= $range['end_time']) {
+                    return true;
+                }
+            }
+
+            return false;
+        } catch (\Exception $e) {
+            Log::error('检查排班时间异常', [
+                'coach_id' => $coachId,
+                'error' => $e->getMessage(),
+            ]);
+
+            return false;
+        }
+    }
+
+    /**
+     * 更新工作状态缓存
+     */
+    private function updateWorkStatusCache(int $coachId, int $status): void
+    {
+        try {
+            $cacheKey = "coach:work_status:{$coachId}";
+            $cacheData = [
+                'status' => $status,
+                'updated_at' => now()->toDateTimeString(),
+            ];
+
+            Redis::setex($cacheKey, 86400, json_encode($cacheData));
+
+        } catch (\Exception $e) {
+            Log::error('更新工作状态缓存失败', [
+                'coach_id' => $coachId,
+                'error' => $e->getMessage(),
+            ]);
+            // 缓存更新失败不影响主流程
+        }
+    }
 }

+ 2 - 0
routes/api.php

@@ -151,6 +151,8 @@ Route::middleware(['auth:sanctum'])->prefix('coach')->group(function () {
         Route::get('location', [\App\Http\Controllers\Coach\AccountController::class, 'getLocation']);
         // 排班管理
         Route::post('schedule', [\App\Http\Controllers\Coach\AccountController::class, 'setSchedule']);
+        // 更新技师工作状态
+        Route::post('work-status', [App\Http\Controllers\Coach\AccountController::class, 'updateWorkStatus']);
     });
 
     // 订单相关路由