|
@@ -107,12 +107,54 @@
|
|
|
<!-- 交卷结果遮罩 -->
|
|
<!-- 交卷结果遮罩 -->
|
|
|
<view v-if="showResult" class="result-shade">
|
|
<view v-if="showResult" class="result-shade">
|
|
|
<view class="result-card">
|
|
<view class="result-card">
|
|
|
- <view class="result-title">{{ resultData.title }}</view>
|
|
|
|
|
- <view class="result-score">{{ resultData.score }} 分</view>
|
|
|
|
|
- <view class="result-desc">{{ resultData.desc }}</view>
|
|
|
|
|
|
|
+ <view class="result-score-wrap">
|
|
|
|
|
+ <text class="result-score-num">{{ resultData.score }}</text>
|
|
|
|
|
+ <text class="result-score-unit">分</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <view class="result-score-label">本次考试成绩</view>
|
|
|
|
|
+ <view class="result-pass-pill" :class="resultData.isPass ? 'is-pass' : 'is-fail'">
|
|
|
|
|
+ <text class="result-pass-text">{{ resultData.isPass ? '考试通过' : '考试未通过' }}</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <view class="result-grid">
|
|
|
|
|
+ <view class="result-grid-item">
|
|
|
|
|
+ <view class="result-grid-label">满分</view>
|
|
|
|
|
+ <view class="result-grid-value">{{ resultData.totalScore }}</view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <view class="result-grid-item">
|
|
|
|
|
+ <view class="result-grid-label">及格分</view>
|
|
|
|
|
+ <view class="result-grid-value text-orange">{{ resultData.passScore }}</view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <view class="result-grid-item">
|
|
|
|
|
+ <view class="result-grid-label">用时</view>
|
|
|
|
|
+ <view class="result-grid-value">{{ resultData.usedTime }}</view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <view class="result-stats">
|
|
|
|
|
+ <view class="result-stats-row">
|
|
|
|
|
+ <text class="result-stats-label">正确题数</text>
|
|
|
|
|
+ <text class="result-stats-value text-green">{{ resultData.correctCount }}</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <view class="result-stats-row">
|
|
|
|
|
+ <text class="result-stats-label">错误题数</text>
|
|
|
|
|
+ <text class="result-stats-value text-red">{{ resultData.wrongCount }}</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <view class="result-stats-row">
|
|
|
|
|
+ <text class="result-stats-label">正确率</text>
|
|
|
|
|
+ <text class="result-stats-value text-blue">{{ resultData.accuracy }}</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
<view class="result-btns">
|
|
<view class="result-btns">
|
|
|
- <view v-if="resultData.canRetake" class="result-btn result-btn-outline" @click="retakeExam">重新考试</view>
|
|
|
|
|
- <view class="result-btn result-btn-primary" @click="closeResult">{{ resultData.canRetake ? '返回' : '确认' }}</view>
|
|
|
|
|
|
|
+ <view v-if="!resultData.isPass" class="result-btn result-btn-outline" @click="reviewMistakes">查看错题</view>
|
|
|
|
|
+ <view v-if="resultData.canRetake" class="result-btn result-btn-primary" @click="retakeExam">重新考试</view>
|
|
|
|
|
+ <view v-else class="result-btn result-btn-primary" @click="closeResult">返回工作台</view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <view class="result-cert">
|
|
|
|
|
+ <text class="result-cert-icon">🏆</text>
|
|
|
|
|
+ <view class="result-cert-info">
|
|
|
|
|
+ <view class="result-cert-title">您已获得证书!</view>
|
|
|
|
|
+ <view class="result-cert-name">{{ resultData.certName }}</view>
|
|
|
|
|
+ <view class="result-cert-btn" @click="goCertificate(resultData.certUrl)">查看证书</view>
|
|
|
|
|
+ </view>
|
|
|
</view>
|
|
</view>
|
|
|
</view>
|
|
</view>
|
|
|
</view>
|
|
</view>
|
|
@@ -141,6 +183,7 @@
|
|
|
groupIndex: 0,
|
|
groupIndex: 0,
|
|
|
questionIndex: 0,
|
|
questionIndex: 0,
|
|
|
remainingSeconds: 0,
|
|
remainingSeconds: 0,
|
|
|
|
|
+ initialSeconds: 0,
|
|
|
timer: null,
|
|
timer: null,
|
|
|
hasWarnedTime: false,
|
|
hasWarnedTime: false,
|
|
|
showQuestionNav: false,
|
|
showQuestionNav: false,
|
|
@@ -257,6 +300,7 @@
|
|
|
const { data } = await examUserExamGetExamSurplusTime({ attemptId: this.attemptId });
|
|
const { data } = await examUserExamGetExamSurplusTime({ attemptId: this.attemptId });
|
|
|
if (data.code === 200) {
|
|
if (data.code === 200) {
|
|
|
this.remainingSeconds = Number(data.data) || 0;
|
|
this.remainingSeconds = Number(data.data) || 0;
|
|
|
|
|
+ if (!this.initialSeconds) this.initialSeconds = this.remainingSeconds;
|
|
|
this.clearTimer();
|
|
this.clearTimer();
|
|
|
this.startTimer();
|
|
this.startTimer();
|
|
|
}
|
|
}
|
|
@@ -422,29 +466,37 @@
|
|
|
},
|
|
},
|
|
|
buildResult(resp) {
|
|
buildResult(resp) {
|
|
|
const score = resp.totalScore || 0;
|
|
const score = resp.totalScore || 0;
|
|
|
- const pass = score >= (this.examInfo.passScore || 0);
|
|
|
|
|
- if (pass) {
|
|
|
|
|
- this.resultData = {
|
|
|
|
|
- title: '考试通过',
|
|
|
|
|
- score: score,
|
|
|
|
|
- desc: resp.needPrompt === 1 ? '恭喜!本次成绩为最佳记录' : '考试已通过',
|
|
|
|
|
- canRetake: false,
|
|
|
|
|
- };
|
|
|
|
|
- } else if (resp.canContinueExam === 1) {
|
|
|
|
|
- this.resultData = {
|
|
|
|
|
- title: '考试未通过',
|
|
|
|
|
- score: score,
|
|
|
|
|
- desc: `未达及格线 ${this.examInfo.passScore} 分,可重新考试`,
|
|
|
|
|
- canRetake: true,
|
|
|
|
|
- };
|
|
|
|
|
- } else {
|
|
|
|
|
- this.resultData = {
|
|
|
|
|
- title: '考试未通过',
|
|
|
|
|
- score: score,
|
|
|
|
|
- desc: '未达及格线,暂无剩余考试机会',
|
|
|
|
|
- canRetake: false,
|
|
|
|
|
- };
|
|
|
|
|
|
|
+ const passScore = this.examInfo.passScore || 0;
|
|
|
|
|
+ const pass = score >= passScore;
|
|
|
|
|
+ const correct = this.pickNumber(resp.correctCount, resp.correctNum);
|
|
|
|
|
+ const wrong = this.pickNumber(resp.wrongCount, resp.wrongNum);
|
|
|
|
|
+ const total = this.pickNumber(resp.totalQuestionNum, this.totalCount);
|
|
|
|
|
+ this.resultData = {
|
|
|
|
|
+ score: score,
|
|
|
|
|
+ isPass: pass,
|
|
|
|
|
+ totalScore: this.examInfo.totalScore || 0,
|
|
|
|
|
+ passScore: passScore,
|
|
|
|
|
+ usedTime: this.buildUsedTime(),
|
|
|
|
|
+ correctCount: correct == null ? '-' : `${correct} 题`,
|
|
|
|
|
+ wrongCount: wrong == null ? '-' : `${wrong} 题`,
|
|
|
|
|
+ accuracy: (correct == null || !total) ? '-' : `${Math.round((correct / total) * 100)}%`,
|
|
|
|
|
+ canRetake: !pass && resp.canContinueExam === 1,
|
|
|
|
|
+ certName: resp.certName || '',
|
|
|
|
|
+ certUrl: resp.certUrl || '',
|
|
|
|
|
+ };
|
|
|
|
|
+ },
|
|
|
|
|
+ pickNumber(...vals) {
|
|
|
|
|
+ for (const v of vals) {
|
|
|
|
|
+ if (v !== undefined && v !== null && v !== '') return Number(v);
|
|
|
}
|
|
}
|
|
|
|
|
+ return null;
|
|
|
|
|
+ },
|
|
|
|
|
+ buildUsedTime() {
|
|
|
|
|
+ if (!this.initialSeconds) return '-';
|
|
|
|
|
+ const used = Math.max(0, this.initialSeconds - Math.floor(this.remainingSeconds));
|
|
|
|
|
+ const m = Math.floor(used / 60);
|
|
|
|
|
+ const s = used % 60;
|
|
|
|
|
+ return `${m}'${s < 10 ? '0' : ''}${s}"`;
|
|
|
},
|
|
},
|
|
|
async retakeExam() {
|
|
async retakeExam() {
|
|
|
try {
|
|
try {
|
|
@@ -460,6 +512,7 @@
|
|
|
this.groupIndex = 0;
|
|
this.groupIndex = 0;
|
|
|
this.questionIndex = 0;
|
|
this.questionIndex = 0;
|
|
|
this.remainingSeconds = 0;
|
|
this.remainingSeconds = 0;
|
|
|
|
|
+ this.initialSeconds = 0;
|
|
|
this.pageLoading = true;
|
|
this.pageLoading = true;
|
|
|
this.loadSidebar();
|
|
this.loadSidebar();
|
|
|
} else {
|
|
} else {
|
|
@@ -474,6 +527,41 @@
|
|
|
this.showResult = false;
|
|
this.showResult = false;
|
|
|
uni.navigateBack();
|
|
uni.navigateBack();
|
|
|
},
|
|
},
|
|
|
|
|
+ reviewMistakes() {
|
|
|
|
|
+ uni.showToast({ title: '错题查看功能开发中', icon: 'none' });
|
|
|
|
|
+ },
|
|
|
|
|
+ goCertificate(url) {
|
|
|
|
|
+ if (!url) {
|
|
|
|
|
+ uni.showToast({ title: '暂无证书', icon: 'none' });
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ uni.showLoading({ title: '加载中...', mask: true });
|
|
|
|
|
+ uni.downloadFile({
|
|
|
|
|
+ url: url,
|
|
|
|
|
+ success: (res) => {
|
|
|
|
|
+ if (res.statusCode === 200) {
|
|
|
|
|
+ uni.openDocument({
|
|
|
|
|
+ filePath: res.tempFilePath,
|
|
|
|
|
+ fileType: 'pdf',
|
|
|
|
|
+ showMenu: true,
|
|
|
|
|
+ fail: () => {
|
|
|
|
|
+ uni.showToast({ title: '打开证书失败', icon: 'none' });
|
|
|
|
|
+ },
|
|
|
|
|
+ complete: () => {
|
|
|
|
|
+ uni.hideLoading();
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+ } else {
|
|
|
|
|
+ uni.hideLoading();
|
|
|
|
|
+ uni.showToast({ title: '证书加载失败', icon: 'none' });
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ fail: () => {
|
|
|
|
|
+ uni.hideLoading();
|
|
|
|
|
+ uni.showToast({ title: '证书加载失败', icon: 'none' });
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+ },
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
</script>
|
|
</script>
|
|
@@ -794,34 +882,105 @@
|
|
|
width 580rpx
|
|
width 580rpx
|
|
|
background #fff
|
|
background #fff
|
|
|
border-radius 24rpx
|
|
border-radius 24rpx
|
|
|
- padding 48rpx 40rpx 36rpx
|
|
|
|
|
|
|
+ padding 40rpx 32rpx 32rpx
|
|
|
display flex
|
|
display flex
|
|
|
flex-direction column
|
|
flex-direction column
|
|
|
align-items center
|
|
align-items center
|
|
|
|
|
|
|
|
- .result-title
|
|
|
|
|
- font-size 32rpx
|
|
|
|
|
|
|
+ .result-score-wrap
|
|
|
|
|
+ display flex
|
|
|
|
|
+ align-items baseline
|
|
|
|
|
+ line-height 1
|
|
|
|
|
+
|
|
|
|
|
+ .result-score-num
|
|
|
|
|
+ font-size 112rpx
|
|
|
|
|
+ font-weight 900
|
|
|
|
|
+ color #1857d4
|
|
|
|
|
+
|
|
|
|
|
+ .result-score-unit
|
|
|
|
|
+ font-size 30rpx
|
|
|
font-weight 700
|
|
font-weight 700
|
|
|
- color #222
|
|
|
|
|
|
|
+ color #1857d4
|
|
|
|
|
+ margin-left 6rpx
|
|
|
|
|
+
|
|
|
|
|
+ .result-score-label
|
|
|
|
|
+ font-size 24rpx
|
|
|
|
|
+ color #8896a7
|
|
|
|
|
+ margin-top 4rpx
|
|
|
margin-bottom 20rpx
|
|
margin-bottom 20rpx
|
|
|
|
|
|
|
|
- .result-score
|
|
|
|
|
- font-size 72rpx
|
|
|
|
|
|
|
+ .result-pass-pill
|
|
|
|
|
+ display inline-flex
|
|
|
|
|
+ align-items center
|
|
|
|
|
+ justify-content center
|
|
|
|
|
+ border-radius 40rpx
|
|
|
|
|
+ padding 8rpx 40rpx
|
|
|
|
|
+ margin-bottom 28rpx
|
|
|
|
|
+
|
|
|
|
|
+ .result-pass-pill.is-pass
|
|
|
|
|
+ background #f6ffed
|
|
|
|
|
+
|
|
|
|
|
+ .result-pass-pill.is-fail
|
|
|
|
|
+ background #fff5f5
|
|
|
|
|
+
|
|
|
|
|
+ .result-pass-text
|
|
|
|
|
+ font-size 30rpx
|
|
|
font-weight 700
|
|
font-weight 700
|
|
|
- color #1677ff
|
|
|
|
|
- line-height 1
|
|
|
|
|
- margin-bottom 16rpx
|
|
|
|
|
|
|
|
|
|
- .result-desc
|
|
|
|
|
- font-size 26rpx
|
|
|
|
|
- color #666
|
|
|
|
|
|
|
+ .result-pass-pill.is-pass .result-pass-text
|
|
|
|
|
+ color #10a37f
|
|
|
|
|
+
|
|
|
|
|
+ .result-pass-pill.is-fail .result-pass-text
|
|
|
|
|
+ color #e53e3e
|
|
|
|
|
+
|
|
|
|
|
+ .result-grid
|
|
|
|
|
+ display flex
|
|
|
|
|
+ width 100%
|
|
|
|
|
+ gap 16rpx
|
|
|
|
|
+ margin-bottom 24rpx
|
|
|
|
|
+
|
|
|
|
|
+ .result-grid-item
|
|
|
|
|
+ flex 1
|
|
|
|
|
+ background #f4f6fa
|
|
|
|
|
+ border-radius 16rpx
|
|
|
|
|
+ padding 18rpx 12rpx
|
|
|
text-align center
|
|
text-align center
|
|
|
- margin-bottom 36rpx
|
|
|
|
|
- line-height 1.6
|
|
|
|
|
|
|
+
|
|
|
|
|
+ .result-grid-label
|
|
|
|
|
+ font-size 22rpx
|
|
|
|
|
+ color #8896a7
|
|
|
|
|
+ margin-bottom 8rpx
|
|
|
|
|
+
|
|
|
|
|
+ .result-grid-value
|
|
|
|
|
+ font-size 28rpx
|
|
|
|
|
+ font-weight 500
|
|
|
|
|
+ color #1a2233
|
|
|
|
|
+
|
|
|
|
|
+ .result-stats
|
|
|
|
|
+ width 100%
|
|
|
|
|
+ background #f4f6fa
|
|
|
|
|
+ border-radius 16rpx
|
|
|
|
|
+ padding 22rpx 24rpx
|
|
|
|
|
+ margin-bottom 28rpx
|
|
|
|
|
+ box-sizing border-box
|
|
|
|
|
+
|
|
|
|
|
+ .result-stats-row
|
|
|
|
|
+ display flex
|
|
|
|
|
+ justify-content space-between
|
|
|
|
|
+ align-items center
|
|
|
|
|
+ font-size 26rpx
|
|
|
|
|
+ color #4a5568
|
|
|
|
|
+
|
|
|
|
|
+ .result-stats-row + .result-stats-row
|
|
|
|
|
+ margin-top 16rpx
|
|
|
|
|
+
|
|
|
|
|
+ .result-stats-value
|
|
|
|
|
+ font-weight 500
|
|
|
|
|
|
|
|
.result-btns
|
|
.result-btns
|
|
|
display flex
|
|
display flex
|
|
|
width 100%
|
|
width 100%
|
|
|
|
|
+ gap 16rpx
|
|
|
|
|
|
|
|
.result-btn
|
|
.result-btn
|
|
|
flex 1
|
|
flex 1
|
|
@@ -832,13 +991,59 @@
|
|
|
font-size 28rpx
|
|
font-size 28rpx
|
|
|
|
|
|
|
|
.result-btn-outline
|
|
.result-btn-outline
|
|
|
- border 1rpx solid #1677ff
|
|
|
|
|
- color #1677ff
|
|
|
|
|
- margin-right 20rpx
|
|
|
|
|
|
|
+ border 1rpx solid #1857d4
|
|
|
|
|
+ color #1857d4
|
|
|
|
|
|
|
|
.result-btn-primary
|
|
.result-btn-primary
|
|
|
- background #1677ff
|
|
|
|
|
|
|
+ background #1857d4
|
|
|
|
|
+ color #fff
|
|
|
|
|
+
|
|
|
|
|
+ .result-cert
|
|
|
|
|
+ display flex
|
|
|
|
|
+ align-items center
|
|
|
|
|
+ width 100%
|
|
|
|
|
+ margin-top 24rpx
|
|
|
|
|
+ padding 24rpx 20rpx
|
|
|
|
|
+ background #f4f6fa
|
|
|
|
|
+ border-radius 16rpx
|
|
|
|
|
+ box-sizing border-box
|
|
|
|
|
+
|
|
|
|
|
+ .result-cert-icon
|
|
|
|
|
+ font-size 56rpx
|
|
|
|
|
+ margin-right 20rpx
|
|
|
|
|
+
|
|
|
|
|
+ .result-cert-info
|
|
|
|
|
+ flex 1
|
|
|
|
|
+
|
|
|
|
|
+ .result-cert-title
|
|
|
|
|
+ font-size 28rpx
|
|
|
|
|
+ font-weight 500
|
|
|
|
|
+ color #1a2233
|
|
|
|
|
+ margin-bottom 8rpx
|
|
|
|
|
+
|
|
|
|
|
+ .result-cert-name
|
|
|
|
|
+ font-size 24rpx
|
|
|
|
|
+ color #8896a7
|
|
|
|
|
+
|
|
|
|
|
+ .result-cert-btn
|
|
|
|
|
+ display inline-block
|
|
|
|
|
+ margin-top 12rpx
|
|
|
|
|
+ padding 0 24rpx
|
|
|
|
|
+ height 56rpx
|
|
|
|
|
+ line-height 56rpx
|
|
|
|
|
+ background #1857d4
|
|
|
color #fff
|
|
color #fff
|
|
|
|
|
+ font-size 24rpx
|
|
|
|
|
+ border-radius 10rpx
|
|
|
|
|
+
|
|
|
|
|
+ .text-orange
|
|
|
|
|
+ color #e67e22
|
|
|
|
|
+ .text-green
|
|
|
|
|
+ color #10a37f
|
|
|
|
|
+ .text-red
|
|
|
|
|
+ color #e53e3e
|
|
|
|
|
+ .text-blue
|
|
|
|
|
+ color #1857d4
|
|
|
|
|
|
|
|
.empty-tip
|
|
.empty-tip
|
|
|
text-align center
|
|
text-align center
|