xiaoai/php_server/app/api/logic/interview/InterviewDialogLogic.php

500 lines
15 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace app\api\logic\interview;
use app\common\logic\BaseLogic;
use app\common\model\interview\InterviewDialog;
use app\common\model\interview\Interview;
use app\common\model\interview\InterviewRecord;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\facade\Db;
use Exception;
/**
* 面试对话记录逻辑层
* Class InterviewDialogLogic
* @package app\api\logic\interview
*/
class InterviewDialogLogic extends BaseLogic
{
// 用户ID
protected static $userId = 0;
/**
* 设置用户ID
* @param int $userId
*/
public static function setUserId(int $userId)
{
self::$userId = $userId;
}
/**
* 验证面试权限
* @param int $interviewId
* @return bool
*/
protected static function verifyPermission(int $interviewId): bool
{
$interview = Interview::where('id', $interviewId)->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;
}
}
}