联调补招日志功能

This commit is contained in:
guanj
2025-08-26 09:45:01 +08:00
parent d6c494bd96
commit e277fd01a3
10 changed files with 5431 additions and 5416 deletions

View File

@@ -1,23 +1,25 @@
<template>
<el-config-provider :locale="zhCn">
<router-view></router-view>
</el-config-provider>
</template>
<script lang="ts" setup>
import zhCn from 'element-plus/dist/locale/zh-cn.mjs'
import useSetTheme from '@/utils/setTheme'
import { onMounted } from 'vue'
useSetTheme()
onMounted(async () => {
const response = await fetch('/')
const WebSocketUrl:any = response.headers.get('X-WebSocket-Url')
const MqttUrl:any = response.headers.get('X-MqttUrl-Url')
localStorage.setItem('WebSocketUrl', WebSocketUrl)
localStorage.setItem('MqttUrl', MqttUrl)
})
</script>
<style lang="scss">
/* Your SCSS styles here */
</style>
<template>
<el-config-provider :locale="zhCn">
<router-view></router-view>
</el-config-provider>
</template>
<script lang="ts" setup>
import zhCn from 'element-plus/dist/locale/zh-cn.mjs'
import useSetTheme from '@/utils/setTheme'
import { onMounted } from 'vue'
useSetTheme()
onMounted(async () => {
const response = await fetch('/')
const WebSocketUrl:any = response.headers.get('X-WebSocket-Url')
const WebSocketUrl2:any = response.headers.get('X-WebSocket-Url2')
const MqttUrl:any = response.headers.get('X-MqttUrl-Url')
localStorage.setItem('WebSocketUrl2', WebSocketUrl2)
localStorage.setItem('WebSocketUrl', WebSocketUrl)
localStorage.setItem('MqttUrl', MqttUrl)
})
</script>
<style lang="scss">
/* Your SCSS styles here */
</style>

View File

