|
@@ -177,6 +177,59 @@ interface UserProfile {
|
|
|
}>;
|
|
|
}
|
|
|
|
|
|
+// 首先添加类型定义
|
|
|
+interface PhotoResult {
|
|
|
+ url: string;
|
|
|
+ status: string;
|
|
|
+ photo_id: number;
|
|
|
+ detections: any[];
|
|
|
+ description: string;
|
|
|
+ photo_index: number;
|
|
|
+ analysis_model: string;
|
|
|
+ part_verification: {
|
|
|
+ explanation: string;
|
|
|
+ is_correct_part: boolean;
|
|
|
+ } | null;
|
|
|
+ analysis_timestamp: string;
|
|
|
+ overall_assessment: string;
|
|
|
+}
|
|
|
+
|
|
|
+interface VisualAnalysisResults {
|
|
|
+ status: string;
|
|
|
+ timestamp: string;
|
|
|
+ total_photos: number;
|
|
|
+ photo_results: PhotoResult[];
|
|
|
+ application_id: number;
|
|
|
+ failed_analyses: number;
|
|
|
+ successful_analyses: number;
|
|
|
+ verification_summary: {
|
|
|
+ correct_parts: number;
|
|
|
+ total_verified: number;
|
|
|
+ incorrect_parts: number;
|
|
|
+ all_parts_correct: boolean;
|
|
|
+ };
|
|
|
+}
|
|
|
+
|
|
|
+// 修改 apiData 的类型定义
|
|
|
+interface ApiData {
|
|
|
+ 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[];
|
|
|
+ };
|
|
|
+ visual_analysis_results?: VisualAnalysisResults;
|
|
|
+}
|
|
|
+
|
|
|
const candidateInfo = ref<CandidateInfo>({
|
|
|
name: '',
|
|
|
idNumber: '',
|
|
@@ -288,23 +341,8 @@ const candidateInfo = ref<CandidateInfo>({
|
|
|
hireReason: ''
|
|
|
})
|
|
|
|
|
|
-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)
|
|
|
+// 修改 apiData 的声明
|
|
|
+const apiData = ref<ApiData | null>(null);
|
|
|
|
|
|
const loading = ref<boolean>(true)
|
|
|
const error = ref<string>('')
|
|
@@ -575,7 +613,6 @@ const updateCandidateInfo = (data: any) => {
|
|
|
.join(', ');
|
|
|
|
|
|
}
|
|
|
- console.log(q)
|
|
|
return {
|
|
|
question: q.question_text || '未提供问题',
|
|
|
answer: answerText,
|
|
@@ -1159,6 +1196,48 @@ const scrollToSection = (sectionId) => {
|
|
|
}, 100);
|
|
|
}
|
|
|
};
|
|
|
+
|
|
|
+// 修改获取手部照片的方法
|
|
|
+const getHandPhotos = (hand: 'left' | 'right'): PhotoResult[] => {
|
|
|
+ console.log(apiData.value)
|
|
|
+ if (!apiData.value?.application?.visual_analysis_results?.photo_results) {
|
|
|
+ console.log('No photo results available');
|
|
|
+ return Array(3).fill({
|
|
|
+ url: '',
|
|
|
+ description: `${hand === 'left' ? '左手' : '右手'}手势`,
|
|
|
+ part_verification: null
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ const photos = apiData.value.application.visual_analysis_results.photo_results.filter((photo: PhotoResult) => {
|
|
|
+ const description = photo.description.toLowerCase();
|
|
|
+ const searchTerm = hand === 'left' ? '左手' : '右手';
|
|
|
+ const matches = description.includes(searchTerm);
|
|
|
+ console.log(`Checking photo ${photo.photo_id}: "${description}" for "${searchTerm}" - ${matches}`);
|
|
|
+ return matches;
|
|
|
+ });
|
|
|
+
|
|
|
+ console.log(`Found ${photos.length} ${hand} hand photos`);
|
|
|
+
|
|
|
+ // 确保始终返回3张图片的数组
|
|
|
+ const result = [...photos];
|
|
|
+ while (result.length < 3) {
|
|
|
+ result.push({
|
|
|
+ url: '',
|
|
|
+ status: 'empty',
|
|
|
+ photo_id: -result.length,
|
|
|
+ detections: [],
|
|
|
+ description: `${hand === 'left' ? '左手' : '右手'}手势`,
|
|
|
+ photo_index: -result.length,
|
|
|
+ analysis_model: '',
|
|
|
+ part_verification: null,
|
|
|
+ analysis_timestamp: '',
|
|
|
+ overall_assessment: ''
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ return result;
|
|
|
+};
|
|
|
</script>
|
|
|
|
|
|
<template>
|
|
@@ -1534,14 +1613,14 @@ const scrollToSection = (sectionId) => {
|
|
|
<span class="text-gray-600">手机号实名认证:</span>
|
|
|
<span class="text-green-500">{{ candidateInfo.additionalInfo.phoneVerification }}</span>
|
|
|
</div>
|
|
|
- <div class="flex items-center space-x-2">
|
|
|
+ <!-- <div class="flex items-center space-x-2">
|
|
|
<span class="text-gray-600">综合A类评估:</span>
|
|
|
<span class="text-green-500">{{ candidateInfo.additionalInfo.comprehensiveVerification }}</span>
|
|
|
</div>
|
|
|
<div class="flex items-center space-x-2">
|
|
|
<span class="text-gray-600">综合B类评估:</span>
|
|
|
<span class="text-green-500">{{ candidateInfo.additionalInfo.comprehensiveVerification }}</span>
|
|
|
- </div>
|
|
|
+ </div> -->
|
|
|
</div>
|
|
|
|
|
|
<!-- 手部综合检测 -->
|
|
@@ -1552,7 +1631,7 @@ const scrollToSection = (sectionId) => {
|
|
|
</div>
|
|
|
|
|
|
<!-- 手部检测详细信息 -->
|
|
|
- <div class="pl-4 space-y-2">
|
|
|
+ <!-- <div class="pl-4 space-y-2">
|
|
|
<div class="flex items-center space-x-2">
|
|
|
<span class="text-gray-600">手指灵活度:</span>
|
|
|
<span class="text-green-500">{{ candidateInfo.additionalInfo.handBrightness }}</span>
|
|
@@ -1565,68 +1644,122 @@ const scrollToSection = (sectionId) => {
|
|
|
<span class="text-gray-600">手部姿态纹身:</span>
|
|
|
<span class="text-green-500">{{ candidateInfo.additionalInfo.handPoseRecognition }}</span>
|
|
|
</div>
|
|
|
- </div>
|
|
|
+ </div> -->
|
|
|
|
|
|
<!-- 手势验证图片展示 -->
|
|
|
<div class="grid grid-cols-2 gap-8 mt-4">
|
|
|
<!-- 左手验证结果 -->
|
|
|
<div>
|
|
|
- <div class="mb-2">
|
|
|
- <h4 class="text-sm font-medium">左手识别结果</h4>
|
|
|
- <div class="space-y-1">
|
|
|
- <div class="flex items-center space-x-2">
|
|
|
- <span>手指灵活度</span>
|
|
|
- <span class="text-green-500">✓</span>
|
|
|
- </div>
|
|
|
- <div class="flex items-center space-x-2">
|
|
|
- <span>手指完整度</span>
|
|
|
- <span class="text-green-500">✓</span>
|
|
|
- </div>
|
|
|
- <div class="flex items-center space-x-2">
|
|
|
- <span>手部姿态纹身</span>
|
|
|
- <span class="text-green-500">✓</span>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
+ <h4 class="text-gray-600 mb-2">左手手势验证</h4>
|
|
|
<div class="grid grid-cols-3 gap-2">
|
|
|
- <div v-for="(image, index) in candidateInfo.additionalInfo.leftHandGestures.images"
|
|
|
+ <div v-for="(photo, index) in getHandPhotos('left')"
|
|
|
:key="index"
|
|
|
- class="aspect-square rounded-lg overflow-hidden bg-gray-100">
|
|
|
- <img :src="image"
|
|
|
- alt="左手手势"
|
|
|
- class="w-full h-full object-cover"
|
|
|
- @error="handleImageError">
|
|
|
+ class="relative aspect-square rounded-lg overflow-hidden bg-gray-100"
|
|
|
+ :class="{'border-2': photo.part_verification,
|
|
|
+ 'border-green-500': photo.part_verification?.is_correct_part,
|
|
|
+ 'border-red-500': photo.part_verification && !photo.part_verification.is_correct_part}"
|
|
|
+ >
|
|
|
+ <!-- 使用 el-tooltip 包裹内容 -->
|
|
|
+ <el-tooltip
|
|
|
+ v-if="photo.part_verification && !photo.part_verification.is_correct_part"
|
|
|
+ :content="photo.part_verification.explanation || '未提供失败原因'"
|
|
|
+ placement="top"
|
|
|
+ effect="dark"
|
|
|
+ :show-after="200"
|
|
|
+ >
|
|
|
+ <div class="w-full h-full">
|
|
|
+ <img :src="photo.url"
|
|
|
+ :alt="photo.description"
|
|
|
+ class="w-full h-full object-cover"
|
|
|
+ @error="handleImageError">
|
|
|
+
|
|
|
+ <!-- 底部状态显示 -->
|
|
|
+ <div v-if="photo.part_verification"
|
|
|
+ class="absolute bottom-0 left-0 right-0 py-1 px-2 text-xs text-center text-white z-10"
|
|
|
+ :class="{
|
|
|
+ 'bg-green-500 bg-opacity-90': photo.part_verification.is_correct_part,
|
|
|
+ 'bg-red-500 bg-opacity-90': !photo.part_verification.is_correct_part
|
|
|
+ }">
|
|
|
+ {{ photo.part_verification.is_correct_part ? '通过' : '未通过' }}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </el-tooltip>
|
|
|
+
|
|
|
+ <!-- 如果不需要显示tooltip,直接显示图片 -->
|
|
|
+ <template v-else>
|
|
|
+ <img :src="photo.url"
|
|
|
+ :alt="photo.description"
|
|
|
+ class="w-full h-full object-cover"
|
|
|
+ @error="handleImageError">
|
|
|
+
|
|
|
+ <!-- 底部状态显示 -->
|
|
|
+ <div v-if="photo.part_verification"
|
|
|
+ class="absolute bottom-0 left-0 right-0 py-1 px-2 text-xs text-center text-white z-10"
|
|
|
+ :class="{
|
|
|
+ 'bg-green-500 bg-opacity-90': photo.part_verification.is_correct_part,
|
|
|
+ 'bg-red-500 bg-opacity-90': !photo.part_verification.is_correct_part
|
|
|
+ }">
|
|
|
+ {{ photo.part_verification.is_correct_part ? '通过' : '未通过' }}
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
<!-- 右手验证结果 -->
|
|
|
<div>
|
|
|
- <div class="mb-2">
|
|
|
- <h4 class="text-sm font-medium">右手识别结果</h4>
|
|
|
- <div class="space-y-1">
|
|
|
- <div class="flex items-center space-x-2">
|
|
|
- <span>手指灵活度</span>
|
|
|
- <span class="text-green-500">✓</span>
|
|
|
- </div>
|
|
|
- <div class="flex items-center space-x-2">
|
|
|
- <span>手指完整度</span>
|
|
|
- <span class="text-green-500">✓</span>
|
|
|
- </div>
|
|
|
- <div class="flex items-center space-x-2">
|
|
|
- <span>手部姿态纹身</span>
|
|
|
- <span class="text-green-500">✓</span>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
+ <h4 class="text-gray-600 mb-2">右手手势验证</h4>
|
|
|
<div class="grid grid-cols-3 gap-2">
|
|
|
- <div v-for="(image, index) in candidateInfo.additionalInfo.rightHandGestures.images"
|
|
|
+ <div v-for="(photo, index) in getHandPhotos('right')"
|
|
|
:key="index"
|
|
|
- class="aspect-square rounded-lg overflow-hidden bg-gray-100">
|
|
|
- <img :src="image"
|
|
|
- alt="右手手势"
|
|
|
- class="w-full h-full object-cover"
|
|
|
- @error="handleImageError">
|
|
|
+ class="relative aspect-square rounded-lg overflow-hidden bg-gray-100"
|
|
|
+ :class="{'border-2': photo.part_verification,
|
|
|
+ 'border-green-500': photo.part_verification?.is_correct_part,
|
|
|
+ 'border-red-500': photo.part_verification && !photo.part_verification.is_correct_part}"
|
|
|
+ >
|
|
|
+ <!-- 使用 el-tooltip 包裹内容 -->
|
|
|
+ <el-tooltip
|
|
|
+ v-if="photo.part_verification && !photo.part_verification.is_correct_part"
|
|
|
+ :content="photo.part_verification.explanation || '未提供失败原因'"
|
|
|
+ placement="top"
|
|
|
+ effect="dark"
|
|
|
+ :show-after="200"
|
|
|
+ >
|
|
|
+ <div class="w-full h-full">
|
|
|
+ <img :src="photo.url"
|
|
|
+ :alt="photo.description"
|
|
|
+ class="w-full h-full object-cover"
|
|
|
+ @error="handleImageError">
|
|
|
+
|
|
|
+ <!-- 底部状态显示 -->
|
|
|
+ <div v-if="photo.part_verification"
|
|
|
+ class="absolute bottom-0 left-0 right-0 py-1 px-2 text-xs text-center text-white z-10"
|
|
|
+ :class="{
|
|
|
+ 'bg-green-500 bg-opacity-90': photo.part_verification.is_correct_part,
|
|
|
+ 'bg-red-500 bg-opacity-90': !photo.part_verification.is_correct_part
|
|
|
+ }">
|
|
|
+ {{ photo.part_verification.is_correct_part ? '通过' : '未通过' }}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </el-tooltip>
|
|
|
+
|
|
|
+ <!-- 如果不需要显示tooltip,直接显示图片 -->
|
|
|
+ <template v-else>
|
|
|
+ <img :src="photo.url"
|
|
|
+ :alt="photo.description"
|
|
|
+ class="w-full h-full object-cover"
|
|
|
+ @error="handleImageError">
|
|
|
+
|
|
|
+ <!-- 底部状态显示 -->
|
|
|
+ <div v-if="photo.part_verification"
|
|
|
+ class="absolute bottom-0 left-0 right-0 py-1 px-2 text-xs text-center text-white z-10"
|
|
|
+ :class="{
|
|
|
+ 'bg-green-500 bg-opacity-90': photo.part_verification.is_correct_part,
|
|
|
+ 'bg-red-500 bg-opacity-90': !photo.part_verification.is_correct_part
|
|
|
+ }">
|
|
|
+ {{ photo.part_verification.is_correct_part ? '通过' : '未通过' }}
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
@@ -2240,4 +2373,17 @@ body {
|
|
|
flex: 0 0 auto;
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+/* 添加新的样式 */
|
|
|
+.group {
|
|
|
+ position: relative;
|
|
|
+}
|
|
|
+
|
|
|
+.group:hover .group-hover\:opacity-100 {
|
|
|
+ opacity: 1;
|
|
|
+}
|
|
|
+
|
|
|
+.transition-opacity {
|
|
|
+ transition: opacity 0.2s ease-in-out;
|
|
|
+}
|
|
|
</style>
|