Эх сурвалжийг харах

添加ai视频及资料收集配置

yangg 2 сар өмнө
parent
commit
b19582bf3c

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

@@ -52,6 +52,24 @@ export function GetDigitalList(obj: EditReq) {
 	});
 }
 
+/* 创建配置 */
+export function CreateConfig(data:any) {
+	return request({
+		url:`/api/system/job_config/list`,
+		method: 'post',
+		data: {...data,tenant_id:1},
+	});
+}
+
+/* 获取当前配置 */
+export function GetConfig(id:any) {
+	return request({
+		url:`/api/system/job_config/position/detail/${id}`,
+		method: 'get',
+		
+	});
+}
+
 export function DelObj(data:any) {
 	return request({
 		url:`/api/system/competency/delete`,

+ 54 - 0
src/views/position/detail/index.css

@@ -1657,4 +1657,58 @@
   opacity: 0.8;
   background: #fff;
   box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
+}
+
+.field-config-panel {
+  background: #fff;
+  border-radius: 8px;
+  padding: 20px;
+  margin-bottom: 20px;
+}
+
+.panel-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  margin-bottom: 20px;
+  
+  h3 {
+    margin: 0;
+    font-size: 16px;
+    color: #303133;
+  }
+}
+
+.field-config-list {
+  .section-title {
+    font-size: 14px;
+    font-weight: 500;
+    color: #303133;
+    margin: 20px 0 15px;
+    padding-left: 8px;
+    border-left: 3px solid #0419a3;
+  }
+}
+
+.field-config-item {
+  display: flex;
+  align-items: center;
+  margin-bottom: 15px;
+  padding: 10px;
+  background: #f5f7fa;
+  border-radius: 4px;
+  
+  .field-label {
+    flex: 1;
+    font-size: 14px;
+    color: #606266;
+  }
+  
+  .required-tag {
+    margin-left: 8px;
+  }
+  
+  .custom-switch {
+    margin-left: auto;
+  }
 }

+ 480 - 70
src/views/position/detail/index.vue

@@ -353,13 +353,12 @@
             <div class="process-edit-content">
               <div>{{ step.name }}</div>
               <div class="process-edit-desc">{{ step.description }}</div>
-            </div>
+            </div><!--  v-if="step.name=='AI视频'" -->
             <div class="process-edit-btn">
                <el-button 
                 type="info" 
                 size="small" 
                 plain 
-                v-if="step.name=='AI视频'"
                 @click="editAIVideo(step)"
               >
                 修改
@@ -1030,69 +1029,174 @@
     <el-dialog
       title="资料收集"
       v-model="showDataCollectionDialog"
-      width="500px"
+      width="900px"
       :close-on-click-modal="false"
       class="data-collection-dialog"
     >
       <div class="data-collection-form">
-        <div class="question-list">
-          <div v-for="(question, index) in questionTypes" :key="index" class="question-item">
-            <!-- 问题标题栏 -->
-            <div class="question-header">
-              <div class="question-title">
-                <span>{{ question.label }}</span>
-              </div>
-              <div class="question-type">
-                <span>问答类</span>
-                <el-icon><ArrowDown /></el-icon>
-              </div>
-            </div>
-            
-            <!-- 问题内容区 -->
-            <div class="question-content">
-              <div class="user-answer">用户回答</div>
-              
-              <!-- 操作按钮区 -->
-              <div class="question-actions">
-                <div class="action-left">
-                  <el-switch v-model="question.isVisible" />
-                  <span class="action-text">{{ question.isVisible ? '显示' : '隐藏' }}</span>
+        <!-- 字段配置面板 -->
+        <div class="field-config-panel">
+          <div class="panel-header">
+            <h3>字段显示配置</h3>
+            <el-button type="primary" size="small" @click="saveFieldConfig">保存配置</el-button>
+          </div>
+          <div class="field-config-list">
+            <!-- 基本信息部分 -->
+            <div class="section-title">基本信息</div>
+            <el-row :gutter="20">
+              <el-col :span="8" v-for="(field, key) in getBasicFields()" :key="key">
+                <div class="field-config-item">
+                  <span class="field-label">
+                    {{ field.label }}
+                   <!--  <el-tag v-if="field.required" size="small" type="danger" class="required-tag">必填</el-tag> -->
+                  </span>
+                  <el-tooltip
+                    :content="field.required ? '必填项不可隐藏' : '切换显示/隐藏'"
+                    placement="top"
+                  >
+                    <el-switch
+                      v-model="field.visible"
+                      :disabled="field.required"
+                      class="custom-switch"
+                    />
+                  </el-tooltip>
                 </div>
-                <div class="action-right">
-                  <el-icon class="action-icon"><Document /></el-icon>
-                  <el-icon class="action-icon"><Delete /></el-icon>
+              </el-col>
+            </el-row>
+
+            <!-- 家庭成员信息部分 -->
+            <div class="section-title">家庭成员信息</div>
+            <el-row :gutter="20">
+              <el-col :span="24">
+                <div class="field-config-item">
+                  <span class="field-label">
+                    {{ fieldConfig.family_member.label }}
+                    <el-tag v-if="fieldConfig.family_member.visible" size="small" type="success">已启用</el-tag>
+                  </span>
+                  <el-switch v-model="fieldConfig.family_member.visible" class="custom-switch" />
                 </div>
-              </div>
-              
-              <!-- 设置区域 -->
-              <div class="question-settings">
-                <div class="setting-item">
-                  <span>开启评分</span>
-                  <el-switch v-model="question.enableScoring" />
+              </el-col>
+            </el-row>
+            <el-row :gutter="20" v-if="fieldConfig.family_member.visible">
+              <el-col :span="8" v-for="(field, key) in fieldConfig.family_member.fields" :key="key">
+                <div class="field-config-item sub-field">
+                  <span class="field-label">
+                    {{ field.label }}
+                    <!-- <el-tag v-if="field.required" size="small" type="danger" class="required-tag">必填</el-tag> -->
+                  </span>
+                  <el-tooltip
+                    :content="field.required ? '必填项不可隐藏' : '切换显示/隐藏'"
+                    placement="top"
+                  >
+                    <el-switch
+                      v-model="field.visible"
+                      :disabled="field.required"
+                      class="custom-switch"
+                    />
+                  </el-tooltip>
                 </div>
-                <div class="setting-item">
-                  <span>必答</span>
-                  <el-switch v-model="question.isRequired" />
+              </el-col>
+            </el-row>
+
+            <!-- 教育经历部分 -->
+            <div class="section-title">教育经历</div>
+            <el-row :gutter="20">
+              <el-col :span="24">
+                <div class="field-config-item">
+                  <span class="field-label">
+                    {{ fieldConfig.education.label }}
+                    <el-tag v-if="fieldConfig.education.visible" size="small" type="success">已启用</el-tag>
+                  </span>
+                  <el-switch v-model="fieldConfig.education.visible" class="custom-switch" />
                 </div>
-              </div>
-            </div>
+              </el-col>
+            </el-row>
+            <el-row :gutter="20" v-if="fieldConfig.education.visible">
+              <el-col :span="8" v-for="(field, key) in fieldConfig.education.fields" :key="key">
+                <div class="field-config-item sub-field">
+                  <span class="field-label">
+                    {{ field.label }}
+                   <!--  <el-tag v-if="field.required" size="small" type="danger" class="required-tag">必填</el-tag> -->
+                  </span>
+                  <el-tooltip
+                    :content="field.required ? '必填项不可隐藏' : '切换显示/隐藏'"
+                    placement="top"
+                  >
+                    <el-switch
+                      v-model="field.visible"
+                      :disabled="field.required"
+                      class="custom-switch"
+                    />
+                  </el-tooltip>
+                </div>
+              </el-col>
+            </el-row>
+
+            <!-- 专业技能部分 -->
+            <div class="section-title">专业技能</div>
+            <el-row :gutter="20">
+              <el-col :span="8" v-for="(field, key) in getSkillFields()" :key="key">
+                <div class="field-config-item">
+                  <span class="field-label">
+                    {{ field.label }}
+                    <!-- <el-tag v-if="field.required" size="small" type="danger" class="required-tag">必填</el-tag> -->
+                  </span>
+                  <el-tooltip
+                    :content="field.required ? '必填项不可隐藏' : '切换显示/隐藏'"
+                    placement="top"
+                  >
+                    <el-switch
+                      v-model="field.visible"
+                      :disabled="field.required"
+                      class="custom-switch"
+                    />
+                  </el-tooltip>
+                </div>
+              </el-col>
+            </el-row>
+
+            <!-- 工作经历部分 -->
+            <div class="section-title">工作经历</div>
+            <el-row :gutter="20">
+              <el-col :span="24">
+                <div class="field-config-item">
+                  <span class="field-label">
+                    {{ fieldConfig.work_experience.label }}
+                    <el-tag v-if="fieldConfig.work_experience.visible" size="small" type="success">已启用</el-tag>
+                  </span>
+                  <el-switch v-model="fieldConfig.work_experience.visible" class="custom-switch" />
+                </div>
+              </el-col>
+            </el-row>
+            <el-row :gutter="20" v-if="fieldConfig.work_experience.visible">
+              <el-col :span="8" v-for="(field, key) in fieldConfig.work_experience.fields" :key="key">
+                <div class="field-config-item sub-field">
+                  <span class="field-label">
+                    {{ field.label }}
+                   <!--  <el-tag v-if="field.required" size="small" type="danger" class="required-tag">必填</el-tag> -->
+                  </span>
+                  <el-tooltip
+                    :content="field.required ? '必填项不可隐藏' : '切换显示/隐藏'"
+                    placement="top"
+                  >
+                    <el-switch
+                      v-model="field.visible"
+                      :disabled="field.required"
+                      class="custom-switch"
+                    />
+                  </el-tooltip>
+                </div>
+              </el-col>
+            </el-row>
           </div>
         </div>
-
-        <!-- 添加问题按钮 -->
-        <div class="add-question">
-          <el-button type="primary" plain @click="handleAddQuestion">
-            <el-icon><Plus /></el-icon>
-            添加问题
-          </el-button>
-        </div>
       </div>
 
       <template #footer>
         <span class="dialog-footer">
           <el-button @click="cancelDataCollection">取消</el-button>
           <el-button type="primary" @click="confirmDataCollection">确认</el-button>
-        </span>
+                  </span>
       </template>
     </el-dialog>
 
@@ -1112,8 +1216,8 @@
             placeholder="请输入步骤名称"
             maxlength="30"
             show-word-limit
-          />
-        </div>
+                  />
+                </div>
         
         <!-- <div class="form-item">
           <div class="form-label">必填项</div>
@@ -1154,7 +1258,7 @@
         <span class="dialog-footer">
           <el-button @click="cancelResumeCollection">取消</el-button>
           <el-button type="primary" @click="confirmResumeCollection">确认</el-button>
-        </span>
+                    </span>
       </template>
     </el-dialog>
 
@@ -1323,8 +1427,10 @@ 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 } from './api';
+import { GetCompetencyList,GetQuestionList,GenerateQuestions,GetDraftList,SaveDraft,GetDigitalList,CreateConfig,GetConfig } from './api';
 import draggable from 'vuedraggable';