@@ -1,200 +1,205 @@
import { ElMessage, EVENT_CODE } from 'element-plus'
// 定义消息类型,用于类型检查
type MessageType = {
[key: string]: any
}
export default class SocketService {
// 单例模式实例
private static instance: SocketService | null = null
// 和服务端连接的socket对象
private ws: WebSocket | null = null
// 存储回调函数
private callBackMapping: { [key: string]: ((message: MessageType) => void) | null } = {}
// 标识是否连接成功
private connected: boolean = false
// 记录重试的次数
private sendRetryCount: number = 0
// 重新连接尝试的次数
private connectRetryCount: number = 0
// Web Worker 实例
private work: Worker | null = null
// 临时的 Blob URL
private workerBlobUrl: string | null = null
// 上次活动时间戳
private lastActivityTime: number = 0
// 最后一次收到心跳回复时间
private lastResponseHeartTime: number = Date.now()
// 重新连接延迟,单位毫秒
private reconnectDelay: number = 5000
// 单例模式获取实例
public static get Instance(): SocketService {
if (!this.instance) {
this.instance = new SocketService()
}
return this.instance
}
// 定义连接服务器的方法
public async connect(id: string) {
if (!window.WebSocket) {
console.log('您的浏览器不支持WebSocket')
return
}
setTimeout(() => {
// ws://192.168.1.69:10407/mgtt/api/pushMessage/
const url = (localStorage.getItem('WebSocketUrl') || 'ws://192.168.1.68:10407/api/pushMessage/') + id
this.ws = new WebSocket(url)
this.ws.onopen = () => this.handleOpen()
this.ws.onclose = () => this.handleClose()
this.ws.onerror = () => this.handleError()
this.ws.onmessage = event => this.handleMessage(event)
}, 0)
}
// 处理连接成功事件
private handleOpen(): void {
ElMessage.success('webSocket连接服务端成功了')
console.log('连接服务端成功了')
this.connected = true
this.connectRetryCount = 0
this.updateLastActivityTime()
this.startHeartbeat()
}
// 处理连接关闭事件
private handleClose(): void {
console.log('连接webSocket服务端关闭')
this.connected = false
this.connectRetryCount++
this.clearHeartbeat()
// 可根据需要添加重连逻辑
// setTimeout(() => this.connect(), 500 * this.connectRetryCount);
}
// 处理连接错误事件
private handleError(): void {
ElMessage.error('webSocket连接异常')
}
// 处理服务端发送过来的数据
private handleMessage(event: MessageEvent): void {
// console.log('🚀 ~ SocketService ~ handleMessage ~ event.data:', event.data)
if (event.data == '连接成功') {
this.sendHeartbeat()
} else if (event.data.length > 10) {
let message: MessageType
try {
// console.log('Received message:', event.data)
message = JSON.parse(event.data)
} catch (e) {
console.error('消息解析失败', event.data, e)
return
}
// console.log("🚀 ~ SocketService ~ handleMessage ~ message:", message)
// 通过接受服务端发送的type字段来回调函数
if (message.key && this.callBackMapping['message']) {
this.callBackMapping['message']!(message)
} else {
console.log('抛弃====>')
// console.log(event.data)
// 丢弃或继续写你的逻辑
}
} else {
ElMessage.error(event.data)
}
}
// 启动心跳检测
private startHeartbeat(): void {
this.lastResponseHeartTime = Date.now()
const url = window.URL.createObjectURL(
new Blob(['(function(e){setInterval(function(){this.postMessage(null)},30000)})()'])
)
this.workerBlobUrl = url
this.work = new Worker(url)
this.work.onmessage = e => this.handleWorkerMessage(e)
}
// 处理 Web Worker 消息
private handleWorkerMessage(e: MessageEvent): void {
// if (this.lastActivityTime - this.lastResponseHeartTime > 30000) {
// // 说明已经三轮心跳没收到回复了,关闭检测,提示用户。
// // ElMessage.error('业务主体模块发生未知异常,请尝试重新启动!')
// this.clearHeartbeat()
// return
// }
// console.log(123);
this.sendHeartbeat()
}
// 发送心跳消息
private sendHeartbeat(): void {
// console.log(new Date() + '进入心跳消息发送。。。。。。。。。。。。。')
if (this.ws) {
this.ws.send('alive')
this.updateLastActivityTime()
}
}
// 更新活动时间
private updateLastActivityTime(): void {
this.lastActivityTime = Date.now()
}
// 清除心跳检测
private clearHeartbeat(): void {
if (this.work) {
this.work.terminate()
this.work = null
}
if (this.workerBlobUrl) {
window.URL.revokeObjectURL(this.workerBlobUrl)
this.workerBlobUrl = null
}
}
// 回调函数的注册
public registerCallBack(socketType: string, callBack: (message: MessageType) => void): void {
this.callBackMapping[socketType] = callBack
}
// 取消某一个回调函数
public unRegisterCallBack(socketType: string): void {
this.callBackMapping[socketType] = null
}
// 发送数据的方法
public send(data: any): void {
if (this.connected) {
this.sendRetryCount = 0
try {
if (this.ws) {
this.ws.send(JSON.stringify(data))
}
} catch (e) {
if (this.ws) {
this.ws.send(data)
}
}
} else {
this.sendRetryCount++
setTimeout(() => this.send(data), this.sendRetryCount * 500)
}
}
// 断开方法
public closeWs(): void {
if (this.connected && this.ws) {
this.ws.close()
}
console.log('执行WS关闭命令..')
}
}
import { ElMessage, EVENT_CODE } from 'element-plus'
// 定义消息类型,用于类型检查
type MessageType = {
[key: string]: any
}
export default class SocketService {
// 单例模式实例
private static instance: SocketService | null = null
// 和服务端连接的socket对象
private ws: WebSocket | null = null
// 存储回调函数
private callBackMapping: { [key: string]: ((message: MessageType) => void) | null } = {}
// 标识是否连接成功
private connected: boolean = false
// 记录重试的次数
private sendRetryCount: number = 0
// 重新连接尝试的次数
private connectRetryCount: number = 0
// Web Worker 实例
private work: Worker | null = null
// 临时的 Blob URL
private workerBlobUrl: string | null = null
// 上次活动时间戳
private lastActivityTime: number = 0
// 最后一次收到心跳回复时间
private lastResponseHeartTime: number = Date.now()
// 重新连接延迟,单位毫秒
private reconnectDelay: number = 5000
// 单例模式获取实例
public static get Instance(): SocketService {
if (!this.instance) {
this.instance = new SocketService()
}
return this.instance
}
// 定义连接服务器的方法
public async connect(url: string) {
if (!window.WebSocket) {
console.log('您的浏览器不支持WebSocket')
return
}
setTimeout(() => {
// ws://192.168.1.69:10407/mgtt
// const url =
// (localStorage.getItem('WebSocketUrl') == 'null'
// ? 'ws://192.168.1.130:10405'
// : localStorage.getItem('WebSocketUrl')) + id
this.ws = new WebSocket(url)
this.ws.onopen = () => this.handleOpen()
this.ws.onclose = () => this.handleClose()
this.ws.onerror = () => this.handleError()
this.ws.onmessage = event => this.handleMessage(event)
}, 0)
}
// 处理连接成功事件
private handleOpen(): void {
ElMessage.success('webSocket连接服务端成功了')
console.log('连接服务端成功了')
this.connected = true
this.connectRetryCount = 0
this.updateLastActivityTime()
this.startHeartbeat()
}
// 处理连接关闭事件
private handleClose(): void {
console.log('连接webSocket服务端关闭')
this.connected = false
this.connectRetryCount++
this.clearHeartbeat()
// 可根据需要添加重连逻辑
// setTimeout(() => this.connect(), 500 * this.connectRetryCount);
}
// 处理连接错误事件
private handleError(): void {
ElMessage.error('webSocket连接异常')
}
// 处理服务端发送过来的数据
private handleMessage(event: MessageEvent): void {
// console.log('🚀 ~ SocketService ~ handleMessage ~ event.data:', event.data)
if (event.data == '连接成功') {
this.sendHeartbeat()
} else if (event.data == 'connect') {
} else if (event.data.length > 10) {
let message: MessageType
try {
// console.log('Received message:', event.data)
message = JSON.parse(event.data)
} catch (e) {
console.error('消息解析失败', event.data, e)
return
}
// console.log("🚀 ~ SocketService ~ handleMessage ~ message:", message)
// 通过接受服务端发送的type字段来回调函数
if ((message.key || message.code) && this.callBackMapping['message']) {
this.callBackMapping['message']!(message)
} else {
console.log('抛弃====>')
// console.log(event.data)
// 丢弃或继续写你的逻辑
}
} else {
ElMessage.error(event.data)
}
}
// 启动心跳检测
private startHeartbeat(): void {
this.lastResponseHeartTime = Date.now()
const url = window.URL.createObjectURL(
new Blob(['(function(e){setInterval(function(){this.postMessage(null)},30000)})()'])
)
this.workerBlobUrl = url
this.work = new Worker(url)
this.work.onmessage = e => this.handleWorkerMessage(e)
}
// 处理 Web Worker 消息
private handleWorkerMessage(e: MessageEvent): void {
// if (this.lastActivityTime - this.lastResponseHeartTime > 30000) {
// // 说明已经三轮心跳没收到回复了,关闭检测,提示用户。
// // ElMessage.error('业务主体模块发生未知异常,请尝试重新启动!')
// this.clearHeartbeat()
// return
// }
// console.log(123);
this.sendHeartbeat()
}
// 发送心跳消息
private sendHeartbeat(): void {
// console.log(new Date() + '进入心跳消息发送。。。。。。。。。。。。。')
if (this.ws) {
this.ws.send('alive')
this.updateLastActivityTime()
}
}
// 更新活动时间
private updateLastActivityTime(): void {
this.lastActivityTime = Date.now()
}
// 清除心跳检测
private clearHeartbeat(): void {
if (this.work) {
this.work.terminate()
this.work = null
}
if (this.workerBlobUrl) {
window.URL.revokeObjectURL(this.workerBlobUrl)
this.workerBlobUrl = null
}
}
// 回调函数的注册
public registerCallBack(socketType: string, callBack: (message: MessageType) => void): void {
this.callBackMapping[socketType] = callBack
}
// 取消某一个回调函数
public unRegisterCallBack(socketType: string): void {
this.callBackMapping[socketType] = null
}
// 发送数据的方法
public send(data: any): void {
if (this.connected) {
this.sendRetryCount = 0
try {
if (this.ws) {
this.ws.send(JSON.stringify(data))
}
} catch (e) {
if (this.ws) {
this.ws.send(data)
}
}
} else {
this.sendRetryCount++
setTimeout(() => this.send(data), this.sendRetryCount * 500)
}
}
// 断开方法
public closeWs(): void {
if (this.connected && this.ws) {
this.ws.close()
}
console.log('执行WS关闭命令..')
}
}

