| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326 |
- <template>
- <view class="container">
- <view class="content">
- <!-- 装饰背景 -->
- <view class="decor-bg"></view>
- <!-- 加载状态 -->
- <view class="loading-tip" v-if="loading">
- <text>加载中...</text>
- </view>
- <view class="info-card" v-else>
- <view class="info-list">
- <!-- 测评岗位 -->
- <view class="info-item">
- <view class="label-wrap">
- <view class="dot"></view>
- <text class="label">测评岗位</text>
- </view>
- <text class="value">{{ examInfo.position || '—' }}</text>
- </view>
-
- <!-- 考题题型(从abilityConfigs汇总) -->
- <view class="info-item" v-if="examInfo.questionTypes">
- <view class="label-wrap">
- <view class="dot"></view>
- <text class="label">考题题型</text>
- </view>
- <text class="value">{{ examInfo.questionTypes }}</text>
- </view>
- <!-- 考试时间 -->
- <view class="info-item" v-if="examInfo.totalTime">
- <view class="label-wrap">
- <view class="dot"></view>
- <text class="label">考试时间</text>
- </view>
- <text class="value">{{ examInfo.totalTime }}分钟</text>
- </view>
- <!-- 合格分数(遍历每个能力配置) -->
- <view class="info-item border-none" v-if="examInfo.passMark">
- <view class="label-wrap">
- <view class="dot"></view>
- <text class="label">合格标准</text>
- </view>
- <view class="value-group">
- <text class="value">满分{{ examInfo.totalScore }}分,{{ examInfo.passMark }}分及格</text>
- <!-- 各能力及格线(当多于1个能力时展示) -->
- <text class="sub-value" v-if="examInfo.abilityPassDesc">{{ examInfo.abilityPassDesc }}</text>
- </view>
- </view>
- </view>
- </view>
- <!-- 按钮区域 -->
- <view class="action-area">
- <button class="start-btn" @click="startQuiz" :disabled="loading">确认开始测评</button>
- <text class="bottom-tip">请确保在安静、网络稳定的环境下进行</text>
- </view>
- </view>
- </view>
- </template>
- <script setup lang="js">
- import { onLoad } from '@dcloudio/uni-app';
- import { ref } from 'vue';
- import { getAssessmentDetail, getAssessmentList, createExamApply } from '../../api/assessment.js';
- const source = ref('');
- const assessmentId = ref('');
- const loading = ref(true);
- // 考试汇总信息
- const examInfo = ref({
- position: '', // 测评岗位
- questionTypes: '', // 题型描述
- totalTime: 0, // 总时长(分钟)
- totalScore: 0, // 总分
- passMark: 0, // 合格分
- abilityPassDesc: '', // 各能力子合格描述
- });
- // 保存第一个有链接的静态考试链接(兜底用)
- const firstExamLink = ref('');
- onLoad(async (options) => {
- if (options.source) source.value = options.source;
- if (options.id) assessmentId.value = options.id;
- // 加载测评详情
- await loadExamInfo();
- });
- /**
- * 从后端加载测评详情并解析考试配置
- */
- const loadExamInfo = async () => {
- loading.value = true;
- try {
- let data = null;
- if (assessmentId.value) {
- // 优先用传入的测评ID查详情
- const res = await getAssessmentDetail(assessmentId.value);
- if (res.code === 200 && res.data) {
- data = res.data;
- }
- }
- if (!data) {
- // 无ID时兜底:取第一个测评
- const listRes = await getAssessmentList({ pageNum: 1, pageSize: 1 });
- if (listRes.code === 200 && Array.isArray(listRes.rows) && listRes.rows.length > 0) {
- const detailRes = await getAssessmentDetail(listRes.rows[0].id);
- if (detailRes.code === 200 && detailRes.data) {
- data = detailRes.data;
- // 如果原来没有 assessmentId,使用兜底的ID
- if (!assessmentId.value) {
- assessmentId.value = listRes.rows[0].id;
- console.log('使用兜底测评ID:', assessmentId.value);
- }
- }
- }
- }
- if (data) {
- // 解析岗位信息
- examInfo.value.position = data.position || data.evaluationName || '—';
- // 解析能力配置列表
- const abilityConfigs = Array.isArray(data.abilityConfigs) ? data.abilityConfigs : [];
- if (abilityConfigs.length > 0) {
- // 计算总时长(各能力时长之和)
- const totalTime = abilityConfigs.reduce((sum, c) => sum + (c.thirdExamTime || 0), 0);
- examInfo.value.totalTime = totalTime;
- // 计算总分
- const totalScore = abilityConfigs.reduce((sum, c) => sum + (c.thirdExamTotalScore || 0), 0);
- examInfo.value.totalScore = totalScore;
- // 及格分(汇总所有能力的及格分)
- const passMark = abilityConfigs.reduce((sum, c) => sum + (c.thirdExamPassMark || 0), 0);
- examInfo.value.passMark = passMark;
- // 多能力时:展示各能力及格线描述
- if (abilityConfigs.length > 1) {
- const descs = abilityConfigs.map(c => `${c.abilityName || c.thirdExamName || '能力'}及格${c.thirdExamPassMark || 0}分`);
- examInfo.value.abilityPassDesc = descs.join(',');
- }
- // 固定题型描述
- examInfo.value.questionTypes = '单选/多选/问答';
- // 缓存第一个有效静态链接(兜底用)
- const firstConfig = abilityConfigs.find(c => c && c.thirdExamLink);
- if (firstConfig) {
- firstExamLink.value = firstConfig.thirdExamLink;
- }
- }
- }
- } catch (err) {
- console.error('加载测评信息失败:', err);
- } finally {
- loading.value = false;
- }
- };
- /**
- * 点击确认开始测评
- */
- const startQuiz = async () => {
- try {
- if (!firstExamLink.value && !assessmentId.value) {
- uni.showToast({ title: '未配置考试链接', icon: 'none' });
- return;
- }
- // 获取当前登录用户信息
- const userInfo = uni.getStorageSync('userInfo') || {};
- const studentId = userInfo.studentId;
-
- if (!studentId) {
- uni.showToast({ title: '请先登录', icon: 'none' });
- return;
- }
- // 如果有 assessmentId,先创建测评申请记录
- if (assessmentId.value) {
- try {
- uni.showLoading({ title: '创建测评申请...' });
- console.log('准备创建测评申请,evaluationId:', assessmentId.value, 'studentId:', studentId);
-
- // 创建测评申请记录
- const applyRes = await createExamApply(assessmentId.value, studentId);
- console.log('测评申请创建结果:', applyRes);
-
- uni.hideLoading();
-
- if (applyRes.code !== 200) {
- uni.showToast({ title: applyRes.msg || '创建测评申请失败', icon: 'none' });
- return;
- }
-
- console.log('测评申请创建成功,申请ID:', applyRes.data.id);
- } catch (apiError) {
- uni.hideLoading();
- console.error('创建测评申请失败:', apiError);
- // 创建申请失败不阻止进入考试,只是记录日志
- console.warn('测评申请创建失败,但仍允许进入考试');
- }
- }
- // 保持原有的跳转逻辑
- uni.navigateTo({
- url: `/pages/common/webview?mode=kaoshixing&assessmentId=${encodeURIComponent(assessmentId.value || '')}&fallbackUrl=${encodeURIComponent(firstExamLink.value || '')}`
- });
- } catch (error) {
- console.error('打开考试链接失败:', error);
- uni.showToast({ title: '打开考试链接失败', icon: 'none' });
- }
- };
- </script>
- <style lang="scss" scoped>
- .container {
- min-height: 100vh;
- background-color: #F8F9FB;
- display: flex;
- flex-direction: column;
- }
- .content {
- flex: 1;
- padding: 30rpx 40rpx;
- position: relative;
- overflow: hidden;
- }
- .loading-tip {
- display: flex; justify-content: center; align-items: center;
- padding: 80rpx 0; font-size: 28rpx; color: #999;
- }
- .decor-bg {
- position: absolute; top: -100rpx; right: -100rpx; width: 400rpx; height: 400rpx;
- background: radial-gradient(circle, rgba(31,108,255,0.05) 0%, transparent 70%);
- z-index: 0;
- }
- .info-card {
- background: #FFF;
- border-radius: 32rpx;
- padding: 40rpx;
- box-shadow: 0 8rpx 30rpx rgba(0,0,0,0.02);
- position: relative;
- z-index: 1;
- }
- .info-list {
- display: flex;
- flex-direction: column;
- }
- .info-item {
- display: flex;
- align-items: center;
- padding: 36rpx 0;
- border-bottom: 2rpx solid #F5F7FA;
-
- &.border-none { border-bottom: none; }
- .label-wrap {
- display: flex;
- align-items: center;
- width: 200rpx;
- flex-shrink: 0;
-
- .dot { width: 8rpx; height: 8rpx; background: #1F6CFF; border-radius: 50%; margin-right: 16rpx; }
- .label { font-size: 30rpx; color: #666; font-weight: 500; }
- }
-
- .value {
- font-size: 30rpx;
- color: #1A1A1A;
- font-weight: bold;
- flex: 1;
- }
-
- .value-group {
- display: flex;
- flex-direction: column;
- gap: 8rpx;
- .sub-value { font-size: 24rpx; color: #999; font-weight: normal; }
- }
- }
- .action-area {
- margin-top: 80rpx;
- display: flex;
- flex-direction: column;
- align-items: center;
- position: relative;
- z-index: 1;
-
- .start-btn {
- width: 100%;
- height: 100rpx;
- background: linear-gradient(135deg, #1F6CFF 0%, #0056FF 100%);
- color: #FFFFFF;
- border-radius: 50rpx;
- display: flex;
- align-items: center;
- justify-content: center;
- font-size: 32rpx;
- font-weight: bold;
- box-shadow: 0 12rpx 24rpx rgba(31, 108, 255, 0.2);
- margin-bottom: 30rpx;
-
- &::after { border: none; }
- &:active { transform: scale(0.98); opacity: 0.9; }
- }
-
- .bottom-tip { font-size: 24rpx; color: #999; }
- }
- </style>
|