map/ui/dasadmin/src/views/backend/home/windMatrixpage.vue
2025-01-15 13:49:55 +08:00

676 lines
24 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="FanList-content">
<div class="overviewPart" v-for="item in props.parentData">
<!-- <el-col :xs="12" :sm="8" :md="8" :lg="4" :xl="2" style="margin-bottom: 5px">-->
<div class="grid-content"
@click="handleClick(item)"
@contextmenu.prevent="windContextMenu($event,item)"
>
<div class="FanList-panel wind-default" :class="{
'': item.standard==1,
'': item.standard==0,
'wind-offline': item.attributeMap.processedoperationmode == 33
}">
<div class="fanlist-top">
<span :class="item.standard == 1 ? 'wind-mark-icon' : 'fanlist-icon'">
<img :class="item.standard == 1 ? '' : 'wind-picture'" src="~assets/dashboard/biaogan.png" alt="" />
</span>
<span class="fanlist-name"> {{ item.name }}</span>
<el-tag v-if="item.attributeMap.processedoperationmode === 20" class="tag-panel" :style="getStyles(item.attributeMap.color)" type="primary">并网</el-tag>
<el-tag v-if="item.attributeMap.processedoperationmode === 11" class="tag-panel" :style="getStyles(item.attributeMap.color)" type="primary">待机</el-tag>
<el-tag v-if="item.attributeMap.processedoperationmode === 16" class="tag-panel" :style="getStyles(item.attributeMap.color)" type="primary">启动</el-tag>
<el-tag v-if="item.attributeMap.processedoperationmode === 10" class="tag-panel" :style="getStyles(item.attributeMap.color)" type="primary"
>维护</el-tag>
<el-tag v-if="item.attributeMap.processedoperationmode === 0" class="tag-panel" :style="getStyles(item.attributeMap.color)" type="primary">离线</el-tag>
<el-tag v-if="item.attributeMap.processedoperationmode === 8" class="tag-panel" :style="getStyles(item.attributeMap.color)" type="primary">限功率运行</el-tag>
<el-tag v-if="item.attributeMap.processedoperationmode === 6" class="tag-panel" :style="getStyles(item.attributeMap.color)" type="primary">正常停机</el-tag>
<el-tag v-if="item.attributeMap.processedoperationmode === 1" class="tag-panel" :style="getStyles(item.attributeMap.color)" type="primary"
>外部因素导致停机</el-tag>
<el-tag v-if="item.attributeMap.processedoperationmode === 2" class="tag-panel" :style="getStyles(item.attributeMap.color)" type="primary">停机</el-tag>
<el-tag v-if="item.attributeMap.processedoperationmode === 1110" class="tag-panel" :style="getStyles(item.attributeMap.color)" type="primary">解缆状态</el-tag>
<el-tag v-if="item.attributeMap.processedoperationmode === 1111" class="tag-panel" :style="getStyles(item.attributeMap.color)" type="primary"
>电网故障停机</el-tag>
<el-tag v-if="item.attributeMap.processedoperationmode === 1112" class="tag-panel" :style="getStyles(item.attributeMap.color)" type="primary"
>安全链停机</el-tag>
<el-tag v-if="item.attributeMap.processedoperationmode === 33" class="tag-panel" :style="getStyles(item.attributeMap.color)" type="primary"
>通讯中断</el-tag>
</div>
<div class="fanlist-main">
<el-row>
<el-col :span="24">
<div class="fanlist-pic">
<div class="mask">
<div class="heart"><img :src="getSafeImagePath(item, 'heart')" alt="" /></div>
<div class="leafs" :style="getAnimationStyle(item)">
<div class="leaf_1"><img :src="getSafeImagePath(item, 'leaf')" alt="" /></div>
<div class="leaf_2"><img :src="getSafeImagePath(item, 'leaf')" alt="" /></div>
<div class="leaf_3"><img :src="getSafeImagePath(item, 'leaf')" alt="" /></div>
</div>
</div>
</div>
<div class="fanlist-pic">
<img :src="getSafeImagePath(item, 'fan')" alt="" />
</div>
<div class="fanlist-pic" style="margin: 0;">
<img src="~assets/dashboard/fannew/base.png" alt="" />
</div>
</el-col>
</el-row>
<el-row class="fanlist-data">
<div class="fanlist-text">
<span class="content-number">{{ item.attributeMap.iwindspeed }}</span>
<span>m/s</span>
</div>
<div class="fanlist-text">
<span class="content-number">{{ item.attributeMap.igenpower }}</span>
<span>kW</span>
</div>
</el-row>
</div>
<div class="fanlist-bottom">
<el-tooltip
v-if="item.attributeMap.firsttriggeredcode"
:content="item.attributeMap.firsttriggeredcode">
<span class="rightTip" :style="item.attributeMap.locked == 1 ? 'width:120px;' : 'width:150px;'">
{{ item.attributeMap.firsttriggeredcode }}
</span>
</el-tooltip>
<span class="rightTip"
v-if="!item.attributeMap.firsttriggeredcode"
:style="item.attributeMap.locked == 1 ? 'width:120px;' : 'width:150px;'">
{{ item.attributeMap.firsttriggeredcode }}
</span>
<!-- <el-tag class="tag-panel is-danger">已锁定</el-tag>-->
<el-tag v-if="item.attributeMap.locked === 1" class="tag-panel is-danger">已锁定</el-tag>
</div>
</div>
</div>
<!-- </el-col>-->
</div>
<ContextMenu :pos="contextMenuPos" v-model:visible="OperateVisible">
<template #default>
<div class="modelOperate">
<el-button
class="control-btn"
type="primary"
@click="sendCommand('setTurbineFastStart')"
v-if="realTimeData.processedoperationmode !== 16"
>启动</el-button>
<el-button @click="sendCommand('setTurbineStop')" v-else class="control-btn" type="primary">停机</el-button>
<el-button @click="sendCommand('setTurbineResetStatusCode')" class="control-btn" type="primary">复位</el-button>
<el-button
@click="sendManualCommand(1)"
v-if="realTimeData.locked !== 1"
class="control-btn"
type="primary">锁定</el-button>
<el-button @click="sendManualCommand(0)" v-else class="control-btn" type="primary">解锁</el-button>
<el-button
class="control-btn"
type="primary"
@click="editstandard(1)"
v-if="realTimeData.standard == 0"
>标杆设置</el-button>
<el-button
class="control-btn"
type="primary"
@click="editstandard(0)"
v-else
>标杆取消</el-button>
</div>
</template>
</ContextMenu>
</div>
</template>
<script setup lang="ts">
import {defineProps, ref,onMounted} from 'vue'
import { useRouter } from 'vue-router'
import { adminBaseRoutePath } from '/@/router/static/adminBase'
import ContextMenu from '/@/views/backend/auth/model/contextMenu.vue'
import { sendCommandReq, sendManualCommandReq } from '/@/api/backend/control/request'
import {ElMessage, ElMessageBox} from "element-plus";
import {equipUpdate} from '/@/api/backend/index.ts'
import {queryfaultCodeDict} from "/@/api/backend/theoreticalpowerCurve/request";
import { malFunctionKeys } from '/@/views/backend/equipment/airBlower/utils'
import { useEnumStore } from '/@/stores/enums'
const enumStore = useEnumStore()
const router = useRouter()
const props = defineProps({
parentData: {
type: Array,
default: () => [],
},
})
const getAnimationStyle = (item) => {
const irotorspeed = item.attributeMap?.irotorspeed ?? 0
let animationDuration;
animationDuration = 60 / irotorspeed / 2
const processedoperationmode = item.attributeMap?.processedoperationmode ?? 0
if(processedoperationmode==33||processedoperationmode==0){
return {
'animation-duration': `0s`,
'animation-timing-function': 'linear',
'animation-iteration-count': 'infinite',
'animation-direction': 'normaL',
}
}else{
return {
'animation-duration': `${animationDuration}s`,
'animation-timing-function': 'linear',
'animation-iteration-count': 'infinite',
'animation-direction': 'normaL',
}
}
}
const handleClick = (row) => {
if (!router.hasRoute('windTurbine')) {
router.addRoute('admin', {
path: adminBaseRoutePath + '/windTurbine',
name: 'windTurbine',
component: () => import('/@/views/backend/WindBlower/index.vue'),
meta: {
title: '单风机详情',
menuDesc: '单风机详情',
addtab: true,
},
})
}
router.push({
name: 'windTurbine',
query: {
irn: row.irn,
iotModelId: row.modelId,
deviceCode: row.deviceCode,
name: row.name,
model: row.model,
},
})
}
const OperateVisible = ref(false)
const contextMenuPos = ref({
x: 0,
y: 0,
})
const realTimeData = ref<any>({
processedoperationmode: 1111,
locked: 0,
deviceId: '',
name:'',
code:'',
standard:'',
iotModelId:''
})
const windContextMenu = (event: any,curnodeData) => {
contextMenuPos.value.x = event.pageX
contextMenuPos.value.y = event.pageY
realTimeData.value.processedoperationmode=curnodeData.attributeMap.processedoperationmode
realTimeData.value.locked=curnodeData.attributeMap.locked
realTimeData.value.deviceId=curnodeData.irn
realTimeData.value.name=curnodeData.name
realTimeData.value.code=curnodeData.deviceCode
realTimeData.value.standard=curnodeData.standard
realTimeData.value.iotModelId=curnodeData.modelId
OperateVisible.value = true
}
const sendCommand = (type: 'setTurbineFastStart' | 'setTurbineStop' | 'setTurbineResetStatusCode') => {
const sendTypeEnum = {
setTurbineFastStart: '风机快速启动指令',
setTurbineStop: '风机停机指令',
setTurbineResetStatusCode: '风机复位故障代码指令',
}
ElMessageBox.confirm('确认发送' + sendTypeEnum[type] + '吗?', '', {
confirmButtonText: '确认',
cancelButtonText: '取消',
type: 'warning',
}).then(() => {
const serviceName = sendTypeEnum[type]
const optDesc = serviceName + ',设定值为1'
sendCommandReq({
deviceId: realTimeData.value.deviceId as string,
serviceCode: type,
serviceName,
optDesc,
opValue: 1,
}).then((res) => {
if (res.code == 200) {
ElMessage.success('指令发送成功')
} else {
ElMessage.error('指令发送失败')
}
})
})
}
const sendManualCommand = (type: 1 | 0) => {
const serviceName = type === 0 ? '风机解锁' : '风机锁定'
ElMessageBox.confirm('确认' + serviceName + '吗?', '', {
confirmButtonText: '确认',
cancelButtonText: '取消',
type: 'warning',
}).then(() => {
sendManualCommandReq({
deviceId: realTimeData.value.deviceId as string,
serviceCode: 'Locked',
serviceName,
optDesc: serviceName + ',设定值为:' + type,
opValue: type,
}).then((res) => {
if (res.code == 200) {
ElMessage.success('指令发送成功')
} else {
ElMessage.error('指令发送失败')
}
})
})
}
const editstandard = (type: 1 | 0) => {
const standardName = type === 0 ? '取消风机标杆' : '设置风机标杆'
ElMessageBox.confirm('确认' + standardName + '吗?', '', {
confirmButtonText: '确认',
cancelButtonText: '取消',
type: 'warning',
}).then(() => {
equipUpdate({
id: realTimeData.value.deviceId,
code: realTimeData.value.code,
name:realTimeData.value.name,
iotModelId: realTimeData.value.iotModelId,
standard: type
}).then((res) => {
if (res.code == 200) {
ElMessage.success('设置成功')
} else {
ElMessage.error('设置失败')
}
})
})
}
const getStyles=(color) =>{
if (color && /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/.test(color)) {
const rgbaColor = hexToRgba(color, 0.2);
return {
background: rgbaColor,
border: `1px solid ${color}`,
color: color,
};
} else {
return {
background: 'rgba(48, 89, 236, 0.2)',
border: '1px solid #3059ec',
color: '#3059ec'
};
}
}
const hexToRgba = (hex, alpha) => {
hex = hex.replace('#', '');
let r, g, b;
if (hex.length === 3) {
r = parseInt(hex[0] + hex[0], 16);
g = parseInt(hex[1] + hex[1], 16);
b = parseInt(hex[2] + hex[2], 16);
} else {
r = parseInt(hex.substring(0, 2), 16);
g = parseInt(hex.substring(2, 4), 16);
b = parseInt(hex.substring(4, 6), 16);
}
return `rgba(${r}, ${g}, ${b}, ${alpha})`;
}
const imagePathMap = {
'#9C27B0': {
heart: 'heart1.png',
leaf: 'leaf1.png',
fan: 'fan1.png',
},
'#673AB7': {
heart: 'heart2.png',
leaf: 'leaf2.png',
fan: 'fan2.png',
},
'#3F51B5': {
heart: 'heart3.png',
leaf: 'leaf3.png',
fan: 'fan3.png',
},
'#3059EC': {
heart: 'heart4.png',
leaf: 'leaf4.png',
fan: 'fan4.png',
},
'#0277B3': {
heart: 'heart5.png',
leaf: 'leaf5.png',
fan: 'fan5.png',
},
'#00A096': {
heart: 'heart6.png',
leaf: 'leaf6.png',
fan: 'fan6.png',
},
'#06B429': {
heart: 'heart7.png',
leaf: 'leaf7.png',
fan: 'fan7.png',
},
'#64DD17': {
heart: 'heart8.png',
leaf: 'leaf8.png',
fan: 'fan8.png',
},
'#EEFF41': {
heart: 'heart9.png',
leaf: 'leaf9.png',
fan: 'fan9.png',
},
'#FFB600': {
heart: 'heart10.png',
leaf: 'leaf10.png',
fan: 'fan10.png',
},
'#FF7E00': {
heart: 'heart11.png',
leaf: 'leaf11.png',
fan: 'fan11.png',
},
'#FE3731': {
heart: 'heart12.png',
leaf: 'leaf12.png',
fan: 'fan12.png',
},
'#999999': {
heart: 'heart13.png',
leaf: 'leaf13.png',
fan: 'fan13.png',
}
};
const getImagePath = (item, type) => {
const color = item.attributeMap.color;
return imagePathMap[color]?.[type];
};
const getSafeImagePath = (item, type) => {
const path = getImagePath(item, type);
if (!getSafeImagePath.cache) {
getSafeImagePath.cache = {};
}
if (getSafeImagePath.cache[path]) {
return getSafeImagePath.cache[path];
}
const imagePath = new URL(`/src/assets/dashboard/fannew/${path}`, import.meta.url).href;
getSafeImagePath.cache[path] = imagePath;
return imagePath;
};
</script>
<style scoped lang="scss">
@keyframes leafRotate {
0% {
transform: rotate(0deg);
}
25% {
transform: rotate(90deg);
}
50% {
transform: rotate(180deg);
}
75% {
transform: rotate(270deg);
}
100% {
transform: rotate(360deg);
}
}
.wind-mark {
background-image: linear-gradient(140deg, #ffe3e3 0%, #ffffff 93%);
border: 1px solid #ffe3e3;
}
.wind-default {
background-image: linear-gradient(180deg, #f0f6ff 0%, #ffffff 50%);
border: 1px solid #e1edf6;
}
.wind-offline {
background-image: linear-gradient(180deg, #dddddd 0%, #ffffff 93%);
border: 1px solid #eeeeee;
}
.wind-picture {
display: none;
}
.wind-mark-icon {
background: #ffffff;
border: 1px solid #ffe3e3;
border-radius: 8px 0 100px 0;
display: flex;
justify-content: center;
align-items: center;
width: 40px;
height: 30px;
vertical-align: middle;
}
.FanList-content.flex-start {
justify-content: flex-start;
}
.FanList-content {
overflow-x: hidden;
display: grid;
justify-content: space-between;
grid-template-columns: repeat(auto-fill, 170px);
.overviewPart{
display: flex;
box-sizing: border-box;
width: 170px;
height: 110px;
margin-top: 8px;
margin-bottom: 8px;
.FanList-panel {
border-radius: 8px;
cursor: pointer;
.fanlist-top {
display: flex;
width: 100%;
}
.fanlist-icon {
display: flex;
justify-content: center;
align-items: center;
width: 40px;
height: 30px;
vertical-align: middle;
}
.fanlist-name {
width: 100%;
margin-top: 5px;
}
.tag-panel {
border-radius: 0 8px 0 0;
line-height: 20px;
:deep(.el-tag__content){
max-width: 80px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
}
.is-primary {
background: rgba(2, 119, 179, 0.2);
border: 1px solid #0277b3;
color: #0277b3;
}
.is-success {
background: rgba(6, 180, 41, 0.2);
border: 1px solid #06b429;
color: #06b429;
}
.is-info {
background: rgba(48, 89, 236, 0.2);
border: 1px solid #3059ec;
color: #3059ec;
}
.is-warning {
background: rgba(255, 126, 0, 0.2);
border: 1px solid #ff7e00;
color: #ff7e00;
}
.is-danger {
background: rgba(254, 55, 49, 0.2);
border: 1px solid #fe3731;
color: #fe3731;
}
.is-offline {
background: rgba(153, 153, 153, 0.2);
border: 1px solid #999999;
color: #999999;
}
.is-maintenance {
background: rgba(0, 160, 150, 0.2);
border: 1px solid #00a096;
color: #00a096;
}
.fanlist-main {
width: 100%;
display: flex;
justify-content: space-between;
padding: 5px 10px 0 10px;
text-align: center;
.fanlist-pic {
display: flex;
justify-content: center;
align-items: center;
margin-top: -10px;
.mask {
width: 43px;
height: 38px;
.heart {
position: absolute;
text-align: center;
top: 5px;
left: 19px;
}
.leafs {
position: absolute;
transform-origin: center center;
width: 44px;
height: 48px;
animation-name: leafRotate;
.leaf_1 {
width: 5px;
height: 14px;
position: absolute;
left: 19px;
top: 6px;
}
.leaf_2 {
width: 5px;
height: 14px;
position: absolute;
left: 30px;
top: 22px;
transform: rotate(120deg);
}
.leaf_3 {
width: 5px;
height: 14px;
position: absolute;
left: 9px;
top: 22px;
transform: rotate(240deg);
}
}
}
}
.fanlist-text {
margin-top: 5px;
width: 100%;
text-align: right;
.content-number {
color: #333333;
font-size: 20px;
padding-right: 5px;
}
}
.fanlist-text span {
display: inline-block;
}
}
.fanlist-bottom {
display: flex;
justify-content: space-between;
height: 24px;
.rightTip{
display: inline-block;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
color: #FE3731;
padding-left:5px;
}
.tag-panel {
border-radius: 0 0 8px 0;
line-height: 20px;
}
}
}
}
.grid-content{
width: 170px;
}
.modelOperate{
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: center;
width: 80px;
/* height: 80px;*/
.el-button {
margin: 5px;
}
}
}
/*
.FanList-content::after {
content: '';
flex: auto;
!* 或者flex: 1 *!
}
*/
@media screen and (max-width: 1680px) {
.FanList-content {
.FanList-panel {
.fanlist-text {
font-size: 12px !important;
.content-number {
font-size: 16px !important;
}
}
}
}
}
@media screen and (max-width: 1280px) {
.FanList-content {
.FanList-panel {
.fanlist-text {
margin-top: 10px !important;
}
}
}
}
</style>