marketDistTeamService = $marketDistTeamService; } /** * 获取当前用户信息 * * 业务逻辑: * 1. 通过 Auth 门面获取当前登录用户信息 * 2. 加载用户的技师信息 * 3. 翻译技师状态 * * @return MemberUser 返回用户信息 * * @throws \Exception 获取用户信息失败时抛出异��� */ public function getUserInfo(): MemberUser { try { /** @var MemberUser $user */ $user = Auth::user(); // 加载技师信息 $user->load('coach:id,user_id,state'); return $user; } catch (\Exception $e) { // 记录错误日志 Log::error('获取用户信息失败', ['error' => $e->getMessage()]); throw $e; } } /** * 用户注册 * * 业务逻辑: * 1. 验证手机号是否已被注册 * 2. 验证短信验证码 * 3. 创建新用户记录 * 4. 处理邀请关系(如果有) * * @param string $mobile 手机号 * @param string $code 验证码 * @param string|null $invite_code 邀请码(选填) * @param int|null $invite_id 邀请人ID(选填) * @param string|null $invite_role 邀请人角色(选填) * @return \Illuminate\Http\JsonResponse 返回注册结果 * * @throws \Exception 注册过程中出现错误时抛出异常 */ public function register(string $mobile, string $code, ?string $invite_code = null, ?int $invite_id = null, ?string $invite_role = null): array { try { DB::beginTransaction(); // 检查手机号是否已��册 abort_if(MemberUser::where('mobile', $mobile)->exists(), 422, '该手机号已注册'); // 验证短信验证码 abort_if(! $this->verifySmsCode($mobile, $code), 422, '验证码错或已过期'); // 创建用户 $user = MemberUser::create([ 'mobile' => $mobile, 'password' => bcrypt(substr($mobile, -6)), // 默认密码为手机号后6位 'nickname' => substr_replace($mobile, '****', 3, 4), // 默认昵称为手机号(中间4位隐藏) ]); // 处理邀请关系 if ($invite_code && $invite_role && $invite_id) { $this->marketDistTeamService->createInviteRelation($user, $invite_code, $invite_id, $invite_role); } DB::commit(); return [ 'user_id' => $user->id, 'mobile' => $mobile, 'invite_code' => $user->invite_code, ]; } catch (\Exception $e) { DB::rollBack(); Log::error('用户注册', ['error' => $e->getMessage(), 'mobile' => $mobile]); throw $e; } } /** * 验证短信验证码 * * 业务逻辑: * 1. 从 Redis 获取存储的验证码 * 2. 比对验证码是否匹配 * 3. 验证成功后删除缓存验证码 * * @param string $mobile 手机号 * @param string $code 待验证的验证码 * @return bool 返回验证结果 */ private function verifySmsCode(string $mobile, string $code): bool { try { $cacheKey = "sms_code:{$mobile}"; $cacheCode = Redis::get($cacheKey); if (! $cacheCode || $cacheCode !== $code) { return false; } Redis::del($cacheKey); // 验证成功后删除验证码 return true; } catch (\Exception $e) { Log::error('验证码验证失败', ['error' => $e->getMessage(), 'mobile' => $mobile]); return false; } } /** * 更新当前用户信息 * * 业务逻辑: * 1. 获取当前登录用户 * 2. 更新用户基本信息 * * @param array $data 待更新的用户数据 * @return \Illuminate\Http\JsonResponse 返回更新结果 * * @throws \Exception 更新失败时抛出异常 */ public function updateUserInfo(array $data): MemberUser { try { DB::beginTransaction(); // 更新用户信息 $user = Auth::user(); $user->update($data); DB::commit(); return $user->fresh(); } catch (\Exception $e) { DB::rollBack(); Log::error('更新用户信息失败', ['error' => $e->getMessage(), 'data' => $data]); throw $e; } } /** * 提交用户反馈 * * 业务逻辑: * 1. 创建用户反馈记录 * 2. 保存反馈内容和图片 * 3. 记录用户联系方式(如果提供) * * @param string $content 反馈内容 * @param array $images 反馈图片数组 * @param string|null $contact 联系方式 * @return \Illuminate\Http\JsonResponse 返回提交结果 * * @throws \Exception 提交反馈失败时抛出异常 */ public function feedback(string $content, array $images = [], ?string $contact = null): void //Feedback { try { DB::beginTransaction(); // 创建反馈记录 // $feedback = Feedback::create([ // 'user_id' => Auth::user()->id, // 'content' => $content, // 'images' => $images, // 'contact' => $contact, // ]); DB::commit(); // return $feedback; } catch (\Exception $e) { DB::rollBack(); Log::error('提交反馈失败', ['error' => $e->getMessage(), 'content' => $content]); throw $e; } } /** * 检查用户是否可以申请成为技师 * * 业务逻辑: * 1. 检查用户是否已经是技师 * 2. 检查是否有正在审核的申请 * 3. 如果不满足条件则抛出异常 * * @throws \Exception 当用户不满足申请条件时抛出异常 */ private function checkCoachApplicationEligibility(): void { /** @var MemberUser $user */ $user = Auth::user(); // 检查是否已经是技师且状态不是已终止 abort_if( $user->coach && $user->coach->state != TechnicianStatus::PENDING->value, 422, '您已是技师,无需重复申请' ); // 检查是否有正在审核的申请 $hasActiveApplication = CoachUser::where('user_id', $user->id) ->whereHas('infoRecords', function ($query) { $query->where('state', TechnicianAuthStatus::AUDITING->value); }) ->exists(); abort_if( $hasActiveApplication, 422, '您有正在审核的申请,请耐心等待' ); } /** * 申请成为技师 * * 业务逻辑: * 1. 检查户申请资格 * 2. 创建或更新技师基础信息 * 3. 创建申请记录 * * @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 返回申请记录 * * @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(); // 检查申请资格 $this->checkCoachApplicationEligibility(); /** @var MemberUser $user */ $user = Auth::user(); // 获取用户技师身份 $coach = $user->coach; // 如果用户不存在技师身份 if(!$coach){ // 创建技师用户记录 $coach = CoachUser::create([ 'user_id' => $user->id, 'state' => TechnicianStatus::PENDING->value, ]); } // 创建技师信息记录 $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, ]); // 更新技师用户记录的信息记录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. 获取当前户信息 * 2. 根据用户型生成邀请码 * 3. 生成包含邀请参数的接 * 4. 生成邀请维码 * 5. 记录邀请码生成日志 * * @param string $type 邀请码类型(user/coach) * @return array 返回邀请码和二维码信息 * * @throws \Exception 生成邀请码失败时抛出异常 */ public function generateInviteCode(string $type = 'user'): array { try { /** @var MemberUser $user */ // 1. 获取当前用户 $user = Auth::user(); // 2. 根据类型获取邀请人ID和角色 $inviteInfo = $this->getInviteInfo($user, $type); if (! $inviteInfo) { throw new \Exception('无法生邀请码,用户类型不匹配'); } // 3. 生成邀请码 $inviteCode = $this->generateInviteCodeByType( $type, $inviteInfo['id'] ); // 4. 生成邀请链接和二维码 $inviteUrl = $this->generateInviteUrl($inviteCode); $qrCode = $this->generateQrCode($inviteUrl); // 5. 记录日志 Log::info('生成邀请码', [ 'user_id' => $user->id, 'type' => $type, 'invite_id' => $inviteInfo['id'], 'invite_code' => $inviteCode, 'invite_url' => $inviteUrl, ]); return [ 'invite_code' => $inviteCode, 'invite_url' => $inviteUrl, 'qr_code' => $qrCode, ]; } catch (\Exception $e) { Log::error('生成邀请码失', [ 'error' => $e->getMessage(), 'user_id' => Auth::id(), 'type' => $type, ]); throw $e; } } /** * 获取邀请人信息 * * 业务逻辑: * 1. 根据类型判断邀请人身份 * 2. 户类型:直接返回用信息 * 3. 技师类型: * - 验证技师状态 * - 返回技师信息 * * @param \App\Models\MemberUser $user 当前用户 * @param string $type 邀请类型(user/coach) * @return array|null 返回邀请人信息,无效类型返回null */ private function getInviteInfo(MemberUser $user, string $type): ?array { switch ($type) { case 'user': return [ 'id' => $user->id, 'role' => 'user', ]; case 'coach': $coach = $user->coach; if ($coach && $coach->state === TechnicianAuthStatus::PASSED) { return [ 'id' => $coach->id, 'role' => 'coach', ]; } return null; default: return null; } } /** * 根据类型生成邀请码 * * 业务逻辑: * 1. 合类型和ID * 2. 生成格式化的邀请码 * * @param string $type 邀请类型(user/coach) * @param int $id 邀请人ID * @return string 返回格式为 "type_id" 的邀请码 */ private function generateInviteCodeByType(string $type, int $id): string { return sprintf('%s_%d', $type, $id); } /** * 生成邀请链接 * * 业务逻辑: * 1. 获取应用URL * 2. 添加邀请码参数 * 3. 生成完整的邀请链接 * * @param string $inviteCode 邀请码 * @return string 返回完整的邀请链接 */ private function generateInviteUrl(string $inviteCode): string { return config('app.url') . '/invite?' . http_build_query(['invite_code' => $inviteCode]); } /** * 生成二码 * * 业务逻: * 1. 使用 QrCode 库生成 SVG 格式二维码 * 2. 设置二维码大小和边距 * 3. 转换为 base64 编码 * * @param string $content 二维码内容 * @return string 返回 base64 编码的二维码图片 */ private function generateQrCode(string $content): string { $qrImage = QrCode::format('svg') ->size(200) ->margin(2) ->encoding('UTF-8') ->generate($content); return 'data:image/svg+xml;base64,' . base64_encode($qrImage); } /** * 获取技师申请记录 * * 业务逻辑: * 1. 获取当前用户的技师信息 * 2. 如果用户不是技师,返回 null * 3. 获取最新的申请记录 * * @return CoachInfoRecord|null 返回申请记录,未找到时返回 null */ public function getCoachApplication(): ?CoachInfoRecord { try { /** @var MemberUser $user */ $user = Auth::user(); // 确保用户已登录 abort_if(! $user, 401, '用户未登录'); $coach = $user->coach; // 如果用户不是技师,返回 null if (! $coach) { return null; } // 获取最新的申请记录 return $coach->info; } catch (\Exception $e) { Log::error('获取技师申请记录失败', [ 'error' => $e->getMessage(), 'user_id' => Auth::id(), ]); throw $e; } } }