+import { updateFieldConfig } from './utils';
+import type { ProfileFieldsConfig } from './types';
 
 // 添加 ChatQuestion 接口定义
 interface ChatQuestion {
@@ -1383,9 +1489,11 @@ const positionData = reactive({
 // 招聘流程数据 - 修改为普通数组而非 ref 对象
 const recruitmentProcess = reactive([
   { id: 1, name: '待核验', description: '待核验', active: true },
+  { id: 5, name: '资料收集', description: '资料收集', active: true },
   { id: 2, name: 'AI视频', description: 'AI视频', active: true },
   { id: 3, name: '已通过', description: '已通过', active: true },
-  { id: 4, name: '已淘汰', description: '已淘汰', active: false }
+  { id: 4, name: '已淘汰', description: '已淘汰', active: false },
+  
 ]);
 
 // 是否显示流程编辑对话框
@@ -1398,8 +1506,8 @@ const processStepOptions = [
   { label: 'AI实时对话', value: 'ai_chat' },
   { label: '资料收集', value: 'data_collection' },
   { label: '简历收集', value: 'resume_collection' },
-  { label: '代码测试', value: 'code_test' },
-  { label: '打字测试', value: 'typing_test' }
+  /* { label: '代码测试', value: 'code_test' },
+  { label: '打字测试', value: 'typing_test' } */
 ];
 
 // 当前选择的添加位置
@@ -1781,9 +1889,8 @@ const showStepOptions = (index: number, event: MouseEvent) => {
   // 阻止事件冒泡
   event.stopPropagation();
 };
-
 // 修改添加选定类型的步骤方法
-const addSelectedStepType = (type: string, label: string) => {
+const addSelectedStepType = async (type: string, label: string) => {
   if (type === 'ai_video') {
     showAIVideoDialog.value = true;
     showOptionsMenu.value = false;
@@ -1806,8 +1913,12 @@ const addSelectedStepType = (type: string, label: string) => {
   
   // 添加资料收集类型的处理
   if (type === 'data_collection') {
-    showDataCollectionDialog.value = true;
-    showOptionsMenu.value = false;
+    const response = await GetConfig(route.query.id);
+    if (response && response.data) {
+      updateFieldConfig(fieldConfig, response.data.profile_fields_config as ProfileFieldsConfig);
+      showDataCollectionDialog.value = true;
+      showOptionsMenu.value = false;
+    }
     return;
   }
   
@@ -2086,10 +2197,10 @@ const cancelDataCollection = () => {
 
 // 确认添加资料收集
 const confirmDataCollection = () => {
-  if (dataCollectionForm.questions.length === 0) {
+  /* if (dataCollectionForm.questions.length === 0) {
     ElMessage.warning('请至少选择一个问题');
     return;
-  }
+  } */
 
   // 创建新的资料收集步骤
   const newStep = {
@@ -2650,14 +2761,27 @@ const saveCompetency = async () => {
 const currentEditingStep = ref<AIVideoStep | null>(null);
 
 // 编辑AI视频
-const editAIVideo = (step: AIVideoStep) => {
-  currentEditingStep.value = step;
-  showAIVideoDialog.value = true;
-  currentStep.value = 1;
-  // 重置选项
-  (Object.keys(aiVideoOptions) as Array<keyof typeof aiVideoOptions>).forEach(key => {
-    aiVideoOptions[key] = false;
-  });
+const editAIVideo = async (step: AIVideoStep) => {
+   // 添加资料收集类型的处理
+   if (step.name === '资料收集') {
+    const response = await GetConfig(route.query.id);
+    if (response && response.data) {
+      updateFieldConfig(fieldConfig, response.data.profile_fields_config as ProfileFieldsConfig);
+      showDataCollectionDialog.value = true;
+      showOptionsMenu.value = false;
+    }
+    return;
+  }
+  
+  if (step.name === 'AI视频') {
+    currentEditingStep.value = step;
+    showAIVideoDialog.value = true;
+    currentStep.value = 1;
+    // 重置选项
+    (Object.keys(aiVideoOptions) as Array<keyof typeof aiVideoOptions>).forEach(key => {
+      aiVideoOptions[key] = false;
+    });
+  }
 };
 
 // 保存AI视频配置
@@ -2915,6 +3039,211 @@ console.log(draftResponse);
   }
 };
 
+// 字段配置数据
+const fieldConfig = reactive({
+  // 基本信息
+  name: { visible: true, label: '姓名', required: true },
+  gender: { visible: true, label: '性别', required: true },
+  three_period: { visible: true, label: '是否为三期', required: true },
+  phone: { visible: true, label: '手机号', required: true },
+  id_card: { visible: true, label: '身份证号', required: true },
+  ethnicity: { visible: true, label: '民族', required: true },
+  height: { visible: true, label: '身高(cm)', required: false },
+  weight: { visible: true, label: '体重(kg)', required: false },
+  current_address: { visible: true, label: '现居住地址', required: true },
+  household_location: { visible: true, label: '户口所在地', required: false },
+  marital_status: { visible: true, label: '婚育状况', required: false },
+  expected_salary: { visible: true, label: '期望薪资(元/月)', required: false },
+
+  // 家庭成员信息
+  family_member: {
+    visible: true,
+    label: '家庭成员',
+    fields: {
+      relation: { visible: true, label: '称谓', required: true },
+      name: { visible: true, label: '姓名', required: true },
+      workplace_address: { visible: true, label: '工作单位/家庭地址', required: false },
+      position: { visible: true, label: '职务', required: false },
+      phone: { visible: true, label: '联系电话', required: true },
+      is_emergency_contact: { visible: true, label: '是否为紧急联系人', required: false }
+    }
+  },
+
+  // 教育经历
+  education: {
+    visible: true,
+    label: '教育经历',
+    fields: {
+      start_time: { visible: true, label: '开始时间', required: true },
+      end_time: { visible: true, label: '结束时间', required: true },
+      school_name: { visible: true, label: '学校名称', required: true },
+      major: { visible: true, label: '专业', required: true },
+      degree: { visible: true, label: '学历', required: true }
+    }
+  },
+
+  // 专业技能
+  skills: { visible: true, label: '专业技能', required: true },
+  training: { visible: true, label: '受过的培训', required: true },
+
+  // 工作经历
+  work_experience: {
+    visible: true,
+    label: '工作经历',
+    fields: {
+      start_time: { visible: true, label: '开始时间', required: true },
+      end_time: { visible: true, label: '结束时间', required: true },
+      company_name: { visible: true, label: '单位名称', required: true },
+      employee_count: { visible: true, label: '单位人数', required: true },
+      department: { visible: true, label: '任职部门', required: true },
+      position: { visible: true, label: '担任职务', required: true },
+      monthly_salary: { visible: true, label: '月总收入', required: true },
+      supervisor: { visible: true, label: '直接领导', required: true },
+      supervisor_phone: { visible: true, label: '领导电话', required: true }
+    }
+  }
+});
+
+// 保存字段配置
+const saveFieldConfig = async () => {
+  try {
+    // 构建配置数据
+    const configData = {
+      position_id: route.query.id, // 职位ID
+      config_name: "咖啡师配置", // 配置名称
+      digital_human_id: 4, // 数字人ID
+      
+      // 简历上传配置
+      require_resume_upload: true, // 是否要求上传简历
+      resume_file_types: ["pdf", "docx", "doc"], // 允许的文件类型
+      max_resume_size_mb: 10, // 最大文件大小(MB)
+      
+      // 个人信息配置
+      require_basic_info: true, // 是否要求填写基本信息
+      profile_fields_config: {
+        name: { required: fieldConfig.name.required, visible: fieldConfig.name.visible },
+        phone: { required: fieldConfig.phone.required, visible: fieldConfig.phone.visible },
+        id_card: { required: fieldConfig.id_card.required, visible: fieldConfig.id_card.visible },
+        gender: { required: fieldConfig.gender.required, visible: fieldConfig.gender.visible },
+        birth_date: { required: false, visible: true },
+        political_status: { required: false, visible: true },
+        ethnicity: { required: fieldConfig.ethnicity.required, visible: fieldConfig.ethnicity.visible },
+        height: { required: fieldConfig.height.required, visible: fieldConfig.height.visible },
+        weight: { required: fieldConfig.weight.required, visible: fieldConfig.weight.visible },
+        marital_status: { required: fieldConfig.marital_status.required, visible: fieldConfig.marital_status.visible }
+      },
+      
+      // 教育信息配置
+      require_education_info: fieldConfig.education.visible, // 是否要求填写教育信息
+      education_fields_config: {
+        school_name: { required: fieldConfig.education.fields.school_name.required, visible: fieldConfig.education.fields.school_name.visible },
+        major: { required: fieldConfig.education.fields.major.required, visible: fieldConfig.education.fields.major.visible },
+        degree: { required: fieldConfig.education.fields.degree.required, visible: fieldConfig.education.fields.degree.visible },
+        start_date: { required: fieldConfig.education.fields.start_time.required, visible: fieldConfig.education.fields.start_time.visible },
+        end_date: { required: fieldConfig.education.fields.end_time.required, visible: fieldConfig.education.fields.end_time.visible }
+      },
+      
+      // 工作经验配置
+      require_work_experience: fieldConfig.work_experience.visible, // 是否要求填写工作经验
+      work_experience_fields_config: {
+        company_name: { required: fieldConfig.work_experience.fields.company_name.required, visible: fieldConfig.work_experience.fields.company_name.visible },
+        position: { required: fieldConfig.work_experience.fields.position.required, visible: fieldConfig.work_experience.fields.position.visible },
+        department: { required: fieldConfig.work_experience.fields.department.required, visible: fieldConfig.work_experience.fields.department.visible },
+        start_date: { required: fieldConfig.work_experience.fields.start_time.required, visible: fieldConfig.work_experience.fields.start_time.visible },
+        end_date: { required: fieldConfig.work_experience.fields.end_time.required, visible: fieldConfig.work_experience.fields.end_time.visible },
+        job_description: { required: true, visible: true },
+        achievements: { required: false, visible: true },
+        resignation_reason: { required: false, visible: true }
+      },
+      
+      // 家庭信息配置
+      require_family_info: fieldConfig.family_member.visible, // 是否要求填写家庭信息
+      family_fields_config: {
+        relation: { required: fieldConfig.family_member.fields.relation.required, visible: fieldConfig.family_member.fields.relation.visible },
+        name: { required: fieldConfig.family_member.fields.name.required, visible: fieldConfig.family_member.fields.name.visible },
+        workplace: { required: fieldConfig.family_member.fields.workplace_address.required, visible: fieldConfig.family_member.fields.workplace_address.visible },
+        position: { required: fieldConfig.family_member.fields.position.required, visible: fieldConfig.family_member.fields.position.visible },
+        phone: { required: fieldConfig.family_member.fields.phone.required, visible: fieldConfig.family_member.fields.phone.visible }
+      },
+      
+      // 培训经历配置
+      require_training_info: false,
+      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: {
+        required_photos: ["front", "side", "back"],
+        instructions: "请按照提示上传您的全身照片,确保光线充足,背景简洁"
+      },
+      
+      // 面试配置
+      interview_duration_minutes: 45,
+      enable_video_recording: true,
+      enable_face_recognition: true,
+      
+      // 评分配置
+      scoring_method: "hybrid",
+      auto_analysis_enabled: true,
+      
+      // 其他配置
+      custom_welcome_message: "欢迎参加咖啡师岗位的面试,请放松心情,准备好开始面试吧!",
+      custom_instructions: "本次面试共有10个问题,每个问题有60秒的回答时间,请简洁明了地表达您的观点。",
+      
+      notification_config: {
+        send_email: true,
+        send_sms: false,
+        notify_hr: true,
+        completion_message: "感谢您完成面试,我们将在3个工作日内给您回复。"
+      },
+      
+      is_active: true,
+      is_template: false
+    };
+    
+    // 调用后端 API
+    await CreateConfig(configData);
+    ElMessage.success('配置保存成功');
+  } catch (error) {
+    console.error('保存配置失败:', error);
+    ElMessage.error('配置保存失败');
+  }
+};
+
+// 获取基本信息字段
+const getBasicFields = () => {
+  const basicFields = {
+    name: fieldConfig.name,
+    gender: fieldConfig.gender,
+    three_period: fieldConfig.three_period,
+    phone: fieldConfig.phone,
+    id_card: fieldConfig.id_card,
+    ethnicity: fieldConfig.ethnicity,
+    height: fieldConfig.height,
+    weight: fieldConfig.weight,
+    current_address: fieldConfig.current_address,
+    household_location: fieldConfig.household_location,
+    marital_status: fieldConfig.marital_status,
+    expected_salary: fieldConfig.expected_salary
+  };
+  return basicFields;
+};
+
+// 获取专业技能字段
+const getSkillFields = () => {
+  const skillFields = {
+    skills: fieldConfig.skills,
+    training: fieldConfig.training
+  };
+  return skillFields;
+};
+
 </script>
 
 <style scoped>
@@ -3005,4 +3334,85 @@ console.log(draftResponse);
     margin-right: 8px;
   }
 }
+
+.field-config-panel {
+  background: #fff;
+  border-radius: 8px;
+  padding: 24px;
+  margin-bottom: 20px;
+  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
+
+  .panel-header {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    margin-bottom: 24px;
+    
+    h3 {
+      margin: 0;
+      font-size: 18px;
+      color: #303133;
+      font-weight: 600;
+    }
+  }
+
+  .section-title {
+    font-size: 16px;
+    font-weight: 500;
+    color: #303133;
+    margin: 24px 0 16px;
+    padding-left: 10px;
+    border-left: 4px solid #0419a3;
+  }
+
+  .field-config-item {
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    margin-bottom: 12px;
+    padding: 12px 16px;
+    background: #f5f7fa;
+    border-radius: 6px;
+    transition: all 0.3s ease;
+    
+    &:hover {
+      background: #eef1f6;
+    }
+    
+    &.sub-field {
+      background: #fff;
+      border: 1px solid #e4e7ed;
+      margin-left: 12px;
+      
+      &:hover {
+        border-color: #0419a3;
+      }
+    }
+    
+    .field-label {
+      flex: 1;
+      font-size: 14px;
+      color: #606266;
+      display: flex;
+      align-items: center;
+      gap: 8px;
+    }
+    
+    .required-tag {
+      font-size: 12px;
+      padding: 0 6px;
+      height: 20px;
+      line-height: 18px;
+    }
+    
+    :deep(.el-switch.is-checked .el-switch__core) {
+      border-color: #0419a3;
+      background-color: #0419a3;
+    }
+  }
+}
+
+.el-row {
+  margin-bottom: 12px;
+}
 </style>

+ 36 - 0
src/views/position/detail/types.ts

@@ -0,0 +1,36 @@
+// 字段基本配置接口
+interface FieldConfig {
+  visible: boolean;
+  required: boolean;
+  label: string;
+}
+
+// 嵌套字段配置接口
+interface NestedFieldConfig {
+  visible: boolean;
+  label: string;
+  fields: {
+    [key: string]: FieldConfig;
+  }
+}
+
+// 响应数据接口
+interface ProfileFieldsConfig {
+  [key: string]: FieldConfig | NestedFieldConfig;
+  name: FieldConfig;
+  gender: FieldConfig;
+  phone: FieldConfig;
+  id_card: FieldConfig;
+  ethnicity: FieldConfig;
+  height: FieldConfig;
+  weight: FieldConfig;
+  current_address: FieldConfig;
+  household_location: FieldConfig;
+  marital_status: FieldConfig;
+  expected_salary: FieldConfig;
+  family_member: NestedFieldConfig;
+  education: NestedFieldConfig;
+  work_experience: NestedFieldConfig;
+}
+
+export type { FieldConfig, NestedFieldConfig, ProfileFieldsConfig }; 

+ 40 - 0
src/views/position/detail/utils.ts

@@ -0,0 +1,40 @@
+import type { ProfileFieldsConfig } from './types';
+
+/**
+ * 更新字段配置
+ * @param fieldConfig - 当前字段配置
+ * @param responseData - 接口返回的配置数据
+ */
+export function updateFieldConfig(fieldConfig: any, responseData: ProfileFieldsConfig) {
+  // 基础字段更新
+  const basicFields = [
+    'name', 'gender', 'phone', 'id_card', 'ethnicity', 
+    'height', 'weight', 'current_address', 'household_location', 
+    'marital_status', 'expected_salary'
+  ];
+  
+  basicFields.forEach(field => {
+    if (responseData[field]) {
+      fieldConfig[field].visible = responseData[field].visible;
+      fieldConfig[field].required = responseData[field].required;
+    }
+  });
+
+  // 嵌套字段更新
+  const nestedFields = ['family_member', 'education', 'work_experience'];
+  
+  nestedFields.forEach(field => {
+    if (responseData[field]) {
+      // 更新主字段
+      fieldConfig[field].visible = responseData[field].visible;
+      
+      // 更新子字段
+      Object.keys(responseData[field].fields).forEach(subField => {
+        if (fieldConfig[field].fields[subField]) {
+          fieldConfig[field].fields[subField].visible = responseData[field].fields[subField].visible;
+          fieldConfig[field].fields[subField].required = responseData[field].fields[subField].required;
+        }
+      });
+    }
+  });
+}