diff --git a/src/admin/problem/components/AstRulesEditor.vue b/src/admin/problem/components/AstRulesEditor.vue index 01816e8..0277304 100644 --- a/src/admin/problem/components/AstRulesEditor.vue +++ b/src/admin/problem/components/AstRulesEditor.vue @@ -164,12 +164,12 @@ watch(() => props.languages, (langs) => {
- + props.languages, (langs) => { :options="NODE_TARGET_OPTIONS" :value="rule.target" @update:value="(v: string) => updateRule(lang, index, 'target', v)" - style="width: 140px" + style="width: 150px" size="small" filterable /> @@ -186,7 +186,7 @@ watch(() => props.languages, (langs) => { :value="rule.target" @update:value="(v: string) => updateRule(lang, index, 'target', v)" placeholder="函数/方法名" - style="width: 120px" + style="width: 150px" size="small" /> props.languages, (langs) => { :options="OPERATOR_TARGET_OPTIONS" :value="rule.target" @update:value="(v: string) => updateRule(lang, index, 'target', v)" - style="width: 100px" + style="width: 150px" size="small" /> props.languages, (langs) => { :value="rule.min ?? null" @update:value="(v: number | null) => updateRule(lang, index, 'min', v)" placeholder="最少" - style="width: 90px" + style="width: 150px" size="small" :min="0" clearable @@ -212,7 +212,7 @@ watch(() => props.languages, (langs) => { :value="rule.max ?? null" @update:value="(v: number | null) => updateRule(lang, index, 'max', v)" placeholder="最多" - style="width: 90px" + style="width: 150px" size="small" :min="0" clearable @@ -221,7 +221,7 @@ watch(() => props.languages, (langs) => { :value="rule.message" @update:value="(v: string) => updateRule(lang, index, 'message', v)" placeholder="错误提示(选填)" - style="width: 200px" + style="flex: 1" size="small" /> diff --git a/src/admin/problem/detail.vue b/src/admin/problem/detail.vue index 670da84..282dc56 100644 --- a/src/admin/problem/detail.vue +++ b/src/admin/problem/detail.vue @@ -646,10 +646,14 @@ watch( - + + + + + diff --git a/src/oj/problem/components/ProblemContent.vue b/src/oj/problem/components/ProblemContent.vue index 728dcae..0302fce 100644 --- a/src/oj/problem/components/ProblemContent.vue +++ b/src/oj/problem/components/ProblemContent.vue @@ -6,7 +6,7 @@ import { useCodeStore } from "oj/store/code" import { useProblemStore } from "oj/store/problem" import { createTestSubmission } from "utils/judge" import { DIFFICULTY } from "utils/constants" -import { Problem, ProblemStatus } from "utils/types" +import type { Problem, ProblemStatus } from "utils/types" import Copy from "shared/components/Copy.vue" import { useDark } from "@vueuse/core" import { MdPreview } from "md-editor-v3" @@ -85,6 +85,60 @@ const samples = ref( })), ) +const NODE_TARGET_LABELS: Record = { + for_loop: "for 循环", + while_loop: "while 循环", + if_statement: "if 条件", + else_clause: "else 子句", + function_definition: "函数定义", + return: "return 语句", + break: "break 语句", + continue: "continue 语句", + list_comprehension: "列表推导式", + list_literal: "列表", + dict_literal: "字典", + set_literal: "集合", + f_string: "f-string", + try_except: "try-except", + class_definition: "类定义", +} + +type AstRule = { engine: string; target?: string; min?: number; max?: number; message: string } + +function ruleDescription(rule: AstRule): string { + const target = rule.target || "" + const targetLabel = NODE_TARGET_LABELS[target] || target + const range = (min?: number, max?: number) => { + if (min !== undefined && max !== undefined) return `${min}~${max} 次` + if (min !== undefined) return `至少 ${min} 次` + if (max !== undefined) return `至多 ${max} 次` + return "" + } + switch (rule.engine) { + case "must_exist_node": return `必须使用 ${targetLabel}` + case "must_not_exist_node": return `不能使用 ${targetLabel}` + case "count_node": return `${targetLabel} 出现次数 ${range(rule.min, rule.max)}` + case "must_call_function": return `必须调用函数 ${target}` + case "must_not_call_function": return `不能调用函数 ${target}` + case "count_function_call": return `函数 ${target} 调用次数 ${range(rule.min, rule.max)}` + case "must_call_method": return `必须调用方法 ${target}` + case "must_not_call_method": return `不能调用方法 ${target}` + case "must_use_operator": return `必须使用运算符 ${target}` + default: return rule.message || rule.engine + } +} + +function ruleTagType(engine: string): "error" | "success" | "info" { + if (engine.startsWith("must_not")) return "error" + if (engine.startsWith("must")) return "success" + return "info" +} + +const astRulesForDisplay = computed(() => { + if (!problem.value?.ast_rules) return [] + return Object.entries(problem.value.ast_rules).filter(([, rules]) => rules.length > 0) +}) + async function test(sample: Sample, index: number) { samples.value = samples.value.map((sample) => { if (sample.id === index) { @@ -222,6 +276,29 @@ function type(status: ProblemStatus) { />
+ +
+

+ + + 要求 + +

+
+

{{ lang }}

+ + + + + {{ ruleDescription(rule) }} + + {{ rule.message }} + + + +
+
+

例子 {{ index + 1 }}

@@ -338,4 +415,14 @@ function type(status: ProblemStatus) { .status-alert { margin-bottom: 16px; } + +.lang-label { + font-weight: 600; + margin: 8px 0 4px; +} + +.rule-message { + font-size: 13px; + opacity: 0.65; +}