|
|
<template>
|
|
|
<div v-loading="loading" class="app-container vibration-board-page">
|
|
|
<VibrationBoardFilter
|
|
|
:selection-label="queryForm.selectionLabel"
|
|
|
:time-range="daterangeRecordTime"
|
|
|
:sampling-interval="queryForm.samplingInterval"
|
|
|
@update:time-range="setTimeRange"
|
|
|
@update:sampling-interval="setSamplingInterval"
|
|
|
@query="handleQuery"
|
|
|
/>
|
|
|
|
|
|
<el-row :gutter="16" class="mt-4 vibration-grid">
|
|
|
<el-col :xs="24" :lg="7" :xl="6">
|
|
|
<VibrationBoardDeviceTree :loading="treeLoading" :tree-data="monitorTreeOptions" :tree-props="treeProps" @node-click="handleTreeNodeClick" />
|
|
|
</el-col>
|
|
|
<el-col :xs="24" :lg="17" :xl="18">
|
|
|
<el-alert type="info" :closable="false" show-icon class="section-tip" :title="bandTip" />
|
|
|
|
|
|
<el-card shadow="never" class="chart-card">
|
|
|
<template #header>
|
|
|
<div class="card-header">
|
|
|
<div class="card-title-group">
|
|
|
<div class="card-title">位移流向图</div>
|
|
|
<div class="card-subtitle">观察设备样本在不同风险带之间的迁移方向,识别整体恶化路径和主要流量通道。</div>
|
|
|
</div>
|
|
|
<HelpButton title="位移流向图" :content="ADVANCED_HELP" />
|
|
|
</div>
|
|
|
</template>
|
|
|
<div ref="sankeyChartRef" class="chart-container-xl" />
|
|
|
</el-card>
|
|
|
|
|
|
<el-row :gutter="16" class="mt-4 vibration-grid">
|
|
|
<el-col :xs="24" :xl="12">
|
|
|
<el-card shadow="never" class="chart-card">
|
|
|
<template #header>
|
|
|
<div class="card-header">
|
|
|
<div class="card-title-group">
|
|
|
<div class="card-title">矩形树图</div>
|
|
|
<div class="card-subtitle">面积看数值规模,颜色看风险带,适合快速定位高值高影响设备。</div>
|
|
|
</div>
|
|
|
<HelpButton title="矩形树图" :content="ADVANCED_HELP" />
|
|
|
</div>
|
|
|
</template>
|
|
|
<div ref="treemapChartRef" class="chart-container-lg" />
|
|
|
</el-card>
|
|
|
</el-col>
|
|
|
</el-row>
|
|
|
</el-col>
|
|
|
</el-row>
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
|
<script setup lang="ts">
|
|
|
import { getDisplacementAdvancedData, type DisplacementAdvancedPageVO } from '@/api/ems/report/displacementBoard';
|
|
|
import HelpButton from '../components/HelpButton.vue';
|
|
|
import VibrationBoardFilter from '../components/VibrationBoardFilter.vue';
|
|
|
import VibrationBoardDeviceTree from '../components/VibrationBoardDeviceTree.vue';
|
|
|
import { ADVANCED_HELP } from '../components/helpContent';
|
|
|
import { useChartResize } from '../components/useChartResize';
|
|
|
import { useVibrationBoardQueryState } from '../components/useVibrationBoardQueryState';
|
|
|
import { toNumber } from '../components/vibrationBoardShared';
|
|
|
|
|
|
defineOptions({ name: 'VibrationBoardAdvanced' });
|
|
|
|
|
|
const sankeyChartRef = ref<HTMLElement>();
|
|
|
const treemapChartRef = ref<HTMLElement>();
|
|
|
// 高级页已收口为“桑基图 + 矩形树图”,
|
|
|
// 平行坐标图在位移专属语义下无意义,不再保留 parallelChartRef/解析逻辑。
|
|
|
const { getChart } = useChartResize(sankeyChartRef, treemapChartRef);
|
|
|
|
|
|
const {
|
|
|
loading,
|
|
|
treeLoading,
|
|
|
monitorTreeOptions,
|
|
|
treeProps,
|
|
|
daterangeRecordTime,
|
|
|
queryForm,
|
|
|
loadTree,
|
|
|
handleTreeNodeClick,
|
|
|
setTimeRange,
|
|
|
setSamplingInterval,
|
|
|
buildQuery
|
|
|
} = useVibrationBoardQueryState();
|
|
|
|
|
|
const advancedData = ref<DisplacementAdvancedPageVO>({
|
|
|
sankeyNodes: [],
|
|
|
sankeyLinks: [],
|
|
|
treemapItems: []
|
|
|
});
|
|
|
|
|
|
const riskBandColorMap: Record<string, string> = {
|
|
|
高位: '#ef4444',
|
|
|
关注: '#f59e0b',
|
|
|
平稳: '#10b981'
|
|
|
};
|
|
|
|
|
|
const bandTip = computed(() => {
|
|
|
const lowBandUpper = advancedData.value.lowBandUpper;
|
|
|
const focusBandUpper = advancedData.value.focusBandUpper;
|
|
|
if (lowBandUpper === undefined || focusBandUpper === undefined) {
|
|
|
return '高级分析会根据当前位移指标的风险分带,对设备群做迁移与占比分析。';
|
|
|
}
|
|
|
return `当前风险分带建议:平稳 ≤ ${lowBandUpper},关注区 ≤ ${focusBandUpper},其上视为高位。`;
|
|
|
});
|
|
|
|
|
|
const getNodeColor = (name?: string) => {
|
|
|
if (!name) {
|
|
|
return '#5b8ff9';
|
|
|
}
|
|
|
if (name.includes('高')) {
|
|
|
return riskBandColorMap['高位'];
|
|
|
}
|
|
|
if (name.includes('关注') || name.includes('预警')) {
|
|
|
return riskBandColorMap['关注'];
|
|
|
}
|
|
|
return riskBandColorMap['平稳'];
|
|
|
};
|
|
|
|
|
|
const renderCharts = () => {
|
|
|
const sankeyChart = getChart(sankeyChartRef);
|
|
|
const treemapChart = getChart(treemapChartRef);
|
|
|
const sankeyNodes = advancedData.value.sankeyNodes || [];
|
|
|
const sankeyLinks = advancedData.value.sankeyLinks || [];
|
|
|
const treemapItems = advancedData.value.treemapItems || [];
|
|
|
|
|
|
if (sankeyChart) {
|
|
|
if (!sankeyNodes.length || !sankeyLinks.length) {
|
|
|
sankeyChart.clear();
|
|
|
} else {
|
|
|
sankeyChart.setOption(
|
|
|
{
|
|
|
tooltip: {
|
|
|
trigger: 'item',
|
|
|
formatter: (params: any) => {
|
|
|
if (params.dataType === 'edge') {
|
|
|
return `${params.data.source} → ${params.data.target}<br/>流量: <b>${params.data.value}</b>`;
|
|
|
}
|
|
|
return `${params.name}`;
|
|
|
}
|
|
|
},
|
|
|
series: [
|
|
|
{
|
|
|
type: 'sankey',
|
|
|
left: 16,
|
|
|
right: 24,
|
|
|
top: 24,
|
|
|
bottom: 16,
|
|
|
nodeGap: 26,
|
|
|
emphasis: { focus: 'adjacency' },
|
|
|
data: sankeyNodes.map((item) => ({
|
|
|
name: item.name,
|
|
|
itemStyle: { color: getNodeColor(item.name) }
|
|
|
})),
|
|
|
links: sankeyLinks.map((item) => ({
|
|
|
source: item.source,
|
|
|
target: item.target,
|
|
|
value: toNumber(item.value)
|
|
|
})),
|
|
|
lineStyle: {
|
|
|
color: 'gradient',
|
|
|
curveness: 0.52,
|
|
|
opacity: 0.5
|
|
|
},
|
|
|
label: { color: '#334155', fontSize: 12 }
|
|
|
}
|
|
|
]
|
|
|
},
|
|
|
true
|
|
|
);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if (treemapChart) {
|
|
|
if (!treemapItems.length) {
|
|
|
treemapChart.clear();
|
|
|
} else {
|
|
|
treemapChart.setOption(
|
|
|
{
|
|
|
tooltip: {
|
|
|
formatter: (params: any) =>
|
|
|
`${params.name}<br/>值: <b>${Number(params.value).toFixed(2)}</b><br/>风险带: <b>${params.data.levelTag || '--'}</b>`
|
|
|
},
|
|
|
series: [
|
|
|
{
|
|
|
type: 'treemap',
|
|
|
roam: false,
|
|
|
breadcrumb: { show: false },
|
|
|
visibleMin: 8,
|
|
|
data: treemapItems.map((item) => ({
|
|
|
name: item.name,
|
|
|
value: toNumber(item.value),
|
|
|
levelTag: item.levelTag,
|
|
|
itemStyle: {
|
|
|
color: riskBandColorMap[item.levelTag || ''] || '#5b8ff9',
|
|
|
borderColor: '#fff',
|
|
|
borderWidth: 2,
|
|
|
gapWidth: 2
|
|
|
}
|
|
|
})),
|
|
|
upperLabel: { show: false },
|
|
|
label: {
|
|
|
show: true,
|
|
|
color: '#fff',
|
|
|
formatter: (params: any) => `${params.name}\n${Number(params.value).toFixed(1)}`
|
|
|
}
|
|
|
}
|
|
|
]
|
|
|
},
|
|
|
true
|
|
|
);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 高级页仅展示桑基图与矩形树图,不再维护平行坐标图。
|
|
|
};
|
|
|
|
|
|
const handleQuery = async () => {
|
|
|
loading.value = true;
|
|
|
try {
|
|
|
const { data } = await getDisplacementAdvancedData(buildQuery());
|
|
|
advancedData.value = data || {
|
|
|
sankeyNodes: [],
|
|
|
sankeyLinks: [],
|
|
|
treemapItems: []
|
|
|
};
|
|
|
await nextTick();
|
|
|
renderCharts();
|
|
|
} finally {
|
|
|
loading.value = false;
|
|
|
}
|
|
|
};
|
|
|
|
|
|
onMounted(async () => {
|
|
|
await loadTree();
|
|
|
await handleQuery();
|
|
|
});
|
|
|
</script>
|
|
|
|
|
|
<style scoped lang="scss">
|
|
|
@import '../components/vibrationBoardReport.scss';
|
|
|
</style>
|