布置作业、提交与自动评分
- 作业:老师选实验、起点(界面已做好 / 空白工程)、截止时间、每项分值(自动评分项 + 老师评分项); 起点工程由设计器引擎从参考答案生成(去掉事件绑定和事件处理方法),布置时保存起点和评分规则快照 - 提交:后台排队评分(全站同时最多评 3 份、跑 6 个检查项),重启后继续评;评分中不能再交,截止后不能交 - 学生:"我的作业"列表;实验页的作业模式(作业名、截止时间、提交、得分),评分结果弹出逐项显示 - 老师:班级管理页加"作业"标签页,布置、修改、删除作业,查看全班提交情况;改分值后重新算分 - 串口列表为空时提示在 Load 或 Click 事件里填充 - 测试:作业接口(可见范围、排队评分、部分得分、改分值、截止、删除);10 个示例两种起点都能编译 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
37fc747b49
commit
4e6b0d5cb2
23 files changed
+1439
-50
No files matched your search
@@ -0,0 +1,109 @@
|
||||
<script setup lang="ts">
|
||||
// 一次提交的自动评分结果:每项通过与否、得分和不通过的原因;老师评分项只列出名称和分值。
|
||||
import { computed } from 'vue'
|
||||
import { NSpin } from 'naive-ui'
|
||||
import type { Assignment, Submission } from '@iot/shared'
|
||||
|
||||
const props = defineProps<{ assignment: Assignment; submission: Submission }>()
|
||||
|
||||
const autoTotal = computed(() => props.assignment.scoring.auto.reduce((a, b) => a + b, 0))
|
||||
const manual = computed(() => props.assignment.scoring.manual)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="grade">
|
||||
<div v-if="submission.status === 'pending'" class="pending">
|
||||
<NSpin size="small" />
|
||||
<span>评分中…<template v-if="submission.queueAhead">前面还有 {{ submission.queueAhead }} 份在排队</template></span>
|
||||
</div>
|
||||
<div v-else-if="submission.status === 'error'" class="error">评分时服务器出错了,请重新提交;还是不行请告诉老师。</div>
|
||||
<template v-else-if="submission.result">
|
||||
<div class="summary">
|
||||
自动评分 <b>{{ submission.autoScore }}</b> / {{ autoTotal }} 分
|
||||
<span v-if="!submission.result.compiled" class="error">(编译没有通过,先改正编译错误)</span>
|
||||
</div>
|
||||
<ul class="items">
|
||||
<li v-for="(r, i) in submission.result.results" :key="i" :class="r.passed ? 'passed' : 'failed'">
|
||||
<span class="mark">{{ r.passed ? '✓' : '✗' }}</span>
|
||||
<div>
|
||||
<div class="title">
|
||||
{{ r.title }}<span class="points">{{ r.passed ? assignment.scoring.auto[i] : 0 }} / {{ assignment.scoring.auto[i] }} 分</span>
|
||||
</div>
|
||||
<div v-if="r.message" class="message">{{ r.message }}</div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</template>
|
||||
<div v-if="manual.length" class="manual">
|
||||
由老师评分:<span v-for="m in manual" :key="m.title">{{ m.title }}({{ m.points }} 分)</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.grade {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.pending {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.summary b {
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.items {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.items li {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.mark {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.passed .mark {
|
||||
color: #16a34a;
|
||||
}
|
||||
|
||||
.failed .mark,
|
||||
.error {
|
||||
color: #dc2626;
|
||||
}
|
||||
|
||||
.title {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.points {
|
||||
color: #6b7280;
|
||||
}
|
||||
|
||||
.message {
|
||||
margin-top: 2px;
|
||||
color: #b91c1c;
|
||||
}
|
||||
|
||||
.manual {
|
||||
color: #6b7280;
|
||||
}
|
||||
|
||||
.manual span + span::before {
|
||||
content: "、";
|
||||
}
|
||||
</style>
|
||||
Reference in new issue
Block a user