提交 9239d83a authored 作者: 王鹏飞's avatar 王鹏飞

chore: update

上级 ead3ac8b
...@@ -2,13 +2,13 @@ import httpRequest from '@/utils/axios' ...@@ -2,13 +2,13 @@ import httpRequest from '@/utils/axios'
// 获取实验记录列表 // 获取实验记录列表
export function getExperimentRecordList(params?: { export function getExperimentRecordList(params?: {
course_id?: string competition_id?: string
experiment_id?: string check_status?: string
specialty_id?: string organ_id?: string
class_id?: string
student_name?: string student_name?: string
login_id?: string
page?: number page?: number
page_size?: number 'per-page'?: number
}) { }) {
return httpRequest.get('/api/lab/v1/expert/check/list', { params }) return httpRequest.get('/api/lab/v1/expert/check/list', { params })
} }
...@@ -18,20 +18,14 @@ export function getFilterList(params?: { leader?: number }) { ...@@ -18,20 +18,14 @@ export function getFilterList(params?: { leader?: number }) {
return httpRequest.get('/api/lab/v1/expert/check/condition', { params }) return httpRequest.get('/api/lab/v1/expert/check/condition', { params })
} }
// 获取实验记录详情 // 大赛评分详情
export function getExperimentRecord(params: { experiment_id: string; student_id: string }) { export function getCheckView(params: { id: string }) {
return httpRequest.get('/api/lab/v1/teacher/record/view', { params }) return httpRequest.get('/api/lab/v1/expert/check/view', { params })
} }
// 实验记录评分 // 评分
export function checkExperimentRecord(data: { export function submitScore(data: { id: string; scores: string }) {
experiment_id: string return httpRequest.post('/api/lab/v1/expert/check/set-score', data)
student_id: string
operate: number
result: number
file: number
}) {
return httpRequest.post('/api/lab/v1/teacher/record/check', data)
} }
// 同步1+X考试成绩 // 同步1+X考试成绩
......
<script setup lang="ts"> <script setup lang="ts">
import type { FormInstance, FormRules } from 'element-plus' import { ElMessage } from 'element-plus'
import type { RecordItem, FileItem } from '../types'
import { Document } from '@element-plus/icons-vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { getExperimentRecord, checkExperimentRecord } from '../api' import { submitScore } from '../api'
interface Props {
data: RecordItem
}
const props = defineProps<Props>()
const emit = defineEmits<{ const emit = defineEmits<{
(e: 'update'): void (e: 'update'): void
(e: 'update:modelValue', visible: boolean): void (e: 'update:modelValue', visible: boolean): void
}>() }>()
let detail = $ref<RecordItem>() const detail = $ref<any>(inject('detail'))
function fetchInfo() { let tableList = $ref<any>([])
getExperimentRecord({ experiment_id: props.data.experiment_id, student_id: props.data.student_id }).then(res => {
detail = res.data
})
}
watchEffect(() => { watchEffect(() => {
fetchInfo() const checkDetails = detail?.check_details || []
}) tableList = checkDetails.map((item: any) => {
// 实验报告文件 return {
const file = $computed<FileItem>(() => { ...item,
try { old_score: parseFloat(item.old_score),
return detail?.file ? JSON.parse(detail.file) : null ratio: parseFloat(item.ratio),
} catch (error) { score: parseFloat(item.score)
console.log(error) }
} })
return null
})
// 实验过程截图
const pictures = $computed<FileItem[]>(() => {
try {
return detail?.pictures ? JSON.parse(detail.pictures) : []
} catch (error) {
console.log(error)
}
return []
}) })
const formRef = $ref<FormInstance>()
const form = reactive<{ operate?: number; result?: number; file?: number }>({
operate: undefined,
result: undefined,
file: undefined
})
const score = $computed<number>(() => { const score = $computed<number>(() => {
const result = ((form.operate || 0) + (form.result || 0) + (form.file || 0)) / 3 return tableList.reduce((result: number, item: any) => {
return parseFloat(result.toFixed(2)) return (result += item.score || 0)
}) }, 0)
const rules = ref<FormRules>({
operate: [{ required: true, message: '请输入1~100数字' }],
result: [{ required: true, message: '请输入1~100数字' }],
file: [{ required: true, message: '请输入1~100数字' }]
}) })
// 提交 // 提交
function handleSubmit() { function handleSubmit() {
formRef?.validate().then(() => { const scores = tableList.map((item: any) => {
ElMessageBox.confirm('成绩评分不能修改,确认要保存该成绩吗?', '提示').then(() => { return { id: item.id, score: item.score }
const params: any = { ...form, experiment_id: props.data.experiment_id, student_id: props.data.student_id } })
checkExperimentRecord(params).then(() => { const params = { id: detail.id, scores: JSON.stringify(scores) }
ElMessage({ message: '保存成功', type: 'success' }) submitScore(params).then(() => {
emit('update') ElMessage({ message: '保存成功', type: 'success' })
emit('update:modelValue', false) emit('update')
}) emit('update:modelValue', false)
})
}) })
} }
</script> </script>
<template> <template>
<el-dialog <el-dialog title="评分" :close-on-click-modal="false" width="700px" @update:modelValue="$emit('update:modelValue')">
title="学生实验评分" <el-form label-suffix=":" v-if="detail">
:close-on-click-modal="false" <el-form-item label="赛项名称">{{ detail.competition_id_name }}</el-form-item>
width="700px" <el-form-item label="选手姓名">{{ detail.student_name }}</el-form-item>
@update:modelValue="$emit('update:modelValue')" <el-form-item label="选手ID">{{ detail.login_id }}</el-form-item>
>
<el-form :rules="rules" label-width="120px" label-suffix=":" v-if="detail">
<el-row>
<el-col :span="12">
<el-form-item label="实验名称">{{ detail.experiment_name }}</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="实验课程名称">{{ detail.course_name }}</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="学生姓名">{{ detail.student_name }}</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="学生学号">{{ detail.sno_number }}</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="所属专业">{{ detail.specialty_name }}</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="所属班级">{{ detail.class_name }}</el-form-item>
</el-col>
</el-row>
<el-form-item label="实验成绩" class="form-item-score">
<el-form
ref="formRef"
:model="form"
:rules="rules"
hide-required-asterisk
inline
label-position="top"
style="padding: 5px 0 20px"
>
<el-form-item label="实验操作" prop="operate">
<el-input-number :min="1" :max="100" :controls="false" step-strictly v-model="form.operate" />
</el-form-item>
<el-form-item label="实验结果" prop="result">
<el-input-number :min="1" :max="100" :controls="false" step-strictly v-model="form.result" />
</el-form-item>
<el-form-item label="实验报告" prop="file">
<el-input-number :min="1" :max="100" :controls="false" step-strictly v-model="form.file" />
</el-form-item>
<el-form-item label="综合实验成绩">
<el-input-number :min="0" :max="100" :controls="false" disabled v-model="score" />
</el-form-item>
</el-form>
</el-form-item>
<el-form-item label="实验报告文件">
<div v-if="file">
<a :href="file.url" target="_blank" class="file-item">
<el-icon><Document /></el-icon>{{ file.name }}
</a>
</div>
</el-form-item>
<el-form-item label="实验过程截图">
<ul class="picture-list">
<li v-for="item in pictures" :key="item.url">
<p class="t1">
<a :href="item.url" target="_blank">{{ item.name }}</a>
</p>
<p class="t2">截图时间:{{ item.upload_time }}</p>
</li>
</ul>
</el-form-item>
<el-row justify="center">
<el-button type="primary" round auto-insert-space @click="handleSubmit">保存</el-button>
<el-button round auto-insert-space @click="$emit('update:modelValue', false)">取消</el-button>
</el-row>
</el-form> </el-form>
<el-table :data="tableList" :header-cell-style="{ background: '#ededed' }">
<el-table-column label="评分规则" prop="name" align="center"></el-table-column>
<el-table-column label="评分方法" prop="type_name" align="center"></el-table-column>
<el-table-column label="分值" prop="old_score" align="center"></el-table-column>
<el-table-column label="占比(%)" prop="ratio" align="center"></el-table-column>
<el-table-column label="评分" prop="score" align="center">
<template #default="{ row }">
<el-input-number
:controls="false"
v-model="row.score"
:min="0"
:max="row.old_score"
:disabled="row.type === '2'"
style="width: 100%" />
</template>
</el-table-column>
</el-table>
<p class="result">
最终得分:<span>{{ score }}</span>
</p>
<el-row justify="center">
<el-button type="primary" round auto-insert-space @click="handleSubmit">保存</el-button>
<el-button round auto-insert-space @click="$emit('update:modelValue', false)">取消</el-button>
</el-row>
</el-dialog> </el-dialog>
</template> </template>
<style lang="scss" scoped> <style lang="scss" scoped>
.file-item { .result {
padding: 40px 0;
display: flex; display: flex;
align-items: center; align-items: center;
color: var(--main-color); justify-content: center;
.el-icon { span {
margin-right: 5px; padding: 0 10px;
} font-size: 40px;
}
.picture-list {
width: 100%;
li {
display: flex;
justify-content: space-between;
}
a {
color: var(--main-color); color: var(--main-color);
} }
.t1 {
flex: 1;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}
}
.form-item-score {
padding-top: 10px;
background-color: #f8f9fb;
border-radius: 16px;
:deep(.el-form-item__label) {
text-align: center;
}
.el-input-number {
width: 100px;
}
} }
</style> </style>
...@@ -5,6 +5,9 @@ export const routes: Array<RouteRecordRaw> = [ ...@@ -5,6 +5,9 @@ export const routes: Array<RouteRecordRaw> = [
{ {
path: '/teacher/contest/record', path: '/teacher/contest/record',
component: AppLayout, component: AppLayout,
children: [{ path: '', component: () => import('./views/Index.vue') }] children: [
{ path: '', component: () => import('./views/Index.vue') },
{ path: ':id', component: () => import('./views/Detail.vue'), props: true }
]
} }
] ]
<script setup lang="ts">
import Preview from '@/components/Preview.vue'
import { getCheckView } from '../api'
const ScoreDialog = defineAsyncComponent(() => import('../components/ScoreDialog.vue'))
interface Props {
id: string
}
const props = defineProps<Props>()
// 左侧
const leftPanelVisible = $ref<boolean>(true)
let detail = $ref<any>()
provide('detail', $$(detail))
// 评分规则文件
const file = $computed(() => {
return detail ? JSON.parse(detail?.competition_rubric.url) : { url: '' }
})
function fetchInfo() {
getCheckView({ id: props.id }).then(res => {
detail = res.data
})
}
watchEffect(() => {
fetchInfo()
})
// 右侧
const LAB_URL = import.meta.env.VITE_LAB_URL
// 评分
const dialogVisible = $ref(false)
</script>
<template>
<section class="lab" v-if="detail">
<div class="lab-left" :class="{ 'is-hidden': !leftPanelVisible }">
<div class="lab-left__inner">
<el-tabs type="border-card">
<el-tab-pane label="评分规则" lazy>
<Preview :url="file.url"></Preview>
</el-tab-pane>
</el-tabs>
</div>
<div class="panel-icon" @click="leftPanelVisible = !leftPanelVisible">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 86" aria-hidden="true" width="16" height="86">
<g fill="none" fill-rule="evenodd">
<path
class="path-wapper"
d="M0 0l14.12 8.825A4 4 0 0116 12.217v61.566a4 4 0 01-1.88 3.392L0 86V0z"
fill="#e1e4eb"></path>
<path
class="path-arrow"
d="M10.758 48.766a.778.778 0 000-1.127L6.996 43l3.762-4.639a.778.778 0 000-1.127.85.85 0 00-1.172 0l-4.344 5.202a.78.78 0 000 1.128l4.344 5.202a.85.85 0 001.172 0z"
fill="#8D9EA7"
fill-rule="nonzero"></path>
</g>
</svg>
</div>
</div>
<div class="lab-right">
<AppCard>
<el-row justify="space-between">
<div class="info">
<p>
赛项名称:<span>{{ detail.competition_id_name }}</span>
</p>
<p>
选手姓名:<span>{{ detail.student_name }}</span>
</p>
<p>
选手ID:<span>{{ detail.login_id }}</span>
</p>
</div>
<div>
<el-button type="primary" @click="dialogVisible = true">评分</el-button>
</div>
</el-row>
</AppCard>
<div class="lab-box">
<iframe :src="LAB_URL" frameborder="0" class="iframe" ref="iframeRef"></iframe>
</div>
</div>
</section>
<ScoreDialog v-model="dialogVisible"></ScoreDialog>
</template>
<style lang="scss" scoped>
.lab {
display: flex;
height: calc(100vh - 110px);
}
.lab-left {
position: relative;
width: 400px;
padding: 20px;
background-color: #e1e4eb;
border-radius: 6px;
box-sizing: border-box;
transition: all 0.1s;
&.is-hidden {
width: 0;
padding: 0;
.panel-icon {
left: -20px;
right: 0;
}
.path-arrow {
transform-origin: center center;
transform: rotate(180deg);
}
}
.lab-left__inner {
display: flex;
flex-direction: column;
width: 100%;
height: 100%;
overflow: hidden;
}
.el-tabs {
flex: 1;
border: 0;
overflow: hidden;
}
:deep(.el-tabs__header) {
background-color: #e1e4eb;
}
:deep(.el-tabs__item) {
padding: 0 14px !important;
border: 0;
border-radius: 6px 6px 0px 0px;
}
:deep(.el-tabs__content) {
height: calc(100% - 40px);
box-sizing: border-box;
}
:deep(.el-tab-pane) {
height: 100%;
overflow-y: auto;
}
}
.panel-icon {
position: absolute;
top: 50%;
right: -16px;
width: 16px;
height: 86px;
transform: translateY(-50%);
z-index: 100;
cursor: pointer;
}
.lab-right {
margin-left: 20px;
flex: 1;
display: flex;
flex-direction: column;
height: 100%;
}
.lab-box {
flex: 1;
width: 100%;
margin-top: 20px;
}
.iframe {
width: 100%;
height: 100%;
}
.info {
flex: 1;
display: flex;
align-items: center;
span {
color: var(--main-color);
}
p + p {
margin-left: 40px;
}
}
</style>
...@@ -69,7 +69,7 @@ const listOptions = $computed(() => { ...@@ -69,7 +69,7 @@ const listOptions = $computed(() => {
{ label: '评分规则', prop: 'competition_is_more_status' }, { label: '评分规则', prop: 'competition_is_more_status' },
{ label: '已评分人数', prop: 'checked_count', slots: 'table-count' }, { label: '已评分人数', prop: 'checked_count', slots: 'table-count' },
{ label: '已评分', prop: 'checked_flag_name' }, { label: '已评分', prop: 'checked_flag_name' },
{ label: '得分', prop: 'score', slots: 'table-score' }, { label: '得分', prop: 'score_name' },
{ label: '更新时间', prop: 'updated_time' }, { label: '更新时间', prop: 'updated_time' },
{ label: '操作', slots: 'table-x', width: 100 } { label: '操作', slots: 'table-x', width: 100 }
] ]
...@@ -119,7 +119,9 @@ function onUpdateSuccess() { ...@@ -119,7 +119,9 @@ function onUpdateSuccess() {
<span :class="{ 'is-info': row.score !== '--' }">{{ row.score }}</span> <span :class="{ 'is-info': row.score !== '--' }">{{ row.score }}</span>
</template> </template>
<template #table-x="{ row }"> <template #table-x="{ row }">
<el-button text type="primary" v-if="row.checked_flag" v-permission="'v1-teacher-record-check'">评分</el-button> <el-button text type="primary" v-if="row.publish_status === '0'" v-permission="'v1-teacher-record-check'">
<router-link :to="`/teacher/contest/record/${row.id}`" target="_blank">评分</router-link>
</el-button>
</template> </template>
</AppList> </AppList>
</AppCard> </AppCard>
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论