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>
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in new issue
Block a user