find(); if (!$interview) { self::setError('面试不存在'); return false; } if ($interview->user_id != self::$userId) { self::setError('无权限操作该面试的对话记录'); return false; } return true; } /** * @desc 获取详情 * @param int $id * @return bool * @throws DataNotFoundException * @throws DbException * @throws ModelNotFoundException */ public static function detail(int $id): bool { try { $dialog = InterviewDialog::where('id', $id)->findOrEmpty(); if ($dialog->isEmpty()) { self::setError('对话记录不存在'); return false; } // 验证权限 if (!self::verifyPermission($dialog->interview_id)) { return false; } $data = $dialog->toArray(); $data['type_text'] = InterviewDialog::getTypeText($data['type']); self::$returnData = $data; return true; } catch (\Exception $e) { self::setError('获取失败:' . $e->getMessage()); return false; } } /** * @desc 根据面试ID获取对话记录 * @param int $interviewId * @return bool * @throws DataNotFoundException * @throws DbException * @throws ModelNotFoundException */ public static function getByInterviewId(int $interviewId): bool { if (empty($interviewId)) { self::setError('参数错误'); return false; } $list = InterviewDialog::where('interview_id', $interviewId) ->order('create_time', 'asc') ->select() ->toArray(); // 处理数据 foreach ($list as &$item) { $item['type_text'] = self::getTypeText($item['type']); $item['create_time_text'] = date('Y-m-d H:i:s', $item['create_time']); } self::$returnData = $list; return true; } /** * @desc 统计数据 * @param array $params * @return bool * @throws DbException */ public static function stat(array $params): bool { if (empty($params['interview_id'])) { self::setError('参数错误'); return false; } $interviewId = $params['interview_id']; // 统计各类型问题数量 $typeCounts = InterviewDialog::where('interview_id', $interviewId) ->group('type') ->column('count(id)', 'type'); // 获取最后一次对话时间 $lastDialog = InterviewDialog::where('interview_id', $interviewId) ->order('create_time', 'desc') ->find(); $totalCount = InterviewDialog::where('interview_id', $interviewId)->count(); $data = [ 'total_count' => $totalCount, 'focus_question_count' => $typeCounts[1] ?? 0, 'deep_question_count' => $typeCounts[2] ?? 0, 'normal_question_count' => $typeCounts[3] ?? 0, 'opening_count' => $typeCounts[4] ?? 0, 'last_dialog_time' => $lastDialog ? date('Y-m-d H:i:s', $lastDialog['create_time']) : '', ]; self::$returnData = $data; return true; } /** * @desc 获取类型文本 * @param int $type * @return string */ private static function getTypeText(int $type): string { $typeMap = [ 1 => '带关注的问题', 2 => '深入的问题', 3 => '不带关注的问题', 4 => '开场白' ]; return $typeMap[$type] ?? '未知类型'; } /** * 添加对话记录 * @param array $params * @return bool */ public static function add(array $params): bool { Db::startTrans(); try { // 验证权限 if (!self::verifyPermission($params['interview_id'])) { return false; } $params['create_time'] = $params['update_time'] = time(); $dialog = InterviewDialog::create($params); Db::commit(); self::$returnData = $dialog->toArray(); return true; } catch (\Exception $e) { Db::rollback(); self::setError('添加失败:' . $e->getMessage()); return false; } } /** * 更新对话记录 * @param array $params * @return bool */ public static function update(array $params): bool { Db::startTrans(); try { $dialog = InterviewDialog::where('id', $params['id'])->findOrEmpty(); if ($dialog->isEmpty()) { self::setError('对话记录不存在'); return false; } // 验证权限 if (!self::verifyPermission($dialog->interview_id)) { return false; } $params['update_time'] = time(); $dialog->save($params); Db::commit(); return true; } catch (\Exception $e) { Db::rollback(); self::setError('更新失败:' . $e->getMessage()); return false; } } /** * 删除对话记录 * @param array $params * @return bool */ public static function delete(array $params): bool { Db::startTrans(); try { $dialog = InterviewDialog::where('id', $params['id'])->findOrEmpty(); if ($dialog->isEmpty()) { self::setError('对话记录不存在'); return false; } // 验证权限 if (!self::verifyPermission($dialog->interview_id)) { return false; } $dialog->delete_time = time(); $dialog->save(); Db::commit(); return true; } catch (\Exception $e) { Db::rollback(); self::setError('删除失败:' . $e->getMessage()); return false; } } /** * 处理面试结束(退出或中断) * @param array $params * @param int $endType 结束类型:1-主动退出,2-意外中断,3-重新开始 * @return bool */ public static function endInterview(array $params, int $endType = 1): bool { Db::startTrans(); try { $userId = $params['user_id']; $interviewId = $params['interview_id']; // 根据结束类型确定原因字段和消息 if ($endType == 1) { // 主动退出 $reason = $params['reason'] ?? '用户主动退出面试'; $statusCode = Interview::STATUS_EXITED; $dialogType = InterviewDialog::TYPE_OPENING; $reasonField = 'out_reason'; $endMessage = '好的,大致情况我已经了解,本轮面试已结束,感谢您的配合,请提交面试过程并耐心等待通知。'; } elseif ($endType == 2) { // 意外中断 $reason = $params['reason'] ?? '聊天意外中断'; $endMessage = '很抱歉,本次面试由于意外中断。您可以选择重新开始面试或稍后再试。'; $statusCode = Interview::STATUS_INTERRUPTED; $dialogType = InterviewDialog::TYPE_OPENING; $reasonField = 'out_reason'; // 使用相同字段存储 } else { // 重新开始 $reason = $params['reason'] ?? '用户重新开始面试'; $statusCode = Interview::STATUS_RESTART; $dialogType = InterviewDialog::TYPE_OPENING; $reasonField = 'restart_reason'; $endMessage = '好的,大致情况我已经了解,本轮面试已结束,感谢您的配合,请提交面试过程并耐心等待通知。'; // 确保定义了 $endMessage } // 检查面试是否存在 $interview = Interview::where(['id' => $interviewId, 'user_id' => $userId]) ->findOrEmpty(); $returnData = [ 'id' => '', 'status' => '', 'end_message' => $endMessage ]; if ($interview->isEmpty()) { self::$returnData = $returnData; return true; } $returnData = [ 'id' => $interviewId, 'status' => $interview->status, 'end_message' => $endMessage ]; if ($interview->status != 0) { self::$returnData = $returnData; return true; } // 检查面试记录 $interviewRecord = InterviewRecord::where(['id' => $interview->interview_record_id, 'user_id' => $userId]) ->findOrEmpty(); if ($interviewRecord->isEmpty()) { self::$returnData = $returnData; return true; } if ($interviewRecord->status == 1) { self::$returnData = $returnData; return true; } // 更新面试状态 $interview->status = $statusCode; $interview->reason = $reason; $interview->end_time = time(); $interview->save(); $time = time(); $duration = $time - $interviewRecord->first_start_time; // 更新面试记录 $interviewRecord->reason = $reason; $interviewRecord->status = $statusCode; $interviewRecord->last_interview_id = $interviewId; $interviewRecord->last_end_time = $time; $interviewRecord->duration = $duration; $interviewRecord->save(); $curDialog = InterviewDialog::where(['interview_id' => $interviewId]) ->order('id', 'desc') ->findOrEmpty(); if (!$curDialog->isEmpty()) { $curDialog->out_reason = $reason; if ($endType == 3) { $curDialog->restart_reason = $reason; } $curDialog->save(); } else { InterviewDialog::create([ 'interview_id' => $interviewId, 'type' => $dialogType, 'question' => $endMessage, $reasonField => $reason, 'create_time' => time(), 'update_time' => time() ]); } Db::commit(); // 准备返回数据 // 如果是意外中断,添加可重新开始标记 if ($endType == 2) { $returnData['can_restart'] = true; } self::$returnData = $returnData; return true; } catch (Exception $e) { Db::rollback(); // 根据结束类型设置不同的错误码 if ($endType == 1) { self::setError('退出失败:' . $e->getMessage()); } elseif ($endType == 2) { self::setError('处理中断失败:' . $e->getMessage()); } else { self::setError('重新开始失败:' . $e->getMessage()); } return false; } } /** * 创建新面试会话 * @param array $params ['user_id', 'job_id'] * @return bool */ public static function createNewInterview(array $params): bool { Db::startTrans(); try { $userId = $params['user_id']; $jobId = $params['job_id']; // 查找该用户该岗位的面试记录 $interviewRecord = InterviewRecord::where(['user_id' => $userId, 'job_id' => $jobId]) ->findOrEmpty(); // 如果没有记录,创建新记录 if ($interviewRecord->isEmpty()) { $interviewRecord = InterviewRecord::create([ 'user_id' => $userId, 'job_id' => $jobId, 'first_start_time' => time(), 'status' => InterviewRecord::STATUS_ONGOING, 'total_sessions' => 0 ]); } // 计算当前会话序号 $sessionNumber = $interviewRecord->total_sessions + 1; // 创建新的面试会话 $interview = Interview::create([ 'user_id' => $userId, 'interview_record_id' => $interviewRecord->id, 'job_id' => $jobId, 'start_time' => time(), 'status' => Interview::STATUS_ONGOING, 'session_number' => $sessionNumber ]); // 更新面试记录的总会话数 $interviewRecord->total_sessions = $sessionNumber; $interviewRecord->last_interview_id = $interview->id; $interviewRecord->save(); // 创建开场白对话 $openingMessage = "欢迎参加面试,这是您第 {$sessionNumber} 次面试会话。请准备好开始回答问题。"; InterviewDialog::create([ 'interview_id' => $interview->id, 'type' => InterviewDialog::TYPE_OPENING, 'question' => $openingMessage, 'sequence' => 1 ]); Db::commit(); self::$returnData = [ 'interview_id' => $interview->id, 'record_id' => $interviewRecord->id, 'session_number' => $sessionNumber, 'opening_message' => $openingMessage ]; return true; } catch (Exception $e) { Db::rollback(); self::setError('创建面试失败:' . $e->getMessage()); return false; } } public static function getDialogByInterviewId(int $interviewId, int $userId) { $id = Interview::where(['id' => $interviewId, 'user_id' => $userId])->findOrEmpty(); if ($id->isEmpty()) { self::setError('面试不存在'); return false; } try { // 查询对话记录 $dialogs = InterviewDialog::where('interview_id', $interviewId) ->order('create_time', 'asc') // 按时间升序排列 ->select() ->toArray(); self::$returnData = $dialogs; return true; } catch (\Exception $e) { self::setError($e->getMessage()); return false; } } }