Browse Source

feat:用户端-绑定手机号

刘学玺 4 months ago
parent
commit
60ec2d432a

+ 61 - 5
app/Http/Controllers/Client/AccountController.php

@@ -3,6 +3,7 @@
 namespace App\Http\Controllers\Client;
 
 use App\Http\Controllers\Controller;
+use App\Http\Requests\Client\Account\BindMobileRequest;
 use App\Http\Requests\Client\Account\LoginRequest;
 use App\Http\Requests\Client\Account\SendVerifyCodeRequest;
 use App\Http\Requests\Client\Account\WxLoginRequest;
@@ -28,7 +29,6 @@ class AccountController extends Controller
      *
      * 向指定手机号发送验证码,用于登录或注册验证
      *
-     * @group 用户端-账户管理
      *
      * @bodyParam mobile string required 手机号码,必须是11位有效的中国大陆手机号. Example: 13800138000
      *
@@ -67,7 +67,6 @@ class AccountController extends Controller
      *
      * 使用手机号和验证码进行登录,支持新用户自动注册
      *
-     * @group 用户端-账户管理
      *
      * @bodyParam mobile string required 手机号码,必须是11位有效的中国大陆手机号. Example: 13800138000
      * @bodyParam code string required 验证码,必须是6位数字. Example: 123456
@@ -123,7 +122,6 @@ class AccountController extends Controller
      *
      * 使用微信openid进行登录,支持新用户自动注册,可选同步微信用户信息
      *
-     * @group 用户端-账户管理
      *
      * @bodyParam openid string required 微信openid,必须是有效的微信用户标识. Example: wx_123456789
      * @bodyParam userInfo.nickname string optional 用户昵称. Example: 张三
@@ -172,7 +170,6 @@ class AccountController extends Controller
      *
      * 退出当前用户的登录状态,清除认证令牌
      *
-     * @group 用户端-账户管理
      *
      * @authenticated
      *
@@ -201,7 +198,6 @@ class AccountController extends Controller
      *
      * 永久注销当前用户账号,清除认证令牌,账号将无法恢复
      *
-     * @group 用户端-账户管理
      *
      * @authenticated
      *
@@ -229,4 +225,64 @@ class AccountController extends Controller
             $this->service->deleteAccount()
         );
     }
+
+    /**
+     * [账户]绑定/修改手机号
+     *
+     * 为当前用户绑定新的手机号,如已绑定则更新为新手机号
+     *
+     *
+     * @authenticated
+     *
+     * @bodyParam mobile string required 新手机号码,必须是11位有效的中国大陆手机号. Example: 13800138000
+     * @bodyParam code string required 验证码,必须是6位数字. Example: 123456
+     *
+     * @response 200 {
+     *   "code": 200,
+     *   "message": "手机号绑定成功",
+     *   "data": {
+     *     "message": "手机号绑定成功",
+     *     "user": {
+     *       "id": 1,
+     *       "mobile": "13800138000",
+     *       "nickname": "张三",
+     *       "avatar": "https://example.com/avatar.jpg",
+     *       "gender": 1,
+     *       "state": "open",
+     *       "register_area": "330100",
+     *       "created_at": "2024-01-01 00:00:00",
+     *       "updated_at": "2024-01-01 00:00:00"
+     *     }
+     *   }
+     * }
+     * @response 422 {
+     *   "code": 422,
+     *   "message": "验证失败",
+     *   "data": {
+     *     "mobile": ["手机号格式不正确"],
+     *     "code": ["验证码必须是6位数字"]
+     *   }
+     * }
+     * @response 400 {
+     *   "code": 400,
+     *   "message": "验证码错误",
+     *   "data": null
+     * }
+     * @response 409 {
+     *   "code": 409,
+     *   "message": "手机号已被其他用户使用",
+     *   "data": null
+     * }
+     */
+    public function bindMobile(BindMobileRequest $request)
+    {
+        $validated = $request->validated();
+
+        return $this->success(
+            $this->service->bindMobile(
+                $validated['mobile'],
+                $validated['code']
+            )
+        );
+    }
 }

+ 69 - 0
app/Http/Requests/Client/Account/BindMobileRequest.php

