|
@@ -327,6 +327,11 @@ export default {
|
|
|
currentFollowUpQuestion: null, // 添加当前追问问题的完整信息
|
|
currentFollowUpQuestion: null, // 添加当前追问问题的完整信息
|
|
|
lastQuestionWasFollowUp: false,
|
|
lastQuestionWasFollowUp: false,
|
|
|
lastFollowUpQuestionId: null,
|
|
lastFollowUpQuestionId: null,
|
|
|
|
|
+ // 追问次数控制 - 统一使用job_position_question_id作为key
|
|
|
|
|
+ defaultFollowUpLimit: 1, // 默认每个主题目最多1次追问
|
|
|
|
|
+ followUpLimitMap: {}, // { job_position_question_id: limit }
|
|
|
|
|
+ followUpAskedCountMap: {}, // { job_position_question_id: askedCount }
|
|
|
|
|
+ followUpRequestInFlight: {}, // { job_position_question_id: boolean }
|
|
|
lastUpdateTime: Date.now(), // 添加最后更新时间戳
|
|
lastUpdateTime: Date.now(), // 添加最后更新时间戳
|
|
|
subtitleMap: {}, // 用于存储字幕和翻译的映射
|
|
subtitleMap: {}, // 用于存储字幕和翻译的映射
|
|
|
progressPercent: 0, // 录制进度百分比
|
|
progressPercent: 0, // 录制进度百分比
|
|
@@ -419,6 +424,78 @@ export default {
|
|
|
this.cleanupPersonDetectionWebSocket();
|
|
this.cleanupPersonDetectionWebSocket();
|
|
|
},
|
|
},
|
|
|
methods: {
|
|
methods: {
|
|
|
|
|
+ // ===== 追问次数控制:工具方法 =====
|
|
|
|
|
+ getFollowUpLimit(jobPositionQuestionId) {
|
|
|
|
|
+ if (!jobPositionQuestionId) return this.defaultFollowUpLimit;
|
|
|
|
|
+ return this.followUpLimitMap[jobPositionQuestionId] || this.defaultFollowUpLimit;
|
|
|
|
|
+ },
|
|
|
|
|
+ setFollowUpLimit(jobPositionQuestionId, limit) {
|
|
|
|
|
+ if (!jobPositionQuestionId) return;
|
|
|
|
|
+ const parsed = parseInt(limit);
|
|
|
|
|
+ this.followUpLimitMap[jobPositionQuestionId] = Number.isFinite(parsed) && parsed > 0 ? parsed : this.defaultFollowUpLimit;
|
|
|
|
|
+ console.log(`设置问题 ${jobPositionQuestionId} 的追问上限为: ${this.followUpLimitMap[jobPositionQuestionId]}`);
|
|
|
|
|
+ },
|
|
|
|
|
+ resetFollowUpAskedCount(jobPositionQuestionId) {
|
|
|
|
|
+ if (!jobPositionQuestionId) return;
|
|
|
|
|
+ this.followUpAskedCountMap[jobPositionQuestionId] = 1;
|
|
|
|
|
+ console.log(`重置问题 ${jobPositionQuestionId} 的追问次数为: 1`);
|
|
|
|
|
+ },
|
|
|
|
|
+ incrementFollowUpCount(jobPositionQuestionId) {
|
|
|
|
|
+ if (!jobPositionQuestionId) return;
|
|
|
|
|
+ const current = this.followUpAskedCountMap[jobPositionQuestionId] || 0;
|
|
|
|
|
+ this.followUpAskedCountMap[jobPositionQuestionId] = current + 1;
|
|
|
|
|
+ console.log(`问题 ${jobPositionQuestionId} 的追问次数增加到: ${this.followUpAskedCountMap[jobPositionQuestionId]}`);
|
|
|
|
|
+ },
|
|
|
|
|
+ canAskMoreFollowUps(jobPositionQuestionId) {
|
|
|
|
|
+ if (!jobPositionQuestionId) return false;
|
|
|
|
|
+ const asked = this.followUpAskedCountMap[jobPositionQuestionId] || 0;
|
|
|
|
|
+ const limit = this.getFollowUpLimit(jobPositionQuestionId);
|
|
|
|
|
+ const canAsk = asked < limit;
|
|
|
|
|
+ console.log(`检查问题 ${jobPositionQuestionId} 是否可以继续追问: ${canAsk} (已问${asked}次/上限${limit}次)`);
|
|
|
|
|
+ return canAsk;
|
|
|
|
|
+ },
|
|
|
|
|
+ async maybeRequestNextFollowUp(jobPositionQuestionId) {
|
|
|
|
|
+ if (!jobPositionQuestionId) {
|
|
|
|
|
+ console.log('缺少job_position_question_id,直接进入下一题');
|
|
|
|
|
+ this.proceedToNextQuestion();
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ console.log(`检查是否需要继续追问,问题ID: ${jobPositionQuestionId}`);
|
|
|
|
|
+
|
|
|
|
|
+ if (this.canAskMoreFollowUps(jobPositionQuestionId)) {
|
|
|
|
|
+ // 避免重复触发并发请求
|
|
|
|
|
+ if (this.followUpRequestInFlight[jobPositionQuestionId]) {
|
|
|
|
|
+ console.log('已有追问请求进行中,跳过重复触发');
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ // 交由 callInterviewInteraction 统一处理并发标记
|
|
|
|
|
+ const ok = await this.callInterviewInteraction(jobPositionQuestionId);
|
|
|
|
|
+ if (!ok) {
|
|
|
|
|
+ console.log('未获取到下一条追问或调用失败,进入下一题');
|
|
|
|
|
+ this.isFollowUpMode = false;
|
|
|
|
|
+ this.isFollowUpQuestion = false;
|
|
|
|
|
+ this.currentFollowUpQuestion = null;
|
|
|
|
|
+ this.proceedToNextQuestion();
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // 已达上限,进入下一题
|
|
|
|
|
+ console.log(`问题 ${jobPositionQuestionId} 追问次数已达上限,进入下一题`);
|
|
|
|
|
+ this.isFollowUpMode = false;
|
|
|
|
|
+ this.isFollowUpQuestion = false;
|
|
|
|
|
+ this.currentFollowUpQuestion = null;
|
|
|
|
|
+ this.proceedToNextQuestion();
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
|
|
+ // 获取当前问题信息
|
|
|
|
|
+ getCurrentQuestionByIndex(index) {
|
|
|
|
|
+ // 这里需要根据实际的问题数据结构来实现
|
|
|
|
|
+ // 如果问题数据存储在某个数组中,返回对应索引的问题
|
|
|
|
|
+ // 暂时返回null,需要根据实际数据结构调整
|
|
|
|
|
+ return null;
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
// 处理音频播放完成
|
|
// 处理音频播放完成
|
|
|
handleAudioEnd() {
|
|
handleAudioEnd() {
|
|
|
console.log('音频播放完成');
|
|
console.log('音频播放完成');
|
|
@@ -558,7 +635,16 @@ export default {
|
|
|
this.handleAudioEnd();
|
|
this.handleAudioEnd();
|
|
|
},
|
|
},
|
|
|
// 调用面试互动接口
|
|
// 调用面试互动接口
|
|
|
- async callInterviewInteraction(questionId, retryCount = 0, maxRetries = 3) {
|
|
|
|
|
|
|
+ async callInterviewInteraction(jobPositionQuestionId, retryCount = 0, maxRetries = 3) {
|
|
|
|
|
+ // 防重入:同一父问题并发保护
|
|
|
|
|
+ /* if (jobPositionQuestionId && this.followUpRequestInFlight[jobPositionQuestionId]) {
|
|
|
|
|
+ console.log('追问请求已在进行中,跳过本次调用');
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (jobPositionQuestionId) {
|
|
|
|
|
+ this.followUpRequestInFlight[jobPositionQuestionId] = true;
|
|
|
|
|
+ } */
|
|
|
|
|
+
|
|
|
const userInfo = JSON.parse(uni.getStorageSync('userInfo'));
|
|
const userInfo = JSON.parse(uni.getStorageSync('userInfo'));
|
|
|
const appId = uni.getStorageSync('appId');
|
|
const appId = uni.getStorageSync('appId');
|
|
|
const positionConfigId = JSON.parse(uni.getStorageSync('configData')).id;
|
|
const positionConfigId = JSON.parse(uni.getStorageSync('configData')).id;
|
|
@@ -566,13 +652,13 @@ export default {
|
|
|
try {
|
|
try {
|
|
|
// 显示思考中loading
|
|
// 显示思考中loading
|
|
|
this.showThinkingLoading();
|
|
this.showThinkingLoading();
|
|
|
- console.log('开始调用面试互动接口', { questionId, appId });
|
|
|
|
|
|
|
+ console.log('开始调用面试互动接口', { jobPositionQuestionId, appId });
|
|
|
const res = await uni.request({
|
|
const res = await uni.request({
|
|
|
url: `${apiBaseUrl}/api/voice_interview_interaction/`,
|
|
url: `${apiBaseUrl}/api/voice_interview_interaction/`,
|
|
|
method: 'POST',
|
|
method: 'POST',
|
|
|
data: {
|
|
data: {
|
|
|
tenant_id: userInfo.tenant_id || 1,
|
|
tenant_id: userInfo.tenant_id || 1,
|
|
|
- question_id: questionId,
|
|
|
|
|
|
|
+ question_id: jobPositionQuestionId,
|
|
|
position_config_id: positionConfigId,
|
|
position_config_id: positionConfigId,
|
|
|
application_id: appId
|
|
application_id: appId
|
|
|
},
|
|
},
|
|
@@ -588,7 +674,7 @@ export default {
|
|
|
console.log(`视频转写未完成,${retryCount + 1}次重试中...`);
|
|
console.log(`视频转写未完成,${retryCount + 1}次重试中...`);
|
|
|
// 等待3秒后重试
|
|
// 等待3秒后重试
|
|
|
await new Promise(resolve => setTimeout(resolve, 3000));
|
|
await new Promise(resolve => setTimeout(resolve, 3000));
|
|
|
- return this.callInterviewInteraction(questionId, retryCount + 1, maxRetries);
|
|
|
|
|
|
|
+ return this.callInterviewInteraction(jobPositionQuestionId, retryCount + 1, maxRetries);
|
|
|
} else {
|
|
} else {
|
|
|
console.log('达到最大重试次数,视频转写仍未完成');
|
|
console.log('达到最大重试次数,视频转写仍未完成');
|
|
|
uni.showToast({
|
|
uni.showToast({
|
|
@@ -601,7 +687,11 @@ export default {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if (res.data.success) {
|
|
if (res.data.success) {
|
|
|
- // 等待处理追问问题完成
|
|
|
|
|
|
|
+ // 成功获取到一条追问,计数 +1(表示"已请求"这条追问)
|
|
|
|
|
+ if (jobPositionQuestionId) {
|
|
|
|
|
+ this.incrementFollowUpCount(jobPositionQuestionId);
|
|
|
|
|
+ }
|
|
|
|
|
+ // 处理本次追问(即便已达到上限,也应该播放本次追问)
|
|
|
await this.handleFollowUpQuestion(res.data);
|
|
await this.handleFollowUpQuestion(res.data);
|
|
|
this.hideThinkingLoading();
|
|
this.hideThinkingLoading();
|
|
|
return true;
|
|
return true;
|
|
@@ -614,7 +704,12 @@ export default {
|
|
|
console.error('调用面试互动接口失败:', error);
|
|
console.error('调用面试互动接口失败:', error);
|
|
|
this.hideThinkingLoading();
|
|
this.hideThinkingLoading();
|
|
|
return false;
|
|
return false;
|
|
|
- }
|
|
|
|
|
|
|
+ } /* finally {
|
|
|
|
|
+ // 清除并发标记
|
|
|
|
|
+ if (jobPositionQuestionId) {
|
|
|
|
|
+ this.followUpRequestInFlight[jobPositionQuestionId] = false;
|
|
|
|
|
+ }
|
|
|
|
|
+ } */
|
|
|
},
|
|
},
|
|
|
|
|
|
|
|
// 播放追问音频
|
|
// 播放追问音频
|
|
@@ -2597,19 +2692,34 @@ export default {
|
|
|
this.playLowScoreVideo();
|
|
this.playLowScoreVideo();
|
|
|
this.needPlayLowScoreVideo = false;
|
|
this.needPlayLowScoreVideo = false;
|
|
|
} else {
|
|
} else {
|
|
|
- // 如果是追问问题的回答,直接进入下一个问题
|
|
|
|
|
|
|
+ // 如果是追问问题的回答,检查是否继续追问
|
|
|
if (task.isFollowUp) {
|
|
if (task.isFollowUp) {
|
|
|
- console.log('追问问题回答完成,进入下一个问题');
|
|
|
|
|
|
|
+ console.log('追问问题回答完成,检查是否继续追问');
|
|
|
this.retryCount = 0; // 重置重试次数
|
|
this.retryCount = 0; // 重置重试次数
|
|
|
this.isFollowUpQuestion = false; // 重置追问标记
|
|
this.isFollowUpQuestion = false; // 重置追问标记
|
|
|
this.currentFollowUpQuestion = null; // 清除当前追问问题信息
|
|
this.currentFollowUpQuestion = null; // 清除当前追问问题信息
|
|
|
this.videoUrl=''
|
|
this.videoUrl=''
|
|
|
- this.proceedToNextQuestion();
|
|
|
|
|
|
|
+ // 若未达到上限则继续请求下一条追问,否则进入下一题
|
|
|
|
|
+ this.maybeRequestNextFollowUp(this.parentJobPositionQuestionId);
|
|
|
} else {
|
|
} else {
|
|
|
- // 如果是常规问题,记录父问题ID并检查追问问题
|
|
|
|
|
- this.currentParentQuestionId = task.questionId;
|
|
|
|
|
- console.log('检查常规问题的追问,父问题ID:', this.currentParentQuestionId);
|
|
|
|
|
- this.checkAndPlayFollowUpQuestion(this.currentParentQuestionId);
|
|
|
|
|
|
|
+ // 如果是常规问题,检查追问问题
|
|
|
|
|
+ console.log('常规问题回答完成,准备检查追问,父问题ID:', this.parentJobPositionQuestionId);
|
|
|
|
|
+ // 注意:这里应该使用从后端返回的job_position_question_id,而不是前端的questionId
|
|
|
|
|
+ // parentJobPositionQuestionId应该在提交视频成功后就已经设置好了
|
|
|
|
|
+ if (this.parentJobPositionQuestionId) {
|
|
|
|
|
+ // 从题目读取追问上限(使用follow_up_count字段),否则使用默认
|
|
|
|
|
+ const currentQuestion = this.getCurrentQuestionByIndex(this.currentVideoIndex);
|
|
|
|
|
+ if (currentQuestion && typeof currentQuestion.follow_up_count !== 'undefined') {
|
|
|
|
|
+ this.setFollowUpLimit(this.parentJobPositionQuestionId, currentQuestion.follow_up_count);
|
|
|
|
|
+ } else if (typeof this.defaultFollowUpLimit !== 'undefined') {
|
|
|
|
|
+ this.setFollowUpLimit(this.parentJobPositionQuestionId, this.defaultFollowUpLimit);
|
|
|
|
|
+ }
|
|
|
|
|
+ this.resetFollowUpAskedCount(this.parentJobPositionQuestionId);
|
|
|
|
|
+ this.checkAndPlayFollowUpQuestion(this.parentJobPositionQuestionId);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ console.error('缺少parentJobPositionQuestionId,无法检查追问,直接进入下一题');
|
|
|
|
|
+ this.proceedToNextQuestion();
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
},
|
|
},
|
|
@@ -2924,6 +3034,16 @@ export default {
|
|
|
this.parentJobPositionQuestionId = res.data.data.job_position_question_id;
|
|
this.parentJobPositionQuestionId = res.data.data.job_position_question_id;
|
|
|
console.log('保存父问题ID:', this.parentJobPositionQuestionId);
|
|
console.log('保存父问题ID:', this.parentJobPositionQuestionId);
|
|
|
|
|
|
|
|
|
|
+ // 初始化该题的追问上限与已问次数
|
|
|
|
|
+ // 注意:这里使用服务器返回的follow_up_limit字段,如果服务器返回的是follow_up_count,需要相应修改
|
|
|
|
|
+ const limitFromServer = res.data.data.follow_up_limit;
|
|
|
|
|
+ if (typeof limitFromServer !== 'undefined') {
|
|
|
|
|
+ this.setFollowUpLimit(this.parentJobPositionQuestionId, limitFromServer);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ this.setFollowUpLimit(this.parentJobPositionQuestionId, this.defaultFollowUpLimit);
|
|
|
|
|
+ }
|
|
|
|
|
+ this.resetFollowUpAskedCount(this.parentJobPositionQuestionId);
|
|
|
|
|
+
|
|
|
await this.callInterviewInteraction(res.data.data.job_position_question_id);
|
|
await this.callInterviewInteraction(res.data.data.job_position_question_id);
|
|
|
console.log('面试互动接口调用成功');
|
|
console.log('面试互动接口调用成功');
|
|
|
} catch (error) {
|
|
} catch (error) {
|
|
@@ -3167,18 +3287,12 @@ export default {
|
|
|
|
|
|
|
|
// 检查是否已经是最后一个视频
|
|
// 检查是否已经是最后一个视频
|
|
|
if (this.currentVideoIndex + 1 >= this.videoList.length) {
|
|
if (this.currentVideoIndex + 1 >= this.videoList.length) {
|
|
|
- // 所有视频都播放完毕,显示完成页面或返回
|
|
|
|
|
- console.log('所有视频已播放完毕');
|
|
|
|
|
-
|
|
|
|
|
// 清理资源
|
|
// 清理资源
|
|
|
this.stopUserCamera();
|
|
this.stopUserCamera();
|
|
|
this.clearCountdown();
|
|
this.clearCountdown();
|
|
|
-
|
|
|
|
|
// 获取当前职位ID
|
|
// 获取当前职位ID
|
|
|
const currentJobDetail = JSON.parse(uni.getStorageSync('selectedJob'));
|
|
const currentJobDetail = JSON.parse(uni.getStorageSync('selectedJob'));
|
|
|
- console.log('当前职位ID:', currentJobDetail);
|
|
|
|
|
const jobId = currentJobDetail ? currentJobDetail.id : null;
|
|
const jobId = currentJobDetail ? currentJobDetail.id : null;
|
|
|
-
|
|
|
|
|
this.handleVideoCompletion(jobId);
|
|
this.handleVideoCompletion(jobId);
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
@@ -4723,7 +4837,6 @@ export default {
|
|
|
},
|
|
},
|
|
|
|
|
|
|
|
handlePersonDetectionResult(data) {
|
|
handlePersonDetectionResult(data) {
|
|
|
- console.log('data', data);
|
|
|
|
|
/* console.log(data.data.detection.has_person);
|
|
/* console.log(data.data.detection.has_person);
|
|
|
console.log(data.data.identity.status);//identity_verified */
|
|
console.log(data.data.identity.status);//identity_verified */
|
|
|
|
|
|
|
@@ -5015,9 +5128,7 @@ export default {
|
|
|
// 处理视频完成
|
|
// 处理视频完成
|
|
|
handleVideoCompletion(jobId) {
|
|
handleVideoCompletion(jobId) {
|
|
|
this.isVideoSwitching = false; // 重置切换状态锁
|
|
this.isVideoSwitching = false; // 重置切换状态锁
|
|
|
-
|
|
|
|
|
// 延迟执行跳转,确保资源清理完成
|
|
// 延迟执行跳转,确保资源清理完成
|
|
|
- /* setTimeout(() => { */
|
|
|
|
|
// 如果职位ID为9,跳转到interview-question页面
|
|
// 如果职位ID为9,跳转到interview-question页面
|
|
|
if (jobId === 9) {
|
|
if (jobId === 9) {
|
|
|
uni.navigateTo({
|
|
uni.navigateTo({
|
|
@@ -5124,7 +5235,6 @@ export default {
|
|
|
}
|
|
}
|
|
|
});
|
|
});
|
|
|
}
|
|
}
|
|
|
- /* }, 200); */
|
|
|
|
|
},
|
|
},
|
|
|
},
|
|
},
|
|
|
computed: {
|
|
computed: {
|