WholeProcessPlatform/frontend/src/components/developStatusChart/index.vue
2026-07-07 13:50:21 +08:00

310 lines
9.3 KiB
Vue

<!-- developStatusChart/index.vue -->
<template>
<div class="basic_body">
<div ref="chartContainer" class="chart-container"></div>
<!-- 水电开发情况弹窗 -->
<a-modal
v-model:open="modalVisible"
title="水电开发情况"
width="80%"
:footer="null"
:destroy-on-close="true"
>
<ShuiDianKaiFQKTwoLayer
v-if="modalVisible"
:defaultJidiInfo="modalProps.defaultJidiInfo"
:seriesName="modalProps.seriesName"
:stateName="modalProps.stateName"
:defaultTab="modalProps.defaultTab"
/>
</a-modal>
</div>
</template>
<script lang="ts" setup>
import { ref, onMounted, onUnmounted, watch } from 'vue';
import * as echarts from 'echarts';
import { getVmsstbprptKendoList } from '@/api/home';
import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent';
import ShuiDianKaiFQKTwoLayer from '@/modules/shuidianhuangjingjieruMod/TwoLayer/ShuiDianKaiFQKTwoLayer.vue';
import { useDraggable } from '@/utils/drag';
defineOptions({
name: 'developStatusChart'
});
const JidiSelectEventStore = useJidiSelectEventStore();
const baseid = ref('');
const chartContainer = ref<HTMLDivElement | null>(null);
let chartInstance: echarts.ECharts | null = null;
const dataLoading = ref(false);
const modalVisible = ref(false);
const modalProps = ref<any>({});
useDraggable(modalVisible, { boundary: true, resetOnOpen: true });
function openModal(props: any) {
modalProps.value = props;
modalVisible.value = true;
}
defineExpose({
openModal,
dataLoading
});
onUnmounted(() => {
if (chartInstance) {
chartInstance.dispose();
chartInstance = null;
}
});
const transUnit = (value: number) => {
return value * 0.1;
};
const getData = async () => {
if (!baseid.value) return;
const baseFilters: any[] = [
{ field: 'sttpCode', operator: 'eq', dataType: 'string', value: 'ENG' },
{ field: 'prsc', operator: 'in', dataType: 'string', value: ['1', '2', '3'] }
];
if (baseid.value !== 'all') {
baseFilters.unshift({ field: 'baseId', operator: 'eq', dataType: 'string', value: baseid.value });
}
const params1 = {
filter: {
logic: 'and',
filters: [
...baseFilters,
{ field: 'ttpwr', operator: 'isnotnull' }
]
},
group: [{ dir: 'desc', field: 'bldsttCcode', aggregates: [{ field: 'ttpwr', aggregate: 'sum' }] }]
};
const params2 = {
filter: {
logic: 'and',
filters: [...baseFilters]
},
group: [{ dir: 'desc', field: 'bldsttCcode' }]
};
try {
dataLoading.value = true;
const [res1, res2] = await Promise.all([
getVmsstbprptKendoList(params1),
getVmsstbprptKendoList(params2)
]);
const res1Data = res1?.data?.data || [];
const res2Data = res2?.data?.data || [];
if (res1Data.length > 0 || res2Data.length > 0) {
const ttpwrlist = res1Data.map((item: any) => ({
key: item.key,
ttpwr: transUnit(item.items[0].SUM_TTPWR)
}));
const engTotalList = res2Data.map((item: any) => ({
key: item.key,
engTotal: item.count
}));
const result: any = Object.values(
[...engTotalList, ...ttpwrlist].reduce((result: any, item: any) => {
const { key, engTotal = 0, ttpwr = 0 } = item;
const existingItem = result[key] || { key, engTotal: 0, ttpwr: 0 };
existingItem.bldstt = item.key == 0 ? '未建' : item.key == 1 ? '在建' : '已建';
existingItem.engTotal += engTotal;
existingItem.ttpwr += ttpwr;
return { ...result, [key]: existingItem };
}, {})
);
result.sort((a: any, b: any) => {
if (a.bldstt === '已建' && b.bldstt !== '已建') return -1;
else if (a.bldstt !== '已建' && b.bldstt === '已建') return 1;
else if (a.bldstt === '在建' && b.bldstt === '未建') return -1;
else if (a.bldstt === '未建' && b.bldstt === '在建') return 1;
else return 0;
});
const legendData: string[] = [];
const capData: { name: string; value: number }[] = [];
const countData: { name: string; value: number }[] = [];
result.forEach((item: any) => {
const name = item.bldstt;
if (name !== '未建') {
legendData.push(name);
countData.push({ name, value: Number(item.engTotal) });
capData.push({ name, value: Number(item.ttpwr).toFixed(2) });
}
});
const colors = ['#78c300', '#2196F3'];
const option = {
tooltip: {
trigger: 'item',
formatter: '{b}电站{a}: {c}',
position: 'right'
},
legend: {
data: legendData,
left: '60%',
orient: 'vertical',
top: 'center',
itemWidth: 20,
itemHeight: 12
},
color: colors,
series: [
{
name: '数量(座)',
type: 'pie',
radius: [0, '55%'],
label: { show: false },
labelLine: { show: false },
data: countData,
center: ['30%', '50%'],
itemStyle: {
borderRadius: 2,
borderColor: '#fff',
borderWidth: 2
}
},
{
name: '装机容量(万kW)',
type: 'pie',
radius: ['70%', '90%'],
labelLine: { length: 30 },
label: { show: false },
data: capData,
center: ['30%', '50%'],
itemStyle: {
borderRadius: 2,
borderColor: '#fff',
borderWidth: 2
}
}
]
};
if (chartInstance) {
chartInstance.setOption(option, true);
}
}
} catch (error) {
console.error('DevelopStatusChart getData error:', error);
} finally {
dataLoading.value = false;
}
};
const initChart = () => {
if (!chartContainer.value) return;
chartInstance = echarts.init(chartContainer.value);
const option = {
tooltip: {
trigger: 'item',
formatter: '{a} {b}: {c} ({d}%)',
position: 'right'
},
legend: {
data: ['已建', '在建'],
left: '60%',
orient: 'vertical',
top: 'center',
itemWidth: 20,
itemHeight: 12
},
color: ['#78c300', '#2196F3'],
series: [
{
name: '装机容量(万kW)',
type: 'pie',
radius: ['70%', '90%'],
center: ['30%', '50%'],
itemStyle: {
borderRadius: 2,
borderColor: '#fff',
borderWidth: 2
},
label: { show: false },
labelLine: { show: false },
data: []
},
{
name: '数量(座)',
type: 'pie',
radius: ['0%', '50%'],
center: ['30%', '50%'],
itemStyle: {
borderRadius: 2,
borderColor: '#fff',
borderWidth: 2
},
label: { show: false },
labelLine: { show: false },
data: []
}
]
};
chartInstance.setOption(option);
chartInstance.on('click', (params: any) => {
const currentJidiInfo = JidiSelectEventStore.selectedItem;
openModal({
defaultJidiInfo: {
baseid: currentJidiInfo?.wbsCode || 'all',
basename: currentJidiInfo?.wbsName || '全部基地'
},
seriesName: params.seriesName,
stateName: params.name,
defaultTab: params.name
});
});
window.addEventListener('resize', () => {
chartInstance?.resize();
});
};
onMounted(() => {
if (chartContainer.value) {
initChart();
}
});
watch(
() => JidiSelectEventStore.selectedItem,
newVal => {
if (newVal && newVal.wbsCode) {
baseid.value = newVal.wbsCode;
getData();
}
},
{ deep: true, immediate: true }
);
</script>
<style lang="scss" scoped>
.basic_body {
width: 100%;
height: 100%;
.chart-container {
width: 203px;
height: 100px;
}
}
</style>