From 98d8099b5d5ea4ef16f354359f0ce96453a791db Mon Sep 17 00:00:00 2001
From: yuetsh <517252939@qq.com>
Date: Mon, 16 Mar 2026 18:23:31 +0800
Subject: [PATCH] fix
---
src/components/Preview.vue | 6 +-
src/components/Tutorial.vue | 144 +++++++++++++++++-------------------
src/pages/Submissions.vue | 54 +++++++-------
3 files changed, 98 insertions(+), 106 deletions(-)
diff --git a/src/components/Preview.vue b/src/components/Preview.vue
index ce9fe5a..2504383 100644
--- a/src/components/Preview.vue
+++ b/src/components/Preview.vue
@@ -5,15 +5,15 @@
下载
全屏
清空
- 查看代码
+ 代码
复制链接
- 查看代码
+ 代码
- 手动打分
+ 打分
diff --git a/src/components/Tutorial.vue b/src/components/Tutorial.vue
index da66fa9..0f8ddee 100644
--- a/src/components/Tutorial.vue
+++ b/src/components/Tutorial.vue
@@ -11,6 +11,27 @@ import { step } from "../store/tutorial"
import { taskId } from "../store/task"
import { useRouter } from "vue-router"
+marked.use({
+ renderer: {
+ code({ text, lang }) {
+ const language = lang?.toLowerCase() ?? "html"
+ return `
+
+
${language.toUpperCase()}
+
+
+
+
+
+
${text}
+
`
+ },
+ link({ href, text }) {
+ return `${text}`
+ },
+ },
+})
+
const router = useRouter()
const tutorialIds = ref([])
const content = ref("")
@@ -28,12 +49,12 @@ const nextDisabled = () => {
function prev() {
const i = tutorialIds.value.indexOf(step.value)
- step.value = tutorialIds.value[i - 1]
+ step.value = tutorialIds.value[i - 1] as number
}
function next() {
const i = tutorialIds.value.indexOf(step.value)
- step.value = tutorialIds.value[i + 1]
+ step.value = tutorialIds.value[i + 1] as number
}
defineExpose({ tutorialIds, prevDisabled, nextDisabled, prev, next })
@@ -44,91 +65,43 @@ async function prepare() {
content.value = "暂无教程"
}
if (!tutorialIds.value.includes(step.value)) {
- step.value = tutorialIds.value[0]
+ step.value = tutorialIds.value[0] as number
}
}
-async function getContent() {
+async function render() {
const data = await Tutorial.get(step.value)
taskId.value = data.task_ptr
const merged = `# #${data.display} ${data.title}\n${data.content}`
content.value = await marked.parse(merged, { async: true })
}
-function addButton() {
- const existing = $content.value?.querySelectorAll(".codeblock-action") ?? []
- for (const el of existing) el.remove()
+function flash(btn: HTMLButtonElement, done: string, original: string) {
+ btn.textContent = done
+ setTimeout(() => {
+ btn.textContent = original
+ }, 1000)
+}
- const action = document.createElement("div")
- action.className = "codeblock-action"
- const pres = $content.value?.querySelectorAll("pre") ?? []
- for (const pre of pres) {
- let timer = 0
- let copyTimer = 0
- const actions = action.cloneNode() as HTMLDivElement
- pre.insertBefore(actions, pre.children[0])
- const $code = pre.childNodes[1] as HTMLPreElement
- const match = $code.className.match(/-(.*)/)
- let lang = "html"
- if (match) lang = match[1].toLowerCase()
+function setupCodeActions() {
+ $content.value?.addEventListener("click", (e: MouseEvent) => {
+ const btn = (e.target as HTMLElement).closest("[data-action]")
+ if (!btn) return
+ const wrapper = btn.closest("[data-lang]")!
+ const lang = wrapper.dataset.lang ?? "html"
+ const code = wrapper.querySelector("code")?.textContent ?? ""
- const langSpan = document.createElement("span")
- langSpan.className = "lang"
- langSpan.textContent = lang.toUpperCase()
-
- const btnGroup = document.createElement("div")
- btnGroup.className = "btn-group"
-
- const copyBtn = document.createElement("button")
- copyBtn.className = "action-btn"
- copyBtn.textContent = "复制"
-
- const replaceBtn = document.createElement("button")
- replaceBtn.className = "action-btn"
- replaceBtn.textContent = "替换"
-
- btnGroup.appendChild(copyBtn)
- btnGroup.appendChild(replaceBtn)
-
- actions.appendChild(langSpan)
- actions.appendChild(btnGroup)
-
- copyBtn.onclick = () => {
- const content = pre.children[1].textContent
- copyFn(content ?? "")
- copyBtn.textContent = "已复制"
- clearTimeout(copyTimer)
- copyTimer = setTimeout(() => {
- copyBtn.textContent = "复制"
- }, 1000)
- }
-
- replaceBtn.onclick = () => {
+ if (btn.dataset.action === "copy") {
+ copyFn(code)
+ flash(btn, "已复制", "复制")
+ } else if (btn.dataset.action === "replace") {
tab.value = lang
- const content = pre.children[1].textContent
- if (lang === "html") html.value = content
- if (lang === "css") css.value = content
- if (lang === "js") js.value = content
- replaceBtn.textContent = "已替换"
- clearTimeout(timer)
- timer = setTimeout(() => {
- replaceBtn.textContent = "替换"
- }, 1000)
+ if (lang === "html") html.value = code
+ if (lang === "css") css.value = code
+ if (lang === "js") js.value = code
+ flash(btn, "已替换", "替换")
}
- }
-}
-
-function modifyLink() {
- const links = $content.value?.querySelectorAll("a") ?? []
- for (const link of links) {
- link.target = "_blank"
- }
-}
-
-async function render() {
- await getContent()
- addButton()
- modifyLink()
+ })
}
async function init() {
@@ -136,7 +109,10 @@ async function init() {
render()
}
-onMounted(init)
+onMounted(() => {
+ setupCodeActions()
+ init()
+})
watch(step, (v) => {
router.push({ name: "home-tutorial", params: { display: v } })
render()
@@ -160,8 +136,24 @@ watch(step, (v) => {
font-family: Monaco;
}
-.codeblock-action {
+.markdown-body .codeblock-wrapper {
+ padding: 1rem;
+ background-color: #f6f8fa;
+ border-radius: 6px;
margin-bottom: 1rem;
+ overflow: auto;
+}
+
+.markdown-body .codeblock-wrapper pre {
+ padding: 0;
+ background-color: transparent;
+ border-radius: 0;
+ margin-bottom: 0;
+ overflow: visible;
+}
+
+.codeblock-action {
+ margin-bottom: 0.5rem;
font-family:
v-sans,
system-ui,
diff --git a/src/pages/Submissions.vue b/src/pages/Submissions.vue
index 29483cc..83afa14 100644
--- a/src/pages/Submissions.vue
+++ b/src/pages/Submissions.vue
@@ -1,7 +1,7 @@
-
-
-
+
+
+
goHome($router, taskTab, step)">
返回首页
@@ -43,19 +43,21 @@
:row-class-name="rowClassName"
>
-
-
-
-
-
+
+
+
+
+
@@ -304,19 +306,16 @@ const columns: DataTableColumn[] = [
render: (submission) => h(TaskTitle, { submission }),
},
{
- title: "我打的分",
- key: "my_score",
- render: (row) => {
- if (row.my_score > 0) return row.my_score
- else return "-"
- },
- },
- {
- title: "平均得分",
+ title: "得分",
key: "score",
+ width: 80,
render: (row) => {
- if (row.score > 0) return row.score.toFixed(2)
- else return "-"
+ const myScore = row.my_score > 0 ? String(row.my_score) : "-"
+ const avgScore = row.score > 0 ? row.score.toFixed(2) : "-"
+ return h("div", { style: { display: "flex", gap: "6px", alignItems: "baseline" } }, [
+ h("span", avgScore),
+ h("span", { style: { fontSize: "11px", color: "#999" } }, myScore),
+ ])
},
},
{
@@ -420,6 +419,7 @@ onUnmounted(() => {
padding: 10px;
box-sizing: border-box;
height: calc(100% - 43px);
+ width: 100%;
}
:deep(.row-active td) {