Browse Source

修改内容 最新

yangg 2 months ago
parent
commit
a2c3fa45b1

+ 1 - 1
api/user.js

@@ -81,7 +81,7 @@ export const uploadAvatar = (filePath) => {
  * @returns {Promise} - 返回退出结果
  */
 export const logout = () => {
-  return http.post('/api/user/logout');
+  return http.post('/wechat/wechatLogout');
 }; 
 
 /**

+ 1 - 1
common/config.js

@@ -2,7 +2,7 @@
 //线上 https://minlong.raycos.com.cn
 //测试 http://192.168.66.187:8083
 //https://backend.qicai321.com
-export const apiBaseUrl = 'https://backend.qicai321.com';//'http://192.168.100.101:8083';//
+export const apiBaseUrl = 'https://backend.qicai321.com';//'http://192.168.100.187:8083';//
 
 // You can add other global configuration settings here
 export const appVersion = '1.0.0';

+ 14 - 3
pages/Personal/Personal.vue

@@ -384,7 +384,7 @@
 			</view>
 			
 			<!-- 第四步:专业技能 -->
-			<view v-if="currentStep === 6" class="form-container">
+			<view v-if="currentStep === 6 && (showRequireTrainingInfoField || showRequireProfessionalSkillsField)" class="form-container">
 				<view class="section-title" v-if="showRequireTrainingInfoField"><text class="required" style="margin-right: 4rpx;color: #ff4d4f;">*</text>专业技能</view>
 				<view class="skills-container" v-if="showRequireTrainingInfoField">
 					<textarea 
@@ -899,7 +899,9 @@ import { apiBaseUrl } from '@/common/config.js';
 			showRequireTrainingInfoField() {//专业技能
 				return  this.safeConfigData.require_training_info
 			},
-			
+			shouldShowSkillsStep() {
+				return this.showRequireTrainingInfoField || this.showRequireProfessionalSkillsField;
+			},
 		},
 		methods: {
 			// 添加承诺书相关方法
@@ -1683,7 +1685,16 @@ import { apiBaseUrl } from '@/common/config.js';
 				
 				const nextIndex = this.currentStepIndex + 1;
 				if (nextIndex < this.steps.length) {
-					this.currentStep = this.steps[nextIndex].id;
+					// 如果下一步是专业技能步骤(第四步,currentStep === 6),且不需要显示,则跳过
+					if (this.steps[nextIndex].id === 6 && !this.shouldShowSkillsStep) {
+						// 跳到下下一步
+						const skipIndex = nextIndex + 1;
+						if (skipIndex < this.steps.length) {
+							this.currentStep = this.steps[skipIndex].id;
+						}
+					} else {
+						this.currentStep = this.steps[nextIndex].id;
+					}
 					// 滚动到页面顶部
 					uni.pageScrollTo({
 						scrollTop: 0,

+ 15 - 2
pages/face-photo/face-photo.vue

@@ -318,10 +318,23 @@ export default {
               icon: 'success'
             });
             
-            // 上传成功后跳转到下一页
+            // 获取本地存储的configData
+            let configData = {};
+            try {
+              configData = JSON.parse(uni.getStorageSync('configData') || '{}');
+            } catch (e) {
+              console.error('解析configData失败:', e);
+              configData = {};
+            }
+
+            // 根据enable_open_questions的值决定跳转路径
+            const targetUrl = configData?.question_form_switches?.enable_open_questions 
+              ? '/pages/identity-verify/identity-verify'
+              : '/pages/camera/camera';
+
             setTimeout(() => {
               uni.navigateTo({
-                url: '/pages/identity-verify/identity-verify',
+                url: targetUrl,
                 fail: (err) => {
                   console.error('页面跳转失败:', err);
                   uni.showToast({

+ 250 - 142
pages/identity-verify/identity-verify.vue

@@ -247,15 +247,16 @@ export default {
       // 其他属性保持不变...
       questions: [], // 添加新属性存储API返回的问题数据
       introVideoUrl: (() => {
+					const DEFAULT_VIDEO_URL = 'https://data.qicai321.com/minlong/ee4d9cce-c3d5-4350-8c6e-684283827897.mp4';
 					try {
 						const configStr = uni.getStorageSync('configData');
-						if (configStr && configStr.trim()) {
-							return JSON.parse(configStr).digital_human_opening_video_url || 'https://data.qicai321.com/minlong/ee4d9cce-c3d5-4350-8c6e-684283827897.mp4';
-						}
-						return 'https://data.qicai321.com/minlong/ee4d9cce-c3d5-4350-8c6e-684283827897.mp4';
+						if (!configStr) return DEFAULT_VIDEO_URL;
+						
+						const config = JSON.parse(configStr);
+						return config.digital_human_opening_video_url || DEFAULT_VIDEO_URL;
 					} catch (error) {
 						console.warn('解析配置数据失败:', error);
-						return {};
+						return DEFAULT_VIDEO_URL;
 					}
 				})(),//'https://data.qicai321.com/minlong/ee4d9cce-c3d5-4350-8c6e-684283827897.mp4', // 保留介绍视频
       isRecording: false,
@@ -288,7 +289,19 @@ export default {
       showGif: false, // 控制是否显示GIF
       gifUrl: '', // GIF图片的URL
       globalSocketTask: null, // 添加全局 WebSocket 连接对象
-      lowScoreVideoUrl: 'https://data.qicai321.com/minlong/latentsync/0530e7f5-1957-422d-8f34-ba4a92608081_result.mp4', // 低分提示视频URL
+      lowScoreVideoUrl: (() => {
+					const DEFAULT_VIDEO_URL = 'https://data.qicai321.com/minlong/latentsync/0530e7f5-1957-422d-8f34-ba4a92608081_result.mp4';
+					try {
+						const configStr = uni.getStorageSync('configData');
+						if (!configStr) return DEFAULT_VIDEO_URL;
+						
+						const config = JSON.parse(configStr);
+						return config.digital_human?.middle_video_url || DEFAULT_VIDEO_URL;
+					} catch (error) {
+						console.warn('解析配置数据失败:', error);
+						return DEFAULT_VIDEO_URL;
+					}
+				})(),//'https://data.qicai321.com/minlong/latentsync/0530e7f5-1957-422d-8f34-ba4a92608081_result.mp4', // 低分提示视频URL
       showRerecordButton: false, // 控制重新录制按钮显示
       isPlayingLowScoreVideo: false, // 标记是否正在播放低分提示视频
       lowScoreVideoSubtitles: [
@@ -334,6 +347,8 @@ export default {
       parentJobPositionQuestionId: null, // 添加父问题的job_position_question_id
       isFollowUpMode: false, // 是否处于追问模式
       mainQuestionIndex: 0, // 当前主问题的索引
+      isVideoSwitching: false, // 添加视频切换状态锁
+      originalQuestionSubtitle: null, // 保存原始字幕信息
     }
   },
   mounted() {
@@ -556,10 +571,10 @@ export default {
             await this.handleFollowUpQuestion(res.data);
           } else {
             console.error('面试互动接口返回错误:', res.data);
-            uni.showToast({
+           /* uni.showToast({
               title: '获取追问失败',
               icon: 'none'
-            });
+            }); */
           }
         } catch (error) {
           console.error('调用面试互动接口失败:', error);
@@ -574,10 +589,10 @@ export default {
           // 检查音频URL
           if (!this.followUpAudioUrl) {
             console.error('没有音频URL');
-            uni.showToast({
+           /* uni.showToast({
               title: '音频URL无效',
               icon: 'none'
-            });
+            }); */
             reject(new Error('没有音频URL'));
             return;
           }
@@ -605,11 +620,11 @@ export default {
               console.log('音频可以播放');
               uni.hideLoading();
               this.isAudioPlaying = true;
-              uni.showToast({
+              /* uni.showToast({
                 title: '正在播放追问',
                 icon: 'none',
                 duration: 2000
-              });
+              }); */
             });
             
             // 监听音频播放完成
@@ -630,10 +645,10 @@ export default {
               console.error('音频播放错误:', res);
               this.isAudioPlaying = false;
               uni.hideLoading();
-              uni.showToast({
+              /* uni.showToast({
                 title: '音频播放失败',
                 icon: 'none'
-              });
+              }); */
               reject(res);
               this.stopAndDestroyAudio();
             });
@@ -646,10 +661,10 @@ export default {
             console.error('创建或播放音频失败:', error);
             this.isAudioPlaying = false;
             uni.hideLoading();
-            uni.showToast({
+            /* uni.showToast({
               title: '音频播放失败',
               icon: 'none'
-            });
+            }); */
             this.stopAndDestroyAudio();
             reject(error);
           }
@@ -687,11 +702,11 @@ export default {
         // 监听音频加载状态
         audioContext.onCanplay(() => {
           console.log('音频可以播放');
-          uni.showToast({
+          /* uni.showToast({
             title: '正在播放追问',
             icon: 'none',
             duration: 2000
-          });
+          }); */
         });
         
         // 监听播放进度
@@ -709,10 +724,10 @@ export default {
         // 监听音频播放错误
         audioContext.onError((res) => {
           console.error('音频播放错误:', res);
-          uni.showToast({
+          /* uni.showToast({
             title: '音频播放失败',
             icon: 'none'
-          });
+          }); */
           this.cleanupAudioContext();
           reject(res);
         });
@@ -1267,10 +1282,10 @@ export default {
         fail: () => {
           // 如果用户取消选择,回退到静态图片
           this.videoPlaying = false;
-          uni.showToast({
+          /* uni.showToast({
             title: '无法加载视频,显示静态图片',
             icon: 'none'
-          });
+          }); */
         }
       });
     },
@@ -1320,9 +1335,11 @@ export default {
           // 显示重新录制按钮
           this.showRerecordButton = true;
           
-          // 如果是追问问题,保持显示追问问题的字幕
+          // 恢复原始问题的字幕
           if (this.isFollowUpQuestion && this.currentFollowUpQuestion) {
             this.currentSubtitle = this.currentFollowUpQuestion.digital_human_video_subtitle || this.currentFollowUpQuestion.question;
+          } else if (this.originalQuestionSubtitle) {
+            this.currentSubtitle = this.originalQuestionSubtitle;
           }
         } else {
           console.log('已达到最大重试次数,继续下一题');
@@ -1336,6 +1353,7 @@ export default {
         
         // 重置标记
         this.isPlayingLowScoreVideo = false;
+        this.originalQuestionSubtitle = null;
         
         return;
       }
@@ -1454,15 +1472,16 @@ export default {
         return;
       }
       
-      // 录制时长足够,停止录制
-      this.completeRecordingStop();
-      
       // 检查是否需要播放低分视频(录制时间少于7秒)
       if (recordingDuration < lowScoreDuration) {
         console.log(`录制时间 ${recordingDuration} 秒,少于 ${lowScoreDuration} 秒,将播放低分提示视频`);
-        // 设置标记,在上传完成后播放低分视频
-        this.needPlayLowScoreVideo = true;
+        // 停止录制但不上传
+        this.completeRecordingStop(false);
+        // 直接播放低分视频
+        this.playLowScoreVideo();
       } else {
+        // 录制时长足够,正常停止录制并上传
+        this.completeRecordingStop(true);
         this.needPlayLowScoreVideo = false;
       }
     },
@@ -1710,10 +1729,10 @@ export default {
     startBrowserRecording() {
       if (!this.cameraStream) {
         console.error('没有可用的摄像头流');
-        uni.showToast({
+       /* uni.showToast({
           title: '录制失败,摄像头未就绪',
           icon: 'none'
-        });
+        }); */
         this.proceedToNextQuestion();
         return;
       }
@@ -1844,10 +1863,10 @@ export default {
         
         if (this.recordedChunks.length === 0) {
           console.error('没有录制到数据');
-          uni.showToast({
+          /* uni.showToast({
             title: '录制失败,未捕获到数据',
             icon: 'none'
-          });
+          }); */
           this.proceedToNextQuestion();
           return;
         }
@@ -1911,49 +1930,6 @@ export default {
       }
     },
 
-    // 添加新方法:停止录制用户回答
-    stopRecordingAnswer() {
-      console.log('停止录制用户回答');
-      
-      // 如果倒计时正在进行,先清除倒计时
-      if (this.countdownTimer) {
-        clearInterval(this.countdownTimer);
-        this.countdownTimer = null;
-        this.showCountdown = false;
-      }
-      
-      // 重置等待回答状态
-      this.isWaitingForAnswer = false;
-      
-      // 检查录制时长
-      const recordingDuration = this.getRecordingDuration();
-      const minimumDuration = 3; // 最小录制时长(秒),改为3秒
-      const lowScoreDuration = 7; // 低分阈值时长(秒),少于7秒视为低分
-      
-      if (recordingDuration < minimumDuration) {
-        // 录制时间过短,显示提示
-        uni.showToast({
-          title: '录制时间过短,请至少录制3秒',
-          icon: 'none',
-          duration: 2000
-        });
-        // 不执行停止录制逻辑,继续录制
-        return;
-      }
-      
-      // 录制时长足够,停止录制
-      this.completeRecordingStop();
-      
-      // 检查是否需要播放低分视频(录制时间少于7秒)
-      if (recordingDuration < lowScoreDuration) {
-        console.log(`录制时间 ${recordingDuration} 秒,少于 ${lowScoreDuration} 秒,将播放低分提示视频`);
-        // 设置标记,在上传完成后播放低分视频
-        this.needPlayLowScoreVideo = true;
-      } else {
-        this.needPlayLowScoreVideo = false;
-      }
-    },
-
     // 添加新方法:获取录制时长
     getRecordingDuration() {
       // 如果有明确的录制开始时间,计算实际录制时长
@@ -2013,15 +1989,15 @@ export default {
       }
       
       // 显示提示
-      uni.showToast({
+      /* uni.showToast({
         title: '请重新开始回答',
         icon: 'none',
         duration: 2000
-      });
+      }); */
     },
 
     // 修改 completeRecordingStop 方法,确保正确处理追问问题ID
-    completeRecordingStop() {
+    completeRecordingStop(uploadVideo = true) {
       console.log('完成录制停止');
       
       // 停止录制计时器
@@ -2045,16 +2021,37 @@ export default {
       
       if (isMiniProgram) {
         // 小程序环境停止录制
-        this.stopMiniProgramRecording();
+        if (uploadVideo) {
+          this.stopMiniProgramRecording();
+        } else {
+          // 如果不需要上传,直接停止录制
+          if (this.cameraContext) {
+            this.cameraContext.stopRecord({
+              success: () => {
+                console.log('相机录制已停止,不上传视频');
+              },
+              fail: (err) => {
+                console.error('停止相机录制失败:', err);
+              }
+            });
+          }
+        }
       } else {
         // H5/App环境停止录制
-        this.stopBrowserRecording();
+        if (uploadVideo) {
+          this.stopBrowserRecording();
+        } else {
+          // 如果不需要上传,直接停止录制
+          if (this.mediaRecorder && this.mediaRecorder.state !== 'inactive') {
+            this.mediaRecorder.stop();
+            this.recordedChunks = []; // 清空已录制的数据
+          }
+        }
       }
       
       // 记录当前问题ID和类型,确保追问问题使用正确的ID
       if (this.isFollowUpQuestion && this.currentFollowUpQuestion) {
         console.log('当前是追问问题,记录追问问题ID:', this.currentFollowUpQuestion.id);
-        // 可以在这里添加额外的标记,确保后续处理使用正确的ID
         this.lastQuestionWasFollowUp = true;
         this.lastFollowUpQuestionId = this.currentFollowUpQuestion.id;
       } else {
@@ -2180,11 +2177,11 @@ export default {
       this.uploadStatus[uploadTask.id] = 'pending';
       
       // 显示上传状态提示
-      uni.showToast({
+     /* uni.showToast({
         title: '正在上传回答...',
         icon: 'loading',
         duration: 1500
-      });
+      }); */
       
       // 更新上传状态文本
       this.updateUploadStatusText();
@@ -2428,11 +2425,11 @@ export default {
         console.log('超过最大重试次数,放弃上传');
         
         // 显示错误提示
-        uni.showToast({
+        /* uni.showToast({
           title: '视频上传失败,请稍后重试',
           icon: 'none',
           duration: 2000
-        });
+        }); */
         
         // 从队列中移除当前任务
         this.uploadQueue.shift();
@@ -2482,22 +2479,28 @@ export default {
           success: async (res) => {
             try {
               if (res.data.code === 200 || res.data.code === 2000) {
+                if (res.data.data && res.data.data.transcription_status === 'pending') {
+                  // 如果转写状态为pending,5秒后重试
+                  console.log('视频转写进行中,5秒后重试');
+                  setTimeout(() => {
+                    this.checkTranscriptionStatus(task, followUpRequestData);
+                  }, 5000);
+                  return;
+                }
+                
                 console.log('追问视频提交成功');
-                // 不直接调用proceedToNextQuestion,而是恢复到主问题序列
                 this.isFollowUpMode = false;
-                // 恢复到当前主问题的索引
                 this.currentVideoIndex = this.mainQuestionIndex;
                 
-                uni.showToast({
+                /* uni.showToast({
                   title: '回答已提交',
                   icon: 'success',
                   duration: 1500
-                });
+                }); */
                 
                 this.uploadQueue.shift();
                 this.processUploadQueue();
                 
-                // 继续播放主问题序列
                 this.$nextTick(() => {
                   if (this.currentVideoIndex < this.videoList.length) {
                     this.videoUrl = this.videoList[this.currentVideoIndex];
@@ -2517,7 +2520,7 @@ export default {
           },
           fail: (err) => {
             console.error('提交视频失败:', err);
-            //this.handleSubmitFailure(task, '提交失败: ' + err.errMsg);
+            this.handleSubmitFailure(task, '提交失败: ' + err.errMsg);
           }
         });
       } else {
@@ -2545,11 +2548,11 @@ export default {
                 this.proceedToNextQuestion();
               }
               
-              uni.showToast({
+              /* uni.showToast({
                 title: '回答已提交',
                 icon: 'success',
                 duration: 1500
-              });
+              }); */
               
               this.uploadQueue.shift();
               this.processUploadQueue();
@@ -2587,11 +2590,11 @@ export default {
         console.log('超过最大重试次数,放弃提交');
         
         // 显示错误提示
-        uni.showToast({
+        /* uni.showToast({
           title: '视频提交失败,请稍后重试',
           icon: 'none',
           duration: 2000
-        });
+        }); */
         
         // 从队列中移除当前任务
         this.uploadQueue.shift();
@@ -2601,6 +2604,80 @@ export default {
       }
     },
     
+    // 添加检查转写状态的方法
+    checkTranscriptionStatus(task, requestData, retryCount = 0) {
+      const maxRetries = 24; // 最大重试次数(2分钟)
+      const retryInterval = 5000; // 重试间隔时间(5秒)
+      
+      if (retryCount >= maxRetries) {
+        console.log('转写超时,继续下一个问题');
+        this.isFollowUpMode = false;
+        this.currentVideoIndex = this.mainQuestionIndex;
+        
+        this.uploadQueue.shift();
+        this.processUploadQueue();
+        return;
+      }
+      
+      uni.request({
+        url: `${apiBaseUrl}/voice_interview/check_transcription_status/`,
+        method: 'POST',
+        data: {
+          application_id: requestData.application_id,
+          original_question_id: requestData.original_question_id,
+          video_url: requestData.video_url
+        },
+        header: {
+          'content-type': 'application/x-www-form-urlencoded'
+        },
+        success: (res) => {
+          if (res.data.code === 200 || res.data.code === 2000) {
+            if (res.data.data && res.data.data.status === 'completed') {
+              console.log('视频转写完成');
+              this.isFollowUpMode = false;
+              this.currentVideoIndex = this.mainQuestionIndex;
+              
+              this.uploadQueue.shift();
+              this.processUploadQueue();
+              
+              this.$nextTick(() => {
+                if (this.currentVideoIndex < this.videoList.length) {
+                  this.videoUrl = this.videoList[this.currentVideoIndex];
+                  this.videoPlaying = true;
+                  const videoContext = uni.createVideoContext('myVideo', this);
+                  if (videoContext) {
+                    videoContext.play();
+                  }
+                }
+              });
+            } else {
+              // 状态仍为pending,继续重试
+              console.log(`转写进行中,${retryInterval/1000}秒后重试 (${retryCount + 1}/${maxRetries})`);
+              setTimeout(() => {
+                this.checkTranscriptionStatus(task, requestData, retryCount + 1);
+              }, retryInterval);
+            }
+          } else if (res.data.message === "面试视频尚未完成转写" || res.data.success === false) {
+            // 特殊处理转写未完成的情况
+            console.log(`转写未完成,${retryInterval/1000}秒后重试 (${retryCount + 1}/${maxRetries})`);
+            setTimeout(() => {
+              this.checkTranscriptionStatus(task, requestData, retryCount + 1);
+            }, retryInterval);
+          } else {
+            this.handleSubmitFailure(task, '检查转写状态失败: ' + (res.data.msg || '未知错误'));
+          }
+        },
+        fail: (err) => {
+          console.error('检查转写状态失败:', err);
+          // 网络错误时也进行重试
+          console.log(`网络请求失败,${retryInterval/1000}秒后重试 (${retryCount + 1}/${maxRetries})`);
+          setTimeout(() => {
+            this.checkTranscriptionStatus(task, requestData, retryCount + 1);
+          }, retryInterval);
+        }
+      });
+    },
+    
     // 添加新方法:更新上传状态文本
     updateUploadStatusText() {
       if (this.uploadQueue.length === 0) {
@@ -2644,7 +2721,21 @@ export default {
     
     // 修改 proceedToNextQuestion 方法,确保在切换视频时重置历史时间
     proceedToNextQuestion() {
+      // 如果正在切换视频,则返回
+      if (this.isVideoSwitching) {
+        console.log('正在切换视频中,请等待...');
+        return;
+      }
+      
       console.log('继续下一个问题');
+      this.isVideoSwitching = true; // 设置切换状态锁
+      
+      // 停止当前视频播放
+      const currentVideo = uni.createVideoContext('myVideo', this);
+      if (currentVideo) {
+        currentVideo.stop();
+        this.videoPlaying = false;
+      }
       
       // 增加当前视频索引,切换到下一个视频
       this.currentVideoIndex++;
@@ -2654,15 +2745,18 @@ export default {
       
       // 如果还有视频,播放下一个视频
       if (this.currentVideoIndex < this.videoList.length) {
+        // 确保先更新视频URL
         this.videoUrl = this.videoList[this.currentVideoIndex];
-        this.videoPlaying = true;
         
-        this.$nextTick(() => {
+        // 使用setTimeout确保DOM更新完成
+        setTimeout(() => {
+          this.videoPlaying = true;
           const videoContext = uni.createVideoContext('myVideo', this);
           if (videoContext) {
             videoContext.play();
           }
-        });
+          this.isVideoSwitching = false; // 重置切换状态锁
+        }, 100);
       } else {
         // 所有视频都播放完毕,显示完成页面或返回
         console.log('所有视频已播放完毕');
@@ -2680,6 +2774,7 @@ export default {
         
         // 延迟后根据职位ID跳转到不同页面
         setTimeout(() => {
+          this.isVideoSwitching = false; // 重置切换状态锁
           // 如果职位ID为9,跳转到interview-question页面
           if (jobId === 9) {
             uni.navigateTo({
@@ -3398,16 +3493,6 @@ export default {
     useDefaultVideosAndSubtitles() {
       console.log('使用默认视频和字幕');
       
-      // 设置默认视频列表
-     /*  this.videoList = [
-        this.introVideoUrl, // 介绍视频
-        'http://121.36.251.245:9000/minlong/tenant_1/general_uploads/e465e23d377b4456bbb3b755d3ad9500.mp4',
-        'http://121.36.251.245:9000/minlong/tenant_1/general_uploads/9bc84230d2a14978b4ea0a97e4102a15.mp4',
-        'http://121.36.251.245:9000/minlong/tenant_1/general_uploads/9b48e824432f451d9e27e12b884d9074.mp4',
-        'http://121.36.251.245:9000/minlong/tenant_1/general_uploads/52f1445b400345e1a673b3c7f05e5cc1.mp4',
-        'http://121.36.251.245:9000/minlong/tenant_1/general_uploads/abdaa6fda8494e3a8613304743ed0433.mp4'
-      ]; */
-      
       // 设置默认字幕
       this.subtitles = [
         {
@@ -3568,8 +3653,11 @@ export default {
       this.videoUrl = this.lowScoreVideoUrl;
       this.videoPlaying = true;
       
-      // 清除现有字幕前先保存
-      const originalSubtitle = this.currentSubtitle;
+      // 保存当前问题的字幕
+      const currentQuestion = this.getCurrentQuestionByIndex(this.currentVideoIndex);
+      const originalSubtitle = currentQuestion ? (currentQuestion.digital_human_video_subtitle || currentQuestion.question) : this.currentSubtitle;
+      
+      // 清除现有字幕
       this.currentSubtitle = '';
       
       // 使用 nextTick 确保 DOM 更新后再播放视频
@@ -3592,19 +3680,12 @@ export default {
                 translation: 'I didn\'t quite catch what you said, could you please repeat it?'
               }
             ];
-
-            // 在提示播放完成后恢复原来的字幕
-            setTimeout(() => {
-              // 如果是追问问题,保持显示追问问题的字幕
-              if (this.isFollowUpQuestion && this.currentFollowUpQuestion) {
-                this.currentSubtitle = this.currentFollowUpQuestion.digital_human_video_subtitle || this.currentFollowUpQuestion.question;
-              } else {
-                this.currentSubtitle = originalSubtitle;
-              }
-            }, 3000); // 3秒后恢复原问题
           }, 500);
         }
       });
+      
+      // 保存原始字幕信息到实例属性,以便在视频结束时恢复
+      this.originalQuestionSubtitle = originalSubtitle;
     },
 
     // 添加新方法:处理重新录制按钮点击
@@ -3818,10 +3899,14 @@ export default {
         // 检查录制时长
         const recordingDuration = this.getRecordingDuration();
         const lowScoreDuration = 7; // 低分阈值时长(秒),少于7秒视为低分
+        const minDuration = 3; // 最小录制时长阈值(秒)
         
-        // 如果录制时间少于7秒,播放"未听清楚"提示视频
+        // 如果录制时间少于最小时长或者在最小时长和低分阈值之间,播放"未听清楚"提示视频
         if (recordingDuration < lowScoreDuration) {
-          console.log(`录制时间 ${recordingDuration} 秒,少于 ${lowScoreDuration} 秒,将播放低分提示视频`);
+          let message = recordingDuration < minDuration ? 
+            `录制时间 ${recordingDuration} 秒,少于最小时长 ${minDuration} 秒` :
+            `录制时间 ${recordingDuration} 秒,少于标准时长 ${lowScoreDuration} 秒`;
+          console.log(message + ',将播放低分提示视频');
           
           // 增加重试次数
           this.retryCount++;
@@ -3976,32 +4061,55 @@ export default {
       }
 
       this.personDetectionInterval = setInterval(() => {
-        if (this.personDetectionSocket && this.cameraContext) {
+        try {
+          if (!this.personDetectionSocket || !this.cameraContext) {
+            console.warn('人脸检测:相机上下文或WebSocket连接未就绪');
+            return;
+          }
+
           this.cameraContext.takePhoto({
             quality: 'low',
             success: (res) => {
-              const tempFilePath = res.tempImagePath;
-              uni.getFileSystemManager().readFile({
-                filePath: tempFilePath,
-                encoding: 'base64',
-                success: (res) => {
-                  const base64Image = res.data;
-                  this.personDetectionSocket.send({
-                    data: JSON.stringify({
-                      type: 'person_detection',
-                      image_data: base64Image
-                    })
-                  });
-                },
-                fail: (error) => {
-                  console.error('Error reading image file:', error);
+              try {
+                const tempFilePath = res.tempImagePath;
+                if (!tempFilePath) {
+                  console.warn('人脸检测:未获取到有效的图片路径');
+                  return;
                 }
-              });
+                uni.getFileSystemManager().readFile({
+                  filePath: tempFilePath,
+                  encoding: 'base64',
+                  success: (res) => {
+                    try {
+                      const base64Image = res.data;
+                      if (!this.personDetectionSocket || this.personDetectionSocket.readyState !== 1) {
+                        console.warn('人脸检测:WebSocket连接已断开或未就绪');
+                        return;
+                      }
+                      this.personDetectionSocket.send({
+                        data: JSON.stringify({
+                          type: 'person_detection',
+                          image_data: base64Image
+                        })
+                      });
+                    } catch (wsError) {
+                      console.error('人脸检测:发送WebSocket数据时出错:', wsError);
+                    }
+                  },
+                  fail: (error) => {
+                    console.error('人脸检测:读取图片文件失败:', error);
+                  }
+                });
+              } catch (fileError) {
+                console.error('人脸检测:处理图片文件时出错:', fileError);
+              }
             },
             fail: (error) => {
-              console.error('Error taking photo:', error);
+              console.error('人脸检测:拍照失败:', error);
             }
           });
+        } catch (mainError) {
+          console.error('人脸检测:主流程执行出错:', mainError);
         }
       }, 3000);
     },
@@ -4184,11 +4292,11 @@ export default {
             console.log('音频可以播放');
             uni.hideLoading();
             this.isAudioPlaying = true;
-            uni.showToast({
+            /* uni.showToast({
               title: '正在播放追问',
               icon: 'none',
               duration: 2000
-            });
+            }); */
           });
           
           // 监听音频播放完成

+ 11 - 4
pages/index/index.vue

@@ -5,7 +5,7 @@
 			<view class="job-list-title">可选职位列表</view>
 			<view class="job-list">
 				<view v-for="(job, index) in jobList" :key="index" class="job-item"
-					:class="{'job-selected': selectedJobId === job.id}" @click="selectJob(job)">
+					:class="{'job-selected': selectedJobId === job.id}" v-show="job.status == 1" @click="selectJob(job)">
 					<view class="job-name">{{job.title}}</view>
 					<view class="job-actions">
 						<button class="detail-btn" @click.stop="viewJobDetail(job)">查看详情</button>
@@ -279,13 +279,20 @@ import { apiBaseUrl } from '@/common/config.js';
 				getJobList()
 					.then(res => {
 						uni.hideLoading();
-						console.log(res);
-						this.jobList = res;
-
+						console.log('职位列表数据:', res);
+						// 确保返回的数据是数组
+						this.jobList = Array.isArray(res) ? res.filter(job => job !== null && job !== undefined) : [];
+						if (this.jobList.length === 0) {
+							uni.showToast({
+								title: '暂无可用职位',
+								icon: 'none'
+							});
+						}
 					})
 					.catch(err => {
 						uni.hideLoading();
 						console.error('获取职位列表失败:', err);
+						this.jobList = []; // 确保发生错误时jobList是空数组
 						uni.showToast({
 							title: '网络错误,请稍后重试',
 							icon: 'none'

+ 52 - 44
pages/interview-question/interview-question.vue

@@ -686,7 +686,11 @@ export default {
     // 播放数字人视频
     playDigitalHumanVideo() {
       // 设置当前视频
-      this.videoUrl = this.videoList[this.currentVideoIndex];
+      if(JSON.parse(uni.getStorageSync('configData'))==null){
+        this.videoUrl = this.videoList[this.currentVideoIndex];
+      }else{
+        this.videoUrl =JSON.parse(uni.getStorageSync('configData')).digital_human?.ending_video_url || this.videoList[this.currentVideoIndex];
+      }
       this.videoPlaying = true;
       
       console.log(`播放视频 ${this.currentVideoIndex + 1}/${this.videoList.length}: ${this.videoUrl}`);
@@ -2847,14 +2851,18 @@ export default {
       // 获取用户信息和租户ID
       const tenant_id = uni.getStorageSync('tenant_id') || '1';
       const application_id = uni.getStorageSync('appId') || '98'; // 默认为98(报告)
-      
+      let positionConfigId = 1;
+      if(JSON.parse(uni.getStorageSync('configData'))){
+        positionConfigId = JSON.parse(uni.getStorageSync('configData')).id;
+      }
       // 准备请求数据
       const requestData = {
         voice_url: videoUrl,
         tenant_id: tenant_id,
         application_id: application_id,
         scene_type: 'interview', // 场景类型:面试
-        voice_type: 'longxiaoxia', // 角色:龙小侠
+       // voice_type: 'longxiaoxia', // 角色:龙小侠
+        position_config_id: positionConfigId,
         conversation_history: this.conversationHistory // 添加对话历史
       };
       
@@ -3199,11 +3207,11 @@ export default {
           console.log('iOS小程序音频开始播放');
           this.currentSubtitle = this.aiText;
           
-          uni.showToast({
-            title: '正在播放AI回复',
-            icon: 'none',
-            duration: 1500
-          });
+          // uni.showToast({
+          //   title: '正在播放AI回复',
+          //   icon: 'none',
+          //   duration: 1500
+          // });
         });
         
         // 设置播放结束事件
@@ -3337,11 +3345,11 @@ export default {
       }
       
       // 显示超时提示
-      uni.showToast({
+      /* uni.showToast({
         title: '音频加载超时,显示文字',
         icon: 'none',
         duration: 2000
-      });
+      }); */
       
       // 使用文本回退
       this.useIOSTextFallback();
@@ -3414,11 +3422,11 @@ export default {
       // 显示友好提示(如果还没有显示过)
       if (!this.hasShownTextFallbackToast) {
         this.hasShownTextFallbackToast = true;
-        uni.showToast({
+       /* uni.showToast({
           title: '为您显示文字回复',
           icon: 'none',
           duration: 2000
-        });
+        }); */
       }
       
       // 显示完整文本
@@ -3599,11 +3607,11 @@ export default {
           console.log('AI语音开始播放');
           
           // 显示正在播放提示
-          uni.showToast({
+          /* uni.showToast({
             title: '正在播放AI回复',
             icon: 'none',
             duration: 2000
-          });
+          }); */
         });
         
         // 监听播放结束事件
@@ -3664,11 +3672,11 @@ export default {
         this.isPlayingAiVoice = false;
         
         // 显示错误提示
-        uni.showToast({
+       /* uni.showToast({
           title: '音频播放失败,请查看文字回复',
           icon: 'none',
           duration: 2000
-        });
+        }); */
         
         // 使用文本显示方式作为备选方案
         this.handleAudioPlaybackFailure();
@@ -3698,25 +3706,25 @@ export default {
           // 检查具体错误类型
           if (err.errMsg && err.errMsg.includes('-11850')) {
             console.log('iOS小程序检测到系统音频错误(-11850)');
-            uni.showToast({
+           /* uni.showToast({
               title: '系统音频暂停,显示文字',
               icon: 'none',
               duration: 2000
-            });
+            }); */
           } else if (err.errCode === 10002) {
             console.log('iOS小程序检测到errCode:10002,网络或资源问题');
-            uni.showToast({
+            /* uni.showToast({
               title: '音频加载中断,显示文字',
               icon: 'none',
               duration: 2000
-            });
+            }); */
           } else {
             console.log('iOS小程序其他音频错误:', err.errCode);
-            uni.showToast({
+           /* uni.showToast({
               title: '音频播放异常,显示文字',
               icon: 'none',
               duration: 2000
-            });
+            }); */
           }
           
           this.useIOSMiniProgramTextFallback(audioContext);
@@ -3730,11 +3738,11 @@ export default {
           console.log('iOS小程序音频开始播放');
           this.currentSubtitle = this.aiText;
           
-          uni.showToast({
+          /* uni.showToast({
             title: '正在播放AI回复',
             icon: 'none',
             duration: 1500
-          });
+          }); */
         });
         
         audioContext.onEnded(() => {
@@ -3887,11 +3895,11 @@ export default {
               this.aiAudioPlayer = null;
               
               // 显示错误提示
-              uni.showToast({
+              /* uni.showToast({
                 title: '无法播放音频,请查看文字回复',
                 icon: 'none',
                 duration: 2000
-              });
+              }); */
               
               this.showContinueQuestionOptions();
               this.checkPendingNavigation();
@@ -3914,11 +3922,11 @@ export default {
       this.isPlayingAiVoice = false;
       
       // 显示错误提示
-      uni.showToast({
+     /* uni.showToast({
         title: '无法播放音频,将直接显示文字回复',
         icon: 'none',
         duration: 2000
-      });
+      }); */
       
       // 确保字幕显示足够长的时间(10秒)让用户阅读
       this.currentSubtitle = this.aiText;
@@ -4063,11 +4071,11 @@ export default {
       if (!this.aiVoiceUrl || this.aiVoiceUrl.trim() === '') {
         console.error('无效的音频URL');
         // 显示错误提示
-        uni.showToast({
+        /* uni.showToast({
           title: '音频加载失败',
           icon: 'none',
           duration: 2000
-        });
+        }); */
         
         // 标记播放结束
         this.isPlayingAiVoice = false;
@@ -4090,11 +4098,11 @@ export default {
           console.log('AI语音开始播放');
           
           // 显示正在播放提示
-          uni.showToast({
+         /* uni.showToast({
             title: '正在播放AI回复',
             icon: 'none',
             duration: 2000
-          });
+          }); */
         });
         
         // 监听播放结束事件
@@ -4155,11 +4163,11 @@ export default {
         this.isPlayingAiVoice = false;
         
         // 显示错误提示
-        uni.showToast({
+        /* uni.showToast({
           title: '音频播放失败,请查看文字回复',
           icon: 'none',
           duration: 2000
-        });
+        }); */
         
         // 使用文本显示方式作为备选方案
         this.handleAudioPlaybackFailure();
@@ -4227,11 +4235,11 @@ export default {
       
       if (systemInfo.platform === 'android' || systemInfo.platform === 'ios') {
         // 在移动端尝试使用系统播放器
-        uni.showToast({
+       /* uni.showToast({
           title: '正在使用系统播放器',
           icon: 'none',
           duration: 2000
-        });
+        }); */
         
         // 使用uni.playVoice API (如果可用)
         if (typeof uni.playVoice === 'function') {
@@ -4315,11 +4323,11 @@ export default {
     handleContinueQuestionClick() {
       // 如果AI语音仍在播放,不允许继续提问
       if (this.isPlayingAiVoice) {
-        uni.showToast({
+        /* uni.showToast({
           title: '请等待面试官回复完成',
           icon: 'none',
           duration: 2000
-        });
+        }); */
         return;
       }
       
@@ -4379,11 +4387,11 @@ export default {
       console.error('录制错误:', error);
       
       // 显示错误提示
-      uni.showToast({
+      /* uni.showToast({
         title: '录制失败,请重试',
         icon: 'none',
         duration: 2000
-      });
+      }); */
       
       // 重置录制状态
       this.isRecording = false;
@@ -4398,11 +4406,11 @@ export default {
       console.error('上传错误:', error);
       
       // 显示错误提示
-      uni.showToast({
+      /* uni.showToast({
         title: '上传失败,请重试',
         icon: 'none',
         duration: 2000
-      });
+      }); */
       
       // 显示重试按钮
       this.showRetryButton = true;
@@ -4500,11 +4508,11 @@ export default {
       
       if (!this.hasShownTextFallbackToast) {
         this.hasShownTextFallbackToast = true;
-        uni.showToast({
+        /* uni.showToast({
           title: '已切换为文字显示',
           icon: 'none',
           duration: 2000
-        });
+        }); */
       }
       
       // 显示AI回复文本

+ 2 - 2
pages/my/my.vue

@@ -717,10 +717,10 @@ export default {
 					this.isLogin = false;
 					
 					if (showConfirm) {
-						uni.showToast({
+						/* uni.showToast({
 							title: err.message || '退出登录失败',
 							icon: 'none'
-						});
+						}); */
 					}
 				});
 			};

+ 1 - 1
pages/preview/preview.vue

@@ -10,7 +10,7 @@
 		</view>
 		<!-- 拍照指引图示 -->
 		<view class="guide-image">
-			<image src="http://data.qicai321.com/minlong/ee86c2e0-6e18-49b8-a001-bba3af8995d4.jpg" mode="aspectFit"></image>
+			<image src="https://data.qicai321.com/minlong/a7f24c02-ca46-47c9-9423-8523d551cda5.jpg" mode="aspectFit"></image>
 		</view>
 		
 		<!-- 拍照要求列表 -->

+ 1 - 1
unpackage/dist/dev/mp-weixin/api/user.js

@@ -33,7 +33,7 @@ const getUserInfo = (userId, openid) => {
   return utils_request.http.get(url);
 };
 const logout = () => {
-  return utils_request.http.post("/api/user/logout");
+  return utils_request.http.post("/wechat/wechatLogout");
 };
 const getJobList = (params = {}) => {
   const defaultParams = {

+ 113 - 89
unpackage/dist/dev/mp-weixin/pages/Personal/Personal.js

@@ -321,6 +321,15 @@ const _sfc_main = {
     showWorkPositionField() {
       var _a;
       return Object.keys(this.safeWorkFieldsConfig).length === 0 || ((_a = this.safeWorkFieldsConfig.position) == null ? void 0 : _a.visible) !== false;
+    },
+    showRequireProfessionalSkillsField() {
+      return this.safeConfigData.require_professional_skills;
+    },
+    showRequireTrainingInfoField() {
+      return this.safeConfigData.require_training_info;
+    },
+    shouldShowSkillsStep() {
+      return this.showRequireTrainingInfoField || this.showRequireProfessionalSkillsField;
     }
   },
   methods: {
@@ -355,10 +364,10 @@ const _sfc_main = {
             // 现居住地址总是显示和必填
             "expectedSalary": true,
             // 期望薪资总是显示
-            "skills": true,
-            // 专业技能总是显示和必填
-            "training": true,
-            // 培训经历总是显示和必填
+            "skills": this.showRequireTrainingInfoField,
+            // 专业技能根据配置显示和必填
+            "training": this.showRequireProfessionalSkillsField,
+            // 培训经历根据配置显示和必填
             "threePeriod": this.formData.gender === "女"
             // 只有女性时才需要验证三期状态
           };
@@ -1007,7 +1016,14 @@ const _sfc_main = {
       }
       const nextIndex = this.currentStepIndex + 1;
       if (nextIndex < this.steps.length) {
-        this.currentStep = this.steps[nextIndex].id;
+        if (this.steps[nextIndex].id === 6 && !this.shouldShowSkillsStep) {
+          const skipIndex = nextIndex + 1;
+          if (skipIndex < this.steps.length) {
+            this.currentStep = this.steps[skipIndex].id;
+          }
+        } else {
+          this.currentStep = this.steps[nextIndex].id;
+        }
         common_vendor.index.pageScrollTo({
           scrollTop: 0,
           duration: 300
@@ -1737,27 +1753,35 @@ function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
     ca: common_vendor.o((...args) => $options.saveEducation && $options.saveEducation(...args)),
     cb: common_vendor.t($data.isEditingEducation ? "保存修改" : "添加学历")
   }) : {}) : {}, {
-    cc: $data.currentStep === 6
-  }, $data.currentStep === 6 ? common_vendor.e({
-    cd: $data.formErrors.skills ? 1 : "",
-    ce: $data.formData.skills,
-    cf: common_vendor.o(($event) => $data.formData.skills = $event.detail.value),
-    cg: $data.formErrors.skills
+    cc: $data.currentStep === 6 && ($options.showRequireTrainingInfoField || $options.showRequireProfessionalSkillsField)
+  }, $data.currentStep === 6 && ($options.showRequireTrainingInfoField || $options.showRequireProfessionalSkillsField) ? common_vendor.e({
+    cd: $options.showRequireTrainingInfoField
+  }, $options.showRequireTrainingInfoField ? {} : {}, {
+    ce: $options.showRequireTrainingInfoField
+  }, $options.showRequireTrainingInfoField ? common_vendor.e({
+    cf: $data.formErrors.skills ? 1 : "",
+    cg: $data.formData.skills,
+    ch: common_vendor.o(($event) => $data.formData.skills = $event.detail.value),
+    ci: $data.formErrors.skills
   }, $data.formErrors.skills ? {
-    ch: common_vendor.t($data.formErrors.skills)
-  } : {}, {
-    ci: $data.formErrors.training ? 1 : "",
-    cj: $data.formData.training,
-    ck: common_vendor.o(($event) => $data.formData.training = $event.detail.value),
-    cl: $data.formErrors.training
-  }, $data.formErrors.training ? {
-    cm: common_vendor.t($data.formErrors.training)
+    cj: common_vendor.t($data.formErrors.skills)
   } : {}) : {}, {
-    cn: $data.currentStep === 8
+    ck: $options.showRequireProfessionalSkillsField
+  }, $options.showRequireProfessionalSkillsField ? {} : {}, {
+    cl: $options.showRequireProfessionalSkillsField
+  }, $options.showRequireProfessionalSkillsField ? common_vendor.e({
+    cm: $data.formErrors.training ? 1 : "",
+    cn: $data.formData.training,
+    co: common_vendor.o(($event) => $data.formData.training = $event.detail.value),
+    cp: $data.formErrors.training
+  }, $data.formErrors.training ? {
+    cq: common_vendor.t($data.formErrors.training)
+  } : {}) : {}) : {}, {
+    cr: $data.currentStep === 8
   }, $data.currentStep === 8 ? common_vendor.e({
-    co: $data.workList.length > 0
+    cs: $data.workList.length > 0
   }, $data.workList.length > 0 ? {
-    cp: common_vendor.f($data.workList, (work, index, i0) => {
+    ct: common_vendor.f($data.workList, (work, index, i0) => {
       return common_vendor.e({
         a: common_vendor.t(index + 1),
         b: common_vendor.o(($event) => $options.editWork(index), index),
@@ -1780,106 +1804,106 @@ function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
         m: index
       });
     }),
-    cq: $options.showWorkTimeField,
-    cr: $options.showWorkCompanyField,
-    cs: $options.showWorkDepartmentField,
-    ct: $options.showWorkEmployeeCountField,
-    cv: $options.showWorkPositionField
+    cv: $options.showWorkTimeField,
+    cw: $options.showWorkCompanyField,
+    cx: $options.showWorkDepartmentField,
+    cy: $options.showWorkEmployeeCountField,
+    cz: $options.showWorkPositionField
   } : {}, {
-    cw: $data.workList.length < 2 || $data.isEditingWork
+    cA: $data.workList.length < 2 || $data.isEditingWork
   }, $data.workList.length < 2 || $data.isEditingWork ? common_vendor.e({
-    cx: common_vendor.t($data.isEditingWork ? "编辑工作经历" : "添加工作经历"),
-    cy: $data.isEditingWork
+    cB: common_vendor.t($data.isEditingWork ? "编辑工作经历" : "添加工作经历"),
+    cC: $data.isEditingWork
   }, $data.isEditingWork ? {
-    cz: common_vendor.o((...args) => $options.cancelEditWork && $options.cancelEditWork(...args))
+    cD: common_vendor.o((...args) => $options.cancelEditWork && $options.cancelEditWork(...args))
   } : {}, {
-    cA: $options.showWorkTimeField
+    cE: $options.showWorkTimeField
   }, $options.showWorkTimeField ? common_vendor.e({
-    cB: common_vendor.t($data.workForm.startTime || "开始时间"),
-    cC: $data.workForm.startTime,
-    cD: common_vendor.o((...args) => $options.bindWorkStartTimeChange && $options.bindWorkStartTimeChange(...args)),
-    cE: $data.workErrors.startTime ? 1 : "",
-    cF: common_vendor.t($data.workForm.endTime || "结束时间"),
-    cG: $data.workForm.endTime,
-    cH: common_vendor.o((...args) => $options.bindWorkEndTimeChange && $options.bindWorkEndTimeChange(...args)),
-    cI: $data.workErrors.endTime ? 1 : "",
-    cJ: $data.workErrors.startTime
+    cF: common_vendor.t($data.workForm.startTime || "开始时间"),
+    cG: $data.workForm.startTime,
+    cH: common_vendor.o((...args) => $options.bindWorkStartTimeChange && $options.bindWorkStartTimeChange(...args)),
+    cI: $data.workErrors.startTime ? 1 : "",
+    cJ: common_vendor.t($data.workForm.endTime || "结束时间"),
+    cK: $data.workForm.endTime,
+    cL: common_vendor.o((...args) => $options.bindWorkEndTimeChange && $options.bindWorkEndTimeChange(...args)),
+    cM: $data.workErrors.endTime ? 1 : "",
+    cN: $data.workErrors.startTime
   }, $data.workErrors.startTime ? {
-    cK: common_vendor.t($data.workErrors.startTime)
+    cO: common_vendor.t($data.workErrors.startTime)
   } : {}, {
-    cL: $data.workErrors.endTime
+    cP: $data.workErrors.endTime
   }, $data.workErrors.endTime ? {
-    cM: common_vendor.t($data.workErrors.endTime)
+    cQ: common_vendor.t($data.workErrors.endTime)
   } : {}) : {}, {
-    cN: $options.showWorkCompanyField
+    cR: $options.showWorkCompanyField
   }, $options.showWorkCompanyField ? common_vendor.e({
-    cO: $data.workErrors.companyName ? 1 : "",
-    cP: $data.workForm.companyName,
-    cQ: common_vendor.o(($event) => $data.workForm.companyName = $event.detail.value),
-    cR: $data.workErrors.companyName
+    cS: $data.workErrors.companyName ? 1 : "",
+    cT: $data.workForm.companyName,
+    cU: common_vendor.o(($event) => $data.workForm.companyName = $event.detail.value),
+    cV: $data.workErrors.companyName
   }, $data.workErrors.companyName ? {
-    cS: common_vendor.t($data.workErrors.companyName)
+    cW: common_vendor.t($data.workErrors.companyName)
   } : {}) : {}, {
-    cT: $options.showWorkEmployeeCountField
+    cX: $options.showWorkEmployeeCountField
   }, $options.showWorkEmployeeCountField ? common_vendor.e({
-    cU: $data.workErrors.employeeCount ? 1 : "",
-    cV: $data.workForm.employeeCount,
-    cW: common_vendor.o(($event) => $data.workForm.employeeCount = $event.detail.value),
-    cX: $data.workErrors.employeeCount
+    cY: $data.workErrors.employeeCount ? 1 : "",
+    cZ: $data.workForm.employeeCount,
+    da: common_vendor.o(($event) => $data.workForm.employeeCount = $event.detail.value),
+    db: $data.workErrors.employeeCount
   }, $data.workErrors.employeeCount ? {
-    cY: common_vendor.t($data.workErrors.employeeCount)
+    dc: common_vendor.t($data.workErrors.employeeCount)
   } : {}) : {}, {
-    cZ: $options.showWorkDepartmentField
+    dd: $options.showWorkDepartmentField
   }, $options.showWorkDepartmentField ? common_vendor.e({
-    da: $data.workErrors.department ? 1 : "",
-    db: $data.workForm.department,
-    dc: common_vendor.o(($event) => $data.workForm.department = $event.detail.value),
-    dd: $data.workErrors.department
+    de: $data.workErrors.department ? 1 : "",
+    df: $data.workForm.department,
+    dg: common_vendor.o(($event) => $data.workForm.department = $event.detail.value),
+    dh: $data.workErrors.department
   }, $data.workErrors.department ? {
-    de: common_vendor.t($data.workErrors.department)
+    di: common_vendor.t($data.workErrors.department)
   } : {}) : {}, {
-    df: $options.showWorkPositionField
+    dj: $options.showWorkPositionField
   }, $options.showWorkPositionField ? common_vendor.e({
-    dg: $data.workErrors.position ? 1 : "",
-    dh: $data.workForm.position,
-    di: common_vendor.o(($event) => $data.workForm.position = $event.detail.value),
-    dj: $data.workErrors.position
+    dk: $data.workErrors.position ? 1 : "",
+    dl: $data.workForm.position,
+    dm: common_vendor.o(($event) => $data.workForm.position = $event.detail.value),
+    dn: $data.workErrors.position
   }, $data.workErrors.position ? {
-    dk: common_vendor.t($data.workErrors.position)
+    dp: common_vendor.t($data.workErrors.position)
   } : {}) : {}, {
-    dl: $data.workForm.monthlySalary,
-    dm: common_vendor.o(($event) => $data.workForm.monthlySalary = $event.detail.value),
-    dn: $data.workErrors.monthlySalary
+    dq: $data.workForm.monthlySalary,
+    dr: common_vendor.o(($event) => $data.workForm.monthlySalary = $event.detail.value),
+    ds: $data.workErrors.monthlySalary
   }, $data.workErrors.monthlySalary ? {
-    dp: common_vendor.t($data.workErrors.monthlySalary)
+    dt: common_vendor.t($data.workErrors.monthlySalary)
   } : {}, {
-    dq: $data.workForm.supervisor,
-    dr: common_vendor.o(($event) => $data.workForm.supervisor = $event.detail.value),
-    ds: $data.workErrors.supervisor
+    dv: $data.workForm.supervisor,
+    dw: common_vendor.o(($event) => $data.workForm.supervisor = $event.detail.value),
+    dx: $data.workErrors.supervisor
   }, $data.workErrors.supervisor ? {
-    dt: common_vendor.t($data.workErrors.supervisor)
+    dy: common_vendor.t($data.workErrors.supervisor)
   } : {}, {
-    dv: $data.workForm.supervisorPhone,
-    dw: common_vendor.o(($event) => $data.workForm.supervisorPhone = $event.detail.value),
-    dx: $data.workErrors.supervisorPhone
+    dz: $data.workForm.supervisorPhone,
+    dA: common_vendor.o(($event) => $data.workForm.supervisorPhone = $event.detail.value),
+    dB: $data.workErrors.supervisorPhone
   }, $data.workErrors.supervisorPhone ? {
-    dy: common_vendor.t($data.workErrors.supervisorPhone)
+    dC: common_vendor.t($data.workErrors.supervisorPhone)
   } : {}, {
-    dz: common_vendor.t($data.isEditingWork ? "✓" : "+"),
-    dA: common_vendor.o((...args) => $options.saveWork && $options.saveWork(...args)),
-    dB: common_vendor.t($data.isEditingWork ? "保存修改" : "添加工作经历")
+    dD: common_vendor.t($data.isEditingWork ? "✓" : "+"),
+    dE: common_vendor.o((...args) => $options.saveWork && $options.saveWork(...args)),
+    dF: common_vendor.t($data.isEditingWork ? "保存修改" : "添加工作经历")
   }) : {}) : {}, {
-    dC: $options.showPrevButton
+    dG: $options.showPrevButton
   }, $options.showPrevButton ? {
-    dD: common_vendor.o((...args) => $options.prevStep && $options.prevStep(...args))
+    dH: common_vendor.o((...args) => $options.prevStep && $options.prevStep(...args))
   } : {}, {
-    dE: $options.showNextButton
+    dI: $options.showNextButton
   }, $options.showNextButton ? {
-    dF: common_vendor.o((...args) => $options.nextStep && $options.nextStep(...args))
+    dJ: common_vendor.o((...args) => $options.nextStep && $options.nextStep(...args))
   } : {}, {
-    dG: $options.showSubmitButton
+    dK: $options.showSubmitButton
   }, $options.showSubmitButton ? {
-    dH: common_vendor.o((...args) => $options.submitForm && $options.submitForm(...args))
+    dL: common_vendor.o((...args) => $options.submitForm && $options.submitForm(...args))
   } : {});
 }
 const MiniProgramPage = /* @__PURE__ */ common_vendor._export_sfc(_sfc_main, [["render", _sfc_render]]);

File diff suppressed because it is too large
+ 0 - 0
unpackage/dist/dev/mp-weixin/pages/Personal/Personal.wxml


+ 10 - 1
unpackage/dist/dev/mp-weixin/pages/face-photo/face-photo.js

@@ -226,6 +226,7 @@ const _sfc_main = {
           "description": "面部照片"
         },
         success: (uploadRes) => {
+          var _a;
           console.log("照片上传成功:", uploadRes);
           let result;
           try {
@@ -242,9 +243,17 @@ const _sfc_main = {
               title: "照片上传成功",
               icon: "success"
             });
+            let configData = {};
+            try {
+              configData = JSON.parse(common_vendor.index.getStorageSync("configData") || "{}");
+            } catch (e) {
+              console.error("解析configData失败:", e);
+              configData = {};
+            }
+            const targetUrl = ((_a = configData == null ? void 0 : configData.question_form_switches) == null ? void 0 : _a.enable_open_questions) ? "/pages/identity-verify/identity-verify" : "/pages/camera/camera";
             setTimeout(() => {
               common_vendor.index.navigateTo({
-                url: "/pages/identity-verify/identity-verify",
+                url: targetUrl,
                 fail: (err) => {
                   console.error("页面跳转失败:", err);
                   common_vendor.index.showToast({

+ 189 - 148
unpackage/dist/dev/mp-weixin/pages/identity-verify/identity-verify.js

@@ -63,15 +63,16 @@ const _sfc_main = {
       questions: [],
       // 添加新属性存储API返回的问题数据
       introVideoUrl: (() => {
+        const DEFAULT_VIDEO_URL = "https://data.qicai321.com/minlong/ee4d9cce-c3d5-4350-8c6e-684283827897.mp4";
         try {
           const configStr = common_vendor.index.getStorageSync("configData");
-          if (configStr && configStr.trim()) {
-            return JSON.parse(configStr).digital_human_opening_video_url || "https://data.qicai321.com/minlong/ee4d9cce-c3d5-4350-8c6e-684283827897.mp4";
-          }
-          return "https://data.qicai321.com/minlong/ee4d9cce-c3d5-4350-8c6e-684283827897.mp4";
+          if (!configStr)
+            return DEFAULT_VIDEO_URL;
+          const config = JSON.parse(configStr);
+          return config.digital_human_opening_video_url || DEFAULT_VIDEO_URL;
         } catch (error) {
           console.warn("解析配置数据失败:", error);
-          return {};
+          return DEFAULT_VIDEO_URL;
         }
       })(),
       //'https://data.qicai321.com/minlong/ee4d9cce-c3d5-4350-8c6e-684283827897.mp4', // 保留介绍视频
@@ -123,8 +124,21 @@ const _sfc_main = {
       // GIF图片的URL
       globalSocketTask: null,
       // 添加全局 WebSocket 连接对象
-      lowScoreVideoUrl: "https://data.qicai321.com/minlong/latentsync/0530e7f5-1957-422d-8f34-ba4a92608081_result.mp4",
-      // 低分提示视频URL
+      lowScoreVideoUrl: (() => {
+        var _a;
+        const DEFAULT_VIDEO_URL = "https://data.qicai321.com/minlong/latentsync/0530e7f5-1957-422d-8f34-ba4a92608081_result.mp4";
+        try {
+          const configStr = common_vendor.index.getStorageSync("configData");
+          if (!configStr)
+            return DEFAULT_VIDEO_URL;
+          const config = JSON.parse(configStr);
+          return ((_a = config.digital_human) == null ? void 0 : _a.middle_video_url) || DEFAULT_VIDEO_URL;
+        } catch (error) {
+          console.warn("解析配置数据失败:", error);
+          return DEFAULT_VIDEO_URL;
+        }
+      })(),
+      //'https://data.qicai321.com/minlong/latentsync/0530e7f5-1957-422d-8f34-ba4a92608081_result.mp4', // 低分提示视频URL
       showRerecordButton: false,
       // 控制重新录制按钮显示
       isPlayingLowScoreVideo: false,
@@ -205,8 +219,12 @@ const _sfc_main = {
       // 添加父问题的job_position_question_id
       isFollowUpMode: false,
       // 是否处于追问模式
-      mainQuestionIndex: 0
+      mainQuestionIndex: 0,
       // 当前主问题的索引
+      isVideoSwitching: false,
+      // 添加视频切换状态锁
+      originalQuestionSubtitle: null
+      // 保存原始字幕信息
     };
   },
   mounted() {
@@ -374,10 +392,6 @@ const _sfc_main = {
           await this.handleFollowUpQuestion(res.data);
         } else {
           console.error("面试互动接口返回错误:", res.data);
-          common_vendor.index.showToast({
-            title: "获取追问失败",
-            icon: "none"
-          });
         }
       } catch (error) {
         console.error("调用面试互动接口失败:", error);
@@ -389,10 +403,6 @@ const _sfc_main = {
         console.log("开始播放追问音频, URL:", this.followUpAudioUrl);
         if (!this.followUpAudioUrl) {
           console.error("没有音频URL");
-          common_vendor.index.showToast({
-            title: "音频URL无效",
-            icon: "none"
-          });
           reject(new Error("没有音频URL"));
           return;
         }
@@ -410,11 +420,6 @@ const _sfc_main = {
             console.log("音频可以播放");
             common_vendor.index.hideLoading();
             this.isAudioPlaying = true;
-            common_vendor.index.showToast({
-              title: "正在播放追问",
-              icon: "none",
-              duration: 2e3
-            });
           });
           innerAudioContext.onEnded(() => {
             console.log("追问音频播放完成");
@@ -429,10 +434,6 @@ const _sfc_main = {
             console.error("音频播放错误:", res);
             this.isAudioPlaying = false;
             common_vendor.index.hideLoading();
-            common_vendor.index.showToast({
-              title: "音频播放失败",
-              icon: "none"
-            });
             reject(res);
             this.stopAndDestroyAudio();
           });
@@ -442,10 +443,6 @@ const _sfc_main = {
           console.error("创建或播放音频失败:", error);
           this.isAudioPlaying = false;
           common_vendor.index.hideLoading();
-          common_vendor.index.showToast({
-            title: "音频播放失败",
-            icon: "none"
-          });
           this.stopAndDestroyAudio();
           reject(error);
         }
@@ -476,11 +473,6 @@ const _sfc_main = {
     bindAudioEvents(audioContext, resolve, reject) {
       audioContext.onCanplay(() => {
         console.log("音频可以播放");
-        common_vendor.index.showToast({
-          title: "正在播放追问",
-          icon: "none",
-          duration: 2e3
-        });
       });
       audioContext.onTimeUpdate(() => {
         console.log("音频播放进度:", audioContext.currentTime);
@@ -492,10 +484,6 @@ const _sfc_main = {
       });
       audioContext.onError((res) => {
         console.error("音频播放错误:", res);
-        common_vendor.index.showToast({
-          title: "音频播放失败",
-          icon: "none"
-        });
         this.cleanupAudioContext();
         reject(res);
       });
@@ -904,10 +892,6 @@ const _sfc_main = {
         },
         fail: () => {
           this.videoPlaying = false;
-          common_vendor.index.showToast({
-            title: "无法加载视频,显示静态图片",
-            icon: "none"
-          });
         }
       });
     },
@@ -942,6 +926,8 @@ const _sfc_main = {
           this.showRerecordButton = true;
           if (this.isFollowUpQuestion && this.currentFollowUpQuestion) {
             this.currentSubtitle = this.currentFollowUpQuestion.digital_human_video_subtitle || this.currentFollowUpQuestion.question;
+          } else if (this.originalQuestionSubtitle) {
+            this.currentSubtitle = this.originalQuestionSubtitle;
           }
         } else {
           console.log("已达到最大重试次数,继续下一题");
@@ -949,6 +935,7 @@ const _sfc_main = {
           this.proceedToNextQuestion();
         }
         this.isPlayingLowScoreVideo = false;
+        this.originalQuestionSubtitle = null;
         return;
       }
       if (this.isFollowUpQuestion) {
@@ -1017,11 +1004,12 @@ const _sfc_main = {
         });
         return;
       }
-      this.completeRecordingStop();
       if (recordingDuration < lowScoreDuration) {
         console.log(`录制时间 ${recordingDuration} 秒,少于 ${lowScoreDuration} 秒,将播放低分提示视频`);
-        this.needPlayLowScoreVideo = true;
+        this.completeRecordingStop(false);
+        this.playLowScoreVideo();
       } else {
+        this.completeRecordingStop(true);
         this.needPlayLowScoreVideo = false;
       }
     },
@@ -1203,10 +1191,6 @@ const _sfc_main = {
     startBrowserRecording() {
       if (!this.cameraStream) {
         console.error("没有可用的摄像头流");
-        common_vendor.index.showToast({
-          title: "录制失败,摄像头未就绪",
-          icon: "none"
-        });
         this.proceedToNextQuestion();
         return;
       }
@@ -1306,10 +1290,6 @@ const _sfc_main = {
         console.log("MediaRecorder停止,数据块数量:", this.recordedChunks.length);
         if (this.recordedChunks.length === 0) {
           console.error("没有录制到数据");
-          common_vendor.index.showToast({
-            title: "录制失败,未捕获到数据",
-            icon: "none"
-          });
           this.proceedToNextQuestion();
           return;
         }
@@ -1350,34 +1330,6 @@ const _sfc_main = {
         console.error("开始录制失败:", e);
       }
     },
-    // 添加新方法:停止录制用户回答
-    stopRecordingAnswer() {
-      console.log("停止录制用户回答");
-      if (this.countdownTimer) {
-        clearInterval(this.countdownTimer);
-        this.countdownTimer = null;
-        this.showCountdown = false;
-      }
-      this.isWaitingForAnswer = false;
-      const recordingDuration = this.getRecordingDuration();
-      const minimumDuration = 3;
-      const lowScoreDuration = 7;
-      if (recordingDuration < minimumDuration) {
-        common_vendor.index.showToast({
-          title: "录制时间过短,请至少录制3秒",
-          icon: "none",
-          duration: 2e3
-        });
-        return;
-      }
-      this.completeRecordingStop();
-      if (recordingDuration < lowScoreDuration) {
-        console.log(`录制时间 ${recordingDuration} 秒,少于 ${lowScoreDuration} 秒,将播放低分提示视频`);
-        this.needPlayLowScoreVideo = true;
-      } else {
-        this.needPlayLowScoreVideo = false;
-      }
-    },
     // 添加新方法:获取录制时长
     getRecordingDuration() {
       if (this.recordingStartTime) {
@@ -1414,14 +1366,9 @@ const _sfc_main = {
           }
         });
       }
-      common_vendor.index.showToast({
-        title: "请重新开始回答",
-        icon: "none",
-        duration: 2e3
-      });
     },
     // 修改 completeRecordingStop 方法,确保正确处理追问问题ID
-    completeRecordingStop() {
+    completeRecordingStop(uploadVideo = true) {
       console.log("完成录制停止");
       if (this.recordingTimer) {
         clearInterval(this.recordingTimer);
@@ -1433,9 +1380,29 @@ const _sfc_main = {
       const systemInfo = common_vendor.index.getSystemInfoSync();
       const isMiniProgram = systemInfo.uniPlatform && systemInfo.uniPlatform.startsWith("mp-");
       if (isMiniProgram) {
-        this.stopMiniProgramRecording();
+        if (uploadVideo) {
+          this.stopMiniProgramRecording();
+        } else {
+          if (this.cameraContext) {
+            this.cameraContext.stopRecord({
+              success: () => {
+                console.log("相机录制已停止,不上传视频");
+              },
+              fail: (err) => {
+                console.error("停止相机录制失败:", err);
+              }
+            });
+          }
+        }
       } else {
-        this.stopBrowserRecording();
+        if (uploadVideo) {
+          this.stopBrowserRecording();
+        } else {
+          if (this.mediaRecorder && this.mediaRecorder.state !== "inactive") {
+            this.mediaRecorder.stop();
+            this.recordedChunks = [];
+          }
+        }
       }
       if (this.isFollowUpQuestion && this.currentFollowUpQuestion) {
         console.log("当前是追问问题,记录追问问题ID:", this.currentFollowUpQuestion.id);
@@ -1536,11 +1503,6 @@ const _sfc_main = {
       this.uploadQueue.push(uploadTask);
       this.uploadProgress[uploadTask.id] = 0;
       this.uploadStatus[uploadTask.id] = "pending";
-      common_vendor.index.showToast({
-        title: "正在上传回答...",
-        icon: "loading",
-        duration: 1500
-      });
       this.updateUploadStatusText();
       return new Promise((resolve) => {
         const checkUploadStatus = () => {
@@ -1713,11 +1675,6 @@ const _sfc_main = {
         }, 5e3);
       } else {
         console.log("超过最大重试次数,放弃上传");
-        common_vendor.index.showToast({
-          title: "视频上传失败,请稍后重试",
-          icon: "none",
-          duration: 2e3
-        });
         this.uploadQueue.shift();
         this.processUploadQueue();
       }
@@ -1756,14 +1713,16 @@ const _sfc_main = {
           success: async (res) => {
             try {
               if (res.data.code === 200 || res.data.code === 2e3) {
+                if (res.data.data && res.data.data.transcription_status === "pending") {
+                  console.log("视频转写进行中,5秒后重试");
+                  setTimeout(() => {
+                    this.checkTranscriptionStatus(task, followUpRequestData);
+                  }, 5e3);
+                  return;
+                }
                 console.log("追问视频提交成功");
                 this.isFollowUpMode = false;
                 this.currentVideoIndex = this.mainQuestionIndex;
-                common_vendor.index.showToast({
-                  title: "回答已提交",
-                  icon: "success",
-                  duration: 1500
-                });
                 this.uploadQueue.shift();
                 this.processUploadQueue();
                 this.$nextTick(() => {
@@ -1785,6 +1744,7 @@ const _sfc_main = {
           },
           fail: (err) => {
             console.error("提交视频失败:", err);
+            this.handleSubmitFailure(task, "提交失败: " + err.errMsg);
           }
         });
       } else {
@@ -1807,11 +1767,6 @@ const _sfc_main = {
                 console.error("面试互动接口调用失败:", error);
                 this.proceedToNextQuestion();
               }
-              common_vendor.index.showToast({
-                title: "回答已提交",
-                icon: "success",
-                duration: 1500
-              });
               this.uploadQueue.shift();
               this.processUploadQueue();
             } else {
@@ -1837,15 +1792,75 @@ const _sfc_main = {
         }, 5e3);
       } else {
         console.log("超过最大重试次数,放弃提交");
-        common_vendor.index.showToast({
-          title: "视频提交失败,请稍后重试",
-          icon: "none",
-          duration: 2e3
-        });
         this.uploadQueue.shift();
         this.processUploadQueue();
       }
     },
+    // 添加检查转写状态的方法
+    checkTranscriptionStatus(task, requestData, retryCount = 0) {
+      const maxRetries = 24;
+      const retryInterval = 5e3;
+      if (retryCount >= maxRetries) {
+        console.log("转写超时,继续下一个问题");
+        this.isFollowUpMode = false;
+        this.currentVideoIndex = this.mainQuestionIndex;
+        this.uploadQueue.shift();
+        this.processUploadQueue();
+        return;
+      }
+      common_vendor.index.request({
+        url: `${common_config.apiBaseUrl}/voice_interview/check_transcription_status/`,
+        method: "POST",
+        data: {
+          application_id: requestData.application_id,
+          original_question_id: requestData.original_question_id,
+          video_url: requestData.video_url
+        },
+        header: {
+          "content-type": "application/x-www-form-urlencoded"
+        },
+        success: (res) => {
+          if (res.data.code === 200 || res.data.code === 2e3) {
+            if (res.data.data && res.data.data.status === "completed") {
+              console.log("视频转写完成");
+              this.isFollowUpMode = false;
+              this.currentVideoIndex = this.mainQuestionIndex;
+              this.uploadQueue.shift();
+              this.processUploadQueue();
+              this.$nextTick(() => {
+                if (this.currentVideoIndex < this.videoList.length) {
+                  this.videoUrl = this.videoList[this.currentVideoIndex];
+                  this.videoPlaying = true;
+                  const videoContext = common_vendor.index.createVideoContext("myVideo", this);
+                  if (videoContext) {
+                    videoContext.play();
+                  }
+                }
+              });
+            } else {
+              console.log(`转写进行中,${retryInterval / 1e3}秒后重试 (${retryCount + 1}/${maxRetries})`);
+              setTimeout(() => {
+                this.checkTranscriptionStatus(task, requestData, retryCount + 1);
+              }, retryInterval);
+            }
+          } else if (res.data.message === "面试视频尚未完成转写" || res.data.success === false) {
+            console.log(`转写未完成,${retryInterval / 1e3}秒后重试 (${retryCount + 1}/${maxRetries})`);
+            setTimeout(() => {
+              this.checkTranscriptionStatus(task, requestData, retryCount + 1);
+            }, retryInterval);
+          } else {
+            this.handleSubmitFailure(task, "检查转写状态失败: " + (res.data.msg || "未知错误"));
+          }
+        },
+        fail: (err) => {
+          console.error("检查转写状态失败:", err);
+          console.log(`网络请求失败,${retryInterval / 1e3}秒后重试 (${retryCount + 1}/${maxRetries})`);
+          setTimeout(() => {
+            this.checkTranscriptionStatus(task, requestData, retryCount + 1);
+          }, retryInterval);
+        }
+      });
+    },
     // 添加新方法:更新上传状态文本
     updateUploadStatusText() {
       if (this.uploadQueue.length === 0) {
@@ -1879,18 +1894,29 @@ const _sfc_main = {
     },
     // 修改 proceedToNextQuestion 方法,确保在切换视频时重置历史时间
     proceedToNextQuestion() {
+      if (this.isVideoSwitching) {
+        console.log("正在切换视频中,请等待...");
+        return;
+      }
       console.log("继续下一个问题");
+      this.isVideoSwitching = true;
+      const currentVideo = common_vendor.index.createVideoContext("myVideo", this);
+      if (currentVideo) {
+        currentVideo.stop();
+        this.videoPlaying = false;
+      }
       this.currentVideoIndex++;
       this.historyTime = 0;
       if (this.currentVideoIndex < this.videoList.length) {
         this.videoUrl = this.videoList[this.currentVideoIndex];
-        this.videoPlaying = true;
-        this.$nextTick(() => {
+        setTimeout(() => {
+          this.videoPlaying = true;
           const videoContext = common_vendor.index.createVideoContext("myVideo", this);
           if (videoContext) {
             videoContext.play();
           }
-        });
+          this.isVideoSwitching = false;
+        }, 100);
       } else {
         console.log("所有视频已播放完毕");
         this.stopUserCamera();
@@ -1900,6 +1926,7 @@ const _sfc_main = {
         const jobId = currentJobDetail ? currentJobDetail.id : null;
         console.log("当前职位ID:", jobId);
         setTimeout(() => {
+          this.isVideoSwitching = false;
           if (jobId === 9) {
             common_vendor.index.navigateTo({
               url: "/pages/interview-question/interview-question",
@@ -2542,7 +2569,8 @@ const _sfc_main = {
       this.showRerecordButton = false;
       this.videoUrl = this.lowScoreVideoUrl;
       this.videoPlaying = true;
-      const originalSubtitle = this.currentSubtitle;
+      const currentQuestion = this.getCurrentQuestionByIndex(this.currentVideoIndex);
+      const originalSubtitle = currentQuestion ? currentQuestion.digital_human_video_subtitle || currentQuestion.question : this.currentSubtitle;
       this.currentSubtitle = "";
       this.$nextTick(() => {
         const videoContext = common_vendor.index.createVideoContext("myVideo", this);
@@ -2558,16 +2586,10 @@ const _sfc_main = {
                 translation: "I didn't quite catch what you said, could you please repeat it?"
               }
             ];
-            setTimeout(() => {
-              if (this.isFollowUpQuestion && this.currentFollowUpQuestion) {
-                this.currentSubtitle = this.currentFollowUpQuestion.digital_human_video_subtitle || this.currentFollowUpQuestion.question;
-              } else {
-                this.currentSubtitle = originalSubtitle;
-              }
-            }, 3e3);
           }, 500);
         }
       });
+      this.originalQuestionSubtitle = originalSubtitle;
     },
     // 添加新方法:处理重新录制按钮点击
     handleRerecordButtonClick() {
@@ -2715,8 +2737,10 @@ const _sfc_main = {
         console.log("找到追问问题:", followUpQuestion);
         const recordingDuration = this.getRecordingDuration();
         const lowScoreDuration = 7;
+        const minDuration = 3;
         if (recordingDuration < lowScoreDuration) {
-          console.log(`录制时间 ${recordingDuration} 秒,少于 ${lowScoreDuration} 秒,将播放低分提示视频`);
+          let message = recordingDuration < minDuration ? `录制时间 ${recordingDuration} 秒,少于最小时长 ${minDuration} 秒` : `录制时间 ${recordingDuration} 秒,少于标准时长 ${lowScoreDuration} 秒`;
+          console.log(message + ",将播放低分提示视频");
           this.retryCount++;
           this.needPlayLowScoreVideo = true;
           this.playLowScoreVideo();
@@ -2821,32 +2845,54 @@ const _sfc_main = {
         clearInterval(this.personDetectionInterval);
       }
       this.personDetectionInterval = setInterval(() => {
-        if (this.personDetectionSocket && this.cameraContext) {
+        try {
+          if (!this.personDetectionSocket || !this.cameraContext) {
+            console.warn("人脸检测:相机上下文或WebSocket连接未就绪");
+            return;
+          }
           this.cameraContext.takePhoto({
             quality: "low",
             success: (res) => {
-              const tempFilePath = res.tempImagePath;
-              common_vendor.index.getFileSystemManager().readFile({
-                filePath: tempFilePath,
-                encoding: "base64",
-                success: (res2) => {
-                  const base64Image = res2.data;
-                  this.personDetectionSocket.send({
-                    data: JSON.stringify({
-                      type: "person_detection",
-                      image_data: base64Image
-                    })
-                  });
-                },
-                fail: (error) => {
-                  console.error("Error reading image file:", error);
+              try {
+                const tempFilePath = res.tempImagePath;
+                if (!tempFilePath) {
+                  console.warn("人脸检测:未获取到有效的图片路径");
+                  return;
                 }
-              });
+                common_vendor.index.getFileSystemManager().readFile({
+                  filePath: tempFilePath,
+                  encoding: "base64",
+                  success: (res2) => {
+                    try {
+                      const base64Image = res2.data;
+                      if (!this.personDetectionSocket || this.personDetectionSocket.readyState !== 1) {
+                        console.warn("人脸检测:WebSocket连接已断开或未就绪");
+                        return;
+                      }
+                      this.personDetectionSocket.send({
+                        data: JSON.stringify({
+                          type: "person_detection",
+                          image_data: base64Image
+                        })
+                      });
+                    } catch (wsError) {
+                      console.error("人脸检测:发送WebSocket数据时出错:", wsError);
+                    }
+                  },
+                  fail: (error) => {
+                    console.error("人脸检测:读取图片文件失败:", error);
+                  }
+                });
+              } catch (fileError) {
+                console.error("人脸检测:处理图片文件时出错:", fileError);
+              }
             },
             fail: (error) => {
-              console.error("Error taking photo:", error);
+              console.error("人脸检测:拍照失败:", error);
             }
           });
+        } catch (mainError) {
+          console.error("人脸检测:主流程执行出错:", mainError);
         }
       }, 3e3);
     },
@@ -2963,11 +3009,6 @@ const _sfc_main = {
             console.log("音频可以播放");
             common_vendor.index.hideLoading();
             this.isAudioPlaying = true;
-            common_vendor.index.showToast({
-              title: "正在播放追问",
-              icon: "none",
-              duration: 2e3
-            });
           });
           innerAudioContext.onEnded(() => {
             console.log("追问音频播放完成");

+ 11 - 3
unpackage/dist/dev/mp-weixin/pages/index/index.js

@@ -164,11 +164,18 @@ const _sfc_main = {
       });
       api_user.getJobList().then((res) => {
         common_vendor.index.hideLoading();
-        console.log(res);
-        this.jobList = res;
+        console.log("职位列表数据:", res);
+        this.jobList = Array.isArray(res) ? res.filter((job) => job !== null && job !== void 0) : [];
+        if (this.jobList.length === 0) {
+          common_vendor.index.showToast({
+            title: "暂无可用职位",
+            icon: "none"
+          });
+        }
       }).catch((err) => {
         common_vendor.index.hideLoading();
         console.error("获取职位列表失败:", err);
+        this.jobList = [];
         common_vendor.index.showToast({
           title: "网络错误,请稍后重试",
           icon: "none"
@@ -481,7 +488,8 @@ function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
         c: common_vendor.t($options.formatLocation(job.location)),
         d: index,
         e: $data.selectedJobId === job.id ? 1 : "",
-        f: common_vendor.o(($event) => $options.selectJob(job), index)
+        f: job.status == 1,
+        g: common_vendor.o(($event) => $options.selectJob(job), index)
       };
     }),
     b: !$data.selectedJobId,

+ 1 - 1
unpackage/dist/dev/mp-weixin/pages/index/index.wxml

@@ -1 +1 @@
-<view class="interview-container"><view class="job-list-container"><view class="job-list-title">可选职位列表</view><view class="job-list"><view wx:for="{{a}}" wx:for-item="job" wx:key="d" class="{{['job-item', job.e && 'job-selected']}}" bindtap="{{job.f}}"><view class="job-name">{{job.a}}</view><view class="job-actions"><button class="detail-btn" catchtap="{{job.b}}">查看详情</button></view><view class="job-details"><text class="job-salary"></text><text class="job-location">{{job.c}}</text></view></view></view><button class="apply-btn" disabled="{{b}}" bindtap="{{c}}">申请面试</button></view></view>
+<view class="interview-container"><view class="job-list-container"><view class="job-list-title">可选职位列表</view><view class="job-list"><view wx:for="{{a}}" wx:for-item="job" wx:key="d" class="{{['job-item', job.e && 'job-selected']}}" hidden="{{!job.f}}" bindtap="{{job.g}}"><view class="job-name">{{job.a}}</view><view class="job-actions"><button class="detail-btn" catchtap="{{job.b}}">查看详情</button></view><view class="job-details"><text class="job-salary"></text><text class="job-location">{{job.c}}</text></view></view></view><button class="apply-btn" disabled="{{b}}" bindtap="{{c}}">申请面试</button></view></view>

+ 12 - 98
unpackage/dist/dev/mp-weixin/pages/interview-question/interview-question.js

@@ -435,7 +435,12 @@ const _sfc_main = {
     },
     // 播放数字人视频
     playDigitalHumanVideo() {
-      this.videoUrl = this.videoList[this.currentVideoIndex];
+      var _a;
+      if (JSON.parse(common_vendor.index.getStorageSync("configData")) == null) {
+        this.videoUrl = this.videoList[this.currentVideoIndex];
+      } else {
+        this.videoUrl = ((_a = JSON.parse(common_vendor.index.getStorageSync("configData")).digital_human) == null ? void 0 : _a.ending_video_url) || this.videoList[this.currentVideoIndex];
+      }
       this.videoPlaying = true;
       console.log(`播放视频 ${this.currentVideoIndex + 1}/${this.videoList.length}: ${this.videoUrl}`);
       this.$nextTick(() => {
@@ -1928,14 +1933,18 @@ const _sfc_main = {
       });
       const tenant_id = common_vendor.index.getStorageSync("tenant_id") || "1";
       const application_id = common_vendor.index.getStorageSync("appId") || "98";
+      let positionConfigId = 1;
+      if (JSON.parse(common_vendor.index.getStorageSync("configData"))) {
+        positionConfigId = JSON.parse(common_vendor.index.getStorageSync("configData")).id;
+      }
       const requestData = {
         voice_url: videoUrl,
         tenant_id,
         application_id,
         scene_type: "interview",
         // 场景类型:面试
-        voice_type: "longxiaoxia",
-        // 角色:龙小侠
+        // voice_type: 'longxiaoxia', // 角色:龙小侠
+        position_config_id: positionConfigId,
         conversation_history: this.conversationHistory
         // 添加对话历史
       };
@@ -2175,11 +2184,6 @@ const _sfc_main = {
         audioContext.onPlay(() => {
           console.log("iOS小程序音频开始播放");
           this.currentSubtitle = this.aiText;
-          common_vendor.index.showToast({
-            title: "正在播放AI回复",
-            icon: "none",
-            duration: 1500
-          });
         });
         audioContext.onEnded(() => {
           console.log("iOS小程序音频播放结束");
@@ -2274,11 +2278,6 @@ const _sfc_main = {
           console.error("销毁超时音频播放器失败:", e);
         }
       }
-      common_vendor.index.showToast({
-        title: "音频加载超时,显示文字",
-        icon: "none",
-        duration: 2e3
-      });
       this.useIOSTextFallback();
     },
     // 新增方法:iOS小程序备选播放方法
@@ -2324,11 +2323,6 @@ const _sfc_main = {
       this.isPlayingAiVoice = false;
       if (!this.hasShownTextFallbackToast) {
         this.hasShownTextFallbackToast = true;
-        common_vendor.index.showToast({
-          title: "为您显示文字回复",
-          icon: "none",
-          duration: 2e3
-        });
       }
       this.currentSubtitle = this.aiText || "抱歉,AI回复内容加载失败";
       const textLength = this.aiText ? this.aiText.length : 20;
@@ -2451,11 +2445,6 @@ const _sfc_main = {
         audioContext.obeyMuteSwitch = false;
         audioContext.onPlay(() => {
           console.log("AI语音开始播放");
-          common_vendor.index.showToast({
-            title: "正在播放AI回复",
-            icon: "none",
-            duration: 2e3
-          });
         });
         audioContext.onEnded(() => {
           console.log("AI语音播放结束");
@@ -2485,11 +2474,6 @@ const _sfc_main = {
       } catch (e) {
         console.error("小程序播放AI语音时发生错误:", e);
         this.isPlayingAiVoice = false;
-        common_vendor.index.showToast({
-          title: "音频播放失败,请查看文字回复",
-          icon: "none",
-          duration: 2e3
-        });
         this.handleAudioPlaybackFailure();
       }
     },
@@ -2506,25 +2490,10 @@ const _sfc_main = {
           console.error("iOS小程序音频播放错误:", err);
           if (err.errMsg && err.errMsg.includes("-11850")) {
             console.log("iOS小程序检测到系统音频错误(-11850)");
-            common_vendor.index.showToast({
-              title: "系统音频暂停,显示文字",
-              icon: "none",
-              duration: 2e3
-            });
           } else if (err.errCode === 10002) {
             console.log("iOS小程序检测到errCode:10002,网络或资源问题");
-            common_vendor.index.showToast({
-              title: "音频加载中断,显示文字",
-              icon: "none",
-              duration: 2e3
-            });
           } else {
             console.log("iOS小程序其他音频错误:", err.errCode);
-            common_vendor.index.showToast({
-              title: "音频播放异常,显示文字",
-              icon: "none",
-              duration: 2e3
-            });
           }
           this.useIOSMiniProgramTextFallback(audioContext);
         });
@@ -2532,11 +2501,6 @@ const _sfc_main = {
         audioContext.onPlay(() => {
           console.log("iOS小程序音频开始播放");
           this.currentSubtitle = this.aiText;
-          common_vendor.index.showToast({
-            title: "正在播放AI回复",
-            icon: "none",
-            duration: 1500
-          });
         });
         audioContext.onEnded(() => {
           console.log("iOS小程序音频播放结束");
@@ -2646,11 +2610,6 @@ const _sfc_main = {
               this.currentSubtitle = "";
               newAudioPlayer.destroy();
               this.aiAudioPlayer = null;
-              common_vendor.index.showToast({
-                title: "无法播放音频,请查看文字回复",
-                icon: "none",
-                duration: 2e3
-              });
               this.showContinueQuestionOptions();
               this.checkPendingNavigation();
             });
@@ -2668,11 +2627,6 @@ const _sfc_main = {
     // 添加新方法:处理音频播放失败的情况
     handleAudioPlaybackFailure() {
       this.isPlayingAiVoice = false;
-      common_vendor.index.showToast({
-        title: "无法播放音频,将直接显示文字回复",
-        icon: "none",
-        duration: 2e3
-      });
       this.currentSubtitle = this.aiText;
       setTimeout(() => {
         this.currentSubtitle = "";
@@ -2772,11 +2726,6 @@ const _sfc_main = {
       this.showEndInterviewButton = false;
       if (!this.aiVoiceUrl || this.aiVoiceUrl.trim() === "") {
         console.error("无效的音频URL");
-        common_vendor.index.showToast({
-          title: "音频加载失败",
-          icon: "none",
-          duration: 2e3
-        });
         this.isPlayingAiVoice = false;
         this.showContinueQuestionOptions();
         return;
@@ -2787,11 +2736,6 @@ const _sfc_main = {
         audioContext.obeyMuteSwitch = false;
         audioContext.onPlay(() => {
           console.log("AI语音开始播放");
-          common_vendor.index.showToast({
-            title: "正在播放AI回复",
-            icon: "none",
-            duration: 2e3
-          });
         });
         audioContext.onEnded(() => {
           console.log("AI语音播放结束");
@@ -2821,11 +2765,6 @@ const _sfc_main = {
       } catch (e) {
         console.error("小程序播放AI语音时发生错误:", e);
         this.isPlayingAiVoice = false;
-        common_vendor.index.showToast({
-          title: "音频播放失败,请查看文字回复",
-          icon: "none",
-          duration: 2e3
-        });
         this.handleAudioPlaybackFailure();
       }
     },
@@ -2874,11 +2813,6 @@ const _sfc_main = {
       console.log("尝试使用系统播放器播放音频");
       const systemInfo = common_vendor.index.getSystemInfoSync();
       if (systemInfo.platform === "android" || systemInfo.platform === "ios") {
-        common_vendor.index.showToast({
-          title: "正在使用系统播放器",
-          icon: "none",
-          duration: 2e3
-        });
         if (typeof common_vendor.index.playVoice === "function") {
           common_vendor.index.playVoice({
             filePath: this.aiVoiceUrl,
@@ -2941,11 +2875,6 @@ const _sfc_main = {
     // 修复 handleContinueQuestionClick 方法,确保状态正确重置
     handleContinueQuestionClick() {
       if (this.isPlayingAiVoice) {
-        common_vendor.index.showToast({
-          title: "请等待面试官回复完成",
-          icon: "none",
-          duration: 2e3
-        });
         return;
       }
       this.showContinueQuestionButton = false;
@@ -2979,11 +2908,6 @@ const _sfc_main = {
     // 添加新方法:处理录制错误
     handleRecordingError(error) {
       console.error("录制错误:", error);
-      common_vendor.index.showToast({
-        title: "录制失败,请重试",
-        icon: "none",
-        duration: 2e3
-      });
       this.isRecording = false;
       this.showStopRecordingButton = false;
       this.showStartRecordingButton = true;
@@ -2991,11 +2915,6 @@ const _sfc_main = {
     // 添加新方法:处理上传错误
     handleUploadError(error) {
       console.error("上传错误:", error);
-      common_vendor.index.showToast({
-        title: "上传失败,请重试",
-        icon: "none",
-        duration: 2e3
-      });
       this.showRetryButton = true;
       this.showUploadStatus = false;
       this.isUploading = false;
@@ -3050,11 +2969,6 @@ const _sfc_main = {
       this.isPlayingAiVoice = false;
       if (!this.hasShownTextFallbackToast) {
         this.hasShownTextFallbackToast = true;
-        common_vendor.index.showToast({
-          title: "已切换为文字显示",
-          icon: "none",
-          duration: 2e3
-        });
       }
       this.currentSubtitle = this.aiText || "抱歉,无法获取AI回复内容";
       const textLength = this.aiText ? this.aiText.length : 20;

+ 0 - 6
unpackage/dist/dev/mp-weixin/pages/my/my.js

@@ -526,12 +526,6 @@ const _sfc_main = {
           common_vendor.index.removeStorageSync("token");
           common_vendor.index.removeStorageSync("userInfo");
           this.isLogin = false;
-          if (showConfirm) {
-            common_vendor.index.showToast({
-              title: err.message || "退出登录失败",
-              icon: "none"
-            });
-          }
         });
       };
       if (showConfirm) {

+ 1 - 1
unpackage/dist/dev/mp-weixin/pages/preview/preview.wxml

@@ -1 +1 @@
-<view class="preview-container"><view class="title"><text>下面我们将拍摄证件照片</text></view><view class="guide-text"><text>请您在白色的背景前拍照</text></view><view class="guide-image"><image src="http://data.qicai321.com/minlong/ee86c2e0-6e18-49b8-a001-bba3af8995d4.jpg" mode="aspectFit"></image></view><view class="requirements-list"><view class="requirement-item"><text>· 请摘掉耳饰、发饰、项链等影响拍摄效果的饰品</text></view><view class="requirement-item"><text>· 请勿化妆、头发不要遮挡耳朵、眉毛</text></view><view class="requirement-item"><text>· 拍照时,请您露出锁骨或衣领</text></view><view class="requirement-item"><text>· 在光线充足的环境下拍摄</text></view></view><view class="action-button"><button bindtap="{{a}}">准备好了</button></view></view>
+<view class="preview-container"><view class="title"><text>下面我们将拍摄证件照片</text></view><view class="guide-text"><text>请您在白色的背景前拍照</text></view><view class="guide-image"><image src="https://data.qicai321.com/minlong/a7f24c02-ca46-47c9-9423-8523d551cda5.jpg" mode="aspectFit"></image></view><view class="requirements-list"><view class="requirement-item"><text>· 请摘掉耳饰、发饰、项链等影响拍摄效果的饰品</text></view><view class="requirement-item"><text>· 请勿化妆、头发不要遮挡耳朵、眉毛</text></view><view class="requirement-item"><text>· 拍照时,请您露出锁骨或衣领</text></view><view class="requirement-item"><text>· 在光线充足的环境下拍摄</text></view></view><view class="action-button"><button bindtap="{{a}}">准备好了</button></view></view>

+ 1 - 1
unpackage/dist/dev/mp-weixin/project.config.json

@@ -8,7 +8,7 @@
     "urlCheck": false,
     "es6": true,
     "postcss": false,
-    "minified": true,
+    "minified": false,
     "newFeature": true,
     "bigPackageSizeSupport": true,
     "babelSetting": {

+ 7 - 0
unpackage/dist/dev/mp-weixin/project.private.config.json

@@ -7,6 +7,13 @@
   "condition": {
     "miniprogram": {
       "list": [
+        {
+          "name": "pages/preview/preview",
+          "pathName": "pages/preview/preview",
+          "query": "",
+          "launchMode": "default",
+          "scene": null
+        },
         {
           "name": "pages/uploadResume/uploadResume",
           "pathName": "pages/uploadResume/uploadResume",

+ 1 - 1
unpackage/dist/dev/mp-weixin/utils/errorHandler.js

@@ -3,7 +3,7 @@ const common_vendor = require("../common/vendor.js");
 const ERROR_CODE_MAP = {
   401: "登录已过期,请重新登录",
   403: "没有权限执行此操作",
-  404: "请求的资源不存在",
+  // 404: '请求的资源不存在',
   500: "服务器错误,请稍后重试",
   502: "网关错误",
   503: "服务不可用,请稍后重试",

+ 1 - 1
utils/errorHandler.js

@@ -6,7 +6,7 @@
 const ERROR_CODE_MAP = {
   401: '登录已过期,请重新登录',
   403: '没有权限执行此操作',
-  404: '请求的资源不存在',
+  // 404: '请求的资源不存在',
   500: '服务器错误,请稍后重试',
   502: '网关错误',
   503: '服务不可用,请稍后重试',

+ 1 - 1
utils/request.js

@@ -80,7 +80,7 @@ const ERROR_CODE_MAP = {
   400: '请求参数错误',
   401: '登录已过期,请重新登录',
   403: '没有权限执行此操作',
-  404: '请求的资源不存在',
+  // 404: '请求的资源不存在',
   500: '服务器错误,请稍后重试',
   502: '网关错误',
   503: '服务不可用,请稍后重试',

Some files were not shown because too many files changed in this diff