소스 검색

fixed:用户端-申请技师(逻辑修改)

刘学玺 4 달 전
부모
커밋
14e1267381

+ 3 - 3
app/Http/Controllers/Client/UserController.php

@@ -191,7 +191,7 @@ class UserController extends Controller
      * @bodyParam work_years integer required 工作年限(0-50年) Example: 5
      * @bodyParam intention_city string required 意向城市 Example: 杭州
      * @bodyParam portrait_images array required 形象照片(最多6张) Example: ["https://example.com/portrait1.jpg"]
-     * @bodyParam description string optional 个人介绍(最多1000字) Example: 专业按摩师,有多年经验
+     * @bodyParam introduction string optional 个人简介(最多1000字) Example: 专业按摩师,有多年经验
      *
      * @response 200 {
      *   "code": 200,
@@ -205,7 +205,7 @@ class UserController extends Controller
      *     "work_years": 5,
      *     "intention_city": "杭州",
      *     "portrait_images": ["https://example.com/portrait1.jpg"],
-     *     "description": "专业按摩师,有多年经验",
+     *     "introduction": "专业按摩师,有多年经验",
      *     "state": "auditing",
      *     "created_at": "2024-03-20 10:00:00",
      *     "updated_at": "2024-03-20 10:00:00"
@@ -250,7 +250,7 @@ class UserController extends Controller
             $validated['work_years'],
             $validated['intention_city'],
             $validated['portrait_images'],
-            $validated['description'] ?? null
+            $validated['introduction'] ?? null
         );
 
         return $this->success($result, '申请提交成功');

+ 2 - 9
app/Http/Requests/Client/User/ApplyCoachRequest.php

@@ -47,12 +47,7 @@ class ApplyCoachRequest extends FormRequest
                 'min:1',
                 'max:6',
             ],
-            // 'portrait_images.*' => [
-            //     'required',
-            //     'string',
-            //     'url',
-            // ],
-            'description' => [
+            'introduction' => [
                 'nullable',
                 'string',
                 'max:1000',
@@ -81,9 +76,7 @@ class ApplyCoachRequest extends FormRequest
             'portrait_images.array' => '形象照片必须是数组',
             'portrait_images.min' => '至少上传1张形象照片',
             'portrait_images.max' => '最多上传6张形象照片',
-            'portrait_images.*.required' => '形象照片不能为空',
-            'portrait_images.*.url' => '形象照片必须是有效的URL地址',
-            'description.max' => '个人介绍不能超过1000个字符',
+            'introduction.max' => '个人简介不能超过1000个字符',
         ];
     }
 }

+ 30 - 2
app/Models/CoachInfoRecord.php

@@ -2,6 +2,7 @@
 
 namespace App\Models;
 
+use App\Enums\TechnicianAuthStatus;
 use Illuminate\Database\Eloquent\SoftDeletes;
 use Slowlyo\OwlAdmin\Models\BaseModel as Model;
 
@@ -10,14 +11,41 @@ use Slowlyo\OwlAdmin\Models\BaseModel as Model;
  */
 class CoachInfoRecord extends Model
 {
-	use SoftDeletes;
+    use SoftDeletes;
 
-	protected $table = 'coach_info_records';
+    protected $table = 'coach_info_records';
 
     protected $guarded = [];
 
+    /**
+     * 应该被转换为原生类型的属性
+     *
+     * @var array
+     */
+    protected $casts = [
+        'portrait_images' => 'array',
+    ];
+
+    /**
+     * 应该被追加到模型数组的访问器
+     *
+     * @var array
+     */
+    protected $appends = ['state_text'];
+
+    /**
+     * 获取状态文本
+     *
+     * @return string
+     */
+    public function getStateTextAttribute(): string
+    {
+        return TechnicianAuthStatus::fromValue($this->state)?->label() ?? '未知状态';
+    }
+
     /**
      * @Author FelixYin
+     *
      * @description 信息记录所属技师
      */
     public function coach()

+ 96 - 103
app/Services/Client/UserService.php

@@ -116,7 +116,7 @@ class UserService
             ];
         } catch (\Exception $e) {
             DB::rollBack();
-            Log::error('用户注册失败', ['error' => $e->getMessage(), 'mobile' => $mobile]);
+            Log::error('用户注册', ['error' => $e->getMessage(), 'mobile' => $mobile]);
             throw $e;
         }
     }
@@ -226,7 +226,7 @@ class UserService
      * 申请成为技师
      *
      * 业务逻辑:
