From 1fd9bf67c224dbe30f6f9da33105bffc16a91cd8 Mon Sep 17 00:00:00 2001 From: yuetsh <517252939@qq.com> Date: Mon, 28 Sep 2026 20:04:20 +0800 Subject: [PATCH] =?UTF-8?q?style(=E9=A2=98=E7=9B=AE):=20=E9=A2=98=E7=9B=AE?= =?UTF-8?q?=E9=A1=B5=E7=85=A7=E8=AE=BE=E8=AE=A1=E7=A8=BF=E3=80=8C=E6=9C=BA?= =?UTF-8?q?=E6=88=BF=EF=BC=88=E6=96=B9=E6=A1=88=20B=EF=BC=89=E3=80=8D?= =?UTF-8?q?=E9=87=8D=E6=8E=92=E2=80=94=E2=80=94=E9=A1=B6=E6=BB=A1=E7=9A=84?= =?UTF-8?q?=E4=B8=A4=E6=A0=8F=E3=80=81=E5=B8=A6=E5=BA=95=E8=89=B2=E7=9A=84?= =?UTF-8?q?=E4=B8=8A=E4=B8=8B=E6=96=87=E6=9D=A1=E3=80=81=E4=B8=8B=E5=88=92?= =?UTF-8?q?=E7=BA=BF=E9=A1=B5=E7=AD=BE=E3=80=81=E6=96=B0=E7=9A=84=E7=BB=93?= =?UTF-8?q?=E6=9E=9C=E5=92=8C=E9=A2=98=E9=9D=A2=E6=A0=B7=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 原来实施时只照了设计文档,没对照设计稿,一路套 Naive 现成的分段页签、提示框、单选组, 功能对了、样子差很多。这次逐块对着设计稿的画板改: - 两栏顶满内容区,中间一条 1px 分隔线;上下文条、页签行、工具栏下面各一道分隔线 - 上下文条:课堂浅绿、题单浅蓝、比赛浅黄三种底色;‹ › 是不带边框的箭头;比赛的题号是方角、 做错的是红色 ✕;手机上不摆一排题号,写「这节课 做完 2/5 · 这是第 3 道」配 44px 的箭头 - 「题目 / 结果」是下划线页签,右边「统计 / 点评 / 我的提交」是胶囊按钮 - 抽屉盖住整个左栏(连上下文条、页签行),顶上有自己的「我的提交 / 统计 / 点评」页签,Esc 能关 - 结果页签:三个分段是胶囊,选中的深色实心、带时间(「提交结果 · 10:42」);标题是圆形图标 + 大字 + 灰字(「答案错误 在例子 1 上就错了」),不再套整块彩色提示框;答错的对比三栏并排、 只把不一样的那几个字标红;「题目要求的输出」是一行小字;「让 AI 分析我的代码」是描边按钮; 答对后的「下一题」是浅绿卡片里 44px 的大按钮 - 工具栏:语言、运行例子(描边)、提交(实心,就叫「提交」)靠左,求助、⋯ 推到最右; 交对之后「提交」变成绿色描边;协作条换成设计稿的深蓝 - 题面:标题下「简单 · 还没交过」,流程图过关的加「流程图 A 级」;代码要求压成一行; 小标题不带图标;输入、输出左右两栏;参考流程图是一行可以点开的条;例子表带「例子 1」和「复制」 - 去掉「限时 1 秒」:执行时间、内存对中职学生只会添迷惑(和设计稿不同,用户定的) - 我的提交:一整块带框的列表,结果用彩色文字;展开的代码先露 5 行;题单锁住的几次合成一行 - 错在隐藏测试点时「去自己输入」给的数跳过例子里出现过的 Co-Authored-By: Claude Opus 5.5 --- .../src/oj/problem/components/CollabBar.vue | 68 ++- .../src/oj/problem/components/ContextBar.vue | 312 +++++++--- .../oj/problem/components/EditorToolbar.vue | 80 ++- .../src/oj/problem/components/LessonNext.vue | 121 +++- .../oj/problem/components/ProblemChips.vue | 120 +++- .../oj/problem/components/ProblemContent.vue | 546 +++++++++++------- .../oj/problem/components/ProblemDrawer.vue | 131 ++++- .../oj/problem/components/ProblemEditor.vue | 10 +- .../problem/components/ProblemSubmission.vue | 293 ++++++---- .../oj/problem/components/ResultHeader.vue | 166 ++++++ .../src/oj/problem/components/ResultPane.vue | 78 ++- .../problem/components/SubmissionResult.vue | 147 +++-- .../src/oj/problem/components/SubmitCode.vue | 14 +- .../problem/components/WrongAnswerExplain.vue | 213 +++---- .../problem/components/submitButtonState.ts | 11 +- apps/web/src/oj/problem/detail.vue | 177 ++++-- apps/web/src/oj/problem/utils/plainText.ts | 19 + 17 files changed, 1800 insertions(+), 706 deletions(-) create mode 100644 apps/web/src/oj/problem/components/ResultHeader.vue create mode 100644 apps/web/src/oj/problem/utils/plainText.ts diff --git a/apps/web/src/oj/problem/components/CollabBar.vue b/apps/web/src/oj/problem/components/CollabBar.vue index 3330b0b..9df01fb 100644 --- a/apps/web/src/oj/problem/components/CollabBar.vue +++ b/apps/web/src/oj/problem/components/CollabBar.vue @@ -31,47 +31,85 @@ function openHisSubmissions() { diff --git a/apps/web/src/oj/problem/components/ContextBar.vue b/apps/web/src/oj/problem/components/ContextBar.vue index 424afa0..dc08969 100644 --- a/apps/web/src/oj/problem/components/ContextBar.vue +++ b/apps/web/src/oj/problem/components/ContextBar.vue @@ -7,6 +7,8 @@ import { isFlowchartPass, useFlowchartStore } from "oj/store/flowchart" import { useLessonStore } from "oj/store/lesson" import { useProblemStore } from "oj/store/problem" import { useUserStore } from "shared/store/user" +import { useBreakpoints } from "shared/composables/breakpoints" +import { useThemeVars } from "naive-ui" import type { ProblemSet, ProblemSetProblem } from "utils/types" import { useProblemPageContext } from "../composables/problemPageContext" import ProblemChips, { type ChipItem } from "./ProblemChips.vue" @@ -27,6 +29,20 @@ import ProblemChips, { type ChipItem } from "./ProblemChips.vue" const CHIPS_FIT = 5 const ctx = useProblemPageContext() +const { isMobile } = useBreakpoints() +const theme = useThemeVars() +const isDark = useDark() + +/** + * 三种入口各一种底色(设计稿「上下文条与协作状态」):课堂浅绿、题单浅蓝、比赛浅黄。 + * 字色在暗色下换成浅一档的,深绿、深蓝、深黄放在暗底上看不清 + */ +const tone = computed(() => ({ + lessonText: isDark.value ? theme.value.primaryColor : theme.value.primaryColorPressed, + setText: isDark.value ? "#8fb4ee" : "#1d4f9c", + setBar: isDark.value ? "#6f9be0" : "#2f6bc4", + contestText: isDark.value ? "#f2c97d" : "#8a5200", +})) const userStore = useUserStore() const { problem } = storeToRefs(useProblemStore()) const currentId = computed(() => problem.value?._id ?? "") @@ -85,6 +101,7 @@ const lesson = computed(() => { chips, done: list.filter((item) => item.myStatus === "accepted").length, total: list.length, + position: index + 1, previous: chips[index - 1]?.to ?? null, next: chips[index + 1]?.to ?? null, } @@ -211,115 +228,274 @@ onSolvedHere(() => { diff --git a/apps/web/src/oj/problem/components/EditorToolbar.vue b/apps/web/src/oj/problem/components/EditorToolbar.vue index 6179c03..ed7a330 100644 --- a/apps/web/src/oj/problem/components/EditorToolbar.vue +++ b/apps/web/src/oj/problem/components/EditorToolbar.vue @@ -10,7 +10,7 @@ import { useUserStore } from "shared/store/user" import storage from "utils/storage" import type { LANGUAGE } from "utils/types" import { Icon } from "@iconify/vue" -import { NFlex } from "naive-ui" +import { NFlex, useThemeVars } from "naive-ui" import SubmitCode from "./SubmitCode.vue" import { useProblemPageContext } from "../composables/problemPageContext" import { statisticsOpen, useEditorMenu } from "../composables/editorMenu" @@ -44,6 +44,7 @@ const mode = computed({ }) const { isDesktop } = useBreakpoints() +const theme = useThemeVars() /** * 「运行例子」:用题目里的例子试跑(Judge0),结果在左栏「结果」页签。顶替原来题面里 @@ -119,8 +120,8 @@ const toggleHelp = () => { * 所以次要的按钮收进「更多」、「写代码 / 画流程图」缩短一点(设计文档 5.4)。语言下拉不收: * 窄于 120px 时图标和「Python」会被挤成两行 */ -const toolbarRef = useTemplateRef<{ $el: HTMLElement }>("toolbarRef") -const { width: toolbarWidth } = useElementSize(() => toolbarRef.value?.$el) +const toolbarRef = useTemplateRef("toolbarRef") +const { width: toolbarWidth } = useElementSize(toolbarRef) const narrow = computed(() => isDesktop.value && toolbarWidth.value > 0 && toolbarWidth.value < 600) /** 「课堂统计」常驻在工具栏上:桌面、而且放得下 */ const statisticsInline = computed(() => isDesktop.value && !narrow.value) @@ -152,7 +153,8 @@ const changeLanguage = (v: LANGUAGE) => { + + diff --git a/apps/web/src/oj/problem/components/LessonNext.vue b/apps/web/src/oj/problem/components/LessonNext.vue index 0b328e0..c3a903e 100644 --- a/apps/web/src/oj/problem/components/LessonNext.vue +++ b/apps/web/src/oj/problem/components/LessonNext.vue @@ -1,4 +1,5 @@ diff --git a/apps/web/src/oj/problem/components/ProblemChips.vue b/apps/web/src/oj/problem/components/ProblemChips.vue index 8888d99..3f6f7d5 100644 --- a/apps/web/src/oj/problem/components/ProblemChips.vue +++ b/apps/web/src/oj/problem/components/ProblemChips.vue @@ -5,8 +5,9 @@ import type { RouteLocationRaw } from "vue-router" /** * 上下文条里的一排题号(课堂、比赛共用)。只放题号,题目名在鼠标停上去时给。 * - * 状态用图标区分,不只靠颜色:✓ 做完(实心绿)/ ! 做过没对(橙)/ 灰底 没做;当前题描边。 - * 一节课一般 5 道以内,一行放得下;多了(比赛、老师一次布置了一长串)就横向滚动, + * 状态用图标区分,不只靠颜色:✓ 做完(实心绿)/ 做过没对(课堂是橙色 !,比赛是红色 ✕)/ + * 灰底 没做;当前题描边,做完了的当前题实心绿再套一圈。课堂是圆角胶囊、比赛是方角 + * (设计稿「上下文条与协作状态」)。一节课一般 5 道以内,一行放得下;多了就横向滚动, * 当前题保持在视野里。 */ export interface ChipItem { @@ -19,17 +20,22 @@ export interface ChipItem { const props = defineProps<{ items: ChipItem[] current: string + variant: "lesson" | "contest" }>() const theme = useThemeVars() -/** - * 「做完」的实心绿上用什么字色。暗色主题的成功色是浅薄荷绿,白字几乎看不见 —— - * 和 Naive 自己的主按钮一样,暗色下换深色字 - */ +/** 「做完」的实心绿上用什么字色:暗色主题的成功色是浅薄荷绿,白字几乎看不见 */ const isDark = useDark() const doneText = computed(() => (isDark.value ? "rgba(0, 0, 0, 0.85)" : "#fff")) -const STATUS_TEXT = { done: "做完了", tried: "做过,还没对", none: "还没做" } as const +const STATUS_TEXT = computed( + () => + ({ + done: "做完了", + tried: props.variant === "contest" ? "交过,还没对" : "做过,还没对", + none: "还没做", + }) as const, +) const isCurrent = (item: ChipItem) => item.displayId.toLowerCase() === props.current.toLowerCase() @@ -49,7 +55,8 @@ watch(