430 lines
8.6 KiB
Vue
430 lines
8.6 KiB
Vue
<template>
|
|
<div class="classroom-report">
|
|
<!-- 课程访问量图表 -->
|
|
<div class="chart-section">
|
|
<div class="chart-header">
|
|
<h3 class="chart-title">课程访问量</h3>
|
|
<div class="time-selector">
|
|
<span
|
|
class="time-option"
|
|
:class="{ active: visitVolumeTimeRange === 'week' }"
|
|
@click="switchVisitVolumeTimeRange('week')"
|
|
>
|
|
本周
|
|
</span>
|
|
<span
|
|
class="time-option"
|
|
:class="{ active: visitVolumeTimeRange === 'month' }"
|
|
@click="switchVisitVolumeTimeRange('month')"
|
|
>
|
|
本月
|
|
</span>
|
|
</div>
|
|
</div>
|
|
<div class="chart-container">
|
|
<v-chart :option="visitVolumeOption" style="height: 100%;" />
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 课程互动图表 -->
|
|
<div class="chart-section">
|
|
<div class="chart-header chart-header2">
|
|
<h3 class="chart-title">课程互动</h3>
|
|
<div class="time-selector">
|
|
<span
|
|
class="time-option"
|
|
:class="{ active: interactionTimeRange === 'week' }"
|
|
@click="switchInteractionTimeRange('week')"
|
|
>
|
|
本周
|
|
</span>
|
|
<span
|
|
class="time-option"
|
|
:class="{ active: interactionTimeRange === 'month' }"
|
|
@click="switchInteractionTimeRange('month')"
|
|
>
|
|
本月
|
|
</span>
|
|
</div>
|
|
</div>
|
|
<div class="chart-wrapper">
|
|
<div class="chart-legend">
|
|
<div class="legend-item">
|
|
<div class="legend-color" style="background-color: #81A2FF;"></div>
|
|
<span>评论</span>
|
|
</div>
|
|
<div class="legend-item">
|
|
<div class="legend-color" style="background-color: #3DC8F4;"></div>
|
|
<span>弹幕</span>
|
|
</div>
|
|
</div>
|
|
<div class="chart-container">
|
|
<v-chart :option="interactionOption" style="height: 100%;" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { ref, computed } from 'vue'
|
|
import type { EChartsOption } from 'echarts'
|
|
|
|
// 时间范围选择
|
|
const visitVolumeTimeRange = ref<'week' | 'month'>('week')
|
|
const interactionTimeRange = ref<'week' | 'month'>('week')
|
|
|
|
const switchVisitVolumeTimeRange = (range: 'week' | 'month') => {
|
|
visitVolumeTimeRange.value = range
|
|
}
|
|
|
|
const switchInteractionTimeRange = (range: 'week' | 'month') => {
|
|
interactionTimeRange.value = range
|
|
}
|
|
|
|
// 模拟数据
|
|
const weekData = {
|
|
dates: ['7.11', '7.12', '7.13', '7.14', '7.15', '7.16', '7.18'],
|
|
visitVolume: [280, 390, 180, 300, 130, 380, 250],
|
|
comments: [240, 420, 260, 390, 240, 370, 220],
|
|
bulletComments: [160, 300, 120, 200, 180, 280, 180]
|
|
}
|
|
|
|
const monthData = {
|
|
dates: ['7.1', '7.5', '7.10', '7.15', '7.20', '7.25', '7.30'],
|
|
visitVolume: [200, 350, 280, 400, 320, 380, 300],
|
|
comments: [180, 320, 250, 380, 300, 350, 280],
|
|
bulletComments: [120, 250, 180, 280, 220, 300, 200]
|
|
}
|
|
|
|
// 当前数据
|
|
const visitVolumeData = computed(() => {
|
|
return visitVolumeTimeRange.value === 'week' ? weekData : monthData
|
|
})
|
|
|
|
const interactionData = computed(() => {
|
|
return interactionTimeRange.value === 'week' ? weekData : monthData
|
|
})
|
|
|
|
// 课程访问量图表配置(柱状图)
|
|
const visitVolumeOption = computed<EChartsOption>(() => ({
|
|
tooltip: {
|
|
trigger: 'axis',
|
|
axisPointer: {
|
|
type: 'shadow'
|
|
}
|
|
},
|
|
grid: {
|
|
left: '2%',
|
|
right: '1%',
|
|
top: '14%',
|
|
bottom: '6%',
|
|
containLabel: true
|
|
},
|
|
xAxis: {
|
|
type: 'category',
|
|
data: visitVolumeData.value.dates,
|
|
axisLine: {
|
|
lineStyle: {
|
|
color: '#C0CEE7'
|
|
}
|
|
},
|
|
axisTick: {
|
|
show: false
|
|
},
|
|
axisLabel: {
|
|
color: '#BDC6D8',
|
|
fontSize: 12
|
|
}
|
|
},
|
|
yAxis: {
|
|
type: 'value',
|
|
max: 400,
|
|
interval: 100,
|
|
axisLine: {
|
|
show: false
|
|
},
|
|
axisTick: {
|
|
show: false
|
|
},
|
|
axisLabel: {
|
|
color: '#BDC6D8',
|
|
fontSize: 12
|
|
},
|
|
splitLine: {
|
|
lineStyle: {
|
|
color: '#F5F5F5',
|
|
type: 'dashed'
|
|
}
|
|
}
|
|
},
|
|
series: [
|
|
{
|
|
name: '背景',
|
|
type: 'bar',
|
|
data: [400, 400, 400, 400, 400, 400, 400],
|
|
itemStyle: {
|
|
color: '#F8F8FC'
|
|
},
|
|
barWidth: '8px',
|
|
barGap: '-100%',
|
|
silent: true
|
|
},
|
|
{
|
|
name: '访问量',
|
|
type: 'bar',
|
|
data: visitVolumeData.value.visitVolume,
|
|
itemStyle: {
|
|
color: {
|
|
type: 'linear',
|
|
x: 0,
|
|
y: 0,
|
|
x2: 0,
|
|
y2: 1,
|
|
colorStops: [
|
|
{ offset: 0, color: '#39E7E8' },
|
|
{ offset: 1, color: '#0288D1' }
|
|
]
|
|
}
|
|
},
|
|
barWidth: '8px',
|
|
emphasis: {
|
|
itemStyle: {
|
|
color: {
|
|
type: 'linear',
|
|
x: 0,
|
|
y: 0,
|
|
x2: 0,
|
|
y2: 1,
|
|
colorStops: [
|
|
{ offset: 0, color: '#4FE8E9' },
|
|
{ offset: 1, color: '#039BE5' }
|
|
]
|
|
}
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}))
|
|
|
|
// 课程互动图表配置(面积图)
|
|
const interactionOption = computed<EChartsOption>(() => ({
|
|
tooltip: {
|
|
trigger: 'axis',
|
|
axisPointer: {
|
|
type: 'line'
|
|
}
|
|
},
|
|
|
|
grid: {
|
|
left: '2%',
|
|
right: '1%',
|
|
bottom: '8%',
|
|
top: '12%',
|
|
containLabel: true
|
|
},
|
|
xAxis: {
|
|
type: 'category',
|
|
data: interactionData.value.dates,
|
|
axisLine: {
|
|
lineStyle: {
|
|
color: '#C0CEE7'
|
|
}
|
|
},
|
|
axisTick: {
|
|
show: false
|
|
},
|
|
axisLabel: {
|
|
color: '#BDC6D8',
|
|
fontSize: 12
|
|
}
|
|
},
|
|
yAxis: {
|
|
type: 'value',
|
|
max: 500,
|
|
interval: 100,
|
|
axisLine: {
|
|
show: false
|
|
},
|
|
axisTick: {
|
|
show: false
|
|
},
|
|
axisLabel: {
|
|
color: '#BDC6D8',
|
|
fontSize: 12
|
|
},
|
|
splitLine: {
|
|
lineStyle: {
|
|
color: '#F5F5F5',
|
|
type: 'dashed'
|
|
}
|
|
}
|
|
},
|
|
series: [
|
|
{
|
|
name: '评论',
|
|
type: 'line',
|
|
smooth: true,
|
|
data: interactionData.value.comments,
|
|
lineStyle: {
|
|
color: '#81A2FF',
|
|
width: 2
|
|
},
|
|
areaStyle: {
|
|
color: {
|
|
type: 'linear',
|
|
x: 0,
|
|
y: 0,
|
|
x2: 0,
|
|
y2: 1,
|
|
colorStops: [
|
|
{ offset: 0, color: 'rgba(129, 162, 255, 0.3)' },
|
|
{ offset: 1, color: 'rgba(129, 162, 255, 0.05)' }
|
|
]
|
|
}
|
|
},
|
|
itemStyle: {
|
|
color: '#81A2FF'
|
|
},
|
|
symbol: 'none'
|
|
},
|
|
{
|
|
name: '弹幕',
|
|
type: 'line',
|
|
smooth: true,
|
|
data: interactionData.value.bulletComments,
|
|
lineStyle: {
|
|
color: '#3DC8F4',
|
|
width: 2
|
|
},
|
|
areaStyle: {
|
|
color: {
|
|
type: 'linear',
|
|
x: 0,
|
|
y: 0,
|
|
x2: 0,
|
|
y2: 1,
|
|
colorStops: [
|
|
{ offset: 0, color: 'rgba(61, 200, 244, 0.2)' },
|
|
{ offset: 1, color: 'rgba(61, 200, 244, 0.02)' }
|
|
]
|
|
}
|
|
},
|
|
itemStyle: {
|
|
color: '#3DC8F4'
|
|
},
|
|
symbol: 'none'
|
|
}
|
|
]
|
|
}))
|
|
</script>
|
|
|
|
<style scoped>
|
|
.classroom-report {
|
|
padding: 0 30px 20px;
|
|
}
|
|
|
|
.chart-section {
|
|
margin-bottom: 24px;
|
|
}
|
|
|
|
.chart-header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
margin-bottom: 20px;
|
|
}
|
|
|
|
.chart-header2 {
|
|
margin-bottom: 35px;
|
|
}
|
|
|
|
.chart-title {
|
|
font-size: 16px;
|
|
font-weight: 500;
|
|
color: #333;
|
|
margin: 0;
|
|
}
|
|
|
|
.time-selector {
|
|
display: flex;
|
|
padding: 4px;
|
|
}
|
|
|
|
.time-option {
|
|
padding: 6px 16px;
|
|
font-size: 16px;
|
|
color: #333333;
|
|
cursor: pointer;
|
|
transition: all 0.3s ease;
|
|
}
|
|
|
|
.time-option.active {
|
|
color: #0C99DA;
|
|
}
|
|
|
|
.time-option:hover:not(.active) {
|
|
background: #E3F2FD;
|
|
color: #1976D2;
|
|
}
|
|
|
|
.chart-wrapper {
|
|
position: relative;
|
|
}
|
|
|
|
.chart-legend {
|
|
position: absolute;
|
|
top: -30px;
|
|
left: 0;
|
|
display: flex;
|
|
gap: 16px;
|
|
z-index: 10;
|
|
}
|
|
|
|
.legend-item {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 6px;
|
|
font-size: 12px;
|
|
color: #666;
|
|
}
|
|
|
|
.legend-color {
|
|
width: 12px;
|
|
height: 12px;
|
|
border-radius: 50%;
|
|
}
|
|
|
|
.chart-container {
|
|
width: 100%;
|
|
height: 210px;
|
|
border: 1px solid #E6E6E6;
|
|
border-radius: 4px;
|
|
overflow: hidden;
|
|
}
|
|
|
|
|
|
|
|
/* 响应式设计 */
|
|
@media (max-width: 768px) {
|
|
.classroom-report {
|
|
padding: 0 16px;
|
|
}
|
|
|
|
.chart-section {
|
|
padding: 16px;
|
|
margin-bottom: 16px;
|
|
}
|
|
|
|
.chart-header {
|
|
flex-direction: column;
|
|
align-items: flex-start;
|
|
gap: 12px;
|
|
}
|
|
|
|
.time-selector {
|
|
align-self: flex-end;
|
|
}
|
|
}
|
|
</style>
|