|
@@ -2,86 +2,89 @@
|
|
|
|
|
|
namespace App\Services\Coach;
|
|
|
|
|
|
-use App\Models\MemberUser;
|
|
|
+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(int $userId, array $data)
|
|
|
+ public function submitBaseInfo($user, array $data)
|
|
|
{
|
|
|
DB::beginTransaction();
|
|
|
try {
|
|
|
- // 获取当前登录用户
|
|
|
- $user = MemberUser::find($userId);
|
|
|
- $coach = $user->coach;
|
|
|
+ $this->setTransactionConfig();
|
|
|
+
|
|
|
+ abort_if(! $user->coach, 404, '技师信息不存在');
|
|
|
+
|
|
|
+ // 检查是否有待审核的记录
|
|
|
+ $pendingRecord = $user->coach->infoRecords()
|
|
|
+ ->where('state', TechnicianAuthStatus::AUDITING->value)
|
|
|
+ ->exists();
|
|
|
+ abort_if($pendingRecord, 422, '已有待审核的基本信息记录');
|
|
|
|
|
|
// 创建技师信息
|
|
|
- $coach->infoRecords()->create(
|
|
|
- [
|
|
|
- 'nickname' => $data['nickname'],
|
|
|
- 'avatar' => $data['avatar'],
|
|
|
- 'gender' => $data['gender'],
|
|
|
- 'mobile' => $data['mobile'],
|
|
|
- 'birthday' => $data['birthday'],
|
|
|
- 'work_years' => $data['work_years'],
|
|
|
- 'intention_city' => $data['intention_city'],
|
|
|
- 'introduction' => $data['introduction'],
|
|
|
- ]
|
|
|
- );
|
|
|
+ $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();
|
|
|
- Log::error('提交技师基本信息失败:', [
|
|
|
- 'message' => $e->getMessage(),
|
|
|
- 'data' => $data,
|
|
|
- ]);
|
|
|
+ $this->logError('提交技师基本信息失败', $user, $data, $e);
|
|
|
throw $e;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 提交技师资质信息
|
|
|
- *
|
|
|
- * @param int $userId 用户ID
|
|
|
- * @param array $data 资质信息数据
|
|
|
- *
|
|
|
- * @throws \Exception 提交失败时抛出异常
|
|
|
*/
|
|
|
- public function submitQualification(int $userId, array $data)
|
|
|
+ public function submitQualification($user, array $data)
|
|
|
{
|
|
|
DB::beginTransaction();
|
|
|
try {
|
|
|
- // 获取当前登录用户
|
|
|
- $user = MemberUser::find($userId);
|
|
|
- $coach = $user->coach;
|
|
|
-
|
|
|
- // 更新技师资质信息
|
|
|
- $coach->qualRecords()->create([
|
|
|
- 'qual_type' => $data['qual_type'],
|
|
|
- 'qual_no' => $data['qual_no'],
|
|
|
- 'qual_photo' => $data['qual_photo'],
|
|
|
- 'valid_start' => $data['valid_start'],
|
|
|
- 'valid_end' => $data['valid_end'],
|
|
|
- ]);
|
|
|
+ $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();
|
|
|
- Log::error('提交技师资质信息失败:', [
|
|
|
- 'message' => $e->getMessage(),
|
|
|
- 'data' => $data,
|
|
|
- ]);
|
|
|
+ $this->logError('提交技师资质信息失败', $user, $data, $e);
|
|
|
throw $e;
|
|
|
}
|
|
|
}
|
|
@@ -89,34 +92,209 @@ class AccountService
|
|
|
/**
|
|
|
* 提交实名认证信息
|
|
|
*/
|
|
|
- public function submitRealName(int $userId, array $data)
|
|
|
+ public function submitRealName($user, array $data)
|
|
|
{
|
|
|
DB::beginTransaction();
|
|
|
try {
|
|
|
- // 获取当前登录用户
|
|
|
- $user = MemberUser::find($userId);
|
|
|
- $coach = $user->coach;
|
|
|
-
|
|
|
- // 更新实名信息
|
|
|
- $coach->realRecords()->create([
|
|
|
- 'real_name' => $data['real_name'],
|
|
|
- 'id_card' => $data['id_card'],
|
|
|
- 'id_card_front_photo' => $data['id_card_front_photo'],
|
|
|
- 'id_card_back_photo' => $data['id_card_back_photo'],
|
|
|
- 'id_card_hand_photo' => $data['id_card_hand_photo'],
|
|
|
- ]);
|
|
|
+ $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();
|
|
|
- Log::error('提交实名认证信息失败:', [
|
|
|
- 'message' => $e->getMessage(),
|
|
|
- 'data' => $data,
|
|
|
- ]);
|
|
|
+ $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);
|
|
|
+ }
|
|
|
}
|