- 新增构建插件:打包分析、压缩、自动部署、图片优化和PWA支持 - 将SVG资源转换为WebP格式以提升加载性能 - 添加新的背景图片资源用于用户界面优化 - 更新环境配置:调整基础URL和服务地址 - 优化用户界面组件以适配新的资源格式 - 更新package.json依赖以支持新的构建功能 - 改进构建流程以支持自动部署和性能监控
157 lines
3.9 KiB
Vue
157 lines
3.9 KiB
Vue
<script setup lang="ts">
|
|
import * as echarts from 'echarts/core'
|
|
import { ref, watch } from 'vue'
|
|
|
|
import { type ECOption, useEcharts } from '@/hooks/common/echarts'
|
|
|
|
interface BarDatum {
|
|
group: string | number
|
|
total: number
|
|
correct: number
|
|
}
|
|
|
|
const props = defineProps<{
|
|
data: BarDatum[]
|
|
height?: number
|
|
}>()
|
|
|
|
// 缓存上一次的数据,用于深度比较
|
|
const lastDataCache = ref<string>('')
|
|
|
|
/**
|
|
* 深度比较数据是否发生变化
|
|
*/
|
|
function isDataChanged(newData: BarDatum[]): boolean {
|
|
const newDataStr = JSON.stringify(newData)
|
|
if (newDataStr === lastDataCache.value) {
|
|
return false
|
|
}
|
|
lastDataCache.value = newDataStr
|
|
return true
|
|
}
|
|
|
|
/**
|
|
* 构建柱状图配置
|
|
* 说明:根据传入的数据生成双系列柱状图(答题数量/正确数量)
|
|
*/
|
|
function buildOption(list: BarDatum[]): ECOption {
|
|
const categories = list.map(i => String(i.group))
|
|
const total = list.map(i => i.total)
|
|
const correct = list.map(i => i.correct)
|
|
|
|
return {
|
|
// 禁用动画,避免频繁刷新时的抖动
|
|
animation: false,
|
|
tooltip: {
|
|
trigger: 'axis',
|
|
axisPointer: { type: 'shadow' },
|
|
},
|
|
legend: {
|
|
data: ['答题数量', '预估得分'],
|
|
top: 0,
|
|
right: 0,
|
|
icon: 'circle',
|
|
textStyle: {
|
|
color: '#666',
|
|
},
|
|
},
|
|
grid: { left: 16, right: 16, top: 40, bottom: 0, containLabel: true },
|
|
xAxis: {
|
|
type: 'category',
|
|
data: categories,
|
|
axisTick: { show: false }, // 隐藏 x 轴刻度线
|
|
axisLine: { show: false }, // 隐藏 x 轴线
|
|
axisLabel: {
|
|
color: '#003366', // 深蓝色字体
|
|
fontWeight: 'bold',
|
|
fontSize: 14,
|
|
margin: 16,
|
|
},
|
|
},
|
|
yAxis: {
|
|
type: 'value',
|
|
minInterval: 1,
|
|
axisTick: { show: false }, // 隐藏 y 轴刻度线
|
|
axisLine: { show: false }, // 隐藏 y 轴线
|
|
splitLine: { show: false }, // 隐藏 y 轴网格线
|
|
axisLabel: { show: false }, // 隐藏 y 轴标签
|
|
},
|
|
series: [
|
|
{
|
|
name: '答题数量',
|
|
type: 'bar',
|
|
data: total,
|
|
barWidth: 24,
|
|
itemStyle: {
|
|
// 从上到下:浅蓝 -> 深蓝
|
|
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
|
{ offset: 0, color: '#e0f2fe' }, // sky-100 (顶部浅色)
|
|
{ offset: 1, color: '#3b82f6' }, // blue-500 (底部深色)
|
|
]),
|
|
borderRadius: [4, 4, 0, 0],
|
|
},
|
|
label: {
|
|
show: true,
|
|
position: 'top',
|
|
color: '#003366', // 深蓝色
|
|
fontWeight: 'bold',
|
|
fontSize: 18,
|
|
offset: [0, 2],
|
|
},
|
|
},
|
|
{
|
|
name: '预估得分',
|
|
type: 'bar',
|
|
data: correct,
|
|
barWidth: 24,
|
|
itemStyle: {
|
|
// 从上到下:浅橙 -> 深橙
|
|
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
|
{ offset: 0, color: '#fff7ed' }, // orange-50 (顶部极浅)
|
|
{ offset: 1, color: '#f97316' }, // orange-500 (底部深色)
|
|
]),
|
|
borderRadius: [4, 4, 0, 0],
|
|
},
|
|
label: {
|
|
show: true,
|
|
position: 'top',
|
|
color: '#ea580c', // orange-600
|
|
fontWeight: 'bold',
|
|
fontSize: 18,
|
|
offset: [0, 2],
|
|
},
|
|
},
|
|
],
|
|
}
|
|
}
|
|
|
|
// 初始化图表
|
|
const { domRef, updateOptions } = useEcharts<ECOption>(() => buildOption(props.data || []))
|
|
|
|
/**
|
|
* 监听数据变化并更新图表
|
|
* 说明:只有当数据真正发生变化时才更新图表,避免不必要的重绘
|
|
*/
|
|
watch(
|
|
() => props.data,
|
|
(newData) => {
|
|
// 只有数据真正变化时才更新
|
|
if (isDataChanged(newData || [])) {
|
|
updateOptions(() => buildOption(newData || []))
|
|
}
|
|
},
|
|
{ deep: true },
|
|
)
|
|
</script>
|
|
|
|
<template>
|
|
<div
|
|
ref="domRef"
|
|
class="w-full"
|
|
:style="{ height: `${props.height ?? 180}px` }"
|
|
/>
|
|
</template>
|
|
|
|
<style scoped>
|
|
</style>
|