소스 검색

修改资料收集

yangg 2 달 전
부모
커밋
66d95be4c0
4개의 변경된 파일238개의 추가작업 그리고 43개의 파일을 삭제
  1. 11 3
      src/views/digitalHuman/list/api.ts
  2. 14 9
      src/views/digitalHuman/list/index.vue
  3. 8 1
      src/views/position/detail/api.ts
  4. 205 30
      src/views/position/detail/index.vue

+ 11 - 3
src/views/digitalHuman/list/api.ts

@@ -18,7 +18,7 @@ export function GetObj(id: InfoReq) {
 
 export function AddObj(obj: AddReq) {
 	return request({
-		url: apiPrefix,
+		url: '/api/system/digital_human/create/',
 		method: 'post',
 		data: {...obj,tenant_id:1},
 	});
@@ -26,8 +26,8 @@ export function AddObj(obj: AddReq) {
 
 export function UpdateObj(obj: EditReq) {
 	return request({
-		url: apiPrefix + obj.id + '/',
-		method: 'put',
+		url:"/api/system/digital_human/update/",// apiPrefix + obj.id + '/',
+		method: 'post',
 		data: {...obj,tenant_id:1},
 	});
 }
@@ -45,3 +45,11 @@ export function GetPermission() {
         method: 'get',
     });
 }
+
+/* 获取语音列表 */
+export function GetVoiceList() {
+    return request({
+        url: '/api/system/digital_human/voice_types',
+        method: 'get',
+    });
+}

+ 14 - 9
src/views/digitalHuman/list/index.vue

@@ -68,7 +68,7 @@
 						</el-tag>
 					</el-descriptions-item>
 					<el-descriptions-item label="语音ID">
-						{{ getVoiceName(formData.config.voice_id) }}
+						{{ getVoiceName(formData.config.voice_type) }}
 					</el-descriptions-item>
 					<el-descriptions-item label="风格">
 						{{ getStyleName(formData.config.style) }}
@@ -128,10 +128,9 @@
 						<el-switch v-model="formData.status" :active-value="1" :inactive-value="0"></el-switch>
 					</el-form-item>
 					
-					<el-form-item label="语音ID" prop="config.voice_id">
-						<el-select v-model="formData.config.voice_id" placeholder="请选择语音">
-							<el-option label="小明(高级)" value="xiaoming_voice_premium"></el-option>
-							<el-option label="小红" value="xiaohong_voice"></el-option>
+					<el-form-item label="语音ID" prop="config.voice_type">
+						<el-select v-model="formData.config.voice_type" placeholder="请选择语音">
+							<el-option v-for="(item,index) in voiceList" :key="index" :label="item.label" :value="item.value"></el-option>
 							<!-- 可以根据实际情况添加更多选项 -->
 						</el-select>
 					</el-form-item>
@@ -165,7 +164,7 @@
 import { onMounted, ref, reactive } from 'vue';
 import { useFs } from '@fast-crud/fast-crud';
 import { createCrudOptions } from './crud';
-import { GetPermission, AddObj, UpdateObj, DelObj } from './api';
+import { GetPermission, AddObj, UpdateObj, DelObj,GetVoiceList } from './api';
 import * as api from './api';  // Import the full api module
 import { handleColumnPermission } from '/@/utils/columnPermission';
 import { ElMessage, ElMessageBox } from 'element-plus';
@@ -186,7 +185,7 @@ const defaultFormData = {
 	status: 1,
 	template_video_url: '',
 	config: {
-		voice_id: 'xiaoming_voice_premium',
+		voice_type: '',
 		style: 'professional'
 	}
 };
@@ -306,7 +305,7 @@ const submitForm = async () => {
 		if (submitData.config && typeof submitData.config === 'object') {
 			// 确保 config 符合类型要求
 			const config = {
-				voice_id: submitData.config.voice_id || '',
+				voice_type: submitData.config.voice_type || '',
 				style: submitData.config.style || ''
 			};
 			// 将config转为字符串
@@ -360,7 +359,12 @@ const handleDelete = (row: any) => {
 const fetchData = () => {
 	crudExpose.doRefresh();
 };
-
+const voiceList = ref([]);
+/* 获取语音列表 */
+const getVoiceList = async () => {
+	const response = await GetVoiceList();
+	voiceList.value = response.data;
+};
 // 页面打开后获取列表数据
 onMounted(async () => {
 	// 设置列权限
@@ -377,6 +381,7 @@ onMounted(async () => {
 	resetCrudOptions(newOptions);
 	// 刷新
 	crudExpose.doRefresh();
+	getVoiceList();
 });
 
 // 获取对话框标题

+ 8 - 1
src/views/position/detail/api.ts

@@ -60,7 +60,14 @@ export function CreateConfig(data:any) {
 		data: {...data,tenant_id:1},
 	});
 }
-
+/* 更新配置 */
+export function UpdateConfig(data:any) {
+	return request({
+		url:`/api/system/job_config/detail/${data.id}`,
+		method: 'put',
+		data: {...data,tenant_id:1},
+	});
+}
 /* 获取当前配置 */
 export function GetConfig(id:any) {
 	return request({

+ 205 - 30
src/views/position/detail/index.vue

@@ -340,9 +340,9 @@
         <div v-for="(step, index) in recruitmentProcess" :key="step.id">
           <!-- 添加在每个步骤上方的加号按钮 -->
           <div class="add-process-btn-top" v-if="index === 0 || true">
-            <el-button type="text" @click="showStepOptions(index, $event)">
+           <!--  <el-button type="text" @click="showStepOptions(index, $event)">
               <el-icon><Plus /></el-icon>
-            </el-button>
+            </el-button> -->
           </div>
           
           <div 
@@ -379,9 +379,9 @@
         
         <!-- 最后一个步骤下方的加号按钮 -->
         <div class="add-process-btn">
-          <el-button type="text" @click="showStepOptions(recruitmentProcess.length, $event)">
+         <!--  <el-button type="text" @click="showStepOptions(recruitmentProcess.length, $event)">
             <el-icon><Plus /></el-icon>
-          </el-button>
+          </el-button> -->
         </div>
       </div>
       
@@ -650,7 +650,7 @@
                     :key="avatar.id"
                     class="avatar-item"
                     :class="{ active: selectedInterviewer.id === avatar.id }"
-                    @click="selectedInterviewer = avatar"
+                    @click="handleInterviewerSelect(avatar)"
                   >
                     <div class="avatar-wrapper">
                       <div class="avatar-circle" :class="{ selected: selectedInterviewer.id === avatar.id }">
@@ -673,22 +673,40 @@
             <div class="interview-settings">
               <div class="setting-item">
                 <div class="setting-label">「回答视频保留」</div>
-                <el-switch v-model="settings.keepVideo" />
+                <el-switch 
+                  v-model="settings.keepVideo" 
+                  @change="(value) => handleSettingChange('keepVideo', value)"
+                />
                 <div class="setting-desc">当候选人不符合中断条件时,保留其回答视频</div>
               </div>
 
               <div class="setting-item">
                 <div class="setting-label">「中断后作答限制」</div>
                 <div class="setting-options">
-                  <el-radio v-model="settings.interruptionMode" label="previous">从上一问重新作答</el-radio>
-                  <el-radio v-model="settings.interruptionMode" label="current">从当前问题作答</el-radio>
+                  <el-radio 
+                    v-model="settings.interruptionMode" 
+                    label="previous"
+                    @change="handleSettingChange('interruptionMode', settings.interruptionMode)"
+                  >
+                    从上一问重新作答
+                  </el-radio>
+                  <el-radio 
+                    v-model="settings.interruptionMode" 
+                    label="current"
+                    @change="handleSettingChange('interruptionMode', settings.interruptionMode)"
+                  >
+                    从当前问题作答
+                  </el-radio>
                 </div>
                 <div class="setting-desc"></div>
               </div>
 
               <div class="setting-item">
                 <div class="setting-label">「智慧追问」</div>
-                <el-switch v-model="settings.smartFollowUp" />
+                <el-switch 
+                  v-model="settings.smartFollowUp" 
+                  @change="(value) => handleSettingChange('smartFollowUp', value)"
+                />
                 <div class="setting-desc">当候选人给出特殊关键词时,系统将自动追问</div>
               </div>
             </div>
@@ -1038,7 +1056,7 @@
         <div class="field-config-panel">
           <div class="panel-header">
             <h3>字段显示配置</h3>
-            <el-button type="primary" size="small" @click="saveFieldConfig">保存配置</el-button>
+            <!-- <el-button type="primary" size="small" @click="saveFieldConfig">保存配置</el-button> -->
           </div>
           <div class="field-config-list">
             <!-- 基本信息部分 -->
@@ -1195,7 +1213,7 @@
       <template #footer>
         <span class="dialog-footer">
           <el-button @click="cancelDataCollection">取消</el-button>
-          <el-button type="primary" @click="confirmDataCollection">确认</el-button>
+          <el-button type="primary" @click="saveFieldConfig">确认</el-button><!-- confirmDataCollection -->
                   </span>
       </template>
     </el-dialog>
@@ -1427,7 +1445,7 @@ import { ElMessage, ElMessageBox, ElDrawer } from 'element-plus';
 import * as api from '../list/api';
 import { Plus, Document, ArrowDown, Edit, Delete, InfoFilled, QuestionFilled, Search, Rank } from '@element-plus/icons-vue';
 import { GetList } from '../../questionBank/classList/api';
-import { GetCompetencyList,GetQuestionList,GenerateQuestions,GetDraftList,SaveDraft,GetDigitalList,CreateConfig,GetConfig } from './api';
+import { GetCompetencyList,GetQuestionList,GenerateQuestions,GetDraftList,SaveDraft,GetDigitalList,CreateConfig,GetConfig,UpdateConfig } from './api';
 import draggable from 'vuedraggable';
 import { updateFieldConfig } from './utils';
 import type { ProfileFieldsConfig } from './types';
@@ -1915,9 +1933,13 @@ const addSelectedStepType = async (type: string, label: string) => {
   if (type === 'data_collection') {
     const response = await GetConfig(route.query.id);
     if (response && response.data) {
+      getConfigId.value=response.data.id;
       updateFieldConfig(fieldConfig, response.data.profile_fields_config as ProfileFieldsConfig);
       showDataCollectionDialog.value = true;
       showOptionsMenu.value = false;
+    }else{
+      showDataCollectionDialog.value = true;
+      showOptionsMenu.value = false;
     }
     return;
   }
@@ -1982,14 +2004,25 @@ const nextStep = async () => {
         await SaveDraft({
           draft_ids: chatQuestions.value.map((draft: any) => draft.id)
         });
-
-
-       
       } catch (error) {
         console.error('保存暂存题目失败:', error);
         ElMessage.error('保存暂存题目失败');
         return; // 如果保存失败,不进入下一步
       }
+    }
+    // 如果从第三步完成配置,验证面试设置
+    if (currentStep.value === 3) {
+      const validation = validateInterviewSettings();
+      if (!validation.isValid) {
+        validation.messages.forEach(message => {
+          ElMessage.warning(message);
+        });
+        return;
+      }
+      
+      // 打印完整的配置信息
+      const completeConfig = getCompleteInterviewConfig();
+      console.log('完整的面试配置:', completeConfig);
     }
      currentStep.value++; 
   } else {
@@ -2006,17 +2039,38 @@ const prevStep = () => {
 };
 
 // 完成配置
-const finishConfig = () => {
-  // 创建新的AI视频步骤
-  const newStep = {
-    id: Date.now(),
-    name: 'AI视频',
-    description: `已选择${selectedAbilities.value.length}项能力测评`,
-    active: true,
-    type: 'ai_video',
-    abilities: selectedAbilities.value.map(a => a.value)
+const finishConfig = async () => {
+  // 获取选中的面试官信息
+  const selectedInterviewerInfo = {
+    id: selectedInterviewer.value.id,
+    name: selectedInterviewer.value.name,
+    avatar_url: selectedInterviewer.value.avatar_url || selectedInterviewer.value.image
   };
   
+  // 获取面试设置选项
+  const interviewSettings = getInterviewSettings();
+  const response = await CreateConfig({
+    position_id:route.query.id,
+    digital_human_id:selectedInterviewer.value.id,
+  })
+  console.log(response);
+  console.log('保存时选中的面试官:', selectedInterviewerInfo);
+  console.log('保存时的面试设置:', interviewSettings);
+  
+      // 创建新的AI视频步骤
+    const newStep = {
+      id: Date.now(),
+      name: 'AI视频',
+      description: `已选择${selectedAbilities.value.length}项能力测评`,
+      active: true,
+      type: 'ai_video',
+      abilities: selectedAbilities.value.map(a => a.value),
+      // 添加面试官信息
+      interviewer: selectedInterviewerInfo,
+      // 添加面试设置信息
+      settings: interviewSettings
+    };
+  
   // 添加到流程中
   recruitmentProcess.splice(currentAddIndex.value, 0, newStep);
   
@@ -2759,20 +2813,25 @@ const saveCompetency = async () => {
 
 // 在setup中添加
 const currentEditingStep = ref<AIVideoStep | null>(null);
-
+/* 获取已配置ID */
+const getConfigId =ref(0)
 // 编辑AI视频
 const editAIVideo = async (step: AIVideoStep) => {
    // 添加资料收集类型的处理
    if (step.name === '资料收集') {
     const response = await GetConfig(route.query.id);
     if (response && response.data) {
+      getConfigId.value=response.data.id;
       updateFieldConfig(fieldConfig, response.data.profile_fields_config as ProfileFieldsConfig);
       showDataCollectionDialog.value = true;
       showOptionsMenu.value = false;
+    }else{
+      showDataCollectionDialog.value = true;
+      showOptionsMenu.value = false;
     }
     return;
   }
-  
+
   if (step.name === 'AI视频') {
     currentEditingStep.value = step;
     showAIVideoDialog.value = true;
@@ -2856,6 +2915,100 @@ const interviewerAvatars = ref([
 
 const selectedInterviewer = ref(interviewerAvatars.value[0]);
 
+// 添加面试官选择处理函数
+const handleInterviewerSelect = (avatar: any) => {
+  // 更新选中的面试官
+  selectedInterviewer.value = avatar;
+  
+  // 打印选中的面试官信息(调试用)
+  console.log('选中的面试官信息:', {
+    id: avatar.id,
+    name: avatar.name,
+    avatar_url: avatar.avatar_url || avatar.image
+  });
+  
+  // 可以在这里添加其他处理逻辑
+  // 比如:保存到后端、触发其他事件等
+  
+  // 提示用户
+  ElMessage.success(`已选择面试官:${avatar.name}`);
+};
+
+// 获取面试设置选项的函数
+const getInterviewSettings = () => {
+  const interviewSettings = {
+    // 回答视频保留设置
+    keepVideo: settings.keepVideo,
+    // 中断后作答限制模式
+    interruptionMode: settings.interruptionMode,
+    // 智慧追问设置
+    smartFollowUp: settings.smartFollowUp
+  };
+  
+  console.log('当前面试设置:', interviewSettings);
+  return interviewSettings;
+};
+
+// 处理面试设置变化的函数
+const handleSettingChange = (settingType: string, value: any) => {
+  console.log(`面试设置 ${settingType} 已更改为:`, value);
+  
+  // 根据不同的设置类型进行处理
+  switch (settingType) {
+    case 'keepVideo':
+      console.log('回答视频保留设置:', value ? '开启' : '关闭');
+      break;
+    case 'interruptionMode':
+      console.log('中断后作答限制模式:', value === 'previous' ? '从上一问重新作答' : '从当前问题作答');
+      break;
+    case 'smartFollowUp':
+      console.log('智慧追问设置:', value ? '开启' : '关闭');
+      break;
+  }
+  
+  // 可以在这里添加其他处理逻辑
+  // 比如:实时保存到后端、触发相关事件等
+};
+
+// 验证面试设置配置完整性
+const validateInterviewSettings = () => {
+  const currentSettings = getInterviewSettings();
+  
+  // 检查必要设置是否已配置
+  const validation = {
+    isValid: true,
+    messages: [] as string[]
+  };
+  
+  // 这里可以添加具体的验证逻辑
+  if (currentSettings.interruptionMode === '') {
+    validation.isValid = false;
+    validation.messages.push('请选择中断后作答限制模式');
+  }
+  
+  return validation;
+};
+
+// 获取完整的面试配置信息
+const getCompleteInterviewConfig = () => {
+  return {
+    // 面试官信息
+    interviewer: {
+      id: selectedInterviewer.value.id,
+      name: selectedInterviewer.value.name,
+      avatar_url: selectedInterviewer.value.avatar_url || selectedInterviewer.value.image
+    },
+    // 面试设置
+    settings: getInterviewSettings(),
+    // 选中的能力标签
+    abilities: selectedAbilities.value,
+    // 题目列表
+    questions: chatQuestions.value,
+    // 当前步骤
+    currentStep: currentStep.value
+  };
+};
+
 /* 获取数字人列表 */
 const getDigitalList = async () => {
   const response = await GetDigitalList({page:1,pageSize:1000});
@@ -3110,8 +3263,8 @@ const saveFieldConfig = async () => {
     // 构建配置数据
     const configData = {
       position_id: route.query.id, // 职位ID
-      config_name: "咖啡师配置", // 配置名称
-      digital_human_id: 4, // 数字人ID
+      /* config_name: "咖啡师配置", // 配置名称
+      digital_human_id: 4, // 数字人ID */
       
       // 简历上传配置
       require_resume_upload: true, // 是否要求上传简历
@@ -3206,10 +3359,32 @@ const saveFieldConfig = async () => {
       is_active: true,
       is_template: false
     };
+    if(getConfigId.value==0){
+    }else{
+      configData.id=getConfigId.value;
+    }
     
     // 调用后端 API
-    await CreateConfig(configData);
-    ElMessage.success('配置保存成功');
+    if(getConfigId.value==0){
+      const response = await CreateConfig(configData);
+       if(response.code==2000){
+      ElMessage.success('配置保存成功');
+      showDataCollectionDialog.value = false;
+      showOptionsMenu.value = false;  
+    }else{
+      ElMessage.error('配置保存失败');
+    }
+    }else{
+      const response = await UpdateConfig(configData);
+      if(response.code==2000){
+        ElMessage.success('配置保存成功');
+        showDataCollectionDialog.value = false;
+        showOptionsMenu.value = false;  
+      }else{
+        ElMessage.error('配置保存失败');
+      }
+    }
+   
   } catch (error) {
     console.error('保存配置失败:', error);
     ElMessage.error('配置保存失败');