View File

@@ -1,346 +1,346 @@
<template>
<el-dialog v-model="Views" draggable title="评估策略配置" width="1000" :before-close="handleClose">
<div style="display: flex; justify-content: end">
<el-button icon="el-icon-Refresh" type="primary" @click="restores">一键还原</el-button>
</div>
<el-divider content-position="left">光伏电站评估策略配置</el-divider>
<vxe-table v-bind="defaultAttribute" :loading="loading" :data="photovoltaicData" :span-method="mergeRowMethod">
<vxe-colgroup field="group0" title="等级">
<vxe-column field="name" width="180" title="结果"></vxe-column>
</vxe-colgroup>
<vxe-column field="comparisonOperators1" title="安全(个)">
<template #default="row">
<div class="cellBox" @click="cells(row, row.row.comparisonOperators1, row.row.count1, 0)">
{{ symbolJudgment(row.row.comparisonOperators1)
}}{{ row.row.comparisonOperators1 == '/' ? '' : row.row.count1 }}
</div>
</template>
</vxe-column>
<vxe-column field="comparisonOperators2" title="III级预警(个)">
<template #default="row">
<div class="cellBox" @click="cells(row, row.row.comparisonOperators2, row.row.count2, 0)">
{{ symbolJudgment(row.row.comparisonOperators2)
}}{{ row.row.comparisonOperators2 == '/' ? '' : row.row.count2 }}
</div>
</template>
</vxe-column>
<vxe-column field="comparisonOperators3" title="II级预警(个)">
<template #default="row">
<div class="cellBox" @click="cells(row, row.row.comparisonOperators3, row.row.count3, 0)">
{{ symbolJudgment(row.row.comparisonOperators3)
}}{{ row.row.comparisonOperators3 == '/' ? '' : row.row.count3 }}
</div>
</template>
</vxe-column>
<vxe-column field="comparisonOperators4" title="I级预警(个)">
<template #default="row">
<div class="cellBox" @click="cells(row, row.row.comparisonOperators4, row.row.count4, 0)">
{{ symbolJudgment(row.row.comparisonOperators4)
}}{{ row.row.comparisonOperators4 == '/' ? '' : row.row.count4 }}
</div>
</template>
</vxe-column>
</vxe-table>
<el-divider content-position="left">充电站电加热负荷电气化铁路评估策略配置</el-divider>
<vxe-table v-bind="defaultAttribute" ref="xTable" :loading="loading" :data="tableData">
<vxe-colgroup field="group0" title="等级">
<vxe-column field="name" width="180" title="结果"></vxe-column>
</vxe-colgroup>
<vxe-column field="comparisonOperators1" title="THD(%)">
<template #default="row">
<div class="cellBox" @click="cells(row, row.row.comparisonOperators1, row.row.count1, 1)">
{{ symbolJudgment(row.row.comparisonOperators1)
}}{{ row.row.comparisonOperators1 == '/' ? '' : row.row.count1 }}
</div>
</template>
</vxe-column>
<vxe-column field="comparisonOperators2" title="2~25次谐波合格个数">
<template #default="row">
<div class="cellBox" @click="cells(row, row.row.comparisonOperators2, row.row.count2, 2)">
{{ symbolJudgment(row.row.comparisonOperators2)
}}{{ row.row.comparisonOperators2 == '/' ? '' : row.row.count2 }}
</div>
</template>
</vxe-column>
<vxe-column field="comparisonOperators3" title="次谐波合格个数">
<template #default="row">
<div class="cellBox" @click="cells(row, row.row.comparisonOperators3, row.row.count3, 3)">
{{ symbolJudgment(row.row.comparisonOperators3)
}}{{ row.row.comparisonOperators3 == '/' ? '' : row.row.count3 }}
</div>
</template>
</vxe-column>
<vxe-column field="comparisonOperators4" title="偶次谐波合格个数">
<template #default="row">
<div class="cellBox" @click="cells(row, row.row.comparisonOperators4, row.row.count4, 4)">
{{ symbolJudgment(row.row.comparisonOperators4)
}}{{ row.row.comparisonOperators4 == '/' ? '' : row.row.count4 }}
</div>
</template>
</vxe-column>
</vxe-table>
<!-- 修改 -->
<el-dialog class="dialogBox" draggable v-model="dialogVisible" title="安全等级配置" width="500">
<el-form :model="form" label-width="auto">
<el-form-item label="运算符号:">
<el-radio-group v-model="form.comparisonOperators" @change="groupChang">
<el-radio v-for="item in sign" :label="item.name">{{ item.name }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="数量:">
<el-input-number
v-model="form.count"
:disabled="disabled"
:min="0"
:precision="0"
:max="10000000"
style="width: 200px"
/>
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="add">确定</el-button>
</div>
</template>
</el-dialog>
</el-dialog>
</template>
<script setup lang="ts">
import { ref, onMounted, provide, reactive } from 'vue'
import { defaultAttribute } from '@/components/table/defaultAttribute'
import { mainHeight } from '@/utils/layout'
import { queyDetail, addCarryc, restore, queyDetailDhl, adddhl } from '@/api/advance-boot/bearingCapacity'
import { ElMessage, ElMessageBox } from 'element-plus'
import { VxeTablePropTypes } from 'vxe-table'
defineOptions({
name: 'Advancedanalysis/eventcorrelation'
})
const emit = defineEmits(['View'])
const Views = ref(true)
const xTable = ref()
const loading = ref(false)
const photovoltaicData: any = ref([])
const sum = ref(0)
const tableData: any = ref([])
const list: any = ref({})
const form: any = ref({
comparisonOperators: '',
count: ''
})
const sign = ref([
{
name: '>'
},
{
name: '<'
},
{
name: '>='
},
{
name: '<='
},
{
name: '=='
},
{
name: '/'
}
])
const dialogVisible = ref(false)
const disabled = ref(false)
const info = () => {
// 光伏
queyDetail().then(res => {
photovoltaicData.value = []
let title = ['安全', 'III级预警', 'II级预警', 'I级预警']
let p = 0
res.data.forEach((item: any, i: any) => {
item.capacityStrategysingleVOList.forEach((item1: any, i1: any) => {
photovoltaicData.value.push({
name: title[i],
id: item1.id,
result: item.result
})
p++
item1.carryCapacityStrategyIndexVOList.forEach((item2: any) => {
photovoltaicData.value[p - 1]['comparisonOperators' + item2.indexResult] = item2.comparisonOperators
photovoltaicData.value[p - 1]['count' + item2.indexResult] = item2.count
})
})
})
console.log('🚀 ~ queyDetail ~ photovoltaicData.value:', photovoltaicData.value)
})
// 电弧炉
queyDetailDhl().then(res => {
tableData.value = res.data
tableData.value[0].name = '电弧炉'
tableData.value[1].name = '充电桩'
tableData.value[2].name = '电气化铁路'
})
}
// <span @click="cells(row,comparisonOperators2,count2)">
const cells = (row: any, comparisonOperators: any, count: any, num: number) => {
form.value = {
comparisonOperators: comparisonOperators,
count: count,
result: row.row.result,
id: row.row.id,
indexResult: row.columnIndex
}
sum.value = num
if (num != 0) {
list.value = JSON.parse(JSON.stringify(row.row))
}
groupChang(comparisonOperators)
dialogVisible.value = true
}
// 运算符变化
const groupChang = e => {
if (e == '/') {
form.value.count = 0
disabled.value = true
} else {
disabled.value = false
}
}
// 安全等级配置确认
const add = () => {
if (sum.value == 0) {
addCarryc(form.value).then(res => {
ElMessage.success('修改成功!')
dialogVisible.value = false
info()
})
} else {
// sum.value = num
// list.value = row
list.value['comparisonOperators' + sum.value] = form.value.comparisonOperators
list.value['count' + sum.value] = form.value.count
list.value.userFlag = 0
list.value.protoFlag = 0
adddhl(list.value).then(res => {
ElMessage.success('修改成功!')
dialogVisible.value = false
info()
})
}
}
// 还原
const restores = () => {
restore().then(res => {
ElMessage.success('还原成功!')
info()
})
}
// 通用行合并函数(将相同多列数据合并为一行)
const mergeRowMethod = ({ row, _rowIndex, column, visibleData }) => {
const fields = ['name']
const cellValue = row[column.field]
if (cellValue && fields.includes(column.field)) {
const prevRow = visibleData[_rowIndex - 1]
let nextRow = visibleData[_rowIndex + 1]
if (prevRow && prevRow[column.field] === cellValue) {
return { rowspan: 0, colspan: 0 }
} else {
let countRowspan = 1
while (nextRow && nextRow[column.field] === cellValue) {
nextRow = visibleData[++countRowspan + _rowIndex]
}
if (countRowspan > 1) {
return { rowspan: countRowspan, colspan: 1 }
}
}
}
}
const symbolJudgment = (value: string) => {
if (value == '==') {
return '='
} else {
return value
}
}
onMounted(() => {
info()
})
// 取消
const handleClose = () => {
emit('View')
}
</script>
<style lang="scss" scoped>
:deep(.vxe-table--header thead tr:first-of-type th:first-of-type) {
// background: var(--vxe-table-header-background-color);
background-image: linear-gradient(var(--vxe-table-border-color), var(--vxe-table-border-color)),
linear-gradient(#e8eaec00, #e8eaec00);
}
:deep(.vxe-table--header thead tr:first-of-type th:first-of-type:before) {
content: '';
position: absolute;
width: 1px;
height: 98px; /*这里需要自己调整根据td的宽度和高度*/
top: 0;
left: 0;
background-color: grey;
opacity: 0.3;
display: block;
transform: rotate(-66deg); /*这里需要自己调整,根据线的位置*/
transform-origin: top;
}
:deep(.vxe-table--header thead tr:last-of-type th:first-of-type:before) {
content: '';
position: absolute;
width: 1px;
height: 98px; /*这里需要自己调整根据td的宽度和高度*/
bottom: 0;
right: 0;
background-color: grey;
opacity: 0.3;
display: block;
transform: rotate(-66deg); /*这里需要自己调整,根据线的位置*/
transform-origin: bottom;
}
.cellBox {
cursor: pointer;
color: var(--el-color-primary);
font-weight: 600;
text-decoration: underline;
}
</style>
<style lang="scss">
.el-dialog__body {
max-height: none !important;
}
.dialogBox {
margin-top: calc(15vh + 200px) !important;
}
/* 确保对话框在页面居中 */
// .el-dialog {
// display: flex;
// flex-direction: column;
// margin: 0 !important;
// position: absolute;
// top: 50%;
// left: 50%;
// transform: translate(-50%, -50%);
// max-height: calc(100% - 30px);
// max-width: calc(100% - 30px);
// }
// /* 确保遮罩层全屏显示 */
// .el-dialog__wrapper {
// display: flex;
// align-items: center;
// justify-content: center;
// }
</style>
<template>
<el-dialog v-model="Views" draggable title="评估策略配置" width="1000" :before-close="handleClose">
<div style="display: flex; justify-content: end">
<el-button icon="el-icon-Refresh" type="primary" @click="restores">一键还原</el-button>
</div>
<el-divider content-position="left">光伏电站评估策略配置</el-divider>
<vxe-table v-bind="defaultAttribute" :loading="loading" :data="photovoltaicData" :span-method="mergeRowMethod">
<vxe-colgroup field="group0" title="等级">
<vxe-column field="name" width="180" title="结果"></vxe-column>
</vxe-colgroup>
<vxe-column field="comparisonOperators1" title="安全(个)">
<template #default="row">
<div class="cellBox" @click="cells(row, row.row.comparisonOperators1, row.row.count1, 0)">
{{ symbolJudgment(row.row.comparisonOperators1)
}}{{ row.row.comparisonOperators1 == '/' ? '' : row.row.count1 }}
</div>
</template>
</vxe-column>
<vxe-column field="comparisonOperators2" title="III级预警(个)">
<template #default="row">
<div class="cellBox" @click="cells(row, row.row.comparisonOperators2, row.row.count2, 0)">
{{ symbolJudgment(row.row.comparisonOperators2)
}}{{ row.row.comparisonOperators2 == '/' ? '' : row.row.count2 }}
</div>
</template>
</vxe-column>
<vxe-column field="comparisonOperators3" title="II级预警(个)">
<template #default="row">
<div class="cellBox" @click="cells(row, row.row.comparisonOperators3, row.row.count3, 0)">
{{ symbolJudgment(row.row.comparisonOperators3)
}}{{ row.row.comparisonOperators3 == '/' ? '' : row.row.count3 }}
</div>
</template>
</vxe-column>
<vxe-column field="comparisonOperators4" title="I级预警(个)">
<template #default="row">
<div class="cellBox" @click="cells(row, row.row.comparisonOperators4, row.row.count4, 0)">
{{ symbolJudgment(row.row.comparisonOperators4)
}}{{ row.row.comparisonOperators4 == '/' ? '' : row.row.count4 }}
</div>
</template>
</vxe-column>
</vxe-table>
<el-divider content-position="left">充电站电加热负荷电气化铁路评估策略配置</el-divider>
<vxe-table v-bind="defaultAttribute" ref="xTable" :loading="loading" :data="tableData">
<vxe-colgroup field="group0" title="等级">
<vxe-column field="name" width="180" title="结果"></vxe-column>
</vxe-colgroup>
<vxe-column field="comparisonOperators1" title="THD(%)">
<template #default="row">
<div class="cellBox" @click="cells(row, row.row.comparisonOperators1, row.row.count1, 1)">
{{ symbolJudgment(row.row.comparisonOperators1)
}}{{ row.row.comparisonOperators1 == '/' ? '' : row.row.count1 }}
</div>
</template>
</vxe-column>
<vxe-column field="comparisonOperators2" title="2~25次谐波合格个数">
<template #default="row">
<div class="cellBox" @click="cells(row, row.row.comparisonOperators2, row.row.count2, 2)">
{{ symbolJudgment(row.row.comparisonOperators2)
}}{{ row.row.comparisonOperators2 == '/' ? '' : row.row.count2 }}
</div>
</template>
</vxe-column>
<vxe-column field="comparisonOperators3" title="次谐波合格个数">
<template #default="row">
<div class="cellBox" @click="cells(row, row.row.comparisonOperators3, row.row.count3, 3)">
{{ symbolJudgment(row.row.comparisonOperators3)
}}{{ row.row.comparisonOperators3 == '/' ? '' : row.row.count3 }}
</div>
</template>
</vxe-column>
<vxe-column field="comparisonOperators4" title="偶次谐波合格个数">
<template #default="row">
<div class="cellBox" @click="cells(row, row.row.comparisonOperators4, row.row.count4, 4)">
{{ symbolJudgment(row.row.comparisonOperators4)
}}{{ row.row.comparisonOperators4 == '/' ? '' : row.row.count4 }}
</div>
</template>
</vxe-column>
</vxe-table>
<!-- 修改 -->
<el-dialog class="dialogBox" draggable v-model="dialogVisible" title="安全等级配置" width="500">
<el-form :model="form" label-width="auto">
<el-form-item label="运算符号:">
<el-radio-group v-model="form.comparisonOperators" @change="groupChang">
<el-radio v-for="item in sign" :label="item.name">{{ item.name }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="数量:">
<el-input-number
v-model="form.count"
:disabled="disabled"
:min="0"
:precision="0"
:max="10000000"
style="width: 200px"
/>
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="add">确定</el-button>
</div>
</template>
</el-dialog>
</el-dialog>
</template>
<script setup lang="ts">
import { ref, onMounted, provide, reactive } from 'vue'
import { defaultAttribute } from '@/components/table/defaultAttribute'
import { mainHeight } from '@/utils/layout'
import { queyDetail, addCarryc, restore, queyDetailDhl, adddhl } from '@/api/advance-boot/bearingCapacity'
import { ElMessage, ElMessageBox } from 'element-plus'
import { VxeTablePropTypes } from 'vxe-table'
defineOptions({
name: 'Advancedanalysis/eventcorrelation'
})
const emit = defineEmits(['View'])
const Views = ref(true)
const xTable = ref()
const loading = ref(false)
const photovoltaicData: any = ref([])
const sum = ref(0)
const tableData: any = ref([])
const list: any = ref({})
const form: any = ref({
comparisonOperators: '',
count: ''
})
const sign = ref([
{
name: '>'
},
{
name: '<'
},
{
name: '>='
},
{
name: '<='
},
{
name: '=='
},
{
name: '/'
}
])
const dialogVisible = ref(false)
const disabled = ref(false)
const info = () => {
// 光伏
queyDetail().then(res => {
photovoltaicData.value = []
let title = ['安全', 'III级预警', 'II级预警', 'I级预警']
let p = 0
res.data.forEach((item: any, i: any) => {
item.capacityStrategysingleVOList.forEach((item1: any, i1: any) => {
photovoltaicData.value.push({
name: title[i],
id: item1.id,
result: item.result
})
p++
item1.carryCapacityStrategyIndexVOList.forEach((item2: any) => {
photovoltaicData.value[p - 1]['comparisonOperators' + item2.indexResult] = item2.comparisonOperators
photovoltaicData.value[p - 1]['count' + item2.indexResult] = item2.count
})
})
})
console.log('🚀 ~ queyDetail ~ photovoltaicData.value:', photovoltaicData.value)
})
// 电弧炉
queyDetailDhl().then(res => {
tableData.value = res.data
tableData.value[0].name = '电弧炉'
tableData.value[1].name = '充电桩'
tableData.value[2].name = '电气化铁路'
})
}
// <span @click="cells(row,comparisonOperators2,count2)">
const cells = (row: any, comparisonOperators: any, count: any, num: number) => {
form.value = {
comparisonOperators: comparisonOperators,
count: count,
result: row.row.result,
id: row.row.id,
indexResult: row.columnIndex
}
sum.value = num
if (num != 0) {
list.value = JSON.parse(JSON.stringify(row.row))
}
groupChang(comparisonOperators)
dialogVisible.value = true
}
// 运算符变化
const groupChang = e => {
if (e == '/') {
form.value.count = 0
disabled.value = true
} else {
disabled.value = false
}
}
// 安全等级配置确认
const add = () => {
if (sum.value == 0) {
addCarryc(form.value).then(res => {
ElMessage.success('修改成功!')
dialogVisible.value = false
info()
})
} else {
// sum.value = num
// list.value = row
list.value['comparisonOperators' + sum.value] = form.value.comparisonOperators
list.value['count' + sum.value] = form.value.count
list.value.userFlag = 0
list.value.protoFlag = 0
adddhl(list.value).then(res => {
ElMessage.success('修改成功!')
dialogVisible.value = false
info()
})
}
}
// 还原
const restores = () => {
restore().then(res => {
ElMessage.success('还原成功!')
info()
})
}
// 通用行合并函数(将相同多列数据合并为一行)
const mergeRowMethod = ({ row, _rowIndex, column, visibleData }) => {
const fields = ['name']
const cellValue = row[column.field]
if (cellValue && fields.includes(column.field)) {
const prevRow = visibleData[_rowIndex - 1]
let nextRow = visibleData[_rowIndex + 1]
if (prevRow && prevRow[column.field] === cellValue) {
return { rowspan: 0, colspan: 0 }
} else {
let countRowspan = 1
while (nextRow && nextRow[column.field] === cellValue) {
nextRow = visibleData[++countRowspan + _rowIndex]
}
if (countRowspan > 1) {
return { rowspan: countRowspan, colspan: 1 }
}
}
}
}
const symbolJudgment = (value: string) => {
if (value == '==') {
return '='
} else {
return value
}
}
onMounted(() => {
info()
})
// 取消
const handleClose = () => {
emit('View')
}
</script>
<style lang="scss" scoped>
:deep(.vxe-table--header thead tr:first-of-type th:first-of-type) {
// background: var(--vxe-table-header-background-color);
background-image: linear-gradient(var(--vxe-table-border-color), var(--vxe-table-border-color)),
linear-gradient(#e8eaec00, #e8eaec00);
}
:deep(.vxe-table--header thead tr:first-of-type th:first-of-type:before) {
content: '';
position: absolute;
width: 1px;
height: 98px; /*这里需要自己调整根据td的宽度和高度*/
top: 0;
left: 0;
background-color: grey;
opacity: 0.3;
display: block;
transform: rotate(-66deg); /*这里需要自己调整,根据线的位置*/
transform-origin: top;
}
:deep(.vxe-table--header thead tr:last-of-type th:first-of-type:before) {
content: '';
position: absolute;
width: 1px;
height: 98px; /*这里需要自己调整根据td的宽度和高度*/
bottom: 0;
right: 0;
background-color: grey;
opacity: 0.3;
display: block;
transform: rotate(-66deg); /*这里需要自己调整,根据线的位置*/
transform-origin: bottom;
}
.cellBox {
cursor: pointer;
color: var(--el-color-primary);
font-weight: 600;
text-decoration: underline;
}
</style>
<style lang="scss">
.el-dialog__body {
max-height: none !important;
}
.dialogBox {
margin-top: calc(15vh + 200px) !important;
}
/* 确保对话框在页面居中 */
// .el-dialog {
// display: flex;
// flex-direction: column;
// margin: 0 !important;
// position: absolute;
// top: 50%;
// left: 50%;
// transform: translate(-50%, -50%);
// max-height: calc(100% - 30px);
// max-width: calc(100% - 30px);
// }
// /* 确保遮罩层全屏显示 */
// .el-dialog__wrapper {
// display: flex;
// align-items: center;
// justify-content: center;
// }
</style>

View File

@@ -1,211 +1,211 @@
<template>
<div class="default-main">
<div v-show="addedShow">
<TableHeader datePicker showExport ref="TableHeaderRef">
<template #select>
<el-form-item label="评估类型">
<el-select
v-model="tableStore.table.params.evaluateType"
clearable
placeholder="请选择评估类型"
>
<el-option v-for="item in uesrList" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
</el-form-item>
</template>
<template #operation>
<el-button icon="el-icon-Setting" type="primary" @click="configuration">评估策略配置</el-button>
<el-button icon="el-icon-Plus" type="primary" @click="addAssess">新增评估</el-button>
</template>
</TableHeader>
<Table ref="tableRef" />
<policy v-if="policyView" @View="policyView = false" />
</div>
<!-- <Added v-if="!addedShow" @quit="addedShow = true" /> -->
<div v-if="!addedShow" style="position: relative">
<el-tabs v-model="activeName" type="border-card" :style="{ height: height }">
<el-tab-pane label="光伏电站承载能力评估" name="1" v-if="code == null || code == 1">
<photovoltaic :rowList="rowList" />
</el-tab-pane>
<el-tab-pane
label="充电站、电加热负荷、电气化铁路承载能力评估"
name="2"
v-if="code == null || code == 2"
>
<charge :rowList="rowList" />
</el-tab-pane>
</el-tabs>
<el-button class="quit" icon="el-icon-Back" @click="quit">返回</el-button>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted, provide, reactive } from 'vue'
import TableStore from '@/utils/tableStore'
import Table from '@/components/table/index.vue'
import TableHeader from '@/components/table/header/index.vue'
import Area from '@/components/form/area/index.vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import policy from './components/policy.vue'
import photovoltaic from './components/photovoltaic.vue'
import charge from './components/charge.vue'
import { remove } from '@/api/advance-boot/bearingCapacity'
import { mainHeight } from '@/utils/layout'
import { useDictData } from '@/stores/dictData'
defineOptions({
name: 'estimate/evaluationList'
})
const height = mainHeight(20).height
const dictData = useDictData()
const levelList = dictData.getBasicData('Dev_Voltage_Stand')
const uesrList = dictData.getBasicData('CARRY_CAPCITY_USER_TYPE')
const activeName = ref('1')
const policyView = ref(false)
const addedShow = ref(true)
const code = ref(null)
const rowList = ref({})
const TableHeaderRef = ref()
const tableStore: any = new TableStore({
url: '/advance-boot/result/queryResultList',
method: 'POST',
column: [
{
title: '序号',
width: '80',
formatter: (row: any) => {
return (tableStore.table.params.pageNum - 1) * tableStore.table.params.pageSize + row.rowIndex + 1
}
},
{ field: 'userName', title: '用户名称' },
{
field: 'evaluateType',
title: '评估类型',
formatter: (row: any) => {
return uesrList.filter(item => item.id == row.cellValue)[0].name
}
},
{
field: 'lineName',
title: '配变台区',
width: '500',
formatter: (row: any) => {
return row.cellValue ? row.cellValue : '/'
}
},
{
field: 'reslutLevel',
title: '评估结果',
type: 'html',
formatter: (row: any) => {
// 1-安全2-III级预警3-II级预警4-I 级预警,5-禁止接入
return `<span style="color: ${
row.cellValue == 1
? '#2E7D32' // 深绿色 - 安全
: row.cellValue == 2
? '#0288D1' // 深蓝色 - III级预警
: row.cellValue == 3
? '#F57C00' // 橙色 - II级预警
: row.cellValue == 4
? '#E64A19' // 深橙色 - I级预警
: row.cellValue == 5
? '#C62828' // 深红色 - 禁止接入
: row.cellValue == 6
? '#00897B' // 深青色 - 允许接入
: ''
}">${
row.cellValue == 1
? '安全'
: row.cellValue == 2
? 'III级预警'
: row.cellValue == 3
? 'II级预警'
: row.cellValue == 4
? 'I 级预警'
: row.cellValue == 5
? '禁止接入'
: row.cellValue == 6
? '允许接入'
: ''
}</span>`
}
},
{ field: 'evaluateDate', title: '评估日期' },
{
title: '操作',
width: '180',
render: 'buttons',
buttons: [
{
name: 'edit',
title: '查看',
type: 'primary',
icon: 'el-icon-Plus',
render: 'basicButton',
click: row => {
rowList.value = row
let data = uesrList.filter(item => item.id == row.evaluateType)[0].code
data == 'Power_Station_Users'
? ((code.value = 1), (activeName.value = '1'))
: ((code.value = 2), (activeName.value = '2'))
addedShow.value = false
}
},
{
name: 'del',
text: '禁止接入',
type: 'danger',
icon: 'el-icon-Delete',
render: 'confirmButton',
popconfirm: {
confirmButtonText: '确认',
cancelButtonText: '取消',
confirmButtonType: 'danger',
title: '确定删除'
},
click: row => {
remove({ ids: row.id }).then(() => {
ElMessage.success('删除成功')
tableStore.index()
})
}
}
]
}
],
loadCallback: () => {}
})
tableStore.table.params.evaluateType = ''
tableStore.table.params.id = dictData.state.area[0].id
provide('tableStore', tableStore)
const quit = () => {
addedShow.value = true
tableStore.index()
rowList.value = {}
}
onMounted(() => {
tableStore.index()
})
const addAssess = () => {
addedShow.value = false
code.value = null
activeName.value = '1'
}
// 配置
const configuration = () => {
policyView.value = true
}
</script>
<style lang="scss" scoped>
.quit {
position: absolute;
top: 5px;
right: 10px;
}
</style>
<template>
<div class="default-main">
<div v-show="addedShow">
<TableHeader datePicker showExport ref="TableHeaderRef">
<template #select>
<el-form-item label="评估类型">
<el-select
v-model="tableStore.table.params.evaluateType"
clearable
placeholder="请选择评估类型"
>
<el-option v-for="item in uesrList" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
</el-form-item>
</template>
<template #operation>
<el-button icon="el-icon-Setting" type="primary" @click="configuration">评估策略配置</el-button>
<el-button icon="el-icon-Plus" type="primary" @click="addAssess">新增评估</el-button>
</template>
</TableHeader>
<Table ref="tableRef" />
<policy v-if="policyView" @View="policyView = false" />
</div>
<!-- <Added v-if="!addedShow" @quit="addedShow = true" /> -->
<div v-if="!addedShow" style="position: relative">
<el-tabs v-model="activeName" type="border-card" :style="{ height: height }">
<el-tab-pane label="光伏电站承载能力评估" name="1" v-if="code == null || code == 1">
<photovoltaic :rowList="rowList" />
</el-tab-pane>
<el-tab-pane
label="充电站、电加热负荷、电气化铁路承载能力评估"
name="2"
v-if="code == null || code == 2"
>
<charge :rowList="rowList" />
</el-tab-pane>
</el-tabs>
<el-button class="quit" icon="el-icon-Back" @click="quit">返回</el-button>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted, provide, reactive } from 'vue'
import TableStore from '@/utils/tableStore'
import Table from '@/components/table/index.vue'
import TableHeader from '@/components/table/header/index.vue'
import Area from '@/components/form/area/index.vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import policy from './components/policy.vue'
import photovoltaic from './components/photovoltaic.vue'
import charge from './components/charge.vue'
import { remove } from '@/api/advance-boot/bearingCapacity'
import { mainHeight } from '@/utils/layout'
import { useDictData } from '@/stores/dictData'
defineOptions({
name: 'estimate/evaluationList'
})
const height = mainHeight(20).height
const dictData = useDictData()
const levelList = dictData.getBasicData('Dev_Voltage_Stand')
const uesrList = dictData.getBasicData('CARRY_CAPCITY_USER_TYPE')
const activeName = ref('1')
const policyView = ref(false)
const addedShow = ref(true)
const code = ref(null)
const rowList = ref({})
const TableHeaderRef = ref()
const tableStore: any = new TableStore({
url: '/advance-boot/result/queryResultList',
method: 'POST',
column: [
{
title: '序号',
width: '80',
formatter: (row: any) => {
return (tableStore.table.params.pageNum - 1) * tableStore.table.params.pageSize + row.rowIndex + 1
}
},
{ field: 'userName', title: '用户名称' },
{
field: 'evaluateType',
title: '评估类型',
formatter: (row: any) => {
return uesrList.filter(item => item.id == row.cellValue)[0].name
}
},
{
field: 'lineName',
title: '配变台区',
width: '500',
formatter: (row: any) => {
return row.cellValue ? row.cellValue : '/'
}
},
{
field: 'reslutLevel',
title: '评估结果',
type: 'html',
formatter: (row: any) => {
// 1-安全2-III级预警3-II级预警4-I 级预警,5-禁止接入
return `<span style="color: ${
row.cellValue == 1
? '#2E7D32' // 深绿色 - 安全
: row.cellValue == 2
? '#0288D1' // 深蓝色 - III级预警
: row.cellValue == 3
? '#F57C00' // 橙色 - II级预警
: row.cellValue == 4
? '#E64A19' // 深橙色 - I级预警
: row.cellValue == 5
? '#C62828' // 深红色 - 禁止接入
: row.cellValue == 6
? '#00897B' // 深青色 - 允许接入
: ''
}">${
row.cellValue == 1
? '安全'
: row.cellValue == 2
? 'III级预警'
: row.cellValue == 3
? 'II级预警'
: row.cellValue == 4
? 'I 级预警'
: row.cellValue == 5
? '禁止接入'
: row.cellValue == 6
? '允许接入'
: ''
}</span>`
}
},
{ field: 'evaluateDate', title: '评估日期' },
{
title: '操作',
width: '180',
render: 'buttons',
buttons: [
{
name: 'edit',
title: '查看',
type: 'primary',
icon: 'el-icon-Plus',
render: 'basicButton',
click: row => {
rowList.value = row
let data = uesrList.filter(item => item.id == row.evaluateType)[0].code
data == 'Power_Station_Users'
? ((code.value = 1), (activeName.value = '1'))
: ((code.value = 2), (activeName.value = '2'))
addedShow.value = false
}
},
{
name: 'del',
text: '禁止接入',
type: 'danger',
icon: 'el-icon-Delete',
render: 'confirmButton',
popconfirm: {
confirmButtonText: '确认',
cancelButtonText: '取消',
confirmButtonType: 'danger',
title: '确定禁止接入'
},
click: row => {
remove({ ids: row.id }).then(() => {
ElMessage.success('禁止接入成功')
tableStore.index()
})
}
}
]
}
],
loadCallback: () => {}
})
tableStore.table.params.evaluateType = ''
tableStore.table.params.id = dictData.state.area[0].id
provide('tableStore', tableStore)
const quit = () => {
addedShow.value = true
tableStore.index()
rowList.value = {}
}
onMounted(() => {
tableStore.index()
})
const addAssess = () => {
addedShow.value = false
code.value = null
activeName.value = '1'
}
// 配置
const configuration = () => {
policyView.value = true
}
</script>
<style lang="scss" scoped>
.quit {
position: absolute;
top: 5px;
right: 10px;
}
</style>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff