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
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>
|