|
|
@@ -1,3832 +0,0 @@
|
|
|
-<template>
|
|
|
- <div class="position-detail-container">
|
|
|
- <div class="header-container">
|
|
|
- <page-header title="测试" @back="goBack" />
|
|
|
- <div class="header-actions">
|
|
|
- <el-button type="primary" @click="handleEdit">编辑</el-button>
|
|
|
- <el-button @click="handleShare">分享职位</el-button>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <div class="detail-content">
|
|
|
- <!-- 左侧详情信息 -->
|
|
|
- <el-card class="detail-card">
|
|
|
- <div class="section-title">
|
|
|
- <div class="section-line"></div>
|
|
|
- <span>职位详情</span>
|
|
|
- </div>
|
|
|
-
|
|
|
- <div class="detail-item">
|
|
|
- <div class="detail-label">职位名称</div>
|
|
|
- <div class="detail-value" v-if="!isEditingTitle">
|
|
|
- {{ positionData.title }}
|
|
|
- <el-button type="text" class="edit-title-btn" @click="startEditTitle">
|
|
|
- <el-icon><Edit /></el-icon>
|
|
|
- </el-button>
|
|
|
- </div>
|
|
|
- <div class="title-edit-container" v-else>
|
|
|
- <el-input
|
|
|
- v-model="editingTitle"
|
|
|
- placeholder="请输入职位名称"
|
|
|
- maxlength="20"
|
|
|
- show-word-limit
|
|
|
- />
|
|
|
- <div class="title-edit-actions">
|
|
|
- <el-button size="small" @click="cancelEditTitle">取消</el-button>
|
|
|
- <el-button size="small" type="primary" @click="saveTitle">保存</el-button>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <!-- 工作地点 -->
|
|
|
- <div class="detail-item">
|
|
|
- <div class="detail-label">工作地点</div>
|
|
|
- <div class="detail-value" v-if="!isEditingLocation">
|
|
|
- {{ positionData.location || '暂无' }}
|
|
|
- <el-button type="text" class="edit-title-btn" @click="startEditLocation">
|
|
|
- <el-icon><Edit /></el-icon>
|
|
|
- </el-button>
|
|
|
- </div>
|
|
|
- <div class="title-edit-container" v-else>
|
|
|
- <el-input
|
|
|
- v-model="editingLocation"
|
|
|
- placeholder="请输入工作地点"
|
|
|
- maxlength="50"
|
|
|
- show-word-limit
|
|
|
- />
|
|
|
- <div class="title-edit-actions">
|
|
|
- <el-button size="small" @click="cancelEditLocation">取消</el-button>
|
|
|
- <el-button size="small" type="primary" @click="saveLocation">保存</el-button>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <!-- 职位薪资 -->
|
|
|
- <div class="detail-item">
|
|
|
- <div class="detail-label">职位薪资</div>
|
|
|
- <div class="detail-value" v-if="!isEditingSalary">
|
|
|
- {{ positionData.salary_range || '暂无' }}
|
|
|
- <el-button type="text" class="edit-title-btn" @click="startEditSalary">
|
|
|
- <el-icon><Edit /></el-icon>
|
|
|
- </el-button>
|
|
|
- </div>
|
|
|
- <div class="title-edit-container" v-else>
|
|
|
- <el-input
|
|
|
- v-model="editingSalary"
|
|
|
- placeholder="请输入职位薪资"
|
|
|
- maxlength="30"
|
|
|
- show-word-limit
|
|
|
- />
|
|
|
- <div class="title-edit-actions">
|
|
|
- <el-button size="small" @click="cancelEditSalary">取消</el-button>
|
|
|
- <el-button size="small" type="primary" @click="saveSalary">保存</el-button>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <!-- 工作经验 -->
|
|
|
- <div class="detail-item">
|
|
|
- <div class="detail-label">工作经验</div>
|
|
|
- <div class="detail-value" v-if="!isEditingExperience">
|
|
|
- {{ positionData.work_experience_required || '暂无' }}
|
|
|
- <el-button type="text" class="edit-title-btn" @click="startEditExperience">
|
|
|
- <el-icon><Edit /></el-icon>
|
|
|
- </el-button>
|
|
|
- </div>
|
|
|
- <div class="title-edit-container" v-else>
|
|
|
- <el-select v-model="editingExperience" placeholder="请选择工作经验" style="width: 100%">
|
|
|
- <el-option label="不限" value="不限" />
|
|
|
- <el-option label="应届毕业生" value="应届毕业生" />
|
|
|
- <el-option label="1年以下" value="1年以下" />
|
|
|
- <el-option label="1-3年" value="1-3年" />
|
|
|
- <el-option label="3-5年" value="3-5年" />
|
|
|
- <el-option label="5-10年" value="5-10年" />
|
|
|
- <el-option label="10年以上" value="10年以上" />
|
|
|
- </el-select>
|
|
|
- <div class="title-edit-actions">
|
|
|
- <el-button size="small" @click="cancelEditExperience">取消</el-button>
|
|
|
- <el-button size="small" type="primary" @click="saveExperience">保存</el-button>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <!-- 学历要求 -->
|
|
|
- <div class="detail-item">
|
|
|
- <div class="detail-label">学历要求</div>
|
|
|
- <div class="detail-value" v-if="!isEditingEducation">
|
|
|
- {{ positionData.education_required || '暂无' }}
|
|
|
- <el-button type="text" class="edit-title-btn" @click="startEditEducation">
|
|
|
- <el-icon><Edit /></el-icon>
|
|
|
- </el-button>
|
|
|
- </div>
|
|
|
- <div class="title-edit-container" v-else>
|
|
|
- <el-select v-model="editingEducation" placeholder="请选择学历要求" style="width: 100%">
|
|
|
- <el-option label="不限" value="不限" />
|
|
|
- <el-option label="高中" value="高中" />
|
|
|
- <el-option label="大专" value="大专" />
|
|
|
- <el-option label="本科" value="本科" />
|
|
|
- <el-option label="硕士" value="硕士" />
|
|
|
- <el-option label="博士" value="博士" />
|
|
|
- </el-select>
|
|
|
- <div class="title-edit-actions">
|
|
|
- <el-button size="small" @click="cancelEditEducation">取消</el-button>
|
|
|
- <el-button size="small" type="primary" @click="saveEducation">保存</el-button>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <!-- 所属部门 -->
|
|
|
- <div class="detail-item">
|
|
|
- <div class="detail-label">所属部门</div>
|
|
|
- <div class="detail-value" v-if="!isEditingDepartment">
|
|
|
- {{ positionData.department || '暂无' }}
|
|
|
- <el-button type="text" class="edit-title-btn" @click="startEditDepartment">
|
|
|
- <el-icon><Edit /></el-icon>
|
|
|
- </el-button>
|
|
|
- </div>
|
|
|
- <div class="title-edit-container" v-else>
|
|
|
- <el-input
|
|
|
- v-model="editingDepartment"
|
|
|
- placeholder="请输入所属部门"
|
|
|
- maxlength="30"
|
|
|
- show-word-limit
|
|
|
- />
|
|
|
- <div class="title-edit-actions">
|
|
|
- <el-button size="small" @click="cancelEditDepartment">取消</el-button>
|
|
|
- <el-button size="small" type="primary" @click="saveDepartment">保存</el-button>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <div class="detail-item">
|
|
|
- <div class="detail-label">职位状态</div>
|
|
|
- <div class="detail-value">
|
|
|
- <el-tag :type="getStatusType(positionData.job_type)">
|
|
|
- {{ getStatusText(positionData.job_type) }}
|
|
|
- </el-tag>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <div class="detail-item">
|
|
|
- <div class="detail-label">截止日期</div>
|
|
|
- <div class="detail-value" v-if="!isEditingEndDate">
|
|
|
- {{ positionData.end_date || '暂无' }}
|
|
|
- <el-button type="text" class="edit-title-btn" @click="startEditEndDate">
|
|
|
- <el-icon><Edit /></el-icon>
|
|
|
- </el-button>
|
|
|
- </div>
|
|
|
- <div class="title-edit-container" v-else>
|
|
|
- <el-date-picker
|
|
|
- v-model="editingEndDate"
|
|
|
- type="date"
|
|
|
- placeholder="请选择截止日期"
|
|
|
- format="YYYY-MM-DD"
|
|
|
- value-format="YYYY-MM-DD"
|
|
|
- style="width: 100%"
|
|
|
- />
|
|
|
- <div class="title-edit-actions">
|
|
|
- <el-button size="small" @click="cancelEditEndDate">取消</el-button>
|
|
|
- <el-button size="small" type="primary" @click="saveEndDate">保存</el-button>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <div class="detail-item">
|
|
|
- <div class="detail-label">职位要求</div>
|
|
|
- <div class="detail-value html-content" v-if="!isEditingRequirements" v-html="positionData.requirements"></div>
|
|
|
- <el-button type="text" class="edit-title-btn" @click="startEditRequirements" v-if="!isEditingRequirements">
|
|
|
- <el-icon><Edit /></el-icon>
|
|
|
- </el-button>
|
|
|
- <div class="title-edit-container" v-else>
|
|
|
- <el-input
|
|
|
- v-model="editingRequirements"
|
|
|
- type="textarea"
|
|
|
- rows="6"
|
|
|
- placeholder="请输入职位要求"
|
|
|
- maxlength="1000"
|
|
|
- show-word-limit
|
|
|
- />
|
|
|
- <div class="title-edit-actions">
|
|
|
- <el-button size="small" @click="cancelEditRequirements">取消</el-button>
|
|
|
- <el-button size="small" type="primary" @click="saveRequirements">保存</el-button>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <div class="detail-item">
|
|
|
- <div class="detail-label">职位描述</div>
|
|
|
- <div class="detail-value html-content" v-if="!isEditingDescription" v-html="positionData.description"></div>
|
|
|
- <el-button type="text" class="edit-title-btn" @click="startEditDescription" v-if="!isEditingDescription">
|
|
|
- <el-icon><Edit /></el-icon>
|
|
|
- </el-button>
|
|
|
- <div class="title-edit-container" v-else>
|
|
|
- <el-input
|
|
|
- v-model="editingDescription"
|
|
|
- type="textarea"
|
|
|
- rows="6"
|
|
|
- placeholder="请输入职位描述"
|
|
|
- maxlength="1000"
|
|
|
- show-word-limit
|
|
|
- />
|
|
|
- <div class="title-edit-actions">
|
|
|
- <el-button size="small" @click="cancelEditDescription">取消</el-button>
|
|
|
- <el-button size="small" type="primary" @click="saveDescription">保存</el-button>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <!-- 在 detail-item 列表中添加能力标签部分 -->
|
|
|
- <div class="detail-item">
|
|
|
- <div class="detail-label">能力标签</div>
|
|
|
- <div class="detail-value" v-if="!isEditingCompetency">
|
|
|
- <el-tag
|
|
|
- v-for="tag in positionData.competency_tags"
|
|
|
- :key="tag.id"
|
|
|
- effect="plain"
|
|
|
- class="competency-tag"
|
|
|
- >
|
|
|
- {{ tag.name }}
|
|
|
- </el-tag>
|
|
|
- <el-button type="text" class="edit-title-btn" @click="startEditCompetency">
|
|
|
- <el-icon><Edit /></el-icon>
|
|
|
- </el-button>
|
|
|
- </div>
|
|
|
- <div class="title-edit-container" v-else>
|
|
|
- <el-select
|
|
|
- v-model="selectedCompetencies"
|
|
|
- multiple
|
|
|
- filterable
|
|
|
- placeholder="请选择能力标签"
|
|
|
- style="width: 100%"
|
|
|
-
|
|
|
- >
|
|
|
- <el-option
|
|
|
- v-for="tag in competencyTags"
|
|
|
- :key="tag.id"
|
|
|
- :label="tag.name"
|
|
|
- :value="tag.id"
|
|
|
- >
|
|
|
- </el-option>
|
|
|
- </el-select>
|
|
|
- <div class="title-edit-actions">
|
|
|
- <el-button size="small" @click="cancelEditCompetency">取消</el-button>
|
|
|
- <el-button size="small" type="primary" @click="saveCompetency">保存</el-button>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </el-card>
|
|
|
-
|
|
|
- <!-- 右侧状态信息 -->
|
|
|
- <div class="status-cards">
|
|
|
- <el-card class="status-card">
|
|
|
- <div class="section-title">
|
|
|
- <div class="section-line"></div>
|
|
|
- <span>职位状态</span>
|
|
|
- </div>
|
|
|
- <div class="status-switch">
|
|
|
- <el-switch
|
|
|
- v-model="positionStatus"
|
|
|
- inactive-text=""
|
|
|
- @change="handleStatusChange"
|
|
|
- />
|
|
|
- <span class="status-text">{{ positionStatus ? '开启职位' : '关闭职位' }}</span>
|
|
|
- </div>
|
|
|
- </el-card>
|
|
|
-
|
|
|
- <el-card class="status-card">
|
|
|
- <div class="section-title">
|
|
|
- <div class="section-line"></div>
|
|
|
- <span>职位用途</span>
|
|
|
- <el-button type="text" class="edit-btn" @click="handleEditUsage">编辑</el-button>
|
|
|
- </div>
|
|
|
- <div class="usage-content">
|
|
|
- <div class="usage-label">职位用途</div>
|
|
|
- <div class="usage-value">正式招聘</div>
|
|
|
- </div>
|
|
|
- </el-card>
|
|
|
-
|
|
|
- <el-card class="status-card">
|
|
|
- <div class="section-title">
|
|
|
- <div class="section-line"></div>
|
|
|
- <span>招聘流程</span>
|
|
|
- <el-button type="text" class="edit-btn" @click="handleEditProcess">设置流程</el-button>
|
|
|
- </div>
|
|
|
- <div class="process-steps">
|
|
|
- <div
|
|
|
- v-for="(step, index) in recruitmentProcess"
|
|
|
- :key="step.id"
|
|
|
- class="process-step"
|
|
|
- :class="{ 'disabled': !step.active }"
|
|
|
- >
|
|
|
- <div class="step-number">{{ index + 1 }}</div>
|
|
|
- <div class="step-content">
|
|
|
- <div class="step-title">{{ step.name }}</div>
|
|
|
- <div class="step-desc">{{ step.description }}</div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </el-card>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <!-- 添加招聘流程编辑对话框 -->
|
|
|
- <el-dialog
|
|
|
- title="设置招聘流程"
|
|
|
- v-model="showProcessDialog"
|
|
|
- width="500px"
|
|
|
- :close-on-click-modal="false"
|
|
|
- >
|
|
|
- <div class="process-dialog-content">
|
|
|
- <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-icon><Plus /></el-icon>
|
|
|
- </el-button>
|
|
|
- </div>
|
|
|
-
|
|
|
- <div
|
|
|
- class="process-edit-item"
|
|
|
- :class="{ 'highlight': step.active }"
|
|
|
- >
|
|
|
- <div class="process-number">{{ index + 1 }}</div>
|
|
|
- <div class="process-edit-content">
|
|
|
- <div>{{ step.name }}</div>
|
|
|
- <div class="process-edit-desc">{{ step.description }}</div>
|
|
|
- </div>
|
|
|
- <el-button
|
|
|
- type="danger"
|
|
|
- size="small"
|
|
|
- plain
|
|
|
- class="delete-btn"
|
|
|
- @click="deleteProcessStep(index)"
|
|
|
- >
|
|
|
- 删除
|
|
|
- </el-button>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <!-- 最后一个步骤下方的加号按钮 -->
|
|
|
- <div class="add-process-btn">
|
|
|
- <el-button type="text" @click="showStepOptions(recruitmentProcess.length, $event)">
|
|
|
- <el-icon><Plus /></el-icon>
|
|
|
- </el-button>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <!-- 添加选项菜单 -->
|
|
|
- <div
|
|
|
- v-if="showOptionsMenu"
|
|
|
- class="process-options-menu"
|
|
|
- :style="{ top: menuPosition.top, left: menuPosition.left }"
|
|
|
- @click.stop
|
|
|
- >
|
|
|
- <div
|
|
|
- v-for="option in processStepOptions"
|
|
|
- :key="option.value"
|
|
|
- class="process-option-item"
|
|
|
- @click="addSelectedStepType(option.value, option.label)"
|
|
|
- >
|
|
|
- {{ option.label }}
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <template #footer>
|
|
|
- <span class="dialog-footer">
|
|
|
- <el-button @click="cancelEditProcess">取消</el-button>
|
|
|
- <el-button type="primary" @click="saveProcess">确定</el-button>
|
|
|
- </span>
|
|
|
- </template>
|
|
|
- </el-dialog>
|
|
|
-
|
|
|
- <!-- AI视频配置对话框 -->
|
|
|
- <el-drawer
|
|
|
- title="AI视频"
|
|
|
- v-model="showAIVideoDialog"
|
|
|
- direction="rtl"
|
|
|
- size="60%"
|
|
|
- :close-on-click-modal="false"
|
|
|
- class="ai-video-drawer"
|
|
|
- :destroy-on-close="false"
|
|
|
- >
|
|
|
- <!-- 步骤指示器 -->
|
|
|
- <div class="ai-video-steps">
|
|
|
- <div class="step-item" :class="{ 'active': currentStep === 1 }" @click="jumpToStep(1)">
|
|
|
- <div class="step-number">1</div>
|
|
|
- <div class="step-title">考察能力</div>
|
|
|
- </div>
|
|
|
- <div class="step-line" :class="{ 'active-line': currentStep >= 2 }"></div>
|
|
|
- <div class="step-item" :class="{ 'active': currentStep === 2 }" @click="jumpToStep(2)">
|
|
|
- <div class="step-number">2</div>
|
|
|
- <div class="step-title">面试题目</div>
|
|
|
- </div>
|
|
|
- <div class="step-line" :class="{ 'active-line': currentStep >= 3 }"></div>
|
|
|
- <div class="step-item" :class="{ 'active': currentStep === 3 }" @click="jumpToStep(3)">
|
|
|
- <div class="step-number">3</div>
|
|
|
- <div class="step-title">系统设置</div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <!-- 步骤1:考察能力 -->
|
|
|
- <div v-if="currentStep === 1" class="ai-video-content">
|
|
|
- <div class="ai-video-options">
|
|
|
- <p class="option-tip">请选择要优先使用的考察能力,也可以点击"下一步"直接出题</p>
|
|
|
-
|
|
|
- <div class="new-feature-tip">
|
|
|
- <span class="new-tag">NEW</span>
|
|
|
- AI根据岗位信息生成的能力,创建完步骤后,会自动将选择的新智能能力加入到该职位的考察能力列表中。
|
|
|
- </div>
|
|
|
-
|
|
|
- <div class="ability-options">
|
|
|
-
|
|
|
- <el-checkbox v-model="aiVideoOptions.qualityControl" label="质量控制">
|
|
|
- <div class="ability-label">质量控制</div>
|
|
|
- </el-checkbox>
|
|
|
-
|
|
|
- <el-checkbox v-model="aiVideoOptions.teamwork" label="团队协作">
|
|
|
- <div class="ability-label">团队协作</div>
|
|
|
- </el-checkbox>
|
|
|
-
|
|
|
- <el-checkbox v-model="aiVideoOptions.problemSolving" label="问题解决">
|
|
|
- <div class="ability-label">问题解决</div>
|
|
|
- </el-checkbox>
|
|
|
-
|
|
|
- <el-checkbox v-model="aiVideoOptions.dataAnalysis" label="问题分析">
|
|
|
- <div class="ability-label">问题分析</div>
|
|
|
- </el-checkbox>
|
|
|
-
|
|
|
- <!-- <el-checkbox v-model="aiVideoOptions.taskManagement" label="分析问题">
|
|
|
- <div class="ability-label">分析问题</div>
|
|
|
- </el-checkbox>
|
|
|
-
|
|
|
- <el-checkbox v-model="aiVideoOptions.productivity" label="生产效率">
|
|
|
- <div class="ability-label">生产效率</div>
|
|
|
- </el-checkbox>
|
|
|
-
|
|
|
- <el-checkbox v-model="aiVideoOptions.manufacturingSkills" label="制造制作技能">
|
|
|
- <div class="ability-label">制造制作技能</div>
|
|
|
- </el-checkbox>
|
|
|
-
|
|
|
- <el-checkbox v-model="aiVideoOptions.customerService" label="客户服务技能">
|
|
|
- <div class="ability-label">客户服务技能</div>
|
|
|
- </el-checkbox>
|
|
|
-
|
|
|
- <el-checkbox v-model="aiVideoOptions.resistanceToPressure" label="抗压能力-客户服务">
|
|
|
- <div class="ability-label">抗压能力-客户服务</div>
|
|
|
- </el-checkbox>
|
|
|
-
|
|
|
- <el-checkbox v-model="aiVideoOptions.workDefinition" label="工作稳定-宣誓">
|
|
|
- <div class="ability-label">工作稳定-宣誓</div>
|
|
|
- </el-checkbox>
|
|
|
-
|
|
|
- <el-checkbox v-model="aiVideoOptions.selfIntroduction" label="自我介绍-宣誓">
|
|
|
- <div class="ability-label">自我介绍-宣誓</div>
|
|
|
- </el-checkbox>
|
|
|
-
|
|
|
- <el-checkbox v-model="aiVideoOptions.detailOrientation" label="细节关注">
|
|
|
- <div class="ability-label">细节关注</div>
|
|
|
- </el-checkbox>
|
|
|
-
|
|
|
- <el-checkbox v-model="aiVideoOptions.logicalThinking" label="清晰逻辑思维">
|
|
|
- <div class="ability-label">清晰逻辑思维</div>
|
|
|
- </el-checkbox>
|
|
|
-
|
|
|
- <el-checkbox v-model="aiVideoOptions.safetyAwareness" label="安全意识">
|
|
|
- <div class="ability-label">安全意识</div>
|
|
|
- </el-checkbox>
|
|
|
-
|
|
|
- <el-checkbox v-model="aiVideoOptions.customerServiceAwareness" label="客户服务意识">
|
|
|
- <div class="ability-label">客户服务意识</div>
|
|
|
- </el-checkbox>
|
|
|
-
|
|
|
- <el-checkbox v-model="aiVideoOptions.timeManagement" label="时间管理">
|
|
|
- <div class="ability-label">时间管理</div>
|
|
|
- </el-checkbox>
|
|
|
-
|
|
|
- <el-checkbox v-model="aiVideoOptions.teamCooperation" label="团队合作">
|
|
|
- <div class="ability-label">团队合作</div>
|
|
|
- </el-checkbox>
|
|
|
-
|
|
|
- <el-checkbox v-model="aiVideoOptions.timeManagementSkills" label="时间管理能力">
|
|
|
- <div class="ability-label">时间管理能力</div>
|
|
|
- </el-checkbox>
|
|
|
-
|
|
|
- <el-checkbox v-model="aiVideoOptions.productEvaluation" label="品鉴评估能力">
|
|
|
- <div class="ability-label">品鉴评估能力</div>
|
|
|
- </el-checkbox>
|
|
|
-
|
|
|
- <el-checkbox v-model="aiVideoOptions.basicQualifications" label="基本素质">
|
|
|
- <div class="ability-label">基本素质</div>
|
|
|
- </el-checkbox>
|
|
|
-
|
|
|
- <el-checkbox v-model="aiVideoOptions.networkDeployment" label="网位布署">
|
|
|
- <div class="ability-label">网位布署</div>
|
|
|
- </el-checkbox>
|
|
|
-
|
|
|
- <el-checkbox v-model="aiVideoOptions.remoteCooperation" label="泡通协作">
|
|
|
- <div class="ability-label">泡通协作</div>
|
|
|
- </el-checkbox>
|
|
|
-
|
|
|
- <el-checkbox v-model="aiVideoOptions.executionAbility" label="执行能力">
|
|
|
- <div class="ability-label">执行能力</div>
|
|
|
- </el-checkbox>
|
|
|
-
|
|
|
- <el-checkbox v-model="aiVideoOptions.selfDiscipline" label="自驱力">
|
|
|
- <div class="ability-label">自驱力</div>
|
|
|
- </el-checkbox>
|
|
|
-
|
|
|
- <el-checkbox v-model="aiVideoOptions.managementAbility" label="管理能力">
|
|
|
- <div class="ability-label">管理能力</div>
|
|
|
- </el-checkbox>
|
|
|
-
|
|
|
- <el-checkbox v-model="aiVideoOptions.customerOrientation" label="客户导向">
|
|
|
- <div class="ability-label">客户导向</div>
|
|
|
- </el-checkbox>
|
|
|
-
|
|
|
- <el-checkbox v-model="aiVideoOptions.stability" label="稳定性">
|
|
|
- <div class="ability-label">稳定性</div>
|
|
|
- </el-checkbox>
|
|
|
-
|
|
|
- <el-checkbox v-model="aiVideoOptions.salesSkills" label="销售技巧">
|
|
|
- <div class="ability-label">销售技巧</div>
|
|
|
- </el-checkbox>
|
|
|
-
|
|
|
- <el-checkbox v-model="aiVideoOptions.responseAbility" label="应变能力">
|
|
|
- <div class="ability-label">应变能力</div>
|
|
|
- </el-checkbox> -->
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <!-- 步骤2:面试题目 -->
|
|
|
- <div v-if="currentStep === 2" class="ai-video-content">
|
|
|
- <div class="interview-settings">
|
|
|
- <div class="interview-header">
|
|
|
- <div class="interview-duration">
|
|
|
- <span>预计面试时长: </span>
|
|
|
- <span class="duration-value">0秒</span>
|
|
|
- <span class="duration-tip">拖动试题卡片可改变试题顺序</span>
|
|
|
- </div>
|
|
|
-
|
|
|
- <div class="interview-actions">
|
|
|
- <el-button type="primary" plain class="import-btn">
|
|
|
- <el-icon><Document /></el-icon>
|
|
|
- 导入题目
|
|
|
- </el-button>
|
|
|
- <el-button type="success" plain class="custom-btn">
|
|
|
- <el-icon><Plus /></el-icon>
|
|
|
- 自定义题目
|
|
|
- </el-button>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <div class="interview-mode">
|
|
|
- <span>面试问答方式: </span>
|
|
|
- <span class="mode-value">传统读题模式</span>
|
|
|
- <el-button type="primary" plain size="small" class="customize-btn">定制面试间</el-button>
|
|
|
- </div>
|
|
|
-
|
|
|
- <div class="interview-questions-container">
|
|
|
- <div class="no-questions">
|
|
|
- <p>暂无题目</p>
|
|
|
- <p class="ai-tip">点击"AI自动组题"按钮</p>
|
|
|
- <p class="ai-tip">可根据您选择的能力类型一键组题</p>
|
|
|
- <el-button type="success" class="auto-generate-btn">AI自动组题</el-button>
|
|
|
- </div>
|
|
|
-
|
|
|
- <div class="question-list">
|
|
|
- <div v-for="(question, index) in chatQuestions" :key="index" class="question-card">
|
|
|
- <div class="question-header">
|
|
|
- <div class="question-title">
|
|
|
- <span class="question-number">题目{{ index + 1 }}</span>
|
|
|
- <span>{{ question.title }}</span>
|
|
|
- </div>
|
|
|
- <div class="question-actions">
|
|
|
- <div class="weight-control">
|
|
|
- <span class="weight-label">权重占比:</span>
|
|
|
- <el-input-number
|
|
|
- v-model="question.weight"
|
|
|
- :min="0"
|
|
|
- :max="100"
|
|
|
- :step="1"
|
|
|
- size="small"
|
|
|
- controls-position="right"
|
|
|
- >
|
|
|
- <template #suffix>%</template>
|
|
|
- </el-input-number>
|
|
|
- </div>
|
|
|
- <div class="answer-limit">
|
|
|
- <span class="answer-label">最多回答次数</span>
|
|
|
- <el-select v-model="question.maxAnswers" size="small" placeholder="请选择">
|
|
|
- <el-option label="1次" :value="1" />
|
|
|
- <el-option label="2次" :value="2" />
|
|
|
- <el-option label="3次" :value="3" />
|
|
|
- </el-select>
|
|
|
- </div>
|
|
|
- <el-button type="text" @click="editQuestion(index)">
|
|
|
- <el-icon><Edit /></el-icon>
|
|
|
- </el-button>
|
|
|
- <el-button type="text" @click="deleteQuestion(index)">
|
|
|
- <el-icon><Delete /></el-icon>
|
|
|
- </el-button>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <div class="question-info">
|
|
|
- <div class="info-item">
|
|
|
- <span class="info-label">考察能力:</span>
|
|
|
- <span>{{ question.ability }}</span>
|
|
|
- </div>
|
|
|
- <div class="info-item">
|
|
|
- <span class="info-label">面试内容:</span>
|
|
|
- <span>{{ question.content }}</span>
|
|
|
- </div>
|
|
|
- <div class="info-item">
|
|
|
- <span class="info-label">对话目标:</span>
|
|
|
- <span>{{ question.target }}</span>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <div class="multi-dimension-questions">
|
|
|
- <div class="dimension-title">多维度能力测评题</div>
|
|
|
- <div class="dimension-list">
|
|
|
- <div v-for="ability in selectedAbilities" :key="ability.value" class="dimension-item">
|
|
|
- <div class="dimension-header">
|
|
|
- <span>{{ ability.label }}</span>
|
|
|
- <span class="new-tag" v-if="ability.isNew">NEW</span>
|
|
|
- <el-icon class="expand-icon"><ArrowDown /></el-icon>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <!-- 步骤3:系统设置 -->
|
|
|
- <div v-if="currentStep === 3" class="ai-video-content">
|
|
|
- <div class="system-settings">
|
|
|
- <!-- 排名区间设置 -->
|
|
|
- <div class="setting-section">
|
|
|
- <div class="section-header">排名区间设置</div>
|
|
|
- <div class="rank-settings">
|
|
|
- <div class="rank-range">
|
|
|
- <span>排名前</span>
|
|
|
- <div class="range-inputs">
|
|
|
- <el-input v-model="rankSettings.min" size="small" class="percent-input">
|
|
|
- <template #suffix>%</template>
|
|
|
- </el-input>
|
|
|
- <span>-</span>
|
|
|
- <el-input v-model="rankSettings.max" size="small" class="percent-input">
|
|
|
- <template #suffix>%</template>
|
|
|
- </el-input>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <div class="score-display">
|
|
|
- <span>分数</span>
|
|
|
- <div class="score-range">{{ rankSettings.minScore }} - {{ rankSettings.maxScore }} 分</div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <el-button type="primary" plain class="add-rank-btn">
|
|
|
- <el-icon><Plus /></el-icon>
|
|
|
- 添加排名区间
|
|
|
- </el-button>
|
|
|
- </div>
|
|
|
-
|
|
|
- <!-- AI视频有效期 -->
|
|
|
- <div class="setting-section">
|
|
|
- <div class="section-header">AI视频有效期</div>
|
|
|
- <div class="validity-setting">
|
|
|
- <el-switch v-model="validityEnabled" />
|
|
|
- <span class="validity-label">开启AI视频有效期</span>
|
|
|
- </div>
|
|
|
- <div class="validity-tip">暂未设置,设置后候选人超过有效期则不可进入</div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <!-- AI模型版本 -->
|
|
|
- <div class="setting-section">
|
|
|
- <div class="section-header">AI模型版本</div>
|
|
|
- <el-select v-model="aiModelVersion" placeholder="请选择" class="model-select">
|
|
|
- <el-option label="标准版" value="standard"></el-option>
|
|
|
- </el-select>
|
|
|
- </div>
|
|
|
-
|
|
|
- <!-- 评分AI -->
|
|
|
- <div class="setting-section">
|
|
|
- <div class="section-header">评分AI</div>
|
|
|
- <!-- 评分AI设置内容 -->
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <template #footer>
|
|
|
- <div class="drawer-footer">
|
|
|
- <el-button v-if="currentStep > 1" @click="prevStep">上一步</el-button>
|
|
|
- <el-button @click="cancelAIVideoConfig">取消</el-button>
|
|
|
- <el-button v-if="currentStep < 3" type="primary" @click="nextStep">下一步</el-button>
|
|
|
- <el-button v-else type="success" @click="finishConfig">新增</el-button>
|
|
|
- </div>
|
|
|
- </template>
|
|
|
- </el-drawer>
|
|
|
-
|
|
|
- <!-- 在 template 中添加视频宣讲弹窗 -->
|
|
|
- <el-dialog
|
|
|
- title="新增视频宣讲"
|
|
|
- v-model="showVideoLectureDialog"
|
|
|
- width="35%"
|
|
|
- :close-on-click-modal="false"
|
|
|
- class="video-lecture-dialog"
|
|
|
- >
|
|
|
- <div class="video-lecture-form">
|
|
|
- <!-- <div class="form-item">
|
|
|
- <div class="form-label">步骤名称</div>
|
|
|
- <el-input
|
|
|
- v-model="videoLectureForm.title"
|
|
|
- placeholder="请输入步骤名称"
|
|
|
- maxlength="30"
|
|
|
- show-word-limit
|
|
|
- />
|
|
|
- </div> -->
|
|
|
-
|
|
|
- <div class="form-item">
|
|
|
- <div class="form-label">上传视频</div>
|
|
|
- <el-upload
|
|
|
- class="video-uploader"
|
|
|
- action="#"
|
|
|
- :auto-upload="false"
|
|
|
- :show-file-list="false"
|
|
|
- accept="video/*"
|
|
|
- >
|
|
|
- <div class="upload-area">
|
|
|
- <el-icon><Plus /></el-icon>
|
|
|
- <div class="upload-text">上传文件大小不超过500M</div>
|
|
|
- </div>
|
|
|
- </el-upload>
|
|
|
- </div>
|
|
|
-
|
|
|
- <div class="form-item">
|
|
|
- <div class="form-label">视频简介</div>
|
|
|
- <el-input
|
|
|
- v-model="videoLectureForm.description"
|
|
|
- type="textarea"
|
|
|
- rows="4"
|
|
|
- placeholder="视频简介会显示在视频下方的标题下方"
|
|
|
- maxlength="200"
|
|
|
- show-word-limit
|
|
|
- />
|
|
|
- </div>
|
|
|
-
|
|
|
- <div class="form-item">
|
|
|
- <div class="form-label">播放设置</div>
|
|
|
- <el-radio-group v-model="videoLectureForm.broadcastType">
|
|
|
- <el-radio label="required">必须看完</el-radio>
|
|
|
- <el-radio label="optional">看过即可</el-radio>
|
|
|
- </el-radio-group>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <template #footer>
|
|
|
- <span class="dialog-footer">
|
|
|
- <el-button @click="cancelVideoLecture">取消</el-button>
|
|
|
- <el-button type="primary" @click="confirmVideoLecture">确认</el-button>
|
|
|
- </span>
|
|
|
- </template>
|
|
|
- </el-dialog>
|
|
|
-
|
|
|
- <!-- AI实时对话抽屉 -->
|
|
|
- <el-drawer
|
|
|
- title="AI实时对话"
|
|
|
- v-model="showAIChatDialog"
|
|
|
- direction="rtl"
|
|
|
- size="60%"
|
|
|
- :close-on-click-modal="false"
|
|
|
- class="ai-chat-drawer"
|
|
|
- :destroy-on-close="false"
|
|
|
- >
|
|
|
- <div class="ai-chat-content">
|
|
|
- <!-- AI实时对话的配置内容 -->
|
|
|
- <div class="chat-settings">
|
|
|
- <div class="section-title">
|
|
|
- <div class="section-line"></div>
|
|
|
- <span>对话设置</span>
|
|
|
- </div>
|
|
|
-
|
|
|
- <!-- 添加按钮组 -->
|
|
|
- <div class="chat-actions">
|
|
|
- <el-button type="primary" plain @click="handleAddQuestion">
|
|
|
- <el-icon><Plus /></el-icon>
|
|
|
- 添加问题
|
|
|
- </el-button>
|
|
|
- <el-button type="success" plain @click="handleImportQuestion">
|
|
|
- <el-icon><Document /></el-icon>
|
|
|
- 导入问题
|
|
|
- </el-button>
|
|
|
- </div>
|
|
|
-
|
|
|
- <!-- 添加问题列表容器 -->
|
|
|
- <div class="chat-questions">
|
|
|
- <div v-if="chatQuestions.length === 0" class="empty-questions">
|
|
|
- <p>暂无问题</p>
|
|
|
- <p class="tip-text">点击"添加问题"或"导入问题"添加面试问题</p>
|
|
|
- </div>
|
|
|
- <div v-else class="question-list">
|
|
|
- <div v-for="(question, index) in chatQuestions" :key="index" class="question-card">
|
|
|
- <div class="question-header">
|
|
|
- <div class="question-title">
|
|
|
- <span class="question-number">题目{{ index + 1 }}</span>
|
|
|
- <span>{{ question.title }}</span>
|
|
|
- </div>
|
|
|
- <div class="question-actions">
|
|
|
- <div class="weight-control">
|
|
|
- <span class="weight-label">权重占比:</span>
|
|
|
- <el-input-number
|
|
|
- v-model="question.weight"
|
|
|
- :min="0"
|
|
|
- :max="100"
|
|
|
- :step="1"
|
|
|
- size="small"
|
|
|
- controls-position="right"
|
|
|
- >
|
|
|
- <template #suffix>%</template>
|
|
|
- </el-input-number>
|
|
|
- </div>
|
|
|
- <div class="answer-limit">
|
|
|
- <span class="answer-label">最多回答次数</span>
|
|
|
- <el-select v-model="question.maxAnswers" size="small" placeholder="请选择">
|
|
|
- <el-option label="1次" :value="1" />
|
|
|
- <el-option label="2次" :value="2" />
|
|
|
- <el-option label="3次" :value="3" />
|
|
|
- </el-select>
|
|
|
- </div>
|
|
|
- <el-button type="text" @click="editQuestion(index)">
|
|
|
- <el-icon><Edit /></el-icon>
|
|
|
- </el-button>
|
|
|
- <el-button type="text" @click="deleteQuestion(index)">
|
|
|
- <el-icon><Delete /></el-icon>
|
|
|
- </el-button>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <div class="question-info">
|
|
|
- <div class="info-item">
|
|
|
- <span class="info-label">考察能力:</span>
|
|
|
- <span>{{ question.ability }}</span>
|
|
|
- </div>
|
|
|
- <div class="info-item">
|
|
|
- <span class="info-label">面试内容:</span>
|
|
|
- <span>{{ question.content }}</span>
|
|
|
- </div>
|
|
|
- <div class="info-item">
|
|
|
- <span class="info-label">对话目标:</span>
|
|
|
- <span>{{ question.target }}</span>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <template #footer>
|
|
|
- <div class="drawer-footer">
|
|
|
- <el-button @click="cancelAIChatConfig">取消</el-button>
|
|
|
- <el-button type="primary" @click="handleAIChatConfig">确认</el-button>
|
|
|
- </div>
|
|
|
- </template>
|
|
|
- </el-drawer>
|
|
|
-
|
|
|
- <!-- 在 template 中添加问题编辑弹框 -->
|
|
|
- <el-dialog
|
|
|
- title="添加问题"
|
|
|
- v-model="showQuestionDialog"
|
|
|
- width="500px"
|
|
|
- :close-on-click-modal="false"
|
|
|
- class="question-dialog"
|
|
|
- >
|
|
|
- <div class="question-form">
|
|
|
- <div class="form-item">
|
|
|
- <div class="form-label">
|
|
|
- 标题<span class="required">*</span>
|
|
|
- </div>
|
|
|
- <el-input
|
|
|
- v-model="questionForm.title"
|
|
|
- placeholder="请输入标题"
|
|
|
- maxlength="15"
|
|
|
- show-word-limit
|
|
|
- />
|
|
|
- </div>
|
|
|
-
|
|
|
- <div class="form-item">
|
|
|
- <div class="form-label">考察能力</div>
|
|
|
- <el-select
|
|
|
- v-model="questionForm.ability"
|
|
|
- placeholder="请选择考察能力"
|
|
|
- class="full-width"
|
|
|
- >
|
|
|
- <el-option label="深入考察抗压能力" value="pressure" />
|
|
|
- <el-option label="候选人回答中包含一个详细的案例" value="case" />
|
|
|
- <el-option label="获取候选人明确的毕业院校和专业" value="education" />
|
|
|
- </el-select>
|
|
|
- </div>
|
|
|
-
|
|
|
- <div class="form-item">
|
|
|
- <div class="form-label">
|
|
|
- 面试内容<span class="required">*</span>
|
|
|
- </div>
|
|
|
- <el-input
|
|
|
- v-model="questionForm.content"
|
|
|
- type="textarea"
|
|
|
- rows="4"
|
|
|
- placeholder="请输入面试内容"
|
|
|
- maxlength="300"
|
|
|
- show-word-limit
|
|
|
- />
|
|
|
- </div>
|
|
|
-
|
|
|
- <div class="form-item">
|
|
|
- <div class="form-label">对话目标</div>
|
|
|
- <el-input
|
|
|
- v-model="questionForm.target"
|
|
|
- type="textarea"
|
|
|
- rows="3"
|
|
|
- placeholder="输入你想在对话中达成的目标,示例:
|
|
|
-• 深入考察抗压能力
|
|
|
-• 候选人回答中包含一个详细的案例
|
|
|
-• 获取候选人明确的毕业院校和专业"
|
|
|
- maxlength="100"
|
|
|
- show-word-limit
|
|
|
- />
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <template #footer>
|
|
|
- <span class="dialog-footer">
|
|
|
- <el-button @click="cancelAddQuestion">取消</el-button>
|
|
|
- <el-button type="primary" @click="confirmAddQuestion">确认</el-button>
|
|
|
- </span>
|
|
|
- </template>
|
|
|
- </el-dialog>
|
|
|
-
|
|
|
- <!-- 修改资料收集对话框模板 -->
|
|
|
- <el-dialog
|
|
|
- title="资料收集"
|
|
|
- v-model="showDataCollectionDialog"
|
|
|
- width="500px"
|
|
|
- :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>
|
|
|
- <div class="action-right">
|
|
|
- <el-icon class="action-icon"><Document /></el-icon>
|
|
|
- <el-icon class="action-icon"><Delete /></el-icon>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <!-- 设置区域 -->
|
|
|
- <div class="question-settings">
|
|
|
- <div class="setting-item">
|
|
|
- <span>开启评分</span>
|
|
|
- <el-switch v-model="question.enableScoring" />
|
|
|
- </div>
|
|
|
- <div class="setting-item">
|
|
|
- <span>必答</span>
|
|
|
- <el-switch v-model="question.isRequired" />
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </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>
|
|
|
- </template>
|
|
|
- </el-dialog>
|
|
|
-
|
|
|
- <!-- 添加简历收集对话框 -->
|
|
|
- <el-dialog
|
|
|
- title="简历收集"
|
|
|
- v-model="showResumeCollectionDialog"
|
|
|
- width="500px"
|
|
|
- :close-on-click-modal="false"
|
|
|
- class="resume-collection-dialog"
|
|
|
- >
|
|
|
- <div class="resume-collection-form">
|
|
|
- <div class="form-item">
|
|
|
- <div class="form-label">步骤名称</div>
|
|
|
- <el-input
|
|
|
- v-model="resumeCollectionForm.title"
|
|
|
- placeholder="请输入步骤名称"
|
|
|
- maxlength="30"
|
|
|
- show-word-limit
|
|
|
- />
|
|
|
- </div>
|
|
|
-
|
|
|
- <!-- <div class="form-item">
|
|
|
- <div class="form-label">必填项</div>
|
|
|
- <el-switch v-model="resumeCollectionForm.isRequired" />
|
|
|
- <span class="switch-label">{{ resumeCollectionForm.isRequired ? '开启' : '关闭' }}</span>
|
|
|
- </div>
|
|
|
-
|
|
|
- <div class="resume-preview">
|
|
|
- <div class="preview-title">简历收集预览</div>
|
|
|
- <div class="preview-content">
|
|
|
- <div class="preview-item">
|
|
|
- <div class="item-label">姓名</div>
|
|
|
- <div class="item-input"></div>
|
|
|
- <div class="item-required" v-if="resumeCollectionForm.isRequired">*</div>
|
|
|
- </div>
|
|
|
- <div class="preview-item">
|
|
|
- <div class="item-label">手机号</div>
|
|
|
- <div class="item-input"></div>
|
|
|
- <div class="item-required" v-if="resumeCollectionForm.isRequired">*</div>
|
|
|
- </div>
|
|
|
- <div class="preview-item">
|
|
|
- <div class="item-label">邮箱</div>
|
|
|
- <div class="item-input"></div>
|
|
|
- <div class="item-required" v-if="resumeCollectionForm.isRequired">*</div>
|
|
|
- </div>
|
|
|
- <div class="preview-item">
|
|
|
- <div class="item-label">上传简历</div>
|
|
|
- <div class="item-upload">
|
|
|
- <el-icon><Plus /></el-icon>
|
|
|
- </div>
|
|
|
- <div class="item-required" v-if="resumeCollectionForm.isRequired">*</div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div> -->
|
|
|
- </div>
|
|
|
-
|
|
|
- <template #footer>
|
|
|
- <span class="dialog-footer">
|
|
|
- <el-button @click="cancelResumeCollection">取消</el-button>
|
|
|
- <el-button type="primary" @click="confirmResumeCollection">确认</el-button>
|
|
|
- </span>
|
|
|
- </template>
|
|
|
- </el-dialog>
|
|
|
-
|
|
|
- <!-- 添加代码测试对话框 -->
|
|
|
- <el-dialog
|
|
|
- title="添加代码笔试步骤"
|
|
|
- v-model="showCodeTestDialog"
|
|
|
- width="500px"
|
|
|
- :close-on-click-modal="false"
|
|
|
- class="code-test-dialog"
|
|
|
- >
|
|
|
- <div class="code-test-form">
|
|
|
- <div class="form-item">
|
|
|
- <div class="form-label">步骤名称</div>
|
|
|
- <el-input
|
|
|
- v-model="codeTestForm.title"
|
|
|
- placeholder="请输入步骤名称"
|
|
|
- maxlength="30"
|
|
|
- show-word-limit
|
|
|
- />
|
|
|
- </div>
|
|
|
-
|
|
|
- <div class="form-item">
|
|
|
- <div class="form-label">自动评判试卷</div>
|
|
|
- <el-switch v-model="codeTestForm.autoJudge" />
|
|
|
- <span class="switch-label">{{ codeTestForm.autoJudge ? '开启' : '关闭' }}</span>
|
|
|
- </div>
|
|
|
-
|
|
|
- <div class="form-item">
|
|
|
- <div class="form-label">添加考试试卷</div>
|
|
|
- <div class="test-paper-selector">
|
|
|
- <div class="empty-paper" v-if="!codeTestForm.selectedPaper">
|
|
|
- <el-button type="primary" plain @click="handleSelectPaper">
|
|
|
- <el-icon><Plus /></el-icon>
|
|
|
- 添加考卷
|
|
|
- </el-button>
|
|
|
- <p class="tip-text">多选时,考生会随机分配到一套试卷</p>
|
|
|
- </div>
|
|
|
- <div class="selected-paper" v-else>
|
|
|
- <div class="paper-info">
|
|
|
- <div class="paper-title">{{ codeTestForm.selectedPaper.title }}</div>
|
|
|
- <div class="paper-meta">
|
|
|
- <span>{{ codeTestForm.selectedPaper.questionCount }}道题</span>
|
|
|
- <span>{{ codeTestForm.selectedPaper.duration }}分钟</span>
|
|
|
- <span>{{ codeTestForm.selectedPaper.difficulty }}</span>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <div class="paper-actions">
|
|
|
- <el-button type="text" @click="handleViewPaper">查看</el-button>
|
|
|
- <el-button type="text" @click="handleChangePaper">更换</el-button>
|
|
|
- <el-button type="text" @click="handleRemovePaper">删除</el-button>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <template #footer>
|
|
|
- <span class="dialog-footer">
|
|
|
- <el-button @click="cancelCodeTest">取消</el-button>
|
|
|
- <el-button type="primary" @click="confirmCodeTest">确认</el-button>
|
|
|
- </span>
|
|
|
- </template>
|
|
|
- </el-dialog>
|
|
|
-
|
|
|
- <!-- 添加打字测试对话框 -->
|
|
|
- <el-drawer
|
|
|
- title="添加打字测试步骤"
|
|
|
- v-model="showTypingTestDialog"
|
|
|
- size="60%"
|
|
|
- :close-on-click-modal="false"
|
|
|
- class="typing-test-dialog"
|
|
|
- :destroy-on-close="false"
|
|
|
- >
|
|
|
- <div class="typing-test-form">
|
|
|
- <div class="form-item">
|
|
|
- <div class="form-label">选择文章</div>
|
|
|
- <div class="article-selection">
|
|
|
- <el-button type="primary" size="small" class="add-article-btn">
|
|
|
- <el-icon><Plus /></el-icon>
|
|
|
- 添加文章
|
|
|
- </el-button>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <div class="form-item">
|
|
|
- <div class="form-label">候选人选择文章方式</div>
|
|
|
- <el-radio-group v-model="typingTestForm.selectionMode">
|
|
|
- <el-radio label="random">随机抽取</el-radio>
|
|
|
- <el-radio label="self">候选人自主选择</el-radio>
|
|
|
- </el-radio-group>
|
|
|
- </div>
|
|
|
-
|
|
|
- <div class="form-item">
|
|
|
- <div class="form-label">测试时间</div>
|
|
|
- <div class="time-input-container">
|
|
|
- <el-input v-model="typingTestForm.duration" class="time-input" />
|
|
|
- <span class="time-unit">分钟</span>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <div class="form-item">
|
|
|
- <div class="form-label">登录界面预览图(建议尺寸1024*768像素,最大不要超过5M)</div>
|
|
|
- <el-upload
|
|
|
- class="preview-uploader"
|
|
|
- action="#"
|
|
|
- :auto-upload="false"
|
|
|
- :show-file-list="false"
|
|
|
- accept="image/*"
|
|
|
- >
|
|
|
- <div class="upload-area">
|
|
|
- <el-icon><Plus /></el-icon>
|
|
|
- <div class="upload-text">添加图片</div>
|
|
|
- </div>
|
|
|
- </el-upload>
|
|
|
- </div>
|
|
|
-
|
|
|
- <div class="form-item">
|
|
|
- <div class="form-label">注意事项内容(在登录界面显示)</div>
|
|
|
- <el-input
|
|
|
- v-model="typingTestForm.notes"
|
|
|
- type="textarea"
|
|
|
- rows="4"
|
|
|
- placeholder="请输入注意事项内容"
|
|
|
- maxlength="300"
|
|
|
- show-word-limit
|
|
|
- />
|
|
|
- </div>
|
|
|
-
|
|
|
- <div class="form-item">
|
|
|
- <div class="form-label">测试页面标题</div>
|
|
|
- <el-input
|
|
|
- v-model="typingTestForm.pageTitle"
|
|
|
- placeholder="测试页面标题"
|
|
|
- />
|
|
|
- </div>
|
|
|
-
|
|
|
- <div class="form-item">
|
|
|
- <div class="form-label">视频监控</div>
|
|
|
- <el-checkbox v-model="typingTestForm.videoMonitoring">视频监控</el-checkbox>
|
|
|
- </div>
|
|
|
-
|
|
|
- <div class="form-item">
|
|
|
- <div class="form-label">通过标准</div>
|
|
|
- <div class="criteria-options">
|
|
|
- <el-checkbox v-model="typingTestForm.passCriteria.speed">速度</el-checkbox>
|
|
|
- <el-checkbox v-model="typingTestForm.passCriteria.accuracy">正确率</el-checkbox>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <template #footer>
|
|
|
- <span class="dialog-footer">
|
|
|
- <el-button @click="cancelTypingTest">取消</el-button>
|
|
|
- <el-button type="primary" @click="confirmTypingTest">保存</el-button>
|
|
|
- </span>
|
|
|
- </template>
|
|
|
- </el-drawer>
|
|
|
- </div>
|
|
|
-</template>
|
|
|
-
|
|
|
-<script setup lang="ts">
|
|
|
-import { ref, reactive, onMounted, computed } from 'vue';
|
|
|
-import { useRouter, useRoute } from 'vue-router';
|
|
|
-import { ElMessage, ElMessageBox, ElDrawer } from 'element-plus';
|
|
|
-import * as api from '../list/api';
|
|
|
-import { Plus, Document, ArrowDown, Edit, Delete, InfoFilled } from '@element-plus/icons-vue';
|
|
|
-import { GetList } from '../../questionBank/classList/api';
|
|
|
-import { GetCompetencyList } from '../list/api';
|
|
|
-
|
|
|
-// 添加 ChatQuestion 接口定义
|
|
|
-interface ChatQuestion {
|
|
|
- title: string;
|
|
|
- ability: string;
|
|
|
- content: string;
|
|
|
- target: string;
|
|
|
- weight: number;
|
|
|
- maxAnswers: number;
|
|
|
-}
|
|
|
-
|
|
|
-// 添加 Paper 接口定义
|
|
|
-interface Paper {
|
|
|
- id: number;
|
|
|
- title: string;
|
|
|
- questionCount: number;
|
|
|
- duration: number;
|
|
|
- difficulty: string;
|
|
|
-}
|
|
|
-
|
|
|
-const router = useRouter();
|
|
|
-const route = useRoute();
|
|
|
-const positionId = ref(route.params.id as string);
|
|
|
-const positionStatus = ref(false);
|
|
|
-
|
|
|
-// 职位数据
|
|
|
-const positionData = reactive({
|
|
|
- title: '',
|
|
|
- job_category: '',
|
|
|
- job_type_display: '',
|
|
|
- city: '',
|
|
|
- location: [],
|
|
|
- location_str: '',
|
|
|
- address_detail: '',
|
|
|
- benefits: [],
|
|
|
- requirements: '',
|
|
|
- job_type: 0,
|
|
|
- salary_range: '',
|
|
|
- department: '',
|
|
|
- end_date: '',
|
|
|
- description: '',
|
|
|
- work_experience_required: '',
|
|
|
- education_required: '',
|
|
|
- competency_tags: []
|
|
|
-});
|
|
|
-
|
|
|
-// 招聘流程数据 - 修改为普通数组而非 ref 对象
|
|
|
-const recruitmentProcess = reactive([
|
|
|
- { id: 1, name: '待核验', description: '待核验', active: true },
|
|
|
- { id: 2, name: 'AI视频', description: 'AI视频', active: true },
|
|
|
- { id: 3, name: '已通过', description: '已通过', active: true },
|
|
|
- { id: 4, name: '已淘汰', description: '已淘汰', active: false }
|
|
|
-]);
|
|
|
-
|
|
|
-// 是否显示流程编辑对话框
|
|
|
-const showProcessDialog = ref(false);
|
|
|
-
|
|
|
-// 定义可选的流程步骤类型
|
|
|
-const processStepOptions = [
|
|
|
- { label: 'AI视频', value: 'ai_video' },
|
|
|
- { label: '视频宣讲', value: 'video_presentation' },
|
|
|
- { label: 'AI实时对话', value: 'ai_chat' },
|
|
|
- { label: '资料收集', value: 'data_collection' },
|
|
|
- { label: '简历收集', value: 'resume_collection' },
|
|
|
- { label: '代码测试', value: 'code_test' },
|
|
|
- { label: '打字测试', value: 'typing_test' }
|
|
|
-];
|
|
|
-
|
|
|
-// 当前选择的添加位置
|
|
|
-const currentAddIndex = ref(-1);
|
|
|
-// 是否显示选项菜单
|
|
|
-const showOptionsMenu = ref(false);
|
|
|
-// 选项菜单的位置
|
|
|
-const menuPosition = reactive({ top: '0px', left: '0px' });
|
|
|
-
|
|
|
-// AI视频对话框显示状态
|
|
|
-const showAIVideoDialog = ref(false);
|
|
|
-
|
|
|
-// AI视频配置选项
|
|
|
-const aiVideoOptions = reactive({
|
|
|
- qualityControl: true,
|
|
|
- teamwork: false,
|
|
|
- problemSolving: false,
|
|
|
- dataAnalysis: false,
|
|
|
- taskManagement: false,
|
|
|
- productivity: false,
|
|
|
- manufacturingSkills: false,
|
|
|
- customerService: false,
|
|
|
- resistanceToPressure: false,
|
|
|
- workDefinition: false,
|
|
|
- selfIntroduction: false,
|
|
|
- detailOrientation: false,
|
|
|
- logicalThinking: false,
|
|
|
- safetyAwareness: false,
|
|
|
- customerServiceAwareness: false,
|
|
|
- timeManagement: false,
|
|
|
- teamCooperation: false,
|
|
|
- timeManagementSkills: false,
|
|
|
- productEvaluation: false,
|
|
|
- basicQualifications: false,
|
|
|
- networkDeployment: false,
|
|
|
- remoteCooperation: false,
|
|
|
- executionAbility: false,
|
|
|
- selfDiscipline: false,
|
|
|
- managementAbility: false,
|
|
|
- customerOrientation: false,
|
|
|
- stability: false,
|
|
|
- salesSkills: false,
|
|
|
- responseAbility: false
|
|
|
-});
|
|
|
-
|
|
|
-// 当前步骤
|
|
|
-const currentStep = ref(1);
|
|
|
-
|
|
|
-// 选中的能力列表
|
|
|
-const selectedAbilities = computed(() => {
|
|
|
- return Object.entries(aiVideoOptions)
|
|
|
- .filter(([_, value]) => value)
|
|
|
- .map(([key, _]) => {
|
|
|
- const label = getAbilityLabel(key);
|
|
|
- return {
|
|
|
- value: key,
|
|
|
- label,
|
|
|
- isNew: ['teamwork', 'problemSolving', 'qualityControl'].includes(key)
|
|
|
- };
|
|
|
- });
|
|
|
-});
|
|
|
-
|
|
|
-// 获取能力标签
|
|
|
-const getAbilityLabel = (key: string) => {
|
|
|
- const abilityMap: Record<string, string> = {
|
|
|
- qualityControl: '质量控制',
|
|
|
- teamwork: '团队协作',
|
|
|
- problemSolving: '问题解决',
|
|
|
- dataAnalysis: '问题分析',
|
|
|
- taskManagement: '分析问题',
|
|
|
- productivity: '生产效率',
|
|
|
- manufacturingSkills: '制造制作技能',
|
|
|
- customerService: '客户服务技能',
|
|
|
- resistanceToPressure: '抗压能力-客户服务',
|
|
|
- workDefinition: '工作稳定-宣誓',
|
|
|
- selfIntroduction: '自我介绍-宣誓',
|
|
|
- detailOrientation: '细节关注',
|
|
|
- logicalThinking: '清晰逻辑思维',
|
|
|
- safetyAwareness: '安全意识',
|
|
|
- customerServiceAwareness: '客户服务意识',
|
|
|
- timeManagement: '时间管理',
|
|
|
- teamCooperation: '团队合作',
|
|
|
- timeManagementSkills: '时间管理能力',
|
|
|
- productEvaluation: '品鉴评估能力',
|
|
|
- basicQualifications: '基本素质',
|
|
|
- networkDeployment: '网位布署',
|
|
|
- remoteCooperation: '泡通协作',
|
|
|
- executionAbility: '执行能力',
|
|
|
- selfDiscipline: '自驱力',
|
|
|
- managementAbility: '管理能力',
|
|
|
- customerOrientation: '客户导向',
|
|
|
- stability: '稳定性',
|
|
|
- salesSkills: '销售技巧',
|
|
|
- responseAbility: '应变能力'
|
|
|
- };
|
|
|
- return abilityMap[key] || key;
|
|
|
-};
|
|
|
-
|
|
|
-// 排名设置
|
|
|
-const rankSettings = reactive({
|
|
|
- min: 0,
|
|
|
- max: 100,
|
|
|
- minScore: 0.00,
|
|
|
- maxScore: 0.00
|
|
|
-});
|
|
|
-
|
|
|
-// AI模型版本
|
|
|
-const aiModelVersion = ref('standard');
|
|
|
-
|
|
|
-// 是否启用有效期
|
|
|
-const validityEnabled = ref(false);
|
|
|
-
|
|
|
-// 在 script setup 部分添加以下响应式变量
|
|
|
-const showVideoLectureDialog = ref(false); // 控制视频宣讲弹窗显示
|
|
|
-const videoLectureForm = reactive({
|
|
|
- title: '', // 步骤名称
|
|
|
- videoFile: null, // 视频文件
|
|
|
- description: '', // 视频简介
|
|
|
- broadcastType: 'required', // 播放设置:必须看完/看过即可
|
|
|
-});
|
|
|
-
|
|
|
-// 在 script setup 部分添加新的响应式变量
|
|
|
-const showAIChatDialog = ref(false); // 控制AI实时对话抽屉显示
|
|
|
-
|
|
|
-// 添加 AI 实时对话配置相关的响应式变量
|
|
|
-const chatDuration = ref(15); // 默认15分钟
|
|
|
-const maxQuestions = ref(5); // 默认5个问题
|
|
|
-
|
|
|
-// 在 script setup 部分添加以下响应式变量
|
|
|
-const showQuestionDialog = ref(false); // 控制添加问题弹框显示
|
|
|
-const questionForm = reactive({
|
|
|
- title: '', // 标题
|
|
|
- ability: '', // 考察能力
|
|
|
- content: '', // 面试内容
|
|
|
- target: '', // 对话目标
|
|
|
- weight: 100, // 权重占比,默认100%
|
|
|
- maxAnswers: 1 // 最多回答次数,默认1次
|
|
|
-});
|
|
|
-
|
|
|
-// 在 script setup 中添加以下响应式变量
|
|
|
-const showDataCollectionDialog = ref(false); // 控制资料收集对话框显示
|
|
|
-const dataCollectionForm = reactive({
|
|
|
- isRequired: false, // 开启评分开关
|
|
|
- questions: [] // 问题列表
|
|
|
-});
|
|
|
-
|
|
|
-// 修改问题类型定义
|
|
|
-interface QuestionType {
|
|
|
- label: string;
|
|
|
- value: string;
|
|
|
- isVisible?: boolean;
|
|
|
- enableScoring?: boolean;
|
|
|
- isRequired?: boolean;
|
|
|
-}
|
|
|
-
|
|
|
-// 定义问题列表
|
|
|
-const questionTypes = ref<QuestionType[]>([
|
|
|
- {
|
|
|
- label: 'Q1',
|
|
|
- value: 'q1',
|
|
|
- isVisible: true,
|
|
|
- enableScoring: false,
|
|
|
- isRequired: false
|
|
|
- },
|
|
|
- {
|
|
|
- label: '请问你的毕业院校是哪里?',
|
|
|
- value: 'school',
|
|
|
- isVisible: true,
|
|
|
- enableScoring: false,
|
|
|
- isRequired: true
|
|
|
- }
|
|
|
-]);
|
|
|
-
|
|
|
-// 添加简历收集相关的状态和方法
|
|
|
-const showResumeCollectionDialog = ref(false);
|
|
|
-const resumeCollectionForm = reactive({
|
|
|
- title: '简历收集',
|
|
|
- isRequired: true,
|
|
|
- steps: 4, // 默认步骤数
|
|
|
-});
|
|
|
-
|
|
|
-// 显示简历收集弹窗
|
|
|
-const showResumeCollectionConfig = () => {
|
|
|
- showResumeCollectionDialog.value = true;
|
|
|
-};
|
|
|
-
|
|
|
-// 取消简历收集配置
|
|
|
-const cancelResumeCollection = () => {
|
|
|
- showResumeCollectionDialog.value = false;
|
|
|
- // 重置表单
|
|
|
- Object.assign(resumeCollectionForm, {
|
|
|
- title: '简历收集',
|
|
|
- isRequired: true,
|
|
|
- steps: 4
|
|
|
- });
|
|
|
-};
|
|
|
-
|
|
|
-// 确认添加简历收集
|
|
|
-const confirmResumeCollection = () => {
|
|
|
- // 创建新的简历收集步骤
|
|
|
- const newStep = {
|
|
|
- id: Date.now(),
|
|
|
- name: resumeCollectionForm.title,
|
|
|
- description: '简历收集',
|
|
|
- active: true,
|
|
|
- type: 'resume_collection',
|
|
|
- config: {
|
|
|
- ...resumeCollectionForm
|
|
|
- }
|
|
|
- };
|
|
|
-
|
|
|
- // 添加到流程中
|
|
|
- recruitmentProcess.splice(currentAddIndex.value, 0, newStep);
|
|
|
-
|
|
|
- // 关闭弹窗
|
|
|
- showResumeCollectionDialog.value = false;
|
|
|
-
|
|
|
- // 提示成功
|
|
|
- ElMessage.success('简历收集步骤已添加');
|
|
|
-
|
|
|
- // 重置表单
|
|
|
- cancelResumeCollection();
|
|
|
-};
|
|
|
-
|
|
|
-// 获取职位详情
|
|
|
-const getPositionDetail = async () => {
|
|
|
- try {
|
|
|
- const id = route.query.id;
|
|
|
- if (!id) {
|
|
|
- ElMessage.error('职位ID不存在');
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- // 修复类型错误,创建符合InfoReq类型的对象
|
|
|
- const idValue = Array.isArray(id) ? id[0] : id;
|
|
|
- // 创建一个符合API要求的请求对象
|
|
|
- const infoReq = id
|
|
|
- const response = await api.GetObj(id); // 使用 infoReq 而不是 id
|
|
|
- if (response && response.data) {
|
|
|
- Object.assign(positionData, response.data);
|
|
|
- // 设置职位状态
|
|
|
- positionStatus.value = positionData.job_type === 1;
|
|
|
- }
|
|
|
- } catch (error) {
|
|
|
- console.error('获取职位详情失败:', error);
|
|
|
- ElMessage.error('获取职位详情失败');
|
|
|
- }
|
|
|
-};
|
|
|
-
|
|
|
-// 返回列表页
|
|
|
-const goBack = () => {
|
|
|
- router.push('/position/list');
|
|
|
-};
|
|
|
-
|
|
|
-// 编辑职位
|
|
|
-const handleEdit = () => {
|
|
|
- router.push(`/position/edit/${positionId.value}`);
|
|
|
-};
|
|
|
-
|
|
|
-// 分享职位
|
|
|
-const handleShare = () => {
|
|
|
- ElMessage.success('分享链接已复制到剪贴板');
|
|
|
-};
|
|
|
-
|
|
|
-// 修改职位状态
|
|
|
-const handleStatusChange = async (value: boolean) => {
|
|
|
- const id = route.query.id;
|
|
|
- try {
|
|
|
- const newStatus = value ? 1 : 0;
|
|
|
- await api.UpdateObj({
|
|
|
- id: id,
|
|
|
- job_type: newStatus
|
|
|
- });
|
|
|
- positionData.job_type = newStatus;
|
|
|
- ElMessage.success(`职位已${value ? '开启' : '关闭'}`);
|
|
|
- } catch (error) {
|
|
|
- console.error('修改状态失败:', error);
|
|
|
- ElMessage.error('修改状态失败');
|
|
|
- // 恢复原状态
|
|
|
- positionStatus.value = !value;
|
|
|
- }
|
|
|
-};
|
|
|
-
|
|
|
-// 编辑职位用途
|
|
|
-const handleEditUsage = () => {
|
|
|
- ElMessage.info('编辑职位用途功能开发中');
|
|
|
-};
|
|
|
-
|
|
|
-// 编辑招聘流程
|
|
|
-const handleEditProcess = () => {
|
|
|
- showProcessDialog.value = true;
|
|
|
-};
|
|
|
-
|
|
|
-// 保存招聘流程
|
|
|
-const saveProcess = () => {
|
|
|
- showProcessDialog.value = false;
|
|
|
- ElMessage.success('招聘流程已更新');
|
|
|
-};
|
|
|
-
|
|
|
-// 取消编辑
|
|
|
-const cancelEditProcess = () => {
|
|
|
- showProcessDialog.value = false;
|
|
|
-};
|
|
|
-
|
|
|
-// 删除流程步骤
|
|
|
-const deleteProcessStep = (index: number) => {
|
|
|
- recruitmentProcess.splice(index, 1);
|
|
|
-};
|
|
|
-
|
|
|
-// 在特定位置添加流程步骤
|
|
|
-const addProcessStepAt = (index: number) => {
|
|
|
- if (recruitmentProcess.length >= 6) {
|
|
|
- ElMessage.warning('最多只能添加6个流程步骤');
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- const newStep = {
|
|
|
- id: Date.now(),
|
|
|
- name: '新步骤',
|
|
|
- description: '新步骤',
|
|
|
- active: true
|
|
|
- };
|
|
|
-
|
|
|
- recruitmentProcess.splice(index, 0, newStep);
|
|
|
-};
|
|
|
-
|
|
|
-// 修改原有的添加方法,调用新方法
|
|
|
-const addProcessStep = () => {
|
|
|
- addProcessStepAt(recruitmentProcess.length);
|
|
|
-};
|
|
|
-
|
|
|
-// 获取状态文本
|
|
|
-const getStatusText = (status: number) => {
|
|
|
- const statusMap: Record<number, string> = {
|
|
|
- 0: '未发布',
|
|
|
- 1: '已发布',
|
|
|
- 2: '已结束'
|
|
|
- };
|
|
|
- return statusMap[status] || '未知状态';
|
|
|
-};
|
|
|
-
|
|
|
-// 获取状态类型
|
|
|
-const getStatusType = (status: number) => {
|
|
|
- const typeMap: Record<number, string> = {
|
|
|
- 0: 'info',
|
|
|
- 1: 'success',
|
|
|
- 2: 'danger'
|
|
|
- };
|
|
|
- return typeMap[status] || 'info';
|
|
|
-};
|
|
|
-
|
|
|
-// 获取职位性质文本
|
|
|
-const getJobTypeText = (type: number) => {
|
|
|
- const typeMap: Record<number, string> = {
|
|
|
- 0: '全职',
|
|
|
- 1: '兼职',
|
|
|
- 2: '实习',
|
|
|
- 3: '其他'
|
|
|
- };
|
|
|
- return typeMap[type] || '未知';
|
|
|
-};
|
|
|
-
|
|
|
-// 显示选项菜单
|
|
|
-const showStepOptions = (index: number, event: MouseEvent) => {
|
|
|
- currentAddIndex.value = index;
|
|
|
- showOptionsMenu.value = true;
|
|
|
-
|
|
|
- // 计算菜单位置 - 获取按钮元素
|
|
|
- const button = event.currentTarget as HTMLElement;
|
|
|
- // 获取对话框元素,作为相对定位的参考
|
|
|
- const dialogContent = button.closest('.process-dialog-content');
|
|
|
-
|
|
|
- if (dialogContent) {
|
|
|
- // 获取按钮和对话框的位置信息
|
|
|
- const buttonRect = button.getBoundingClientRect();
|
|
|
- const dialogRect = dialogContent.getBoundingClientRect();
|
|
|
-
|
|
|
- // 计算相对于对话框的位置
|
|
|
- const top = buttonRect.bottom - dialogRect.top + 5; // 按钮下方5px
|
|
|
- const left = buttonRect.left - dialogRect.left;
|
|
|
-
|
|
|
- // 设置菜单位置
|
|
|
- menuPosition.top = `${top}px`;
|
|
|
- menuPosition.left = `${left}px`;
|
|
|
- }
|
|
|
-
|
|
|
- // 阻止事件冒泡
|
|
|
- event.stopPropagation();
|
|
|
-};
|
|
|
-
|
|
|
-// 修改添加选定类型的步骤方法
|
|
|
-const addSelectedStepType = (type: string, label: string) => {
|
|
|
- if (type === 'ai_video') {
|
|
|
- showAIVideoDialog.value = true;
|
|
|
- showOptionsMenu.value = false;
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- // 添加 AI 实时对话类型的处理
|
|
|
- if (type === 'ai_chat') {
|
|
|
- showAIChatDialog.value = true;
|
|
|
- showOptionsMenu.value = false;
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- // 添加视频宣讲类型的处理
|
|
|
- if (type === 'video_presentation') {
|
|
|
- showVideoLectureConfig();
|
|
|
- showOptionsMenu.value = false;
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- // 添加资料收集类型的处理
|
|
|
- if (type === 'data_collection') {
|
|
|
- showDataCollectionDialog.value = true;
|
|
|
- showOptionsMenu.value = false;
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- // 添加简历收集类型的处理
|
|
|
- if (type === 'resume_collection') {
|
|
|
- showResumeCollectionConfig();
|
|
|
- showOptionsMenu.value = false;
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- // 添加代码测试类型的处理
|
|
|
- if (type === 'code_test') {
|
|
|
- showCodeTestConfig();
|
|
|
- showOptionsMenu.value = false;
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- // 添加打字测试类型的处理
|
|
|
- if (type === 'typing_test') {
|
|
|
- showTypingTestDialog.value = true;
|
|
|
- showOptionsMenu.value = false;
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- // 其他类型的处理保持不变
|
|
|
- if (recruitmentProcess.length >= 6) {
|
|
|
- ElMessage.warning('最多只能添加6个流程步骤');
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- const newStep = {
|
|
|
- id: Date.now(),
|
|
|
- name: label,
|
|
|
- description: label,
|
|
|
- active: true,
|
|
|
- type: type
|
|
|
- };
|
|
|
-
|
|
|
- recruitmentProcess.splice(currentAddIndex.value, 0, newStep);
|
|
|
- showOptionsMenu.value = false;
|
|
|
-};
|
|
|
-
|
|
|
-// 下一步
|
|
|
-const nextStep = () => {
|
|
|
- if (currentStep.value < 3) {
|
|
|
- currentStep.value++;
|
|
|
- } else {
|
|
|
- finishConfig();
|
|
|
- }
|
|
|
-};
|
|
|
-
|
|
|
-// 上一步
|
|
|
-const prevStep = () => {
|
|
|
- if (currentStep.value > 1) {
|
|
|
- currentStep.value--;
|
|
|
- }
|
|
|
-};
|
|
|
-
|
|
|
-// 完成配置
|
|
|
-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)
|
|
|
- };
|
|
|
-
|
|
|
- // 添加到流程中
|
|
|
- recruitmentProcess.splice(currentAddIndex.value, 0, newStep);
|
|
|
-
|
|
|
- // 关闭对话框
|
|
|
- showAIVideoDialog.value = false;
|
|
|
-
|
|
|
- // 重置当前步骤
|
|
|
- currentStep.value = 1;
|
|
|
-
|
|
|
- // 提示成功
|
|
|
- ElMessage.success('AI视频步骤已添加');
|
|
|
-};
|
|
|
-
|
|
|
-// 取消AI视频配置
|
|
|
-const cancelAIVideoConfig = () => {
|
|
|
- showAIVideoDialog.value = false;
|
|
|
- currentStep.value = 1; // 重置步骤
|
|
|
-};
|
|
|
-
|
|
|
-// 跳转到指定步骤
|
|
|
-const jumpToStep = (step: number) => {
|
|
|
- // 确保步骤在有效范围内
|
|
|
- if (step >= 1 && step <= 3) {
|
|
|
- currentStep.value = step;
|
|
|
- }
|
|
|
-};
|
|
|
-
|
|
|
-// 显示视频宣讲配置弹窗
|
|
|
-const showVideoLectureConfig = () => {
|
|
|
- showVideoLectureDialog.value = true;
|
|
|
-};
|
|
|
-
|
|
|
-// 取消视频宣讲配置
|
|
|
-const cancelVideoLecture = () => {
|
|
|
- showVideoLectureDialog.value = false;
|
|
|
- // 重置表单
|
|
|
- Object.assign(videoLectureForm, {
|
|
|
- title: '',
|
|
|
- videoFile: null,
|
|
|
- description: '',
|
|
|
- broadcastType: 'required'
|
|
|
- });
|
|
|
-};
|
|
|
-
|
|
|
-// 确认添加视频宣讲
|
|
|
-const confirmVideoLecture = () => {
|
|
|
- // 创建新的视频宣讲步骤
|
|
|
- const newStep = {
|
|
|
- id: Date.now(),
|
|
|
- name: videoLectureForm.title || '视频宣讲',
|
|
|
- description: videoLectureForm.description || '视频宣讲',
|
|
|
- active: true,
|
|
|
- type: 'video_presentation',
|
|
|
- config: {
|
|
|
- ...videoLectureForm
|
|
|
- }
|
|
|
- };
|
|
|
-
|
|
|
- // 添加到流程中
|
|
|
- recruitmentProcess.splice(currentAddIndex.value, 0, newStep);
|
|
|
-
|
|
|
- // 关闭弹窗
|
|
|
- showVideoLectureDialog.value = false;
|
|
|
-
|
|
|
- // 提示成功
|
|
|
- ElMessage.success('视频宣讲步骤已添加');
|
|
|
-
|
|
|
- // 重置表单
|
|
|
- cancelVideoLecture();
|
|
|
-};
|
|
|
-
|
|
|
-// 添加 AI 实时对话相关方法
|
|
|
-const handleAIChatConfig = () => {
|
|
|
- // 这里添加确认配置的逻辑
|
|
|
- const newStep = {
|
|
|
- id: Date.now(),
|
|
|
- name: 'AI实时对话',
|
|
|
- description: 'AI实时对话',
|
|
|
- active: true,
|
|
|
- type: 'ai_chat'
|
|
|
- };
|
|
|
-
|
|
|
- recruitmentProcess.splice(currentAddIndex.value, 0, newStep);
|
|
|
- showAIChatDialog.value = false;
|
|
|
- ElMessage.success('AI实时对话步骤已添加');
|
|
|
-};
|
|
|
-
|
|
|
-const cancelAIChatConfig = () => {
|
|
|
- showAIChatDialog.value = false;
|
|
|
-};
|
|
|
-
|
|
|
-// 添加问题列表数据
|
|
|
-const chatQuestions = ref<ChatQuestion[]>([]);
|
|
|
-
|
|
|
-// 添加问题处理方法
|
|
|
-const handleAddQuestion = () => {
|
|
|
- showQuestionDialog.value = true;
|
|
|
-};
|
|
|
-
|
|
|
-// 取消添加问题
|
|
|
-const cancelAddQuestion = () => {
|
|
|
- showQuestionDialog.value = false;
|
|
|
- // 重置表单
|
|
|
- Object.assign(questionForm, {
|
|
|
- title: '',
|
|
|
- ability: '',
|
|
|
- content: '',
|
|
|
- target: '',
|
|
|
- weight: 100,
|
|
|
- maxAnswers: 1
|
|
|
- });
|
|
|
-};
|
|
|
-
|
|
|
-// 确认添加问题
|
|
|
-const confirmAddQuestion = () => {
|
|
|
- if (!questionForm.title || !questionForm.content) {
|
|
|
- ElMessage.warning('请填写必填项');
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- // 创建新问题对象
|
|
|
- const newQuestion = {
|
|
|
- title: questionForm.title,
|
|
|
- ability: questionForm.ability,
|
|
|
- content: questionForm.content,
|
|
|
- target: questionForm.target,
|
|
|
- weight: questionForm.weight,
|
|
|
- maxAnswers: questionForm.maxAnswers
|
|
|
- };
|
|
|
-
|
|
|
- // 添加到问题列表
|
|
|
- chatQuestions.value.push(newQuestion);
|
|
|
-
|
|
|
- // 关闭弹框
|
|
|
- showQuestionDialog.value = false;
|
|
|
-
|
|
|
- // 重置表单
|
|
|
- cancelAddQuestion();
|
|
|
-
|
|
|
- // 提示成功
|
|
|
- ElMessage.success('问题添加成功');
|
|
|
-};
|
|
|
-
|
|
|
-// 导入问题处理方法
|
|
|
-const handleImportQuestion = () => {
|
|
|
- ElMessage.info('导入问题功能开发中');
|
|
|
-};
|
|
|
-
|
|
|
-// 在 script setup 中添加
|
|
|
-const editQuestion = (index: number) => {
|
|
|
- // 编辑问题的逻辑
|
|
|
- const question = chatQuestions.value[index];
|
|
|
- Object.assign(questionForm, question);
|
|
|
- showQuestionDialog.value = true;
|
|
|
-};
|
|
|
-
|
|
|
-const deleteQuestion = (index: number) => {
|
|
|
- ElMessageBox.confirm('确认删除该问题?', '提示', {
|
|
|
- confirmButtonText: '确定',
|
|
|
- cancelButtonText: '取消',
|
|
|
- type: 'warning'
|
|
|
- }).then(() => {
|
|
|
- chatQuestions.value.splice(index, 1);
|
|
|
- ElMessage.success('删除成功');
|
|
|
- });
|
|
|
-};
|
|
|
-
|
|
|
-// 取消资料收集配置
|
|
|
-const cancelDataCollection = () => {
|
|
|
- showDataCollectionDialog.value = false;
|
|
|
- // 重置表单
|
|
|
- Object.assign(dataCollectionForm, {
|
|
|
- isRequired: false,
|
|
|
- questions: []
|
|
|
- });
|
|
|
-};
|
|
|
-
|
|
|
-// 确认添加资料收集
|
|
|
-const confirmDataCollection = () => {
|
|
|
- if (dataCollectionForm.questions.length === 0) {
|
|
|
- ElMessage.warning('请至少选择一个问题');
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- // 创建新的资料收集步骤
|
|
|
- const newStep = {
|
|
|
- id: Date.now(),
|
|
|
- name: '资料收集',
|
|
|
- description: `已选择${dataCollectionForm.questions.length}个问题`,
|
|
|
- active: true,
|
|
|
- type: 'data_collection',
|
|
|
- config: {
|
|
|
- ...dataCollectionForm,
|
|
|
- questions: dataCollectionForm.questions.map(q => {
|
|
|
- // 修复 find 方法的使用
|
|
|
- const question = questionTypes.value.find(type => type.value === q);
|
|
|
- return {
|
|
|
- type: q,
|
|
|
- title: question?.label || '',
|
|
|
- required: dataCollectionForm.isRequired
|
|
|
- };
|
|
|
- })
|
|
|
- }
|
|
|
- };
|
|
|
-
|
|
|
- // 添加到流程中
|
|
|
- recruitmentProcess.splice(currentAddIndex.value, 0, newStep);
|
|
|
-
|
|
|
- // 关闭弹窗
|
|
|
- showDataCollectionDialog.value = false;
|
|
|
-
|
|
|
- // 提示成功
|
|
|
- ElMessage.success('资料收集步骤已添加');
|
|
|
-
|
|
|
- // 重置表单
|
|
|
- cancelDataCollection();
|
|
|
-};
|
|
|
-
|
|
|
-// 使用 onMounted 和 onUnmounted 钩子
|
|
|
-onMounted(() => {
|
|
|
- getPositionDetail();
|
|
|
- getCompetencyList();
|
|
|
-});
|
|
|
-
|
|
|
-// 添加代码测试相关的状态和方法
|
|
|
-const showCodeTestDialog = ref(false);
|
|
|
-const codeTestForm = reactive({
|
|
|
- title: '代码笔试',
|
|
|
- autoJudge: true,
|
|
|
- selectedPaper: null as Paper | null,
|
|
|
-});
|
|
|
-
|
|
|
-// 显示代码测试弹窗
|
|
|
-const showCodeTestConfig = () => {
|
|
|
- showCodeTestDialog.value = true;
|
|
|
-};
|
|
|
-
|
|
|
-// 取消代码测试配置
|
|
|
-const cancelCodeTest = () => {
|
|
|
- showCodeTestDialog.value = false;
|
|
|
- // 重置表单
|
|
|
- Object.assign(codeTestForm, {
|
|
|
- title: '代码笔试',
|
|
|
- autoJudge: true,
|
|
|
- selectedPaper: null
|
|
|
- });
|
|
|
-};
|
|
|
-
|
|
|
-// 确认添加代码测试
|
|
|
-const confirmCodeTest = () => {
|
|
|
- if (!codeTestForm.selectedPaper) {
|
|
|
- ElMessage.warning('请添加考试试卷');
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- // 创建新的代码测试步骤
|
|
|
- const newStep = {
|
|
|
- id: Date.now(),
|
|
|
- name: codeTestForm.title,
|
|
|
- description: `${codeTestForm.selectedPaper.title}`,
|
|
|
- active: true,
|
|
|
- type: 'code_test',
|
|
|
- config: {
|
|
|
- ...codeTestForm
|
|
|
- }
|
|
|
- };
|
|
|
-
|
|
|
- // 添加到流程中
|
|
|
- recruitmentProcess.splice(currentAddIndex.value, 0, newStep);
|
|
|
-
|
|
|
- // 关闭弹窗
|
|
|
- showCodeTestDialog.value = false;
|
|
|
-
|
|
|
- // 提示成功
|
|
|
- ElMessage.success('代码笔试步骤已添加');
|
|
|
-
|
|
|
- // 重置表单
|
|
|
- cancelCodeTest();
|
|
|
-};
|
|
|
-
|
|
|
-// 选择试卷
|
|
|
-const handleSelectPaper = () => {
|
|
|
- // 模拟选择试卷
|
|
|
- codeTestForm.selectedPaper = {
|
|
|
- id: 1,
|
|
|
- title: '前端开发工程师笔试',
|
|
|
- questionCount: 4,
|
|
|
- duration: 60,
|
|
|
- difficulty: '中等难度'
|
|
|
- } as Paper;
|
|
|
-};
|
|
|
-
|
|
|
-// 查看试卷
|
|
|
-const handleViewPaper = () => {
|
|
|
- ElMessage.info('查看试卷功能开发中');
|
|
|
-};
|
|
|
-
|
|
|
-// 更换试卷
|
|
|
-const handleChangePaper = () => {
|
|
|
- ElMessage.info('更换试卷功能开发中');
|
|
|
-};
|
|
|
-
|
|
|
-// 删除试卷
|
|
|
-const handleRemovePaper = () => {
|
|
|
- codeTestForm.selectedPaper = null;
|
|
|
-};
|
|
|
-
|
|
|
-// 添加打字测试对话框
|
|
|
-const showTypingTestDialog = ref(false);
|
|
|
-const typingTestForm = reactive({
|
|
|
- title: '', // 步骤名称
|
|
|
- duration: 5, // 测试时间,默认5分钟
|
|
|
- content: '', // 测试页面标题
|
|
|
- notes: '', // 注意事项内容
|
|
|
- videoMonitoring: false, // 是否启用视频监控
|
|
|
- passCriteria: {
|
|
|
- speed: false, // 是否通过速度标准
|
|
|
- accuracy: true, // 是否通过正确率标准,默认选中
|
|
|
- },
|
|
|
- selectionMode: 'random', // 文章选择方式:random-随机抽取,self-候选人自主选择
|
|
|
- pageTitle: '', // 测试页面标题
|
|
|
- previewImage: null, // 登录界面预览图
|
|
|
- articles: [] // 文章列表
|
|
|
-});
|
|
|
-
|
|
|
-// 取消打字测试配置
|
|
|
-const cancelTypingTest = () => {
|
|
|
- showTypingTestDialog.value = false;
|
|
|
- // 重置表单
|
|
|
- Object.assign(typingTestForm, {
|
|
|
- title: '',
|
|
|
- duration: 5,
|
|
|
- content: '',
|
|
|
- notes: '',
|
|
|
- videoMonitoring: false,
|
|
|
- passCriteria: {
|
|
|
- speed: false,
|
|
|
- accuracy: true,
|
|
|
- },
|
|
|
- selectionMode: 'random',
|
|
|
- pageTitle: '',
|
|
|
- previewImage: null,
|
|
|
- articles: []
|
|
|
- });
|
|
|
-};
|
|
|
-
|
|
|
-// 确认添加打字测试
|
|
|
-const confirmTypingTest = () => {
|
|
|
- // 创建新的打字测试步骤
|
|
|
- const newStep = {
|
|
|
- id: Date.now(),
|
|
|
- name: typingTestForm.title,
|
|
|
- description: `打字测试 ${typingTestForm.duration}分钟`,
|
|
|
- active: true,
|
|
|
- type: 'typing_test',
|
|
|
- config: {
|
|
|
- ...typingTestForm
|
|
|
- }
|
|
|
- };
|
|
|
-
|
|
|
- // 添加到流程中
|
|
|
- recruitmentProcess.splice(currentAddIndex.value, 0, newStep);
|
|
|
-
|
|
|
- // 关闭弹窗
|
|
|
- showTypingTestDialog.value = false;
|
|
|
-
|
|
|
- // 提示成功
|
|
|
- ElMessage.success('打字测试步骤已添加');
|
|
|
-
|
|
|
- // 重置表单
|
|
|
- cancelTypingTest();
|
|
|
-};
|
|
|
-
|
|
|
-// 添加职位名称编辑功能
|
|
|
-const isEditingTitle = ref(false);
|
|
|
-const editingTitle = ref('');
|
|
|
-
|
|
|
-// 开始编辑职位名称
|
|
|
-const startEditTitle = () => {
|
|
|
- editingTitle.value = positionData.title;
|
|
|
- isEditingTitle.value = true;
|
|
|
-};
|
|
|
-
|
|
|
-// 取消编辑职位名称
|
|
|
-const cancelEditTitle = () => {
|
|
|
- isEditingTitle.value = false;
|
|
|
-};
|
|
|
-
|
|
|
-// 保存编辑后的职位名称
|
|
|
-const saveTitle = async () => {
|
|
|
- if (!editingTitle.value.trim()) {
|
|
|
- ElMessage.warning('职位名称不能为空');
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- try {
|
|
|
- const id = route.query.id;
|
|
|
- await api.UpdateObj({
|
|
|
- id: id,
|
|
|
- title: editingTitle.value.trim()
|
|
|
- });
|
|
|
-
|
|
|
- // 更新本地数据
|
|
|
- positionData.title = editingTitle.value.trim();
|
|
|
- isEditingTitle.value = false;
|
|
|
- ElMessage.success('职位名称已更新');
|
|
|
- } catch (error) {
|
|
|
- console.error('更新职位名称失败:', error);
|
|
|
- ElMessage.error('更新职位名称失败');
|
|
|
- }
|
|
|
-};
|
|
|
-
|
|
|
-// 工作地点编辑
|
|
|
-const isEditingLocation = ref(false);
|
|
|
-const editingLocation = ref('');
|
|
|
-
|
|
|
-// 开始编辑工作地点
|
|
|
-const startEditLocation = () => {
|
|
|
- editingLocation.value = positionData.location || '';
|
|
|
- isEditingLocation.value = true;
|
|
|
-};
|
|
|
-
|
|
|
-// 取消编辑工作地点
|
|
|
-const cancelEditLocation = () => {
|
|
|
- isEditingLocation.value = false;
|
|
|
-};
|
|
|
-
|
|
|
-// 保存工作地点
|
|
|
-const saveLocation = async () => {
|
|
|
- try {
|
|
|
- const id = route.query.id;
|
|
|
- await api.UpdateObj({
|
|
|
- id: id,
|
|
|
- location: editingLocation.value.trim()
|
|
|
- });
|
|
|
-
|
|
|
- // 更新本地数据
|
|
|
- positionData.location = editingLocation.value.trim();
|
|
|
- isEditingLocation.value = false;
|
|
|
- ElMessage.success('工作地点已更新');
|
|
|
- } catch (error) {
|
|
|
- console.error('更新工作地点失败:', error);
|
|
|
- ElMessage.error('更新工作地点失败');
|
|
|
- }
|
|
|
-};
|
|
|
-
|
|
|
-// 职位薪资编辑
|
|
|
-const isEditingSalary = ref(false);
|
|
|
-const editingSalary = ref('');
|
|
|
-
|
|
|
-// 开始编辑职位薪资
|
|
|
-const startEditSalary = () => {
|
|
|
- editingSalary.value = positionData.salary_range || '';
|
|
|
- isEditingSalary.value = true;
|
|
|
-};
|
|
|
-
|
|
|
-// 取消编辑职位薪资
|
|
|
-const cancelEditSalary = () => {
|
|
|
- isEditingSalary.value = false;
|
|
|
-};
|
|
|
-
|
|
|
-// 保存职位薪资
|
|
|
-const saveSalary = async () => {
|
|
|
- try {
|
|
|
- const id = route.query.id;
|
|
|
- await api.UpdateObj({
|
|
|
- id: id,
|
|
|
- salary_range: editingSalary.value.trim()
|
|
|
- });
|
|
|
-
|
|
|
- // 更新本地数据
|
|
|
- positionData.salary_range = editingSalary.value.trim();
|
|
|
- isEditingSalary.value = false;
|
|
|
- ElMessage.success('职位薪资已更新');
|
|
|
- } catch (error) {
|
|
|
- console.error('更新职位薪资失败:', error);
|
|
|
- ElMessage.error('更新职位薪资失败');
|
|
|
- }
|
|
|
-};
|
|
|
-
|
|
|
-// 工作经验编辑
|
|
|
-const isEditingExperience = ref(false);
|
|
|
-const editingExperience = ref('');
|
|
|
-
|
|
|
-// 开始编辑工作经验
|
|
|
-const startEditExperience = () => {
|
|
|
- editingExperience.value = positionData.work_experience_required || '';
|
|
|
- isEditingExperience.value = true;
|
|
|
-};
|
|
|
-
|
|
|
-// 取消编辑工作经验
|
|
|
-const cancelEditExperience = () => {
|
|
|
- isEditingExperience.value = false;
|
|
|
-};
|
|
|
-
|
|
|
-// 保存工作经验
|
|
|
-const saveExperience = async () => {
|
|
|
- try {
|
|
|
- const id = route.query.id;
|
|
|
- await api.UpdateObj({
|
|
|
- id: id,
|
|
|
- work_experience_required: editingExperience.value
|
|
|
- });
|
|
|
-
|
|
|
- // 更新本地数据
|
|
|
- positionData.work_experience_required = editingExperience.value;
|
|
|
- isEditingExperience.value = false;
|
|
|
- ElMessage.success('工作经验已更新');
|
|
|
- } catch (error) {
|
|
|
- console.error('更新工作经验失败:', error);
|
|
|
- ElMessage.error('更新工作经验失败');
|
|
|
- }
|
|
|
-};
|
|
|
-
|
|
|
-// 学历要求编辑
|
|
|
-const isEditingEducation = ref(false);
|
|
|
-const editingEducation = ref('');
|
|
|
-
|
|
|
-// 开始编辑学历要求
|
|
|
-const startEditEducation = () => {
|
|
|
- editingEducation.value = positionData.education_required || '';
|
|
|
- isEditingEducation.value = true;
|
|
|
-};
|
|
|
-
|
|
|
-// 取消编辑学历要求
|
|
|
-const cancelEditEducation = () => {
|
|
|
- isEditingEducation.value = false;
|
|
|
-};
|
|
|
-
|
|
|
-// 保存学历要求
|
|
|
-const saveEducation = async () => {
|
|
|
- try {
|
|
|
- const id = route.query.id;
|
|
|
- await api.UpdateObj({
|
|
|
- id: id,
|
|
|
- education_required: editingEducation.value
|
|
|
- });
|
|
|
-
|
|
|
- // 更新本地数据
|
|
|
- positionData.education_required = editingEducation.value;
|
|
|
- isEditingEducation.value = false;
|
|
|
- ElMessage.success('学历要求已更新');
|
|
|
- } catch (error) {
|
|
|
- console.error('更新学历要求失败:', error);
|
|
|
- ElMessage.error('更新学历要求失败');
|
|
|
- }
|
|
|
-};
|
|
|
-
|
|
|
-// 所属部门编辑
|
|
|
-const isEditingDepartment = ref(false);
|
|
|
-const editingDepartment = ref('');
|
|
|
-
|
|
|
-// 开始编辑所属部门
|
|
|
-const startEditDepartment = () => {
|
|
|
- editingDepartment.value = positionData.department || '';
|
|
|
- isEditingDepartment.value = true;
|
|
|
-};
|
|
|
-
|
|
|
-// 取消编辑所属部门
|
|
|
-const cancelEditDepartment = () => {
|
|
|
- isEditingDepartment.value = false;
|
|
|
-};
|
|
|
-
|
|
|
-// 保存所属部门
|
|
|
-const saveDepartment = async () => {
|
|
|
- try {
|
|
|
- const id = route.query.id;
|
|
|
- await api.UpdateObj({
|
|
|
- id: id,
|
|
|
- department: editingDepartment.value.trim()
|
|
|
- });
|
|
|
-
|
|
|
- // 更新本地数据
|
|
|
- positionData.department = editingDepartment.value.trim();
|
|
|
- isEditingDepartment.value = false;
|
|
|
- ElMessage.success('所属部门已更新');
|
|
|
- } catch (error) {
|
|
|
- console.error('更新所属部门失败:', error);
|
|
|
- ElMessage.error('更新所属部门失败');
|
|
|
- }
|
|
|
-};
|
|
|
-
|
|
|
-// 截止日期编辑
|
|
|
-const isEditingEndDate = ref(false);
|
|
|
-const editingEndDate = ref('');
|
|
|
-
|
|
|
-// 开始编辑截止日期
|
|
|
-const startEditEndDate = () => {
|
|
|
- editingEndDate.value = positionData.end_date || '';
|
|
|
- isEditingEndDate.value = true;
|
|
|
-};
|
|
|
-
|
|
|
-// 取消编辑截止日期
|
|
|
-const cancelEditEndDate = () => {
|
|
|
- isEditingEndDate.value = false;
|
|
|
-};
|
|
|
-
|
|
|
-// 保存截止日期
|
|
|
-const saveEndDate = async () => {
|
|
|
- try {
|
|
|
- const id = route.query.id;
|
|
|
- await api.UpdateObj({
|
|
|
- id: id,
|
|
|
- end_date: editingEndDate.value
|
|
|
- });
|
|
|
-
|
|
|
- // 更新本地数据
|
|
|
- positionData.end_date = editingEndDate.value;
|
|
|
- isEditingEndDate.value = false;
|
|
|
- ElMessage.success('截止日期已更新');
|
|
|
- } catch (error) {
|
|
|
- console.error('更新截止日期失败:', error);
|
|
|
- ElMessage.error('更新截止日期失败');
|
|
|
- }
|
|
|
-};
|
|
|
-
|
|
|
-// 职位要求编辑
|
|
|
-const isEditingRequirements = ref(false);
|
|
|
-const editingRequirements = ref('');
|
|
|
-
|
|
|
-// 开始编辑职位要求
|
|
|
-const startEditRequirements = () => {
|
|
|
- editingRequirements.value = positionData.requirements || '';
|
|
|
- isEditingRequirements.value = true;
|
|
|
-};
|
|
|
-
|
|
|
-// 取消编辑职位要求
|
|
|
-const cancelEditRequirements = () => {
|
|
|
- isEditingRequirements.value = false;
|
|
|
-};
|
|
|
-
|
|
|
-// 保存职位要求
|
|
|
-const saveRequirements = async () => {
|
|
|
- try {
|
|
|
- const id = route.query.id;
|
|
|
- await api.UpdateObj({
|
|
|
- id: id,
|
|
|
- requirements: editingRequirements.value
|
|
|
- });
|
|
|
-
|
|
|
- // 更新本地数据
|
|
|
- positionData.requirements = editingRequirements.value;
|
|
|
- isEditingRequirements.value = false;
|
|
|
- ElMessage.success('职位要求已更新');
|
|
|
- } catch (error) {
|
|
|
- console.error('更新职位要求失败:', error);
|
|
|
- ElMessage.error('更新职位要求失败');
|
|
|
- }
|
|
|
-};
|
|
|
-
|
|
|
-// 职位描述编辑
|
|
|
-const isEditingDescription = ref(false);
|
|
|
-const editingDescription = ref('');
|
|
|
-
|
|
|
-// 开始编辑职位描述
|
|
|
-const startEditDescription = () => {
|
|
|
- editingDescription.value = positionData.description || '';
|
|
|
- isEditingDescription.value = true;
|
|
|
-};
|
|
|
-
|
|
|
-// 取消编辑职位描述
|
|
|
-const cancelEditDescription = () => {
|
|
|
- isEditingDescription.value = false;
|
|
|
-};
|
|
|
-
|
|
|
-// 保存职位描述
|
|
|
-const saveDescription = async () => {
|
|
|
- try {
|
|
|
- const id = route.query.id;
|
|
|
- await api.UpdateObj({
|
|
|
- id: id,
|
|
|
- description: editingDescription.value
|
|
|
- });
|
|
|
-
|
|
|
- // 更新本地数据
|
|
|
- positionData.description = editingDescription.value;
|
|
|
- isEditingDescription.value = false;
|
|
|
- ElMessage.success('职位描述已更新');
|
|
|
- } catch (error) {
|
|
|
- console.error('更新职位描述失败:', error);
|
|
|
- ElMessage.error('更新职位描述失败');
|
|
|
- }
|
|
|
-};
|
|
|
-
|
|
|
-// 添加能力标签相关的响应式变量
|
|
|
-const competencyTags = ref([]);
|
|
|
-const isEditingCompetency = ref(false);
|
|
|
-const selectedCompetencies = ref([]);
|
|
|
-
|
|
|
-// 获取能力标签列表
|
|
|
-const getCompetencyList = async () => {
|
|
|
- try {
|
|
|
- const response = await api.GetCompetencyList({page:1,pageSize:1000});
|
|
|
- if (response && response.data) {
|
|
|
- competencyTags.value = response.data.items;
|
|
|
- }
|
|
|
- } catch (error) {
|
|
|
- console.error('获取能力标签列表失败:', error);
|
|
|
- ElMessage.error('获取能力标签列表失败');
|
|
|
- }
|
|
|
-};
|
|
|
-
|
|
|
-// 开始编辑能力标签
|
|
|
-const startEditCompetency = () => {
|
|
|
- selectedCompetencies.value = positionData.competency_tags?.map(tag => tag.id) || [];
|
|
|
- isEditingCompetency.value = true;
|
|
|
-};
|
|
|
-
|
|
|
-// 取消编辑能力标签
|
|
|
-const cancelEditCompetency = () => {
|
|
|
- isEditingCompetency.value = false;
|
|
|
-};
|
|
|
-
|
|
|
-// 保存能力标签
|
|
|
-const saveCompetency = async () => {
|
|
|
- try {
|
|
|
- const id = route.query.id;
|
|
|
- await api.UpdateObj({
|
|
|
- id: id,
|
|
|
- competency_tags: selectedCompetencies.value
|
|
|
- });
|
|
|
-
|
|
|
- // 更新本地数据
|
|
|
- positionData.competency_tags = competencyTags.value.filter(tag =>
|
|
|
- selectedCompetencies.value.includes(tag.id)
|
|
|
- );
|
|
|
- isEditingCompetency.value = false;
|
|
|
- ElMessage.success('能力标签已更新');
|
|
|
- } catch (error) {
|
|
|
- console.error('更新能力标签失败:', error);
|
|
|
- ElMessage.error('更新能力标签失败');
|
|
|
- }
|
|
|
-};
|
|
|
-</script>
|
|
|
-
|
|
|
-<style scoped>
|
|
|
-.position-detail-container {
|
|
|
- padding: 20px;
|
|
|
- width: 80% !important;
|
|
|
- margin: 0 auto;
|
|
|
-}
|
|
|
-
|
|
|
-.header-container {
|
|
|
- display: flex;
|
|
|
- justify-content: space-between;
|
|
|
- align-items: center;
|
|
|
- margin-bottom: 20px;
|
|
|
-}
|
|
|
-
|
|
|
-.header-actions {
|
|
|
- display: flex;
|
|
|
- gap: 10px;
|
|
|
-}
|
|
|
-
|
|
|
-.detail-content {
|
|
|
- display: flex;
|
|
|
- gap: 20px;
|
|
|
-}
|
|
|
-
|
|
|
-.detail-card {
|
|
|
- flex: 2;
|
|
|
-}
|
|
|
-
|
|
|
-.status-cards {
|
|
|
- flex: 1;
|
|
|
- display: flex;
|
|
|
- flex-direction: column;
|
|
|
- gap: 20px;
|
|
|
-}
|
|
|
-
|
|
|
-.section-title {
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- margin-bottom: 20px;
|
|
|
- font-weight: bold;
|
|
|
- color: #333;
|
|
|
- position: relative;
|
|
|
-}
|
|
|
-
|
|
|
-.section-line {
|
|
|
- width: 4px;
|
|
|
- height: 16px;
|
|
|
- background-color: #67C23A;
|
|
|
- margin-right: 8px;
|
|
|
-}
|
|
|
-
|
|
|
-.edit-btn {
|
|
|
- position: absolute;
|
|
|
- right: 0;
|
|
|
- color: #67C23A;
|
|
|
-}
|
|
|
-
|
|
|
-.detail-item {
|
|
|
- display: flex;
|
|
|
- margin-bottom: 20px;
|
|
|
- line-height: 1.5;
|
|
|
-}
|
|
|
-
|
|
|
-.detail-label {
|
|
|
- width: 120px;
|
|
|
- color: #606266;
|
|
|
- font-weight: 500;
|
|
|
-}
|
|
|
-
|
|
|
-.detail-value {
|
|
|
- flex: 1;
|
|
|
- color: #303133;
|
|
|
-}
|
|
|
-
|
|
|
-.html-content {
|
|
|
- max-height: 300px;
|
|
|
- overflow-y: auto;
|
|
|
- padding: 10px;
|
|
|
- /* background-color: #f9f9f9; */
|
|
|
- border-radius: 4px;
|
|
|
-}
|
|
|
-
|
|
|
-.benefit-tag {
|
|
|
- margin-right: 8px;
|
|
|
- margin-bottom: 8px;
|
|
|
-}
|
|
|
-
|
|
|
-.status-switch {
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- gap: 10px;
|
|
|
-}
|
|
|
-
|
|
|
-.status-text {
|
|
|
- font-size: 14px;
|
|
|
- color: #303133;
|
|
|
-}
|
|
|
-
|
|
|
-.usage-content {
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- margin-top: 10px;
|
|
|
-}
|
|
|
-
|
|
|
-.usage-label {
|
|
|
- width: 80px;
|
|
|
- color: #606266;
|
|
|
-}
|
|
|
-
|
|
|
-.usage-value {
|
|
|
- color: #303133;
|
|
|
- font-weight: 500;
|
|
|
-}
|
|
|
-
|
|
|
-.process-steps {
|
|
|
- margin-top: 20px;
|
|
|
-}
|
|
|
-
|
|
|
-.process-step {
|
|
|
- display: flex;
|
|
|
- align-items: flex-start;
|
|
|
- margin-bottom: 15px;
|
|
|
-}
|
|
|
-
|
|
|
-.step-number {
|
|
|
- width: 24px;
|
|
|
- height: 24px;
|
|
|
- border-radius: 50%;
|
|
|
- background-color: #67C23A;
|
|
|
- color: white;
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- justify-content: center;
|
|
|
- margin-right: 10px;
|
|
|
- font-size: 14px;
|
|
|
-}
|
|
|
-
|
|
|
-.step-content {
|
|
|
- flex: 1;
|
|
|
-}
|
|
|
-
|
|
|
-.step-title {
|
|
|
- font-weight: 500;
|
|
|
- color: #303133;
|
|
|
- margin-bottom: 4px;
|
|
|
-}
|
|
|
-
|
|
|
-.step-desc {
|
|
|
- font-size: 12px;
|
|
|
- color: #909399;
|
|
|
-}
|
|
|
-
|
|
|
-.process-step.disabled .step-number {
|
|
|
- background-color: #909399;
|
|
|
-}
|
|
|
-
|
|
|
-.process-step.disabled .step-title,
|
|
|
-.process-step.disabled .step-desc {
|
|
|
- color: #C0C4CC;
|
|
|
-}
|
|
|
-
|
|
|
-/* 招聘流程编辑对话框样式 */
|
|
|
-.process-dialog-content {
|
|
|
- max-height: 400px;
|
|
|
- overflow-y: auto;
|
|
|
-}
|
|
|
-
|
|
|
-.process-edit-item {
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- padding: 15px;
|
|
|
- border-radius: 4px;
|
|
|
- margin-bottom: 10px;
|
|
|
- background-color: #f5f7fa;
|
|
|
- position: relative;
|
|
|
-}
|
|
|
-
|
|
|
-.process-edit-item.highlight {
|
|
|
- background-color: #f0f9eb;
|
|
|
- border: 1px solid #e1f3d8;
|
|
|
-}
|
|
|
-
|
|
|
-.process-number {
|
|
|
- width: 24px;
|
|
|
- height: 24px;
|
|
|
- border-radius: 50%;
|
|
|
- background-color: #67C23A;
|
|
|
- color: white;
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- justify-content: center;
|
|
|
- margin-right: 15px;
|
|
|
-}
|
|
|
-
|
|
|
-.process-edit-content {
|
|
|
- flex: 1;
|
|
|
-}
|
|
|
-
|
|
|
-.process-edit-desc {
|
|
|
- font-size: 12px;
|
|
|
- color: #909399;
|
|
|
- margin-top: 4px;
|
|
|
-}
|
|
|
-
|
|
|
-.delete-btn {
|
|
|
- position: absolute;
|
|
|
- right: 10px;
|
|
|
- top: 50%;
|
|
|
- transform: translateY(-50%);
|
|
|
-}
|
|
|
-
|
|
|
-/* 添加在每个步骤上方的加号按钮样式 */
|
|
|
-.add-process-btn-top {
|
|
|
- display: flex;
|
|
|
- justify-content: center;
|
|
|
- margin-bottom: 5px;
|
|
|
-}
|
|
|
-
|
|
|
-.add-process-btn-top .el-button {
|
|
|
- color: #67C23A;
|
|
|
- padding: 5px;
|
|
|
-}
|
|
|
-
|
|
|
-/* 确保原有的底部加号按钮样式保持不变 */
|
|
|
-.add-process-btn {
|
|
|
- display: flex;
|
|
|
- justify-content: center;
|
|
|
- margin-top: 15px;
|
|
|
-}
|
|
|
-
|
|
|
-.add-process-btn .el-button {
|
|
|
- color: #67C23A;
|
|
|
-}
|
|
|
-
|
|
|
-/* 流程步骤选项菜单 */
|
|
|
-.process-options-menu {
|
|
|
- position: absolute;
|
|
|
- background-color: white;
|
|
|
- border-radius: 4px;
|
|
|
- box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
|
|
|
- padding: 8px 0;
|
|
|
- z-index: 2000;
|
|
|
- max-height: 300px;
|
|
|
- overflow-y: auto;
|
|
|
- width: 150px;
|
|
|
-}
|
|
|
-
|
|
|
-.process-option-item {
|
|
|
- padding: 8px 16px;
|
|
|
- cursor: pointer;
|
|
|
- font-size: 14px;
|
|
|
- color: #606266;
|
|
|
-}
|
|
|
-
|
|
|
-.process-option-item:hover {
|
|
|
- background-color: #f5f7fa;
|
|
|
- color: #67C23A;
|
|
|
-}
|
|
|
-
|
|
|
-/* AI视频抽屉样式 */
|
|
|
-.ai-video-drawer {
|
|
|
- --el-drawer-padding-primary: 0;
|
|
|
-}
|
|
|
-
|
|
|
-.ai-video-steps {
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- justify-content: center;
|
|
|
- padding: 20px 0;
|
|
|
- border-bottom: 1px solid #e4e7ed;
|
|
|
- background-color: #fff;
|
|
|
-}
|
|
|
-
|
|
|
-.step-item {
|
|
|
- display: flex;
|
|
|
- flex-direction: column;
|
|
|
- align-items: center;
|
|
|
- color: #909399;
|
|
|
- position: relative;
|
|
|
- z-index: 1;
|
|
|
- cursor: pointer;
|
|
|
- transition: all 0.3s;
|
|
|
-}
|
|
|
-
|
|
|
-.step-item:hover {
|
|
|
- color: #67C23A;
|
|
|
-}
|
|
|
-
|
|
|
-.step-item:hover .step-number {
|
|
|
- border-color: #67C23A;
|
|
|
-}
|
|
|
-
|
|
|
-.step-number {
|
|
|
- width: 30px;
|
|
|
- height: 30px;
|
|
|
- border-radius: 50%;
|
|
|
- background-color: #f5f7fa;
|
|
|
- color: #909399;
|
|
|
- border: 1px solid #dcdfe6;
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- justify-content: center;
|
|
|
- margin-bottom: 8px;
|
|
|
- font-weight: bold;
|
|
|
-}
|
|
|
-
|
|
|
-.step-item.active .step-number {
|
|
|
- background-color: #67C23A;
|
|
|
- color: white;
|
|
|
- border-color: #67C23A;
|
|
|
-}
|
|
|
-
|
|
|
-.step-line {
|
|
|
- width: 100px;
|
|
|
- height: 1px;
|
|
|
- background-color: #e4e7ed;
|
|
|
- margin: 0 15px;
|
|
|
- position: relative;
|
|
|
- top: -15px;
|
|
|
-}
|
|
|
-
|
|
|
-.step-line.active-line {
|
|
|
- background-color: #67C23A;
|
|
|
-}
|
|
|
-
|
|
|
-.step-title {
|
|
|
- font-size: 14px;
|
|
|
-}
|
|
|
-
|
|
|
-.ai-video-content {
|
|
|
- padding: 20px;
|
|
|
- height: calc(100% - 120px); /* 减去header和footer高度 */
|
|
|
- overflow-y: auto;
|
|
|
-}
|
|
|
-
|
|
|
-.drawer-footer {
|
|
|
- padding: 10px 20px;
|
|
|
- text-align: right;
|
|
|
- border-top: 1px solid #e4e7ed;
|
|
|
- position: absolute;
|
|
|
- bottom: 0;
|
|
|
- left: 0;
|
|
|
- right: 0;
|
|
|
- background-color: white;
|
|
|
-}
|
|
|
-
|
|
|
-/* 步骤1:考察能力样式 */
|
|
|
-.option-tip {
|
|
|
- margin-bottom: 15px;
|
|
|
- color: #606266;
|
|
|
-}
|
|
|
-
|
|
|
-.new-feature-tip {
|
|
|
- background-color: #f0f9eb;
|
|
|
- padding: 10px;
|
|
|
- border-radius: 4px;
|
|
|
- margin-bottom: 20px;
|
|
|
- font-size: 14px;
|
|
|
- color: #606266;
|
|
|
- line-height: 1.5;
|
|
|
-}
|
|
|
-
|
|
|
-.new-tag {
|
|
|
- display: inline-block;
|
|
|
- background-color: #f56c6c;
|
|
|
- color: white;
|
|
|
- padding: 2px 6px;
|
|
|
- border-radius: 4px;
|
|
|
- font-size: 12px;
|
|
|
- margin-right: 5px;
|
|
|
-}
|
|
|
-
|
|
|
-.ability-options {
|
|
|
- display: grid;
|
|
|
- grid-template-columns: repeat(3, 1fr);
|
|
|
- gap: 15px;
|
|
|
-}
|
|
|
-
|
|
|
-.ability-label {
|
|
|
- font-size: 14px;
|
|
|
- color: #606266;
|
|
|
-}
|
|
|
-
|
|
|
-/* 步骤2:面试题目样式 */
|
|
|
-.interview-settings {
|
|
|
- width: 100%;
|
|
|
-}
|
|
|
-
|
|
|
-.interview-header {
|
|
|
- display: flex;
|
|
|
- justify-content: space-between;
|
|
|
- align-items: center;
|
|
|
- margin-bottom: 20px;
|
|
|
-}
|
|
|
-
|
|
|
-.interview-duration {
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
-}
|
|
|
-
|
|
|
-.duration-value {
|
|
|
- font-weight: bold;
|
|
|
- margin: 0 10px;
|
|
|
-}
|
|
|
-
|
|
|
-.duration-tip {
|
|
|
- color: #909399;
|
|
|
- font-size: 12px;
|
|
|
-}
|
|
|
-
|
|
|
-.interview-mode {
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- margin-bottom: 20px;
|
|
|
-}
|
|
|
-
|
|
|
-.mode-value {
|
|
|
- font-weight: bold;
|
|
|
- margin: 0 10px;
|
|
|
-}
|
|
|
-
|
|
|
-.interview-questions-container {
|
|
|
- min-height: 200px;
|
|
|
- border: 1px dashed #dcdfe6;
|
|
|
- border-radius: 4px;
|
|
|
- margin-bottom: 20px;
|
|
|
- display: flex;
|
|
|
- justify-content: center;
|
|
|
- align-items: center;
|
|
|
-}
|
|
|
-
|
|
|
-.no-questions {
|
|
|
- text-align: center;
|
|
|
- color: #909399;
|
|
|
-}
|
|
|
-
|
|
|
-.ai-tip {
|
|
|
- font-size: 12px;
|
|
|
- color: #c0c4cc;
|
|
|
- margin: 5px 0;
|
|
|
-}
|
|
|
-
|
|
|
-.auto-generate-btn {
|
|
|
- margin-top: 15px;
|
|
|
-}
|
|
|
-
|
|
|
-.multi-dimension-questions {
|
|
|
- margin-top: 30px;
|
|
|
-}
|
|
|
-
|
|
|
-.dimension-title {
|
|
|
- font-weight: bold;
|
|
|
- margin-bottom: 15px;
|
|
|
-}
|
|
|
-
|
|
|
-.dimension-list {
|
|
|
- display: flex;
|
|
|
- flex-direction: column;
|
|
|
- gap: 10px;
|
|
|
-}
|
|
|
-
|
|
|
-.dimension-item {
|
|
|
- border: 1px solid #dcdfe6;
|
|
|
- border-radius: 4px;
|
|
|
- padding: 10px;
|
|
|
-}
|
|
|
-
|
|
|
-.dimension-header {
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- justify-content: space-between;
|
|
|
-}
|
|
|
-
|
|
|
-.expand-icon {
|
|
|
- cursor: pointer;
|
|
|
-}
|
|
|
-
|
|
|
-/* 步骤3:系统设置样式 */
|
|
|
-.system-settings {
|
|
|
- width: 100%;
|
|
|
-}
|
|
|
-
|
|
|
-.setting-section {
|
|
|
- margin-bottom: 30px;
|
|
|
- border-bottom: 1px solid #ebeef5;
|
|
|
- padding-bottom: 20px;
|
|
|
-}
|
|
|
-
|
|
|
-.section-header {
|
|
|
- font-weight: bold;
|
|
|
- color: #303133;
|
|
|
- margin-bottom: 15px;
|
|
|
- position: relative;
|
|
|
- padding-left: 10px;
|
|
|
-}
|
|
|
-
|
|
|
-.section-header::before {
|
|
|
- content: '';
|
|
|
- position: absolute;
|
|
|
- left: 0;
|
|
|
- top: 50%;
|
|
|
- transform: translateY(-50%);
|
|
|
- width: 4px;
|
|
|
- height: 16px;
|
|
|
- background-color: #67C23A;
|
|
|
-}
|
|
|
-
|
|
|
-.rank-settings {
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- margin-bottom: 15px;
|
|
|
-}
|
|
|
-
|
|
|
-.rank-range {
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- margin-right: 30px;
|
|
|
-}
|
|
|
-
|
|
|
-.range-inputs {
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- margin-left: 10px;
|
|
|
-}
|
|
|
-
|
|
|
-.percent-input {
|
|
|
- width: 80px;
|
|
|
-}
|
|
|
-
|
|
|
-.score-display {
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
-}
|
|
|
-
|
|
|
-.score-range {
|
|
|
- margin-left: 10px;
|
|
|
- color: #67C23A;
|
|
|
-}
|
|
|
-
|
|
|
-.add-rank-btn {
|
|
|
- margin-top: 10px;
|
|
|
-}
|
|
|
-
|
|
|
-.validity-setting {
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- margin-bottom: 10px;
|
|
|
-}
|
|
|
-
|
|
|
-.validity-label {
|
|
|
- margin-left: 10px;
|
|
|
-}
|
|
|
-
|
|
|
-.validity-tip {
|
|
|
- font-size: 12px;
|
|
|
- color: #909399;
|
|
|
- margin-top: 5px;
|
|
|
-}
|
|
|
-
|
|
|
-.model-select {
|
|
|
- width: 200px;
|
|
|
-}
|
|
|
-
|
|
|
-@media (max-width: 768px) {
|
|
|
- .ability-options {
|
|
|
- grid-template-columns: repeat(2, 1fr);
|
|
|
- }
|
|
|
-
|
|
|
- .step-line {
|
|
|
- width: 50px;
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-@media (max-width: 480px) {
|
|
|
- .ability-options {
|
|
|
- grid-template-columns: 1fr;
|
|
|
- }
|
|
|
-
|
|
|
- .interview-header {
|
|
|
- flex-direction: column;
|
|
|
- align-items: flex-start;
|
|
|
- }
|
|
|
-
|
|
|
- .interview-actions {
|
|
|
- margin-top: 10px;
|
|
|
- }
|
|
|
-
|
|
|
- .rank-settings {
|
|
|
- flex-direction: column;
|
|
|
- align-items: flex-start;
|
|
|
- }
|
|
|
-
|
|
|
- .rank-range {
|
|
|
- margin-bottom: 10px;
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-/* 视频宣讲弹窗样式 */
|
|
|
-.video-lecture-form {
|
|
|
- padding: 20px 0;
|
|
|
-}
|
|
|
-
|
|
|
-.form-item {
|
|
|
- margin-bottom: 20px;
|
|
|
-}
|
|
|
-
|
|
|
-.form-label {
|
|
|
- font-weight: 500;
|
|
|
- margin-bottom: 8px;
|
|
|
- color: #606266;
|
|
|
-}
|
|
|
-
|
|
|
-.video-uploader {
|
|
|
- width: 100%;
|
|
|
-}
|
|
|
-
|
|
|
-.upload-area {
|
|
|
- width: 100%;
|
|
|
- height: 120px;
|
|
|
- border: 1px dashed #d9d9d9;
|
|
|
- border-radius: 6px;
|
|
|
- display: flex;
|
|
|
- flex-direction: column;
|
|
|
- align-items: center;
|
|
|
- justify-content: center;
|
|
|
- cursor: pointer;
|
|
|
- transition: border-color 0.3s;
|
|
|
-}
|
|
|
-
|
|
|
-.upload-area:hover {
|
|
|
- border-color: #67C23A;
|
|
|
-}
|
|
|
-
|
|
|
-.upload-text {
|
|
|
- color: #909399;
|
|
|
- font-size: 12px;
|
|
|
- margin-top: 8px;
|
|
|
-}
|
|
|
-
|
|
|
-.el-icon {
|
|
|
- font-size: 24px;
|
|
|
- color: #909399;
|
|
|
-}
|
|
|
-
|
|
|
-/* AI实时对话抽屉样式 */
|
|
|
-.ai-chat-drawer {
|
|
|
- --el-drawer-padding-primary: 0;
|
|
|
-}
|
|
|
-
|
|
|
-.ai-chat-content {
|
|
|
- padding: 20px;
|
|
|
- height: calc(100% - 120px);
|
|
|
- overflow-y: auto;
|
|
|
-}
|
|
|
-
|
|
|
-.chat-settings {
|
|
|
- margin-bottom: 30px;
|
|
|
-}
|
|
|
-
|
|
|
-.chat-actions {
|
|
|
- display: flex;
|
|
|
- gap: 10px;
|
|
|
- margin: 20px 0;
|
|
|
-}
|
|
|
-
|
|
|
-.chat-questions {
|
|
|
- margin-top: 20px;
|
|
|
- min-height: 200px;
|
|
|
- border: 1px dashed #dcdfe6;
|
|
|
- border-radius: 4px;
|
|
|
-}
|
|
|
-
|
|
|
-.empty-questions {
|
|
|
- height: 200px;
|
|
|
- display: flex;
|
|
|
- flex-direction: column;
|
|
|
- align-items: center;
|
|
|
- justify-content: center;
|
|
|
- color: #909399;
|
|
|
-}
|
|
|
-
|
|
|
-.tip-text {
|
|
|
- font-size: 12px;
|
|
|
- color: #c0c4cc;
|
|
|
- margin-top: 8px;
|
|
|
-}
|
|
|
-
|
|
|
-.question-list {
|
|
|
- padding: 16px;
|
|
|
- background: #f5f7fa;
|
|
|
- border-radius: 8px;
|
|
|
- min-height: 200px;
|
|
|
-}
|
|
|
-
|
|
|
-.question-card {
|
|
|
- background: #fff;
|
|
|
- border-radius: 8px;
|
|
|
- padding: 20px;
|
|
|
- margin-bottom: 16px;
|
|
|
- box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.05);
|
|
|
-}
|
|
|
-
|
|
|
-.question-header {
|
|
|
- display: flex;
|
|
|
- justify-content: space-between;
|
|
|
- align-items: center;
|
|
|
- margin-bottom: 20px;
|
|
|
- flex-wrap: wrap;
|
|
|
- gap: 10px;
|
|
|
-}
|
|
|
-
|
|
|
-.question-title {
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- gap: 10px;
|
|
|
-}
|
|
|
-
|
|
|
-.question-number {
|
|
|
- color: #333;
|
|
|
- font-weight: 500;
|
|
|
-}
|
|
|
-
|
|
|
-.question-actions {
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- gap: 20px;
|
|
|
-}
|
|
|
-
|
|
|
-.weight-control, .answer-limit {
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- gap: 8px;
|
|
|
-}
|
|
|
-
|
|
|
-.weight-label, .answer-label {
|
|
|
- color: #606266;
|
|
|
- font-size: 14px;
|
|
|
- white-space: nowrap;
|
|
|
-}
|
|
|
-
|
|
|
-:deep(.el-input-number) {
|
|
|
- width: 100px;
|
|
|
-}
|
|
|
-
|
|
|
-:deep(.el-select) {
|
|
|
- width: 120px;
|
|
|
-}
|
|
|
-
|
|
|
-.question-info {
|
|
|
- background: #f8f9fa;
|
|
|
- padding: 15px;
|
|
|
- border-radius: 4px;
|
|
|
-}
|
|
|
-
|
|
|
-.info-item {
|
|
|
- margin-bottom: 12px;
|
|
|
- line-height: 1.6;
|
|
|
-}
|
|
|
-
|
|
|
-.info-item:last-child {
|
|
|
- margin-bottom: 0;
|
|
|
-}
|
|
|
-
|
|
|
-.info-label {
|
|
|
- color: #909399;
|
|
|
- margin-right: 8px;
|
|
|
- font-weight: 500;
|
|
|
-}
|
|
|
-
|
|
|
-/* 问题编辑弹框样式 */
|
|
|
-.question-form {
|
|
|
- padding: 20px 0;
|
|
|
-}
|
|
|
-
|
|
|
-.form-item {
|
|
|
- margin-bottom: 20px;
|
|
|
-}
|
|
|
-
|
|
|
-.form-label {
|
|
|
- font-weight: 500;
|
|
|
- margin-bottom: 8px;
|
|
|
- color: #606266;
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
-}
|
|
|
-
|
|
|
-.required {
|
|
|
- color: #f56c6c;
|
|
|
- margin-left: 4px;
|
|
|
-}
|
|
|
-
|
|
|
-.full-width {
|
|
|
- width: 100%;
|
|
|
-}
|
|
|
-
|
|
|
-:deep(.el-input__count) {
|
|
|
- background: transparent;
|
|
|
-}
|
|
|
-
|
|
|
-:deep(.el-textarea__count) {
|
|
|
- background: transparent;
|
|
|
-}
|
|
|
-
|
|
|
-/* 资料收集对话框样式 */
|
|
|
-.data-collection-form {
|
|
|
- padding: 20px;
|
|
|
-}
|
|
|
-
|
|
|
-/* 表单项样式 */
|
|
|
-.form-item {
|
|
|
- margin-bottom: 24px;
|
|
|
-}
|
|
|
-
|
|
|
-/* 表单标签样式 */
|
|
|
-.form-label {
|
|
|
- font-size: 14px;
|
|
|
- color: #333;
|
|
|
- font-weight: 500;
|
|
|
- margin-bottom: 12px;
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
-}
|
|
|
-
|
|
|
-/* 必填星号样式 */
|
|
|
-.required {
|
|
|
- color: #ff4d4f;
|
|
|
- margin-left: 4px;
|
|
|
- font-size: 14px;
|
|
|
-}
|
|
|
-
|
|
|
-/* 开关样式 */
|
|
|
-:deep(.el-switch) {
|
|
|
- margin-top: 8px;
|
|
|
-}
|
|
|
-
|
|
|
-/* 问题列表容器样式 */
|
|
|
-.question-list {
|
|
|
- margin-top: 12px;
|
|
|
- /* border: 1px solid #e4e7ed; */
|
|
|
- border-radius: 4px;
|
|
|
- padding: 16px;
|
|
|
-/* background-color: #f8f9fa; */
|
|
|
-}
|
|
|
-
|
|
|
-/* 问题项样式 */
|
|
|
-.question-item {
|
|
|
- margin-bottom: 16px;
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- flex-direction: column;
|
|
|
-}
|
|
|
-
|
|
|
-/* 复选框组样式 */
|
|
|
-:deep(.el-checkbox-group) {
|
|
|
- display: flex;
|
|
|
- flex-direction: column;
|
|
|
- gap: 16px;
|
|
|
-}
|
|
|
-
|
|
|
-/* 复选框样式 */
|
|
|
-:deep(.el-checkbox) {
|
|
|
- margin-right: 0;
|
|
|
- height: auto;
|
|
|
-}
|
|
|
-
|
|
|
-/* 复选框标签样式 */
|
|
|
-:deep(.el-checkbox__label) {
|
|
|
- font-size: 14px;
|
|
|
- color: #606266;
|
|
|
-}
|
|
|
-
|
|
|
-.data-collection-dialog {
|
|
|
- .data-collection-form {
|
|
|
- padding: 0;
|
|
|
- }
|
|
|
-
|
|
|
- .question-list {
|
|
|
- padding: 0;
|
|
|
- }
|
|
|
-
|
|
|
- .question-item {
|
|
|
- border: 1px solid #DCDFE6;
|
|
|
- border-radius: 4px;
|
|
|
- margin-bottom: 16px;
|
|
|
- overflow: hidden;
|
|
|
- }
|
|
|
-
|
|
|
- .question-header {
|
|
|
- background: #F5F7FA;
|
|
|
- padding: 12px 16px;
|
|
|
- border-bottom: 1px solid #DCDFE6;
|
|
|
- display: flex;
|
|
|
- justify-content: space-between;
|
|
|
- align-items: center;
|
|
|
- }
|
|
|
-
|
|
|
- .question-title {
|
|
|
- font-size: 14px;
|
|
|
- color: #303133;
|
|
|
- }
|
|
|
-
|
|
|
- .question-type {
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- gap: 4px;
|
|
|
- color: #909399;
|
|
|
- font-size: 14px;
|
|
|
- cursor: pointer;
|
|
|
-
|
|
|
- .el-icon {
|
|
|
- font-size: 12px;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- .question-content {
|
|
|
- padding: 16px;
|
|
|
- }
|
|
|
-
|
|
|
- .user-answer {
|
|
|
- color: #909399;
|
|
|
- font-size: 14px;
|
|
|
- margin-bottom: 16px;
|
|
|
- }
|
|
|
-
|
|
|
- .question-actions {
|
|
|
- display: flex;
|
|
|
- justify-content: space-between;
|
|
|
- align-items: center;
|
|
|
- margin-bottom: 16px;
|
|
|
- padding-bottom: 16px;
|
|
|
- border-bottom: 1px solid #EBEEF5;
|
|
|
- }
|
|
|
-
|
|
|
- .action-left {
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- gap: 8px;
|
|
|
-
|
|
|
- .action-text {
|
|
|
- font-size: 14px;
|
|
|
- color: #606266;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- .action-right {
|
|
|
- display: flex;
|
|
|
- gap: 16px;
|
|
|
-
|
|
|
- .action-icon {
|
|
|
- font-size: 16px;
|
|
|
- color: #909399;
|
|
|
- cursor: pointer;
|
|
|
-
|
|
|
- &:hover {
|
|
|
- color: #409EFF;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- .question-settings {
|
|
|
- display: flex;
|
|
|
- gap: 24px;
|
|
|
- }
|
|
|
-
|
|
|
- .setting-item {
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- gap: 8px;
|
|
|
-
|
|
|
- span {
|
|
|
- font-size: 14px;
|
|
|
- color: #606266;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- .add-question {
|
|
|
- margin-top: 24px;
|
|
|
- text-align: center;
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-/* 简历收集对话框样式 */
|
|
|
-.resume-collection-dialog {
|
|
|
- .resume-collection-form {
|
|
|
- padding: 20px 0;
|
|
|
- }
|
|
|
-
|
|
|
- .switch-label {
|
|
|
- margin-left: 10px;
|
|
|
- font-size: 14px;
|
|
|
- color: #606266;
|
|
|
- }
|
|
|
-
|
|
|
- .resume-preview {
|
|
|
- margin-top: 20px;
|
|
|
- border: 1px solid #e4e7ed;
|
|
|
- border-radius: 4px;
|
|
|
- }
|
|
|
-
|
|
|
- .preview-title {
|
|
|
- padding: 10px 15px;
|
|
|
- background-color: #f5f7fa;
|
|
|
- border-bottom: 1px solid #e4e7ed;
|
|
|
- font-weight: 500;
|
|
|
- color: #606266;
|
|
|
- }
|
|
|
-
|
|
|
- .preview-content {
|
|
|
- padding: 15px;
|
|
|
- }
|
|
|
-
|
|
|
- .preview-item {
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- margin-bottom: 15px;
|
|
|
- }
|
|
|
-
|
|
|
- .item-label {
|
|
|
- width: 80px;
|
|
|
- color: #606266;
|
|
|
- }
|
|
|
-
|
|
|
- .item-input {
|
|
|
- flex: 1;
|
|
|
- height: 32px;
|
|
|
- background-color: #f5f7fa;
|
|
|
- border: 1px solid #dcdfe6;
|
|
|
- border-radius: 4px;
|
|
|
- }
|
|
|
-
|
|
|
- .item-upload {
|
|
|
- flex: 1;
|
|
|
- height: 60px;
|
|
|
- background-color: #f5f7fa;
|
|
|
- border: 1px dashed #dcdfe6;
|
|
|
- border-radius: 4px;
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- justify-content: center;
|
|
|
- }
|
|
|
-
|
|
|
- .item-required {
|
|
|
- color: #f56c6c;
|
|
|
- margin-left: 5px;
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-/* 添加代码测试对话框样式 */
|
|
|
-.code-test-dialog {
|
|
|
- .code-test-form {
|
|
|
- padding: 20px 0;
|
|
|
- }
|
|
|
-
|
|
|
- .switch-label {
|
|
|
- margin-left: 10px;
|
|
|
- font-size: 14px;
|
|
|
- color: #606266;
|
|
|
- }
|
|
|
-
|
|
|
- .test-paper-selector {
|
|
|
- margin-top: 10px;
|
|
|
- }
|
|
|
-
|
|
|
- .empty-paper {
|
|
|
- display: flex;
|
|
|
- flex-direction: column;
|
|
|
- align-items: center;
|
|
|
- justify-content: center;
|
|
|
- padding: 30px;
|
|
|
- border: 1px dashed #dcdfe6;
|
|
|
- border-radius: 4px;
|
|
|
- background-color: #f8f9fa;
|
|
|
- }
|
|
|
-
|
|
|
- .tip-text {
|
|
|
- margin-top: 10px;
|
|
|
- font-size: 12px;
|
|
|
- color: #909399;
|
|
|
- }
|
|
|
-
|
|
|
- .selected-paper {
|
|
|
- display: flex;
|
|
|
- justify-content: space-between;
|
|
|
- align-items: center;
|
|
|
- padding: 15px;
|
|
|
- border: 1px solid #dcdfe6;
|
|
|
- border-radius: 4px;
|
|
|
- background-color: #f8f9fa;
|
|
|
- }
|
|
|
-
|
|
|
- .paper-info {
|
|
|
- flex: 1;
|
|
|
- }
|
|
|
-
|
|
|
- .paper-title {
|
|
|
- font-weight: 500;
|
|
|
- color: #303133;
|
|
|
- margin-bottom: 5px;
|
|
|
- }
|
|
|
-
|
|
|
- .paper-meta {
|
|
|
- display: flex;
|
|
|
- gap: 15px;
|
|
|
- font-size: 12px;
|
|
|
- color: #909399;
|
|
|
- }
|
|
|
-
|
|
|
- .paper-actions {
|
|
|
- display: flex;
|
|
|
- gap: 10px;
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-/* 添加打字测试对话框样式 */
|
|
|
-.typing-test-dialog {
|
|
|
- .typing-test-form {
|
|
|
- padding: 20px;
|
|
|
- }
|
|
|
-
|
|
|
- .form-item {
|
|
|
- margin-bottom: 24px;
|
|
|
- position: relative;
|
|
|
- }
|
|
|
-
|
|
|
- .form-label {
|
|
|
- font-weight: 500;
|
|
|
- margin-bottom: 12px;
|
|
|
- color: #606266;
|
|
|
- font-size: 14px;
|
|
|
- }
|
|
|
-
|
|
|
- .article-selection {
|
|
|
- margin-top: 10px;
|
|
|
- }
|
|
|
-
|
|
|
- .add-article-btn {
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- gap: 5px;
|
|
|
- font-size: 13px;
|
|
|
- }
|
|
|
-
|
|
|
- .time-input-container {
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- }
|
|
|
-
|
|
|
- .time-input {
|
|
|
- width: 120px;
|
|
|
- }
|
|
|
-
|
|
|
- .time-unit {
|
|
|
- margin-left: 10px;
|
|
|
- color: #606266;
|
|
|
- }
|
|
|
-
|
|
|
- .preview-uploader {
|
|
|
- width: 100px;
|
|
|
- }
|
|
|
-
|
|
|
- .upload-area {
|
|
|
- width: 100px;
|
|
|
- height: 100px;
|
|
|
- border: 1px dashed #d9d9d9;
|
|
|
- border-radius: 6px;
|
|
|
- display: flex;
|
|
|
- flex-direction: column;
|
|
|
- align-items: center;
|
|
|
- justify-content: center;
|
|
|
- cursor: pointer;
|
|
|
- transition: border-color 0.3s;
|
|
|
- }
|
|
|
-
|
|
|
- .upload-area:hover {
|
|
|
- border-color: #67C23A;
|
|
|
- }
|
|
|
-
|
|
|
- .upload-text {
|
|
|
- color: #909399;
|
|
|
- font-size: 12px;
|
|
|
- margin-top: 8px;
|
|
|
- }
|
|
|
-
|
|
|
- .notes-counter {
|
|
|
- position: absolute;
|
|
|
- right: 10px;
|
|
|
- bottom: -20px;
|
|
|
- font-size: 12px;
|
|
|
- color: #909399;
|
|
|
- }
|
|
|
-
|
|
|
- .criteria-options {
|
|
|
- display: flex;
|
|
|
- gap: 20px;
|
|
|
- }
|
|
|
-
|
|
|
- /* 添加以下新样式 */
|
|
|
- :deep(.el-radio) {
|
|
|
- margin-right: 30px;
|
|
|
- }
|
|
|
-
|
|
|
- :deep(.el-radio__label) {
|
|
|
- font-size: 14px;
|
|
|
- }
|
|
|
-
|
|
|
- :deep(.el-textarea) {
|
|
|
- margin-bottom: 5px;
|
|
|
- }
|
|
|
-
|
|
|
- :deep(.el-checkbox__label) {
|
|
|
- font-size: 14px;
|
|
|
- }
|
|
|
-
|
|
|
- :deep(.el-input) {
|
|
|
- width: auto;
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-.title-edit-container {
|
|
|
- display: flex;
|
|
|
- align-items: flex-start;
|
|
|
- gap: 10px;
|
|
|
- flex-direction: column;
|
|
|
-}
|
|
|
-
|
|
|
-.edit-title-btn {
|
|
|
- color: #67C23A;
|
|
|
-}
|
|
|
-
|
|
|
-/* 职位名称编辑相关样式 */
|
|
|
-.edit-title-btn {
|
|
|
- margin-left: 10px;
|
|
|
- font-size: 14px;
|
|
|
- color: #409EFF;
|
|
|
-}
|
|
|
-
|
|
|
-.title-edit-container {
|
|
|
- flex: 1;
|
|
|
-}
|
|
|
-
|
|
|
-.title-edit-actions {
|
|
|
- display: flex;
|
|
|
- justify-content: flex-end;
|
|
|
- margin-top: 10px;
|
|
|
- gap: 10px;
|
|
|
-}
|
|
|
-
|
|
|
-/* 确保在编辑模式下输入框有足够的宽度 */
|
|
|
-.title-edit-container :deep(.el-input) {
|
|
|
- width: 100%;
|
|
|
-}
|
|
|
-
|
|
|
-.competency-tag {
|
|
|
- margin-right: 8px;
|
|
|
- margin-bottom: 8px;
|
|
|
-}
|
|
|
-
|
|
|
-.info-icon {
|
|
|
- margin-left: 4px;
|
|
|
- font-size: 14px;
|
|
|
- color: #909399;
|
|
|
- float: right;
|
|
|
-}
|
|
|
-
|
|
|
-:deep(.el-checkbox-group) {
|
|
|
- display: flex;
|
|
|
- flex-wrap: wrap;
|
|
|
- gap: 12px;
|
|
|
-}
|
|
|
-
|
|
|
-:deep(.el-checkbox) {
|
|
|
- margin-right: 0;
|
|
|
-}
|
|
|
-</style>
|