学习进度统计
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
<div class="progress-header">
|
||||
<div class="header-left">
|
||||
<h3 class="progress-title">学习进度</h3>
|
||||
<p class="update-time">更新时间:2025-09-25 18:30:00</p>
|
||||
<p class="update-time">更新时间:{{ updateTime || '-' }}</p>
|
||||
</div>
|
||||
<div class="tab-buttons">
|
||||
<button v-for="(tab, index) in tabs" :key="index" :class="['tab-btn', { active: activeTab === index }]"
|
||||
@@ -21,38 +21,51 @@
|
||||
import { ref, computed, onMounted, onUnmounted, watch } from 'vue';
|
||||
import * as echarts from 'echarts';
|
||||
import type { EChartsOption } from 'echarts';
|
||||
import dayjs from 'dayjs';
|
||||
import { learningTaskApi } from '@/apis/study/learning-task';
|
||||
|
||||
const tabs = ref(['今日', '近一周', '近一月']);
|
||||
const activeTab = ref(0);
|
||||
const chartRef = ref<HTMLElement | null>(null);
|
||||
let chartInstance: echarts.ECharts | null = null;
|
||||
|
||||
// 模拟不同时间段的数据
|
||||
const chartDataMap = {
|
||||
0: [
|
||||
{ name: '党史', value: 43, highlight: false },
|
||||
{ name: '理论', value: 58, highlight: false },
|
||||
{ name: '政策', value: 34, highlight: false },
|
||||
{ name: '思政', value: 20, highlight: false },
|
||||
{ name: '文化', value: 52, highlight: true }
|
||||
],
|
||||
1: [
|
||||
{ name: '党史', value: 68, highlight: true },
|
||||
{ name: '理论', value: 52, highlight: false },
|
||||
{ name: '政策', value: 45, highlight: false },
|
||||
{ name: '思政', value: 38, highlight: false },
|
||||
{ name: '文化', value: 41, highlight: false }
|
||||
],
|
||||
2: [
|
||||
{ name: '党史', value: 85, highlight: true },
|
||||
{ name: '理论', value: 72, highlight: false },
|
||||
{ name: '政策', value: 58, highlight: false },
|
||||
{ name: '思政', value: 65, highlight: false },
|
||||
{ name: '文化', value: 43, highlight: false }
|
||||
]
|
||||
};
|
||||
// 后端返回的数据结构映射为图表数据
|
||||
const chartData = ref<{ name: string; value: number; highlight: boolean }[]>([]);
|
||||
|
||||
const chartData = computed(() => chartDataMap[activeTab.value as keyof typeof chartDataMap]);
|
||||
const updateTime = ref('');
|
||||
|
||||
async function loadStatistics() {
|
||||
// 根据当前 tab 计算时间范围
|
||||
const now = dayjs();
|
||||
let start: dayjs.Dayjs;
|
||||
|
||||
if (activeTab.value === 0) {
|
||||
// 今日:从今天 00:00:00 到现在
|
||||
start = now.startOf('day');
|
||||
} else if (activeTab.value === 1) {
|
||||
// 近一周:过去 7 天
|
||||
start = now.subtract(6, 'day').startOf('day');
|
||||
} else {
|
||||
// 近一月:过去 30 天
|
||||
start = now.subtract(29, 'day').startOf('day');
|
||||
}
|
||||
|
||||
const startTime = start.format('YYYY-MM-DD HH:mm:ss');
|
||||
const endTime = now.format('YYYY-MM-DD HH:mm:ss');
|
||||
|
||||
const res = await learningTaskApi.getMyStatistics(startTime, endTime);
|
||||
if (res.code === 200 && res.data) {
|
||||
const list = (res.data.tagProgressList || []) as { tagName: string; avgProgress: number }[];
|
||||
chartData.value = list.map(item => ({
|
||||
name: item.tagName,
|
||||
value: Number(item.avgProgress ?? 0),
|
||||
highlight: false,
|
||||
}));
|
||||
updateTime.value = now.format('YYYY-MM-DD HH:mm:ss');
|
||||
} else {
|
||||
chartData.value = [];
|
||||
}
|
||||
}
|
||||
|
||||
// 图表配置
|
||||
function getChartOption(): EChartsOption {
|
||||
@@ -155,8 +168,9 @@ function handleResize() {
|
||||
}
|
||||
|
||||
// 处理标签切换
|
||||
function handleTabChange(index: number) {
|
||||
async function handleTabChange(index: number) {
|
||||
activeTab.value = index;
|
||||
await loadStatistics();
|
||||
if (chartInstance) {
|
||||
chartInstance.setOption(chartOption.value, true);
|
||||
}
|
||||
@@ -169,8 +183,12 @@ watch(() => chartOption.value, () => {
|
||||
}
|
||||
}, { deep: true });
|
||||
|
||||
onMounted(() => {
|
||||
onMounted(async () => {
|
||||
initChart();
|
||||
await loadStatistics();
|
||||
if (chartInstance) {
|
||||
chartInstance.setOption(chartOption.value, true);
|
||||
}
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
|
||||
@@ -62,13 +62,14 @@
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="form-label">任务分类标签</label>
|
||||
<label class="form-label required">任务分类标签</label>
|
||||
<select
|
||||
v-model="selectedTagID"
|
||||
class="form-input form-select"
|
||||
@change="handleTagChange"
|
||||
@blur="validateTag"
|
||||
>
|
||||
<option value="">请选择分类标签(可选)</option>
|
||||
<option value="">请选择分类标签</option>
|
||||
<option
|
||||
v-for="tag in availableTags"
|
||||
:key="tag.tagID"
|
||||
@@ -77,6 +78,7 @@
|
||||
{{ tag.name }}
|
||||
</option>
|
||||
</select>
|
||||
<span v-if="errors.tag" class="error-msg">{{ errors.tag }}</span>
|
||||
<div v-if="selectedTag" class="selected-tag-preview">
|
||||
<div class="tag-badge" :style="{ backgroundColor: selectedTag.color || '#409eff' }">
|
||||
{{ selectedTag.name }}
|
||||
@@ -350,7 +352,8 @@ const taskData = ref<TaskVO>({
|
||||
const errors = ref({
|
||||
name: '',
|
||||
startTime: '',
|
||||
endTime: ''
|
||||
endTime: '',
|
||||
tag: ''
|
||||
});
|
||||
|
||||
// 选中的数据
|
||||
@@ -732,6 +735,7 @@ function handleTagChange() {
|
||||
} else {
|
||||
selectedTag.value = null;
|
||||
}
|
||||
validateTag();
|
||||
}
|
||||
|
||||
// 表单验证
|
||||
@@ -744,6 +748,15 @@ function validateTaskName() {
|
||||
return true;
|
||||
}
|
||||
|
||||
function validateTag() {
|
||||
if (!selectedTagID.value) {
|
||||
errors.value.tag = '请选择任务分类标签';
|
||||
return false;
|
||||
}
|
||||
errors.value.tag = '';
|
||||
return true;
|
||||
}
|
||||
|
||||
function validateTime() {
|
||||
if (!taskData.value.learningTask.startTime) {
|
||||
errors.value.startTime = '请选择开始时间';
|
||||
@@ -765,8 +778,9 @@ function validateTime() {
|
||||
function validateForm() {
|
||||
const isNameValid = validateTaskName();
|
||||
const isTimeValid = validateTime();
|
||||
const isTagValid = validateTag();
|
||||
|
||||
if (!isNameValid || !isTimeValid) {
|
||||
if (!isNameValid || !isTimeValid || !isTagValid) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user