8
package-lock.json
generated
8
package-lock.json
generated
@@ -28,7 +28,7 @@
|
|||||||
"date-fns": "^4.1.0",
|
"date-fns": "^4.1.0",
|
||||||
"fflate": "^0.8.2",
|
"fflate": "^0.8.2",
|
||||||
"highlight.js": "^11.11.1",
|
"highlight.js": "^11.11.1",
|
||||||
"md-editor-v3": "^6.2.1",
|
"md-editor-v3": "^6.3.0",
|
||||||
"mermaid": "^11.12.2",
|
"mermaid": "^11.12.2",
|
||||||
"naive-ui": "^2.43.2",
|
"naive-ui": "^2.43.2",
|
||||||
"nanoid": "^5.1.6",
|
"nanoid": "^5.1.6",
|
||||||
@@ -4530,9 +4530,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/md-editor-v3": {
|
"node_modules/md-editor-v3": {
|
||||||
"version": "6.2.1",
|
"version": "6.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/md-editor-v3/-/md-editor-v3-6.2.1.tgz",
|
"resolved": "https://registry.npmmirror.com/md-editor-v3/-/md-editor-v3-6.3.0.tgz",
|
||||||
"integrity": "sha512-/9pmLG9qJ1/NmxE5e4aNmGSxWJh4vLVAd0zQ9w52YXe8I7b+xjXAQj7GRZVMxRhB9tXTjY7THiqwrNUy+9r0hQ==",
|
"integrity": "sha512-KvrxFA7YZbrTQ5JH6nTPNnAhfDVAV1uOVUGziyds0+wyCeWL5lbuTXjFmL8/2sILPw2v0VPxCEw7SMTlUQmvzg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/autocomplete": "^6.18.7",
|
"@codemirror/autocomplete": "^6.18.7",
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
"version": "1.8.0",
|
"version": "1.8.0",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "rsbuild dev",
|
"start": "rsbuild dev --env-mode=production",
|
||||||
"build": "rsbuild build",
|
"build": "rsbuild build",
|
||||||
"build:staging": "rsbuild build --env-mode=staging",
|
"build:staging": "rsbuild build --env-mode=staging",
|
||||||
"build:test": "rsbuild build --env-mode=test",
|
"build:test": "rsbuild build --env-mode=test",
|
||||||
@@ -30,7 +30,7 @@
|
|||||||
"date-fns": "^4.1.0",
|
"date-fns": "^4.1.0",
|
||||||
"fflate": "^0.8.2",
|
"fflate": "^0.8.2",
|
||||||
"highlight.js": "^11.11.1",
|
"highlight.js": "^11.11.1",
|
||||||
"md-editor-v3": "^6.2.1",
|
"md-editor-v3": "^6.3.0",
|
||||||
"mermaid": "^11.12.2",
|
"mermaid": "^11.12.2",
|
||||||
"naive-ui": "^2.43.2",
|
"naive-ui": "^2.43.2",
|
||||||
"nanoid": "^5.1.6",
|
"nanoid": "^5.1.6",
|
||||||
|
|||||||
@@ -1,3 +1,11 @@
|
|||||||
body {
|
body {
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.md-editor-dark {
|
||||||
|
--md-bk-color: var(--n-body-color) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.md-editor-dark div.vuepress-theme {
|
||||||
|
--md-theme-color: var(--n-text-color) !important;
|
||||||
|
}
|
||||||
@@ -7,6 +7,9 @@ import { useProblemStore } from "oj/store/problem"
|
|||||||
import { createTestSubmission } from "utils/judge"
|
import { createTestSubmission } from "utils/judge"
|
||||||
import { Problem, ProblemStatus } from "utils/types"
|
import { Problem, ProblemStatus } from "utils/types"
|
||||||
import Copy from "shared/components/Copy.vue"
|
import Copy from "shared/components/Copy.vue"
|
||||||
|
import { useDark } from "@vueuse/core"
|
||||||
|
import { MdPreview } from "md-editor-v3"
|
||||||
|
import "md-editor-v3/lib/preview.css"
|
||||||
|
|
||||||
type Sample = Problem["samples"][number] & {
|
type Sample = Problem["samples"][number] & {
|
||||||
id: number
|
id: number
|
||||||
@@ -17,7 +20,7 @@ type Sample = Problem["samples"][number] & {
|
|||||||
|
|
||||||
const theme = useThemeVars()
|
const theme = useThemeVars()
|
||||||
const style = computed(() => "color: " + theme.value.primaryColor)
|
const style = computed(() => "color: " + theme.value.primaryColor)
|
||||||
|
const isDark = useDark()
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const codeStore = useCodeStore()
|
const codeStore = useCodeStore()
|
||||||
const problemStore = useProblemStore()
|
const problemStore = useProblemStore()
|
||||||
@@ -25,10 +28,6 @@ const { problem } = storeToRefs(problemStore)
|
|||||||
|
|
||||||
const problemSetId = computed(() => route.params.problemSetId)
|
const problemSetId = computed(() => route.params.problemSetId)
|
||||||
|
|
||||||
// 判断用户是否尝试过但未通过
|
|
||||||
// my_status === 0: 已通过
|
|
||||||
// my_status !== 0 && my_status !== null: 尝试过但未通过
|
|
||||||
// my_status === null: 从未尝试
|
|
||||||
const hasTriedButNotPassed = computed(() => {
|
const hasTriedButNotPassed = computed(() => {
|
||||||
return (
|
return (
|
||||||
problem.value?.my_status !== undefined &&
|
problem.value?.my_status !== undefined &&
|
||||||
@@ -108,7 +107,7 @@ function type(status: ProblemStatus) {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div v-if="problem" class="problemContent">
|
<div v-if="problem">
|
||||||
<template v-if="!problemSetId">
|
<template v-if="!problemSetId">
|
||||||
<!-- 已通过 -->
|
<!-- 已通过 -->
|
||||||
<n-alert
|
<n-alert
|
||||||
@@ -140,7 +139,11 @@ function type(status: ProblemStatus) {
|
|||||||
描述
|
描述
|
||||||
</n-flex>
|
</n-flex>
|
||||||
</p>
|
</p>
|
||||||
<div class="content" v-html="problem.description"></div>
|
<MdPreview
|
||||||
|
preview-theme="vuepress"
|
||||||
|
:model-value="problem.description"
|
||||||
|
:theme="isDark ? 'dark' : 'light'"
|
||||||
|
/>
|
||||||
|
|
||||||
<p class="title" :style="style">
|
<p class="title" :style="style">
|
||||||
<n-flex align="center">
|
<n-flex align="center">
|
||||||
@@ -148,7 +151,11 @@ function type(status: ProblemStatus) {
|
|||||||
输入
|
输入
|
||||||
</n-flex>
|
</n-flex>
|
||||||
</p>
|
</p>
|
||||||
<div class="content" v-html="problem.input_description"></div>
|
<MdPreview
|
||||||
|
preview-theme="vuepress"
|
||||||
|
:model-value="problem.input_description"
|
||||||
|
:theme="isDark ? 'dark' : 'light'"
|
||||||
|
/>
|
||||||
|
|
||||||
<p class="title" :style="style">
|
<p class="title" :style="style">
|
||||||
<n-flex align="center">
|
<n-flex align="center">
|
||||||
@@ -156,7 +163,11 @@ function type(status: ProblemStatus) {
|
|||||||
输出
|
输出
|
||||||
</n-flex>
|
</n-flex>
|
||||||
</p>
|
</p>
|
||||||
<div class="content" v-html="problem.output_description"></div>
|
<MdPreview
|
||||||
|
preview-theme="vuepress"
|
||||||
|
:model-value="problem.output_description"
|
||||||
|
:theme="isDark ? 'dark' : 'light'"
|
||||||
|
/>
|
||||||
|
|
||||||
<div v-if="problem.hint">
|
<div v-if="problem.hint">
|
||||||
<p class="title" :style="style">
|
<p class="title" :style="style">
|
||||||
@@ -165,7 +176,11 @@ function type(status: ProblemStatus) {
|
|||||||
提示
|
提示
|
||||||
</n-flex>
|
</n-flex>
|
||||||
</p>
|
</p>
|
||||||
<div class="content" v-html="problem.hint"></div>
|
<MdPreview
|
||||||
|
preview-theme="preview"
|
||||||
|
:model-value="problem.hint"
|
||||||
|
:theme="isDark ? 'dark' : 'light'"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-for="(sample, index) of samples" :key="index">
|
<div v-for="(sample, index) of samples" :key="index">
|
||||||
@@ -210,25 +225,16 @@ function type(status: ProblemStatus) {
|
|||||||
|
|
||||||
<div v-if="problem.source">
|
<div v-if="problem.source">
|
||||||
<p class="title" :style="style">来源</p>
|
<p class="title" :style="style">来源</p>
|
||||||
<div class="content" v-html="problem.source"></div>
|
<MdPreview
|
||||||
|
preview-theme="vuepress"
|
||||||
|
:model-value="problem.source"
|
||||||
|
:theme="isDark ? 'dark' : 'light'"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.problemContent {
|
|
||||||
--border-color-light: rgb(239, 239, 245);
|
|
||||||
--bg-code-light: rgb(250, 250, 252);
|
|
||||||
--bg-code-dark: rgb(24, 24, 28);
|
|
||||||
--bg-table-light: rgba(250, 250, 252, 1);
|
|
||||||
--bg-table-dark: rgba(38, 38, 42, 1);
|
|
||||||
--border-color-dark: rgba(255, 255, 255, 0.09);
|
|
||||||
--blockquote-color: #7b7b7b;
|
|
||||||
--blockquote-border: #bbbec4;
|
|
||||||
--link-color: #18a058;
|
|
||||||
--transition: 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.problemTitle {
|
.problemTitle {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
@@ -247,106 +253,4 @@ function type(status: ProblemStatus) {
|
|||||||
.status-alert {
|
.status-alert {
|
||||||
margin-bottom: 16px;
|
margin-bottom: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.content {
|
|
||||||
font-size: 16px;
|
|
||||||
line-height: 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 针对 v-html 渲染内容的深度样式 */
|
|
||||||
.content :deep(p) {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.content :deep(blockquote) {
|
|
||||||
border-left: 3px solid var(--blockquote-border);
|
|
||||||
padding-left: 10px;
|
|
||||||
margin: 10px 0;
|
|
||||||
color: var(--blockquote-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.content :deep(pre) {
|
|
||||||
width: 100%;
|
|
||||||
background-color: var(--bg-code-light);
|
|
||||||
border: 1px solid var(--border-color-light);
|
|
||||||
word-break: break-word;
|
|
||||||
box-sizing: border-box;
|
|
||||||
transition:
|
|
||||||
background-color var(--transition),
|
|
||||||
border-color var(--transition);
|
|
||||||
}
|
|
||||||
|
|
||||||
.content :deep(pre code) {
|
|
||||||
font-family: "Monaco", monospace;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dark .content :deep(pre) {
|
|
||||||
background-color: var(--bg-code-dark);
|
|
||||||
border-color: var(--border-color-dark);
|
|
||||||
}
|
|
||||||
|
|
||||||
.content :deep(table) {
|
|
||||||
width: 100%;
|
|
||||||
border-spacing: 0;
|
|
||||||
border: 1px solid var(--border-color-light);
|
|
||||||
transition:
|
|
||||||
background-color var(--transition),
|
|
||||||
border-color var(--transition);
|
|
||||||
}
|
|
||||||
|
|
||||||
.content :deep(table th) {
|
|
||||||
background-color: var(--bg-table-light);
|
|
||||||
padding: 8px;
|
|
||||||
transition:
|
|
||||||
background-color var(--transition),
|
|
||||||
border-color var(--transition);
|
|
||||||
}
|
|
||||||
|
|
||||||
.dark .content :deep(table th) {
|
|
||||||
background-color: var(--bg-table-dark);
|
|
||||||
}
|
|
||||||
|
|
||||||
.content :deep(table td) {
|
|
||||||
padding: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.content :deep(table td),
|
|
||||||
.content :deep(table th) {
|
|
||||||
border-right: 1px solid var(--border-color-light);
|
|
||||||
border-bottom: 1px solid var(--border-color-light);
|
|
||||||
}
|
|
||||||
|
|
||||||
.content :deep(table th:last-child),
|
|
||||||
.content :deep(table td:last-child) {
|
|
||||||
border-right: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.content :deep(table tr:last-child td) {
|
|
||||||
border-bottom: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.content :deep(p code) {
|
|
||||||
font-size: 90%;
|
|
||||||
padding: 2px 5px;
|
|
||||||
margin: 0 4px;
|
|
||||||
background-color: rgba(27, 31, 35, 0.05);
|
|
||||||
border-radius: 3px;
|
|
||||||
line-height: 1.5;
|
|
||||||
font-family: "Monaco", monospace;
|
|
||||||
}
|
|
||||||
|
|
||||||
.content :deep(img) {
|
|
||||||
max-width: 100%;
|
|
||||||
height: auto !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.content :deep(a) {
|
|
||||||
color: var(--link-color);
|
|
||||||
text-decoration: none;
|
|
||||||
transition: opacity var(--transition);
|
|
||||||
}
|
|
||||||
|
|
||||||
.content :deep(a:hover) {
|
|
||||||
opacity: 0.8;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
Reference in New Issue
Block a user