feat(自学): 自学重做——首页课程地图、读一课按项目分目录、代码块就地运行、学完给题做
Deploy / deploy (push) Canceled after 0s

- 顶栏「自学」进新的自学首页 /learn:接着学(按服务端记录,不再串到上一个学生)+ 按项目分组的课程地图
- 读一课:左边目录按项目折叠,正文加宽,右边本课大纲带练一练标记;去掉了不能运行的示例代码栏
- 正文里的代码块能改能运行,报错用题目页那套中文解释;读输入的代码出输入框
- 课末:练一练做到几道 → 学完了 → 老师挑的几道题(必会标出来)→ 下一课
- 练一练统一成绿色提交、结果一行字;手机版目录从底部弹出
- 后台:教程列表按项目分组拖动排序,编辑页左写右看、练一练插到光标处、挑相关题;
  自学情况改成方块格 + 还没打开过的名单

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
xuyueandClaude Opus 5.5 committed 2026-10-12 09:40:34 +08:00
1 parent 11194543a3
commit 845e41c060
43 files changed
+4675 -1294

No files matched your search

@@ -1,17 +1,44 @@
<template>
<MdEditor :theme="isDark ? 'dark' : 'light'" v-model="modelValue" @onUploadImg="onUploadImg" />
<MdEditor
ref="editor"
:theme="isDark ? 'dark' : 'light'"
v-model="modelValue"
:preview="preview"
:style="height ? { height } : undefined"
@onUploadImg="onUploadImg"
/>
</template>
<script setup lang="ts">
import { MdEditor } from "md-editor-v3"
import { MdEditor, type ExposeParam } from "md-editor-v3"
import "md-editor-v3/lib/style.css"
import { uploadImage } from "../../admin/api"
/**
* `preview` 关掉自带的预览:教程编辑页右边要用学生端同一套组件预览(练一练、能运行的
* 代码块),md-editor 自己那份预览认不出 `[[exercise:N]]`。
*/
const { preview = true, height } = defineProps<{ preview?: boolean; height?: string }>()
const isDark = useDark()
const editor = useTemplateRef<ExposeParam>("editor")
const modelValue = defineModel<string>("value")
const message = useMessage()
/** 在光标处插一段文字(教程编辑页插练一练占位符用),自成一行 */
function insert(text: string) {
editor.value?.insert(() => ({
targetValue: `\n${text}\n`,
select: false,
deviationStart: 0,
deviationEnd: 0,
}))
}
defineExpose({ insert })
const onUploadImg = async (files: File[], callback: (urls: string[]) => void) => {
try {
const res = await Promise.all(