|
@@ -121,7 +121,7 @@ class UserService
|
|
|
* 业务逻辑:
|
|
|
* 1. 从 Redis 获取存储的验证码
|
|
|
* 2. 比对验证码是否匹配
|
|
|
- * 3. 验证成功后删除缓存的验证码
|
|
|
+ * 3. 验证成功后删除缓���证码
|
|
|
*
|
|
|
* @param string $mobile 手机号
|
|
|
* @param string $code 待验证的验证码
|
|
@@ -216,6 +216,33 @@ class UserService
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 检查用户是否可以申请成为技师
|
|
|
+ *
|
|
|
+ * @throws \Exception 当用户不满足申请条件时抛出异常
|
|
|
+ */
|
|
|
+ private function checkCoachApplicationEligibility(): void
|
|
|
+ {
|
|
|
+ /** @var MemberUser $user */
|
|
|
+ $user = Auth::user();
|
|
|
+
|
|
|
+ // 检查是否已经是技师且状态不是已终止
|
|
|
+ abort_if(
|
|
|
+ $user->coach && $user->coach->state !== TechnicianStatus::TERMINATED->value,
|
|
|
+ 422,
|
|
|
+ '您已是技师,无需重复申请'
|
|
|
+ );
|
|
|
+
|
|
|
+ // 检查是否有正在审核的申请
|
|
|
+ abort_if(
|
|
|
+ CoachInfoRecord::where('user_id', $user->id)
|
|
|
+ ->where('state', TechnicianAuthStatus::AUDITING->value)
|
|
|
+ ->exists(),
|
|
|
+ 422,
|
|
|
+ '您有正在审核的申请,请耐心等待'
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* 申请成为技师
|
|
|
*
|
|
@@ -228,7 +255,7 @@ class UserService
|
|
|
* @param string $mobile 联系电话
|
|
|
* @param int $gender 性别(1:男/2:女)
|
|
|
* @param string $work_years 工作年限
|
|
|
- * @param string $intention_city 意向城市
|
|
|
+ * @param string $intention_city 意向市
|
|
|
* @param array $portrait_images 形象照片数组
|
|
|
* @param string|null $introduction 个人简介
|
|
|
* @return \App\Models\CoachInfoRecord 返回申请记录
|
|
@@ -247,206 +274,37 @@ class UserService
|
|
|
try {
|
|
|
DB::beginTransaction();
|
|
|
|
|
|
- // 1. 获取验证用户信息
|
|
|
- $user = $this->getAndValidateUser();
|
|
|
-
|
|
|
- // 2. 创建技师和基础信息记录
|
|
|
- $infoRecord = $this->getOrCreateCoach(
|
|
|
- $user,
|
|
|
- $mobile,
|
|
|
- $gender,
|
|
|
- $age,
|
|
|
- $work_years,
|
|
|
- $intention_city,
|
|
|
- $portrait_images,
|
|
|
- $introduction
|
|
|
- );
|
|
|
+ // 检查申请资格
|
|
|
+ $this->checkCoachApplicationEligibility();
|
|
|
|
|
|
- DB::commit();
|
|
|
+ /** @var MemberUser $user */
|
|
|
+ $user = Auth::user();
|
|
|
|
|
|
- // 记录成功日志
|
|
|
- $this->logApplicationSuccess($user, $user->coach, $infoRecord);
|
|
|
+ // 创建技师信息记录
|
|
|
+ $infoRecord = CoachInfoRecord::create([
|
|
|
+ 'user_id' => $user->id,
|
|
|
+ 'age' => $age,
|
|
|
+ 'mobile' => $mobile,
|
|
|
+ 'gender' => $gender,
|
|
|
+ 'work_years' => $work_years,
|
|
|
+ 'intention_city' => $intention_city,
|
|
|
+ 'portrait_images' => $portrait_images,
|
|
|
+ 'introduction' => $introduction,
|
|
|
+ 'state' => TechnicianAuthStatus::AUDITING->value,
|
|
|
+ ]);
|
|
|
+
|
|
|
+ DB::commit();
|
|
|
|
|
|
return $infoRecord;
|
|
|
} catch (\Exception $e) {
|
|
|
DB::rollBack();
|
|
|
- $this->logApplicationError($e, $mobile);
|
|
|
- throw $e;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 获取并验证用户信息
|
|
|
- *
|
|
|
- * 业务逻辑:
|
|
|
- * 1. 获取当前登录用户
|
|
|
- * 2. 验证用户是否存在
|
|
|
- * 3. 返回用户模型
|
|
|
- *
|
|
|
- * @return \App\Models\MemberUser 返回用户模型
|
|
|
- *
|
|
|
- * @throws \Illuminate\Http\Exceptions\HttpResponseException 用户未登录时抛出异常
|
|
|
- */
|
|
|
- private function getAndValidateUser(): MemberUser
|
|
|
- {
|
|
|
- /** @var MemberUser $user */
|
|
|
- $user = Auth::user();
|
|
|
-
|
|
|
- // 确保用户存在
|
|
|
- abort_if(! $user, 401, '用户未登录');
|
|
|
-
|
|
|
- return $user;
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 获取或创建技师信息
|
|
|
- *
|
|
|
- * 业务逻辑:
|
|
|
- * 1. 检查用户是否已经是技师
|
|
|
- * - 如果是技师,验证是否可以再次申请
|
|
|
- * 2. 如果不是技师,创建技师记录
|
|
|
- * 3. 创建新的申请记录
|
|
|
- * - 创建技师申请记录,包含详细信息
|
|
|
- * - 关联技师记录和申请记录
|
|
|
- *
|
|
|
- * @param MemberUser $user 用户模型
|
|
|
- * @param string $mobile 联系电话
|
|
|
- * @param int $gender 性别(1:男/2:女)
|
|
|
- * @param int $age 年龄
|
|
|
- * @param string $work_years 工作年限
|
|
|
- * @param string $intention_city 意向城市
|
|
|
- * @param array $portrait_images 形象照片
|
|
|
- * @param string|null $introduction 个人简介
|
|
|
- * @return CoachInfoRecord 返回申请记录
|
|
|
- *
|
|
|
- * @throws \Illuminate\Http\Exceptions\HttpResponseException 当技师已存在且不能再次申请时抛出异常
|
|
|
- */
|
|
|
- private function getOrCreateCoach(
|
|
|
- MemberUser $user,
|
|
|
- string $mobile,
|
|
|
- int $gender,
|
|
|
- int $age,
|
|
|
- string $work_years,
|
|
|
- string $intention_city,
|
|
|
- array $portrait_images,
|
|
|
- ?string $introduction = null
|
|
|
- ): CoachInfoRecord {
|
|
|
- // 1. 获取用户关联的技师信息
|
|
|
- $coach = $user->coach;
|
|
|
-
|
|
|
- // 2. 如果已是技师,验证是否可以再次申请
|
|
|
- if ($coach) {
|
|
|
- // 验证现有申请状态,如果不能申请会抛出异常
|
|
|
- $this->validateExistingApplication($coach);
|
|
|
- } else {
|
|
|
- // 3. 如果不是技师,创建技师记录,初始状态为待认证
|
|
|
- $coach = $user->coach()->create([
|
|
|
- 'state' => TechnicianStatus::PENDING->value,
|
|
|
+ Log::error('申请成为技师失败', [
|
|
|
+ 'error' => $e->getMessage(),
|
|
|
+ 'user_id' => Auth::id(),
|
|
|
+ 'mobile' => $mobile,
|
|
|
]);
|
|
|
+ throw $e;
|
|
|
}
|
|
|
-
|
|
|
- // 4. 创建技师申请记录,状态为待审核
|
|
|
- $infoRecord = CoachInfoRecord::create([
|
|
|
- 'coach_id' => $coach->id, // 关联技师ID
|
|
|
- 'mobile' => $mobile, // 联系电话
|
|
|
- 'gender' => $gender, // 性别
|
|
|
- 'age' => $age, // 年龄
|
|
|
- 'work_years' => $work_years, // 工作年限
|
|
|
- 'intention_city' => $intention_city, // 意向城市
|
|
|
- 'portrait_images' => $portrait_images, // 形象照片,让 Laravel 自动处理数组转换
|
|
|
- 'introduction' => $introduction, // 个人简介
|
|
|
- 'state' => TechnicianAuthStatus::AUDITING->value, // 申请状态:待审核
|
|
|
- ]);
|
|
|
-
|
|
|
- // 5. 更新技师记,关联申请信息
|
|
|
- $coach->update([
|
|
|
- 'info_record_id' => $infoRecord->id,
|
|
|
- ]);
|
|
|
-
|
|
|
- return $infoRecord;
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 验证技师的现有申请状态
|
|
|
- *
|
|
|
- * 业务逻辑:
|
|
|
- * 1. 检查技师的最新申请记录状态
|
|
|
- * 2. 如果申请记录状态为待审核或审核通过,不允许再次申请
|
|
|
- * 3. 如果申请记录状态为审核拒绝,允许再次申请
|
|
|
- *
|
|
|
- * @param Coach $coach 技师模型
|
|
|
- * @return bool 如果可以申请返回 true
|
|
|
- *
|
|
|
- * @throws \Illuminate\Http\Exceptions\HttpResponseException 当不能申请抛出异常
|
|
|
- */
|
|
|
- private function validateExistingApplication($coach): bool
|
|
|
- {
|
|
|
- // 获取最新的申请记录
|
|
|
- $latestApplication = $coach->info;
|
|
|
-
|
|
|
- // 如果没有申请记录,允许申请
|
|
|
- if (! $latestApplication) {
|
|
|
- return true;
|
|
|
- }
|
|
|
-
|
|
|
- // 如果申请状态为待审核,不允许申请
|
|
|
- if ($latestApplication->state === TechnicianAuthStatus::AUDITING->value) {
|
|
|
- abort(422, '您有一个正在审核中的申请,请等待审核结果');
|
|
|
- }
|
|
|
-
|
|
|
- // 如果申请状态为审核通过,不允许申请
|
|
|
- if ($latestApplication->state === TechnicianAuthStatus::PASSED->value) {
|
|
|
- abort(422, '您的申请已通过,无需再次申请');
|
|
|
- }
|
|
|
-
|
|
|
- // 其他状态(如审核拒绝)允许再次申请
|
|
|
- return true;
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 记录申请成功日志
|
|
|
- *
|
|
|
- * 业务逻辑:
|
|
|
- * 1. 记录用户ID和技师ID
|
|
|
- * 2. 记录申请记录ID和状态
|
|
|
- * 3. 记录联方式
|
|
|
- *
|
|
|
- * @param \App\Models\MemberUser $user 用户模型
|
|
|
- * @param \App\Models\Coach $coach 技师模型
|
|
|
- * @param \App\Models\CoachInfoRecord $application 申请记录
|
|
|
- */
|
|
|
- private function logApplicationSuccess(MemberUser $user, $coach, CoachInfoRecord $application): void
|
|
|
- {
|
|
|
- Log::info('技师申请提交成功', [
|
|
|
- 'user_id' => $user->id,
|
|
|
- 'coach_id' => $coach->id,
|
|
|
- 'application_id' => $application->id,
|
|
|
- 'mobile' => $application->mobile,
|
|
|
- 'state' => $application->state,
|
|
|
- ]);
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 记录申请错误日志
|
|
|
- *
|
|
|
- * 业务逻辑:
|
|
|
- * 1. 记录错误信息和堆栈跟踪
|
|
|
- * 2. 记录用户ID和联方式
|
|
|
- * 3. 记录错误发生的文件和行号
|
|
|
- *
|
|
|
- * @param \Exception $e 异常对象
|
|
|
- * @param string $mobile 联系电话
|
|
|
- */
|
|
|
- private function logApplicationError(\Exception $e, string $mobile): void
|
|
|
- {
|
|
|
- Log::error('申请成为技师失败', [
|
|
|
- 'error' => $e->getMessage(),
|
|
|
- 'user_id' => Auth::id(),
|
|
|
- 'mobile' => $mobile,
|
|
|
- 'trace' => $e->getTraceAsString(),
|
|
|
- 'file' => $e->getFile(),
|
|
|
- 'line' => $e->getLine(),
|
|
|
- ]);
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -457,7 +315,7 @@ class UserService
|
|
|
* 2. 根据用户型生成邀请码
|
|
|
* 3. 生成包含邀请参数的接
|
|
|
* 4. 生成邀请维码
|
|
|
- * 5. 记录邀请码生���日志
|
|
|
+ * 5. 记录邀请码生成日志
|
|
|
*
|
|
|
* @param string $type 邀请码类型(user/coach)
|
|
|
* @return array 返回邀请码和二维码信息
|
|
@@ -582,7 +440,7 @@ class UserService
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 生成二维码
|
|
|
+ * 生成二码
|
|
|
*
|
|
|
* 业务逻:
|
|
|
* 1. 使用 QrCode 库生成 SVG 格式二维码
|
|
@@ -616,23 +474,25 @@ class UserService
|
|
|
public function getCoachApplication(): ?CoachInfoRecord
|
|
|
{
|
|
|
try {
|
|
|
- // 1. 获取当前用户的技师信息
|
|
|
- $user = $this->getAndValidateUser();
|
|
|
+ /** @var MemberUser $user */
|
|
|
+ $user = Auth::user();
|
|
|
+
|
|
|
+ // 确保用户已登录
|
|
|
+ abort_if(!$user, 401, '用户未登录');
|
|
|
+
|
|
|
$coach = $user->coach;
|
|
|
|
|
|
- // 2. 如果用户不是技师,返回 null
|
|
|
- if (! $coach) {
|
|
|
+ // 如果用户不是技师,返回 null
|
|
|
+ if (!$coach) {
|
|
|
return null;
|
|
|
}
|
|
|
|
|
|
- // 3. 获取最新的申请记录
|
|
|
+ // 获取最新的申请记录
|
|
|
return $coach->info;
|
|
|
} catch (\Exception $e) {
|
|
|
- // 记录错误日志
|
|
|
Log::error('获取技师申请记录失败', [
|
|
|
'error' => $e->getMessage(),
|
|
|
'user_id' => Auth::id(),
|
|
|
- 'trace' => $e->getTraceAsString(),
|
|
|
]);
|
|
|
throw $e;
|
|
|
}
|