完善考试页和开发考试结算页

This commit is contained in:
田岩
2025-08-13 18:03:33 +08:00
parent bdf96bb74b
commit a62a5f611e
24 changed files with 1215 additions and 88 deletions
+20
View File
@@ -12,5 +12,25 @@ export const startTraExamPapersInfo = (data) => {
data
});
};
// 提交试卷
export const commitPaperExam = (data) => {
return request({
url: base_url + '/traExamPapers/commitPaperExam',
method: 'post',
toastErrors: true,
data
});
};
// 试卷考试查分
export const queryPaperExamScore = (data) => {
return request({
url: base_url + '/traExamPapers/queryPaperExamScore',
method: 'post',
toastErrors: true,
data
});
};
+1 -1
View File
@@ -50,7 +50,7 @@ export const goto_login_fun = (from = 'http') => {
} else {
common.navigateTo('/pages/login/login')
}
}).finally(() => {
no_login_show_modal_state = false
})
+2 -1
View File
@@ -9,4 +9,5 @@ export const queryTraExamPapersPage = (data) => {
method: 'post',
data
});
};
};
+17 -3
View File
@@ -5,9 +5,9 @@ export const optionSuccessIcon = (color : string) : string => {
return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svgXml)}`;
};
export const optionErrorIcon = () : string => {
export const optionErrorIcon = (color: string='#F5212D') : string => {
const svgXml = `
<svg t="1754619171929" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6505" width="64" height="64"><path d="M910.336 186.368l-72.704-72.704L512 439.808 186.368 113.664 113.664 186.368 439.808 512l-326.144 325.632 72.704 72.704L512 584.192l325.632 326.144 72.704-72.704L584.192 512l326.144-325.632z" fill="#F5212D" p-id="6506"></path></svg>
<svg t="1754619171929" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6505" width="64" height="64"><path d="M910.336 186.368l-72.704-72.704L512 439.808 186.368 113.664 113.664 186.368 439.808 512l-326.144 325.632 72.704 72.704L512 584.192l325.632 326.144 72.704-72.704L584.192 512l326.144-325.632z" fill="${color}" p-id="6506"></path></svg>
`.trim();
return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svgXml)}`;
};
@@ -17,4 +17,18 @@ export const examinationSheetIcon = () : string => {
<svg t="1754630871725" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6324" width="64" height="64"><path d="M802.107077 51.2a145.289846 145.289846 0 0 1 145.092923 145.526154v630.547692a145.289846 145.289846 0 0 1-145.092923 145.526154H221.892923a145.329231 145.329231 0 0 1-145.092923-145.526154V196.726154A145.289846 145.289846 0 0 1 221.892923 51.2h580.214154z m-3.387077 76.8H225.28a71.837538 71.837538 0 0 0-71.561846 67.741538l-0.118154 4.253539v624.009846a71.837538 71.837538 0 0 0 67.465846 71.876923l4.214154 0.118154h573.44c38.203077 0 69.356308-29.932308 71.561846-67.741538l0.118154-4.253539V200.034462a71.876923 71.876923 0 0 0-67.465846-71.876924l-4.214154-0.157538zM729.6 512a38.4 38.4 0 1 1 0 76.8h-230.4a38.4 38.4 0 1 1 0-76.8h230.4z m-384 0a38.4 38.4 0 1 1 0 76.8h-51.2a38.4 38.4 0 1 1 0-76.8h51.2z m384-204.8a38.4 38.4 0 1 1 0 76.8h-230.4a38.4 38.4 0 1 1 0-76.8h230.4z m-384 0a38.4 38.4 0 1 1 0 76.8h-51.2a38.4 38.4 0 0 1 0-76.8h51.2z" p-id="6325"></path></svg>
`.trim();
return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svgXml)}`;
};
};
export const markIcon = (color: string='#ABABAB') : string => {
const svgXml = `
<svg t="1754987745092" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="13983" width="64" height="64"><path d="M693.01933598 59.45166004c-24.99339629-24.99339629-65.5162717-24.99339629-90.50966799 0-24.99339629 24.99339629-24.99339629 65.5162717 0 90.50966799l22.627417 22.627417-181.19328425 181.19328425c-78.50370195-71.13564929-199.8637317-68.83684515-275.5976964 6.89711955l-33.94112549 33.94112549a8 8 0 0 0 0 11.3137085l208.59650045 208.59650045-175.36248174 175.36248174a8 8 0 0 0 0 11.3137085l56.5685425 56.56854249a8 8 0 0 0 11.3137085 0L410.88373029 682.41273427l208.59650045 208.59650045a8 8 0 0 0 11.3137085 0l33.9411255-33.9411255c76.21055466-76.21055466 78.05893179-198.62346641 5.54583848-277.07484246L851.41125497 398.86291501l22.627417 22.627417c24.99339629 24.99339629 65.5162717 24.99339629 90.50966799 0 24.99339629-24.99339629 24.99339629-65.5162717 0-90.50966799L693.01933598 59.45166004z" fill="${color}" p-id="13984"></path></svg>
`.trim();
return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svgXml)}`;
};
export const feedbackIcon = () : string => {
const svgXml = `
<svg t="1754962550365" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6478" width="64" height="64"><path d="M512 853.333333C323.4816 853.333333 170.666667 700.5184 170.666667 512S323.4816 170.666667 512 170.666667s341.333333 152.814933 341.333333 341.333333-152.814933 341.333333-341.333333 341.333333z m0-51.2a290.133333 290.133333 0 1 0 0-580.266666 290.133333 290.133333 0 0 0 0 580.266666z m-25.6-429.738666a25.6 25.6 0 1 1 51.2 0v248.2176a25.6 25.6 0 0 1-51.2 0v-248.251734zM512 729.1904a31.061333 31.061333 0 1 1 0-62.088533 31.061333 31.061333 0 0 1 0 62.088533z" fill="#999999" p-id="6479"></path></svg>
`.trim();
return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svgXml)}`;
};
@@ -11,6 +11,10 @@
</view>
<view class="right">
<view class="mark_and_feedback_div">
<image :src="markIcon(props.item.mark?'#0066FF':'#ABABAB')" class="img" @click="mark_click()"></image>
<image :src="feedbackIcon()" class="img" @click="feedback_click()"></image>
</view>
<!-- <view class="right_text">展开</view>
<uv-icon class="arrow-icon" name="arrow-right"></uv-icon> -->
</view>
@@ -36,6 +40,9 @@
} from 'vue'
import questionVue from './question.vue';
import radioSubjectItem from './radio-subject-item.vue'
import {
markIcon,feedbackIcon
} from '@/common/imgSvg'
import {
SUBJECT_TYPE
} from '@/enum.js'
@@ -59,7 +66,7 @@
},
});
const emit = defineEmits(['subject_click'])
const talkingInfo = ref({
id: '3',
intrctWay: "",
@@ -79,11 +86,12 @@
}
}
})
// "chatId": "CHAT025018122068202508081709060000000000000000000000000000000098",
// "fileId": "S3F0250181220722025080817090600000476885",
// "ossFileAddr": "http://25.18.122.66::9786/traoss/show//S3F0250181220722025080817090600000476885",
// "transContent": "一二三四。"
// const activeVoiceId = ref()
const feedback_click = () =>{
emit('subject_click', 'feedback', props.item)
}
const mark_click = () =>{
emit('subject_click', 'mark', props.item)
}
const customStyle = {
borderRadius: '16rpx',
@@ -91,9 +99,7 @@
backgroundColor: '#0066FF',
border: '1rpx solid rgb(12, 123, 245)',
}
const emit = defineEmits(['click_option'])
const subject_data = reactive({
qnsId: '',
qnsContent: '',
@@ -114,6 +120,18 @@
</script>
<style scoped lang="scss">
.mark_and_feedback_div{
display: flex;
height: 100%;
justify-content: end;
align-items: center;
.img{
width: 38rpx;
height: 38rpx;
margin-left: 4rpx;
padding: 4rpx;
}
}
.option_div {
padding-top: 46rpx;
@@ -64,7 +64,6 @@
})
const click_option = () => {
console.log('props.analysisVo.itemId', props.analysisVo.itemId);
emit('click_option', props.analysisVo)
}
+32 -11
View File
@@ -11,6 +11,10 @@
</view>
<view class="right">
<view class="mark_and_feedback_div">
<image :src="markIcon(props.item.mark?'#0066FF':'#ABABAB')" class="img" @click="mark_click()"></image>
<image :src="feedbackIcon()" class="img" @click="feedback_click()"></image>
</view>
<!-- <view class="right_text">展开</view>
<uv-icon class="arrow-icon" name="arrow-right"></uv-icon> -->
</view>
@@ -39,6 +43,9 @@
toRaw
} from 'vue'
import radioSubjectItem from './radio-subject-item.vue'
import {
markIcon,feedbackIcon
} from '@/common/imgSvg'
import {
SUBJECT_TYPE
} from '@/enum.js'
@@ -48,7 +55,7 @@
backgroundColor: '#0066FF',
border: '1rpx solid rgb(12, 123, 245)',
}
const emit = defineEmits(['click_option'])
const emit = defineEmits(['subject_click'])
const props = defineProps({
item: {
type: Object,
@@ -59,7 +66,14 @@
required: true,
}
});
const feedback_click = () =>{
emit('subject_click', 'feedback', props.item)
}
const mark_click = () =>{
emit('subject_click', 'mark', props.item)
}
const subject_data = reactive({
qnsId: '',
qnsContent: '',
@@ -80,11 +94,8 @@
const subject_type_text = computed(() => SUBJECT_TYPE.find(res => subject_data.qnsTyp === res.value)?.label || '')
// 点击答题
const click_option = (analysisVo) => {
// emit('click_option', props.item.qnsId, analysisVo)
// // 无论什么类型如果表里已经有了,再次点击就是弹出
if (props.item.my_answer.includes(analysisVo.itemId)) {
// console.log('无论什么类型如果表里已经有了,再次点击就是弹出', analysisVo.itemId);
props.item.my_answer = props.item.my_answer.filter(id => id !== analysisVo.itemId);
}
else if (props.item.qnsTyp === 'SN') { // 单选
@@ -102,6 +113,18 @@
</script>
<style scoped lang="scss">
.mark_and_feedback_div{
display: flex;
height: 100%;
justify-content: end;
align-items: center;
.img{
width: 38rpx;
height: 38rpx;
margin-left: 4rpx;
padding: 4rpx;
}
}
.option_div_button{
width: 100%;
height: 84rpx;
@@ -117,11 +140,10 @@
display: flex;
flex-direction: column;
padding-bottom: 40rpx;
.top {
display: flex;
align-items: center;
.type {
width: 108rpx;
height: 46rpx;
@@ -146,20 +168,19 @@
.right {
display: flex;
align-items: center;
.right_text {
font-family: PingFangSC;
font-weight: 600;
font-size: 28rpx;
color: #333;
line-height: 40rpx;
text-align: left;
font-style: normal;
}
}
}
.question_text {
font-family: PingFangSC;
font-weight: 500;
+9
View File
@@ -199,6 +199,15 @@
}
}
},
{
"path": "pages/examination/result",
"style": {
"navigationBarTitleText": "考试结果",
"app-plus": {
"titleNView": false
}
}
},
{
"path": "pages/practice/index",
"style": {
@@ -148,7 +148,6 @@
keyboardHeight = Math.max(0, keyboardHeight - safeAreaBottomHeight); // 避免负数
}
popup_input_bottom.value = `${keyboardHeight}px`;
console.log(res);
});
})
}
+4 -6
View File
@@ -36,8 +36,7 @@
提问</view>
</view>
<view class="input-textarea">
<uv-textarea v-model="formData.bbsContent" height="124" count
:maxlength="100"
<uv-textarea v-model="formData.bbsContent" height="124" count :maxlength="100"
:placeholder="formData.bbsTag == 'SUG'?'请输入你的建议...':'请输入你的问题...'"></uv-textarea>
</view>
</view>
@@ -74,7 +73,7 @@
const sliderChange = (event) => {
formData.bbsGrade = event.detail.value
}
const submit = () => {
if (formData.bbsContent === '') {
if (formData.bbsTag == 'SUG') {
@@ -87,9 +86,7 @@
common.msg('发表成功')
setTimeout(() => {
uni.$emit('refresh_comment_data')
if(from.value === 'study'){
} else {
}
if (from.value === 'study') {} else {}
common.navigateBack()
}, 500)
})
@@ -253,6 +250,7 @@
.back_div {
// margin-right: 10rpx;
padding: 15rpx;
// background-color: red;
.back-icon {
position: relative;
+116
View File
@@ -0,0 +1,116 @@
<template>
<uni-popup ref="PopupRef" class="popup">
<view class="popup_div">
<view class="title_div">
<!-- 1. 插槽优先 -->
<slot name="title" v-if="$slots.title"></slot>
<!-- 2. 有HTML内容且不为空时使用v-html -->
<!-- <view v-else-if="html && html.trim() !== ''" v-html="html"></view> -->
<!-- 3. 最后显示默认标题 -->
<template v-else>{{ title }}</template>
</view>
<view class="button_div">
<view class="button_item" v-for="item in buttonList" :style="item?.style" @click="click_button(item)">
{{item?.name || ''}}
</view>
</view>
</view>
</uni-popup>
</template>
<script setup>
import {
ref,
reactive,
computed,
onMounted,
nextTick,
} from 'vue';
const props = defineProps({
dialogConfiguration: {
type: Object,
required: true,
}
});
const emit = defineEmits(['button_click'])
const title = ref('')
const html = ref('')
const buttonList = ref([])
const PopupRef = ref(null)
// 点击按钮
const click_button = (value) => {
emit('button_click', value)
}
const close = () => PopupRef.value?.close()
const open = () => {
// 解构赋值更清晰
const {
title: t,
html: h,
buttonList: bl = []
} = props.dialogConfiguration || {};
title.value = t || '';
html.value = h || '';
buttonList.value = Array.isArray(bl) ? bl : [];
// 确保PopupRef存在再调用open
if (PopupRef.value) {
PopupRef.value.open('bottom');
}
}
defineExpose({
open,
close
})
</script>
<style scoped lang="scss">
.popup {
z-index: 1810;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, .9);
}
.popup_div {
width: 80%;
background-color: #FFFFFF;
padding: 20rpx 34rpx 50rpx 34rpx;
display: flex;
flex-direction: column;
align-items: center;
border-radius: 16rpx;
position: relative;
margin: 0 auto 76% auto;
.title_div {
width: 100%;
text-align: center;
padding: 30rpx 0;
font-family: PingFangSC;
text-align: center;
font-style: normal;
font-weight: 400;
font-size: 30rpx;
color: #333333;
}
.button_div {
display: flex;
flex-direction: column;
.button_item {
margin-top: 30rpx;
width: 356rpx;
height: 80rpx;
text-align: center;
line-height: 80rpx;
}
}
}
</style>
@@ -0,0 +1,176 @@
<template>
<uni-popup ref="feedbackPopupRef" class="popup">
<view class="feedback_popup_div" :style="{marginBottom:feedback_popup_bottom}">
<view class="title_div">
<view class="text">
反馈
</view>
<view class="popup_back_div" @click="openFeedback(false)">
<image :src="optionErrorIcon('#000000')" class="img"></image>
</view>
</view>
<view class="feedback_item_div">
<view class="feedback_item"
:class="{'feedback_item_clidked':feedbackInfo.type.includes(feedback_type_item.value)}"
@click="feedback_item_click(feedback_type_item.value)"
v-for="feedback_type_item in feedbackTypeList">场景问题</view>
</view>
<view class="feedback_text_area_div">
<uv-textarea height="124" count :maxlength="100" placeholder="请输入反馈内容..." :adjustPosition="false"
v-model="feedbackInfo.text"></uv-textarea>
</view>
<view class="feedback_button">
<uv-button class="button" type="primary" :throttleTime="100" text="提交" color="#0066FF"
custom-style="color:#FFFFFF;borderRadius:16rpx;height:92rpx;"
@click="submit_feedback_fun()"></uv-button>
</view>
</view>
</uni-popup>
</template>
<script setup>
import {
ref,
reactive,
computed,
onMounted,
nextTick
} from 'vue';
import {
optionErrorIcon
} from '@/common/imgSvg'
const feedback_popup_bottom = ref('0px') // 反馈框下距离
const feedbackPopupRef = ref(null)
const feedbackTypeList = reactive([{
value: "SN",
label: "场景问题",
}, {
value: "GN",
label: "功能问题",
}, {
value: "PN",
label: "陪练内容",
}])
const feedbackInfo = reactive({
type: [], // 反馈类型
text: '', // 反馈内容
examId: '', // 考试ID
qnsId: '', // 试题IDID
})
const feedback_item_click = (value) => {
if (feedbackInfo.type.includes(value)) {
feedbackInfo.type = feedbackInfo.type.filter(item => item !== value); // 如果已存在,则从数组中移除
} else {
feedbackInfo.type.push(value); // 如果不存在,则添加到数组中
}
}
// 反馈提交
const submit_feedback_fun = (value) => {
// todo 待接口
console.log('反馈提交');
}
const openFeedback = (status) => {
if (status) {
feedbackPopupRef.value.open('bottom')
// feedbackInfo.examId
const systemInfo = uni.getSystemInfoSync();
// 安全区域底部到屏幕底部的高度(即底部安全区域高度)
const safeAreaBottomHeight = systemInfo.screenHeight - systemInfo.safeArea.bottom;
nextTick(() => {
uni.onKeyboardHeightChange(res => {
let keyboardHeight = res.height;
// 仅在iOS端补偿安全区域高度
if (systemInfo.platform === 'ios') {
keyboardHeight = Math.max(0, keyboardHeight - safeAreaBottomHeight); // 避免负数
}
feedback_popup_bottom.value = `${keyboardHeight}px`;
});
})
} else {
feedbackPopupRef.value.close()
}
}
const open = () => openFeedback(true)
defineExpose({
open
})
</script>
<style scoped lang="scss">
.feedback_popup_div {
width: 100%;
height: 100%;
background-color: #FFFFFF;
padding: 10rpx 34rpx;
display: flex;
flex-direction: column;
align-items: center;
border-radius: 16rpx 16rpx 0px 0px;
position: relative;
.title_div {
width: 100%;
text-align: center;
padding: 30rpx 0;
font-family: PingFangSC;
font-weight: 600;
font-size: 34rpx;
color: #000000;
text-align: center;
font-style: normal;
border-bottom: 2rpx solid #EFEFEF;
}
.popup_back_div {
width: 60rpx;
height: 60rpx;
position: absolute;
top: 30rpx;
right: 30rpx;
display: flex;
align-items: center;
justify-content: center;
.img {
width: 30rpx;
height: 30rpx;
}
}
.feedback_item.feedback_item_clidked {
border: 2rpx solid #0066FF !important;
background-color: #fff !important;
}
.feedback_item_div {
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
margin: 30rpx 0;
.feedback_item {
border: 2rpx solid #F0F0F0;
background-color: #F0F0F0;
border-radius: 16rpx;
padding: 26rpx 36rpx;
font-family: PingFangSC;
font-weight: 500;
font-size: 30rpx;
color: #000000;
text-align: center;
}
}
.feedback_text_area_div {
width: 100%;
margin-bottom: 40rpx;
}
.feedback_button {
width: 100%;
margin-bottom: 20rpx;
}
}
</style>
+247 -42
View File
@@ -2,7 +2,7 @@
<view class="main_div max_page">
<nav-bar :is_seat="true"></nav-bar>
<view class="nav-div">
<view class="title ellipsis-text" @click="hand_in_paper()">
<view class="title ellipsis-text" @click="hand_in_paper_button_click()">
{{paperData.papersName}}
</view>
<view class="back_div"></view>
@@ -23,7 +23,6 @@
:height="8"></uv-line-progress>
</view>
</view>
<view class="scroll_div">
<swiper class="swiper" :indicator-dots="false" @change="swiperChange" :current="questionNumber"
easing-function="linear">
@@ -31,12 +30,12 @@
<view class="content">
<view class="expose_shadow"></view>
<scroll-view :scroll-y="true" class="scroll-Y" :show-scrollbar="false" :refresher-threshold="0">
<RadioSubject :item="item" v-if="item.qnsTyp !== 'ES'" :mode="mode">
<RadioSubject :item="item" v-if="item.qnsTyp !== 'ES'" :mode="mode"
@subject_click="subject_click">
</RadioSubject>
<CharactersSubject :item="item" v-if="item.qnsTyp === 'ES'" :mode="mode"
:activeVoiceId="activeVoiceId"
:voicePathValue="voicePathValue"
>
:activeVoiceId="activeVoiceId" :voicePathValue="voicePathValue"
@subject_click="subject_click">
</CharactersSubject>
</scroll-view>
</view>
@@ -46,7 +45,7 @@
<view class="fixed-box font_pf">
<view class="fixed-btn-box">
<view class="sheet_button" @click="openSheet()">
<view class="sheet_button" @click="openSheet(true)">
<image :src="examinationSheetIcon()" class="img"></image>
<view class="sheet_text">答题卡</view>
</view>
@@ -55,7 +54,7 @@
custom-style="color:#0066FF;borderRadius:16rpx;height:92rpx;"
@click="button_tab(-1)"></uv-button>
<view style="width:46rpx"></view>
<uv-button class="button" type="primary" :throttleTime="100" text="下一题" color="#0066FF"
<uv-button class="button" type="primary" :throttleTime="100" :text="next_question" color="#0066FF"
custom-style="color:#FFFFFF;borderRadius:16rpx;height:92rpx;"
@click="button_tab(1)"></uv-button>
</view>
@@ -66,18 +65,22 @@
</view>
</view>
<uni-popup ref="popup" class="popup">
<uni-popup ref="popupRef" class="popup">
<view class="sheet_popup_div">
<view class="title_div">
<view class="text">
答题卡
</view>
<view class="popup_back_div">
<view class="popup_back_div" @click="openSheet(false)">
<image :src="optionErrorIcon('#000000')" class="img"></image>
</view>
</view>
<view class="sheet_table">
<view class="sheet_table_item" v-for="(item,index) in [1,2,3,4,5,67,8,9,10,11,12,13,14,15]">
<view class="sheet_table_item" v-for="(item,index) in topicList" :class="{
'current':index === questionNumber,
'mark':markList.includes(item.qnsId),
'completed':completedList.includes(item.qnsId),
}" @click="clikc_sheet_item(index)">
<view class="circle">
{{index + 1}}
</view>
@@ -86,14 +89,22 @@
<view class="sheet_button">
<uv-button class="button" type="primary" :throttleTime="100" text="交卷" color="#0066FF"
custom-style="color:#FFFFFF;borderRadius:16rpx;height:92rpx;"
></uv-button>
@click="hand_in_paper_button_click()"></uv-button>
</view>
</view>
</uni-popup>
<!-- 反馈组件 -->
<Feedback ref="feedbackRef"></Feedback>
<!-- 结尾弹出层 -->
<Dialog ref="dialogRef" :dialogConfiguration="dialogConfiguration" @button_click="result_click">
</Dialog>
</view>
</template>
<script setup>
import Feedback from './components/feedback.vue'
import Dialog from './components/dialog.vue'
import RadioSubject from '@/components/examination/radio-subject.vue'
import CharactersSubject from '@/components/examination/characters-subject.vue'
import TouchBtn from '@/pages/course/components/touchBtn.vue'
@@ -102,12 +113,8 @@
reactive,
computed,
onMounted,
nextTick,
getCurrentInstance
nextTick
} from 'vue';
import {
examinationSheetIcon
} from '@/common/imgSvg'
import {
onLoad
} from '@dcloudio/uni-app'
@@ -118,22 +125,43 @@
import {
commonUploadVoiceFile
} from "@/api/common.js"
import {
optionErrorIcon,
examinationSheetIcon
} from '@/common/imgSvg'
import {
commitPaperExam,
queryPaperExamScore
} from '@/api/examination.js'
const sendLoadingText = ref('问题回答中,请在问题回答结束后重试!')
const answerIsOver = ref(true)
const examId = ref('')
const popup = ref(null)
const feedbackRef = ref(null)
const dialogRef = ref(null)
const popupRef = ref(null)
const mode = ref('examination') // 考试 examination 练习practice
const paperData = reactive({
papersId: '',
limitTm: 0,
papersName: '',
execId: '', // 执行ID
examId: '', // 考试ID
papersId: '', // 试卷ID
limitTm: 0, // 考试限制时间
papersName: '', // 试卷名称
}) // 试卷信息
const topicList = reactive([]) // 问题列表
const questionNumber = ref(0) // 题号
const showTouchBtn = computed(() => {
return topicList[questionNumber.value]['qnsTyp'] === 'ES'
})
const completedList = computed(() => {
return []
})
const markList = computed(() => topicList.filter(res => !!res.mark).map(res => res.qnsId)) // 标记列表
// 下一题按钮状态
const next_question = computed(() => (topicList.length === questionNumber.value + 1) ? '交卷' : '下一题')
const progress = computed(() => { // 计算进度百分比(保留两位小数)
const total = topicList.length;
@@ -141,7 +169,11 @@
const completed = questionNumber.value + 1;
return Math.min(Math.round((completed / total) * 10000) / 100, 100);
})
// 弹出框配置
const dialogConfiguration = reactive({})
const activeVoiceId = ref('')
const swiperChange = (item) => {
questionNumber.value = item.detail.current
}
@@ -153,33 +185,38 @@
newNumber = 0;
} else if (newNumber >= topicList.length) {
newNumber = topicList.length - 1;
hand_in_paper_button_click() // 调用交卷
}
questionNumber.value = newNumber;
}
// 打开答题卡
const openSheet = () => {
popup.value.open('bottom');
// 打开或者关闭弹出层
const openSheet = (status) => status ? popupRef.value.open('bottom') : popupRef.value.close();
// 点击答题卡按钮
const clikc_sheet_item = (index) => {
questionNumber.value = index
}
const subject_click = (type, params) => {
if (type === 'mark') {
topicList[questionNumber.value]['mark'] = !topicList[questionNumber.value]['mark']
} else if (type === 'feedback') {
console.log('feedbackRef.value', feedbackRef.value);
feedbackRef.value.open()
}
}
const voicePathValue = ref('')
// 发送语音
const uploadRecordNow = (voicePath) => {
console.log('voicePath',voicePath);
//#ifdef APP-PLUS
// talkingList.value.push({
// type: 'question',
// talkingText: '',
// isLoading: true
// })
// scrollToBottomNow()
commonUploadVoiceFile(voicePath, '/traask/traAskchat/voiceTrans', {}).then(res => {
let _res = JSON.parse(res.data)
voicePathValue.value = voicePath
console.log('_res', _res, voicePath);
if (_res.rtnCode === '0000') {
// "chatId": "CHAT025018122068202508081537410000000000000000000000000000000088",
// "fileId": "S3F0250181220722025080815374100000456565",
// "ossFileAddr": "http://25.18.122.66::9786/traoss/show//S3F0250181220722025080815374100000456565",
@@ -229,24 +266,147 @@
common.navigateBack()
return
}
paperData.execId = examination.execId
paperData.examId = examination.examId
paperData.papersId = examination.papersId
paperData.limitTm = examination.limitTm
paperData.papersName = examination.papersName
topicList.push(...examination.qnsInfoVos.map(res => ({
...res,
mark: false,
my_answer: [],
backend_answer: [],
})))
});
const result_click = ({
key
}) => {
console.log('res', key);
if (key === 'hand_in_paper') { // 现在交卷
hand_in_paper()
} else if (key === 'continue') { // 继续考试
dialogRef.value.close()
}
}
// 交卷按钮点击,打开交卷确认框
const hand_in_paper_button_click = () => {
console.log('点击交卷', paperData);
// 判断是否完成所有题目
const completeList = topicList.filter(res => !!(Array.isArray(res.my_answer) ? res.my_answer.length : res
.my_answer)).map(res => ({
a: res.qnsId,
b: res.my_answer,
c: !!res.my_answer
}))
dialogConfiguration.title = '确认现在交卷吗?'
const style_button_1 = {
color: '#FFFFFF',
fontSize: '30rpx',
backgroundColor: '#0066FF',
borderRadius: '8rpx'
}
const style_button_2 = {
color: '#0066FF',
fontSize: '30rpx',
backgroundColor: '#E2EDFF',
borderRadius: '8rpx'
}
const incompleteNumber = topicList.length - completeList.length
if (incompleteNumber === 0) { // 完成
dialogConfiguration.type = 'complete'
dialogConfiguration.title = '确认现在交卷吗?'
dialogConfiguration.buttonList = [{
key: 'hand_in_paper',
name: '现在交卷',
style: style_button_1
}, {
key: 'continue',
name: '继续考试',
style: style_button_2
}]
} else {
dialogConfiguration.type = 'incomplete' // 未完成
dialogConfiguration.html =
`当前考试进度:<text style="color:#0066FF;font-weight:bold;">${completeList.length}/${topicList.length}</text> 题 还有<text style="color:#0066FF;font-weight:bold;">${incompleteNumber}</text>道题未作答,确认交卷吗?`
dialogConfiguration.buttonList = [{
key: 'continue',
name: '继续考试',
style: style_button_1
}, {
key: 'hand_in_paper',
name: '现在交卷',
style: style_button_2
}]
}
dialogRef.value.open()
}
// 执行交卷
const hand_in_paper = () => {
console.log('点击交卷', showTouchBtn.value);
showTouchBtn.value = !showTouchBtn.value
const answerDtoList = topicList.map(res => {
let answerItem = {
examId: paperData.examId,
papersId: paperData.papersId,
qnsId: res.qnsId,
ossKey: '',
anserResult: '',
}
if (res.qnsTyp === 'ES') { // 问答题特殊处理
return {
...answerItem,
anserResult: ''
}
} else { //其他题
return {
...answerItem,
anserResult: res.my_answer.join(',')
}
}
})
console.log('answerDtoList', answerDtoList);
dialogRef.value.close()
common.loading('正在提交')
commitPaperExam({
examId: paperData.examId,
execId: paperData.execId || '1',
examLenTm: 1200,
answerDtoStr: JSON.stringify(answerDtoList)
}).then(res => {
console.log('提交成功', res);
if (res.body.flagQuery === 'Y') { // 需要查分
common.redirectTo('/pages/examination/result?execId=' + res.body.execId)
} else { // 不需要查分
common.navigateBack()
}
// const execId = res.body.execId
// let timer = setInterval(() => {
// queryPaperExamScore({
// execId
// }).then(res => {
// console.log('分数返回', res);
// clearInterval(timer)
// })
// }, 1000)
}).catch((res) => {
console.log('error', res);
}).finally(() => {
common.hideLoading().body
})
}
</script>
<style scoped lang="scss">
$bg-margin-left: 30rpx;
.popup_title_text {
color: red;
}
.popup {
//答题卡
z-index: 1800;
@@ -261,6 +421,8 @@
flex-direction: column;
align-items: center;
border-radius: 16rpx 16rpx 0px 0px;
position: relative;
.title_div {
width: 100%;
text-align: center;
@@ -274,16 +436,31 @@
border-bottom: 2rpx solid #EFEFEF;
}
.popup_back_div {
width: 60rpx;
height: 60rpx;
position: absolute;
top: 30rpx;
right: 30rpx;
display: flex;
align-items: center;
justify-content: center;
.img {
width: 30rpx;
height: 30rpx;
}
}
.sheet_table {
margin-top: 48rpx;
margin-bottom: 48rpx;
display: flex;
/* 启用 Flex 布局 */
flex-wrap: wrap;
/* 超出宽度时自动换行 */
width: calc(100vw - 108rpx);
align-content: space-between;
.sheet_table_item {
width: calc((100vw - 108rpx) / 5 - 16rpx);
height: calc((100vw - 108rpx) / 5 - 16rpx);
@@ -294,10 +471,38 @@
align-items: center;
justify-content: center;
font-size: 32rpx;
color: #999999;
}
.current {
background-color: rgba(0, 102, 255, 0.6);
border-color: #0066FF;
color: #FFFFFF;
}
.completed {
// 已完成
background-color: rgba(0, 102, 255, 0.1);
border-color: #0066FF;
color: #0066FF;
}
.mark,
.completed.mark {
background-color: rgba(232, 181, 49, 0.1);
color: #E8B531;
border-color: #E8B531;
}
.current.mark {
// 已完成
background-color: rgba(0, 102, 255, 0.6);
color: #FFFFFF;
border-color: #E8B531;
}
}
.sheet_button{
.sheet_button {
width: 100%;
}
}
+537
View File
@@ -0,0 +1,537 @@
<template>
<view class="main_div max_page">
<nav-bar :is_seat="true"></nav-bar>
<view class="nav-div">
<view class="title ellipsis-text">
考试结算
</view>
<view class="back_div">
<view class="back-icon"></view>
</view>
</view>
<view class="information-details-div">
<view class="top">
<view class="left">
<view class="top">得分</view>
<view class="mid">
<text v-if="pass_status===0" class="loading-pass">--</text>
<text v-if="pass_status===-1" class="no-pass">40</text>
<text v-if="pass_status===1" class="pass">50</text>
</view>
<view class="bottom">
<text v-if="pass_status===-1">失败乃成功之母继续努力</text>
<text v-if="pass_status===1">考的不错啊继续加油</text>
<text v-if="pass_status===0">考试结果计算中...</text>
<image v-if="pass_status===1" src="@/static/images/login/clap.png" mode="widthFix"
style="width: 32rpx;"></image>
</view>
</view>
<view class="right">
<view class="img">
<image v-if="pass_status===1" src="@/static/images/examination/qualified.png" mode="widthFix"
style="width: 270rpx;"></image>
<image v-if="pass_status===-1" src="@/static/images/examination/unqualified.png" mode="widthFix"
style="width: 270rpx;"></image>
<image v-if="pass_status===0" src="@/static/images/examination/getting_in.gif" mode="widthFix"
style="width: 270rpx;"></image>
</view>
</view>
</view>
<view class="bottom">
<!-- 考试标题 -->
<view class="title-div">
<view class="title-icon">
<image src="@/static/images/examination/examination-icon.png" mode="widthFix" class="img">
</image>
</view>
<view class="title">
考试这里是考试名称
</view>
</view>
<!-- 时间和考试按钮 -->
<view class="time-and-exam-button">
<view class="time-icon">
<image src="@/static/images/examination/duration-icon.png" mode="widthFix" class="img"></image>
</view>
<view class="time">
时长12 15
</view>
<view class="fl1">
</view>
<view class="examination">
<view>考试排行榜</view>
<view class="back-icon"></view>
</view>
</view>
</view>
</view>
<view class="main-div">
<view class="main-div-title">
答题详情
</view>
<!-- 获取答题结果时候的图片 -->
<view class="loading-pass-image-div" v-if="pass_status===0">
<image src="@/static/images/examination/getting_robot.png" mode="widthFix" class="img"></image>
<view class="tip">
你的等待会有更精确的结果要耐心哦~
</view>
</view>
<view class="sheet_table">
<view class="sheet_table_item" v-for="(item,index) in topicList">
<view class="circle">
{{index + 1}}
</view>
</view>
</view>
<view class="item" :class="getStatusClass(index)" v-for="(item,index) in dataList">
<view class="top">
<view class="type">
单选题
</view>
<view class="score">
5
</view>
<view class="fl1">
</view>
<view class="right">
<view class="right_text">
展开
</view>
<uv-icon class="arrow-icon" name="arrow-right"></uv-icon>
</view>
</view>
<view class="text">
属于商业银行风险管理三道防线的哪些风险管理部门为什么
</view>
<view class="additional_div">
<RadioSubject></RadioSubject>
</view>
</view>
</view>
<!-- <view class="scroll_div">
<swiper class="swiper" :current="tabAct" :indicator-dots="false" :disable-touch="true">
<swiper-item>
<view class="content">
<view class="expose_shadow"></view>
<scroll-view :scroll-y="true" class="scroll-Y" :show-scrollbar="false" :refresher-threshold="0">
<RadioSubject></RadioSubject>
</scroll-view>
</view>
</swiper-item>
</swiper>
</view> -->
</view>
</template>
<script setup>
import {
ref,
reactive,
computed,
onMounted,
nextTick,
getCurrentInstance
} from 'vue';
import RadioSubject from '../wrong_question_record/components/radio-subject.vue'
const pass_status = ref(1)
const topicList = reactive([1, 2, 3, 4, 5, 6])
const dataList = reactive([1, 2, 3, 4, 5, 6])
const getStatusClass = (index) => {
const remainder = index % 3;
if (remainder === 0) return 'in_progress';
if (remainder === 1) return 'completed';
return 'expired';
};
// 初始化时检查
onMounted(() => {
});
</script>
<style scoped lang="scss">
$bg-margin-left: 30rpx;
.item {
border-radius: 16rpx;
margin: 32rpx 0;
padding: 34rpx 30rpx 34rpx 36rpx;
background-color: #fff;
display: flex;
flex-direction: column;
.top {
display: flex;
align-items: center;
.type {
width: 108rpx;
height: 46rpx;
background: #267EFF;
border-radius: 8rpx;
font-family: PingFangSC;
font-weight: 500;
font-size: 25rpx;
color: #FFFFFF;
text-align: center;
line-height: 46rpx;
}
.score {
margin-left: 24rpx;
font-family: ArialMT;
font-size: 30rpx;
color: #333333;
text-align: left;
}
.right {
display: flex;
align-items: center;
.right_text {
font-family: PingFangSC;
font-weight: 600;
font-size: 28rpx;
color: #333;
line-height: 40rpx;
text-align: left;
font-style: normal;
}
}
}
.text {
font-family: PingFangSC;
font-weight: 500;
font-size: 30rpx;
color: #333333;
line-height: 48rpx;
text-align: left;
font-style: normal;
margin-top: 20rpx;
}
}
.sheet_table {
margin:30rpx 48rpx 48rpx 48rpx;
display: flex;
flex-wrap: wrap;
width: calc(100vw - 96rpx - 56rpx);
// height: 20rpx;
align-content: space-between;
justify-content: space-between;
// background-color: red;
.sheet_table_item {
width: calc((100vw - 96rpx) / 5 - 46rpx);
height: calc((100vw - 96rpx) / 5 - 46rpx);
margin: 16rpx;
margin-bottom: 16rpx;
border: 2rpx solid #E5E5E5;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 32rpx;
color: #999999;
}
.current {
background-color: rgba(0, 102, 255, 0.6);
border-color: #0066FF;
color: #FFFFFF;
}
.completed {
// 已完成
background-color: rgba(0, 102, 255, 0.1);
border-color: #0066FF;
color: #0066FF;
}
.mark,
.completed.mark {
background-color: rgba(232, 181, 49, 0.1);
color: #E8B531;
border-color: #E8B531;
}
.current.mark {
// 已完成
background-color: rgba(0, 102, 255, 0.6);
color: #FFFFFF;
border-color: #E8B531;
}
}
// 主内容框
.main-div {
display: flex;
flex-direction: column;
padding: 34rpx 0 30rpx 0;
margin: 30rpx 28rpx 20rpx 28rpx;
border-radius: 16rpx;
position: relative;
background-color: #fff;
min-height: calc(100vh - var(--status-bar-height) - 70rpx - 380rpx - 100rpx);
.main-div-title {
width: 100%;
height: 44rpx;
font-family: PingFangSC;
font-weight: 700;
font-size: 33rpx;
color: #000000;
line-height: 44rpx;
text-align: left;
font-style: normal;
margin-left: 48rpx;
}
.loading-pass-image-div {
display: flex;
flex-direction: column;
align-items: center;
padding-top: 80rpx;
padding-bottom: 100rpx;
.img {
// background-color: red;
width: 52vw;
margin-left: -100rpx;
}
.tip {
font-family: PingFangSC;
font-weight: 400;
font-size: 30rpx;
color: #666666;
line-height: 40rpx;
text-align: center;
font-style: normal;
}
}
}
// 信息框
.information-details-div {
display: flex;
flex-direction: column;
padding: 34rpx 20rpx 30rpx 48rpx;
margin: 44rpx 28rpx 0 28rpx;
border-radius: 16rpx;
position: relative;
background-color: #fff;
opacity: .8;
box-shadow: 2rpx -2rpx 2rpx #fff;
&>.top {
display: flex;
justify-content: space-between;
&>.left {
&>.top {
font-family: PingFangSC;
font-weight: 700;
font-size: 34rpx;
color: #000000;
line-height: 34rpx;
text-align: left;
font-style: normal;
}
&>.mid {
font-weight: 700;
font-size: 66rpx;
line-height: 66rpx;
text-align: left;
font-style: normal;
margin-top: 34rpx;
margin-bottom: 30rpx;
}
&>.bottom {
display: flex;
align-items: center;
font-family: PingFangSC;
font-weight: 400;
font-size: 24rpx;
color: #999999;
line-height: 24rpx;
text-align: left;
font-style: normal;
}
}
&>.right {
margin-left: 20rpx;
}
}
&>.bottom {
font-family: PingFangSC;
font-weight: 400;
font-size: 26rpx;
color: #666666;
line-height: 26rpx;
text-align: left;
font-style: normal;
margin-top: 26rpx;
.title-icon,
.time-icon {
display: flex;
align-items: center;
padding-right: 12rpx;
.img {
width: 26rpx;
}
}
.title-div {
display: flex;
align-items: center;
padding-bottom: 24rpx;
}
.time-and-exam-button {
display: flex;
align-items: center;
padding-right: 12rpx;
.examination {
display: flex;
align-items: center;
color: #0066FF;
.back-icon {
position: relative;
width: 40rpx;
height: 40rpx;
cursor: pointer;
}
.back-icon::before,
.back-icon::after {
content: '';
position: absolute;
transition: all 0.3s ease;
}
.back-icon::after {
top: 25%;
left: 25%;
width: 40%;
height: 40%;
border-top: 4rpx solid #0066FF;
border-left: 4rpx solid #0066FF;
transform: rotate(135deg);
}
}
}
}
.loading-pass {
color: #0066FF;
font-family: DINAlternate, DINAlternate;
font-weight: bold;
font-size: 65rpx;
color: #0066FF;
letter-spacing: 12rpx
}
.no-pass {
color: #D70C18;
}
.pass {
color: #0066FF;
}
}
.scroll-Y {
max-height: calc(100vh - var(--status-bar-height) - 70rpx - 70rpx - 40rpx - 64rpx - 68rpx - 60rpx);
min-height: calc(100vh - var(--status-bar-height) - 70rpx - 70rpx - 40rpx - 64rpx - 68rpx - 60rpx - 380rpx);
}
.nav-div {
position: relative;
.title {
height: 70rpx;
font-family: PingFangSC;
font-weight: 500;
font-size: 34rpx;
color: #000000;
line-height: 70rpx;
text-align: center;
font-style: normal;
}
.back_div {
margin-right: 10rpx;
position: absolute;
left: 25rpx;
top: 0;
padding: 15rpx;
.back-icon {
position: relative;
width: 40rpx;
height: 40rpx;
cursor: pointer;
}
.back-icon::before,
.back-icon::after {
content: '';
position: absolute;
transition: all 0.3s ease;
}
.back-icon::after {
top: 25%;
left: 25%;
width: 40%;
height: 40%;
border-top: 4rpx solid #000;
border-left: 4rpx solid #000;
transform: rotate(-45deg);
}
}
}
.main_div {
display: flex;
flex-direction: column;
background-color: #F0F5F9;
/* 添加30度角的斜向上渐变,高度限制为400px */
background-image: linear-gradient(30deg, #F0F5F9, #EBF1FF);
/* 渐变背景高度400px,宽度充满容器 */
background-size: 100% 600rpx;
/* 防止渐变背景重复 */
background-repeat: no-repeat;
min-height: 100vh;
margin: 0;
}
</style>
+1 -1
View File
@@ -89,7 +89,7 @@
<view class="title">AI问答</view>
</view>
<view class="item" @click="common.navigateTo('/pages/examination/index')">
<view class="item" @click="common.navigateTo('/pages/examination/result?execId=1')">
<image class="icon" src="@/static/images/index/navigation_ai.png"></image>
<view class="title">AI陪练</view>
</view>
+17 -12
View File
@@ -11,7 +11,6 @@
<view class="subscript" v-if="detailData.examStatText==='Y'">已完成</view>
<view class="title_div">
<view class="title ellipsis-text">{{detailData.papersName}}</view>
</view>
<view class="time">
<text class="color_3">起止时间</text><text
@@ -138,10 +137,10 @@
</view>
<view class="fl1"></view>
<view class="table_td">
20
{{allNumber}}
</view>
<view class="table_td">
100
{{allGrade}}
</view>
</view>
</view>
@@ -162,7 +161,8 @@
onLoad
} from '@dcloudio/uni-app';
import {
reactive
reactive,
computed
} from 'vue'
import {
startTraExamPapersInfo
@@ -177,33 +177,38 @@
examEndTm: '',
execPersionNumer: '',
planPersionNumber: '',
judgeNumber: 0,
singleNumber: 0,
multiNumber: 0,
essayNumber: 0,
judgeGrade: 0,
singleGrade: 0,
multiGrade: 0,
essayGrade: 0,
})
const customStyle = {
backgroundColor: '#0066FF',
border: '1px solid rgb(12, 123, 245)',
}
const allNumber = computed(() => detailData.judgeNumber + detailData.singleNumber + detailData.multiNumber + detailData.essayNumber)
const allGrade = computed(() => detailData.judgeGrade + detailData.singleGrade + detailData.multiGrade + detailData.essayGrade)
const goto_examination = async () => {
common.loading()
startTraExamPapersInfo({
examId : "1"
examId : detailData.examId
}).then(res => {
setPageCache('examination', res.body)
setPageCache('examination', {...res.body, examId:detailData.examId})
common.navigateTo('/pages/examination/index')
}).finally(() => {
common.hideLoading()
})
// papersId.value = e.papersId
// paperData.value = setPageCache('examination_'+papersId.value)
// if (!papersId.value || !paperData.value) {
// common.navigateBack()
// return
// }
}
onLoad((e) => {
const testing_hall_details = getPageCache('testing_hall_details')
Object.assign(detailData, {
...testing_hall_details
})
console.log('detailData', detailData);
})
</script>
+9
View File
@@ -135,6 +135,15 @@
}
}
},
{
"path": "pages/examination/result",
"style": {
"navigationBarTitleText": "考试结果",
"app-plus": {
"titleNView": false
}
}
},
{
"path": "pages/practice/index",
"style": {
Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 845 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 357 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 125 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB