Files
lpt-fe/src/components/Review.vue
T

211 lines
4.8 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script setup lang="ts">
import { computed, onMounted, ref } from "vue";
import { useRouter } from "vue-router";
import { ElMessage } from "element-plus";
import {
getReviewTaskStats,
getTaskReview,
type ReviewFeedItem,
type ReviewTaskStats,
} from "@/api/review";
const router = useRouter();
const loading = ref(false);
const openingTaskNum = ref("");
const tasks = ref<ReviewTaskStats[]>([]);
const summary = computed(() => ({
totalTasks: tasks.value.length,
totalReports: tasks.value.reduce((acc, item) => acc + Number(item.reportCount || 0), 0),
totalFragments: tasks.value.reduce((acc, item) => acc + Number(item.fragmentCount || 0), 0),
}));
const formatEffectiveTime = (seconds: number | string): string => {
const s = Number(seconds);
if (!s || s <= 0) return "0分钟";
const hours = Math.floor(s / 3600);
const minutes = Math.floor((s % 3600) / 60);
if (hours > 0) return `${hours}小时${minutes}分钟`;
return `${minutes}分钟`;
};
const loadTasks = async () => {
loading.value = true;
try {
const res = await getReviewTaskStats();
tasks.value = res?.data || [];
} finally {
loading.value = false;
}
};
const openTaskReview = async (row: ReviewTaskStats) => {
if (!row.taskNum) return;
openingTaskNum.value = row.taskNum;
try {
const res = await getTaskReview(row.taskNum);
const items: ReviewFeedItem[] = res?.data || [];
const first = items[0];
if (!first) {
ElMessage.info("该任务暂无可复习内容");
return;
}
router.push(`/review/detail/${first.sourceType.toLowerCase()}/${first.id}`);
} finally {
openingTaskNum.value = "";
}
};
onMounted(() => {
loadTasks();
});
</script>
<template>
<section class="review-page">
<div class="table-toolbar">
<span class="toolbar-placeholder"></span>
<el-button type="success" plain :loading="loading" @click="loadTasks">刷新</el-button>
</div>
<div class="summary-grid">
<article class="surface-card metric-card">
<span>任务数</span>
<strong>{{ summary.totalTasks }}</strong>
</article>
<article class="surface-card metric-card">
<span>学习报告总数</span>
<strong>{{ summary.totalReports }}</strong>
</article>
<article class="surface-card metric-card">
<span>学习残片总数</span>
<strong>{{ summary.totalFragments }}</strong>
</article>
</div>
<div v-if="tasks.length > 0" v-loading="loading" class="task-list">
<article
v-for="row in tasks"
:key="row.taskNum"
class="surface-card task-card"
>
<div class="task-head">
<strong>{{ row.taskName }}</strong>
</div>
<div class="task-meta">
<span>累计有效学习时长{{ formatEffectiveTime(row.effectiveTime) }}</span>
</div>
<div class="task-stats">
<span>学习报告数量{{ row.reportCount || 0 }}</span>
<span>学习残片数量{{ row.fragmentCount || 0 }}</span>
</div>
<div class="task-actions">
<el-button
text
type="success"
size="small"
:loading="openingTaskNum === row.taskNum"
@click="openTaskReview(row)"
>
查看记录
</el-button>
<el-button
class="recall-button"
type="success"
size="small"
@click="router.push(`/review/recall/${row.taskNum}`)"
>
回忆复习
</el-button>
</div>
</article>
</div>
<el-empty v-if="!loading && tasks.length === 0" description="暂无复习任务" />
</section>
</template>
<style scoped>
.review-page {
display: flex;
flex-direction: column;
gap: 14px;
}
.table-toolbar {
display: flex;
justify-content: flex-end;
}
.summary-grid {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 12px;
}
.metric-card {
padding: 16px 18px;
}
.metric-card span {
color: var(--text-secondary);
font-size: 13px;
}
.metric-card strong {
display: block;
margin-top: 6px;
font-size: 30px;
line-height: 1;
color: var(--green-900);
}
.task-list {
display: flex;
flex-direction: column;
gap: 10px;
}
.task-card {
padding: 14px 16px;
display: flex;
flex-direction: column;
gap: 10px;
}
.task-head strong {
display: block;
color: var(--green-900);
font-size: 15px;
overflow-wrap: anywhere;
}
.task-meta,
.task-stats {
display: flex;
flex-wrap: wrap;
gap: 8px 14px;
color: var(--text-secondary);
font-size: 13px;
}
.task-actions {
display: flex;
justify-content: space-between;
align-items: center;
gap: 4px;
}
@media (max-width: 900px) {
.summary-grid {
grid-template-columns: 1fr;
}
}
@media (max-width: 768px) {
.task-actions .recall-button {
order: -1;
}
}
</style>