|
@@ -732,64 +732,39 @@ class AccountService
|
|
|
/**
|
|
|
* 设置技师排班时间(每天通用)
|
|
|
*
|
|
|
- * @param int $userId 技师用户ID
|
|
|
- * @param array $timeRanges 时间段数组 格式: [
|
|
|
- * ['start_time' => '09:00', 'end_time' => '12:00'],
|
|
|
- * ['start_time' => '14:00', 'end_time' => '18:00']
|
|
|
- * ]
|
|
|
- *
|
|
|
- * @throws \Exception
|
|
|
+ * @param CoachUser $coach 技师对象
|
|
|
+ * @param array $timeRanges 时间段数组
|
|
|
+ * @return array 返回设置结果
|
|
|
+ * @throws \Exception 当设置失败时抛出异常
|
|
|
*/
|
|
|
- public function setSchedule(int $userId, array $timeRanges): array
|
|
|
+ public function setSchedule(CoachUser $coach, array $timeRanges): array
|
|
|
{
|
|
|
- return DB::transaction(function () use ($userId, $timeRanges) {
|
|
|
- try {
|
|
|
- // 获取技师信息
|
|
|
- $user = MemberUser::with(['coach'])->findOrFail($userId);
|
|
|
- $coach = $user->coach;
|
|
|
- abort_if(! $coach, 404, '技师信息不存在');
|
|
|
-
|
|
|
- // 验证并排序时间段
|
|
|
- $sortedRanges = $this->validateAndSortTimeRanges($timeRanges);
|
|
|
-
|
|
|
- // 创建或更新排班记录
|
|
|
- $schedule = CoachSchedule::updateOrCreate(
|
|
|
- [
|
|
|
- 'coach_id' => $coach->id,
|
|
|
- ],
|
|
|
- [
|
|
|
- 'time_ranges' => json_encode($sortedRanges),
|
|
|
- 'state' => 1,
|
|
|
- ]
|
|
|
- );
|
|
|
+ return DB::transaction(function () use ($coach, $timeRanges) {
|
|
|
+ // 验证并排序时间段
|
|
|
+ $sortedRanges = $this->validateAndSortTimeRanges($timeRanges);
|
|
|
+
|
|
|
+ // 创建或更新排班记录
|
|
|
+ $schedule = CoachSchedule::updateOrCreate(
|
|
|
+ ['coach_id' => $coach->id],
|
|
|
+ [
|
|
|
+ 'time_ranges' => $sortedRanges, // 直接传入数组,模型会自动处理JSON转换
|
|
|
+ 'state' => 1,
|
|
|
+ ]
|
|
|
+ );
|
|
|
|
|
|
- // 更新Redis缓存
|
|
|
- $this->updateScheduleCache($coach->id, $sortedRanges);
|
|
|
+ // 更新Redis缓存
|
|
|
+ $this->updateScheduleCache($coach->id, $sortedRanges);
|
|
|
|
|
|
- // 记录日志
|
|
|
- Log::info('技师排班设置成功', [
|
|
|
+ // 返回设置结果
|
|
|
+ return [
|
|
|
+ 'status' => true,
|
|
|
+ 'message' => '排班设置成功',
|
|
|
+ 'data' => [
|
|
|
'coach_id' => $coach->id,
|
|
|
'time_ranges' => $sortedRanges,
|
|
|
- ]);
|
|
|
-
|
|
|
- return [
|
|
|
- 'status' => true,
|
|
|
- 'message' => '排班设置成功',
|
|
|
- 'data' => [
|
|
|
- 'coach_id' => $coach->id,
|
|
|
- 'time_ranges' => $sortedRanges,
|
|
|
- 'updated_at' => $schedule->updated_at->toDateTimeString(),
|
|
|
- ],
|
|
|
- ];
|
|
|
- } catch (\Exception $e) {
|
|
|
- Log::error('技师排班设置败', [
|
|
|
- 'user_id' => $userId,
|
|
|
- 'time_ranges' => $timeRanges,
|
|
|
- 'error' => $e->getMessage(),
|
|
|
- 'trace' => $e->getTraceAsString(),
|
|
|
- ]);
|
|
|
- throw $e;
|
|
|
- }
|
|
|
+ 'updated_at' => $schedule->updated_at->toDateTimeString(),
|
|
|
+ ],
|
|
|
+ ];
|
|
|
});
|
|
|
}
|
|
|
|
|
@@ -804,17 +779,23 @@ class AccountService
|
|
|
// 验证每个时间段格式并转换为分钟数进行比较
|
|
|
$ranges = collect($timeRanges)->map(function ($range) {
|
|
|
abort_if(
|
|
|
- ! isset($range['start_time'], $range['end_time']),
|
|
|
+ !isset($range['start_time'], $range['end_time']),
|
|
|
400,
|
|
|
'时间段格式错误'
|
|
|
);
|
|
|
|
|
|
- // 验证时间格式
|
|
|
+ // 验证时间格式,限制在 00:00-24:00
|
|
|
foreach (['start_time', 'end_time'] as $field) {
|
|
|
+ // 先检查是否为 24:00
|
|
|
+ if ($range[$field] === '24:00') {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 其他时间格式验证 (00:00-23:59)
|
|
|
abort_if(
|
|
|
- ! preg_match('/^([01][0-9]|2[0-3]):[0-5][0-9]$/', $range[$field]),
|
|
|
+ !preg_match('/^((?:[01][0-9]|2[0-3]):[0-5][0-9]|24:00)$/', $range[$field]),
|
|
|
400,
|
|
|
- '时间格式错,应为HH:mm格式'
|
|
|
+ '时间格式错误,应为00:00-24:00格式'
|
|
|
);
|
|
|
}
|
|
|
|
|
@@ -866,9 +847,12 @@ class AccountService
|
|
|
*/
|
|
|
private function timeToMinutes(string $time): int
|
|
|
{
|
|
|
- [$hours, $minutes] = explode(':', $time);
|
|
|
+ if ($time === '24:00') {
|
|
|
+ return 24 * 60; // 特殊处理 24:00
|
|
|
+ }
|
|
|
|
|
|
- return (int) $hours * 60 + (int) $minutes;
|
|
|
+ [$hours, $minutes] = explode(':', $time);
|
|
|
+ return (int)$hours * 60 + (int)$minutes;
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -876,24 +860,17 @@ class AccountService
|
|
|
*/
|
|
|
private function updateScheduleCache(int $coachId, array $timeRanges): void
|
|
|
{
|
|
|
- try {
|
|
|
- $cacheKey = "coach:schedule:{$coachId}";
|
|
|
- $cacheData = [
|
|
|
- 'updated_at' => now()->toDateTimeString(),
|
|
|
- 'time_ranges' => $timeRanges,
|
|
|
- ];
|
|
|
+ $cacheKey = "coach:schedule:{$coachId}";
|
|
|
+ $cacheData = [
|
|
|
+ 'time_ranges' => $timeRanges,
|
|
|
+ 'updated_at' => now()->toDateTimeString(),
|
|
|
+ ];
|
|
|
|
|
|
- Redis::setex($cacheKey, 86400, json_encode($cacheData));
|
|
|
+ // 使用 Redis 存储,24小时过期
|
|
|
+ Redis::setex($cacheKey, 86400, json_encode($cacheData));
|
|
|
|
|
|
- // 清除相关的可预约时间段缓存
|
|
|
- $this->clearTimeSlotCache($coachId);
|
|
|
- } catch (\Exception $e) {
|
|
|
- Log::error('更新排班缓存失败', [
|
|
|
- 'coach_id' => $coachId,
|
|
|
- 'error' => $e->getMessage(),
|
|
|
- ]);
|
|
|
- // 缓存更新失败不影响主流程
|
|
|
- }
|
|
|
+ // 清除相关的可预约时间段缓存
|
|
|
+ $this->clearTimeSlotCache($coachId);
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -901,17 +878,10 @@ class AccountService
|
|
|
*/
|
|
|
public function clearTimeSlotCache(int $coachId): void
|
|
|
{
|
|
|
- try {
|
|
|
- $pattern = "coach:timeslots:{$coachId}:*";
|
|
|
- $keys = Redis::keys($pattern);
|
|
|
- if (! empty($keys)) {
|
|
|
- Redis::del($keys);
|
|
|
- }
|
|
|
- } catch (\Exception $e) {
|
|
|
- Log::error('清除可预约时间段缓存失败', [
|
|
|
- 'coach_id' => $coachId,
|
|
|
- 'error' => $e->getMessage(),
|
|
|
- ]);
|
|
|
+ $pattern = "coach:timeslots:{$coachId}:*";
|
|
|
+ $keys = Redis::keys($pattern);
|
|
|
+ if (! empty($keys)) {
|
|
|
+ Redis::del($keys);
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -1053,48 +1023,33 @@ class AccountService
|
|
|
/**
|
|
|
* 获取技师排班信息
|
|
|
*
|
|
|
- * 业务流程:
|
|
|
- * 1. 从缓存获取数据,不存在则从数据库读取
|
|
|
- * 2. 解析排班时间段
|
|
|
- * 3. 缓存结果数据
|
|
|
- *
|
|
|
* @param CoachUser $coach 技师对象
|
|
|
- * @return array 返回排班信息,包含:
|
|
|
- * - time_ranges: array 工作时间段列表
|
|
|
- * - start_time: string 开始时间
|
|
|
- * - end_time: string 结束时间
|
|
|
- * @throws \Exception 当获取失败时抛出异常
|
|
|
+ * @return array 返回排班信息
|
|
|
*/
|
|
|
public function getSchedule(CoachUser $coach): array
|
|
|
{
|
|
|
$cacheKey = "coach:schedule:{$coach->id}";
|
|
|
|
|
|
- return (array) Cache::remember($cacheKey, 86400, function () use ($coach) {
|
|
|
- // 从数据库获取有效的排班记录
|
|
|
- $schedule = CoachSchedule::where('coach_id', $coach->id)
|
|
|
- ->where('state', 1) // 有效状态
|
|
|
- ->first();
|
|
|
+ // 尝试从 Redis 获取缓存
|
|
|
+ $cached = Redis::get($cacheKey);
|
|
|
+ if ($cached) {
|
|
|
+ return json_decode($cached, true);
|
|
|
+ }
|
|
|
|
|
|
- // 构建并返回数据
|
|
|
- return [
|
|
|
- 'time_ranges' => $this->parseTimeRanges($schedule), // 解析时间段
|
|
|
- ];
|
|
|
- });
|
|
|
- }
|
|
|
+ // 缓存不存在,从数据库获取
|
|
|
+ $schedule = CoachSchedule::where('coach_id', $coach->id)
|
|
|
+ ->where('state', 1)
|
|
|
+ ->first();
|
|
|
|
|
|
- /**
|
|
|
- * 解析排班时间段
|
|
|
- *
|
|
|
- * @param CoachSchedule|null $schedule 排班记录
|
|
|
- * @return array 时间段列表
|
|
|
- */
|
|
|
- private function parseTimeRanges(?CoachSchedule $schedule): array
|
|
|
- {
|
|
|
- if (!$schedule) {
|
|
|
- return [];
|
|
|
- }
|
|
|
+ $data = [
|
|
|
+ 'time_ranges' => $schedule ? $schedule->time_ranges : [],
|
|
|
+ 'updated_at' => $schedule ? $schedule->updated_at->toDateTimeString() : now()->toDateTimeString(),
|
|
|
+ ];
|
|
|
+
|
|
|
+ // 写入 Redis 缓存
|
|
|
+ Redis::setex($cacheKey, 86400, json_encode($data));
|
|
|
|
|
|
- return json_decode($schedule->time_ranges, true) ?: [];
|
|
|
+ return $data;
|
|
|
}
|
|
|
|
|
|
/**
|