feat(提交列表): 重做成左边列表、右边代码,方向键一条条翻,不再开弹框
- 右栏常驻选中那条的代码:编译失败 / 运行时错误用中文说清第几行错了并标红, 老师看得到逐个测试点,学生看别人的只显示结果 - 老师一键「这节课」:筛到正在上课的班、这节课的题、今天 - 「正在评分」的行自己变成结果;新交的不插队,顶上提示「有 N 条新提交」 - 按天分组、默认每页 30 条;状态筛选补全,语言补上 SQL;流程图的评分详情也放进右栏 - 课堂看板的格子和名字能直接点进这个学生今天的提交 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
ea480d5e0c
commit
660f689a5c
14 files changed
+2845
-673
No files matched your search
@@ -0,0 +1,137 @@
|
||||
<script setup lang="ts">
|
||||
import { useThemeVars } from "naive-ui"
|
||||
import { useDark } from "@vueuse/core"
|
||||
|
||||
/**
|
||||
* 只读的代码区:行号 + 高亮 + 可选地标红一行(编译失败 / 运行时错误报了行号时)。
|
||||
*
|
||||
* 不用 n-code 自带的 show-line-numbers:它没法标出某一行。行高写死成一个值,
|
||||
* 标红的那条底色按行号算 top,和代码逐行对齐。
|
||||
*/
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
code: string
|
||||
/** highlight.js 的语言名(LANGUAGE_FORMAT_VALUE) */
|
||||
language: string
|
||||
/** 要标红的行,1 起 */
|
||||
markLine?: number | null
|
||||
fontSize?: number
|
||||
lineHeight?: number
|
||||
}>(),
|
||||
{ markLine: null, fontSize: 18, lineHeight: 30 },
|
||||
)
|
||||
|
||||
const theme = useThemeVars()
|
||||
const isDark = useDark()
|
||||
|
||||
const PADDING = 8
|
||||
const lineCount = computed(() => Math.max(1, props.code.split("\n").length))
|
||||
const markStyle = computed(() =>
|
||||
props.markLine && props.markLine <= lineCount.value
|
||||
? {
|
||||
top: `${PADDING + (props.markLine - 1) * props.lineHeight}px`,
|
||||
height: `${props.lineHeight}px`,
|
||||
}
|
||||
: null,
|
||||
)
|
||||
|
||||
const scroller = useTemplateRef<HTMLElement>("scroller")
|
||||
// 换了一条就回到顶上;有标红行的,滚到那一行附近
|
||||
watch(
|
||||
() => [props.code, props.markLine] as const,
|
||||
async () => {
|
||||
await nextTick()
|
||||
const el = scroller.value
|
||||
if (!el) return
|
||||
const target = props.markLine ? (props.markLine - 3) * props.lineHeight : 0
|
||||
el.scrollTop = Math.max(0, target)
|
||||
el.scrollLeft = 0
|
||||
},
|
||||
{ immediate: true },
|
||||
)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
ref="scroller"
|
||||
class="code-view"
|
||||
:style="{
|
||||
'--fs': `${fontSize}px`,
|
||||
'--lh': `${lineHeight}px`,
|
||||
'--pad': `${PADDING}px`,
|
||||
}"
|
||||
>
|
||||
<div class="gutter">
|
||||
<div v-for="n in lineCount" :key="n" :class="{ marked: n === markLine }">{{ n }}</div>
|
||||
</div>
|
||||
<div class="body">
|
||||
<div v-if="markStyle" class="mark" :style="markStyle"></div>
|
||||
<n-code :code="code" :language="language" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.code-view {
|
||||
flex: 1 1 0;
|
||||
min-height: 0;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
overflow: auto;
|
||||
border: 1px solid v-bind("theme.dividerColor");
|
||||
border-radius: 6px;
|
||||
background: v-bind("theme.cardColor");
|
||||
font-family: Consolas, Monaco, monospace;
|
||||
font-size: var(--fs);
|
||||
line-height: var(--lh);
|
||||
}
|
||||
|
||||
.gutter {
|
||||
position: sticky;
|
||||
left: 0;
|
||||
z-index: 1;
|
||||
flex: none;
|
||||
min-width: 40px;
|
||||
min-height: 100%;
|
||||
box-sizing: border-box;
|
||||
padding: var(--pad) 10px var(--pad) 8px;
|
||||
text-align: right;
|
||||
color: v-bind("theme.textColor3");
|
||||
background: v-bind("isDark ? 'rgba(255,255,255,0.03)' : '#fafafb'");
|
||||
border-right: 1px solid v-bind("theme.dividerColor");
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.gutter .marked {
|
||||
color: v-bind("theme.errorColor");
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.body {
|
||||
position: relative;
|
||||
flex: 1 0 auto;
|
||||
padding: var(--pad) 14px;
|
||||
}
|
||||
|
||||
.mark {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: v-bind("isDark ? 'rgba(232, 128, 128, 0.16)' : '#fdf0f2'");
|
||||
}
|
||||
|
||||
.body :deep(.n-code) {
|
||||
position: relative;
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
line-height: inherit;
|
||||
}
|
||||
|
||||
.body :deep(pre) {
|
||||
margin: 0;
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
line-height: inherit;
|
||||
white-space: pre;
|
||||
}
|
||||
</style>
|
||||
Reference in new issue
Block a user