From 9cc7f0f60c43183a31fa9375678c630af74310e3 Mon Sep 17 00:00:00 2001 From: yuetsh <517252939@qq.com> Date: Fri, 9 Oct 2026 13:06:43 +0800 Subject: [PATCH] =?UTF-8?q?fix(=E9=A2=98=E7=9B=AE=E5=88=97=E8=A1=A8):=20?= =?UTF-8?q?=E5=B7=A6=E8=BE=B9=E6=8D=A2=E4=BA=86=E7=9F=A5=E8=AF=86=E7=82=B9?= =?UTF-8?q?=EF=BC=8C=E3=80=8C=E5=85=A8=E9=83=A8=E7=B1=BB=E5=9E=8B=E3=80=8D?= =?UTF-8?q?=E4=B8=8B=E6=8B=89=E9=87=8C=E8=BF=98=E6=98=AF=E5=85=A8=E7=AB=99?= =?UTF-8?q?=E7=9A=84=2013=20/=2013=20/=2014=20=E9=81=93=EF=BC=8C=E7=9C=8B?= =?UTF-8?q?=E7=9D=80=E5=83=8F=E6=B2=A1=E7=94=9F=E6=95=88=E2=80=94=E2=80=94?= =?UTF-8?q?=E9=A2=98=E6=95=B0=E8=B7=9F=E7=9D=80=E5=BD=93=E5=89=8D=E7=9F=A5?= =?UTF-8?q?=E8=AF=86=E7=82=B9=E5=92=8C=E7=AD=9B=E9=80=89=E8=B5=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 「全部类型」本身也带上题数。手机「筛选」里的类型下拉同样带数。 Co-Authored-By: Claude Opus 5.5 --- apps/web/src/oj/problem/list.vue | 58 +++++++++++++++++++++++++++----- 1 file changed, 49 insertions(+), 9 deletions(-) diff --git a/apps/web/src/oj/problem/list.vue b/apps/web/src/oj/problem/list.vue index c95b933..92bca02 100644 --- a/apps/web/src/oj/problem/list.vue +++ b/apps/web/src/oj/problem/list.vue @@ -202,6 +202,7 @@ async function loadAuthors(show: boolean) { // ---- 类型 ---- const showTypeMenu = ref(false) +const [showMobileFilters, toggleMobileFilters] = useToggle(false) // 弹层被传送到 body 下面,样式里的 v-bind 变量挂在页面根上、够不着它,主题色只能就地给 const menuVars = computed(() => ({ "--menu-bg": theme.value.popoverColor, @@ -213,13 +214,47 @@ const menuVars = computed(() => ({ "--menu-check": theme.value.successColor, })) // 下拉里每类后面的题数:一共三十几道,第一次打开时数一下就行 -const typeCounts = ref>>({}) -watch(showTypeMenu, async (open) => { - if (!open || Object.keys(typeCounts.value).length) return - const counts = await Promise.all(TYPES.map((type) => getProblemList(0, 1, { type }))) - typeCounts.value = Object.fromEntries(TYPES.map((type, i) => [type, counts[i]!.total])) +// 下拉里每类后面的题数,跟着左栏的知识点和其它筛选走(类型本身除外): +// 选了「条件判断」就说「条件判断」里有几道画流程图的题,不然一直是全站那个固定数,看着像没生效。 +// 只在下拉打开时数,条件没变就不重数 +type Counts = Partial> +const typeCounts = ref({}) +let countedFor = "" +const countFilters = computed(() => ({ + keyword: query.keyword, + tag: query.tag, + difficulty: query.difficulty, + author: query.author, + undone: undoneOn.value ? "1" : "", +})) +async function refreshTypeCounts() { + const key = JSON.stringify(countFilters.value) + if (key === countedFor) return + countedFor = key + const kinds = ["all", ...TYPES] as const + const results = await Promise.all( + kinds.map((kind) => + getProblemList(0, 1, { ...countFilters.value, type: kind === "all" ? "" : kind }), + ), + ) + // 数的过程中条件又变了:这一份已经过时,留给下一次 + if (key !== JSON.stringify(countFilters.value)) return + typeCounts.value = Object.fromEntries(kinds.map((kind, i) => [kind, results[i]!.total])) +} +watch([showTypeMenu, () => showMobileFilters.value, countFilters], () => { + if (showTypeMenu.value || showMobileFilters.value) refreshTypeCounts() }) +const mobileTypeOptions = computed(() => + TYPES.map((kind) => ({ + label: + typeCounts.value[kind] === undefined + ? PROBLEM_TYPE_LABEL[kind] + : `${PROBLEM_TYPE_LABEL[kind]}(${typeCounts.value[kind]} 道)`, + value: kind, + })), +) + function pickType(value: string) { query.type = value showTypeMenu.value = false @@ -272,8 +307,6 @@ function difficultyStyle(row: ProblemRow) { return { color: t.color, background: t.background } } -const [showMobileFilters, toggleMobileFilters] = useToggle(false) - // 手机上知识点横着滑:带着 ?tag= 进来、或者点了靠后的知识点,把它滑到看得见的地方 const chipsRef = ref(null) watch( @@ -367,7 +400,14 @@ const gridColumns = computed(() =>