大湾社区城市书房智慧大屏
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

311 lines
8.2 KiB

<template>
<!-- 1. 样式抽离到class提升可读性和维护性 -->
<div class="chart-container">
<div ref="todayTypeRef" class="today-type-chart" />
</div>
</template>
<script>
import centerImg from '@/assets/images/circle-bg.png'
export default {
name: 'TodayTypePieChart', // 3. 增加组件名,便于调试和复用
props: {
todayAllNum: {
type: Object,
required: true, // 4. 修正拼写错误 require -> required
default: () => ({}) // 5. 简化默认值写法
}
},
data() {
return {
myChart: null,
initDebounceTimer: null
}
},
watch: {
todayAllNum: {
handler(val) {
if (!val) return
clearTimeout(this.initDebounceTimer)
this.initDebounceTimer = setTimeout(() => {
this.$nextTick(() => {
this.initTodayCircle()
})
}, 300)
},
immediate: true,
deep: true
}
},
mounted() {
this.initTodayCircle()
},
beforeDestroy() {
this.destroyChart()
},
methods: {
/**
* 9. 销毁图表实例和定时器(抽离通用逻辑)
*/
destroyChart() {
clearTimeout(this.initDebounceTimer)
if (this.myChart) {
this.myChart.dispose()
this.myChart = null
}
},
/**
* 10. 计算数组value总和(抽离为独立方法,提升可读性)
* @param {Array} arr - 数据数组
* @returns {Number} 总和
*/
calculateTotal(arr) {
if (!Array.isArray(arr) || arr.length === 0) return 0
return arr.reduce((total, item) => total + (item.value || 0), 0)
},
/**
* 11. 构建图例格式化文本(抽离独立方法)
* @param {String} name - 图例名称
* @param {Array} data - 图表数据
* @returns {Array|String} 格式化后的文本
*/
formatLegendName(name, data) {
const total = this.calculateTotal(data)
const targetItem = data.find(item => item.name === name)
if (!targetItem) return name
const percentage = total > 0 ? `${((targetItem.value / total) * 100).toFixed(0)}%` : '0%'
return [`{name|${name}}`, `{num|${percentage}}`]
},
/**
* 初始化今日类型饼图
*/
initTodayCircle() {
// 12. 使用ref替代getElementById,更符合Vue规范
const chartDom = this.$refs.todayTypeRef
if (!chartDom) {
console.warn('图表容器未找到')
return
}
// 13. 数据处理抽离,提升代码可读性
const chartData = [
{ value: this.todayAllNum.headerLib || 0, name: '大湾' },
{ value: this.todayAllNum.branchLib || 0, name: '张家湾' }
]
// 14. 销毁旧实例,避免内存泄漏
if (this.myChart) {
this.myChart.dispose()
}
// 初始化图表
this.myChart = this.$echarts.init(chartDom)
// 15. 抽离option配置,拆分基础配置和媒体查询配置,提升可维护性
const baseOption = {
tooltip: {
show: false,
trigger: 'item',
position: 'bottom',
textStyle: {
color: '#EEF6FF',
fontSize: 18
}
},
legend: {
orient: 'vertical',
right: 40,
top: 55,
itemWidth: 10,
itemHeight: 10,
icon: 'circle',
selectedMode: false,
data: ['大湾', '张家湾'],
formatter: (name) => this.formatLegendName(name, chartData),
textStyle: {
rich: {
name: {
fontSize: 18,
color: '#EEF6FF',
padding: [20, 0, 20, 4],
fontFamily: 'DingTalk_JinBuTi_Regular'
},
num: {
fontSize: 24,
fontWeight: 600,
padding: [20, 0, 20, 15],
color: '#4C90FF',
fontFamily: 'DingTalk_JinBuTi_Regular'
}
}
}
},
graphic: [
{
type: 'image',
id: 'logo',
left: '8.5%',
top: '22%',
z: -10,
bounding: 'raw',
rotation: 0,
origin: [64.5, 32.5],
scale: [1.0, 1.0],
style: {
image: centerImg,
width: 132,
height: 131,
opacity: 1
}
}
],
series: [
{
name: '今日累计借阅',
type: 'pie',
left: '-50%',
radius: ['60%', '70%'],
avoidLabelOverlap: false,
label: {
show: false,
position: 'center'
},
labelLine: {
show: true
},
itemStyle: {
borderWidth: 2,
borderColor: 'rgba(16,16,21,0.4)'
},
emphasis: {
label: {
show: true,
formatter: ({ value, name }) => [ // 16. 解构赋值简化代码
`{c| ${value}}`,
`{b| ${name}}`
].join('\n'),
rich: {
c: {
fontSize: 24,
fontWeight: 600,
color: '#317FFF',
fontFamily: 'DingTalk_JinBuTi_Regular',
lineHeight: 34
},
b: {
fontSize: 18,
color: '#fff',
fontFamily: 'DingTalk_JinBuTi_Regular'
}
}
}
},
color: ['#FFD14F', '#317FFF'],
data: chartData
}
]
}
const mediaOption = [
{
query: { maxWidth: 317 },
option: {
legend: {
right: 30,
top: 'center',
textStyle: {
rich: {
name: { fontSize: 14 },
num: { fontSize: 16 }
}
}
},
graphic: [
{
left: '8%',
top: '26%',
z: -10,
bounding: 'raw',
rotation: 0,
origin: [64.5, 32.5],
scale: [1.0, 1.0],
style: {
image: centerImg,
width: 110,
height: 110,
opacity: 1
}
}
],
series: [
{
type: 'pie',
radius: ['50%', '55%'],
emphasis: {
label: {
rich: {
c: { fontSize: 22, lineHeight: 28 },
b: { fontSize: 16 }
}
}
}
}
]
}
}
]
// 合并配置并设置
const option = { baseOption, media: mediaOption }
this.myChart.setOption(option)
// 自动轮播tooltip
this.$LoopShowTooltip(this.myChart, baseOption, { loopSeries: true, interval: 4000 })
// 17. 监听窗口大小变化,自适应图表
window.addEventListener('resize', this.handleResize)
},
/**
* 18. 窗口大小变化时重绘图表
*/
handleResize() {
if (this.myChart) {
this.myChart.resize()
}
}
},
// 19. 移除无用的created钩子
beforeUnmount() {
// 20. 移除resize监听,避免内存泄漏
window.removeEventListener('resize', this.handleResize)
this.destroyChart()
}
}
</script>
<style lang="scss" scoped> // 21. 添加scoped,避免样式污染
@import "~@/assets/styles/index.scss";
@import "~@/assets/styles/font-some.css";
// 22. 样式抽离,便于维护和修改
.chart-container {
height: calc(100% - 200px);
display: flex;
align-items: center;
justify-content: flex-start;
.today-type-chart {
width: 400px;
height: 230px;
}
}
</style>