update
Deploy / deploy (push) Canceled after 0s

This commit is contained in:
xuyue committed 2026-09-27 19:36:28 +08:00
1 parent 23844ae301
commit d25b5dbe6d
268 files changed
+3684 -8861

No files matched your search

@@ -42,15 +42,11 @@ function getProgressPercentage() {
// 有选做题时把「必做 N 题」标出来,否则「共 10 道题目」和「9 / 9」对不上
const optionalCount = computed(
() =>
props.problemSet.problemsCount -
(props.problemSet.userProgress?.totalCount ?? 0),
() => props.problemSet.problemsCount - (props.problemSet.userProgress?.totalCount ?? 0),
)
const endTimeText = computed(() =>
props.problemSet.endTime
? parseTime(props.problemSet.endTime, "YYYY-MM-DD HH:mm")
: "",
props.problemSet.endTime ? parseTime(props.problemSet.endTime, "YYYY-MM-DD HH:mm") : "",
)
function handleJoin() {
@@ -62,9 +58,7 @@ function handleJoin() {
<n-card style="margin-bottom: 24px">
<n-flex justify="space-between" align="center">
<n-flex align="center">
<n-tag type="warning" v-if="problemSet.status === 'archived'">
已归档
</n-tag>
<n-tag type="warning" v-if="problemSet.status === 'archived'"> 已归档 </n-tag>
<n-tag :type="getDifficultyTag(problemSet.difficulty).type">
{{ getDifficultyTag(problemSet.difficulty).text }}
</n-tag>
@@ -89,11 +83,7 @@ function handleJoin() {
<!-- 用户徽章显示区域 - 只在已加入且有徽章时显示 -->
<n-flex v-if="isJoined && userBadges.length > 0" align="center">
<n-text>已获徽章</n-text>
<UserBadge
v-for="badge in userBadges"
:key="badge.id"
:badge="badge"
/>
<UserBadge v-for="badge in userBadges" :key="badge.id" :badge="badge" />
</n-flex>
<!-- 完成进度 - 只在已加入时显示 -->
@@ -103,9 +93,7 @@ function handleJoin() {
{{ problemSet.userProgress?.completedCount ?? 0 }} /
{{ problemSet.userProgress?.totalCount ?? 0 }}
</n-text>
<n-text depth="3" v-if="optionalCount > 0">
(另有 {{ optionalCount }} 道选做)
</n-text>
<n-text depth="3" v-if="optionalCount > 0"> (另有 {{ optionalCount }} 道选做) </n-text>
</n-flex>
<n-progress
v-if="isJoined"
@@ -27,10 +27,7 @@ function handleProblemClick(problemId: string) {
<template>
<div>
<n-grid :cols="isDesktop ? 4 : 1" :x-gap="16" :y-gap="16">
<n-grid-item
v-for="(problemSetProblem, index) in problems"
:key="problemSetProblem.id"
>
<n-grid-item v-for="(problemSetProblem, index) in problems" :key="problemSetProblem.id">
<n-card
hoverable
@click="handleProblemClick(problemSetProblem.problem._id)"
@@ -21,9 +21,7 @@ const statistics = ref<{
avgProgress: number
} | null>(null)
const classFilter = ref<string>("")
const completionFilter = ref<"" | "completed" | "in_progress" | "not_started">(
"",
)
const completionFilter = ref<"" | "completed" | "in_progress" | "not_started">("")
const allProblems = ref<Array<{ id: number; _id: string; title: string }>>([])
// 完成度筛选选项
@@ -136,8 +134,7 @@ const progressColumns = [
title: "加入时间",
key: "join_time",
width: 180,
render: (row: ProblemSetProgress) =>
parseTime(row.joinTime, "YYYY-MM-DD HH:mm:ss"),
render: (row: ProblemSetProgress) => parseTime(row.joinTime, "YYYY-MM-DD HH:mm:ss"),
},
{
title: "已完成数量",
@@ -153,12 +150,8 @@ const progressColumns = [
return "全部题目已完成"
}
if (row.progressPercentage > 50 && row.progressPercentage < 100) {
const completedProblemIds = new Set(
row.completedProblems.map((p: any) => p.id),
)
const incompleteProblems = allProblems.value.filter(
(p) => !completedProblemIds.has(p.id),
)
const completedProblemIds = new Set(row.completedProblems.map((p: any) => p.id))
const incompleteProblems = allProblems.value.filter((p) => !completedProblemIds.has(p.id))
return h("div", { style: "max-height: 120px; overflow-y: auto" }, [
h(NFlex, {}, () =>
incompleteProblems.map((problem) =>
@@ -249,10 +242,7 @@ const progressColumns = [
</n-grid-item>
<n-grid-item>
<n-card size="small">
<n-statistic
label="平均进度"
:value="stats.avgProgress.toFixed(0) + '%'"
/>
<n-statistic label="平均进度" :value="stats.avgProgress.toFixed(0) + '%'" />
</n-card>
</n-grid-item>
</n-grid>
+2 -11
View File
@@ -1,16 +1,7 @@
<script setup lang="ts">
import { errorMessage } from "utils/api"
import {
getProblemSetDetail,
getProblemSetProblems,
joinProblemSet,
getUserBadges,
} from "../api"
import type {
ProblemSet,
ProblemSetProblem,
UserBadge as UserBadgeType,
} from "utils/types"
import { getProblemSetDetail, getProblemSetProblems, joinProblemSet, getUserBadges } from "../api"
import type { ProblemSet, ProblemSetProblem, UserBadge as UserBadgeType } from "utils/types"
import { useFireworks } from "../problem/composables/useFireworks"
import ProblemSetHeader from "./components/ProblemSetHeader.vue"
import ProblemSetProblemsList from "./components/ProblemSetProblemsList.vue"
+13 -52
View File
@@ -52,10 +52,7 @@ function goToProblemSet(problemSetId: number) {
router.push(`/problemset/${problemSetId}`)
}
function getConditionText(
conditionType: string,
conditionValue: number,
): string {
function getConditionText(conditionType: string, conditionValue: number): string {
const conditionMap: Record<string, string> = {
all_problems: "完成所有题目",
problem_count: `完成 ${conditionValue} 道题目`,
@@ -97,18 +94,9 @@ watch(() => [query.page, query.limit], listProblemSets)
/>
</n-space>
<n-grid
v-if="problemSets.length > 0"
:cols="isDesktop ? 3 : 1"
:x-gap="16"
:y-gap="16"
>
<n-grid v-if="problemSets.length > 0" :cols="isDesktop ? 3 : 1" :x-gap="16" :y-gap="16">
<n-grid-item v-for="problemSet in problemSets" :key="problemSet.id">
<n-card
hoverable
@click="goToProblemSet(problemSet.id)"
style="cursor: pointer"
>
<n-card hoverable @click="goToProblemSet(problemSet.id)" style="cursor: pointer">
<template #header>
<n-flex justify="space-between" align="center">
<n-text strong>{{ problemSet.title }}</n-text>
@@ -127,36 +115,22 @@ watch(() => [query.page, query.limit], listProblemSets)
<n-flex align="center" style="height: 28px">
<!-- 用户进度显示 -->
<n-progress
v-if="
problemSet.userProgress?.isJoined &&
!problemSet.userProgress?.isCompleted
"
v-if="problemSet.userProgress?.isJoined && !problemSet.userProgress?.isCompleted"
type="line"
:percentage="
Math.round(problemSet.userProgress.progressPercentage)
"
:percentage="Math.round(problemSet.userProgress.progressPercentage)"
:height="4"
:border-radius="2"
style="width: 100px"
:color="
getProgressColor(problemSet.userProgress.progressPercentage)
"
:color="getProgressColor(problemSet.userProgress.progressPercentage)"
/>
<n-tag type="warning" v-if="problemSet.status === 'archived'">
已归档
</n-tag>
<n-tag type="warning" v-if="problemSet.status === 'archived'"> 已归档 </n-tag>
<n-tag
v-if="
problemSet.userProgress?.isJoined &&
!problemSet.userProgress?.isCompleted
"
v-if="problemSet.userProgress?.isJoined && !problemSet.userProgress?.isCompleted"
type="warning"
>
已加入
</n-tag>
<n-tag v-if="problemSet.userProgress?.isCompleted" type="error">
已完成
</n-tag>
<n-tag v-if="problemSet.userProgress?.isCompleted" type="error"> 已完成 </n-tag>
</n-flex>
</n-flex>
@@ -167,11 +141,7 @@ watch(() => [query.page, query.limit], listProblemSets)
{{ parseTime(problemSet.createTime, "YYYY-MM-DD") }}
</n-text>
<n-flex>
<n-tooltip
v-for="badge in problemSet.badges"
:key="badge.id"
trigger="hover"
>
<n-tooltip v-for="badge in problemSet.badges" :key="badge.id" trigger="hover">
<template #trigger>
<n-image
:src="badge.icon"
@@ -183,21 +153,12 @@ watch(() => [query.page, query.limit], listProblemSets)
/>
</template>
<n-flex vertical size="small">
<span style="font-weight: bold">
徽章: {{ badge.name }}
</span>
<span style="font-weight: bold"> 徽章: {{ badge.name }} </span>
<span>
获取条件:
{{
getConditionText(
badge.conditionType,
badge.conditionValue,
)
}}
{{ getConditionText(badge.conditionType, badge.conditionValue) }}
</span>
<n-text type="primary" v-if="badge.isEarned">
✓ 已获得
</n-text>
<n-text type="primary" v-if="badge.isEarned"> ✓ 已获得 </n-text>
</n-flex>
</n-tooltip>
</n-flex>