Browse Source

Merge branch 'master' of ssh://gogs.yinbin.ink:30004/didong/owl-admin

Yin Bin 4 months ago
parent
commit
534ee498d0

+ 2 - 4
app/Enums/WalletType.php

@@ -34,7 +34,7 @@ enum WalletType: int
      */
     public function label(): string
     {
-        return match($this) {
+        return match ($this) {
             self::PLATFORM => '平台自有资金钱包',
             self::ESCROW => '平台代收代付钱包',
             self::PERSONAL => '个人钱包',
@@ -71,7 +71,7 @@ enum WalletType: int
      */
     public static function fromValue(int $value): ?self
     {
-        return match($value) {
+        return match ($value) {
             self::PLATFORM->value => self::PLATFORM,
             self::ESCROW->value => self::ESCROW,
             self::PERSONAL->value => self::PERSONAL,
@@ -104,6 +104,4 @@ enum WalletType: int
             self::MERCHANT->value => self::MERCHANT->label(),
         ];
     }
-
-  
 }

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

@@ -0,0 +1,150 @@
+<?php
+
+namespace App\Http\Controllers\Coach;
+
+use App\Http\Controllers\Controller;
+use App\Http\Requests\Coach\SubmitBaseInfoRequest;
+use App\Http\Requests\Coach\SubmitQualificationRequest;
+use App\Http\Requests\Coach\SubmitRealNameRequest;
+use App\Services\Coach\AccountService;
+use App\Traits\ResponseTrait;
+use Illuminate\Support\Facades\Auth;
+
+/**
+ * @group 技师端
+ *
+ * 技师账户相关的API接口
+ */
+class AccountController extends Controller
+{
+    use ResponseTrait;
+
+    protected AccountService $service;
+
+    public function __construct(AccountService $service)
+    {
+        $this->service = $service;
+    }
+
+    /**
+     * [账户]提交基本信息
+     *
+     * @description 提交技师的基本个人信息
+     *
+     * @authenticated
+     *
+     * @bodyParam nickname string required 昵称(2-20个字符) Example: 张三
+     * @bodyParam avatar string required 头像URL Example: http://example.com/avatar.jpg
+     * @bodyParam gender string required 性别(1:男 2:女) Example: 1
+     * @bodyParam mobile string required 手机号 Example: 13800138000
+     * @bodyParam birthday date required 出生日期(年龄需满18岁) Example: 1990-01-01
+     * @bodyParam work_years integer required 工作年限(0-99) Example: 5
+     * @bodyParam intention_city string required 意向城市 Example: 北京
+     * @bodyParam introduction string required 个人简介(10-255个字符) Example: 专业按摩师,从业5年
+     *
+     * @response {
+     *  "message": "基本信息提交成功"
+     * }
+     */
+    public function submitBaseInfo(SubmitBaseInfoRequest $request)
+    {
+        $data = $request->validated();
+
+        return $this->success($this->service->submitBaseInfo(Auth::user(), $data));
+    }
+
+    /**
+     * [账户]提交资质信息
+     *
+     * @description 提交技师的资质认证信息
+     *
+     * @authenticated
+     *
+     * @bodyParam qual_type string required 资质类型(按摩师/理疗师等) Example: 高级按摩师
+     * @bodyParam qual_no string required 资质证书编号(5-50个字符) Example: XZ2024001
+     * @bodyParam qual_photo string required 资质证书照片 Example: http://example.com/cert.jpg
+     * @bodyParam valid_start date required 有效期开始日期 Example: 2024-01-01
+     * @bodyParam valid_end date required 有效期结束日期(必须大于开始日期) Example: 2029-01-01
+     *
+     * @response {
+     *  "message": "资质信息提交成功"
+     * }
+     */
+    public function submitQualification(SubmitQualificationRequest $request)
+    {
+        $data = $request->validated();
+
+        return $this->success($this->service->submitQualification(Auth::user(), $data));
+    }
+
+    /**
+     * [账户]提交实名认证
+     *
+     * @description 提交技师的实名认证信息
+     *
+     * @authenticated
+     *
+     * @bodyParam real_name string required 姓名(2-20个字符) Example: 张三
+     * @bodyParam id_card string required 身份证号(18位) Example: 370602199001011234
+     * @bodyParam id_card_front_photo string required 身份证正面照片 Example: http://example.com/front.jpg
+     * @bodyParam id_card_back_photo string required 身份证反面照片 Example: http://example.com/back.jpg
+     * @bodyParam id_card_hand_photo string required 手持身份证照片 Example: http://example.com/hold.jpg
+     *
+     * @response {
+     *  "message": "实名认证信息提交成功"
+     * }
+     */
+    public function submitRealName(SubmitRealNameRequest $request)
+    {
+        $data = $request->validated();
+
+        return $this->success($this->service->submitRealName(Auth::user(), $data));
+    }
+
+    /**
+     * [账户]获取技师信息
+     *
+     * @description 获取技师的基本信息、资质信息和实名信息
+     *
+     * @authenticated
+     *
+     * @response {
+     *   "data": {
+     *     "base_info": {
+     *       "nickname": "张三",
+     *       "avatar": "http://example.com/avatar.jpg",
+     *       "gender": "1",
+     *       "mobile": "138****8000",
+     *       "birthday": "1990-01-01",
+     *       "work_years": 5,
+     *       "intention_city": "北京",
+     *       "introduction": "专业按摩师,从业5年",
+     *       "state": 1,
+     *       "audit_remark": "审核通过"
+     *     },
+     *     "qualification": {
+     *       "qual_type": "高级按摩师",
+     *       "qual_no": "XZ2024001",
+     *       "qual_photo": "http://example.com/cert.jpg",
+     *       "valid_start": "2024-01-01",
+     *       "valid_end": "2029-01-01",
+     *       "state": 1,
+     *       "audit_remark": "审核通过"
+     *     },
+     *     "real_name": {
+     *       "real_name": "张三",
+     *       "id_card": "370602****1234",
+     *       "id_card_front_photo": "http://example.com/front.jpg",
+     *       "id_card_back_photo": "http://example.com/back.jpg",
+     *       "id_card_hand_photo": "http://example.com/hold.jpg",
+     *       "state": 1,
+     *       "audit_remark": "审核通过"
+     *     }
+     *   }
+     * }
+     */
+    public function info()
+    {
+        return $this->success($this->service->getCoachInfo(Auth::user()));
+    }
+}

+ 58 - 0
app/Http/Requests/Coach/SubmitBaseInfoRequest.php

@@ -0,0 +1,58 @@
+<?php
+
+namespace App\Http\Requests\Coach;
+
+use Illuminate\Foundation\Http\FormRequest;
+
+class SubmitBaseInfoRequest extends FormRequest
+{
+    public function authorize()
+    {
+        return true;
+    }
+
+    public function rules()
+    {
+        return [
+            'nickname' => 'required|string|min:2|max:20',
+            'avatar' => 'required|url|max:255',
+            'gender' => 'required|in:1,2',
+            'mobile' => ['required', 'string', 'regex:/^1[3-9]\d{9}$/'],
+            'birthday' => [
+                'required',
+                'date',
+                'before:'.now()->subYears(18)->format('Y-m-d'),
+            ],
+            'work_years' => 'required|integer|min:0|max:99',
+            'intention_city' => 'required|string|max:50',
+            'introduction' => 'required|string|min:10|max:255',
+        ];
+    }
+
+    public function messages()
+    {
+        return [
+            'nickname.required' => '昵称不能为空',
+            'nickname.min' => '昵称不能少于2个字符',
+            'nickname.max' => '昵称不能超过20个字符',
+            'avatar.required' => '头像不能为空',
+            'avatar.url' => '头像必须是有效的URL地址',
+            'gender.required' => '性别不能为空',
+            'gender.in' => '性别只能是1(男)或2(女)',
+            'mobile.required' => '手机号不能为空',
+            'mobile.regex' => '手机号格式不正确',
+            'birthday.required' => '出生日期不能为空',
+            'birthday.date' => '出生日期格式不正确',
+            'birthday.before' => '年龄必须满18岁',
+            'work_years.required' => '工作年限不能为空',
+            'work_years.integer' => '工作年限必须是整数',
+            'work_years.min' => '工作年限不能小于0年',
+            'work_years.max' => '工作年限不能超过99年',
+            'intention_city.required' => '意向城市不能为空',
+            'intention_city.max' => '意向城市不能超过50个字符',
+            'introduction.required' => '个人简介不能为空',
+            'introduction.min' => '个人简介不能少于10个字符',
+            'introduction.max' => '个人简介不能超过255个字符',
+        ];
+    }
+}

+ 42 - 0
app/Http/Requests/Coach/SubmitQualificationRequest.php

@@ -0,0 +1,42 @@
+<?php
+
+namespace App\Http\Requests\Coach;
+
+use Illuminate\Foundation\Http\FormRequest;
+
+class SubmitQualificationRequest extends FormRequest
+{
+    public function authorize()
+    {
+        return true;
+    }
+
+    public function rules()
+    {
+        return [
+            'qual_type' => 'required|string|max:50',
+            'qual_no' => 'required|string|min:5|max:50',
+            'qual_photo' => 'required|url|max:255',
+            'valid_start' => 'required|date|date_format:Y-m-d',
+            'valid_end' => 'required|date|date_format:Y-m-d|after:valid_start',
+        ];
+    }
+
+    public function messages()
+    {
+        return [
+            'qual_type.required' => '资质类型不能为空',
+            'qual_type.max' => '资质类型不能超过50个字符',
+            'qual_no.required' => '资质证书编号不能为空',
+            'qual_no.min' => '资质证书编号不能少于5个字符',
+            'qual_no.max' => '资质证书编号不能超过50个字符',
+            'qual_photo.required' => '资质证书照片不能为空',
+            'qual_photo.url' => '资质证书照片必须是有效的URL地址',
+            'valid_start.required' => '有效期开始日期不能为空',
+            'valid_start.date' => '有效期开始日期格式不正确',
+            'valid_end.required' => '有效期结束日期不能为空',
+            'valid_end.date' => '有效期结束日期格式不正确',
+            'valid_end.after' => '有效期结束日期必须大于开始日期',
+        ];
+    }
+}

+ 47 - 0
app/Http/Requests/Coach/SubmitRealNameRequest.php

@@ -0,0 +1,47 @@
+<?php
+
+namespace App\Http\Requests\Coach;
+
+use Illuminate\Foundation\Http\FormRequest;
+
+class SubmitRealNameRequest extends FormRequest
+{
+    public function authorize()
+    {
+        return true;
+    }
+
+    public function rules()
+    {
+        return [
+            'real_name' => 'required|string|min:2|max:20',
+            'id_card' => [
+                'required',
+                'string',
+                'size:18',
+                'regex:/^[1-9]\d{5}(19|20)\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])\d{3}[\dX]$/',
+            ],
+            'id_card_front_photo' => 'required|url|max:255',
+            'id_card_back_photo' => 'required|url|max:255',
+            'id_card_hand_photo' => 'required|url|max:255',
+        ];
+    }
+
+    public function messages()
+    {
+        return [
+            'real_name.required' => '姓名不能为空',
+            'real_name.min' => '姓名不能少于2个字符',
+            'real_name.max' => '姓名不能超过20个字符',
+            'id_card.required' => '身份证号不能为空',
+            'id_card.size' => '身份证号必须是18位',
+            'id_card.regex' => '身份证号格式不正确',
+            'id_card_front_photo.required' => '身份证正面照片不能为空',
+            'id_card_front_photo.url' => '身份证正面照片必须是有效的URL地址',
+            'id_card_back_photo.required' => '身份证反面照片不能为空',
+            'id_card_back_photo.url' => '身份证反面照片必须是有效的URL地址',
+            'id_card_hand_photo.required' => '手持身份证照片不能为空',
+            'id_card_hand_photo.url' => '手持身份证照片必须是有效的URL地址',
+        ];
+    }
+}

+ 6 - 3
app/Models/CoachQualRecord.php

@@ -10,16 +10,19 @@ use Slowlyo\OwlAdmin\Models\BaseModel as Model;
  */
 class CoachQualRecord extends Model
 {
-	use SoftDeletes;
+    use SoftDeletes;
 
-	protected $table = 'coach_qual_records';
+    protected $table = 'coach_qual_records';
+
+    protected $guarded = [];
 
     /**
      * @Author FelixYin
+     *
      * @description 资质记录所属技师
      */
     public function coach()
     {
         return $this->belongsTo('App\Models\CoachUser', 'coach_id');
     }
-}
+}

+ 5 - 3
app/Models/CoachRealRecord.php

@@ -10,7 +10,9 @@ use Slowlyo\OwlAdmin\Models\BaseModel as Model;
  */
 class CoachRealRecord extends Model
 {
-	use SoftDeletes;
+    use SoftDeletes;
 
-	protected $table = 'coach_real_records';
-}
+    protected $table = 'coach_real_records';
+
+    protected $guarded = [];
+}

+ 2 - 2
app/Models/MemberUser.php

@@ -2,12 +2,12 @@
 
 namespace App\Models;
 
-use Illuminate\Database\Eloquent\Model;
 use Illuminate\Database\Eloquent\Relations\HasMany;
 use Illuminate\Database\Eloquent\SoftDeletes;
+use Illuminate\Foundation\Auth\User as Authenticatable;
 use Laravel\Sanctum\HasApiTokens;
 
-class MemberUser extends Model
+class MemberUser extends Authenticatable
 {
     use HasApiTokens, SoftDeletes;
 

+ 300 - 0
app/Services/Coach/AccountService.php

@@ -0,0 +1,300 @@
+<?php
+
+namespace App\Services\Coach;
+
+use App\Enums\TechnicianAuthStatus;
+use Illuminate\Support\Facades\Cache;
+use Illuminate\Support\Facades\DB;
+use Illuminate\Support\Facades\Log;
+
+class AccountService
+{
+    private const CACHE_KEY_PREFIX = 'coach_info_';
+
+    private const CACHE_TTL = 300; // 5分钟
+
+    /**
+     * 提交技师基本信息
+     */
+    public function submitBaseInfo($user, array $data)
+    {
+        DB::beginTransaction();
+        try {
+            $this->setTransactionConfig();
+
+            abort_if(! $user->coach, 404, '技师信息不存在');
+
+            // 检查是否有待审核的记录
+            $pendingRecord = $user->coach->infoRecords()
+                ->where('state', TechnicianAuthStatus::AUDITING->value)
+                ->exists();
+            abort_if($pendingRecord, 422, '已有待审核的基本信息记录');
+
+            // 创建技师信息
+            $record = $user->coach->infoRecords()->create(array_merge($data, [
+                'state' => TechnicianAuthStatus::AUDITING->value,
+            ]));
+
+            // 清除技师信息缓存
+            $this->clearCoachCache($user->coach->id);
+
+            DB::commit();
+
+            $this->logInfo('技师提交基本信息成功', $user, $data);
+
+            return ['message' => '基本信息提交成功'];
+
+        } catch (\Exception $e) {
+            DB::rollBack();
+            $this->logError('提交技师基本信息失败', $user, $data, $e);
+            throw $e;
+        }
+    }
+
+    /**
+     * 提交技师资质信息
+     */
+    public function submitQualification($user, array $data)
+    {
+        DB::beginTransaction();
+        try {
+            $this->setTransactionConfig();
+
+            abort_if(! $user->coach, 404, '技师信息不存在');
+
+            // 检查是否有待审核的记录
+            $pendingRecord = $user->coach->qualRecords()
+                ->where('state', TechnicianAuthStatus::AUDITING->value)
+                ->exists();
+            abort_if($pendingRecord, 422, '已有待审核的资质信息记录');
+
+            // 创建资质信息
+            $record = $user->coach->qualRecords()->create(array_merge($data, [
+                'state' => TechnicianAuthStatus::AUDITING->value,
+            ]));
+
+            // 清除技师信息缓存
+            $this->clearCoachCache($user->coach->id);
+
+            DB::commit();
+
+            $this->logInfo('技师提交资质信息成功', $user, $data);
+
+            return ['message' => '资质信息提交成功'];
+
+        } catch (\Exception $e) {
+            DB::rollBack();
+            $this->logError('提交技师资质信息失败', $user, $data, $e);
+            throw $e;
+        }
+    }
+
+    /**
+     * 提交实名认证信息
+     */
+    public function submitRealName($user, array $data)
+    {
+        DB::beginTransaction();
+        try {
+            $this->setTransactionConfig();
+
+            abort_if(! $user->coach, 404, '技师信息不存在');
+
+            // 检查是否有待审核的记录
+            $pendingRecord = $user->coach->realRecords()
+                ->where('state', TechnicianAuthStatus::AUDITING->value)
+                ->exists();
+            abort_if($pendingRecord, 422, '已有待审核的实名认证信息');
+
+            // 创建实名认证信息
+            $record = $user->coach->realRecords()->create(array_merge($data, [
+                'state' => TechnicianAuthStatus::AUDITING->value,
+            ]));
+
+            // 清除技师信息缓存
+            $this->clearCoachCache($user->coach->id);
+
+            DB::commit();
+
+            $this->logInfo('技师提交实名认证信息成功', $user, $this->maskSensitiveData($data));
+
+            return ['message' => '实名认证信息提交成功'];
+
+        } catch (\Exception $e) {
+            DB::rollBack();
+            $this->logError('提交实名认证信息失败', $user, $this->maskSensitiveData($data), $e);
+            throw $e;
+        }
+    }
+
+    /**
+     * 获取技师信息
+     */
+    public function getCoachInfo($user)
+    {
+        try {
+            abort_if(! $user, 404, '用户不存在');
+            abort_if(! $user->coach, 404, '技师信息不存在');
+
+            return Cache::remember(
+                self::CACHE_KEY_PREFIX.$user->coach->id,
+                self::CACHE_TTL,
+                function () use ($user) {
+                    return $this->fetchCoachInfo($user->coach);
+                }
+            );
+        } catch (\Exception $e) {
+            $this->logError('获取技师信息失败', $user, [], $e);
+            throw $e;
+        }
+    }
+
+    /**
+     * 设置事务配置
+     */
+    private function setTransactionConfig()
+    {
+        DB::statement('SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED');
+        DB::statement('SET SESSION innodb_lock_wait_timeout=10');
+    }
+
+    /**
+     * 记录信息日志
+     */
+    private function logInfo(string $message, $user, array $data)
+    {
+        Log::info($message, [
+            'user_id' => $user->id,
+            'coach_id' => $user->coach->id,
+            'data' => $data,
+            'ip' => request()->ip(),
+            'timestamp' => now()->toDateTimeString(),
+        ]);
+    }
+
+    /**
+     * 记录错误日志
+     */
+    private function logError(string $message, $user, array $data, \Exception $e)
+    {
+        Log::error($message, [
+            'user_id' => $user->id,
+            'coach_id' => $user->coach->id ?? null,
+            'data' => $data,
+            'error' => $e->getMessage(),
+            'file' => $e->getFile(),
+            'line' => $e->getLine(),
+            'ip' => request()->ip(),
+            'timestamp' => now()->toDateTimeString(),
+        ]);
+    }
+
+    /**
+     * 获取技师详细信息
+     */
+    private function fetchCoachInfo($coach)
+    {
+        $baseInfo = $coach->infoRecords()->latest()->first();
+        $qualification = $coach->qualRecords()->latest()->first();
+        $realName = $coach->realRecords()->latest()->first();
+
+        return [
+            'base_info' => $baseInfo ? $this->formatBaseInfo($baseInfo) : null,
+            'qualification' => $qualification ? $this->formatQualification($qualification) : null,
+            'real_name' => $realName ? $this->formatRealName($realName) : null,
+        ];
+    }
+
+    /**
+     * 格式化基本信息
+     */
+    private function formatBaseInfo($info)
+    {
+        return [
+            'nickname' => $info->nickname,
+            'avatar' => $info->avatar,
+            'gender' => $info->gender,
+            'mobile' => $this->maskMobile($info->mobile),
+            'birthday' => $info->birthday,
+            'work_years' => $info->work_years,
+            'intention_city' => $info->intention_city,
+            'introduction' => $info->introduction,
+            'state' => $info->state,
+            'state_text' => TechnicianAuthStatus::fromValue($info->state)->label(),
+            'audit_remark' => $info->audit_remark,
+        ];
+    }
+
+    /**
+     * 格式化资质信息
+     */
+    private function formatQualification($qual)
+    {
+        return [
+            'qual_type' => $qual->qual_type,
+            'qual_no' => $qual->qual_no,
+            'qual_photo' => $qual->qual_photo,
+            'valid_start' => $qual->valid_start,
+            'valid_end' => $qual->valid_end,
+            'state' => $qual->state,
+            'state_text' => TechnicianAuthStatus::fromValue($qual->state)->label(),
+            'audit_remark' => $qual->audit_remark,
+        ];
+    }
+
+    /**
+     * 格式化实名信息
+     */
+    private function formatRealName($real)
+    {
+        return [
+            'real_name' => $real->real_name,
+            'id_card' => $this->maskIdCard($real->id_card),
+            'id_card_front_photo' => $real->id_card_front_photo,
+            'id_card_back_photo' => $real->id_card_back_photo,
+            'id_card_hand_photo' => $real->id_card_hand_photo,
+            'state' => $real->state,
+            'state_text' => TechnicianAuthStatus::fromValue($real->state)->label(),
+            'audit_remark' => $real->audit_remark,
+        ];
+    }
+
+    /**
+     * 手机号脱敏
+     */
+    private function maskMobile($mobile)
+    {
+        return substr_replace($mobile, '****', 3, 4);
+    }
+
+    /**
+     * 身份证号脱敏
+     */
+    private function maskIdCard($idCard)
+    {
+        return substr_replace($idCard, '****', 6, 8);
+    }
+
+    /**
+     * 敏感数据脱敏
+     */
+    private function maskSensitiveData(array $data)
+    {
+        if (isset($data['id_card'])) {
+            $data['id_card'] = $this->maskIdCard($data['id_card']);
+        }
+        if (isset($data['mobile'])) {
+            $data['mobile'] = $this->maskMobile($data['mobile']);
+        }
+
+        return $data;
+    }
+
+    /**
+     * 清除技师信息缓存
+     */
+    private function clearCoachCache($coachId)
+    {
+        Cache::forget(self::CACHE_KEY_PREFIX.$coachId);
+    }
+}

+ 15 - 0
app/Traits/ResponseTrait.php

@@ -0,0 +1,15 @@
+<?php
+
+namespace App\Traits;
+
+trait ResponseTrait
+{
+    protected function success($data = [], $message = 'success')
+    {
+        return [
+            'code' => 0,
+            'message' => $message,
+            'data' => $data,
+        ];
+    }
+}

+ 7 - 15
doc/系统设计/数据库设计/物理模型/分析后台设计增加/07代理列表.sql

@@ -7,14 +7,6 @@
 3. wallet 和 member_users通过判断owner_type和owner_id关联
 4. wallet_withdraw_records和wallet通过wallet_id关联
 */
-DROP TABLE IF EXISTS report_agent_list;
-
-CREATE TABLE report_agent_list AS
-/* 代理信息统计查询 */
-/* 代理列表视图 */
-
-DROP VIEW IF EXISTS manage_agent_list;
-
 CREATE OR REPLACE VIEW manage_agent_list AS
 WITH
     agent_withdraw AS (
@@ -22,10 +14,10 @@ WITH
         FROM
             wallet w
             LEFT JOIN wallet_withdraw_records wr ON w.id = wr.wallet_id
-            AND wr.audit_state = 'approved'
-            AND wr.state = 'success'
+            AND wr.audit_state = 1
+            AND wr.state = 1
         WHERE
-            w.owner_type = 'AGENT'
+            w.owner_type = 3
         GROUP BY
             w.owner_id
     )
@@ -37,15 +29,15 @@ SELECT
     mu.mobile as mobile /* 联系电话 */,
     ai.area_code as area /* 代理地区 */,
     COALESCE(w.total_income, 0) as total_income /* 总收益金额 */,
-    COALESCE(aw.total_withdraw_amount, 0) as withdraw_amount /* 提现金额 */,
     COALESCE(w.available_balance, 0) as balance /* 余额 */
 FROM
     agent_infos ai
-    INNER JOIN member_users mu ON ai.user_id = mu.id
+    LEFT JOIN member_users mu ON ai.user_id = mu.id
     LEFT JOIN wallet w ON w.owner_id = ai.id
-    AND w.owner_type = 'AGENT'
-    LEFT JOIN agent_withdraw aw ON aw.owner_id = mu.id
+    AND w.owner_type = 3
 WHERE
     ai.deleted_at IS NULL
     AND mu.deleted_at IS NULL
     AND w.deleted_at IS NULL;
+
+select * from manage_agent_list;

+ 103 - 88
routes/api.php

@@ -18,108 +18,123 @@ use Illuminate\Support\Facades\Route;
 Route::get('scribe/update-token/{mobile}', [ScribeController::class, 'updateAuthToken']);
 Route::get('/enums', [EnumController::class, 'getEnumData']);
 
-// 无需认证的公开路由
-Route::prefix('account')->group(function () {
-    // 发送验证码
-    Route::post('send-code', [AccountController::class, 'sendVerifyCode']);
-    // 手机号登录
-    Route::post('login', [AccountController::class, 'login']);
-    // 微信登录
-    Route::post('wx-login', [AccountController::class, 'wxLogin']);
-});
+// 客户端路由组
+Route::prefix('client')->group(function () {
 
-// 需要认证的路由组
-Route::middleware('auth:sanctum')->group(function () {
-    // 账号相关
+    // 无需认证的公开路由
     Route::prefix('account')->group(function () {
-        // 退出登录
-        Route::post('logout', [AccountController::class, 'logout']);
-        // 注销账号
-        Route::delete('/', [AccountController::class, 'destroy']);
+        // 发送验证码
+        Route::post('send-code', [AccountController::class, 'sendVerifyCode']);
+        // 手机号登录
+        Route::post('login', [AccountController::class, 'login']);
+        // 微信登录
+        Route::post('wx-login', [AccountController::class, 'wxLogin']);
     });
 
-    // 用户相关
-    Route::prefix('user')->group(function () {
-        // 获取用户信息
-        Route::get('/', [UserController::class, 'show']);
-        // 用户注册
-        Route::post('/', [UserController::class, 'register']);
-        // 更新用户信息
-        Route::put('/', [UserController::class, 'update']);
-
-        // 提现
-        Route::post('withdraw', [UserController::class, 'withdraw']);
-
-        // 用户反馈
-        // Route::post('/feedback', [UserController::class, 'feedback']);
-        // 申请成为技师
-        Route::post('/apply-coach', [UserController::class, 'applyCoach']);
-        // 生成邀请码
-        Route::get('/invite-code', [UserController::class, 'generateInviteCode']);
-    });
+    // 需要认证的路由组
+    Route::middleware('auth:sanctum')->group(function () {
+        // 账号相关
+        Route::prefix('account')->group(function () {
+            // 退出登录
+            Route::post('logout', [AccountController::class, 'logout']);
+            // 注销账号
+            Route::delete('/', [AccountController::class, 'destroy']);
+        });
 
-    // 项目相关
-    Route::prefix('project')->group(function () {
-        Route::get('/', [ProjectController::class, 'index']); // 获取项目列表
-        Route::get('/detail', [ProjectController::class, 'detail']); // 获取项目详情
-        Route::get('/coach-list', [ProjectController::class, 'coachProjectList']); // 获取技师开通的项目列表
-    });
+        // 用户相关
+        Route::prefix('user')->group(function () {
+            // 获取用户信息
+            Route::get('/', [UserController::class, 'show']);
+            // 用户注册
+            Route::post('/', [UserController::class, 'register']);
+            // 更新用户信息
+            Route::put('/', [UserController::class, 'update']);
+
+            // 提现
+            Route::post('withdraw', [UserController::class, 'withdraw']);
+
+            // 用户反馈
+            // Route::post('/feedback', [UserController::class, 'feedback']);
+            // 申请成为技师
+            Route::post('/apply-coach', [UserController::class, 'applyCoach']);
+            // 生成邀请码
+            Route::get('/invite-code', [UserController::class, 'generateInviteCode']);
+        });
 
-    // 技师相关
-    Route::prefix('coach')->group(function () {
-        Route::prefix('location')->group(function () {
-            Route::get('/', [CoachLocationController::class, 'index']); // 获取所有技师定位
-            Route::post('/', [CoachLocationController::class, 'store']); // 创建新的技师定位
-            Route::delete('/{id}', [CoachLocationController::class, 'destroy']);    // 删除技师定位
+        // 项目相关
+        Route::prefix('project')->group(function () {
+            Route::get('/', [ProjectController::class, 'index']); // 获取项目列表
+            Route::get('/detail', [ProjectController::class, 'detail']); // 获取项目详情
+            Route::get('/coach-list', [ProjectController::class, 'coachProjectList']); // 获取技师开通的项目列表
         });
-        Route::get('/', [CoachController::class, 'list']); // 获取技师列表
-        Route::get('/{id}', [CoachController::class, 'detail']); // 获取技师详情
 
-    });
+        // 技师相关
+        Route::prefix('coach')->group(function () {
+            Route::prefix('location')->group(function () {
+                Route::get('/', [CoachLocationController::class, 'index']); // 获取所有技师定位
+                Route::post('/', [CoachLocationController::class, 'store']); // 创建新的技师定位
+                Route::delete('/{id}', [CoachLocationController::class, 'destroy']);    // 删除技师定位
+            });
+            Route::get('/', [CoachController::class, 'list']); // 获取技师列表
+            Route::get('/{id}', [CoachController::class, 'detail']); // 获取技师详情
 
-    // 用户地址相关
-    Route::prefix('address')->group(function () {
-        Route::get('default', [UserAddressController::class, 'getDefault']);
-        Route::post('/', [UserAddressController::class, 'store']);
-        Route::put('/{id}', [UserAddressController::class, 'update']);
-        Route::delete('/{id}', [UserAddressController::class, 'destroy']);
-        Route::put('/{id}/default', [UserAddressController::class, 'setDefault']);
-    });
+        });
 
-    // 订单相关
-    Route::prefix('orders')->group(function () {
-        Route::post('initialize', [OrderController::class, 'initialize']);
-        Route::post('create', [OrderController::class, 'create']);
-        Route::post('cancel', [OrderController::class, 'cancel']);
-        Route::post('finish', [OrderController::class, 'finish']);
-        Route::post('confirm-leave', [OrderController::class, 'confirmLeave']);
-        Route::get('list', [OrderController::class, 'list']);
-        Route::get('detail/{id}', [OrderController::class, 'detail']);
-        Route::post('add-time', [OrderController::class, 'addTime']);
-        Route::post('calculate-order-amount', [OrderController::class, 'calculateOrderAmount']);
-        // Route::post('refund/{id}', [OrderController::class, 'refund']);
-        // Route::post('get-agent-config', [OrderController::class, 'getAgentConfig']);
-        // Route::post('get-coach-config', [OrderController::class, 'getCoachConfig']);
-        // Route::post('calculate-delivery-fee', [OrderController::class, 'calculateDeliveryFee']);
-        Route::get('grab-list', [OrderController::class, 'getOrderGrabList']);
-    });
+        // 用户地址相关
+        Route::prefix('address')->group(function () {
+            Route::get('default', [UserAddressController::class, 'getDefault']);
+            Route::post('/', [UserAddressController::class, 'store']);
+            Route::put('/{id}', [UserAddressController::class, 'update']);
+            Route::delete('/{id}', [UserAddressController::class, 'destroy']);
+            Route::put('/{id}/default', [UserAddressController::class, 'setDefault']);
+        });
 
-    // 钱包相关
-    Route::prefix('wallet')->group(function () {
-        Route::get('records', [WalletController::class, 'records']);
-        // 获取钱包信息
-        Route::get('wallet', [WalletController::class, 'wallet']);
-    });
+        // 订单相关
+        Route::prefix('orders')->group(function () {
+            Route::post('initialize', [OrderController::class, 'initialize']);
+            Route::post('create', [OrderController::class, 'create']);
+            Route::post('cancel', [OrderController::class, 'cancel']);
+            Route::post('finish', [OrderController::class, 'finish']);
+            Route::post('confirm-leave', [OrderController::class, 'confirmLeave']);
+            Route::get('list', [OrderController::class, 'list']);
+            Route::get('detail/{id}', [OrderController::class, 'detail']);
+            Route::post('add-time', [OrderController::class, 'addTime']);
+            Route::post('calculate-order-amount', [OrderController::class, 'calculateOrderAmount']);
+            // Route::post('refund/{id}', [OrderController::class, 'refund']);
+            // Route::post('get-agent-config', [OrderController::class, 'getAgentConfig']);
+            // Route::post('get-coach-config', [OrderController::class, 'getCoachConfig']);
+            // Route::post('calculate-delivery-fee', [OrderController::class, 'calculateDeliveryFee']);
+            Route::get('grab-list', [OrderController::class, 'getOrderGrabList']);
+        });
+
+        // 钱包相关
+        Route::prefix('wallet')->group(function () {
+            Route::get('records', [WalletController::class, 'records']);
+            // 获取钱包信息
+            Route::get('wallet', [WalletController::class, 'wallet']);
+        });
+
+        // 团队管理路由
+        Route::prefix('team')->group(function () {
+            Route::get('list', [MarketDistTeamController::class, 'index'])->name('team.list');
+        });
 
-    // 团队管理路由
-    Route::prefix('team')->group(function () {
-        Route::get('list', [MarketDistTeamController::class, 'index'])->name('team.list');
     });
 
-    // 技师端路由组
-    Route::prefix('coach')->middleware(['auth:sanctum'])->group(function () {
-        // 技师端路由组
-        Route::get('orders/grab-list', [CoachOrderController::class, 'getGrabList']);
+});
+
+// 技师端路由组
+Route::prefix('coach')->middleware(['auth:sanctum', 'throttle:6,1'])->group(function () {
+    // 账户相关路由组
+    Route::prefix('account')->group(function () {
+        Route::post('base-info', [App\Http\Controllers\Coach\AccountController::class, 'submitBaseInfo'])
+            ->name('coach.account.base-info');
+        Route::post('qualification', [App\Http\Controllers\Coach\AccountController::class, 'submitQualification']);
+        Route::post('real-name', [App\Http\Controllers\Coach\AccountController::class, 'submitRealName'])
+            ->middleware('throttle:3,1');  // 实名认证限制更严格
+        Route::get('info', [App\Http\Controllers\Coach\AccountController::class, 'info']);
     });
 
+    // 订单相关路由
+    Route::get('orders/grab-list', [CoachOrderController::class, 'getGrabList']);
 });