|
@@ -2,14 +2,15 @@
|
|
|
|
|
|
namespace App\Services\Client;
|
|
|
|
|
|
-use App\Enums\TechnicianAuthStatus;
|
|
|
-use App\Enums\TechnicianStatus;
|
|
|
-use App\Models\CoachInfoRecord;
|
|
|
use App\Models\CoachUser;
|
|
|
use App\Models\MemberUser;
|
|
|
-use Illuminate\Support\Facades\Auth;
|
|
|
+use App\Enums\TechnicianStatus;
|
|
|
+use App\Models\CoachInfoRecord;
|
|
|
+use App\DTOs\CoachApplicationDTO;
|
|
|
use Illuminate\Support\Facades\DB;
|
|
|
+use App\Enums\TechnicianAuthStatus;
|
|
|
use Illuminate\Support\Facades\Log;
|
|
|
+use Illuminate\Support\Facades\Auth;
|
|
|
use Illuminate\Support\Facades\Redis;
|
|
|
use SimpleSoftwareIO\QrCode\Facades\QrCode;
|
|
|
|
|
@@ -42,7 +43,7 @@ class UserService
|
|
|
*
|
|
|
* @return MemberUser 返回用户信息
|
|
|
*
|
|
|
- * @throws \Exception 获取用户信息失败时抛出异���
|
|
|
+ * @throws \Exception 获取用户信息失败时抛出异常
|
|
|
*/
|
|
|
public function getUserInfo(): MemberUser
|
|
|
{
|
|
@@ -84,7 +85,7 @@ class UserService
|
|
|
try {
|
|
|
DB::beginTransaction();
|
|
|
|
|
|
- // 检查手机号是否已��册
|
|
|
+ // 检查手机号是否已注册
|
|
|
abort_if(MemberUser::where('mobile', $mobile)->exists(), 422, '该手机号已注册');
|
|
|
|
|
|
// 验证短信验证码
|
|
@@ -257,78 +258,76 @@ class UserService
|
|
|
* 申请成为技师
|
|
|
*
|
|
|
* 业务逻辑:
|
|
|
- * 1. 检查户申请资格
|
|
|
+ * 1. 检查用户申请资格
|
|
|
* 2. 创建或更新技师基础信息
|
|
|
* 3. 创建申请记录
|
|
|
+ * 4. 更新关联关系
|
|
|
*
|
|
|
- * @param int $age 年龄
|
|
|
- * @param string $mobile 联系电话
|
|
|
- * @param int $gender 性别(1:男/2:女)
|
|
|
- * @param string $work_years 工作年限
|
|
|
- * @param string $intention_city 意向市
|
|
|
- * @param array $portrait_images 形象照片数组
|
|
|
- * @param string|null $introduction 个人简介
|
|
|
- * @return \App\Models\CoachInfoRecord 返回申请记录
|
|
|
- *
|
|
|
+ * @param CoachApplicationDTO $data 申请数据传输对象
|
|
|
+ * @return CoachInfoRecord 返回申请记录
|
|
|
* @throws \Exception 申请失败时抛出异常
|
|
|
*/
|
|
|
- public function applyCoach(
|
|
|
- int $age,
|
|
|
- string $mobile,
|
|
|
- int $gender,
|
|
|
- string $work_years,
|
|
|
- string $intention_city,
|
|
|
- array $portrait_images,
|
|
|
- ?string $introduction = null
|
|
|
- ): CoachInfoRecord {
|
|
|
- try {
|
|
|
- DB::beginTransaction();
|
|
|
-
|
|
|
+ public function applyCoach(CoachApplicationDTO $data): CoachInfoRecord
|
|
|
+ {
|
|
|
+ return DB::transaction(function () use ($data) {
|
|
|
// 检查申请资格
|
|
|
$this->checkCoachApplicationEligibility();
|
|
|
|
|
|
+ // 验证业务规则
|
|
|
+ $this->validateBusinessRules($data);
|
|
|
+
|
|
|
+ // 获取当前用户
|
|
|
/** @var MemberUser $user */
|
|
|
$user = Auth::user();
|
|
|
|
|
|
- // 获取用户技师身份
|
|
|
- $coach = $user->coach;
|
|
|
- // 如果用户不存在技师身份
|
|
|
- if(!$coach){
|
|
|
- // 创建技师用户记录
|
|
|
- $coach = CoachUser::create([
|
|
|
- 'user_id' => $user->id,
|
|
|
- 'state' => TechnicianStatus::PENDING->value,
|
|
|
- ]);
|
|
|
- }
|
|
|
+ // 创建或获取技师用户记录
|
|
|
+ $coach = $this->getOrCreateCoachUser($user);
|
|
|
|
|
|
// 创建技师信息记录
|
|
|
- $infoRecord = CoachInfoRecord::create([
|
|
|
- 'coach_id' => $coach->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,
|
|
|
- ]);
|
|
|
+ $infoRecord = $this->createCoachInfoRecord($coach, $data);
|
|
|
|
|
|
// 更新技师用户记录的信息记录ID
|
|
|
$coach->update(['info_record_id' => $infoRecord->id]);
|
|
|
|
|
|
- DB::commit();
|
|
|
-
|
|
|
return $infoRecord;
|
|
|
- } catch (\Exception $e) {
|
|
|
- DB::rollBack();
|
|
|
- Log::error('申请成为技师失败', [
|
|
|
- 'error' => $e->getMessage(),
|
|
|
- 'user_id' => Auth::id(),
|
|
|
- 'mobile' => $mobile,
|
|
|
- ]);
|
|
|
- throw $e;
|
|
|
- }
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 验证技师申请业务规则
|
|
|
+ *
|
|
|
+ * 验证规则:
|
|
|
+ * 1. 工作年限不能超过实际工作可能年限(年龄-18)
|
|
|
+ * 2. 生活照片数量验证(1-6张)
|
|
|
+ * 3. 手机号格式统一验证
|
|
|
+ *
|
|
|
+ * @param CoachApplicationDTO $data 申请数据
|
|
|
+ * @throws \Exception 验证失败时抛出异常
|
|
|
+ */
|
|
|
+ private function validateBusinessRules(CoachApplicationDTO $data): void
|
|
|
+ {
|
|
|
+ // 验证工作年限合理性
|
|
|
+ $maxPossibleWorkYears = $data->age - 18; // 实际可能的最大工作年限
|
|
|
+ abort_if(
|
|
|
+ $data->workYears > $maxPossibleWorkYears,
|
|
|
+ 422,
|
|
|
+ sprintf('工作年限不能超过%d年(当前年龄%d岁)', $maxPossibleWorkYears, $data->age)
|
|
|
+ );
|
|
|
+
|
|
|
+ // 验证生活照片数量
|
|
|
+ $photoCount = count($data->lifePhotos);
|
|
|
+ abort_if(
|
|
|
+ $photoCount < 1 || $photoCount > 6,
|
|
|
+ 422,
|
|
|
+ '生活照片数量必须在1-6张之间'
|
|
|
+ );
|
|
|
+
|
|
|
+ // 验证手机号格式
|
|
|
+ abort_if(
|
|
|
+ !preg_match('/^1[3-9]\d{9}$/', $data->mobile),
|
|
|
+ 422,
|
|
|
+ '手机号格式不正确'
|
|
|
+ );
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -521,4 +520,62 @@ class UserService
|
|
|
throw $e;
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 创建或获取技师用户记录
|
|
|
+ *
|
|
|
+ * @param MemberUser $user 用户对象
|
|
|
+ * @return CoachUser 技师用户记录
|
|
|
+ */
|
|
|
+ private function getOrCreateCoachUser(MemberUser $user): CoachUser
|
|
|
+ {
|
|
|
+ // 获取用户技师身份
|
|
|
+ $coach = $user->coach;
|
|
|
+
|
|
|
+ // 如果用户不存在技师身份,创建新记录
|
|
|
+ if (!$coach) {
|
|
|
+ $coach = CoachUser::create([
|
|
|
+ 'user_id' => $user->id,
|
|
|
+ 'state' => TechnicianStatus::PENDING->value,
|
|
|
+ ]);
|
|
|
+ }
|
|
|
+
|
|
|
+ return $coach;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 创建技师信息记录
|
|
|
+ *
|
|
|
+ * @param CoachUser $coach 技师用户对象
|
|
|
+ * @param CoachApplicationDTO $data 技师信息数据
|
|
|
+ * @return CoachInfoRecord 技师信息记录
|
|
|
+ */
|
|
|
+ private function createCoachInfoRecord(CoachUser $coach, CoachApplicationDTO $data): CoachInfoRecord
|
|
|
+ {
|
|
|
+ // 定义允许的字段和默认值
|
|
|
+ $allowedFields = [
|
|
|
+ 'age' => $data->age,
|
|
|
+ 'mobile' => $data->mobile,
|
|
|
+ 'gender' => $data->gender,
|
|
|
+ 'work_years' => $data->workYears,
|
|
|
+ 'intention_city' => $data->intentionCity,
|
|
|
+ 'life_photos' => json_encode($data->lifePhotos), // 将数组转换为JSON字符串
|
|
|
+ 'introduction' => $data->introduction,
|
|
|
+ 'coach_id' => $coach->id,
|
|
|
+ 'state' => TechnicianAuthStatus::AUDITING->value,
|
|
|
+ ];
|
|
|
+
|
|
|
+ // 过滤空值,但保留必填字段
|
|
|
+ $requiredFields = ['age', 'mobile', 'gender', 'work_years', 'intention_city', 'life_photos', 'coach_id', 'state'];
|
|
|
+
|
|
|
+ $recordData = array_filter(
|
|
|
+ $allowedFields,
|
|
|
+ function ($value, $key) use ($requiredFields) {
|
|
|
+ return !is_null($value) || in_array($key, $requiredFields);
|
|
|
+ },
|
|
|
+ ARRAY_FILTER_USE_BOTH
|
|
|
+ );
|
|
|
+
|
|
|
+ return CoachInfoRecord::create($recordData);
|
|
|
+ }
|
|
|
}
|