yangg 2 mēneši atpakaļ
vecāks
revīzija
095c2f1a75

+ 2 - 1
api/user.js

@@ -27,6 +27,7 @@ export function wxLogin(loginParams) {
     rawData: loginParams.rawData || '',
     encryptedData: loginParams.encryptedData || '',
     iv: loginParams.iv || '',
+    tenant_id: 1,
     _csrf: csrfToken // 添加 CSRF token
   };
   
@@ -106,7 +107,7 @@ export const getJobList = (params = {}) => {
   // 合并默认参数和传入参数
   const queryParams = { ...defaultParams, ...params };
   
-  return http.get('/api/job/list', defaultParams);
+  return http.get('/api/system/job/list', defaultParams);
 };
 
 /* 填写用户信息 */

+ 2 - 1
common/config.js

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

+ 4 - 1
pages/Personal/Personal.vue

@@ -1278,8 +1278,11 @@ import { apiBaseUrl } from '@/common/config.js';
 							// 	scrollTop: 0,
 							// 	duration: 300
 							// });
-							uni.switchTab({
+							/* uni.switchTab({
 								url: '/pages/index/index'
+							}); */
+							uni.navigateTo({
+								url: '/pages/interview-notice/interview-notice'
 							});
 						} else {
 							// 验证失败,显示错误信息

+ 15 - 1
pages/index/index.vue

@@ -291,8 +291,22 @@ import { apiBaseUrl } from '@/common/config.js';
 					});
 			},
 			selectJob(job) {
+				// 清除之前的问题缓存
+				try {
+					uni.removeStorageSync('interviewQuestions');
+					uni.removeStorageSync('currentQuestionIndex');
+				} catch (e) {
+					console.error('清除问题缓存失败:', e);
+				}
+				
+				// 更新选中的职位
 				this.selectedJobId = job.id;
 				this.selectedJob = job;
+				
+				// 立即更新本地存储中的职位信息
+				uni.setStorageSync('selectedJob', JSON.stringify(job));
+				
+				console.log('已选择职位:', job.id, job.title);
 			},
 			applyForJob() {
 				if (!this.checkLogin()) {
@@ -330,7 +344,7 @@ import { apiBaseUrl } from '@/common/config.js';
 					}
 					
 					uni.navigateTo({
-						url: '/pages/interview-notice/interview-notice',
+						url: '/pages/Personal/Personal',
 						fail: (err) => {
 							console.error('页面跳转失败:', err);
 							uni.showToast({

+ 235 - 25
pages/interview-question/interview-question.vue

@@ -263,6 +263,13 @@ export default {
       countdownTimer: null,
       showGif: false, // 控制是否显示GIF
       gifUrl: '', // GIF图片的URL
+      
+      // 添加AI语音交互相关属性
+      aiVoiceUrl: '', // AI语音URL
+      aiText: '', // AI回复文本
+      transcribedText: '', // 转写文本
+      isPlayingAiVoice: false, // 是否正在播放AI语音
+      aiAudioPlayer: null, // AI语音播放器
     }
   },
   onLoad(options) {
@@ -305,6 +312,12 @@ export default {
   beforeDestroy() {
     // 组件销毁前停止摄像头
     this.stopUserCamera();
+    
+    // 销毁AI音频播放器
+    if (this.aiAudioPlayer) {
+      this.aiAudioPlayer.destroy();
+      this.aiAudioPlayer = null;
+    }
   },
   methods: {
     // 初始化相机
@@ -1909,7 +1922,7 @@ export default {
         tenant_id: uni.getStorageSync('tenant_id') || '1'
       };
       
-      // 发送请求到面试接口
+      // 首先提交到面试接口
       uni.request({
         url: `${apiBaseUrl}/api/job/upload_video`,
         method: 'POST',
@@ -1926,13 +1939,6 @@ export default {
               // 从队列中移除当前任务
               this.uploadQueue.shift();
               
-              // 显示简短的成功提示
-              // uni.showToast({
-              //   title: '视频提交成功',
-              //   icon: 'success',
-              //   duration: 1500
-              // });
-              
               // 继续处理队列中的下一个任务
               this.processUploadQueue();
             } else {
@@ -1949,6 +1955,9 @@ export default {
               this.showRetryButton = false;
               this.lastVideoToRetry = null;
             }
+            
+            // 提交到AI语音交互接口
+            this.submitToAiVoiceInteraction(videoUrl);
           } else {
             // 提交失败
             if (task) {
@@ -2066,6 +2075,12 @@ export default {
     proceedToNextQuestion() {
       console.log('准备跳转到下一页面');
       
+      // 如果正在播放AI语音,不立即跳转
+      if (this.isPlayingAiVoice) {
+        console.log('AI语音正在播放,等待播放完成后再跳转');
+        return;
+      }
+      
       // 不再等待上传队列完成,直接跳转
       this.navigateToNextPage();
       
@@ -2073,16 +2088,6 @@ export default {
       if (this.uploadQueue.length > 0) {
         console.log('上传队列将在后台继续处理...');
         
-        // // 重置GIF状态
-        // this.showGif = false;
-        // this.gifUrl = '';
-        // 显示简短的提示
-        // uni.showToast({
-        //   title: '视频将在后台上传',
-        //   icon: 'none',
-        //   duration: 2000
-        // });
-        
         // 保存上传状态到本地存储,以便在其他页面可以查看
         this.saveUploadStatus();
       }
@@ -2090,6 +2095,14 @@ export default {
     
     // 修改 navigateToNextPage 方法
     navigateToNextPage() {
+      console.log('准备导航到下一个页面');
+      
+      // 如果正在播放AI语音,不立即跳转
+      if (this.isPlayingAiVoice) {
+        console.log('AI语音正在播放,等待播放完成后再跳转');
+        return;
+      }
+      
       console.log('导航到下一个页面');
       
       // 移除延迟,直接跳转
@@ -2122,10 +2135,6 @@ export default {
       // 隐藏答题按钮
       this.showAnswerButton = false;
       
-      /* // 重置GIF状态
-      this.showGif = false;
-      this.gifUrl = ''; */
-      
       // 显示简短提示
       uni.showToast({
         title: '面试完成',
@@ -2133,10 +2142,13 @@ export default {
         duration: 500 // 只显示0.5秒
       });
       
-      // 短暂延迟后跳转
-      setTimeout(() => {
+      // 如果有最后上传的视频URL,提交到AI语音交互接口
+      if (this.lastUploadedVideoUrl) {
+        this.submitToAiVoiceInteraction(this.lastUploadedVideoUrl);
+      } else {
+        // 没有视频URL,直接跳转
         this.navigateToNextPage();
-      }, 500); // 0.5秒后跳转
+      }
     },
 
     // 处理相机错误
@@ -2626,6 +2638,204 @@ export default {
         console.error('保存上传状态失败:', e);
       }
     },
+
+    // 修改 submitToAiVoiceInteraction 方法,使用 FormData 提交
+    submitToAiVoiceInteraction(videoUrl) {
+      console.log('提交视频到AI语音交互接口:', videoUrl);
+      
+      // 显示加载提示
+      uni.showLoading({
+        title: 'AI正在思考...',
+        mask: true
+      });
+      
+      // 获取用户信息和租户ID
+      const tenant_id = uni.getStorageSync('tenant_id') || '1';
+      const userInfo = uni.getStorageSync('userInfo');
+      const openid = userInfo ? (JSON.parse(userInfo).openid || '') : '';
+      
+      // 检查环境
+      const systemInfo = uni.getSystemInfoSync();
+      const isMiniProgram = systemInfo.uniPlatform && systemInfo.uniPlatform.startsWith('mp-');
+      
+      if (isMiniProgram) {
+        // 小程序环境使用 uni.request
+        uni.request({
+          url: `${apiBaseUrl}/api/voice_ai_interaction`,
+          method: 'POST',
+          data: {
+            url: videoUrl,
+            tenant_id: tenant_id,
+            openid: openid,
+            application_id: uni.getStorageSync('appId') || ''
+          },
+          header: {
+            'content-type': 'application/json'
+          },
+          success: (res) => {
+            this.handleAiInteractionResponse(res.data);
+          },
+          fail: (err) => {
+            this.handleAiInteractionError(err);
+          }
+        });
+      } else {
+        // H5/App环境使用 FormData 和 XMLHttpRequest
+        const formData = new FormData();
+        formData.append('url', videoUrl);
+        formData.append('tenant_id', tenant_id);
+        formData.append('openid', openid);
+        formData.append('application_id', uni.getStorageSync('appId') || '');
+        
+        const xhr = new XMLHttpRequest();
+        xhr.open('POST', `${apiBaseUrl}/api/voice_ai_interaction`, true);
+        xhr.timeout = 60000; // 60秒超时
+        
+        xhr.onload = () => {
+          if (xhr.status === 200) {
+            try {
+              const response = JSON.parse(xhr.responseText);
+              this.handleAiInteractionResponse(response);
+            } catch (e) {
+              console.error('解析AI响应失败:', e);
+              this.handleAiInteractionError({ errMsg: '解析响应失败' });
+            }
+          } else {
+            this.handleAiInteractionError({ errMsg: 'HTTP状态: ' + xhr.status });
+          }
+        };
+        
+        xhr.onerror = () => {
+          this.handleAiInteractionError({ errMsg: '网络错误' });
+        };
+        
+        xhr.ontimeout = () => {
+          this.handleAiInteractionError({ errMsg: '请求超时' });
+        };
+        
+        xhr.send(formData);
+      }
+    },
+
+    // 添加处理AI交互响应的方法
+    handleAiInteractionResponse(data) {
+      console.log('AI语音交互接口响应:', data);
+      
+      // 隐藏加载提示
+      uni.hideLoading();
+      
+      if (data && data.success) {
+        // 保存AI回复数据
+        this.aiText = data.ai_text || '';
+        this.transcribedText = data.transcribed_text ? data.transcribed_text.text : '';
+        
+        // 获取AI语音URL
+        const aiVoiceUrl = data.ai_voice_url || '';
+        if (aiVoiceUrl) {
+          // 构建完整的URL
+          this.aiVoiceUrl = aiVoiceUrl.startsWith('http') 
+            ? aiVoiceUrl 
+            : `${apiBaseUrl}${aiVoiceUrl}`;
+          
+          console.log('AI语音URL:', this.aiVoiceUrl);
+          
+          // 显示AI回复文本作为字幕
+          this.currentSubtitle = this.aiText;
+          
+          // 播放AI语音
+          this.playAiVoice();
+        } else {
+          console.warn('未获取到AI语音URL');
+          // 如果没有语音URL,直接跳转
+          this.navigateToNextPage();
+        }
+      } else {
+        console.error('AI语音交互失败:', data);
+        // AI交互失败,直接跳转
+        this.navigateToNextPage();
+      }
+    },
+
+    // 添加处理AI交互错误的方法
+    handleAiInteractionError(err) {
+      console.error('AI语音交互请求失败:', err);
+      uni.hideLoading();
+      
+      // 显示错误提示
+      uni.showToast({
+        title: 'AI处理失败,请稍后再试',
+        icon: 'none',
+        duration: 2000
+      });
+      
+      // 请求失败,直接跳转
+      this.navigateToNextPage();
+    },
+
+    // 添加新方法:播放AI语音
+    playAiVoice() {
+      console.log('开始播放AI语音:', this.aiVoiceUrl);
+      
+      // 标记正在播放AI语音
+      this.isPlayingAiVoice = true;
+      
+      // 创建音频播放器
+      this.aiAudioPlayer = uni.createInnerAudioContext();
+      this.aiAudioPlayer.src = this.aiVoiceUrl;
+      this.aiAudioPlayer.autoplay = true;
+      
+      // 监听播放开始事件
+      this.aiAudioPlayer.onPlay(() => {
+        console.log('AI语音开始播放');
+        
+        // 显示正在播放提示
+        uni.showToast({
+          title: '正在播放AI回复',
+          icon: 'none',
+          duration: 2000
+        });
+      });
+      
+      // 监听播放结束事件
+      this.aiAudioPlayer.onEnded(() => {
+        console.log('AI语音播放结束');
+        
+        // 标记播放结束
+        this.isPlayingAiVoice = false;
+        
+        // 清空字幕
+        this.currentSubtitle = '';
+        
+        // 销毁音频播放器
+        if (this.aiAudioPlayer) {
+          this.aiAudioPlayer.destroy();
+          this.aiAudioPlayer = null;
+        }
+        
+        // 播放结束后跳转到下一页
+        this.navigateToNextPage();
+      });
+      
+      // 监听播放错误事件
+      this.aiAudioPlayer.onError((err) => {
+        console.error('AI语音播放错误:', err);
+        
+        // 标记播放结束
+        this.isPlayingAiVoice = false;
+        
+        // 清空字幕
+        this.currentSubtitle = '';
+        
+        // 销毁音频播放器
+        if (this.aiAudioPlayer) {
+          this.aiAudioPlayer.destroy();
+          this.aiAudioPlayer = null;
+        }
+        
+        // 播放错误时也跳转到下一页
+        this.navigateToNextPage();
+      });
+    },
   }
 }
 </script>

+ 3 - 3
pages/interview/interview.vue

@@ -422,11 +422,11 @@ import { apiBaseUrl } from '@/common/config.js'; // Import the base URL from a c
 							success: () => {
 								// 延迟跳转,让用户看到成功提示
 								setTimeout(() => {
-									// 返回首页
-									uni.navigateTo({
+									// 使用redirectTo替代navigateTo,避免页面栈溢出
+									uni.redirectTo({
 										url: '/pages/interview_success/interview_success'
 									});
-								}, 2000);
+								}, 100);
 							}
 						});
 					}, 500);

+ 14 - 9
pages/login/login.vue

@@ -91,6 +91,7 @@ export default {
           const loginParams = {
             code: this.wxLoginCode,
             userInfo: profileRes.userInfo,
+            tenant_id: 1,
             signature: profileRes.signature,
             rawData: profileRes.rawData,
             encryptedData: profileRes.encryptedData,
@@ -110,8 +111,11 @@ export default {
               gender: 0,
               province: '',
               city: '',
-              country: ''
-            }
+              country: '',
+              tenant_id: 1
+            },
+            tenant_id: 1
+            
           });
         }
       });
@@ -160,7 +164,8 @@ export default {
         
         is_new_user: data.is_new_user || false,
         
-        loginTime: new Date().getTime()
+        loginTime: new Date().getTime(),
+        tenant_id: 1
       };
       
       console.log('构建的用户数据:', userData);
@@ -242,12 +247,12 @@ export default {
         icon: 'success',
         success: () => {
           setTimeout(() => {
-            // uni.switchTab({
-            //   url: '/pages/index/index'
-            // });
-			uni.navigateTo({
-				url:'/pages/Personal/Personal'
-			})
+            uni.switchTab({
+              url: '/pages/index/index'
+            });
+			// uni.navigateTo({
+			// 	url:'/pages/Personal/Personal'
+			// })
           }, 1500);
         }
       });