-     * 1. 检查���户申请资格
+     * 1. 检查户申请资格
      * 2. 创建或更新技师基础信息
      * 3. 创建申请记录
      *
@@ -236,7 +236,7 @@ class UserService
      * @param  string  $work_years  工作年限
      * @param  string  $intention_city  意向城市
      * @param  array  $portrait_images  形象照片数组
-     * @param  string|null  $description  个人介绍
+     * @param  string|null  $introduction  个人简介
      * @return \App\Models\CoachInfoRecord 返回申请记录
      *
      * @throws \Exception 申请失败时抛出异常
@@ -248,35 +248,32 @@ class UserService
         string $work_years,
         string $intention_city,
         array $portrait_images,
-        ?string $description = null
+        ?string $introduction = null
     ): CoachInfoRecord {
         try {
             DB::beginTransaction();
 
-            // 1. 获取验证用户信息
+            // 1. 获取验证用户信息
             $user = $this->getAndValidateUser();
 
-            // 2. 获取或创建技师基础信息
-            $coach = $this->getOrCreateCoach($user, $mobile, $gender);
-
-            // 3. 创建申请记录
-            $application = $this->createCoachApplication(
-                $coach,
-                $age,
+            // 2. 创建技师和基础信息记录
+            $infoRecord = $this->getOrCreateCoach(
+                $user,
                 $mobile,
                 $gender,
+                $age,
                 $work_years,
                 $intention_city,
                 $portrait_images,
-                $description
+                $introduction
             );
 
             DB::commit();
 
             // 记录成功日志
-            $this->logApplicationSuccess($user, $coach, $application);
+            $this->logApplicationSuccess($user, $user->coach, $infoRecord);
 
-            return $application;
+            return $infoRecord;
         } catch (\Exception $e) {
             DB::rollBack();
             $this->logApplicationError($e, $mobile);
@@ -308,112 +305,108 @@ class UserService
     }
 
     /**
-     * 获取或创建技师基础信息
+     * 获取或创建技师信息
      *
      * 业务逻辑:
-     * 1. 获取用户关联的技师信息
-     * 2. 如果存在技师信息:
-     *    - 验证现申请状态
-     *    - 更新基础信息
-     * 3. 如果不存在技师信息:
-     *    - 创建新的技师记录
-     *
-     * @param  \App\Models\MemberUser  $user  用户模型
+     * 1. 检查用户是否已经是技师
+     *    - 如果是技师,验证是否可以再次申请
+     * 2. 如果不是技师,创建技师记录
+     * 3. 创建新的申请记录
+     *    - 创建技师申请记录,包含详细信息
+     *    - 关联技师记录和申请记录
+     *
+     * @param  MemberUser  $user  用户模型
      * @param  string  $mobile  手机号
      * @param  int  $gender  性别(1:男/2:女)
-     * @return \App\Models\Coach 返回技师模型
+     * @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 验证失败时抛出异常
+     * @throws \Illuminate\Http\Exceptions\HttpResponseException 当技师已存在且不能再次申请时抛出异常
      */
-    private function getOrCreateCoach(MemberUser $user, string $mobile, int $gender)
-    {
+    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);
-            // 更新基础信息
-            $coach->update([
-                'mobile' => $mobile,
-                'gender' => $gender,
+        } else {
+            // 3. 如果不是技师,创建技师记录,初始状态为待认证
+            $coach = $user->coach()->create([
+                'state' => TechnicianStatus::PENDING->value,
             ]);
-
-            return $coach->fresh();
         }
 
-        // 创建新的技师记录
-        return $user->coach()->create([
-            'mobile' => $mobile,
-            'gender' => $gender,
-            'state' => TechnicianStatus::PENDING->value,
+        // 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. 根据状态返回相应的错误信息
+     * 1. 查技师的最新申请记录状态
+     * 2. 如果申请记录状态为待审核或审核通过,不允许再次申请
+     * 3. 如果申请记录状态为审核拒绝,允许再次申请
      *
-     * @param  \App\Models\Coach  $coach  技师模型
+     * @param  Coach  $coach  技师模型
+     * @return bool 如果可以申请返回 true
      *
-     * @throws \Illuminate\Http\Exceptions\HttpResponseException 存在未��成申请时抛出异常
+     * @throws \Illuminate\Http\Exceptions\HttpResponseException 当不能申请时抛出异常
      */
-    private function validateExistingApplication($coach): void
+    private function validateExistingApplication($coach): bool
     {
-        $existingApplication = CoachInfoRecord::where('coach_id', $coach->id)
-            ->whereIn('state', [TechnicianAuthStatus::AUDITING, TechnicianAuthStatus::PASSED])
-            ->first();
-
-        if ($existingApplication) {
-            $message = $existingApplication->state === TechnicianAuthStatus::PASSED
-                ? '您已是技师,无需重复申请'
-                : '您有正在审核的申请,请耐心等待';
-            abort(422, $message);
+        // 获取最新的申请记录
+        $latestApplication = $coach->info;
+
+        // 如果没有申请记录,允许申请
+        if (! $latestApplication) {
+            return true;
         }
-    }
 
-    /**
-     * 创建技师申请记录
-     *
-     * 业务逻辑:
-     * 1. 准备申请记录数据
-     * 2. 处理形象照片数据
-     * 3. 创建申请记录
-     *
-     * @param  \App\Models\Coach  $coach  技师模型
-     * @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  $description  个人介绍
-     * @return \App\Models\CoachInfoRecord 返回申请记录
-     */
-    private function createCoachApplication(
-        $coach,
-        int $age,
-        string $mobile,
-        int $gender,
-        string $work_years,
-        string $intention_city,
-        array $portrait_images,
-        ?string $description
-    ): CoachInfoRecord {
-        return CoachInfoRecord::create([
-            'coach_id' => $coach->id,
-            'age' => $age,
-            'mobile' => $mobile,
-            'gender' => $gender,
-            'work_years' => $work_years,
-            'intention_city' => $intention_city,
-            'portrait_images' => json_encode($portrait_images, JSON_UNESCAPED_UNICODE),
-            'description' => $description,
-            'state' => TechnicianAuthStatus::AUDITING,
-        ]);
+        // 如果申请状态为待审核,不允许申请
+        if ($latestApplication->state === TechnicianAuthStatus::AUDITING->value) {
+            abort(422, '您有一个正在审核中的申请,请等待审核结果');
+        }
+
+        // 如果申请状态为审核通过,不允许申请
+        if ($latestApplication->state === TechnicianAuthStatus::PASSED->value) {
+            abort(422, '您的申请已通过,无需再次申请');
+        }
+
+        // 其他状态(如审核拒绝)允许再次申请
+        return true;
     }
 
     /**
@@ -422,7 +415,7 @@ class UserService
      * 业务逻辑:
      * 1. 记录用户ID和技师ID
      * 2. 记录申请记录ID和状态
-     * 3. 记录联方式
+     * 3. 记录联方式
      *
      * @param  \App\Models\MemberUser  $user  用户模型
      * @param  \App\Models\Coach  $coach  技师模型
@@ -444,7 +437,7 @@ class UserService
      *
      * 业务逻辑:
      * 1. 记录错误信息和堆栈跟踪
-     * 2. 记录用户ID和联方式
+     * 2. 记录用户ID和联方式
      * 3. 记录错误发生的文件和行号
      *
      * @param  \Exception  $e  异常对象
@@ -467,9 +460,9 @@ class UserService
      *
      * 业务逻辑:
      * 1. 获取当前户信息
-     * 2. 根据用户型生成邀请码
+     * 2. 根据用户型生成邀请码
      * 3. 生成包含邀请参数的接
-     * 4. 生成邀请维码
+     * 4. 生成邀请维码
      * 5. 记录邀请码生成日志
      *
      * @param  string  $type  邀请码类型(user/coach)
@@ -488,7 +481,7 @@ class UserService
             // 2. 根据类型获取邀请人ID和角色
             $inviteInfo = $this->getInviteInfo($user, $type);
             if (! $inviteInfo) {
-                throw new \Exception('无法生邀请码,用户类型不匹配');
+                throw new \Exception('无法生邀请码,用户类型不匹配');
             }
 
             // 3. 生成邀请码
@@ -530,7 +523,7 @@ class UserService
      *
      * 业务逻辑:
      * 1. 根据类型判断邀请人身份
-     * 2. 户类型:直接返回用信息
+     * 2. 户类型:直接返回用信息
      * 3. 技师类型:
      *    - 验证技师状态
      *    - 返回技师信息
@@ -598,7 +591,7 @@ class UserService
     /**
      * 生成二维码
      *
-     * 业务逻
+     * 业务逻:
      * 1. 使用 QrCode 库生成 SVG 格式二维码
      * 2. 设置二维码大小和边距
      * 3. 转换为 base64 编码