提交 be13cd6d authored 作者: lhh's avatar lhh
...@@ -120,3 +120,13 @@ export function getExperimentReport(params: { experiment_id: string }) { ...@@ -120,3 +120,13 @@ export function getExperimentReport(params: { experiment_id: string }) {
export function getExperimentScore(params: { experiment_id: string }) { export function getExperimentScore(params: { experiment_id: string }) {
return httpRequest.get('/api/lab/v1/student/experiment/achievement', { params }) return httpRequest.get('/api/lab/v1/student/experiment/achievement', { params })
} }
// 获取实验试题列表
export function getExperimentQuestionList(params: { experiment_id: string }) {
return httpRequest.get('/api/lab/v1/student/experiment-question/list', { params })
}
// 获取实验试题详情
export function getExperimentQuestion(params: { experiment_id: string; id: string }) {
return httpRequest.get('/api/lab/v1/student/experiment-question/detail', { params })
}
<script setup lang="ts">
import { getExperimentQuestionList, getExperimentQuestion } from '../api'
interface Props {
experiment_id: string
}
interface QuestionListItem {
experiment_id: string
id: string
type: string
}
type QuestionGroupListItem = QuestionListItem & { index: number }
interface QuestionGroupList {
type: string
list: Array<QuestionGroupListItem>
}
const props = defineProps<Props>()
const questionIndex = ref<number>(1)
const questionId = computed(() => {
return questionList.value[questionIndex.value - 1]?.id
})
const questionList = ref<QuestionListItem[]>([])
const questionGroupList = computed<QuestionGroupList[]>(() => {
return questionList.value.reduce((result, item, index) => {
let currentGroup = result.find(({ type }) => type === item.type)
if (!currentGroup) {
result.push({ type: item.type, list: [] })
currentGroup = result[result.length - 1]
}
currentGroup.list.push({ ...item, index: index + 1 })
return result
}, [] as QuestionGroupList[])
})
const hasPrev = computed(() => questionIndex.value > 1)
const hasNext = computed(() => questionIndex.value < questionList.value.length)
// 试题列表
async function fetchList() {
if (!props.experiment_id) return
const res = await getExperimentQuestionList({ experiment_id: props.experiment_id })
questionList.value = res.data.items
}
watchEffect(() => {
if (props.experiment_id) fetchList()
})
// 试题详情
const questionDetail = ref()
async function fetchDetail() {
if (!questionId.value) return
const res = await getExperimentQuestion({ experiment_id: props.experiment_id, id: questionId.value })
const detail = res.data.detail
let files = []
try {
files = JSON.parse(detail.files)
} catch (error) {
console.log(error)
}
questionDetail.value = { ...detail, files, score: parseFloat(detail.score) }
}
watch(questionId, id => {
if (id) fetchDetail()
})
function handleClick(question: QuestionGroupListItem) {
questionIndex.value = question.index
}
function handlePrev() {
questionIndex.value--
}
function handleNext() {
questionIndex.value++
}
</script>
<template>
<div v-if="questionList.length">
<el-card shadow="never" class="question-number">
<dl v-for="group in questionGroupList" :key="group.type">
<dt>{{ group.type }}</dt>
<dd>
<span
:class="{ 'is-active': question.id === questionId }"
v-for="question in group.list"
:key="question.index"
@click="handleClick(question)"
>{{ question.index }}</span
>
</dd>
</dl>
</el-card>
<el-card shadow="never" class="question-item" v-if="questionDetail">
<h3 class="question-item__title">标签管理</h3>
<p class="question-item__stem">
{{ questionIndex }}{{ questionDetail.title }} <span>{{ questionDetail.score }}分)</span>
</p>
<p class="question-item__content">{{ questionDetail.content }}</p>
<ul class="question-item__files">
<li class="question-item__files-item" v-for="(file, index) in questionDetail.files" :key="index">
<div class="question-item__files-item__title">
<p>{{ file.name }}</p>
<p>{{ file.size }}</p>
</div>
<a :href="file.url" target="_blank" v-if="file.is_download">下载</a>
<a :href="file.url" target="_blank">查看</a>
</li>
</ul>
</el-card>
<el-row justify="center">
<el-button type="primary" :disabled="!hasPrev" @click="handlePrev">上一题</el-button>
<el-button type="primary" :disabled="!hasNext" @click="handleNext">下一题</el-button>
</el-row>
</div>
<el-empty description="暂无数据" v-else />
</template>
<style lang="scss" scoped>
.question-number {
dt {
font-size: 14px;
margin-bottom: 10px;
}
dd {
span {
margin-right: 10px;
margin-bottom: 10px;
display: inline-block;
width: 28px;
height: 28px;
text-align: center;
font-size: 14px;
line-height: 28px;
border: 1px solid #bbb;
border-radius: 50%;
cursor: pointer;
&.is-active {
color: #fff;
background-color: var(--main-color);
border-color: var(--main-color);
}
}
}
}
.question-item {
margin-top: 10px;
margin-bottom: 20px;
}
.question-item__title {
margin-bottom: 10px;
font-size: 16px;
font-weight: 500;
}
.question-item__stem {
font-size: 14px;
color: #101010;
}
.question-item__content {
margin-top: 10px;
font-size: 13px;
color: #75797b;
}
.question-item__files-item {
margin-top: 10px;
display: flex;
align-items: center;
padding: 10px;
background-color: #f2f2f2;
border-radius: 6px;
a {
margin-left: 10px;
font-size: 14px;
color: var(--main-color);
}
}
.question-item__files-item__title {
flex: 1;
font-size: 12px;
color: #75797b;
}
</style>
...@@ -11,6 +11,7 @@ import { saveAs } from 'file-saver' ...@@ -11,6 +11,7 @@ import { saveAs } from 'file-saver'
import html2pdf from 'html2pdf.js' import html2pdf from 'html2pdf.js'
import { useCookies } from '@vueuse/integrations/useCookies' import { useCookies } from '@vueuse/integrations/useCookies'
const Question = defineAsyncComponent(() => import('../components/Question.vue'))
const Info = defineAsyncComponent(() => import('../components/Info.vue')) const Info = defineAsyncComponent(() => import('../components/Info.vue'))
const Case = defineAsyncComponent(() => import('../components/Case.vue')) const Case = defineAsyncComponent(() => import('../components/Case.vue'))
const Book = defineAsyncComponent(() => import('../components/Book.vue')) const Book = defineAsyncComponent(() => import('../components/Book.vue'))
...@@ -235,6 +236,9 @@ function handleReportPreviewReady() { ...@@ -235,6 +236,9 @@ function handleReportPreviewReady() {
</el-form-item> </el-form-item>
</el-form> </el-form>
<el-tabs type="border-card"> <el-tabs type="border-card">
<el-tab-pane label="实验试题" lazy>
<Question :experiment_id="form.experiment_id"></Question>
</el-tab-pane>
<el-tab-pane label="实验信息" lazy> <el-tab-pane label="实验信息" lazy>
<Info :data="experimentInfo"></Info> <Info :data="experimentInfo"></Info>
</el-tab-pane> </el-tab-pane>
...@@ -274,8 +278,7 @@ function handleReportPreviewReady() { ...@@ -274,8 +278,7 @@ function handleReportPreviewReady() {
<el-button <el-button
type="primary" type="primary"
:disabled="disabled" :disabled="disabled"
v-if="experimentInfo?.report_upload_way === 2 && !experimentInfo?.is_commit_report" v-if="experimentInfo?.report_upload_way === 2 && !experimentInfo?.is_commit_report">
>
<router-link :to="`/student/lab/report/${form.experiment_id}`" target="_blank">在线实验报告</router-link> <router-link :to="`/student/lab/report/${form.experiment_id}`" target="_blank">在线实验报告</router-link>
</el-button> </el-button>
<el-button <el-button
...@@ -309,26 +312,22 @@ function handleReportPreviewReady() { ...@@ -309,26 +312,22 @@ function handleReportPreviewReady() {
v-model="reportDialogVisible" v-model="reportDialogVisible"
:data="experimentInfo" :data="experimentInfo"
@update="fetchExperimentRecord" @update="fetchExperimentRecord"
v-if="reportDialogVisible && experimentInfo" v-if="reportDialogVisible && experimentInfo"></ReportDialog>
></ReportDialog>
<ReportFilePreview <ReportFilePreview
v-model="reportFilePreviewVisible" v-model="reportFilePreviewVisible"
:data="experimentInfo" :data="experimentInfo"
v-if="reportFilePreviewVisible && experimentInfo" v-if="reportFilePreviewVisible && experimentInfo"></ReportFilePreview>
></ReportFilePreview>
<!-- 实验准备 --> <!-- 实验准备 -->
<PrepareDialog <PrepareDialog
v-model="prepareDialogVisible" v-model="prepareDialogVisible"
:data="experimentInfo" :data="experimentInfo"
v-if="prepareDialogVisible && experimentInfo" v-if="prepareDialogVisible && experimentInfo"></PrepareDialog>
></PrepareDialog>
<!-- 实验结果 --> <!-- 实验结果 -->
<ResultDialog <ResultDialog
v-model="resultDialogVisible" v-model="resultDialogVisible"
:data="experimentInfo" :data="experimentInfo"
v-if="resultDialogVisible && experimentInfo" v-if="resultDialogVisible && experimentInfo"></ResultDialog>
></ResultDialog>
<!-- 导出在线报告 --> <!-- 导出在线报告 -->
<template v-if="experimentInfo?.id && isExport"> <template v-if="experimentInfo?.id && isExport">
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论