This commit is contained in:
2025-10-27 19:05:56 +08:00
parent 0033ac10ec
commit 98c73632bd
25 changed files with 1223 additions and 133 deletions

View File

@@ -0,0 +1,262 @@
<template>
<div class="learning-progress">
<div class="progress-header">
<div class="header-left">
<h3 class="progress-title">学习进度</h3>
<p class="update-time">更新时间2025-09-25 18:30:00</p>
</div>
<div class="tab-buttons">
<button v-for="(tab, index) in tabs" :key="index" :class="['tab-btn', { active: activeTab === index }]"
@click="handleTabChange(index)">
{{ tab }}
</button>
</div>
</div>
<div class="chart-container" ref="chartRef"></div>
</div>
</template>
<script setup lang="ts">
import { ref, computed, onMounted, onUnmounted, watch } from 'vue';
import * as echarts from 'echarts';
import type { EChartsOption } from 'echarts';
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 = computed(() => chartDataMap[activeTab.value as keyof typeof chartDataMap]);
// 图表配置
function getChartOption(): EChartsOption {
const data = chartData.value;
return {
tooltip: {
trigger: 'axis',
backgroundColor: 'rgba(0, 0, 0, 0.8)',
borderColor: 'transparent',
textStyle: {
color: '#fff',
fontSize: 12
},
formatter: function(params: any) {
const item = params[0];
return `${item.name}: ${item.value}%`;
}
},
grid: {
left: '0',
right: '20px',
top: '20px',
bottom: '40px',
containLabel: true
},
xAxis: {
type: 'category',
data: data.map(item => item.name),
axisLine: {
show: false
},
axisTick: {
show: false
},
axisLabel: {
color: '#979797',
fontSize: 14,
fontFamily: 'PingFang SC'
}
},
yAxis: {
type: 'value',
min: 0,
max: 100,
interval: 20,
axisLine: {
show: false
},
axisTick: {
show: false
},
axisLabel: {
color: '#979797',
fontSize: 14,
fontFamily: 'PingFang SC'
},
splitLine: {
lineStyle: {
color: '#D4D4D5',
type: 'dashed'
}
}
},
series: [{
type: 'bar',
data: data.map(item => ({
value: item.value,
itemStyle: {
color: item.highlight ? '#FF6B6B' : '#C62828',
borderRadius: [8, 8, 0, 0]
}
})),
barWidth: 40,
label: {
show: false
}
}]
};
}
const chartOption = computed(getChartOption);
// 初始化图表
function initChart() {
if (!chartRef.value) return;
chartInstance = echarts.init(chartRef.value);
chartInstance.setOption(chartOption.value);
// 自动调整大小
window.addEventListener('resize', handleResize);
}
// 处理窗口大小变化
function handleResize() {
if (chartInstance) {
chartInstance.resize();
}
}
// 处理标签切换
function handleTabChange(index: number) {
activeTab.value = index;
if (chartInstance) {
chartInstance.setOption(chartOption.value, true);
}
}
// 监听配置变化
watch(() => chartOption.value, () => {
if (chartInstance) {
chartInstance.setOption(chartOption.value, true);
}
}, { deep: true });
onMounted(() => {
initChart();
});
onUnmounted(() => {
if (chartInstance) {
chartInstance.dispose();
}
window.removeEventListener('resize', handleResize);
});
</script>
<style lang="scss" scoped>
.learning-progress {
width: 100%;
height: 371px;
background: #FFFFFF;
border: 1px solid rgba(0, 0, 0, 0.1);
border-radius: 10px;
padding: 30px 30px 40px 30px;
.progress-header {
display: flex;
justify-content: space-between;
align-items: flex-start;
margin-bottom: 30px;
.header-left {
display: flex;
align-items: center;
gap: 8px;
}
.progress-title {
font-family: 'PingFang SC';
font-weight: 600;
font-size: 20px;
line-height: 38px;
color: #141F38;
margin: 0;
}
.update-time {
font-family: 'PingFang SC';
font-weight: 400;
font-size: 14px;
line-height: 22px;
color: #B4B8BF;
margin: 0;
}
}
.tab-buttons {
display: flex;
gap: 4px;
background: #F9F9F9;
border: 1px solid #EBEBEB;
border-radius: 8px;
padding: 4px;
.tab-btn {
padding: 8px;
min-width: 71px;
height: 40px;
background: transparent;
border: none;
border-radius: 6px;
font-family: 'PingFang SC';
font-weight: 600;
font-size: 14px;
line-height: 22px;
color: #B4B8BF;
cursor: pointer;
transition: all 0.3s;
&.active {
background: #FFFFFF;
color: #C62828;
}
&:hover:not(.active) {
color: #141F38;
}
}
}
}
.chart-container {
height: 243px;
}
</style>

View File

@@ -434,8 +434,8 @@ async function loadTaskList() {
try {
const pageParam: PageParam = {
page: pagination.value.current,
size: pagination.value.pageSize
pageNumber: pagination.value.current,
pageSize: pagination.value.pageSize
};
const filter: any = {};

View File

@@ -1,3 +1,4 @@
export { default as LearningTaskAdd } from './LearningTaskAdd.vue';
export { default as LearningTaskList } from './LearningTaskList.vue';
export { default as LearingTaskDetail } from './LearingTaskDetail.vue';
export { default as LearingTaskDetail } from './LearningTaskDetail.vue';
export { default as LearningProgress } from './LearningProgress.vue';