You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1878 lines
93 KiB
HTML

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<!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>
<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切换 -->
<div class="top-box">
<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="top-timer" v-if="timeSelectArr.includes(activeKey)">
<el-date-picker v-model="dateRange" style="width: 260px" class="custom-date-picker"
value-format="YYYY-MM-DD HH:mm:ss" type="datetimerange" range-separator="至"
start-placeholder="开始日期" end-placeholder="结束日期" />
</div>
</div>
<div class="panel-views">
<div v-if="activeKey === 'historyTrend'" key="historyTrend" class="sub-content history-trend">
<div class="trend-graph-container">
<history-trend-graph v-for="(item,index) in trendGraphData" :key="item.key"
:ref="el => { if (el) trendGraphRefs[index] = el }" :data="item" />
</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-panel">
<!-- 累计PRPD -->
<div>
<history-trend-graph :data='trendGraphInfo' used-tab="countPRPD"
@get-time-list="getTimeList" />
</div>
<div class="prpd-box">
<!-- 累计PRPD组件 -->
<div class="totle-prpds">
<total-prpd class="total-prpd-item" v-for="(item,index) in totalPrpds" :key="index"
:data="item" :time="prpdTimeArr" />
</div>
<div class="time-sider">
<div class="title">时间:</div>
<div class="list">
<div v-for="item in timeList" :key="item"
:class="['time-item',activeTime==item?'time-active-item':'']"
@click="selectTime(item)">
{{item}}
</div>
</div>
</div>
</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"
:ref="el => { if (el) prpdAndPrpsRefs[index] = el }" v-for="(item,index) in totalPrpds"
:key="index" :sort="index" />
</div>
</div>
<div v-if="activeKey === 'eventCount'" key="eventCount" class="sub-content">
<!-- 事件统计 -->
<event-count :time="dateRange" :selected-key="selectedKey" :tree-data="fullTreeData" />
</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-radio-group v-if="item.key==='ALARM_TYPE'" v-model="item.value">
<el-radio value="3">国网</el-radio>
<el-radio value="2">南网</el-radio>
</el-radio-group>
<el-input v-else 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 v-if="item.key==='MERGIN_ROOT_PATH'" size="small" type="primary"
style="margin-right: 4px;" :loading="isCurrentInit"
@click="initCatalogue">初始化</a-button>
<a-button size="small" @click="resetPathConfig(item.key)">重置</a-button>
<p v-if="item.key==='MERGIN_ROOT_PATH'&&isCurrentInit" class="init-warning-tips">
当前初始化进度:{{initTips}}
</p>
</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>
const { createApp, ref, onMounted, unref, watch, reactive, computed, nextTick, onUnmounted, components, provide, inject } = Vue;
const { message } = antd;
axios.defaults.baseURL = 'http://192.168.1.198:9501'; // 临时服务地址
axios.defaults.timeout = 10000;
const HISTORY_TREND_LEGEND = [
{ id: 'avg', name: '平均值' },
{ id: 'maxValue', name: '最大值' },
{ id: 'plusAvg', name: '脉冲平均值' },
{ id: 'plusCount', name: '脉冲次数' },
]
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;
}
// 处理数据,生成 ECharts 所需的三维坐标格式
const 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;
}
const findMonitorNameByKey = (arr, key) => {
let result = [];
arr.forEach(item => {
if (item?.children?.length) {
result = [...result, ...item.children]
}
});
return result.find(item => item.key === key)?.name
}
// 生成21个时间点
const generateTimePoints = (centralTimeString) => {
const timePoints = [];
const centralDate = new Date(centralTimeString);
if (isNaN(centralDate.getTime())) {
return [];
}
const firstPointTime = centralDate.getTime() - (10 * 15 * 60 * 1000);
for (let i = 0; i < 21; i++) {
const currentTime = new Date(firstPointTime + (i * 15 * 60 * 1000));
// 4. 格式化时间点为 'YYYY-MM-DD HH:mm:ss' 格式
const year = currentTime.getFullYear();
const month = (currentTime.getMonth() + 1).toString().padStart(2, '0'); // 月份从0开始
const day = currentTime.getDate().toString().padStart(2, '0');
const hours = currentTime.getHours().toString().padStart(2, '0');
const minutes = currentTime.getMinutes().toString().padStart(2, '0');
const seconds = currentTime.getSeconds().toString().padStart(2, '0');
const formattedTime = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
timePoints.push(formattedTime);
}
return timePoints;
}
// 获取前十五分钟数据
const getFifteenMinutesBefore = (timeString) => {
const originalDate = new Date(timeString);
if (isNaN(originalDate.getTime())) {
return null; // 返回 null 或抛出错误,表示输入无效
}
const originalTimeInMs = originalDate.getTime();
const fifteenMinutesInMs = 15 * 60 * 1000;
const newTimeInMs = originalTimeInMs - fifteenMinutesInMs;
const newDate = new Date(newTimeInMs);
const year = newDate.getFullYear();
const month = (newDate.getMonth() + 1).toString().padStart(2, '0'); // 月份从0开始需要加1
const day = newDate.getDate().toString().padStart(2, '0');
const hours = newDate.getHours().toString().padStart(2, '0');
const minutes = newDate.getMinutes().toString().padStart(2, '0');
const seconds = newDate.getSeconds().toString().padStart(2, '0');
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
}
// 历史趋势图组件
const trendGraphRefs = ref([]);
watch(trendGraphRefs, (arr) => {
// 此处定时器解决异步
setTimeout(() => {
arr.forEach((el) => {
el.getChart().group = 'trend-group';
});
}, 300);
}, {
immediate: true,
deep: true,
},);
// 历史趋势图谱
const historyTrendGraph = {
template: `<div class='graph-container'>
<div class="title">
监测点:{{ data?.label||'' }}
</div>
<div ref='graphRef' class="line-graph"></div>
</div>`,
data() {
return {
resizeObserver: null
}
},
props: {
data: {
type: Object,
default: () => { }
},
// 使用的场景
usedTab: {
type: String,
default: 'historyTrend'
}
},
// 定义常量不定义在data减少性能开销
created() {
this.chart = null
},
watch: {
data: {
async handler(val) {
const { startTime, endTime, key } = val
if (!key || !startTime) return
const params = {
current: 1,
startTime,
endTime,
monitorKey: key,
pageSize: 99999
}
const { data: { result: { result: { result } } } } = await axios.get(`/ldpdtools/trendData/listByParam`, {
params,
})
this.initTrendGraph(result || [])
},
deep: true,
immediate: true
}
},
async mounted() {
this.resizeObserver = new ResizeObserver(() => {
this.chart?.resize();
});
this.resizeObserver.observe(this.$refs.graphRef);
},
methods: {
initTrendGraph(data) {
// 图数据
const series = HISTORY_TREND_LEGEND.map((item, index) => ({
name: item.name,
type: 'line',
yAxisIndex: index,
data: data.map(el => el[item.id]),
smooth: true,
showSymbol: false,
lineStyle: {
width: 2,
},
markLine: {
data: [], // 初始为空,点击时再添加
symbol: 'none', // 不显示标记线两端的箭头
lineStyle: {
color: '#ff0000', // 标记线的颜色,例如红色
type: 'solid',
width: 1.5
},
label: {
show: false // 标记线上不显示标签
},
// 可以在这里设置 z 值让标记线在最上层
// z: 99
}
}));
const legend = {
data: HISTORY_TREND_LEGEND.map(s => s.name), // 图例数据
top: 0,
};
const xAxis = {
type: 'category',
data: data.map(el => el.time.replace(' ', '\n')),
axisLine: {
onZero: false, // 禁止轴线对齐到0刻度强制固定在底部
},
name: '时间',
axisLabel: {
fontSize: 10,
},
};
const yAxis = HISTORY_TREND_LEGEND.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个刻度线
};
});
this.chart = echarts.init(this.$refs.graphRef);
const option = {
// 设置响应式
grid: {
top: 30,
right: 230,
bottom: 30,
left: 30
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross'
}
},
legend,
xAxis,
yAxis,
series,
}
// 3. 设置配置项并渲染图表
this.chart.setOption(option);
// 图数据的点击事件(获取时间段数据)
this.chart.on('click', (params) => {
if (this.usedTab === 'countPRPD' && params.componentType === 'series' && params.dataIndex !== undefined) {
// 或者直接获取 X 轴的值
const clickedXValue = params.name;
const updatedSeries = this.chart.getOption().series.map((s, idx) => {
// 克隆 series防止直接修改option导致问题
const newSeries = JSON.parse(JSON.stringify(s));
// 更新 markLine 数据
newSeries.markLine = {
symbol: 'none',
lineStyle: {
color: '#ff0000',
type: 'solid',
width: 1.5
},
data: [{ xAxis: clickedXValue }]
};
return newSeries;
});
this.chart.setOption({
series: updatedSeries
});
this.$emit('getTimeList', clickedXValue);
}
});
},
getChart() {
return this.chart;
}
},
}
// 累计prpd组件
const totalPrpd = {
template: `<div>
<div class="total-prpd-title" :style="{color:!!data.monitorName?'red':''}">{{data.monitorName ||'暂无监测点'}}</div>
<div ref="prpdBoxRef" class="prpd"></div>
</div>`,
props: ['data', 'time'], // 接收父组件传递的数据
data() {
return {
}
},
computed: {
// prpd所需参数
mixPRPDParams() {
return {
...this.data,
time: this.time
}
}
},
watch: {
mixPRPDParams: {
handler(newVal) {
if (newVal.monitorKey && newVal.time[0]) {
// 新增操作
this.$nextTick(() => {
this.fetchPRPDData(newVal)
})
}
if (!newVal.monitorKey) {
// 删除操作
this.myChart.setOption({
series: [{
name: 'PRPD数据',
data: []
}]
}, { notMerge: false });
}
},
deep: true
}
},
created() {
this.myChart = null
this.resizeObserver = null
},
mounted() {
this.initPrpd()
},
methods: {
initPrpd() {
const chartDom = this.$refs.prpdBoxRef;
this.myChart = echarts.init(chartDom);
const option = {
backgroundColor: '#ffffff', // 设置背景色为深色,与图片相似
tooltip: {
show: false
},
// axisPointer: {
// show: true,
// snap: true,
// lineStyle: {
// type: 'dashed',
// },
// label: {
// show: true,
// margin: 6,
// backgroundColor: '#556',
// textStyle: {
// color: '#fff'
// }
// },
// link: [{
// xAxisId: ['xAxisLeft-yAxisTop', 'xAxisLeft-yAxisBottom']
// }, {
// xAxisId: ['xAxisRight-yAxisTop', 'xAxisRight-yAxisBottom']
// }, {
// yAxisId: ['xAxisLeft-yAxisTop', 'xAxisRight-yAxisTop']
// }, {
// yAxisId: ['xAxisLeft-yAxisBottom', 'xAxisRight-yAxisBottom']
// }]
// },
grid: {
left: '8%',
right: '10%',
top: '8%',
bottom: '10%',
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轴刻度文字颜色
},
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: 1,
data: [],
},
]
};
this.myChart.setOption(option);
this.resizeObserver = new ResizeObserver(() => {
this.myChart?.resize();
});
this.resizeObserver.observe(chartDom);
},
// 请求PRPD数据
async fetchPRPDData(data) {
const params = {
// startTime: data.time[0],
// endTime: data.time[1],
// monitorKey: data.monitorKey,
// mock数据
startTime: '2025-07-16 22:50:54',
endTime: '2025-07-16 23:05:54',
monitorKey: '50100542_1'
}
const { data: { code, result } } = await axios.get(`/ldpdtools/eventData/getPrpdByParam`, {
params,
})
if (code === 200) {
console.log(result, 'res');
const countArr = result.map(item => item[2])
const minCount = Math.min(...countArr)
const maxCount = Math.max(...countArr)
this.myChart.setOption({
series: [{
name: 'PRPD数据',
data: result
}],
visualMap: {
min: minCount,
max: maxCount
}
}, { notMerge: false });
}
}
},
}
// 放在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 prpdAndPrpsRefs = ref([]);
const prpdAndPrps = {
components: {
totalPrpd,
},
template: `<div class='prps-and-prpd-container'>
<div v-show='currentKey==="PRPS"' ref='prpsRef' style="width: 100%; height: 100%;"></div>
<total-prpd v-show='currentKey==="PRPD"' class="total-prpd-item" />
<div class='switcher'>
<span v-for='item in switchBox' :key='item' @click='currentKey=item'
:class='{"active-span":currentKey===item}'>
<span v-if='item==="PRPD"'>/</span>
{{item}}</span>
</div>
</div>`,
data() {
return {
len: 0,
timer: 0,
switchBox: ['PRPS', 'PRPD'],
currentKey: 'PRPS'
};
},
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) {
this.closeTimer()
}
},
methods: {
closeTimer() {
clearTimeout(this.timer);
},
initChart() {
if (this.$refs.prpsRef) {
prpsData[this.sort].prpsChart = echarts.init(this.$refs.prpsRef);
// 初始化一次不变的 ECharts 配置
prpsData[this.sort].prpsChartOps = {
title: {
text: 'PRPS',
left: 'center',
top: 10,
textStyle: {
fontSize: 14,
color: '#111'
}
},
animation: false,
tooltip: {
show: false,
},
toolbox: {
show: false,
},
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: '周期',
nameGap: 24,
axisLine: {
lineStyle: {
color: '#000'
}
},
axisLabel: {
color: '#000',
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,
},
axisLine: {
lineStyle: {
color: '#000'
}
},
axisLabel: {
color: '#000',
fontSize: 14,
},
},
zAxis3D: {
type: 'value',
min: 0,
max: 80,
scale: true,
splitNumber: 4,
name: '幅值',
nameGap: 24,
axisLine: {
lineStyle: {
color: '#000'
}
},
axisLabel: {
color: '#000',
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: [{
type: 'bar3D',
data: [],
shading: 'color',
label: {
show: false,
},
itemStyle: {
opacity: 0.8,
},
silent: true,
emphasis: {
label: { show: false },
}
}]
};
prpsData[this.sort].prpsChart.setOption(prpsData[this.sort].prpsChartOps);
}
},
// 绘制/更新 ECharts 3D 图表
drawEcharts3d(obj) {
if (!prpsData[this.sort].prpsChart) return; // 确保图表实例已存在
let arr = [];
deal(arr, obj); // 处理数据
// 只更新 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);
}
// 设置下一个定时器
this.timer = setTimeout(() => {
this.dispose(data); // 递归调用自身
}, 200);
}
}
}
// 事件统计组件
const eventCount = {
components: {
historyTrendGraph,
},
template: `<div class='event-count-box'>
<history-trend-graph :data='graphInfo' used-tab="eventCount"/>
<div class="pd-type-grid">
<el-table :data="pdTypeData" border>
<el-table-column prop="typeCn" label="局放类型"/>
<el-table-column prop="max" label="最大值" />
<el-table-column prop="avg" label="平均值" />
<el-table-column prop="count" label="事件数" />
<el-table-column prop="plusCount" label="脉冲数" />
</el-table>
</div>
</div>`,
data() {
return {
pdTypeData: []
}
},
props: ['time', 'selectedKey', 'treeData'],
inject: ['provideAllPdTypes'],
computed: {
graphInfo() {
return {
key: this.selectedKey,
label: findMonitorNameByKey(this.treeData, this.selectedKey),
startTime: this.time[0],
endTime: this.time[1],
};
}
},
watch: {
graphInfo: {
handler(value) {
const { startTime, endTime, key } = value
if (!key || !startTime) {
return
}
this.feachGrid()
},
deep: true,
immediate: true
}
},
methods: {
// 获取表格数据
async feachGrid() {
this.loading = true
const params = {
startTime: this.time[0],
endTime: this.time[1],
monitorKey: this.selectedKey,
}
const { data: { result } } = await axios.get(`/ldpdtools/eventData/getEventStatistics`, {
params,
})
const res = result || {}
const data = [] // 展示的数据
Object.keys(res).forEach(key => {
const type = unref(this.provideAllPdTypes).find(el => el.value == key)
data.push({
typeCn: type.label,
typeEn: type.value,
...res[key]
})
})
this.pdTypeData = data || []
},
}
}
createApp({
setup() {
const typeOfCheckable = ['historyTrend', 'countPRPD', 'prpdAndPrps']
const timeSelectArr = ['historyTrend', 'countPRPD', 'prpdAndPrps', 'eventCount'] // 含有时间选择的组件
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('countPRPD')
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 = (checkedNode, { checkedKeys: currentKeys }) => {
if (currentKeys.length > 6) {
message.warning('最多只能勾选6个节点');
// 阻止勾选:回退到前一次的状态
checkedKeys1.value = checkedKeys1.value.slice(0, 6);
treeRef.value.setCheckedKeys(checkedKeys1.value);
} else {
if (unref(activeKey) === 'countPRPD') {
// 处理累计prpd逻辑
handleCountPRPDSelect(checkedNode)
}
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 dateRange = ref([]);
// tab在历史趋势监听勾选节点
watch([checkedKeys1, dateRange], async ([keys, time]) => {
const [startTime, endTime] = time || [];
if (unref(activeKey) !== 'historyTrend' || !startTime || !endTime) return;
echarts.connect('trend-group'); // 通过分组连接
trendGraphData.value = keys.map((key) => {
return {
key,
label: findMonitorNameByKey(unref(fullTreeData), key),
startTime,
endTime,
};
});
});
// 告警信息
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: '', // 监控点key
monitorName: '' // 监控点名称
},
{
monitorKey: '',
monitorName: ''
},
{
monitorKey: '',
monitorName: ''
},
{
monitorKey: '',
monitorName: ''
},
{
monitorKey: '',
monitorName: ''
},
{
monitorKey: '',
monitorName: ''
},
])
const timeList = ref([]) // 事件列表
const activeTime = ref('')
const prpdTimeArr = ref([]) // prpd筛选时间
// 历史趋势所需数据
const trendGraphInfo = computed(() => {
return {
key: unref(selectedKey),
label: findMonitorNameByKey(unref(fullTreeData), unref(selectedKey)),
startTime: unref(dateRange)[0],
endTime: unref(dateRange)[1],
}
})
const getTimeList = (time) => {
timeList.value = generateTimePoints(time)
}
const selectTime = async (time) => {
activeTime.value = time
const before15Min = getFifteenMinutesBefore(time)
prpdTimeArr.value = [before15Min, time]
console.log(prpdTimeArr.value, ' prpdTimeArr.value ');
}
const handleCountPRPDSelect = ({ key: currentKey }) => {
const index = unref(checkedKeys1).indexOf(currentKey);
if (index > -1) {
// 取消选中
const deleteItem = unref(totalPrpds).find(item => item.monitorKey === currentKey)
deleteItem.monitorKey = ''
deleteItem.monitorName = ''
} else {
// 选中
const addItem = unref(totalPrpds).find(item => !item.monitorKey)
addItem.monitorKey = currentKey
addItem.monitorName = findMonitorNameByKey(unref(fullTreeData), currentKey)
}
console.log(unref(totalPrpds), ' unref(totalPrpds)');
}
// 配置页面
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 isCurrentInit = ref(false) // 是否正在初始化
const initTips = ref('')
const allPdTypes = ref([])
provide('provideAllPdTypes', allPdTypes)
// 获取放电类型
const getPdTypes = async () => {
const types = []
const { data: { result } } = await axios.get('/ldpdtools/config/getPdTypes');
Object.keys(result).forEach(key => {
types.push({
value: key,
label: result[key]
})
})
allPdTypes.value = types
}
// 获取所有配置项
const getAllConfigs = async () => {
getPdTypes()
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 itemIdToMoves = ["ALARM_TYPE", "MERGIN_ROOT_PATH"];
const startOfItemToMove = unref(allPathCongfigs).find(item => item.key === itemIdToMoves[0]);
const endOfItemToMove = unref(allPathCongfigs).find(item => item.key === itemIdToMoves[1]);
const remainingItems = unref(allPathCongfigs).filter(item => !itemIdToMoves.includes(item.key));
if (startOfItemToMove && endOfItemToMove) {
allPathCongfigs.value = [startOfItemToMove, ...remainingItems, endOfItemToMove];
}
}
// 保存路径
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()
}
// 获取初始化进度
const getInitPrgress = async () => {
const { data: { message } } = await axios.get('/ldpdtools/config/getInitProgress')
isCurrentInit.value = message.includes('/')
initTips.value = message
}
// 初始化目录
const initCatalogue = async () => {
const { data: { code } } = await axios.get('/ldpdtools/config/initConfig')
if (code === 200) {
setTimeout(() => {
getInitPrgress()
}, 1000) // 后台有一定延迟
}
}
// 监听tab切换
watch(activeKey, (tabKey, oldKey) => {
// 先注释切换tab不清空树选中状态
// checkedKeys1.value = []
// treeRef.value.setCheckedKeys([]);
// selectedKey.value = ''
// treeRef.value.setCurrentKey(null);
if (oldKey === 'historyTrend') {
// 销毁历史趋势数据
// trendGraphData.value = []
// dateRange.value = []
}
if (oldKey === 'alarmConfig') {
// 销毁告警管理
Object.assign(alarmFilters, {
times: [],
isCancel: '',
pdTypes: []
});
dataSource.value = []
}
if (oldKey === 'prpdAndPrps') {
// 销毁prpd/Prps
unref(prpdAndPrpsRefs).forEach(item => {
item.closeTimer()
})
prpsData.forEach(item => {
item.prpsChart?.dispose()
})
}
});
onMounted(() => {
initTreeData()
getAllConfigs()
getInitPrgress()
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,
checkTree,
trendGraphData,
typeOfCheckable,
timeSelectArr,
columns,
dataSource,
pagination,
configLoading,
handleTableChange,
selectedKey,
selectTree,
cancelOps,
alarmFilters,
pdTypeOps,
deleteAlarmTimes,
deleteAlarmConfirm,
fetchAlarmGridData,
initAlarmGridData,
stationName1,
alarmCustomUpload,
alarmBeforeUpload,
defaultProps,
totalPrpds,
allPathCongfigs,
savePathConfig,
resetPathConfig,
prpdAndPrpsRefs,
initCatalogue,
isCurrentInit,
initTips,
trendGraphRefs,
allPdTypes,
trendGraphInfo,
getTimeList,
timeList,
selectTime,
activeTime,
prpdTimeArr
};
},
components: {
totalPrpd,
prpdAndPrps,
eventCount,
historyTrendGraph
}
})
.use(antd)
.use(ElementPlus, {
locale: ElementPlusLocaleZhCn // 使用中文语言包
})
.mount('#app');
</script>
</body>
</html>