440 lines
9.9 KiB
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>
|