|
|
<!DOCTYPE html>
|
|
|
<html lang="zh-CN">
|
|
|
|
|
|
<head>
|
|
|
<meta charset="UTF-8">
|
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
|
<title>tool</title>
|
|
|
<script type="text/javascript" src="./three/three.min.js"></script>
|
|
|
<script type="text/javascript" src="./three/OrbitControls.js"></script>
|
|
|
<script type="text/javascript" src="./three/Lut.js"></script>
|
|
|
<script src="./js/vue.global.min.js"></script>
|
|
|
<script src="./js/antd.min.js"></script>
|
|
|
<link rel="stylesheet" href="./css/antd.min.css">
|
|
|
<link rel="stylesheet" href="./css/element-plus.css">
|
|
|
<script src="./js/element-plus.js"></script>
|
|
|
<!-- 引入 Element Plus 中文语言包 -->
|
|
|
<script src="./js/zh-cn.min.js"></script>
|
|
|
<script src="./js/echarts.min.js"></script>
|
|
|
<script src="./js/echarts-gl.min.js"></script>
|
|
|
<!-- <script src="https://cdn.jsdelivr.net/npm/echarts-gl@2.0.9/dist/echarts-gl.min.js"></script> -->
|
|
|
<link rel="stylesheet" href="./css/common.css">
|
|
|
<script type="text/javascript" src="./js/axios.min.js"></script>
|
|
|
<style>
|
|
|
body {
|
|
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
|
|
padding: 10px;
|
|
|
background-color: #f5f5f5;
|
|
|
}
|
|
|
</style>
|
|
|
</head>
|
|
|
|
|
|
<body>
|
|
|
<div id="app">
|
|
|
<div class="content">
|
|
|
<!-- 树菜单 -->
|
|
|
<div ref="treeMenu" v-if="treeMenuInfo.menuVisible" class="context-menu"
|
|
|
:style="{ left: `${treeMenuInfo.menuX}px`, top: `${treeMenuInfo.menuY}px` }">
|
|
|
<div v-if="treeMenuInfo.data.isRoot" @click="addMonitor(treeMenuInfo.data)">新增监测点</div>
|
|
|
<div @click="editNodeItem(treeMenuInfo.data)">编辑</div>
|
|
|
<a-popconfirm title="确定要删除吗?" ok-text="确定" cancel-text="取消"
|
|
|
@confirm="deleteNodeItem(treeMenuInfo.data)">
|
|
|
<div>删除</div>
|
|
|
</a-popconfirm>
|
|
|
</div>
|
|
|
<div class="tree-content">
|
|
|
<div class="input-box">
|
|
|
<a-input placeholder="名称" v-model:value="searchValue" @change="search">
|
|
|
</a-input>
|
|
|
</div>
|
|
|
<div class="tree-box">
|
|
|
<el-tree ref="treeRef" node-key="key" check-strictly :check-on-click-node="false" :data="treeData"
|
|
|
:props="defaultProps" :load="onLoadData" lazy v-model:checked-keys="checkedKeys1"
|
|
|
:current-node-key="selectedKey" :show-checkbox="typeOfCheckable.includes(activeKey)"
|
|
|
@check="checkTree" @node-click="selectTree" highlight-current :filter-node-method="filterNode"
|
|
|
@node-contextmenu="handleRightClick" />
|
|
|
</div>
|
|
|
<div class="bottom-btns">
|
|
|
<a-button type="primary" size="small" @click="isImportMonitorModalShow=true"> 导入监测点 </a-button>
|
|
|
<a-button style="margin-left: 4px;" type="primary" size="small" @click="addSite"> 新增站点 </a-button>
|
|
|
</div>
|
|
|
</div>
|
|
|
<div class="right-content">
|
|
|
<!-- tab切换 -->
|
|
|
<a-tabs v-model:activeKey="activeKey" @change="(key)=>activeKey=key">
|
|
|
<a-tab-pane v-for="item in tabsArr" :key="item.key" :tab="item.tab"></a-tab-pane>
|
|
|
</a-tabs>
|
|
|
<div class="panel-views">
|
|
|
<div v-if="activeKey === 'historyTrend'" key="historyTrend" class="sub-content history-trend">
|
|
|
<!-- 历史趋势 -->
|
|
|
<div class="top-selector">
|
|
|
<el-date-picker v-model="dateRange" style="width: 360px" class="custom-date-picker"
|
|
|
value-format="YYYY-MM-DD HH:mm:ss" type="datetimerange" range-separator="至"
|
|
|
start-placeholder="开始日期" end-placeholder="结束日期" :disabled-date="disabledDate"
|
|
|
@panel-change="handlePanelChange" />
|
|
|
</div>
|
|
|
<div class="trend-graph-container">
|
|
|
<div class="trend-item" v-for="item in trendGraphData" :key="item.id">
|
|
|
<div class="title">
|
|
|
监测点:{{ item.id }}
|
|
|
</div>
|
|
|
<div class="line-graph" :ref="(el) => trendGraphRefs(el, item.id)"></div>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
<div v-if="activeKey === 'alarmConfig'" key="alarmConfig" class="sub-content alarm-config">
|
|
|
<!-- 告警配置 -->
|
|
|
<div class="search-bar">
|
|
|
<div class="search-item">
|
|
|
<span>放电类型:</span>
|
|
|
<a-select v-model:value="alarmFilters.pdTypes" :options="pdTypeOps" mode="tags"
|
|
|
placeholder="请选择" style="width: 300px">
|
|
|
</div>
|
|
|
<div class="search-item">
|
|
|
<span>时间:</span>
|
|
|
<el-date-picker v-model="alarmFilters.times" style="width: 360px"
|
|
|
class="custom-date-picker" value-format="YYYY-MM-DD HH:mm:ss" type="datetimerange"
|
|
|
range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期" />
|
|
|
</div>
|
|
|
<div class="break"></div>
|
|
|
<div class="search-item">
|
|
|
<span>是否复归:</span>
|
|
|
<a-radio-group :options="cancelOps" v-model:value="alarmFilters.isCancel" />
|
|
|
</div>
|
|
|
<div class="search-item">
|
|
|
<a-button type="primary" size="small" @click="fetchAlarmGridData">查询</a-button>
|
|
|
</div>
|
|
|
<div class="search-item">
|
|
|
<a-button size="small" @click="initAlarmGridData">重置</a-button>
|
|
|
</div>
|
|
|
</div>
|
|
|
<div class="grid-content">
|
|
|
<a-table :columns="columns" :data-source="dataSource" :pagination="pagination"
|
|
|
:loading="configLoading" @change="handleTableChange" :scroll="{ y: 460 }">
|
|
|
<template #name1="{ text }">
|
|
|
{{pdTypeOps.find(item=>item.value==text).label}}
|
|
|
</template>
|
|
|
<template #name2="{ text }">
|
|
|
{{ cancelOps.find(item=>item.value==text).label}}
|
|
|
</template>
|
|
|
</a-table>
|
|
|
</div>
|
|
|
</div>
|
|
|
<div v-if="activeKey === 'countPRPD'" key="countPRPD" class="sub-content total-prpd">
|
|
|
<!-- 累计PRPD -->
|
|
|
<div class="trend-box"></div>
|
|
|
<div class="prpd-box">
|
|
|
<!-- 累计PRPD组件 -->
|
|
|
<total-prpd class="total-prpd-item" v-for="(item,index) in totalPrpds" :key="index"
|
|
|
:data="item" />
|
|
|
</div>
|
|
|
</div>
|
|
|
<div v-if="activeKey === 'prpdAndPrps'" key="prpdAndPrps" class="sub-content prpd-and-prps">
|
|
|
<!-- PRPD/PRPS -->
|
|
|
<div class="trend-box"></div>
|
|
|
<div class="prpd-and-prps-box">
|
|
|
<prpd-and-prps class="prpd-and-prps-item" v-for="(item,index) in 1" :key="index"
|
|
|
:sort="index" />
|
|
|
</div>
|
|
|
</div>
|
|
|
<div v-if="activeKey === 'eventCount'" key="eventCount" class="sub-content">
|
|
|
<!-- 事件统计 -->
|
|
|
事件统计
|
|
|
</div>
|
|
|
<div v-if="activeKey === 'config'" key="config" class="sub-content config-page">
|
|
|
<!-- 配置页面 -->
|
|
|
<div class="station-config">
|
|
|
<div class="title">站点告警配置</div>
|
|
|
<div class="station">
|
|
|
<span>站点:</span>
|
|
|
<a-select v-model:value="stationName1" size="small" style="width: 200px">
|
|
|
<a-select-option v-for="item in treeData" :key="item.key" :value="item.stationName">
|
|
|
{{ item.stationName }}
|
|
|
</a-select-option>
|
|
|
</a-select>
|
|
|
</div>
|
|
|
<div class="delete-bar">
|
|
|
<span class="delete-time">
|
|
|
<span class="label">清除告警时间段:</span>
|
|
|
<el-date-picker v-model="deleteAlarmTimes" style="width: 360px"
|
|
|
class="custom-date-picker" value-format="YYYY-MM-DD HH:mm:ss"
|
|
|
type="datetimerange" range-separator="至" start-placeholder="开始日期"
|
|
|
end-placeholder="结束日期" />
|
|
|
</span>
|
|
|
<a-popconfirm title="确定删除?" ok-text="是" cancel-text="否" @confirm="deleteAlarmConfirm">
|
|
|
<a href="#">删除</a>
|
|
|
</a-popconfirm>
|
|
|
</div>
|
|
|
<el-upload action="#" :http-request="alarmCustomUpload" :show-file-list="false" :limit="1"
|
|
|
accept=".csv,.xlsx,.xls" :before-upload="alarmBeforeUpload">
|
|
|
<a-button type="primary" size="small">导入告警</el-button>
|
|
|
</el-upload>
|
|
|
</div>
|
|
|
<div class="path-config">
|
|
|
<div class="title">路径配置</div>
|
|
|
<div class="path-item" v-for="item in allPathCongfigs" :key="item.key">
|
|
|
<div class="name">{{item.label}} :</div>
|
|
|
<div class="row">
|
|
|
<el-input v-model="item.value" style="width: 560px" placeholder="请输入路径" />
|
|
|
</div>
|
|
|
<a-button size="small" type="primary" style="margin-right: 4px;"
|
|
|
@click="savePathConfig(item)">保存</a-button>
|
|
|
<a-button size="small" @click="resetPathConfig(item.key)">重置</a-button>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
<!-- 导入监测点弹框 -->
|
|
|
<a-modal width="550px" :destroyOnClose="true" :visible="isImportMonitorModalShow" title="导入监测点"
|
|
|
@ok="onImportMonitor" @cancel="isImportMonitorModalShow=false"
|
|
|
:confirmLoading="importMonitorModalloading"></a-modal>
|
|
|
<!-- 站点弹框 -->
|
|
|
<a-modal width="550px" :destroyOnClose="true" :visible="isSiteModalShow"
|
|
|
:title="isAddTypeOfSiteModal?'新增站点':'编辑站点'" @cancel="isSiteModalShow=false">
|
|
|
<a-form layout=" vertical" ref="siteModalRef" :model="siteModalForm">
|
|
|
<a-form-item label="站点名称" name="stationName" :rules="[
|
|
|
{
|
|
|
required: true,
|
|
|
message: '请输入站点名称',
|
|
|
},
|
|
|
{
|
|
|
max: 20,
|
|
|
message: '最多输入20个字符',
|
|
|
},
|
|
|
]">
|
|
|
<a-input v-model:value="siteModalForm.stationName" placeholder="请输入" />
|
|
|
</a-form-item>
|
|
|
<a-form-item label="背景图路径" name="img" :rules="[
|
|
|
{
|
|
|
required: true,
|
|
|
message: '请输入背景图路径',
|
|
|
},
|
|
|
]">
|
|
|
<a-input v-model:value="siteModalForm.img" placeholder="请输入" />
|
|
|
</a-form-item>
|
|
|
</a-form>
|
|
|
<template #footer>
|
|
|
<a-button @click="isSiteModalShow=false">关闭</a-button>
|
|
|
<a-button type="primary" @click="onSiteModalSubmit" :loading="siteModalloading">确定</a-button>
|
|
|
</template>
|
|
|
</a-modal>
|
|
|
<!-- 监测点弹框 -->
|
|
|
<a-modal width="550px" :destroyOnClose="true" :visible="isMonitorModalShow"
|
|
|
:title="isAddTypeOfMonitorModal?'新增监测点':'编辑监测点'" @cancel="isMonitorModalShow=false">
|
|
|
<a-form layout=" vertical" ref="monitorModalRef" :model="monitorModalForm">
|
|
|
<a-form-item label="站点名称" name="stationName" :rules="[
|
|
|
{
|
|
|
required: true,
|
|
|
message: '请输入监测点名称',
|
|
|
},
|
|
|
]" disabled>
|
|
|
<a-input v-model:value="monitorModalForm.stationName" disabled />
|
|
|
</a-form-item>
|
|
|
<a-form-item label="监测点Key" name="monitorKey" :rules="[
|
|
|
{
|
|
|
required: true,
|
|
|
message: '请输入监测点Key',
|
|
|
},
|
|
|
{
|
|
|
max: 20,
|
|
|
message: '最多输入20个字符',
|
|
|
},
|
|
|
]">
|
|
|
<a-input v-model:value="monitorModalForm.monitorKey" placeholder="请输入"
|
|
|
:disabled="!isAddTypeOfMonitorModal" />
|
|
|
</a-form-item>
|
|
|
<a-form-item label="监测点名称" name="name" :rules="[
|
|
|
{
|
|
|
required: true,
|
|
|
message: '请输入监测点名称',
|
|
|
},
|
|
|
{
|
|
|
max: 20,
|
|
|
message: '最多输入20个字符',
|
|
|
},
|
|
|
]">
|
|
|
<a-input v-model:value="monitorModalForm.name" placeholder="请输入" />
|
|
|
</a-form-item>
|
|
|
</a-form>
|
|
|
<template #footer>
|
|
|
<a-button @click="isMonitorModalShow=false">关闭</a-button>
|
|
|
<a-button type="primary" @click="onMonitorModalSubmit" :loading="monitorModalLoading">确定</a-button>
|
|
|
</template>
|
|
|
</a-modal>
|
|
|
</div>
|
|
|
<script>
|
|
|
axios.defaults.baseURL = 'http://192.168.1.80:9501'; // 临时服务地址
|
|
|
axios.defaults.timeout = 10000;
|
|
|
const findParentByKey = (tree, targetKey) => {
|
|
|
for (const parent of tree) {
|
|
|
// 检查子节点
|
|
|
if (parent?.children?.length) {
|
|
|
for (const child of parent.children) {
|
|
|
if (child.key === targetKey) {
|
|
|
return parent.stationName; // 返回父节点
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
return null;
|
|
|
}
|
|
|
const formatTreeData = (node) => {
|
|
|
return {
|
|
|
...node.data,
|
|
|
children: node.childNodes?.map(child => formatTreeData(child)) || []
|
|
|
};
|
|
|
};
|
|
|
// 生成正弦波形
|
|
|
const generateSineWaveData = () => {
|
|
|
const dataPoints = [];
|
|
|
// 遍历0到360度,每1度取一个点
|
|
|
for (let angle = 0; angle <= 360; angle++) {
|
|
|
// 将角度转换为弧度
|
|
|
const radian = angle * Math.PI / 180;
|
|
|
// 计算增益值
|
|
|
const gain = 40 * Math.sin(radian) - 40;
|
|
|
// 将 [相位, 增益] 对添加到数组中
|
|
|
// 使用 toFixed(2) 来保留两位小数,避免浮点数精度问题,并将其转换为数字类型
|
|
|
dataPoints.push([angle, parseFloat(gain.toFixed(2))]);
|
|
|
}
|
|
|
return dataPoints;
|
|
|
}
|
|
|
const { createApp, ref, onMounted, unref, watch, reactive, computed, nextTick, onUnmounted, components } = Vue;
|
|
|
const { message } = antd;
|
|
|
// 累计prpd组件
|
|
|
const totalPrpd = {
|
|
|
template: `<div ref="prpdBoxRef" style="width: 100%; height: 100%;"></div>`,
|
|
|
props: ['data'], // 接收父组件传递的数据
|
|
|
data() {
|
|
|
return {
|
|
|
}
|
|
|
},
|
|
|
methods: {
|
|
|
initPrpd() {
|
|
|
const chartDom = this.$refs.prpdBoxRef;
|
|
|
this.myChart = echarts.init(chartDom);
|
|
|
const option = {
|
|
|
backgroundColor: '#ffffff', // 设置背景色为深色,与图片相似
|
|
|
title: {
|
|
|
text: 'PRPD',
|
|
|
left: 'center',
|
|
|
top: '2%',
|
|
|
textStyle: {
|
|
|
color: '#444444', // 标题文字颜色
|
|
|
fontSize: 20
|
|
|
}
|
|
|
},
|
|
|
|
|
|
tooltip: {
|
|
|
trigger: 'axis',
|
|
|
formatter: function (params) {
|
|
|
// 自定义提示框内容,显示x和y的值
|
|
|
return `相位: ${params[0].value[0]}<br/>幅值: ${params[0].value[1]}`;
|
|
|
},
|
|
|
axisPointer: {
|
|
|
type: 'cross',
|
|
|
label: {
|
|
|
backgroundColor: '#6a7985'
|
|
|
}
|
|
|
}
|
|
|
},
|
|
|
grid: {
|
|
|
left: '10%',
|
|
|
right: '10%',
|
|
|
top: '15%',
|
|
|
bottom: '15%',
|
|
|
containLabel: true
|
|
|
},
|
|
|
xAxis: {
|
|
|
type: 'value',
|
|
|
name: '相位',
|
|
|
nameTextStyle: {
|
|
|
color: '#000000' // <-- 将轴名称“相位”的颜色设置为黑色
|
|
|
},
|
|
|
nameLocation: 'middle',
|
|
|
nameGap: 30, // 调整名称与轴线的距离
|
|
|
min: 0,
|
|
|
max: 360,
|
|
|
interval: 90, // 固定刻度为0, 90, 180, 270, 360
|
|
|
axisLabel: {
|
|
|
color: '#000' // X轴刻度文字颜色
|
|
|
},
|
|
|
axisLine: {
|
|
|
lineStyle: {
|
|
|
color: '#ccc' // X轴线颜色
|
|
|
}
|
|
|
},
|
|
|
splitLine: {
|
|
|
show: true,
|
|
|
lineStyle: {
|
|
|
color: '#ccc', // X轴网格线颜色
|
|
|
type: 'solid'
|
|
|
}
|
|
|
}
|
|
|
},
|
|
|
yAxis: {
|
|
|
type: 'value',
|
|
|
name: '幅值',
|
|
|
nameLocation: 'middle',
|
|
|
nameTextStyle: {
|
|
|
color: '#000000' // <-- 将轴名称“相位”的颜色设置为黑色
|
|
|
},
|
|
|
nameRotate: 90, // Y轴名称旋转
|
|
|
nameGap: 30, // 调整名称与轴线的距离
|
|
|
min: -80,
|
|
|
max: 0,
|
|
|
interval: 20, // 固定刻度为 -80, -60, -40, -20, 0
|
|
|
axisLabel: {
|
|
|
color: '#000', // Y轴刻度文字颜色
|
|
|
formatter: function (value) {
|
|
|
// 根据图片中的刻度值,手动设置Y轴刻度显示
|
|
|
if (value === -80) return '-80';
|
|
|
if (value === -60) return '-60'; // 图片中-60没有显示数字
|
|
|
if (value === -40) return '-40';
|
|
|
if (value === -20) return '-20';
|
|
|
if (value === 0) return '0';
|
|
|
return value;
|
|
|
}
|
|
|
},
|
|
|
axisLine: {
|
|
|
lineStyle: {
|
|
|
color: '#ccc' // Y轴线颜色
|
|
|
}
|
|
|
},
|
|
|
splitLine: {
|
|
|
show: true,
|
|
|
lineStyle: {
|
|
|
color: '#ccc', // Y轴网格线颜色
|
|
|
type: 'solid'
|
|
|
}
|
|
|
}
|
|
|
},
|
|
|
// 颜色区分
|
|
|
visualMap: {
|
|
|
dimension: 2,
|
|
|
show: false,
|
|
|
inRange: {
|
|
|
color: ['#007ACC', '#FF4500'] // 例如:从浅蓝色到深蓝色
|
|
|
},
|
|
|
},
|
|
|
series: [
|
|
|
{
|
|
|
name: '正弦波形', // 系列名称
|
|
|
type: 'line', // 图表类型为折线图
|
|
|
smooth: true, // 开启平滑曲线
|
|
|
showSymbol: false, // 不显示数据点符号
|
|
|
lineStyle: {
|
|
|
width: 2 // 调整线条宽度
|
|
|
},
|
|
|
data: generateSineWaveData() // 调用函数生成数据
|
|
|
},
|
|
|
{
|
|
|
name: 'PRPD数据',
|
|
|
type: 'scatter', // 使用折线图来模拟曲线
|
|
|
symbolSize: 2.5,
|
|
|
data: [],
|
|
|
},
|
|
|
]
|
|
|
};
|
|
|
this.myChart.setOption(option);
|
|
|
this.resizeObserver = new ResizeObserver(() => {
|
|
|
this.myChart?.resize();
|
|
|
});
|
|
|
this.resizeObserver.observe(chartDom);
|
|
|
}
|
|
|
},
|
|
|
created() {
|
|
|
this.myChart = null
|
|
|
this.resizeObserver = null
|
|
|
},
|
|
|
mounted() {
|
|
|
this.$nextTick(() => {
|
|
|
this.initPrpd()
|
|
|
})
|
|
|
fetch('./three/prpd.json') // JSON文件路径
|
|
|
.then(response => response.json()) // 解析为JSON对象
|
|
|
.then(data => {
|
|
|
let index = 0;
|
|
|
const intervalId = setInterval(() => {
|
|
|
const curret = data[index].map(item => {
|
|
|
|
|
|
const y = Number(item[0]) - 80
|
|
|
return [item[1], y, item[2]]
|
|
|
});
|
|
|
const countArr = data[index].map(item => item[2])
|
|
|
const minCount = Math.min(...countArr)
|
|
|
const maxCount = Math.max(...countArr)
|
|
|
this.myChart.setOption({
|
|
|
series: [{
|
|
|
name: 'PRPD数据',
|
|
|
data: curret
|
|
|
}],
|
|
|
visualMap: {
|
|
|
min: minCount,
|
|
|
max: maxCount
|
|
|
}
|
|
|
}, { notMerge: false });
|
|
|
index = (index + 1) % data.length; // 循环索引
|
|
|
}, 1000);
|
|
|
})
|
|
|
.catch(error => console.error('加载JSON失败:', error));
|
|
|
},
|
|
|
}
|
|
|
// 放在vue中的data会卡顿
|
|
|
const prpsData = [
|
|
|
{
|
|
|
prpsChart: null,
|
|
|
prpsChartOps: null
|
|
|
},
|
|
|
{
|
|
|
prpsChart: null,
|
|
|
prpsChartOps: null
|
|
|
},
|
|
|
{
|
|
|
prpsChart: null,
|
|
|
prpsChartOps: null
|
|
|
},
|
|
|
{
|
|
|
prpsChart: null,
|
|
|
prpsChartOps: null
|
|
|
},
|
|
|
{
|
|
|
prpsChart: null,
|
|
|
prpsChartOps: null
|
|
|
},
|
|
|
{
|
|
|
prpsChart: null,
|
|
|
prpsChartOps: null
|
|
|
}
|
|
|
]
|
|
|
// const prpdAndPrps = {
|
|
|
// template: `<div ref='prpsRef' style="width: 100%; height: 100%;">prpd/prps组件</div>`,
|
|
|
// data() {
|
|
|
// return {
|
|
|
// len: 0,
|
|
|
// timer: 0
|
|
|
// };
|
|
|
// },
|
|
|
// props: {
|
|
|
// sort: {
|
|
|
// type: Number,
|
|
|
// default: 0
|
|
|
// }
|
|
|
// },
|
|
|
// async mounted() {
|
|
|
// this.initChart(); // 初始化 ECharts 实例和基础配置
|
|
|
// await fetch('./three/prps copy.json') // JSON文件路径
|
|
|
// .then(response => response.json()) // 解析为JSON对象
|
|
|
// .then(data => {
|
|
|
// let databox = []
|
|
|
// for (let i = 0; i < 5000; i++) {
|
|
|
// databox[i] = -100;
|
|
|
|
|
|
// }
|
|
|
// const fullData = databox.concat(data); // 直接使用导入的 JSON 数
|
|
|
// this.dispose([...fullData]); // 启动动画
|
|
|
// })
|
|
|
|
|
|
// .catch(error => console.error('加载JSON失败:', error));
|
|
|
// },
|
|
|
// beforeDestroy() {
|
|
|
// // 在组件销毁前,清除定时器并销毁 ECharts 实例
|
|
|
// if (this.timer) {
|
|
|
// clearTimeout(this.timer);
|
|
|
// }
|
|
|
// },
|
|
|
// methods: {
|
|
|
// initChart() {
|
|
|
// if (this.$refs.prpsRef) {
|
|
|
// prpsData[this.sort].prpsChart = echarts.init(this.$refs.prpsRef);
|
|
|
// // 初始化一次不变的 ECharts 配置
|
|
|
// prpsData[this.sort].prpsChartOps = {
|
|
|
// backgroundColor: '#111',
|
|
|
// title: {
|
|
|
// text: 'PRPS',
|
|
|
// left: 'center',
|
|
|
// top: 10,
|
|
|
// textStyle: {
|
|
|
// fontSize: 16,
|
|
|
// color: 'rgba(255, 255, 255, 0.7)'
|
|
|
// }
|
|
|
// },
|
|
|
// animation: false,
|
|
|
// tooltip: {
|
|
|
// show: false,
|
|
|
// },
|
|
|
// toolbox: {
|
|
|
// show: true,
|
|
|
// orient: 'horizontal',
|
|
|
// top: 0,
|
|
|
// right: '0',
|
|
|
// showTitle: false,
|
|
|
// iconStyle: {
|
|
|
// borderColor: '#fff'
|
|
|
// },
|
|
|
// emphasis: {
|
|
|
// show: false,
|
|
|
// iconStyle: {
|
|
|
// borderColor: '#fff'
|
|
|
// }
|
|
|
// },
|
|
|
// feature: {
|
|
|
// mark: { show: true },
|
|
|
// restore: { show: true },
|
|
|
// saveAsImage: { show: true }
|
|
|
// }
|
|
|
// },
|
|
|
// visualMap: {
|
|
|
// min: -20,
|
|
|
// max: 80,
|
|
|
// show: false,
|
|
|
// itemWidth: 5,
|
|
|
// orient: "vertical",
|
|
|
// inRange: {
|
|
|
// color: ['transparent', '#00ee00', '#eeee00', '#ee0000', '#4e0211']
|
|
|
// },
|
|
|
// formatter: function (value) {
|
|
|
// return parseInt(value - 80);
|
|
|
// }
|
|
|
// },
|
|
|
// xAxis3D: {
|
|
|
// type: 'value',
|
|
|
// min: 0,
|
|
|
// max: 50,
|
|
|
// splitNumber: 5,
|
|
|
// name: '周期', // 注意:$.i18n.prop 如果是 jQuery i18n,需要确保引入
|
|
|
// nameGap: 24,
|
|
|
// axisLabel: {
|
|
|
// fontSize: 14,
|
|
|
// formatter: function (value, index) { value = 50 - value; if (value >= 0) { return value; } }
|
|
|
// },
|
|
|
// },
|
|
|
// yAxis3D: {
|
|
|
// type: 'value',
|
|
|
// min: 0,
|
|
|
// max: 360,
|
|
|
// splitNumber: 4,
|
|
|
// interval: 90,
|
|
|
// name: '相位',
|
|
|
// nameGap: 24,
|
|
|
// splitArea: {
|
|
|
// interval: 4,
|
|
|
// },
|
|
|
// axisLabel: {
|
|
|
// fontSize: 14,
|
|
|
// },
|
|
|
// },
|
|
|
// zAxis3D: {
|
|
|
// type: 'value',
|
|
|
// min: 0,
|
|
|
// max: 80,
|
|
|
// scale: true,
|
|
|
// splitNumber: 4,
|
|
|
// name: '幅值',
|
|
|
// nameGap: 24,
|
|
|
// axisLabel: {
|
|
|
// fontSize: 14,
|
|
|
// formatter: function (value, index) {
|
|
|
// if (value >= 0) {
|
|
|
// return value - 80;
|
|
|
// }
|
|
|
// }
|
|
|
// },
|
|
|
// },
|
|
|
// grid3D: {
|
|
|
// boxHeight: 100,
|
|
|
// boxWidth: 120,
|
|
|
// boxDepth: 100,
|
|
|
// axisLine: {
|
|
|
// lineStyle: {
|
|
|
// color: '#fff',
|
|
|
// opacity: 0.1
|
|
|
// }
|
|
|
// },
|
|
|
// axisPointer: {
|
|
|
// show: false,
|
|
|
// lineStyle: {
|
|
|
// color: '#fff'
|
|
|
// },
|
|
|
// },
|
|
|
// viewControl: {
|
|
|
// distance: 260,
|
|
|
// minDistance: 40,
|
|
|
// maxDistance: 400,
|
|
|
// rotateSensitivity: [1, 1],
|
|
|
// zoomSensitivity: 0,
|
|
|
// panSensitivity: 0,
|
|
|
// panMouseButton: "middle",
|
|
|
// rotateMouseButton: "left",
|
|
|
// orthographicSize: 150,
|
|
|
// maxOrthographicSize: 400,
|
|
|
// minOrthographicSize: 20,
|
|
|
// center: [0, -10, 0],
|
|
|
// minBeta: 30,
|
|
|
// maxBeta: 180,
|
|
|
// minAlpha: -90,
|
|
|
// maxAlpha: 90,
|
|
|
// projection: "perspective",
|
|
|
// autoRotateDirection: "cw",
|
|
|
// autoRotateAfterStill: 3,
|
|
|
// damping: 0.8
|
|
|
// },
|
|
|
// light: {
|
|
|
// main: { intensity: 1.2 },
|
|
|
// ambient: { intensity: 0.3 }
|
|
|
// }
|
|
|
// },
|
|
|
// roam: false,
|
|
|
// // series 放在这里作为初始结构,data 留空
|
|
|
// series: [{
|
|
|
// type: 'bar3D',
|
|
|
// data: [], // 初始数据为空
|
|
|
// shading: 'color',
|
|
|
// label: {
|
|
|
// show: false,
|
|
|
// textStyle: {
|
|
|
// fontSize: 16,
|
|
|
// borderWidth: 1
|
|
|
// },
|
|
|
// formatter: function (param) {
|
|
|
// return parseInt(param.value[2] - 80);
|
|
|
// }
|
|
|
// },
|
|
|
// itemStyle: {
|
|
|
// opacity: 0.8,
|
|
|
// },
|
|
|
// silent: true,
|
|
|
// emphasis: {
|
|
|
// label: { show: false },
|
|
|
// }
|
|
|
// }]
|
|
|
// };
|
|
|
|
|
|
// // 首次设置 ECharts option
|
|
|
// prpsData[this.sort].prpsChart.setOption(prpsData[this.sort].prpsChartOps);
|
|
|
// }
|
|
|
// },
|
|
|
// // 处理数据,生成 ECharts 所需的三维坐标格式
|
|
|
// deal(arr, dbm) {
|
|
|
// for (let i = 0; i < 5000; i++) {
|
|
|
// let j = parseInt(i / 100) + 1;
|
|
|
// arr[i] = [j, parseInt((i - (j - 1) * 100 + 1) * 3.6), parseInt(dbm[i]) + 80];
|
|
|
// }
|
|
|
// return arr;
|
|
|
// },
|
|
|
// // 绘制/更新 ECharts 3D 图表
|
|
|
// drawEcharts3d(obj) {
|
|
|
// if (!prpsData[this.sort].prpsChart) return; // 确保图表实例已存在
|
|
|
|
|
|
// let arr = [];
|
|
|
// this.deal(arr, obj); // 处理数据
|
|
|
// console.log(arr, 'arr');
|
|
|
|
|
|
// // 只更新 series 的 data 部分
|
|
|
// prpsData[this.sort].prpsChart.setOption({
|
|
|
// series: [{
|
|
|
// data: arr.map(function (item) {
|
|
|
// return {
|
|
|
// value: [item[0], item[1], item[2]]
|
|
|
// }
|
|
|
// })
|
|
|
// }]
|
|
|
// });
|
|
|
// },
|
|
|
// // 动画循环逻辑
|
|
|
// dispose(data) {
|
|
|
// clearTimeout(this.timer); // 清除上一个定时器
|
|
|
|
|
|
// this.drawEcharts3d(data); // 绘制图表
|
|
|
|
|
|
// let em = [];
|
|
|
// em = data.splice(0, 1000); // 移除前1000个元素
|
|
|
// this.len++; // 计数器加一
|
|
|
|
|
|
// if (this.len > 5) { // 如果超过5次循环,将移除的元素重新加回末尾
|
|
|
// data = data.concat(em);
|
|
|
// }
|
|
|
|
|
|
// // console.log('[ data ] >', data); // **重要:在生产环境中请注释或删除此行!**
|
|
|
|
|
|
// // 设置下一个定时器
|
|
|
// this.timer = setTimeout(() => {
|
|
|
// this.dispose(data); // 递归调用自身
|
|
|
// }, 200);
|
|
|
// }
|
|
|
// }
|
|
|
// }
|
|
|
// prpd/prps组件
|
|
|
const prpdAndPrps = {
|
|
|
template: `<div ref='prpsRef' style="width: 100%; height: 100%;">prpd/prps组件</div>`,
|
|
|
data() {
|
|
|
return {
|
|
|
totalData: [],
|
|
|
renderData: [],
|
|
|
timer: [],
|
|
|
chart: null,
|
|
|
chartData: [],
|
|
|
// 假设您的 maxNum 是幅值的最大绝对值,用于颜色映射
|
|
|
maxNum: 80, // 根据您的实际幅值范围设置,例如图中的-80到0,那么最大绝对值就是80
|
|
|
currentPeriodCycle: 50, // 当前数据从哪个周期开始
|
|
|
totalPeriods: 50, // 图表上显示的周期总数,对应您three.js中的this.period
|
|
|
phasesPerPeriod: 128, // 每个周期包含的相位点数量
|
|
|
intervalId: null,
|
|
|
};
|
|
|
},
|
|
|
async mounted() {
|
|
|
await fetch('./three/prps.json') // JSON文件路径
|
|
|
.then(response => response.json()) // 解析为JSON对象
|
|
|
.then(data => {
|
|
|
this.totalData = JSON.parse(JSON.stringify(data))
|
|
|
this.rawAmplitudeData = [];
|
|
|
data.forEach(periodDataArray => {
|
|
|
// 确保每个周期处理 100 个点。如果原始数据多于 100,只取前 100;如果少于 100,则补0。
|
|
|
for (let i = 0; i < this.phasesPerPeriod; i++) {
|
|
|
if (periodDataArray[i] && periodDataArray[i][2] !== undefined) {
|
|
|
this.rawAmplitudeData.push(parseFloat(periodDataArray[i][2]));
|
|
|
} else {
|
|
|
this.rawAmplitudeData.push(0); // 数据不足时补0
|
|
|
}
|
|
|
}
|
|
|
});
|
|
|
console.log('扁平化后的总幅值数据点数量:', this.rawAmplitudeData);
|
|
|
})
|
|
|
.catch(error => console.error('加载JSON失败:', error));
|
|
|
this.initChart(); // 首次初始化图表,包括所有配置
|
|
|
this.startDynamicData();
|
|
|
},
|
|
|
beforeDestroy() {
|
|
|
// 在组件销毁前清除定时器,避免内存泄漏
|
|
|
if (this.intervalId) {
|
|
|
clearInterval(this.intervalId);
|
|
|
}
|
|
|
},
|
|
|
methods: {
|
|
|
initChart() {
|
|
|
this.chart = echarts.init(this.$refs.prpsRef);
|
|
|
// 首次设置所有图表配置,包括轴、光照、视觉映射等
|
|
|
const option = {
|
|
|
tooltip: {
|
|
|
show: false
|
|
|
},
|
|
|
toolbox: {
|
|
|
show: false,
|
|
|
},
|
|
|
animation: false,
|
|
|
visualMap: {
|
|
|
max: 80,
|
|
|
min: -20,
|
|
|
show: !1,
|
|
|
itemWidth: 5,
|
|
|
dimension: 2,
|
|
|
orient: "vertical",
|
|
|
inRange: {
|
|
|
color: ["transparent", "#00ee00", "#eeee00", "#ee0000", "#4e0211"]
|
|
|
},
|
|
|
formatter: function (e) {
|
|
|
return parseInt(e - 80)
|
|
|
}
|
|
|
},
|
|
|
xAxis3D: {
|
|
|
type: "value",
|
|
|
min: 0,
|
|
|
max: 50,
|
|
|
splitNumber: 5,
|
|
|
name: '周期',
|
|
|
nameGap: 24,
|
|
|
axisLine: {
|
|
|
lineStyle: {
|
|
|
color: '#000'
|
|
|
}
|
|
|
},
|
|
|
axisLabel: {
|
|
|
color: '#000',
|
|
|
fontSize: 14,
|
|
|
formatter: function (e, t) {
|
|
|
if (0 <= (e = 50 - e))
|
|
|
return e
|
|
|
}
|
|
|
}
|
|
|
},
|
|
|
yAxis3D: {
|
|
|
type: "value",
|
|
|
min: 0,
|
|
|
max: 360,
|
|
|
splitNumber: 4,
|
|
|
interval: 90,
|
|
|
name: '相位',
|
|
|
nameGap: 24,
|
|
|
splitArea: {
|
|
|
interval: 4
|
|
|
},
|
|
|
axisLine: {
|
|
|
lineStyle: {
|
|
|
color: '#000'
|
|
|
}
|
|
|
},
|
|
|
axisLabel: {
|
|
|
fontSize: 14,
|
|
|
color: '#000'
|
|
|
}
|
|
|
},
|
|
|
zAxis3D: {
|
|
|
name: '幅值',
|
|
|
min: 0,
|
|
|
max: 80,
|
|
|
scale: !0,
|
|
|
splitNumber: 4,
|
|
|
name: '幅值',
|
|
|
nameGap: 24,
|
|
|
axisLine: {
|
|
|
lineStyle: {
|
|
|
color: '#000'
|
|
|
}
|
|
|
},
|
|
|
axisLabel: {
|
|
|
color: '#000',
|
|
|
fontSize: 14,
|
|
|
formatter: function (e, t) {
|
|
|
if (0 <= e)
|
|
|
return e - 80
|
|
|
}
|
|
|
}
|
|
|
},
|
|
|
grid3D: {
|
|
|
boxWidth: 100,
|
|
|
boxHeight: 100,
|
|
|
boxDepth: 100,
|
|
|
axisLine: {
|
|
|
lineStyle: {
|
|
|
color: "#fff",
|
|
|
opacity: .1
|
|
|
}
|
|
|
},
|
|
|
axisPointer: {
|
|
|
show: !1,
|
|
|
lineStyle: {
|
|
|
color: "#fff"
|
|
|
}
|
|
|
},
|
|
|
viewControl: {
|
|
|
distance: 260,
|
|
|
minDistance: 40,
|
|
|
maxDistance: 400,
|
|
|
rotateSensitivity: [1, 1],
|
|
|
zoomSensitivity: 0,
|
|
|
panSensitivity: 0,
|
|
|
panMouseButton: "middle",
|
|
|
rotateMouseButton: "left",
|
|
|
orthographicSize: 150,
|
|
|
maxOrthographicSize: 400,
|
|
|
minOrthographicSize: 20,
|
|
|
center: [0, -10, 0],
|
|
|
minBeta: 30,
|
|
|
maxBeta: 180,
|
|
|
minAlpha: -90,
|
|
|
maxAlpha: 90,
|
|
|
projection: "perspective",
|
|
|
autoRotateDirection: "cw",
|
|
|
autoRotateAfterStill: 3,
|
|
|
damping: .8
|
|
|
},
|
|
|
light: {
|
|
|
main: {
|
|
|
intensity: 1.2
|
|
|
},
|
|
|
ambient: {
|
|
|
intensity: .3
|
|
|
}
|
|
|
}
|
|
|
},
|
|
|
roam: !1,
|
|
|
series: [
|
|
|
{
|
|
|
type: 'bar3D',
|
|
|
data: [], // 初始为空数据,或调用 initChartData() 填充
|
|
|
shading: 'color', // lambert
|
|
|
barSize: 0.5,
|
|
|
label: {
|
|
|
show: !1,
|
|
|
textStyle: {
|
|
|
fontSize: 16,
|
|
|
borderWidth: 1
|
|
|
},
|
|
|
formatter: function (e) {
|
|
|
return parseInt(e.value[2] - 80)
|
|
|
}
|
|
|
},
|
|
|
itemStyle: {
|
|
|
opacity: .8
|
|
|
},
|
|
|
silent: !0,
|
|
|
emphasis: {
|
|
|
label: {
|
|
|
show: !1
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
]
|
|
|
};
|
|
|
this.chart.setOption(option);
|
|
|
},
|
|
|
delay(id, callBack, ms) {
|
|
|
return new Promise((resolve) => {
|
|
|
this.timer[id] = setTimeout(() => {
|
|
|
callBack();
|
|
|
resolve();
|
|
|
}, ms);
|
|
|
});
|
|
|
},
|
|
|
async startDynamicData() {
|
|
|
console.log('[ this.totalData ] >', this.totalData)
|
|
|
for (let [index, item] of this.totalData.entries()) {
|
|
|
let callBack = () => {
|
|
|
const currentData = JSON.parse(JSON.stringify(item)).map((item) => [50, item[1], Number(item[2])]) // 50周期开始,数据从右往左
|
|
|
this.renderData = [currentData, ...JSON.parse(JSON.stringify(this.renderData))]
|
|
|
this.renderData.forEach(periodArray => {
|
|
|
periodArray.forEach(dataPoint => {
|
|
|
dataPoint[0]-- // x轴减一
|
|
|
});
|
|
|
});
|
|
|
this.renderData = this.renderData.filter(item => item[0][0] >= 0) // 筛选掉x轴为负的
|
|
|
const aa = this.renderData.flat()
|
|
|
console.log('[ this.renderData ] >',)
|
|
|
this.chart.setOption({
|
|
|
series: [{
|
|
|
data: aa
|
|
|
}]
|
|
|
});
|
|
|
};
|
|
|
await this.delay(index, callBack, 200);
|
|
|
}
|
|
|
// 等待所有延迟完成后再次开始
|
|
|
// this.startDynamicData();
|
|
|
},
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
createApp({
|
|
|
setup() {
|
|
|
const typeOfCheckable = ['historyTrend', 'countPRPD', 'prpdAndPrps']
|
|
|
const treeData = ref([])
|
|
|
const fullTreeData = ref([]) // 懒加载后的完整菜单数据
|
|
|
const checkedKeys1 = ref([]); // 勾选
|
|
|
const selectedKey = ref('') // 选中
|
|
|
const treeMenuInfo = reactive({
|
|
|
menuVisible: false,
|
|
|
data: null,
|
|
|
menuX: 0,
|
|
|
menuY: 0
|
|
|
})
|
|
|
const treeMenu = ref()
|
|
|
const handleClickOutside = (e) => {
|
|
|
if (treeMenuInfo.menuVisible && !treeMenu.value?.contains(e.target)) {
|
|
|
treeMenuInfo.menuVisible = false;
|
|
|
}
|
|
|
};
|
|
|
const searchValue = ref('');
|
|
|
const treeRef = ref()
|
|
|
const activeKey = ref('prpdAndPrps')
|
|
|
const tabsArr = [
|
|
|
{ key: 'historyTrend', tab: '历史趋势' },
|
|
|
{ key: 'alarmConfig', tab: '告警管理' },
|
|
|
{ key: 'countPRPD', tab: '累计PRPD' },
|
|
|
{ key: 'prpdAndPrps', tab: 'PRPD/PRPS' },
|
|
|
{ key: 'eventCount', tab: '事件统计' },
|
|
|
{ key: 'config', tab: '配置' }
|
|
|
|
|
|
]
|
|
|
const isImportMonitorModalShow = ref(false)
|
|
|
const importMonitorModalloading = ref(false)
|
|
|
const siteModalloading = ref(false)
|
|
|
const isSiteModalShow = ref(false)
|
|
|
const siteModalRef = ref()
|
|
|
const siteHistoryData = ref() // 站点历史数据
|
|
|
// 站点信息
|
|
|
const siteModalForm = reactive({
|
|
|
stationName: '',
|
|
|
img: ''
|
|
|
})
|
|
|
const isAddTypeOfSiteModal = ref(true) // true:新增站点 false:修改站点
|
|
|
const isMonitorModalShow = ref(false) // 监测点弹框
|
|
|
const isAddTypeOfMonitorModal = ref(true) // true:新增监测点 false:修改监测点
|
|
|
const monitorModalLoading = ref(false)
|
|
|
const monitorModalRef = ref()
|
|
|
const monitorModalForm = reactive({
|
|
|
stationName: '', // 站点名称
|
|
|
name: '',// 监测点名称
|
|
|
monitorKey: '' // 监测点key
|
|
|
})
|
|
|
// 查询树
|
|
|
const search = () => {
|
|
|
treeRef.value.filter(unref(searchValue)); // 触发过滤
|
|
|
};
|
|
|
const filterNode = (value, data) => {
|
|
|
if (!value) return true;
|
|
|
return data.name.includes(value); // 根据label匹配
|
|
|
};
|
|
|
const handleRightClick = (event, data) => {
|
|
|
event.preventDefault();
|
|
|
treeMenuInfo.menuVisible = true
|
|
|
treeMenuInfo.menuX = event.clientX - 8
|
|
|
treeMenuInfo.menuY = event.clientY - 12
|
|
|
treeMenuInfo.data = data
|
|
|
}
|
|
|
const checkTree = (checkedKeys, { checkedKeys: currentKeys }) => {
|
|
|
if (currentKeys.length > 6) {
|
|
|
message.warning('最多只能勾选6个节点!');
|
|
|
// 阻止勾选:回退到前一次的状态
|
|
|
checkedKeys1.value = checkedKeys1.value.slice(0, 6);
|
|
|
treeRef.value.setCheckedKeys(checkedKeys1.value);
|
|
|
} else {
|
|
|
checkedKeys1.value = currentKeys
|
|
|
}
|
|
|
|
|
|
}
|
|
|
const selectTree = (node) => {
|
|
|
if (node.isRoot) {
|
|
|
selectedKey.value = ''
|
|
|
} else {
|
|
|
selectedKey.value = node.key
|
|
|
}
|
|
|
}
|
|
|
const defaultProps = {
|
|
|
children: 'children',
|
|
|
label: 'name',
|
|
|
isLeaf: 'leaf',
|
|
|
class: (node) => node.isRoot ? 'is-root' : ''
|
|
|
}
|
|
|
const onLoadData = (node, resolve) => {
|
|
|
if (node.level !== 1) {
|
|
|
resolve([]);
|
|
|
return
|
|
|
}
|
|
|
const stationName = node?.label ?? ''
|
|
|
axios.get(`/ldpdtools/monitor/monitorList?stationName=${stationName}`).then(({ data: { code, result } }) => {
|
|
|
const data = (result || []).map(item => {
|
|
|
return {
|
|
|
title: item.name,
|
|
|
key: item.monitorKey,
|
|
|
isRoot: false,
|
|
|
disabled: false,
|
|
|
leaf: true,
|
|
|
...item
|
|
|
}
|
|
|
})
|
|
|
resolve(data)
|
|
|
fullTreeData.value = treeRef.value?.store?.root.childNodes.map(node => formatTreeData(node));
|
|
|
})
|
|
|
}
|
|
|
// 初始化树
|
|
|
const initTreeData = async () => {
|
|
|
const { data: { code, result } } = await axios.get('/ldpdtools/monitor/getStations');
|
|
|
if (code !== 200) {
|
|
|
return
|
|
|
}
|
|
|
treeData.value = result.map((item, index) => {
|
|
|
return {
|
|
|
key: index,
|
|
|
title: item.stationName,
|
|
|
isRoot: true,
|
|
|
disabled: true,
|
|
|
...item
|
|
|
}
|
|
|
})
|
|
|
fullTreeData.value = treeRef.value?.store?.root.childNodes.map(node => formatTreeData(node));
|
|
|
}
|
|
|
// 编辑节点
|
|
|
const editNodeItem = (data) => {
|
|
|
const { isRoot, stationName, img, monitorKey, name } = data
|
|
|
if (isRoot) {
|
|
|
// 编辑站点
|
|
|
isSiteModalShow.value = true
|
|
|
isAddTypeOfSiteModal.value = false
|
|
|
siteModalForm.stationName = stationName
|
|
|
siteModalForm.img = img
|
|
|
siteHistoryData.value = JSON.parse(JSON.stringify({ stationName, img }))
|
|
|
} else {
|
|
|
// 编辑监测点
|
|
|
isMonitorModalShow.value = true
|
|
|
isAddTypeOfMonitorModal.value = false
|
|
|
monitorModalForm.stationName = stationName
|
|
|
monitorModalForm.name = name
|
|
|
monitorModalForm.monitorKey = monitorKey
|
|
|
}
|
|
|
}
|
|
|
// 删除节点
|
|
|
const deleteNodeItem = async (data) => {
|
|
|
const { isRoot, stationName, monitorKey } = data
|
|
|
let resultCode = 200
|
|
|
if (isRoot) {
|
|
|
// 删除站点
|
|
|
const { data: { code } } = await axios.delete(`/ldpdtools/monitor/deleteStation?stationName=${stationName}`);
|
|
|
resultCode = code
|
|
|
} else {
|
|
|
// 删除检测点
|
|
|
const { data: { code } } = await axios.delete(`/ldpdtools/monitor/deleteMonitor?stationName=${stationName}&monitorKey=${monitorKey}`);
|
|
|
resultCode = code
|
|
|
}
|
|
|
if (resultCode === 200) {
|
|
|
message.success(`删除${isRoot ? '站点' : '监测点'}成功`);
|
|
|
initTreeData()
|
|
|
} else {
|
|
|
message.error(`删除${isRoot ? '站点' : '监测点'}失败`);
|
|
|
}
|
|
|
}
|
|
|
// 新增监测点
|
|
|
const addMonitor = (data) => {
|
|
|
const { stationName } = data
|
|
|
monitorModalForm.stationName = stationName
|
|
|
isMonitorModalShow.value = true
|
|
|
}
|
|
|
// 导入监测点
|
|
|
const onImportMonitor = () => {
|
|
|
|
|
|
}
|
|
|
const addSite = () => {
|
|
|
isSiteModalShow.value = true
|
|
|
}
|
|
|
// 新增、编辑站点
|
|
|
const onSiteModalSubmit = async () => {
|
|
|
await siteModalRef.value.validate()
|
|
|
siteModalloading.value = true
|
|
|
const { img, stationName } = unref(siteModalForm)
|
|
|
let resultCode = 200
|
|
|
if (unref(isAddTypeOfSiteModal)) {
|
|
|
// 新增
|
|
|
const { data: { code } } = await axios.put(`/ldpdtools/monitor/saveStateion?img=${img}&stationName=${stationName}`);
|
|
|
resultCode = code
|
|
|
} else {
|
|
|
// 编辑
|
|
|
const { data: { code } } = await axios.put(`/ldpdtools/monitor/editStateion?img=${img}&newStationName=${stationName}&stationName=${unref(siteHistoryData).stationName}`);
|
|
|
resultCode = code
|
|
|
}
|
|
|
siteModalloading.value = false
|
|
|
if (resultCode === 200) {
|
|
|
message.success(`${unref(isAddTypeOfSiteModal) ? '新增' : '编辑'}站点成功`);
|
|
|
isSiteModalShow.value = false
|
|
|
initTreeData()
|
|
|
} else {
|
|
|
message.error(`${unref(isAddTypeOfSiteModal) ? '新增' : '编辑'}站点失败`);
|
|
|
}
|
|
|
}
|
|
|
// 新增、编辑监测点
|
|
|
const onMonitorModalSubmit = async () => {
|
|
|
await monitorModalRef.value.validate()
|
|
|
monitorModalLoading.value = true
|
|
|
const { stationName, name, monitorKey } = unref(monitorModalForm)
|
|
|
let resultCode = 200
|
|
|
let resultMsg = ''
|
|
|
if (unref(isAddTypeOfMonitorModal)) {
|
|
|
// 新增
|
|
|
const { data: { code, message } } = await axios.put(`/ldpdtools/monitor/saveMonitor?stationName=${stationName}&name=${name}&monitorKey=${monitorKey}`);
|
|
|
resultCode = code
|
|
|
resultMsg = message
|
|
|
} else {
|
|
|
// 编辑
|
|
|
const { data: { code, message } } = await axios.put(`/ldpdtools/monitor/editMonitor?stationName=${stationName}&name=${name}&monitorKey=${monitorKey}`);
|
|
|
resultCode = code
|
|
|
resultMsg = message
|
|
|
}
|
|
|
monitorModalLoading.value = false
|
|
|
if (resultCode === 200) {
|
|
|
message.success(`${unref(isAddTypeOfMonitorModal) ? '新增' : '编辑'}监测点成功`);
|
|
|
isMonitorModalShow.value = false
|
|
|
initTreeData()
|
|
|
} else {
|
|
|
message.error(resultMsg);
|
|
|
}
|
|
|
}
|
|
|
// 监测站点弹框关闭
|
|
|
watch(isSiteModalShow, (bool) => {
|
|
|
if (bool) {
|
|
|
return
|
|
|
}
|
|
|
siteModalRef.value.resetFields()
|
|
|
isAddTypeOfSiteModal.value = true
|
|
|
siteModalForm.stationName = ''
|
|
|
siteModalForm.img = ''
|
|
|
siteHistoryData.value = {}
|
|
|
})
|
|
|
// 监测监测点弹框关闭
|
|
|
watch(isMonitorModalShow, (bool) => {
|
|
|
if (bool) {
|
|
|
return
|
|
|
}
|
|
|
monitorModalRef.value.resetFields()
|
|
|
isAddTypeOfMonitorModal.value = true
|
|
|
monitorModalForm.stationName = ''
|
|
|
monitorModalForm.name = ''
|
|
|
monitorModalForm.monitorKey = ''
|
|
|
})
|
|
|
// 历史趋势部分逻辑
|
|
|
const trendGraphData = ref([])
|
|
|
const trendGraphRefs = (el, id) => {
|
|
|
if (el) childRefs.value[id] = el;
|
|
|
};
|
|
|
const childRefs = ref({});
|
|
|
const dateRange = ref([]);
|
|
|
const currentYear = ref(new Date().getFullYear());
|
|
|
const allowedMonths = ref([]); // 允许选择的月份(如[1,5]表示1月和5月)
|
|
|
// 禁用日期规则(核心逻辑)
|
|
|
const disabledDate = (time) => {
|
|
|
const date = new Date(time);
|
|
|
const year = date.getFullYear();
|
|
|
const month = date.getMonth() + 1;
|
|
|
// 规则1:只允许选择当前年份
|
|
|
if (year !== currentYear.value) return true;
|
|
|
// 规则2:只允许选择API返回的月份
|
|
|
if (!allowedMonths.value.includes(month)) return true;
|
|
|
// 规则3:限制选择范围为1个月内(当已选开始日期时)
|
|
|
if (dateRange.value?.[0]) {
|
|
|
const startDate = new Date(dateRange.value[0]);
|
|
|
const minDate = new Date(startDate);
|
|
|
const maxDate = new Date(startDate);
|
|
|
minDate.setMonth(minDate.getMonth() - 1);
|
|
|
maxDate.setMonth(maxDate.getMonth() + 1);
|
|
|
return date < minDate || date > maxDate;
|
|
|
}
|
|
|
return false;
|
|
|
};
|
|
|
const handlePanelChange = (date) => {
|
|
|
currentYear.value = date?.[0]?.getFullYear() || 2025
|
|
|
};
|
|
|
const fetchHistoryTrendData = async (id, time) => {
|
|
|
try {
|
|
|
const params = {
|
|
|
current: 1,
|
|
|
startTimeStr: time[0],
|
|
|
endTimeStr: time[1],
|
|
|
monitorKey: id,
|
|
|
pageSize: 99999
|
|
|
}
|
|
|
const { data: { result: { result: { result } } } } = await axios.get(`/ldpdtools/trendData/listByParam`, {
|
|
|
params,
|
|
|
})
|
|
|
return {
|
|
|
id,
|
|
|
// label:
|
|
|
data: result
|
|
|
}
|
|
|
} catch (error) {
|
|
|
console.error(`请求 ${id} 时出错:`, error);
|
|
|
return null;
|
|
|
}
|
|
|
}
|
|
|
// 初始化趋势echart
|
|
|
const initTrendGraph = (el, data) => {
|
|
|
const legendData = [
|
|
|
{ id: 'avg', name: '平均值' },
|
|
|
{ id: 'maxValue', name: '最大值' },
|
|
|
{ id: 'plusAvg', name: '脉冲平均值' },
|
|
|
{ id: 'plusCount', name: '脉冲次数' },
|
|
|
]
|
|
|
// 图数据
|
|
|
const series = legendData.map((item, index) => ({
|
|
|
name: item.name,
|
|
|
type: 'line',
|
|
|
yAxisIndex: index,
|
|
|
data: data.data.map(el => el[item.id]),
|
|
|
smooth: true,
|
|
|
showSymbol: false,
|
|
|
lineStyle: {
|
|
|
width: 2,
|
|
|
},
|
|
|
}));
|
|
|
const legend = {
|
|
|
data: legendData.map(s => s.name), // 图例数据
|
|
|
top: 0,
|
|
|
};
|
|
|
const xAxis = {
|
|
|
type: 'category',
|
|
|
data: data.data.map(el => el.time.replace(' ', '\n')),
|
|
|
axisLine: {
|
|
|
onZero: false, // 禁止轴线对齐到0刻度,强制固定在底部
|
|
|
},
|
|
|
name: '时间',
|
|
|
axisLabel: {
|
|
|
fontSize: 10,
|
|
|
},
|
|
|
};
|
|
|
const yAxis = legendData.map((item, index) => {
|
|
|
return {
|
|
|
type: 'value',
|
|
|
name: item.name,
|
|
|
nameTextStyle: {
|
|
|
color: '#666',
|
|
|
fontSize: 10,
|
|
|
padding: [0, 0, 0, 30], // 上、右、下、左(左间距30px)
|
|
|
},
|
|
|
triggerEvent: true, // 关键配置
|
|
|
axisLabel: {
|
|
|
formatter: '{value}',
|
|
|
fontSize: 10,
|
|
|
},
|
|
|
position: 'right',
|
|
|
offset: (index + 1) * 48, // 控制 Y 轴横向间距
|
|
|
splitLine: {
|
|
|
show: false, // 仅第一个 Y 轴显示网格线
|
|
|
},
|
|
|
splitNumber: 3, // Y轴仅显示3个刻度线
|
|
|
};
|
|
|
});
|
|
|
const chart = echarts.init(el);
|
|
|
const option = {
|
|
|
// 设置响应式
|
|
|
grid: {
|
|
|
top: 30,
|
|
|
right: 230,
|
|
|
bottom: 30,
|
|
|
left: 30
|
|
|
},
|
|
|
tooltip: {
|
|
|
trigger: 'axis',
|
|
|
axisPointer: {
|
|
|
type: 'cross'
|
|
|
}
|
|
|
},
|
|
|
legend,
|
|
|
xAxis,
|
|
|
yAxis,
|
|
|
series
|
|
|
};
|
|
|
// 3. 设置配置项并渲染图表
|
|
|
chart.setOption(option);
|
|
|
// 4. 窗口大小改变时重新调整图表大小
|
|
|
const resizeHandler = () => chart.resize();
|
|
|
window.addEventListener('resize', resizeHandler);
|
|
|
// 返回图表实例和清理函数
|
|
|
return {
|
|
|
instance: chart,
|
|
|
dispose: () => {
|
|
|
window.removeEventListener('resize', resizeHandler);
|
|
|
chart.dispose();
|
|
|
}
|
|
|
};
|
|
|
}
|
|
|
const chartGroups = ref({});
|
|
|
// tab在历史趋势监听勾选节点
|
|
|
watch([checkedKeys1, dateRange], async ([keys, time]) => {
|
|
|
const [starTime, endTime] = time || [];
|
|
|
if (unref(activeKey) !== 'historyTrend' || !keys.length || !starTime || !endTime) return;
|
|
|
// 先清理之前的图表
|
|
|
Object.values(chartGroups.value).forEach(group => {
|
|
|
group.instances.forEach(chart => chart.dispose());
|
|
|
});
|
|
|
chartGroups.value = {};
|
|
|
const promises = keys.map((key) => fetchHistoryTrendData(key, time));
|
|
|
trendGraphData.value = await Promise.all(promises);
|
|
|
nextTick(() => {
|
|
|
// 按分组存储图表实例
|
|
|
const groupMap = {};
|
|
|
Object.keys(childRefs.value).forEach((id) => {
|
|
|
const childEl = childRefs.value[id];
|
|
|
const childData = trendGraphData.value.find((item) => item.id === id);
|
|
|
if (childEl && childData) {
|
|
|
const { instance, dispose } = initTrendGraph(childEl, childData);
|
|
|
// 假设你的数据中有 groupId 字段表示分组
|
|
|
const groupId = childData.groupId || 'default';
|
|
|
if (!groupMap[groupId]) {
|
|
|
groupMap[groupId] = [];
|
|
|
}
|
|
|
groupMap[groupId].push(instance);
|
|
|
}
|
|
|
});
|
|
|
|
|
|
// 连接同一组的图表
|
|
|
Object.keys(groupMap).forEach(groupId => {
|
|
|
if (groupMap[groupId].length > 1) {
|
|
|
echarts.connect(groupMap[groupId]);
|
|
|
}
|
|
|
// 存储分组信息
|
|
|
chartGroups.value[groupId] = {
|
|
|
instances: groupMap[groupId],
|
|
|
// 可以存储其他分组相关信息
|
|
|
};
|
|
|
});
|
|
|
});
|
|
|
});
|
|
|
const checkedKeys1Str = computed(() => checkedKeys1.value.join(',')) // 选中节点的字符串 为了减少监听
|
|
|
// 请求可选择的月份
|
|
|
watch([checkedKeys1Str, currentYear], async ([keys, year]) => {
|
|
|
if (!keys || !year) return
|
|
|
dateRange.value = []
|
|
|
const { data: { result } } = await axios.post(`/ldpdtools/trendData/multHasData?year=${year}`, unref(checkedKeys1))
|
|
|
allowedMonths.value = result.map(item => Number(item))
|
|
|
}, {
|
|
|
immediate: true
|
|
|
})
|
|
|
|
|
|
// 告警信息
|
|
|
const configLoading = ref(false)
|
|
|
const columns = [
|
|
|
{
|
|
|
title: '监测点',
|
|
|
dataIndex: 'name',
|
|
|
align: 'center',
|
|
|
ellipsis: true,
|
|
|
width: 120
|
|
|
},
|
|
|
{
|
|
|
title: '告警信息',
|
|
|
dataIndex: 'detailsInfo',
|
|
|
align: 'center',
|
|
|
ellipsis: true,
|
|
|
},
|
|
|
{
|
|
|
title: '放电类型',
|
|
|
dataIndex: 'pdType',
|
|
|
align: 'center',
|
|
|
ellipsis: true,
|
|
|
slots: { customRender: 'name1' },
|
|
|
width: 120
|
|
|
},
|
|
|
{
|
|
|
title: '是否复归',
|
|
|
dataIndex: 'isCancel',
|
|
|
align: 'center',
|
|
|
ellipsis: true,
|
|
|
slots: { customRender: 'name2' },
|
|
|
width: 120
|
|
|
},
|
|
|
{
|
|
|
title: '告警时间',
|
|
|
dataIndex: 'time',
|
|
|
align: 'center',
|
|
|
ellipsis: true,
|
|
|
width: 180
|
|
|
},
|
|
|
]
|
|
|
const dataSource = ref([])
|
|
|
const pagination = reactive({
|
|
|
current: 1,
|
|
|
pageSize: 10,
|
|
|
total: 0,
|
|
|
showSizeChanger: true,
|
|
|
showQuickJumper: true,
|
|
|
pageSizeOptions: ['5', '10', '20'],
|
|
|
showTotal: (total) => `共 ${total} 条数据`,
|
|
|
});
|
|
|
const cancelOps = [
|
|
|
{ label: '是', value: '0' },
|
|
|
{ label: '否', value: '1' },
|
|
|
]
|
|
|
const pdTypeOps = [
|
|
|
{
|
|
|
value: '1',
|
|
|
label: '尖刺放电',
|
|
|
},
|
|
|
{
|
|
|
value: '2',
|
|
|
label: '悬浮放电',
|
|
|
},
|
|
|
{
|
|
|
value: '3',
|
|
|
label: '沿面放电',
|
|
|
},
|
|
|
{
|
|
|
value: '4',
|
|
|
label: '内部放电',
|
|
|
},
|
|
|
{
|
|
|
value: '5',
|
|
|
label: '颗粒放电',
|
|
|
}
|
|
|
]
|
|
|
const alarmFilters = reactive({
|
|
|
times: [],
|
|
|
isCancel: '',
|
|
|
pdTypes: []
|
|
|
})
|
|
|
|
|
|
// 请求告警信息表格数据
|
|
|
const fetchAlarmGridData = async () => {
|
|
|
if (!unref(selectedKey)) {
|
|
|
message.warning(`请先选择左侧监测点`);
|
|
|
return
|
|
|
}
|
|
|
configLoading.value = true;
|
|
|
const params = {
|
|
|
current: pagination.current,
|
|
|
pageSize: pagination.pageSize,
|
|
|
startTime: alarmFilters.times?.[0] || '',
|
|
|
endTime: alarmFilters.times?.[1] || '',
|
|
|
isCancel: alarmFilters.isCancel,
|
|
|
pdType: alarmFilters.pdTypes,
|
|
|
monitorKey: unref(selectedKey),
|
|
|
stationName: findParentByKey(unref(fullTreeData), unref(selectedKey))
|
|
|
}
|
|
|
const { data: { result } } = await axios.post(`/ldpdtools/alarm/queryAlarmList`, params)
|
|
|
configLoading.value = false
|
|
|
dataSource.value = result?.result || []
|
|
|
pagination.total = result?.total || 0
|
|
|
}
|
|
|
// 重置表格
|
|
|
const initAlarmGridData = () => {
|
|
|
Object.assign(alarmFilters, {
|
|
|
times: [],
|
|
|
isCancel: '',
|
|
|
pdTypes: []
|
|
|
});
|
|
|
fetchAlarmGridData();
|
|
|
}
|
|
|
const handleTableChange = (pag) => {
|
|
|
Object.assign(pagination, pag);
|
|
|
fetchAlarmGridData();
|
|
|
};
|
|
|
// 告警管理监听
|
|
|
watch(selectedKey, (key) => {
|
|
|
if (!key || unref(activeKey) !== 'alarmConfig') return
|
|
|
// 初始化筛选数据
|
|
|
Object.assign(alarmFilters, {
|
|
|
times: [],
|
|
|
isCancel: '',
|
|
|
pdTypes: []
|
|
|
});
|
|
|
// 请求数据
|
|
|
fetchAlarmGridData();
|
|
|
});
|
|
|
// 累计prpd
|
|
|
const totalPrpds = ref([
|
|
|
{
|
|
|
monitorKey: ''
|
|
|
},
|
|
|
{
|
|
|
monitorKey: ''
|
|
|
},
|
|
|
{
|
|
|
monitorKey: ''
|
|
|
},
|
|
|
{
|
|
|
monitorKey: ''
|
|
|
},
|
|
|
{
|
|
|
monitorKey: ''
|
|
|
},
|
|
|
{
|
|
|
monitorKey: ''
|
|
|
},
|
|
|
])
|
|
|
// 配置页面
|
|
|
const stationName1 = ref('')
|
|
|
const deleteAlarmTimes = ref([]) // 删除告警时间段
|
|
|
const deleteAlarmConfirm = async () => {
|
|
|
if (!unref(stationName1)) {
|
|
|
return message.warning(`请选择站点!`);
|
|
|
}
|
|
|
if (!unref(deleteAlarmTimes).length) {
|
|
|
return message.warning(`请选择需要清除告警时间段!`);
|
|
|
}
|
|
|
const res = await axios.get(`/ldpdtools/alarm/deleteAlarmByTime`, {
|
|
|
params: {
|
|
|
startTime: unref(deleteAlarmTimes)?.[0] || '',
|
|
|
endTime: unref(deleteAlarmTimes)?.[1] || '',
|
|
|
stationName: unref(stationName1)
|
|
|
},
|
|
|
})
|
|
|
}
|
|
|
// 上传前校验
|
|
|
const alarmBeforeUpload = (file) => {
|
|
|
if (!unref(stationName1)) {
|
|
|
message.warning(`请选择站点!`);
|
|
|
return false
|
|
|
}
|
|
|
const allowedTypes = ['text/csv', 'application/vnd.ms-excel', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet']
|
|
|
const isAllowedType = allowedTypes.includes(file.type) ||
|
|
|
['.csv', '.xlsx', '.xls'].some(ext => file.name.toLowerCase().endsWith(ext))
|
|
|
if (!isAllowedType) {
|
|
|
message.error('只能上传 CSV 或 Excel 文件!')
|
|
|
return false
|
|
|
}
|
|
|
const isLt10M = file.size / 1024 / 1024 < 10
|
|
|
if (!isLt10M) {
|
|
|
message.error('文件大小不能超过 10MB!')
|
|
|
return false
|
|
|
}
|
|
|
return true
|
|
|
}
|
|
|
|
|
|
// 自定义上传方法
|
|
|
const alarmCustomUpload = async (options) => {
|
|
|
const { file } = options
|
|
|
try {
|
|
|
const formData = new FormData()
|
|
|
formData.append('file', file)
|
|
|
const { data: { code, message: message1 } } = await axios.post(`/ldpdtools/alarm/importAlarm`, formData, {
|
|
|
params: {
|
|
|
stationName: unref(stationName1)
|
|
|
}
|
|
|
})
|
|
|
if (code === 200) {
|
|
|
message.success(message1)
|
|
|
} else {
|
|
|
message.error('导入失败')
|
|
|
}
|
|
|
} catch (error) {
|
|
|
console.error('上传错误:', error)
|
|
|
}
|
|
|
}
|
|
|
const allPathCongfigs = ref([]) // 所有路径配置
|
|
|
// 获取所有配置项
|
|
|
const getAllConfigs = async () => {
|
|
|
allPathCongfigs.value = []
|
|
|
const { data: { result } } = await axios.post('/ldpdtools/config/getConfigKey')
|
|
|
Object.keys(result).forEach(key => {
|
|
|
allPathCongfigs.value = [...unref(allPathCongfigs), {
|
|
|
key,
|
|
|
label: result[key],
|
|
|
value: ''
|
|
|
}]
|
|
|
})
|
|
|
const { data: { result: paths } } = await axios.get('/ldpdtools/config/getConfig')
|
|
|
// 初始化路径赋值
|
|
|
allPathCongfigs.value.forEach(item => {
|
|
|
item.value = paths[item.key] || ''
|
|
|
})
|
|
|
}
|
|
|
// 保存路径
|
|
|
const savePathConfig = async (data) => {
|
|
|
if (!data.value) {
|
|
|
return message.error(`请输入${data.label}!`);
|
|
|
}
|
|
|
const { label, ...params } = data
|
|
|
const { data: { code } } = await axios.get('/ldpdtools/config/editConfig', { params })
|
|
|
if (code !== 200) return message.error(`保存${data.label}失败`)
|
|
|
message.success('保存成功!')
|
|
|
getAllConfigs()
|
|
|
}
|
|
|
// 重置路径
|
|
|
const resetPathConfig = async (key) => {
|
|
|
const { data: { code } } = await axios.get('/ldpdtools/config/resetConfig', { params: { key } })
|
|
|
if (code !== 200) return message.error(`重置${data.label}失败`)
|
|
|
message.success('重置成功!')
|
|
|
getAllConfigs()
|
|
|
}
|
|
|
// 监听tab切换
|
|
|
watch(activeKey, (tabKey, oldKey) => {
|
|
|
checkedKeys1.value = []
|
|
|
treeRef.value.setCheckedKeys([]);
|
|
|
selectedKey.value = ''
|
|
|
treeRef.value.setCurrentKey(null);
|
|
|
if (oldKey === 'historyTrend') {
|
|
|
// 销毁历史趋势数据
|
|
|
trendGraphData.value = []
|
|
|
childRefs.value = {}
|
|
|
dateRange.value = []
|
|
|
currentYear.value = new Date().getFullYear()
|
|
|
allowedMonths.value = []
|
|
|
}
|
|
|
if (oldKey === 'alarmConfig') {
|
|
|
// 销毁告警管理
|
|
|
Object.assign(alarmFilters, {
|
|
|
times: [],
|
|
|
isCancel: '',
|
|
|
pdTypes: []
|
|
|
});
|
|
|
dataSource.value = []
|
|
|
}
|
|
|
});
|
|
|
onMounted(() => {
|
|
|
initTreeData()
|
|
|
getAllConfigs()
|
|
|
document.addEventListener('click', handleClickOutside);
|
|
|
})
|
|
|
onUnmounted(() => {
|
|
|
document.removeEventListener('click', handleClickOutside);
|
|
|
});
|
|
|
return {
|
|
|
treeRef,
|
|
|
treeData,
|
|
|
fullTreeData,
|
|
|
treeMenuInfo,
|
|
|
treeMenu,
|
|
|
filterNode,
|
|
|
handleRightClick,
|
|
|
checkedKeys1,
|
|
|
searchValue,
|
|
|
search,
|
|
|
activeKey,
|
|
|
tabsArr,
|
|
|
onLoadData,
|
|
|
editNodeItem,
|
|
|
deleteNodeItem,
|
|
|
isImportMonitorModalShow,
|
|
|
onImportMonitor,
|
|
|
importMonitorModalloading,
|
|
|
siteModalloading,
|
|
|
addSite,
|
|
|
isSiteModalShow,
|
|
|
siteModalRef,
|
|
|
siteModalForm,
|
|
|
onSiteModalSubmit,
|
|
|
isAddTypeOfSiteModal,
|
|
|
isMonitorModalShow,
|
|
|
isAddTypeOfMonitorModal,
|
|
|
monitorModalLoading,
|
|
|
addMonitor,
|
|
|
monitorModalRef,
|
|
|
monitorModalForm,
|
|
|
onMonitorModalSubmit,
|
|
|
dateRange,
|
|
|
handlePanelChange,
|
|
|
currentYear,
|
|
|
disabledDate,
|
|
|
checkTree,
|
|
|
trendGraphData,
|
|
|
trendGraphRefs,
|
|
|
chartGroups,
|
|
|
typeOfCheckable,
|
|
|
columns,
|
|
|
dataSource,
|
|
|
pagination,
|
|
|
configLoading,
|
|
|
handleTableChange,
|
|
|
selectedKey,
|
|
|
selectTree,
|
|
|
cancelOps,
|
|
|
alarmFilters,
|
|
|
pdTypeOps,
|
|
|
deleteAlarmTimes,
|
|
|
deleteAlarmConfirm,
|
|
|
fetchAlarmGridData,
|
|
|
initAlarmGridData,
|
|
|
stationName1,
|
|
|
alarmCustomUpload,
|
|
|
alarmBeforeUpload,
|
|
|
defaultProps,
|
|
|
totalPrpds,
|
|
|
allPathCongfigs,
|
|
|
savePathConfig,
|
|
|
resetPathConfig
|
|
|
};
|
|
|
},
|
|
|
components: {
|
|
|
totalPrpd,
|
|
|
prpdAndPrps
|
|
|
}
|
|
|
})
|
|
|
.use(antd)
|
|
|
.use(ElementPlus, {
|
|
|
locale: ElementPlusLocaleZhCn // 使用中文语言包
|
|
|
})
|
|
|
.mount('#app');
|
|
|
</script>
|
|
|
</body>
|
|
|
|
|
|
</html> |