web-home
This commit is contained in:
262
schoolNewsWeb/src/views/public/task/LearningProgress.vue
Normal file
262
schoolNewsWeb/src/views/public/task/LearningProgress.vue
Normal 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>
|
||||
@@ -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 = {};
|
||||
|
||||
@@ -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';
|
||||
Reference in New Issue
Block a user