yangg 5 dienas atpakaļ
vecāks
revīzija
1ed38018d9
3 mainītis faili ar 320 papildinājumiem un 17 dzēšanām
  1. 1 1
      .env.development
  2. 8 0
      src/views/position/detail/api.ts
  3. 311 16
      src/views/position/detail/index.vue

+ 1 - 1
.env.development

@@ -6,7 +6,7 @@ ENV = 'development'
 # 本地环境接口地址 121.36.251.245
 
 
-VITE_API_URL = 'https://backend.qicai321.com'
+VITE_API_URL = 'http://192.168.100.187:8083'
 # VITE_API_URL = 'https://backend.qicai321.com'
 VITE_API_WX_URL='https://api.weixin.qq.com/'
 VITE_API_URL_MINLONG='http://117.185.80.170:7861'

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

@@ -173,6 +173,14 @@ export function UpdateQuestion(obj: AddReq) {
 		data: {...obj,tenant_id:1},
 	});
 }
+/* 获取当前职位下的所有问题 */
+export function GetPositionQuestions(obj: AddReq) {
+	return request({
+		url: '/api/system/job/questions',
+		method: 'get',
+		params: {...obj,tenant_id:1},
+	});
+}
 
 export function GetcategoryList(query: UserPageQuery) {
 	return request({

+ 311 - 16
src/views/position/detail/index.vue

@@ -1139,11 +1139,10 @@
         <div class="form-item">
           <div class="form-label">胜任力标签</div>
           <el-select
-            v-model="questionForm.competency_tags"
+            v-model="competencyTagsValue"
             placeholder="请选择胜任力标签"
             class="full-width"
             multiple
-            @change="handleCompetencyTagsChange"
           >
             <el-option 
               v-for="tag in competencyTagOptions" 
@@ -1163,15 +1162,40 @@
             <div class="config-row">
               <span class="config-label">标签</span>
               <span class="config-label">权重</span>
+              <!-- <el-button 
+                type="text" 
+                size="small" 
+                @click="distributeWeightsEvenly"
+                style="color: #409eff; font-size: 12px;"
+              >
+                平均分配
+              </el-button> -->
              <!--  <span class="config-label">级别</span> -->
             </div>
-            <div class="config-row" v-for="tag in questionForm.competency_tags" :key="tag.id">
+            <div class="config-row" v-for="(tag, index) in questionForm.competency_tags" :key="tag.id">
               <span class="tag-name">{{ tag.name }}</span>
-              <el-input-number v-model="tag.weight" :min="0" :max="100" :step="1" controls-position="right" /> %
+              <el-input-number 
+                v-model="tag.weight" 
+                :min="0" 
+                :max="100" 
+                :step="1" 
+                controls-position="right"
+                @change="(value) => handleWeightChange(index, value)"
+              /> %
             <!--   <el-input-number v-model="tag.importance" :min="1" :max="5" :step="1" controls-position="right" /> -->
             </div>
           </div>
-          <div class="form-tip">配置各个胜任力标签的权重,总和需要100%</div>
+          <div class="form-tip">
+            配置各个胜任力标签的权重,总和需要100%
+            <span class="weight-sum" :class="{ 'weight-error': getTotalWeight() !== 100 }">
+              (当前总计: {{ getTotalWeight() }}%)
+            </span>
+            <br/>
+            <el-icon style="color: #409eff; margin-right: 4px; margin-top: 4px;"><InfoFilled /></el-icon>
+            <span style="color: #909399; font-size: 11px;">
+              修改任意权重时,其他权重会自动按比例调整以保持总和为100%。点击"平均分配"可快速平均分配所有权重。
+            </span>
+          </div>
         </div>
 
         <div class="form-item">
@@ -2220,8 +2244,9 @@ import { GetList } from '../../questionBank/classList/api';
 import { GetCompetencyList,GetQuestionList,GenerateQuestions,
   GetDraftList,SaveDraft,GetDigitalList,
   CreateConfig,GetConfig,UpdateConfig,AddDocument,
-  GetOpeningSpeech,GetVideo,BatchBind,BatchUnbind,UpdateObj,GenerateCompetency,SaveCompetency,GetPositionTags,
-  UpdateQuestion } from './api';
+  GetOpeningSpeech,GetVideo,BatchBind,BatchUnbind,UpdateObj,
+  GenerateCompetency,SaveCompetency,GetPositionTags,
+  UpdateQuestion,GetPositionQuestions } from './api';
 import draggable from 'vuedraggable';
 import { updateFieldConfig } from './utils';
 import type { ProfileFieldsConfig } from './types';
@@ -2322,7 +2347,7 @@ const recruitmentProcess = reactive([
   { id: 6, name: '简历收集', description: '简历收集', active: true, type: 'resume_collection' },
   { id: 5, name: '资料收集', description: '资料收集', active: true, type: 'data_collection' },
    { id: 2, name: 'AI考察', description: 'AI考察', active: true, type: 'ai_video' },
-  { id: 7, name: '候选人提问', description: '时长5分钟,最多3个问题', active: true, type: 'candidate_questions',
+ /*  { id: 7, name: '候选人提问', description: '时长5分钟,最多3个问题', active: true, type: 'candidate_questions',
     config: {
       title: '候选人提问',
       duration: 5,
@@ -2337,7 +2362,7 @@ const recruitmentProcess = reactive([
       ]
     }
   },
- /*  { id: 8, name: '常识问题', description: '常识问题', active: true, type: 'common_sense' },
+  { id: 8, name: '常识问题', description: '常识问题', active: true, type: 'common_sense' },
   { id: 9, name: '心理问题', description: '心理问题', active: true, type: 'psychological_problem' }, */
  
  /*  { id: 1, name: '待核验', description: '待核验', active: true, type: 'pending_verification' }, */
@@ -2622,6 +2647,18 @@ const questionForm = reactive({
   scoring_reference: '' // 评分标准
 });
 
+// 定义胜任力标签类型
+interface CompetencyTagItem {
+  id: string;
+  name: string;
+  weight: number;
+}
+
+const getcompetency_tags = (value:any)=>{
+  return value.map((item:any)=>{
+    return item.id
+  })
+}
 // 胜任力标签选项
 const competencyTagOptions = ref<CompetencyTag[]>([]);
 
@@ -2918,6 +2955,7 @@ const cancelEditProcess = () => {
 
 // 删除流程步骤 - 删除后允许重新添加相同类型的步骤
 const deleteProcessStep = (index: number) => {
+  
   recruitmentProcess.splice(index, 1);
 };
 
@@ -3662,6 +3700,7 @@ const editQuestion = (index: number) => {
   console.log(question);
   Object.assign(questionForm, question);
   showQuestionDialog.value = true;
+  distributeWeightsEvenly()
 };
 
 const deleteQuestion = (index: number) => {
@@ -4401,6 +4440,12 @@ const editAIVideo = async (step: AIVideoStep) => {
   }
 
   if (step.name === 'AI考察') {
+    // 如果是删除操作,先删除相关的AI考察问题
+    if (step.action === 'delete') {
+      await handleDeleteAIQuestions();
+      return;
+    }
+
     const response = await GetConfig(route.query.id);
     competencyLoading.value = true;
     currentEditingStep.value = step;
@@ -5282,8 +5327,8 @@ const fieldConfig = reactive({
   },
 
   // 专业技能
-  skills: { visible: true, label: '专业技能', required: true },
-  training: { visible: true, label: '受过的培训', required: true },
+  require_professional_skills: { visible: true, label: '专业技能', required: true },
+  training_fields_config: { visible: true, label: '受过的培训', required: true },
 
   // 工作经历
   work_experience: {
@@ -5366,15 +5411,17 @@ const saveFieldConfig = async () => {
       },
       
       // 培训经历配置
-      require_training_info: false,
-      training_fields_config: {
+      require_training_info: fieldConfig.training_fields_config.visible,
+      require_professional_skills: fieldConfig.require_professional_skills.visible,
+
+   /*    training_fields_config: {
         training_name: { required: true, visible: true },
         institution: { required: true, visible: true },
         start_date: { required: true, visible: true },
         end_date: { required: false, visible: true },
         certificate: { required: false, visible: true }
       },
-      
+       */
       // 姿态配置
       enable_posture_check: true,
       posture_check_config: {
@@ -5460,8 +5507,8 @@ const getBasicFields = () => {
 // 获取专业技能字段
 const getSkillFields = () => {
   const skillFields = {
-    skills: fieldConfig.skills,
-    training: fieldConfig.training
+    skills: fieldConfig.require_professional_skills,
+    training: fieldConfig.training_fields_config
   };
   return skillFields;
 };
@@ -5880,6 +5927,132 @@ const editProcessStep = (step: any, index: number) => {
   }
 };
 
+// 权重变化处理函数
+const handleWeightChange = (index: number, value: number | null) => {
+  if (value === null || value < 0) value = 0;
+  if (value > 100) value = 100;
+  
+  const tags = questionForm.competency_tags as CompetencyTagItem[];
+  const oldWeight = tags[index].weight;
+  const newWeight = Math.round(value);
+  
+  // 更新当前标签权重
+  tags[index].weight = newWeight;
+  
+  // 如果只有一个标签,直接设置为100
+  if (tags.length === 1) {
+    tags[0].weight = 100;
+    return;
+  }
+  
+  // 计算权重差值
+  const weightDiff = newWeight - oldWeight;
+  const otherTags = tags.filter((_, i) => i !== index);
+  const totalOtherWeight = otherTags.reduce((sum, tag) => sum + tag.weight, 0);
+  
+  // 如果其他标签总权重为0,则平均分配剩余权重
+  if (totalOtherWeight === 0) {
+    const remainingWeight = 100 - newWeight;
+    const averageWeight = Math.floor(remainingWeight / otherTags.length);
+    const remainder = remainingWeight % otherTags.length;
+    
+    otherTags.forEach((tag, i) => {
+      const tagIndex = tags.findIndex(t => t.id === tag.id);
+      tags[tagIndex].weight = averageWeight + (i < remainder ? 1 : 0);
+    });
+  } else {
+    // 按比例调整其他标签权重
+    const targetTotalOther = 100 - newWeight;
+    
+    if (targetTotalOther > 0) {
+      otherTags.forEach(tag => {
+        const tagIndex = tags.findIndex(t => t.id === tag.id);
+        const proportion = tag.weight / totalOtherWeight;
+        tags[tagIndex].weight = Math.round(targetTotalOther * proportion);
+      });
+      
+      // 处理舍入误差
+      const currentTotal = getTotalWeight();
+      if (currentTotal !== 100) {
+        const diff = 100 - currentTotal;
+        // 找到最大权重的其他标签进行调整
+        const maxOtherTag = otherTags.reduce((max, tag) => 
+          tag.weight > max.weight ? tag : max
+        );
+        const maxTagIndex = tags.findIndex(t => t.id === maxOtherTag.id);
+        tags[maxTagIndex].weight += diff;
+      }
+    } else {
+      // 如果当前权重已经是100%,其他标签设为0
+      otherTags.forEach(tag => {
+        const tagIndex = tags.findIndex(t => t.id === tag.id);
+        tags[tagIndex].weight = 0;
+      });
+    }
+  }
+};
+
+// 获取总权重
+const getTotalWeight = (): number => {
+  const tags = questionForm.competency_tags as CompetencyTagItem[];
+  return tags.reduce((total, tag) => total + (tag.weight || 0), 0);
+};
+
+// 平均分配权重
+const distributeWeightsEvenly = () => {
+  const tags = questionForm.competency_tags as CompetencyTagItem[];
+  if (tags.length === 0) return;
+  
+  const averageWeight = Math.floor(100 / tags.length);
+  const remainder = 100 % tags.length;
+  
+  tags.forEach((tag, index) => {
+    tag.weight = averageWeight + (index < remainder ? 1 : 0);
+  });
+};
+
+const competencyTagsValue = computed({
+  get: () => getcompetency_tags(questionForm.competency_tags),
+  set: (value) => {
+    questionForm.competency_tags = value;
+    handleCompetencyTagsChange(value);
+  }
+});
+
+// 删除AI考察相关问题
+const handleDeleteAIQuestions = async () => {
+  try {
+    // 获取当前职位下的所有AI生成的问题
+    const response = await GetPositionQuestions({
+      position_id: route.query.id,
+      tenant_id: 1,
+      is_ai_generated: true // 只获取AI生成的问题
+    });
+
+    if (response && response.data && response.data.length > 0) {
+      // 批量解绑AI生成的问题
+      await BatchUnbind({
+        position_id: route.query.id,
+        question_id: response.data.map((item: any) => item.id),
+        tenant_id: 1
+      });
+
+      // 更新配置
+      if (getConfigId.value > 0) {
+        await UpdateConfig({
+          id: getConfigId.value,
+          enable_ai_questions: false
+        });
+      }
+
+      ElMessage.success('AI考察问题已删除');
+    }
+  } catch (error) {
+    console.error('删除AI考察问题失败:', error);
+    ElMessage.error('删除AI考察问题失败');
+  }
+};
+
 </script>
 
 <style scoped>
@@ -6492,4 +6665,126 @@ const editProcessStep = (step: any, index: number) => {
     border-top: 1px solid #ebeef5;
   }
 }
+
+/* 权重配置增强样式 */
+.competency-config {
+  .config-row {
+    &:first-child {
+      background-color: #f8f9fa;
+      border-radius: 4px 4px 0 0;
+      font-weight: 600;
+      color: #409eff;
+    }
+    
+    /* 平均分配按钮样式 */
+    .el-button--text {
+      padding: 4px 8px;
+      margin-left: auto;
+      font-size: 12px;
+      
+      &:hover {
+        background-color: #ecf5ff;
+        color: #409eff;
+      }
+    }
+  }
+  
+  .tag-name {
+    font-weight: 500;
+    color: #303133;
+  }
+}
+
+.weight-sum {
+  font-weight: bold;
+  color: #67c23a;
+  margin-left: 8px;
+  font-size: 13px;
+  
+  &.weight-error {
+    color: #f56c6c;
+    animation: shake 0.5s ease-in-out;
+  }
+}
+
+/* 输入框优化样式 */
+:deep(.el-input-number) {
+  .el-input__inner {
+    text-align: center;
+    font-weight: 500;
+  }
+  
+  &.is-focus .el-input__inner {
+    border-color: #409eff;
+    box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.2);
+  }
+}
+
+/* 权重错误提示动画 */
+@keyframes shake {
+  0%, 100% { transform: translateX(0); }
+  25% { transform: translateX(-2px); }
+  75% { transform: translateX(2px); }
+}
+
+/* 权重配置增强样式 */
+.competency-config {
+  .config-row {
+    &:first-child {
+      background-color: #f8f9fa;
+      border-radius: 4px 4px 0 0;
+      font-weight: 600;
+      color: #409eff;
+    }
+    
+    /* 平均分配按钮样式 */
+    .el-button--text {
+      padding: 4px 8px;
+      margin-left: auto;
+      font-size: 12px;
+      
+      &:hover {
+        background-color: #ecf5ff;
+        color: #409eff;
+      }
+    }
+  }
+  
+  .tag-name {
+    font-weight: 500;
+    color: #303133;
+  }
+}
+
+.weight-sum {
+  font-weight: bold;
+  color: #67c23a;
+  margin-left: 8px;
+  font-size: 13px;
+  
+  &.weight-error {
+    color: #f56c6c;
+    animation: shake 0.5s ease-in-out;
+  }
+}
+
+/* 输入框优化样式 */
+:deep(.el-input-number) {
+  .el-input__inner {
+    text-align: center;
+    font-weight: 500;
+  }
+  
+  &.is-focus .el-input__inner {
+    border-color: #409eff;
+    box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.2);
+  }
+}
+
+/* 权重错误提示动画 */
+@keyframes shake {
+  0%, 100% { transform: translateX(0); }
+  25% { transform: translateX(-2px); }
+  75% { transform: translateX(2px); }
+}
 </style>