|
@@ -196,7 +196,24 @@ const candidateInfo = ref<CandidateInfo>({
|
|
hireReason: ''
|
|
hireReason: ''
|
|
})
|
|
})
|
|
|
|
|
|
-const apiData = ref<any>(null)
|
|
|
|
|
|
+const apiData = ref<{
|
|
|
|
+ applicant?: any;
|
|
|
|
+ application?: any;
|
|
|
|
+ position?: any;
|
|
|
|
+ interview_progress?: any[];
|
|
|
|
+ posture_photos?: any[];
|
|
|
|
+ scoring_summary?: {
|
|
|
|
+ total_score_obtained: number;
|
|
|
|
+ max_possible_score: number;
|
|
|
|
+ answered_scoring_questions_count: number;
|
|
|
|
+ scoring_details: any[];
|
|
|
|
+ };
|
|
|
|
+ required_questions_summary?: {
|
|
|
|
+ all_correct: boolean;
|
|
|
|
+ failed_questions_details: any[];
|
|
|
|
+ };
|
|
|
|
+} | null>(null)
|
|
|
|
+
|
|
const loading = ref<boolean>(true)
|
|
const loading = ref<boolean>(true)
|
|
const error = ref<string>('')
|
|
const error = ref<string>('')
|
|
|
|
|
|
@@ -276,8 +293,25 @@ const updateCandidateInfo = (data: any) => {
|
|
|
|
|
|
// 如果成功解析出最小值和最大值,则根据分数计算建议薪资
|
|
// 如果成功解析出最小值和最大值,则根据分数计算建议薪资
|
|
if (!isNaN(min) && !isNaN(max) && min > 0 && max > 0 && max > min) {
|
|
if (!isNaN(min) && !isNaN(max) && min > 0 && max > 0 && max > min) {
|
|
- // 根据分数比例计算建议薪资
|
|
|
|
- const scoreRatio = candidateInfo.value.score / 100;
|
|
|
|
|
|
+ // 改进的薪资计算逻辑
|
|
|
|
+ // 使用更合理的评分映射:
|
|
|
|
+ // 60分以下 -> 最低薪资
|
|
|
|
+ // 60-80分 -> 线性增长从最低薪资到中间值
|
|
|
|
+ // 80-100分 -> 线性增长从中间值到最高薪资
|
|
|
|
+ let scoreRatio;
|
|
|
|
+ const score = candidateInfo.value.score;
|
|
|
|
+
|
|
|
|
+ if (score < 60) {
|
|
|
|
+ // 低于60分,给予最低薪资
|
|
|
|
+ scoreRatio = 0;
|
|
|
|
+ } else if (score <= 80) {
|
|
|
|
+ // 60-80分,线性增长到中间点
|
|
|
|
+ scoreRatio = (score - 60) / 40 * 0.5; // 0到0.5之间
|
|
|
|
+ } else {
|
|
|
|
+ // 80-100分,线性增长到最高点
|
|
|
|
+ scoreRatio = 0.5 + (score - 80) / 20 * 0.5; // 0.5到1之间
|
|
|
|
+ }
|
|
|
|
+
|
|
const suggested = Math.floor(min + (max - min) * scoreRatio);
|
|
const suggested = Math.floor(min + (max - min) * scoreRatio);
|
|
|
|
|
|
// 格式化薪资显示
|
|
// 格式化薪资显示
|
|
@@ -459,7 +493,7 @@ const updateCandidateInfo = (data: any) => {
|
|
videoUrl: q.video_answer?.video_url || '',
|
|
videoUrl: q.video_answer?.video_url || '',
|
|
question_image_url: q.question_image_url || '',
|
|
question_image_url: q.question_image_url || '',
|
|
options: q.options || [],
|
|
options: q.options || [],
|
|
- thumbnail: '/images/video-placeholder.jpg'
|
|
|
|
|
|
+ thumbnail: ''
|
|
}
|
|
}
|
|
})
|
|
})
|
|
}
|
|
}
|
|
@@ -799,6 +833,30 @@ const handleVideoError = (event: Event) => {
|
|
console.error('视频加载错误')
|
|
console.error('视频加载错误')
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+// 添加 DUV 得分解释函数
|
|
|
|
+const getDuvScoreInterpretation = (score: number | undefined): string => {
|
|
|
|
+ if (score === undefined) return '未进行心理测评或数据缺失'
|
|
|
|
+ return score.toString()
|
|
|
|
+ /* if (score <= 30) {
|
|
|
|
+ return '心理状态良好,无明显异常。候选人在心理测评中表现出稳定的情绪状态和健康的心理特质,适合岗位要求。'
|
|
|
|
+ } else if (score <= 60) {
|
|
|
|
+ return '心理状态基本正常,存在轻微波动。候选人在某些方面可能存在轻微的心理压力,但总体上仍保持稳定,基本符合岗位要求。'
|
|
|
|
+ } else if (score <= 90) {
|
|
|
|
+ return '心理状态存在一定波动,建议关注。候选人在测评中表现出一定程度的心理压力或情绪波动,可能需要进一步评估其适应性。'
|
|
|
|
+ } else {
|
|
|
|
+ return '心理状态波动较大,建议谨慎考虑。候选人在测评中表现出较明显的心理压力或情绪不稳定性,可能不完全符合岗位要求。'
|
|
|
|
+ } */
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// 添加安全获取分数值的辅助函数
|
|
|
|
+const getSafeScoreValue = (score: number | undefined): number => {
|
|
|
|
+ return score !== undefined ? score : 0
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+const getSafeMaxScoreValue = (maxScore: number | undefined): number => {
|
|
|
|
+ return maxScore !== undefined ? maxScore : 210
|
|
|
|
+}
|
|
</script>
|
|
</script>
|
|
|
|
|
|
<template>
|
|
<template>
|
|
@@ -891,6 +949,31 @@ const handleVideoError = (event: Event) => {
|
|
<p class="text-gray-600 text-sm">{{ candidateInfo.hireReason || '无详细说明' }}</p>
|
|
<p class="text-gray-600 text-sm">{{ candidateInfo.hireReason || '无详细说明' }}</p>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
+ <!-- 添加红线题检测结果 -->
|
|
|
|
+ <div class="border-b pb-4">
|
|
|
|
+ <div class="flex items-center justify-between mb-2">
|
|
|
|
+ <span class="text-gray-600" style="color: red;">红线题检测结果</span>
|
|
|
|
+ <span :class="{
|
|
|
|
+ 'text-green-500': apiData?.required_questions_summary?.all_correct,
|
|
|
|
+ 'text-red-500': apiData?.required_questions_summary && !apiData.required_questions_summary.all_correct
|
|
|
|
+ }">
|
|
|
|
+ {{ apiData?.required_questions_summary?.all_correct ? '全部正确' : '存在错误,建议不录用' }}
|
|
|
|
+ </span>
|
|
|
|
+ </div>
|
|
|
|
+ <div v-if="apiData?.required_questions_summary && !apiData.required_questions_summary.all_correct"
|
|
|
|
+ class="mt-2 border-l-4 border-red-500 pl-3 bg-red-50 p-2 rounded">
|
|
|
|
+ <p class="text-red-700 font-medium mb-1">未通过的红线题:</p>
|
|
|
|
+ <ul v-if="apiData.required_questions_summary.failed_questions_details.length > 0"
|
|
|
|
+ class="list-disc pl-5 text-gray-600 text-sm">
|
|
|
|
+ <li v-for="(question, index) in apiData.required_questions_summary.failed_questions_details"
|
|
|
|
+ :key="'failed-'+index">
|
|
|
|
+ {{ question.question_text || `问题 ${index + 1}` }}
|
|
|
|
+ </li>
|
|
|
|
+ </ul>
|
|
|
|
+ <p v-else class="text-gray-600 text-sm">未提供详细信息</p>
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+
|
|
<div v-if="candidateInfo.strengths && candidateInfo.strengths.length > 0" class="border-b pb-4">
|
|
<div v-if="candidateInfo.strengths && candidateInfo.strengths.length > 0" class="border-b pb-4">
|
|
<h3 class="font-semibold mb-2">优点</h3>
|
|
<h3 class="font-semibold mb-2">优点</h3>
|
|
<ul class="list-disc pl-5 text-gray-600 text-sm">
|
|
<ul class="list-disc pl-5 text-gray-600 text-sm">
|
|
@@ -909,12 +992,28 @@ const handleVideoError = (event: Event) => {
|
|
</ul>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
+ <!-- 修改 DUV 得分显示部分,添加更安全的处理 /{{ getSafeMaxScoreValue(apiData?.scoring_summary?.max_possible_score) }}-->
|
|
|
|
+ <div class="border-b pb-4">
|
|
|
|
+ <div class="flex items-center justify-between mt-4 mb-2">
|
|
|
|
+ <span class="text-gray-600">DUV 心理测评得分</span>
|
|
|
|
+ <span :class="{
|
|
|
|
+ 'text-green-500': getSafeScoreValue(apiData?.scoring_summary?.total_score_obtained) <= 30,
|
|
|
|
+ 'text-yellow-500': getSafeScoreValue(apiData?.scoring_summary?.total_score_obtained) > 30 && getSafeScoreValue(apiData?.scoring_summary?.total_score_obtained) <= 60,
|
|
|
|
+ 'text-red-500': getSafeScoreValue(apiData?.scoring_summary?.total_score_obtained) > 60
|
|
|
|
+ }">{{ getSafeScoreValue(apiData?.scoring_summary?.total_score_obtained) }}</span>
|
|
|
|
+ </div>
|
|
|
|
+ <!-- <p class="text-gray-600 text-sm">
|
|
|
|
+ {{ getDuvScoreInterpretation(apiData?.scoring_summary?.total_score_obtained) }}
|
|
|
|
+ </p> -->
|
|
|
|
+ </div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
<!-- 2. DUV分析评估 -->
|
|
<!-- 2. DUV分析评估 -->
|
|
<div class="mb-8">
|
|
<div class="mb-8">
|
|
<h2 class="text-xl font-bold mb-6">2. 图片分析评估</h2>
|
|
<h2 class="text-xl font-bold mb-6">2. 图片分析评估</h2>
|
|
<div class="space-y-4">
|
|
<div class="space-y-4">
|
|
|
|
+
|
|
|
|
+
|
|
<div v-for="(item, index) in candidateInfo.duvAnalysis" :key="index" class="border-b pb-4">
|
|
<div v-for="(item, index) in candidateInfo.duvAnalysis" :key="index" class="border-b pb-4">
|
|
<div class="flex items-center justify-between mb-2">
|
|
<div class="flex items-center justify-between mb-2">
|
|
<span class="text-gray-600">{{ item.title }}</span>
|
|
<span class="text-gray-600">{{ item.title }}</span>
|
|
@@ -990,15 +1089,15 @@ const handleVideoError = (event: Event) => {
|
|
</div>
|
|
</div>
|
|
|
|
|
|
<!-- 选择题布局 -->
|
|
<!-- 选择题布局 -->
|
|
- <div v-else-if="record.question_form === 1 || record.question_form === 2" class="mt-4">
|
|
|
|
|
|
+ <div v-else-if="record.question_form === 1 || record.question_form === 2 || record.question_form === 4" class="mt-4">
|
|
<div class="bg-white p-4 rounded-lg">
|
|
<div class="bg-white p-4 rounded-lg">
|
|
<div class="flex items-center justify-between mb-3">
|
|
<div class="flex items-center justify-between mb-3">
|
|
<div class="flex items-center space-x-2">
|
|
<div class="flex items-center space-x-2">
|
|
- <div class="bg-green-100 text-green-800 px-2 py-1 rounded text-sm">候选人</div>
|
|
|
|
|
|
+ <div class="bg-green-100 text-green-800 px-2 py-1 rounded text-sm">候选人:</div>
|
|
<p class="text-gray-700" style="margin: 0;">{{ record.answer }}</p>
|
|
<p class="text-gray-700" style="margin: 0;">{{ record.answer }}</p>
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<div>
|
|
- <span :class="[
|
|
|
|
|
|
+ <span v-if="record.question_form === 1 || record.question_form === 2" :class="[
|
|
'px-3 py-1 rounded-full text-sm',
|
|
'px-3 py-1 rounded-full text-sm',
|
|
record.is_correct === true || record.is_correct === 'true'
|
|
record.is_correct === true || record.is_correct === 'true'
|
|
? 'bg-green-100 text-green-800'
|
|
? 'bg-green-100 text-green-800'
|
|
@@ -1313,7 +1412,7 @@ const handleVideoError = (event: Event) => {
|
|
}
|
|
}
|
|
|
|
|
|
/* 修改页面标题区域样式 */
|
|
/* 修改页面标题区域样式 */
|
|
-.bg-[#1d1e3a] {
|
|
|
|
|
|
+:deep(.bg-\[#1d1e3a\]) {
|
|
background-color: #004d99 !important; /* 深蓝色标题背景 */
|
|
background-color: #004d99 !important; /* 深蓝色标题背景 */
|
|
}
|
|
}
|
|
|
|
|