WholeProcessPlatform/frontend/src/modules/shuidianhuangjingjieruMod/TwoLayer/HuanJingSJJRQK.vue

440 lines
9.9 KiB
Vue

<!-- HuanJingSJJRQK.vue -->
<template>
<div class="huanjing-sjjrqk">
<a-tabs v-model:activeKey="activeTab" @change="handleTabChange">
<a-tab-pane key="notAccess" tab="大中型已建在建电站" />
<a-tab-pane key="partAccess" tab="已接入电站运行数据" />
<a-tab-pane key="isAccess" tab="已开展全过程监测工作" />
</a-tabs>
<div class="content-wrapper">
<!-- 左侧饼图 -->
<div class="chart-section">
<div ref="chartContainer" class="chart-container"></div>
</div>
<!-- 右侧表格 -->
<div class="table-section">
<a-table
:columns="columns"
:data-source="tableData"
:pagination="false"
size="middle"
:customRow="customRow"
:loading="tableLoading"
class="custom-table"
/>
</div>
</div>
<!-- 详情弹窗 -->
<a-modal
v-model:open="detailModalVisible"
:title="detailModalTitle"
width="1200px"
:footer="null"
:destroy-on-close="true"
>
<component
v-if="detailModalVisible && detailComponent"
:is="detailComponent"
v-bind="detailProps"
/>
</a-modal>
</div>
</template>
<script lang="ts" setup>
import { ref, onMounted, onUnmounted, watch, shallowRef } from 'vue';
import * as echarts from 'echarts';
import { getVmsstbprptKendoList } from '@/api/home';
import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent';
defineOptions({
name: 'HuanJingSJJRQK'
});
const props = defineProps<{
dataDimensionVal: string;
name: string;
}>();
const JidiSelectEventStore = useJidiSelectEventStore();
const activeTab = ref(props.name || 'notAccess');
const chartContainer = ref<HTMLDivElement | null>(null);
let chartInstance: echarts.ECharts | null = null;
const tableLoading = ref(false);
const tableData = ref<any[]>([]);
const chartFilter = ref<string>('');
// 详情弹窗相关
const detailModalVisible = ref(false);
const detailModalTitle = ref('');
const detailComponent = shallowRef<any>(null);
const detailProps = ref<any>({});
// 表格列配置
const columns = ref([
{
title: '电站名称',
dataIndex: 'stnm',
key: 'stnm',
align: 'left'
},
{
title: '接入状态',
dataIndex: 'accessStatus',
key: 'accessStatus',
align: 'center'
},
{
title: '操作',
key: 'action',
align: 'center',
width: 120
}
]);
// 自定义行样式
const customRow = (record: any) => {
return {
onClick: () => {
handleRowClick(record);
}
};
};
// 处理表格行点击
const handleRowClick = async (record: any) => {
// 根据当前 Tab 打开不同的详情组件
if (activeTab.value === 'notAccess') {
// 大中型已建在建电站 - 打开电站详情
detailModalTitle.value = '电站详情';
// 这里需要动态导入对应的详情组件
// 暂时使用占位符
detailComponent.value = null;
detailProps.value = {
stcd: record.stcd,
stnm: record.stnm
};
detailModalVisible.value = true;
} else if (activeTab.value === 'partAccess') {
// 已接入电站运行数据
detailModalTitle.value = '运行数据详情';
detailComponent.value = null;
detailProps.value = {
stcd: record.stcd,
stnm: record.stnm
};
detailModalVisible.value = true;
} else if (activeTab.value === 'isAccess') {
// 已开展全过程监测工作
detailModalTitle.value = '监测数据详情';
detailComponent.value = null;
detailProps.value = {
stcd: record.stcd,
stnm: record.stnm
};
detailModalVisible.value = true;
}
};
// 获取图表和表格数据
const getData = async () => {
if (!props.dataDimensionVal) return;
const baseFilters: any[] = [
{ field: 'sttpCode', operator: 'eq', dataType: 'string', value: 'ENG' },
{ field: 'bldsttCcode', operator: 'in', dataType: 'string', value: ['1', '2'] }
];
if (props.dataDimensionVal !== 'all') {
baseFilters.unshift({ field: 'baseId', operator: 'eq', dataType: 'string', value: props.dataDimensionVal });
}
let params: any = {};
if (activeTab.value === 'notAccess') {
// 大中型已建在建电站
params = {
filter: {
logic: 'and',
filters: [
...baseFilters,
{ field: 'prsc', operator: 'in', dataType: 'string', value: ['1', '2', '3'] }
]
}
};
} else if (activeTab.value === 'partAccess') {
// 已接入电站运行数据
params = {
filter: {
logic: 'and',
filters: [
...baseFilters,
{ field: 'runState', operator: 'eq', dataType: 'number', value: 4 },
{ field: 'dtin', operator: 'eq', dataType: 'number', value: 1 }
]
}
};
} else if (activeTab.value === 'isAccess') {
// 已开展全过程监测工作
params = {
filter: {
logic: 'and',
filters: [
...baseFilters,
{ field: 'prsc', operator: 'in', dataType: 'string', value: ['1', '2', '3'] },
{ field: 'dtinEnv', operator: 'in', dataType: 'string', value: ['2'] }
]
}
};
}
try {
tableLoading.value = true;
const res = await getVmsstbprptKendoList(params);
const resData = res?.data?.data || [];
// 处理表格数据
tableData.value = resData.map((item: any) => ({
key: item.stcd,
stcd: item.stcd,
stnm: item.stnm,
accessStatus: getAccessStatus(item),
...item
}));
// 更新图表
updateChart(resData);
} catch (error) {
console.error('HuanJingSJJRQK getData error:', error);
} finally {
tableLoading.value = false;
}
};
// 获取接入状态文本
const getAccessStatus = (item: any) => {
if (activeTab.value === 'notAccess') {
return '已建在建';
} else if (activeTab.value === 'partAccess') {
return '已接入';
} else if (activeTab.value === 'isAccess') {
return '已监测';
}
return '-';
};
// 更新图表
const updateChart = (data: any[]) => {
if (!chartInstance) return;
// 按建设状态分组统计
const statusMap: Record<string, number> = {};
data.forEach((item: any) => {
const status = item.bldsttCcode === '1' ? '在建' : '已建';
statusMap[status] = (statusMap[status] || 0) + 1;
});
const chartData = Object.entries(statusMap).map(([name, value]) => ({
name,
value
}));
const option = {
tooltip: {
trigger: 'item',
formatter: '{b}: {c} ({d}%)'
},
legend: {
orient: 'vertical',
left: 'left',
top: 'center'
},
color: ['#78c300', '#2196F3'],
series: [
{
name: '电站数量',
type: 'pie',
radius: ['40%', '70%'],
center: ['60%', '50%'],
data: chartData,
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
},
label: {
show: true,
formatter: '{b}: {c}'
}
}
]
};
chartInstance.setOption(option, true);
// 添加点击事件
chartInstance.off('click');
chartInstance.on('click', (params: any) => {
chartFilter.value = params.name;
filterTableByChart(params.name);
});
};
// 根据图表筛选表格
const filterTableByChart = (status: string) => {
// 这里需要根据实际数据重新请求或过滤
// 暂时简单实现:高亮显示对应状态的数据
console.log('筛选状态:', status);
};
// 初始化图表
const initChart = () => {
if (!chartContainer.value) return;
chartInstance = echarts.init(chartContainer.value);
const option = {
tooltip: {
trigger: 'item',
formatter: '{b}: {c} ({d}%)'
},
legend: {
orient: 'vertical',
left: 'left',
top: 'center'
},
color: ['#78c300', '#2196F3'],
series: [
{
name: '电站数量',
type: 'pie',
radius: ['40%', '70%'],
center: ['60%', '50%'],
data: [],
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
},
label: {
show: true,
formatter: '{b}: {c}'
}
}
]
};
chartInstance.setOption(option);
};
// 处理 Tab 切换
const handleTabChange = (key: string) => {
activeTab.value = key;
chartFilter.value = '';
getData();
};
onMounted(() => {
if (chartContainer.value) {
initChart();
}
getData();
});
onUnmounted(() => {
if (chartInstance) {
chartInstance.dispose();
chartInstance = null;
}
});
// 监听 props 变化
watch(
() => props.dataDimensionVal,
() => {
getData();
}
);
// 监听窗口大小变化
const handleResize = () => {
if (chartInstance) {
chartInstance.resize();
}
};
onMounted(() => {
window.addEventListener('resize', handleResize);
});
onUnmounted(() => {
window.removeEventListener('resize', handleResize);
});
</script>
<style lang="scss" scoped>
.huanjing-sjjrqk {
padding: 20px;
.content-wrapper {
display: flex;
gap: 20px;
margin-top: 20px;
.chart-section {
flex: 0 0 400px;
.chart-container {
width: 100%;
height: 400px;
}
}
.table-section {
flex: 1;
}
}
.custom-table {
:deep(.ant-table) {
font-size: 13px;
border: 1px solid #e8e8e8;
.ant-table-thead {
> tr {
> th {
background-color: #e5eff8 !important;
color: #2f6b98;
font-weight: 600;
border: 1px solid #e8e8e8 !important;
padding: 6px 8px;
text-align: center;
}
}
}
.ant-table-tbody {
> tr {
> td {
border: 1px solid #e8e8e8;
padding: 6px 8px;
text-align: center;
}
&:hover {
background-color: #e6f7ff !important;
}
}
}
}
}
}
</style>