布置时多一个「做什么」:写代码 / 先画再写 / 画流程图(只能选打开了画流程图的题)。 - 先画再写:一道题图画到 A/S、代码也交对才算做完;学生画一道写一道、全画完再写都行, 打开题目自动停在该做的那一步(图没画对停画布,画对了换到布置的语言) - 也能分开布置:先一节画流程图,看板上「用这几道题写代码」再开一节;学生那边把今天 几节课的要求合起来,还没画完的照样看得到要画 - 看板格子是一条进度:图 1/6 → 空心「图 ✓」→ 代码 ✗ → ✓,先写代码没画图的写「缺图」; 卡在画图上的点开讲那张图(要改的框标红 + AI 的哪里错/怎么改),按走对几组归堆 - 写代码的课不再拿画对的流程图顶替做完;数据统计里画流程图的课数流程图提交 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
71323d9b63
commit
38a331c2b7
33 files changed
+4987
-209
No files matched your search
@@ -1,6 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import { Icon } from '@iconify/vue'
|
||||
import type { AdminLesson, LessonLanguage } from '@oj2/contract'
|
||||
import { LESSON_MODE_LABEL, lessonNeeds, type AdminLesson, type LessonLanguage, type LessonMode } from '@oj2/contract'
|
||||
import ProblemPicker from 'oj/classroom/components/ProblemPicker.vue'
|
||||
import { useConfigStore } from 'shared/store/config'
|
||||
import { errorMessage } from 'utils/api'
|
||||
@@ -24,12 +24,16 @@ const configStore = useConfigStore()
|
||||
|
||||
const LESSON_LANGUAGES: LessonLanguage[] = ['Python', 'C', 'C++', 'SQL']
|
||||
const languageOptions = LESSON_LANGUAGES.map((value) => ({ label: LANGUAGE_SHOW_VALUE[value], value }))
|
||||
const modeOptions = (['code', 'both', 'flowchart'] as const).map((value) => ({ label: LESSON_MODE_LABEL[value], value }))
|
||||
const classOptions = computed(() => groupClassOptions(configStore.config?.classList ?? []))
|
||||
|
||||
const className = ref<string | null>(null)
|
||||
const day = ref<string | null>(null)
|
||||
const time = ref<string | null>(null)
|
||||
const language = ref<LessonLanguage>('Python')
|
||||
/** 做什么:画流程图不用选语言(存成 null) */
|
||||
const mode = ref<LessonMode>('code')
|
||||
const needsCode = computed(() => lessonNeeds(mode.value).code)
|
||||
const idsInput = ref('')
|
||||
const saving = ref(false)
|
||||
|
||||
@@ -42,6 +46,7 @@ watch(show, (open) => {
|
||||
day.value = lesson?.day ?? parseTime(now, 'YYYY-MM-DD')
|
||||
time.value = parseTime(lesson?.createdAt ?? now, 'HH:mm')
|
||||
language.value = lesson?.language ?? 'Python'
|
||||
mode.value = lesson?.mode ?? 'code'
|
||||
idsInput.value = lesson?.problems.map((p) => p.problemDisplayId).join(' ') ?? ''
|
||||
})
|
||||
|
||||
@@ -71,7 +76,8 @@ async function save() {
|
||||
className: className.value!,
|
||||
day: day.value!,
|
||||
time: time.value!,
|
||||
language: language.value,
|
||||
language: needsCode.value ? language.value : null,
|
||||
mode: mode.value,
|
||||
problemDisplayIds: inputIds(),
|
||||
}
|
||||
try {
|
||||
@@ -90,7 +96,7 @@ async function save() {
|
||||
|
||||
<template>
|
||||
<n-modal v-model:show="show" preset="card" :title="lesson ? '改这一节' : '补一节'" :bordered="false" :style="{ width: 'min(520px, calc(100vw - 32px))' }">
|
||||
<n-form label-placement="left" label-width="56">
|
||||
<n-form label-placement="left" label-width="64">
|
||||
<n-form-item label="班级">
|
||||
<n-select v-model:value="className" :options="classOptions" filterable placeholder="选班级" />
|
||||
</n-form-item>
|
||||
@@ -100,8 +106,11 @@ async function save() {
|
||||
<n-time-picker v-model:formatted-value="time" value-format="HH:mm" format="HH:mm" class="time" />
|
||||
</div>
|
||||
</n-form-item>
|
||||
<n-form-item label="语言">
|
||||
<n-select v-model:value="language" :options="languageOptions" class="lang" />
|
||||
<n-form-item label="做什么">
|
||||
<div class="when">
|
||||
<n-select v-model:value="mode" :options="modeOptions" class="lang" />
|
||||
<n-select v-if="needsCode" v-model:value="language" :options="languageOptions" aria-label="用什么语言写" class="lang" />
|
||||
</div>
|
||||
</n-form-item>
|
||||
<n-form-item label="题目">
|
||||
<div class="ids">
|
||||
@@ -119,7 +128,15 @@ async function save() {
|
||||
<n-button type="primary" :disabled="!ready" :loading="saving" @click="save">{{ lesson ? '保存' : '补上' }}</n-button>
|
||||
</div>
|
||||
</template>
|
||||
<ProblemPicker v-model:show="picking" v-model:language="language" :initial="pickerInitial" :saving="false" mode="pick" @confirm="picked" />
|
||||
<ProblemPicker
|
||||
v-model:show="picking"
|
||||
v-model:language="language"
|
||||
v-model:lesson-mode="mode"
|
||||
:initial="pickerInitial"
|
||||
:saving="false"
|
||||
mode="pick"
|
||||
@confirm="picked"
|
||||
/>
|
||||
</n-modal>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import type { AdminLesson, AdminLessonList } from '@oj2/contract'
|
||||
import { LESSON_MODE_LABEL, type AdminLesson, type AdminLessonList } from '@oj2/contract'
|
||||
import { useRouteQuery } from '@vueuse/router'
|
||||
import PageHeader from 'admin/components/PageHeader.vue'
|
||||
import { NButton, NPopconfirm, NTooltip, useThemeVars } from 'naive-ui'
|
||||
@@ -133,16 +133,17 @@ function renderActions(lesson: AdminLesson) {
|
||||
])
|
||||
}
|
||||
|
||||
/** 「画流程图」「先画再写 · C语言」「C语言」:写代码是默认的,不写出来 */
|
||||
function wayText(lesson: AdminLesson) {
|
||||
return [lesson.mode !== 'code' ? LESSON_MODE_LABEL[lesson.mode] : '', lesson.language ? LANGUAGE_SHOW_VALUE[lesson.language] : ''].filter(Boolean).join(' · ')
|
||||
}
|
||||
|
||||
/** 手机上一节课一张卡:日子 · 时刻 · 班级一行,题号一行,老师 · 语言 · 做完一行小字,操作一行 */
|
||||
function renderMobileCard(lesson: AdminLesson) {
|
||||
return h('div', { class: 'm-card' }, [
|
||||
h('div', { class: 'm-head' }, `${dayText(lesson.day)} ${parseTime(lesson.createdAt, 'HH:mm')} · ${classLabel(lesson.className)}`),
|
||||
renderProblems(lesson),
|
||||
h(
|
||||
'div',
|
||||
{ class: 'm-meta' },
|
||||
[lesson.createdBy, lesson.language ? LANGUAGE_SHOW_VALUE[lesson.language] : null, `做完 ${renderDone(lesson)}`].filter(Boolean).join(' · '),
|
||||
),
|
||||
h('div', { class: 'm-meta' }, [lesson.createdBy, wayText(lesson), `做完 ${renderDone(lesson)}`].filter(Boolean).join(' · ')),
|
||||
renderActions(lesson),
|
||||
])
|
||||
}
|
||||
@@ -152,7 +153,7 @@ const desktopColumns: DataTableColumn<AdminLesson>[] = [
|
||||
{ title: '布置', key: 'createdAt', width: 70, render: (row) => parseTime(row.createdAt, 'HH:mm') },
|
||||
{ title: '班级', key: 'className', width: 130, render: (row) => classLabel(row.className) },
|
||||
{ title: '老师', key: 'createdBy', width: 90 },
|
||||
{ title: '语言', key: 'language', width: 80, render: (row) => (row.language ? LANGUAGE_SHOW_VALUE[row.language] : '—') },
|
||||
{ title: '做什么', key: 'language', width: 120, render: (row) => wayText(row) || '—' },
|
||||
{ title: '题目', key: 'problems', width: 300, render: renderProblems },
|
||||
{ title: '做完 / 全班', key: 'doneCount', width: 100, render: renderDone },
|
||||
{ title: '', key: 'actions', render: renderActions },
|
||||
|
||||
Reference in new issue
Block a user