264 lines
7.6 KiB
Vue
264 lines
7.6 KiB
Vue
<script setup lang="ts">
|
||
import SmallTitle from '../smallTitle/smallTitle.vue'
|
||
import './BusinessStructure.less'
|
||
import { onMounted, onBeforeUnmount, ref, watch } from 'vue';
|
||
import * as echarts from 'echarts/core';
|
||
import { PieChart } from 'echarts/charts';
|
||
import {
|
||
GridComponent,
|
||
TitleComponent,
|
||
TooltipComponent,
|
||
LegendComponent,
|
||
GraphicComponent
|
||
} from 'echarts/components';
|
||
import { CanvasRenderer } from 'echarts/renderers';
|
||
import businessFormatCenterIcon from '../../../../assets/image/businessFormatCenterIcon.png'
|
||
import moment from 'moment';
|
||
import { handleGetBusinessTradeRevenue } from '../../service';
|
||
|
||
// 注册组件
|
||
echarts.use([
|
||
PieChart,
|
||
GridComponent,
|
||
TitleComponent,
|
||
TooltipComponent,
|
||
LegendComponent,
|
||
GraphicComponent,
|
||
CanvasRenderer
|
||
]);
|
||
|
||
let myChart: echarts.ECharts;
|
||
// 自定义颜色列表
|
||
const colorList = ['#FF9500', '#00FFB7', '#0094FF', '#7D4CD2', '#69BCFF'];
|
||
// 图例数据
|
||
let lengedList = ref<any>([])
|
||
|
||
onMounted(async () => {
|
||
|
||
await handleGoMounted()
|
||
})
|
||
|
||
// 初始运行的方法
|
||
const handleGoMounted = async () => {
|
||
const res: any = await handleGetData()
|
||
|
||
const chartDom = document.getElementById('BusinessStructure');
|
||
if (!chartDom) return;
|
||
|
||
myChart = echarts.init(chartDom);
|
||
|
||
const rect = chartDom.getBoundingClientRect();
|
||
const width = rect.width;
|
||
const height = rect.height;
|
||
|
||
// 计算center位置(20%,50%)对应的实际像素
|
||
const centerX = width * 0.2;
|
||
const centerY = height * 0.5;
|
||
|
||
const option = {
|
||
|
||
tooltip: { // 新增 tooltip 配置
|
||
trigger: 'item', // 触发类型:坐标轴触发
|
||
axisPointer: { // 坐标轴指示器配置
|
||
type: 'shadow' // 阴影指示器(适合柱状图)
|
||
},
|
||
formatter: function (params: any) { // 自定义提示框内容
|
||
return `
|
||
<div style="font-weight:bold">${params.data.name} ${params?.percent}% ${res.realData[params.dataIndex]}</div>
|
||
`;
|
||
}
|
||
},
|
||
graphic: { // 关键配置:在图表中心添加图片
|
||
elements: [
|
||
{
|
||
type: 'image',
|
||
style: {
|
||
image: businessFormatCenterIcon,
|
||
width: 83,
|
||
height: 83
|
||
},
|
||
left: centerX - 41.5,
|
||
top: centerY - 41.5,
|
||
z: 10
|
||
}
|
||
]
|
||
},
|
||
series: [
|
||
{
|
||
name: 'Access From',
|
||
type: 'pie',
|
||
radius: ['85%', '100%'],
|
||
center: ['20%', '50%'], // 图形向左偏移
|
||
avoidLabelOverlap: false,
|
||
itemStyle: {
|
||
color: function (params: any) {
|
||
return colorList[params.dataIndex];
|
||
}
|
||
},
|
||
label: {
|
||
show: false
|
||
},
|
||
emphasis: false,
|
||
labelLine: {
|
||
show: false
|
||
},
|
||
data: res.seriesData
|
||
}
|
||
],
|
||
legend: {
|
||
orient: 'vertical',
|
||
left: 160,
|
||
top: 'center',
|
||
align: 'left',
|
||
itemGap: 10,
|
||
itemWidth: 12,
|
||
itemHeight: 12,
|
||
textStyle: {
|
||
color: '#fff',
|
||
rich: {
|
||
name: {
|
||
width: 90, // 固定名称宽度
|
||
align: 'left',
|
||
padding: [0, 10, 0, 0]
|
||
},
|
||
percent: {
|
||
width: 50, // 固定百分比宽度
|
||
align: 'right',
|
||
padding: [0, 10, 0, 0]
|
||
}
|
||
}
|
||
},
|
||
formatter: function (name: any) {
|
||
let percentData: any = res.lengedData.filter((item: any) => item.name === name)
|
||
|
||
return `{name|${name}}{percent|${percentData[0].value}%}`; // 使用rich样式
|
||
}
|
||
}
|
||
};
|
||
|
||
myChart.setOption(option);
|
||
myChart.resize();
|
||
window.addEventListener('resize', resizeChart);
|
||
}
|
||
|
||
// 拿到传入的数据
|
||
const props = defineProps<{
|
||
currentService?: any;
|
||
}>();
|
||
|
||
// 监听传入的选中服务区
|
||
watch(
|
||
() => props.currentService,
|
||
(newVal, oldVal) => {
|
||
handleGoMounted()
|
||
},
|
||
{ deep: true }
|
||
);
|
||
|
||
// 业态结构占比
|
||
const handleGetData = async () => {
|
||
|
||
const req: any = {
|
||
ProvinceCode: '530000',
|
||
StatisticsDate: moment().subtract(1, 'd').format('YYYY-MM-DD'),
|
||
// StatisticsDate: '2025-04-30',
|
||
BusinessTradeIds: -1,
|
||
ServerpartId: props.currentService?.SERVERPART_ID || ""
|
||
}
|
||
|
||
let BusinessStructure = sessionStorage.getItem('BusinessStructure')
|
||
let data: any = []
|
||
if (BusinessStructure) {
|
||
data = JSON.parse(BusinessStructure)
|
||
} else {
|
||
data = await handleGetBusinessTradeRevenue(req)
|
||
sessionStorage.setItem("BusinessStructure", JSON.stringify(data))
|
||
}
|
||
|
||
|
||
|
||
// const data = await handleGetBusinessTradeRevenue(req)
|
||
|
||
let aiObj: any = {}
|
||
let list: any = data.BusinessTradeRank
|
||
let seriesData: any = []
|
||
let realData: any = []
|
||
let category: any = []
|
||
let lengedLists: any = []
|
||
let lengedData: any = []
|
||
if (list && list.length > 0) {
|
||
list.forEach((item: any) => {
|
||
seriesData.push({ value: Number(item.value), name: item.name })
|
||
realData.push(item.data)
|
||
category.push(item.name)
|
||
lengedLists.push({
|
||
name: item.name,
|
||
percent: Number(item.value),
|
||
value: item.data
|
||
})
|
||
lengedData.push({
|
||
name: item.name,
|
||
value: item.value
|
||
})
|
||
aiObj[item.name] = item.data
|
||
})
|
||
}
|
||
|
||
|
||
let res: any = {
|
||
category: category,// x轴的内容
|
||
seriesData: seriesData,// y轴的数据
|
||
realData: realData,// 真实数据
|
||
lengedData: lengedData
|
||
}
|
||
lengedList.value = lengedLists
|
||
|
||
let BusinessStructureAI = sessionStorage.getItem('BusinessStructureAI')
|
||
if (BusinessStructureAI) { } else {
|
||
sessionStorage.setItem("BusinessStructureAI", JSON.stringify(aiObj))
|
||
}
|
||
|
||
|
||
return res
|
||
}
|
||
|
||
|
||
const resizeChart = () => {
|
||
myChart?.resize();
|
||
};
|
||
|
||
onBeforeUnmount(() => {
|
||
window.removeEventListener('resize', resizeChart);
|
||
myChart?.dispose();
|
||
});
|
||
|
||
</script>
|
||
|
||
|
||
|
||
|
||
<template>
|
||
<div class="BusinessStructureBox">
|
||
<SmallTitle :title="'业态结构占比'"></SmallTitle>
|
||
|
||
<div class="BusinessStructureCharts">
|
||
<!-- <div class="BusinessStructureUnit">万元</div> -->
|
||
<div class="BusinessStructure" id="BusinessStructure"></div>
|
||
|
||
<!-- <div class="BusinessStructureDataList">
|
||
<div class="BusinessStructureDataBox" v-for="(item, index) in lengedList" :key="index">
|
||
<div class="BusinessStructureDataLeftBox">
|
||
<div class="BusinessStructureItem">
|
||
<div class="BusinessStructureItemLeged" :style="{ background: colorList[index] }"></div>
|
||
<div class="BusinessStructureItemLabel">{{ item.name }}</div>
|
||
<div class="BusinessStructureItemLabel" style="margin-left: 8px;">{{ item.percent }}%
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
</div> -->
|
||
|
||
</div>
|
||
</div>
|
||
</template> |