@@ -0,0 +1,69 @@
+<?php
+
+namespace App\Http\Requests\Client\Account;
+
+use Illuminate\Foundation\Http\FormRequest;
+
+class BindMobileRequest extends FormRequest
+{
+    /**
+     * 确定用户是否有权提交此请求
+     */
+    public function authorize(): bool
+    {
+        return true;
+    }
+
+    /**
+     * 获取应用于请求的验证规则
+     *
+     * @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array|string>
+     */
+    public function rules(): array
+    {
+        return [
+            'mobile' => [
+                'required',
+                'string',
+                'regex:/^1[3-9]\d{9}$/',
+                'max:11',
+            ],
+            'code' => [
+                'required',
+                'string',
+                'size:6',
+            ],
+        ];
+    }
+
+    /**
+     * 获取已定义验证规则的错误消息
+     *
+     * @return array<string, string>
+     */
+    public function messages(): array
+    {
+        return [
+            'mobile.required' => '手机号不能为空',
+            'mobile.string' => '手机号必须是字符串',
+            'mobile.regex' => '手机号格式不正确',
+            'mobile.max' => '手机号不能超过11位',
+            'code.required' => '验证码不能为空',
+            'code.string' => '验证码必须是字符串',
+            'code.size' => '验证码必须是6位数字',
+        ];
+    }
+
+    /**
+     * 获取验证错误的自定义属性
+     *
+     * @return array<string, string>
+     */
+    public function attributes(): array
+    {
+        return [
+            'mobile' => '手机号',
+            'code' => '验证码',
+        ];
+    }
+}

+ 47 - 2
app/Services/Client/AccountService.php

@@ -148,7 +148,7 @@ class AccountService
      * 用户退出
      * 业务逻辑:
      * 1. 根据用户ID查找用户
-     * 2. 验证用户是否存在,不在则中断请求
+     * 2. 验证用户是否存在,不���在则中断请求
      * 3. 删除用户所有token
      * 4. 返回退出成功消息
      *
@@ -329,7 +329,7 @@ class AccountService
     {
         // 使用 firstOrCreate 方法查找或创建社交账号记录
         return MemberSocialAccount::firstOrCreate(
-            // 查询条件:平台类型社交ID
+            // 查询条件:平台类型��社交ID
             [
                 'platform' => 'WECHAT',     // 设置平台为微信
                 'social_id' => $openid,     // 设置微信openid
@@ -576,4 +576,49 @@ class AccountService
             ]);
         }
     }
+
+    /**
+     * 绑定/修改手机号
+     * 业务逻辑:
+     * 1. 验证用户输入的验证码是否正确
+     * 2. 检查新手机号是否已被其他用户使用
+     * 3. 更新用户手机号
+     * 4. 返回更新后的用户信息
+     *
+     * @param string $mobile 新手机号
+     * @param string $code 验证码
+     * @return array 包含成功消息和更新后的用户信息
+     *
+     * @throws BusinessException 手机号已被使用时抛出异常
+     */
+    public function bindMobile(string $mobile, string $code): array
+    {
+        // 使用事务确保数据一致性
+        return DB::transaction(function () use ($mobile, $code) {
+            // 验证验证码
+            $this->verifyCode($mobile, $code);
+
+            // 获取当前用户
+            $user = $this->getCurrentUser();
+
+            // 检查手机号是否已被其他用户使用
+            $existingUser = MemberUser::where('mobile', $mobile)
+                ->where('id', '!=', $user->id)
+                ->exists();
+
+            if ($existingUser) {
+                throw new BusinessException('手机号已被其他用户使用', 409);
+            }
+
+            // 更新用户手机号
+            $user->mobile = $mobile;
+            $user->save();
+
+            // 返回成功消息和更新后的用户信息
+            return [
+                'message' => '手机号绑定成功',
+                'user' => $user->fresh(),
+            ];
+        });
+    }
 }

+ 4 - 1
routes/api.php

@@ -43,6 +43,9 @@ Route::prefix('client')->group(function () {
             Route::post('logout', [AccountController::class, 'logout']);
             // 注销账号
             Route::delete('/', [AccountController::class, 'destroy']);
+            // 绑定手机号
+            Route::post('bind-mobile', [AccountController::class, 'bindMobile'])
+                ->middleware(['throttle:6,1']);  // 添加频率限制;
         });
 
         // 用户相关
@@ -57,7 +60,7 @@ Route::prefix('client')->group(function () {
             // 提现
             Route::post('withdraw', [UserController::class, 'withdraw']);
 
-            // 户反馈
+            // 户反馈
             // Route::post('/feedback', [UserController::class, 'feedback']);
             // 申请成为技师
             Route::post('/apply-coach', [UserController::class, 'applyCoach']);