|
@@ -0,0 +1,3236 @@
|
|
|
+<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">{{ positionData.title }}</div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- <div class="detail-item">
|
|
|
+ <div class="detail-label">职位性质</div>
|
|
|
+ <div class="detail-value">{{ getJobTypeText(positionData.job_type) }}</div>
|
|
|
+ </div> -->
|
|
|
+
|
|
|
+ <!-- <div class="detail-item">
|
|
|
+ <div class="detail-label">职位性质</div>
|
|
|
+ <div class="detail-value">{{ positionData.job_type_display }}</div>
|
|
|
+ </div> -->
|
|
|
+
|
|
|
+ <!-- <div class="detail-item">
|
|
|
+ <div class="detail-label">工作城市</div>
|
|
|
+ <div class="detail-value">{{ positionData.city || '暂无' }}</div>
|
|
|
+ </div> -->
|
|
|
+
|
|
|
+ <div class="detail-item">
|
|
|
+ <div class="detail-label">工作地点</div>
|
|
|
+ <div class="detail-value">{{ positionData.location || '暂无' }}</div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- <div class="detail-item">
|
|
|
+ <div class="detail-label">门牌号码</div>
|
|
|
+ <div class="detail-value">{{ positionData.address_detail || '暂无' }}</div>
|
|
|
+ </div> -->
|
|
|
+
|
|
|
+ <!-- <div class="detail-item">
|
|
|
+ <div class="detail-label">福利待遇</div>
|
|
|
+ <div class="detail-value">
|
|
|
+ <el-tag v-for="(benefit, index) in positionData.benefits" :key="index" class="benefit-tag">
|
|
|
+ {{ benefit }}
|
|
|
+ </el-tag>
|
|
|
+ <span v-if="!positionData.benefits || positionData.benefits.length === 0">暂无</span>
|
|
|
+ </div>
|
|
|
+ </div> -->
|
|
|
+
|
|
|
+ <div class="detail-item">
|
|
|
+ <div class="detail-label">职位薪资</div>
|
|
|
+ <div class="detail-value">{{ positionData.salary_range || '暂无' }}</div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="detail-item">
|
|
|
+ <div class="detail-label">工作经验</div>
|
|
|
+ <div class="detail-value">{{ positionData.experience || '暂无' }}</div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="detail-item">
|
|
|
+ <div class="detail-label">学历要求</div>
|
|
|
+ <div class="detail-value">{{ positionData.education || '暂无' }}</div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="detail-item">
|
|
|
+ <div class="detail-label">所属部门</div>
|
|
|
+ <div class="detail-value">{{ positionData.department || '暂无' }}</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">{{ positionData.end_date || '暂无' }}</div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="detail-item">
|
|
|
+ <div class="detail-label">职位要求</div>
|
|
|
+ <div class="detail-value html-content" v-html="positionData.requirements"></div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="detail-item">
|
|
|
+ <div class="detail-label">职位描述</div>
|
|
|
+ <div class="detail-value html-content" v-html="positionData.description"></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 } from '@element-plus/icons-vue';
|
|
|
+
|
|
|
+// 添加 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: '',
|
|
|
+ experience: '',
|
|
|
+ education: '',
|
|
|
+});
|
|
|
+
|
|
|
+// 招聘流程数据 - 修改为普通数组而非 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: idValue };
|
|
|
+ const response = await api.GetObj(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();
|
|
|
+});
|
|
|
+
|
|
|
+// 添加代码测试相关的状态和方法
|
|
|
+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();
|
|
|
+};
|
|
|
+</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;
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|