/* eslint-disable */ import React, { useState, useEffect, useRef, useContext } from 'react'; import classNames from 'classnames'; import moment from 'moment'; import sha1 from 'sha1'; import Empty from '@wisdom-components/empty'; import LoadBox from '@wisdom-components/loadbox'; import { Input, message, Modal, Form, ConfigProvider, Button } from 'antd'; import { ExclamationCircleOutlined, DoubleLeftOutlined, LeftOutlined, RightOutlined, DoubleRightOutlined, } from '@ant-design/icons'; import MqttView from '@wisdom-components/mqttview'; import PropTypes from 'prop-types'; import HistoryInfo from '@wisdom-components/ec_historyinfo'; import * as go from './js/go'; import GuidedDraggingTool from './js/GuidedDraggingTool'; import TopRotatingTool from './js/RotatingTool'; import BarLink from './js/BarLink'; import WaterFlowControlView from './js/WaterFlowControlView'; import ConfigurationDetail from './js/ConfigurationDetail'; import DragModal from './js/DragModal'; import { getSketchPadList, getSketchPadContent, getPointAddress, getHistoryInfo, getDictionaryList, getDeviceRealInfo, } from './apis'; import { isNumber, createGuid, deepCopy, hexToRgba, addNumMethod, hexSwitch, textStyle, } from './js/utils'; import './index.less'; const goJS = go.GraphObject.make; let online = false; let imgUrl = null; let modalComponent = null; // 点击节点展示的模态框内容 let modalConfirmFn = null; // 点击节点展示的模态框的确定事件 let auModalConfirmFn = null; // 登录模态框的确定事件 let jumpModalProps = null; let modalProps = {}; let modalWidth = 520; let historyInfoParams = {}; let nodeData = null; // 选中节点的数据 let twoID = ``; const waterFlow = new WaterFlowControlView(); const StationList = [ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', ]; const ConfigurationView = (props) => { let myDiagram = null; let mqttView = null; let editionArr = []; const guidAggre = {}; const bindData = []; const stationList = []; const { getPrefixCls } = useContext(ConfigProvider.ConfigContext); const prefixCls = getPrefixCls('ec-configuration-view'); const componentPrefix = getPrefixCls(''); const [isModalVisible, setIsModalVisible] = useState(false); const [isAuModalVisible, setIsAuModalVisible] = useState(false); // 登录模态框 const [isHIModalVisible, setIsHIModalVisible] = useState(false); // 历史曲线模态框 const [isJumpModalVisible, setIsJumpModalVisible] = useState(false); // 画板跳转模态框 const [spinning, setSpinning] = useState(true); // 画板loading const [isEmpty, setIsEmpty] = useState(false); // 画板无数据状态 const [description, setDescription] = useState(''); // 画板无数据描述 twoID = `TDG${Date.now().toString(36)}`; const AdjustControlInput = useRef(); const AuthorFrom = useRef(); const ConfigurationRef = useRef(); const customBack = props.customBack ? props.customBack : () => {}; const { devices = [], dictionaryParams, config, isZoom = false, flowShow = true, deviceName = [], } = props; const globalConfig = window.globalConfig || config; let isClose = false; /** **********************************获取工艺图画板信息*********************** */ const getConfiguraList = async () => { imgUrl = online ? 'https://panda-water.cn/PandaConfiguration/Raw/' : `${globalConfig.baseURI}/PandaConfiguration/Raw/`; // 获取画板信息 const drawInfo = await getSketchPadList({ name: props.name, siteCode: globalConfig.userInfo && globalConfig.userInfo.LocalSite ? globalConfig.userInfo.LocalSite : '', version: '全部', _site: globalConfig.userInfo && globalConfig.userInfo.site ? globalConfig.userInfo.site : '', }); if (drawInfo.code === 0) { const data = drawInfo.data ? (drawInfo.data.list ? drawInfo.data.list : []) : []; if (data.length > 0) { const num = data.length ? (data[0].num ? data[0].num * 1 : 0) : 0; const siteInfo = data.length ? (data[0].siteInfo ? JSON.parse(data[0].siteInfo) : {}) : {}; for (let i = 0; i < num; i++) { const round = parseInt(i / 26); const remain = i % 26; if (round) { stationList.push(StationList[remain] + round); } else { stationList.push(StationList[remain]); } } getDiagramJson(data[0], siteInfo); } else { setDescription('咦~未查询到工艺图画板信息哦~'); setIsEmpty(true); setSpinning(false); return false; } } else { setDescription('咦~工艺图画板信息报错啦~'); setIsEmpty(true); setSpinning(false); return message.error(drawInfo.msg); } // 获取点表信息 const pointInfo = await getPointAddress({ code: devices.join(','), _site: globalConfig.userInfo && globalConfig.userInfo.site ? globalConfig.userInfo.site : '', }); editionArr = deepCopy(pointInfo && pointInfo.data ? pointInfo.data : [], []); }; /** *********************************节点展示逻辑****************************** */ const showNodeMethod = (node, list) => { const realVal = list.Value * 1; let switchState; myDiagram.model.setDataProperty(node, 'realVal', realVal); if (node.switch === '是') { switchState = openValState(node.openVal, realVal) ? '开' : '关'; myDiagram.model.setDataProperty(node, 'switchState', switchState); } if (!node.shType) return false; const patt = /[><=]/gi; let shRule = []; try { switch (node.category) { case 'svgCase': // 图片模型 shRule = ruleOperation(node, realVal); myDiagram.model.setDataProperty(node, 'imgSrc', shRule ? shRule.attr : node.dtImgSrc); break; case 'nameCase': // 名称模型 if (node.shType === '文本变化') { shRule = ruleOperation(node, realVal); myDiagram.model.setDataProperty( node, 'fontStroke', shRule ? shRule.attr : node.dtFontStroke, ); myDiagram.model.setDataProperty(node, 'text', shRule ? shRule.text : node.dtText); } else { shRule = ruleOperation(node, realVal); myDiagram.model.setDataProperty( node, 'fillColor', hexToRgba(shRule ? shRule.attr : node.fill, node.opacity), ); } break; case 'valCase': // 实时值模型 if (node.shType === '值显示') { myDiagram.model.setDataProperty(node, 'showVal', realVal < 0 ? 0 : realVal); } else { myDiagram.model.setDataProperty(node, 'showVal', realVal); } break; case 'waterCase': // 水池模型 const height = node.height - node.strokeWidth * 2; let waterHight = (realVal * height) / node.poolHight; waterHight = waterHight >= height ? height : waterHight; myDiagram.model.setDataProperty(node, 'waterHight', waterHight); shRule = JSON.parse(node.shRule); shRule.forEach((item) => { const min = item.min && !isNaN(item.min * 1) ? item.min * 1 : 0; const max = item.max && !isNaN(item.max * 1) ? item.max * 1 : 0; if (realVal >= min && realVal < max) myDiagram.model.setDataProperty( node, 'fillColor', hexToRgba(item.attr ? item.attr : node.fill, node.fillAlpha), ); }); break; case 'switchCase': // 开关模型 shRule = ruleOperation(node, realVal); myDiagram.model.setDataProperty( node, 'fillColor', hexToRgba(shRule ? shRule.attr : node.fill, node.opacity), ); myDiagram.model.setDataProperty(node, 'switch', shRule ? '是' : '否'); break; case 'rotateCase': // 状态模型 shRule = ruleOperation(node, realVal); myDiagram.model.setDataProperty(node, 'imgSrc', shRule ? shRule.attr : node.dtImgSrc); break; case 'pointCase': // 点状态模型 shRule = ruleOperation(node, realVal); myDiagram.model.setDataProperty( node, 'fillColor', hexToRgba(shRule ? shRule.attr : node.fill, node.opacity), ); break; case 'blenderCase': // 搅拌机模型 break; case 'HBar': // 合管模型 shRule = ruleOperation(node, realVal); myDiagram.model.setDataProperty(node, 'stroke', shRule ? shRule.attr : node.stroke); myDiagram.model.setDataProperty( node, 'waterStroke', shRule ? shRule.text : node.waterStroke, ); break; case 'speedCase': // 进度条模型 shRule = ruleOperation(node, realVal); myDiagram.model.setDataProperty( node, 'fillColor', hexToRgba(shRule ? shRule.attr : node.fill, node.opacity), ); const { width } = node; let speedWidth = (realVal * width) / node.speedWidth; speedWidth = speedWidth >= width ? width : speedWidth; myDiagram.model.setDataProperty(node, 'lineWidth', speedWidth); break; case 'modelCase': // 模板块模型 shRule = ruleOperation(node, realVal); myDiagram.model.setDataProperty(node, 'zOrder', shRule ? shRule.text : node.dtzOrder); break; case 'ellipseCase': // 圆形模型 shRule = ruleOperation(node, realVal); myDiagram.model.setDataProperty( node, 'zOrder', shRule ? shRule.text * 1 || 0 : node.dtzOrder, ); break; default: break; } } catch (err) { console.log(err); } }; /** ***********************************展示规则运算********************************* */ const ruleOperation = (node, realVal) => { const patt = /[><=]/gi; const shRule = JSON.parse(node.shRule).find((rule) => { if (rule.val.toString().match(patt)) { const ruleStr = 'if(' + rule.val + '){ return true } else { return false }'; try { return new Function('x', 'X', ruleStr)(realVal, realVal); } catch (err) { return false; } } else { return rule.val.toString().split(',').indexOf(realVal.toString()) > -1; } }); return shRule; }; /** ***********************************运行值规则运算********************************* */ const openValState = (openVal, realVal) => { const patt = /[><=]/gi; if (openVal.toString().match(patt)) { const ruleStr = 'if(' + openVal + '){ return true } else { return false }'; try { return new Function('x', 'X', ruleStr)(realVal, realVal); } catch (err) { return false; } } else { return openVal.toString().split(',').indexOf(realVal.toString()) > -1; } }; /** ***********************************MQTT控制结果回调********************************* */ const controlData = (mqttDatas, code) => { const controlInfo = JSON.parse(mqttDatas); if (guidAggre[code]) { const guid = guidAggre[code]; if (!controlInfo.result) { message.warning(`${guid.tag}控制失败,${controlInfo.message}!`); } else { message.success(`${guid.tag}控制下发成功。`); } delete guidAggre[code]; } }; /** *********************************MQTT请求数据回调****************************** */ const refreshData = (mqttDatas, code) => { const bindList = bindData.find((item) => { return item.code === code; }); const name = bindList ? bindList.name : ''; const mqttData = JSON.parse(mqttDatas)[code]; const editionList = editionArr.find((item) => { return item.code === code; }); if (!mqttData) return false; try { if (unitRender) unitRender.tipRender({ deviceID: code, data: mqttData }); } catch (err) { // 三维调用 } const json = JSON.parse(myDiagram.model.toJson()); const jsonCopy = JSON.parse(JSON.stringify(json)); const oldJson = deepCopy(jsonCopy, {}); try { myDiagram.model.linkDataArray.forEach((item) => { if (!item.shName || item.stationName !== name || item.shType !== '线条展示') return false; mqttData.forEach((list) => { const itemID = list.ItemID; const num = itemID.lastIndexOf('.'); const ptName = itemID.substring(0, num); const shName = itemID.substring(num + 1, Infinity); if (editionList && `${editionList.name}.${editionList.version}` !== ptName) return false; if (list.Value == null || shName !== item.shName || item.realVal === list.Value) return false; item.realVal = list.Value * 1; const shRule = ruleOperation(item, item.realVal); if (shRule) { myDiagram.model.setDataProperty(item, 'stroke', shRule.attr); myDiagram.model.setDataProperty(item, 'waterStroke', shRule.text); } else { myDiagram.model.setDataProperty(item, 'stroke', item.stroke); myDiagram.model.setDataProperty(item, 'waterStroke', item.waterStroke); } }); }); } catch (e) { // 水流样式 } try { jsonCopy.nodeDataArray.forEach((item) => { if (!(item.shName || item.figure === 'updateTime') || item.stationName !== name) return false; const node = myDiagram.model.findNodeDataForKey(item.key); mqttData.forEach((list) => { if (node.figure === 'updateTime') { myDiagram.model.setDataProperty( node, 'text', moment(list.Time).format('yyyy-MM-DD hh:mm:ss'), ); return false; } const itemID = list.ItemID; const num = itemID.lastIndexOf('.'); const ptName = itemID.substring(0, num); const shName = itemID.substring(num + 1, Infinity); if (editionList && `${editionList.name}.${editionList.version}` !== ptName) return false; if (list.Value == null || shName !== item.shName || item.realVal === list.Value) return false; showNodeMethod(node, list); }); }); } catch (e) { // 节点展示 } try { const jsonModel = waterFlow.waterFlowControlByDiagramJson(oldJson, myDiagram); if (!jsonModel) return false; const oldLink = myDiagram.model.linkDataArray; const dataLink = []; jsonModel.linkDataArray.forEach((item, index) => { const list = { ...oldLink[index] }; list.isHavingDash = item.isHavingDash; dataLink.push(list); }); jsonModel.nodeDataArray.forEach((item) => { if (item.category === 'HBar') { const node = myDiagram.model.findNodeDataForKey(item.key); const waterStroke = item.typeDash ? 'transparent' : item.hBarClolor; if (item.typeDash !== node.typeDash) { myDiagram.model.setDataProperty(node, 'waterStroke', waterStroke); myDiagram.model.setDataProperty(node, 'typeDash', item.typeDash); } } }); dataLink.forEach((item) => { const node = myDiagram.findLinkForData(item); if (item.isHavingDash !== node.data.isHavingDash) myDiagram.model.setDataProperty(node.data, 'isHavingDash', item.isHavingDash); }); } catch (e) { // 水流展示 } }; /** **************************************合管****************************************** */ const changLinkRouting = (e) => { const link = e.subject; if (link.toNode == null || link.fromNode == null) { return false; } if (link.fromNode.category === 'HBar' || link.toNode.category === 'HBar') { e.subject.routing = go.Link.Normal; } }; /** ************************************创建连接点*********************************** */ // 创建一个port,ID为name,spot控制其怎么被连接,放置于node的什么位置,output/input决定其哪里可以from和to const makePort = (name, spot, output, input) => { // the port is basically just a small transparent square return goJS(go.Shape, 'Circle', { fill: null, // not seen, by default; set to a translucent gray by showSmallPorts, defined below stroke: null, desiredSize: new go.Size(7, 7), alignment: spot, // align the port on the main Shape alignmentFocus: spot, // just inside the Shape portId: name, // declare this object to be a "port" fromSpot: spot, toSpot: spot, // declare where links may connect at this port fromLinkable: output, toLinkable: input, // declare whether the user may draw links to/from here cursor: 'pointer', // show a different cursor to indicate potential link point }); }; /** 动画设置*********************************************** */ const animationSvg = () => { const diagram = myDiagram; const oldskips = diagram.skipsUndoManager; diagram.skipsUndoManager = true; diagram.nodes.map((node) => { const shape = node.findObject('animateSvg'); if (!shape) return false; const gpRule = JSON.parse(node.data.gpRule || '[]').concat(); const amTime = node.data.amTime || 0; if (!amTime) return false; gpRule.map((item) => { mySetInterval(() => { const { time = 0, fill = 100, scale = 1, angle = 0 } = item; myTimeout(() => { shape.opacity = (fill || 100) / 100; shape.scale = (scale || 1) * 1; shape.angle = (angle || 0) * 1; }, 0.01 * amTime * time); }, amTime * 1); }); }); diagram.skipsUndoManager = oldskips; }; const myTimeout = (fn, delay) => { let timer; const stime = +new Date(); const myLoop = () => { if (isClose) return timer && cancelAnimationFrame(timer); const etime = +new Date(); if (stime + delay <= etime) { fn(); return; } timer = requestAnimationFrame(myLoop); }; timer = requestAnimationFrame(myLoop); return () => { cancelAnimationFrame(timer); }; }; const mySetInterval = (fn, interval) => { let timer; let stime = +new Date(); let etime; let myLoop = () => { etime = +new Date(); if (isClose) return timer && cancelAnimationFrame(timer); timer = requestAnimationFrame(myLoop); if (etime - stime >= interval) { stime = etime = +new Date(); fn(); } }; return requestAnimationFrame(myLoop); }; /** ******************************************水池效果****************************** */ const waterSvg = () => { const diagram = myDiagram; // poolWater = setInterval(() => { mySetInterval(() => { const oldskips = diagram.skipsUndoManager; diagram.skipsUndoManager = true; diagram.nodes.each((node) => { const shape = node.findObject('waterSvg'); if (!shape) return false; const range = (shape.range ? shape.range : 0) + 0.5; shape.range = range >= 5 ? 0 : range; shape.geometryString = `F M0 ${shape.range} L${shape.width} ${5 - shape.range} L${ shape.width } ${shape.height} L0 ${shape.height}z`; }); diagram.skipsUndoManager = oldskips; }, 100); }; /** ***********************************水流效果********************************** */ const loop = () => { const diagram = myDiagram; // tubeWater = setInterval(() => { mySetInterval(() => { const oldskips = diagram.skipsUndoManager; diagram.skipsUndoManager = true; diagram.links.each((link) => { const shape = link.findObject('PIPE'); if (!shape) return false; if (link.data.isHavingDash) { link.zOrder = 1; shape.strokeWidth = link.data.defaultWidth || 3; const off = shape.strokeDashOffset - 3; shape.strokeDashOffset = off <= 0 ? 60 : off; } else { link.zOrder = 0; shape.strokeWidth = 0; shape.strokeDashOffset = 0; } }); diagram.skipsUndoManager = oldskips; }, 60); }; /** **************************************泵状态效果*************************** */ const rotateSvg = () => { const diagram = myDiagram; // pumpType = setInterval(() => { mySetInterval(() => { const oldskips = diagram.skipsUndoManager; diagram.skipsUndoManager = true; diagram.nodes.each((node) => { const shape = node.findObject('rotateSvg'); if (!shape) return false; const _node = node.data; if (_node.switchState !== '开' || _node.realVal === '--' || _node.switch !== '是') return false; const off = shape.angle + 60; shape.angle = off <= 360 ? off : 0; }); diagram.skipsUndoManager = oldskips; }, 60); }; /** *********************************搅拌机状态效果************************* */ const blenderSvg = () => { const diagram = myDiagram; // blenderType = setInterval(() => { mySetInterval(() => { const oldskips = diagram.skipsUndoManager; diagram.skipsUndoManager = true; diagram.nodes.each((node) => { const shape = node.findObject('blenderSvg'); if (!shape) return false; const _node = node.data; const srcStr = _node.dtImgSrc.split('/').pop(); if (_node.switchState !== '开' || _node.realVal === '--' || _node.switch !== '是') { shape.source = require(`./images/组态/状态/${srcStr.replace(/[0-9]/gi, 1)}`); return false; } shape.flag = shape.flag || 1; const num = shape.source.match(/\d/)[0] * 1; let _num = 1; if (shape.flag === 1) { _num = num < 5 ? num + 1 : 4; if (num >= 5) shape.flag = 2; } else { _num = num > 1 ? num - 1 : 2; if (num <= 1) shape.flag = 1; } shape.source = require(`./images/组态/状态/${srcStr.replace(/[0-9]/gi, _num)}`); }); diagram.skipsUndoManager = oldskips; }, 100); }; /** *******************将myDiagram.model中的信息展示在画板上*********************** */ const loadDiagramProperties = (e) => { const pos = myDiagram.model.modelData.position; if (pos) myDiagram.initialPosition = go.Point.parse(pos); }; /** *******************绑定角色可见*************************** */ const roleVisibleBinding = () => { return new go.Binding('visible', '', function (data) { if (!data.roles) return true; const roles = data.roles.split(','); const curRoleMap = {}; globalConfig && globalConfig.userInfo && globalConfig.userInfo.roles && globalConfig.userInfo.roles.forEach(function (role) { curRoleMap[role.OID] = role; }); const samerole = roles.filter(function (roleID) { return !!curRoleMap[roleID]; }); return samerole.length > 0; }); }; /** ***********************************节点样式********************************** */ const nodeStyle = () => { return [ new go.Binding('location', 'loc', go.Point.parse).makeTwoWay(go.Point.stringify), { locationSpot: go.Spot.Center, }, ]; }; /** ************************************联网判断******************************* */ const onlineMethod = (pathImg, url) => { const ImgObj = new Image(); ImgObj.src = pathImg; ImgObj.onload = () => { online = ImgObj.fileSize > 0 || (ImgObj.width > 0 && ImgObj.height > 0); getConfiguraList(); }; ImgObj.onerror = () => { online = false; getConfiguraList(); }; }; useEffect(() => { if (!props.name || !props.devices || !props.devices.length) { setDescription('咦~工艺图配置信息不全哦~'); setIsEmpty(true); setSpinning(false); return false; } const url = globalConfig.mainserver ? globalConfig.mainserver : 'https://panda-water.cn/'; onlineMethod(`${url}civweb4/assets/images/bootPage/熊猫图标.png`, url); return () => { isClose = true; mqttView && mqttView.disSaveWaconnect(); mqttView = null; }; }, []); useEffect(() => { if (!isModalVisible) { modalConfirmFn = null; modalComponent = null; modalProps = {}; } }, [isModalVisible]); useEffect(() => { if (!isAuModalVisible) { auModalConfirmFn = null; } }, [isAuModalVisible]); /** ************************************获取画板JSON******************************* */ const getDiagramJson = async (list, siteInfo) => { const response = await getSketchPadContent({ dimension: list.dimension, siteCode: list.siteCode, fileName: `${list.name}.json`, _site: globalConfig.userInfo && globalConfig.userInfo.site ? globalConfig.userInfo.site : '', }); if (response.code === 0) { if (isClose) return false; const fromJson = response.data ? response.data : { linkFromPortIdProperty: 'fromPort', linkToPortIdProperty: 'toPort', nodeDataArray: [], linkDataArray: [], }; devices.forEach((item, index) => { const name = `设备${stationList[index]}`; bindData.push({ code: item, name, type: siteInfo && siteInfo[name] ? siteInfo[name].Type : '', }); }); mqttView = new MqttView({ mqttIP: globalConfig.mqtt_iotIP, mqttPath: globalConfig.mqtt_path, mqttSsl: globalConfig.mqtt_IsSSL, siteCode: globalConfig.mqtt_mess.site_code, devices, callback: refreshData, controlback: controlData, }); diagramRender(typeof fromJson === 'string' ? fromJson : JSON.stringify(fromJson)); try { mqttView.saveWaterMqtt(); } catch (e) { // 获取实时数据 getRealData(siteInfo); } } else { message.error(response.msg); } }; /** ************************************实时数据获取******************************* */ const getRealData = async (siteInfo) => { try { if (!siteInfo) return false; const accountFieldParams = []; for (let i in siteInfo) { accountFieldParams.push({ aName: siteInfo[i].Type, }); } const params = { equipmentCode: devices.join(','), accountFieldParams, }; const results = await getDeviceRealInfo(params); const realDate = results && results.data && results.data.list ? results.data.list : []; chartDataRender(realDate); } catch (err) {} }; /** ************************************图表数据处理******************************* */ const chartDataRender = (mqttData) => { const json = JSON.parse(myDiagram.model.toJson()); const jsonCopy = JSON.parse(JSON.stringify(json)); const oldJson = deepCopy(jsonCopy); try { jsonCopy.linkDataArray.forEach((item) => { if (!item.shName || item.shType != '线条展示') return false; mqttData.forEach((list) => { const bindList = bindData.find((arr) => { return arr.code === list.code; }); const pvList = list.dataList.find((arr) => { return arr.dName === item.shName; }); if (!bindList || item.stationName !== bindList.name) return false; if ( !pvList || pvList.pv == null || pvList.dName != item.shName || item.realVal == pvList.pv ) return false; item.realVal = pvList.pv * 1; const shRule = ruleOperation(item, item.realVal); if (shRule) { myDiagram.model.setDataProperty(item, 'stroke', shRule.attr); myDiagram.model.setDataProperty(item, 'waterStroke', shRule.text); } else { myDiagram.model.setDataProperty(item, 'stroke', item.stroke); myDiagram.model.setDataProperty(item, 'waterStroke', item.waterStroke); } }); }); } catch (e) { // 水流样式 } try { jsonCopy.nodeDataArray.forEach((item) => { if (!(item.shName || item.figure == 'updateTime')) return false; const node = myDiagram.model.findNodeDataForKey(item.key); mqttData.forEach((list) => { if (node.figure == 'updateTime') { myDiagram.model.setDataProperty( node, 'text', new Date(list.PT).format('yyyy-MM-dd hh:mm:ss'), ); return false; } const bindList = bindData.find((arr) => { return arr.code === list.code; }); const pvList = list.dataList.find((arr) => { return arr.dName === item.shName; }); if (!bindList || item.stationName !== bindList.name) return false; if ( !pvList || pvList.pv == null || pvList.dName != item.shName || item.realVal == pvList.pv ) return false; pvList.Value = pvList.pv; showNodeMethod(node, pvList); }); }); } catch (e) { // 节点展示 } try { const jsonModel = waterFlow.waterFlowControlByDiagramJson(oldJson, myDiagram); if (!jsonModel) return false; const oldLink = myDiagram.model.linkDataArray; const dataLink = []; jsonModel.linkDataArray.forEach((item, index) => { const list = Object.assign({}, oldLink[index]); list.isHavingDash = item.isHavingDash; dataLink.push(list); }); jsonModel.nodeDataArray.forEach((item) => { if (item.category == 'HBar') { const node = myDiagram.model.findNodeDataForKey(item.key); const waterStroke = item.typeDash ? 'transparent' : item.hBarClolor; if (item.typeDash != node.typeDash) { myDiagram.model.setDataProperty(node, 'waterStroke', waterStroke); myDiagram.model.setDataProperty(node, 'typeDash', item.typeDash); } } }); dataLink.forEach((item) => { const node = myDiagram.findLinkForData(item); if (item.isHavingDash != node.data.isHavingDash) myDiagram.model.setDataProperty(node.data, 'isHavingDash', item.isHavingDash); }); } catch (e) { // 水流展示 } }; /** **************************************历史模态渲染****************************************** */ const historyModalRender = (data, list) => { historyInfoParams = { stream: [ { stationCode: list.code, sensors: data.shName, pointVersions: list.type, dateFrom: '', dateTo: '', }, ], ignoreOutliers: false, // 过滤异常值 isVertical: false, // 是否展示竖表 zoom: '', // 数据抽稀 unit: '', // 数据抽稀 min h }; setIsHIModalVisible(true); }; /** **************************************渲染按钮控制****************************************** */ const renderSwitchControlModal = () => { return ( <div className={classNames('switchControlContent')}> <ExclamationCircleOutlined /> {`确定要${nodeData.text}${nodeData.ctName}?`} </div> ); }; /** **************************************渲染输入控制****************************************** */ const renderAdjustControlModal = () => { const ctRule = nodeData.ctRule ? JSON.parse(nodeData.ctRule) : []; const step = ctRule.length ? ctRule[0].step || 0.1 : 0.1; return ( <div className={classNames('adjustControlContent')}> <div className={classNames('label')}>设置</div> <Input placeholder="请输入设置值" ref={AdjustControlInput} defaultValue={nodeData.realVal} onChange={() => {}} suffix={ctRule.length ? ctRule[0].text : ''} /> <div className={classNames('adjustControlGroup')}> <Button type="primary" ghost={true} icon={<DoubleLeftOutlined />} onClick={() => adjustControlStep(step * -10)} /> <Button type="primary" ghost={true} icon={<LeftOutlined />} onClick={() => adjustControlStep(step * -1)} /> <Button type="primary" ghost={true} icon={<RightOutlined />} onClick={() => adjustControlStep(step)} /> <Button type="primary" ghost={true} icon={<DoubleRightOutlined />} onClick={() => adjustControlStep(step * 10)} /> </div> </div> ); }; const adjustControlStep = (step) => { const value = AdjustControlInput.current.state ? AdjustControlInput.current.state.value : AdjustControlInput.current.input.value; if (!isNaN(value * 1)) { if (AdjustControlInput.current.state) { AdjustControlInput.current.setState({ value: addNumMethod(value * 1, step * 1) }); } else { AdjustControlInput.current.input.value = addNumMethod(value * 1, step * 1); } } }; /** **************************************权限控制确认****************************************** */ const defineAutho = (code, tag, node, guid, value) => { const { userName, password } = AuthorFrom.current.getFieldsValue(true); if (!userName || !password) { message.warning('用户名或密码不能为空!'); return false; } setIsAuModalVisible(false); guidAggre[guid] = { tag, code, }; const flag = isNumber(value); mqttView.onSendWaMessageArrived( userName, sha1(password).toUpperCase(), guid, code, tag, value, flag ? value * 1 : '', ); }; /** **************************************权限控制方法****************************************** */ const authoMethod = (code, tag, node, guid, value) => { setIsAuModalVisible(true); auModalConfirmFn = () => defineAutho(code, tag, node, guid, value); }; /** **************************************开关控制确定****************************************** */ const defineSwitch = (code, tag, node) => { const guid = createGuid(); setIsModalVisible(false); const ctRule = JSON.parse(node.ctRule); if (node.isControl === '是') { authoMethod(code, tag, node, guid, ctRule[0].val); return false; } guidAggre[guid] = { tag, code }; const { val } = ctRule[0]; const flag = isNumber(val); mqttView.onSendWaMessageArrived( globalConfig.token || '', '', guid, code, tag, val, flag ? val * 1 : '', ); }; /** **************************************控制方法****************************************** */ const controlMethod = (code, tag, node) => { const ctRule = JSON.parse(node.ctRule); const min = ctRule.length ? ctRule[0].min : ''; const max = ctRule.length ? ctRule[0].max : ''; const hexfrom = ctRule.length ? ctRule[0].hexfrom : ''; const hexto = ctRule.length ? ctRule[0].hexto : ''; let value = AdjustControlInput.current.state ? AdjustControlInput.current.state.value : AdjustControlInput.current.input.value; if (value != 0 && !value) { message.warning('设置值不能为空!'); return false; } if (isNaN(value * 1)) { message.warning('设置值不合理!'); return false; } if (value < 0) { message.warning('设置值不合理!'); return false; } if (min !== '' && !isNaN(min * 1) && value < min * 1) { message.warning(`设置值不能小于${min}!`); return false; } if (max !== '' && !isNaN(max * 1) && value > max * 1) { message.warning(`设置值不能大于${max}!`); return false; } if (hexfrom && hexto) value = hexSwitch(value, hexfrom, hexto); const guid = createGuid(); setIsModalVisible(false); if (node.isControl === '是') { authoMethod(code, tag, node, guid, value); return false; } guidAggre[guid] = { tag, code }; mqttView.onSendWaMessageArrived( globalConfig.token || '', '', guid, code, tag, node.switchType, value * 1, ); }; const moreControlMethod = (code, tag, node, value) => { const guid = createGuid(); setIsModalVisible(false); if (node.isControl === '是') { authoMethod(code, tag, node, guid, value); return false; } guidAggre[guid] = { tag, code }; const flag = isNumber(value); mqttView.onSendWaMessageArrived( globalConfig.token || '', '', guid, code, tag, value, flag ? value * 1 : '', ); }; /** **************************************渲染多选控制****************************************** */ const renderMoreControlModal = () => { const ctRule = nodeData.ctRule ? JSON.parse(nodeData.ctRule) : []; const list = bindData.find((item) => { return item.name === nodeData.stationName; }); return ( <div className={classNames('moreControlContent')}> {ctRule.length > 0 && ctRule.map((rule, index) => { if (rule.val !== '' && rule.text !== '') { return ( <div key={index} className={classNames('moreControlList')}> <span>状态设置</span> <div onClick={(e) => moreControlMethod(list.code, nodeData.ctName, nodeData, rule.val) } > {rule.text} </div> </div> ); } })} </div> ); }; /** **************************************控制模态渲染****************************************** */ const controlModalRender = (data, list) => { const ctRule = data && data.ctRule ? JSON.parse(data.ctRule) : ''; switch (data.ctType) { case '按钮控制': if (data.switch === '是') message.warning(`当前设备已是${data.text}状态,请勿重复操作!`); if ( data.realVal === '--' || data.switch === '是' || !data.ctName || !data.ctName.length || ctRule[0].val === '' ) return false; modalComponent = renderSwitchControlModal; modalConfirmFn = () => defineSwitch(list.code, data.ctName, data); modalProps = { title: '状态控制' }; modalWidth = 520; setIsModalVisible(true); break; case '输入控制': if (data.realVal === '--' || !data.ctName) return false; modalComponent = renderAdjustControlModal; modalConfirmFn = () => controlMethod(list.code, data.ctName, data); modalProps = { title: `${data.ctName}设置` }; modalWidth = 520; setIsModalVisible(true); break; case '多选控制': if (!data.ctName) return false; modalComponent = renderMoreControlModal; modalProps = { footer: null, title: `${data.ctName}设置` }; modalWidth = 'auto'; setIsModalVisible(true); break; default: break; } }; /** **************************************跳转方法****************************************** */ const drawBoardMethod = (data) => { const opRule = JSON.parse(data.opRule); const name = opRule && opRule.name ? opRule.name : ''; const title = opRule && opRule.title ? opRule.title : ''; const device = opRule && opRule.device ? opRule.device : []; const width = opRule && opRule.width ? opRule.width : ''; const height = opRule && opRule.height ? opRule.height : ''; const color = opRule && opRule.color ? opRule.color : '#282d3b'; if (!name) return false; const deviceArr = []; device.forEach((item) => { const list = bindData.find((item1) => { return item1.name === item; }); deviceArr.push(list ? list.code : item); }); jumpModalProps = { width, height, title, name, device: deviceArr, color, }; setIsJumpModalVisible(true); }; const handleOk = (e) => { e.stopPropagation(); modalConfirmFn && modalConfirmFn(); }; const handleCancel = () => { setIsModalVisible(false); }; const handleAuOk = (e) => { e.stopPropagation(); auModalConfirmFn && auModalConfirmFn(); }; const renderModalContent = () => { return modalComponent && nodeData ? modalComponent() : null; }; /** **********************************画布渲染************************************ */ const diagramRender = (jsonStr) => { myDiagram = goJS( go.Diagram, twoID, // must name or refer to the DIV HTML element { initialContentAlignment: go.Spot.Center, contentAlignment: go.Spot.Center, allowDrop: false, // must be true to accept drops from the Palette 右边的面板允许防止图形 draggingTool: new GuidedDraggingTool(), allowZoom: isZoom ? true : false, allowSelect: false, 'draggingTool.dragsLink': true, isReadOnly: true, autoScale: isZoom ? go.Diagram.None : go.Diagram.Uniform, // 自适应,默认不自适应 initialAutoScale: go.Diagram.Uniform, // 自适应,默认不自适应 'draggingTool.isGridSnapEnabled': true, 'linkingTool.isUnconnectedLinkValid': true, 'animationManager.duration': 100, allowHorizontalScroll: isZoom ? true : false, padding: 20, allowVerticalScroll: isZoom ? true : false, 'linkingTool.portGravity': 20, 'relinkingTool.isUnconnectedLinkValid': true, 'relinkingTool.portGravity': 20, 'draggingTool.horizontalGuidelineColor': 'blue', 'draggingTool.verticalGuidelineColor': 'blue', 'draggingTool.centerGuidelineColor': 'green', rotatingTool: goJS(TopRotatingTool), // defined below 'rotatingTool.snapAngleMultiple': 15, 'rotatingTool.snapAngleEpsilon': 15, 'undoManager.isEnabled': true, LinkDrawn: changLinkRouting, // LinkReshaped: (e) => { // e.subject.routing = go.Link.Orthogonal; // }, 'linkingTool.direction': go.LinkingTool.ForwardsOnly, }, ); /** *********************************节点模板************************************* */ // svg节点定义 myDiagram.nodeTemplateMap.add( 'svgCase', goJS( go.Node, 'Spot', { locationSpot: go.Spot.Center, zOrder: 1 }, new go.Binding('zOrder', 'zOrder').makeTwoWay(), new go.Binding('location', 'loc', go.Point.parse).makeTwoWay(go.Point.stringify), new go.Binding('angle').makeTwoWay(), roleVisibleBinding(), // 绑定角色可见 goJS( go.Panel, 'Auto', { name: 'PANEL', }, new go.Binding('desiredSize', 'size', go.Size.parse).makeTwoWay(go.Size.stringify), goJS( go.Picture, { name: 'animateSvg', width: 56, height: 56, column: 0, scale: 1, source: '' }, new go.Binding('source', 'imgSrc', (v) => { return `${imgUrl}File/ModelManage/ModelFilePreview/${encodeURIComponent(v)}`; }), new go.Binding('scale', 'scale').makeTwoWay(), new go.Binding('width', 'width').makeTwoWay(), new go.Binding('height', 'height').makeTwoWay(), ), ), makePort('T', go.Spot.Top, true, true), makePort('L', go.Spot.Left, true, true), makePort('R', go.Spot.Right, true, true), makePort('B', go.Spot.Bottom, true, true), makePort('RB', go.Spot.BottomRight, true, true), makePort('LB', go.Spot.BottomLeft, true, true), makePort('RT', go.Spot.TopRight, true, true), makePort('LT', go.Spot.TopLeft, true, true), { click(e, node) { const { data } = node; nodeData = data; const list = bindData.find((item) => { return item.name === data.stationName; }); if (!list) return false; // 控制方法 if (data.ctName && data.ctType) { controlModalRender(data, list); return false; } // 画板跳转 switch (data.opType) { case '画板跳转': // 图片模型 drawBoardMethod(data); break; case '自定义交互': // 自定义交互 customBack(data); break; default: break; } }, }, ), ); // 模板块定义 myDiagram.nodeTemplateMap.add( 'modelCase', goJS( go.Node, 'Auto', nodeStyle(), 'Spot', { locationSpot: go.Spot.Center, zOrder: 1 }, new go.Binding('zOrder', 'zOrder').makeTwoWay(), new go.Binding('location', 'loc', go.Point.parse).makeTwoWay(go.Point.stringify), { // 设置其可改变大小 resizeObjectName: 'SHAPE', }, new go.Binding('angle').makeTwoWay(), roleVisibleBinding(), // 绑定角色可见 goJS( go.Shape, 'Rectangle', { name: 'SHAPE', fill: 'rgba(128,128,128,0.2)', stroke: 'gray' }, new go.Binding('fill', 'fillColor').makeTwoWay(), new go.Binding('stroke').makeTwoWay(), new go.Binding('strokeWidth').makeTwoWay(), new go.Binding('desiredSize', 'size', go.Size.parse).makeTwoWay(go.Size.stringify), ), ), ); // 圆形定义 myDiagram.nodeTemplateMap.add( 'ellipseCase', goJS( go.Node, 'Auto', nodeStyle(), 'Spot', { locationSpot: go.Spot.Center, zOrder: 1 }, new go.Binding('zOrder', 'zOrder').makeTwoWay(), new go.Binding('location', 'loc', go.Point.parse).makeTwoWay(go.Point.stringify), { // 设置其可改变大小 resizeObjectName: 'SHAPE', }, new go.Binding('angle').makeTwoWay(), roleVisibleBinding(), // 绑定角色可见 goJS( go.Shape, 'Ellipse', { name: 'SHAPE', fill: 'rgba(128,128,128,0.2)', stroke: 'gray' }, new go.Binding('fill', 'fillColor').makeTwoWay(), new go.Binding('stroke').makeTwoWay(), new go.Binding('strokeWidth').makeTwoWay(), new go.Binding('desiredSize', 'size', go.Size.parse).makeTwoWay(go.Size.stringify), ), ), ); // 设备简称 myDiagram.nodeTemplateMap.add( 'deviceCase', goJS( go.Node, 'Auto', nodeStyle(), 'Spot', { locationSpot: go.Spot.Center, zOrder: 3 }, new go.Binding('zOrder', 'zOrder').makeTwoWay(), new go.Binding('location', 'loc', go.Point.parse).makeTwoWay(go.Point.stringify), new go.Binding('angle').makeTwoWay(), roleVisibleBinding(), // 绑定角色可见 goJS( go.Shape, 'Rectangle', { name: 'SHAPE', strokeWidth: 10, stroke: '#000000' }, new go.Binding('fill', 'fillColor').makeTwoWay(), new go.Binding('stroke').makeTwoWay(), new go.Binding('strokeWidth').makeTwoWay(), new go.Binding('desiredSize', 'size', go.Size.parse).makeTwoWay(go.Size.stringify), ), goJS( go.TextBlock, textStyle(), { margin: 5, maxSize: new go.Size(NaN, NaN), minSize: new go.Size(NaN, 1), wrap: go.TextBlock.WrapFit, textAlign: 'center', editable: true, font: 'bold 12px Helvetica, Arial, sans-serif', stroke: '#454545', }, new go.Binding('text').makeTwoWay(), new go.Binding('font', 'fontStyle'), new go.Binding('stroke', 'fontStroke').makeTwoWay(), new go.Binding('textAlign', 'fontAlign'), ), { click(e, node) { const { data } = node; nodeData = data; const list = bindData.find((item) => { return item.name === data.stationName; }); if (!list) return false; switch (data.opType) { case '画板跳转': // 图片模型 drawBoardMethod(data); break; case '自定义交互': // 自定义交互 customBack(data); break; default: break; } }, }, ), ); // 名称定义 myDiagram.nodeTemplateMap.add( 'nameCase', goJS( go.Node, 'Auto', nodeStyle(), 'Spot', { locationSpot: go.Spot.Center, zOrder: 3 }, new go.Binding('zOrder', 'zOrder').makeTwoWay(), new go.Binding('location', 'loc', go.Point.parse).makeTwoWay(go.Point.stringify), new go.Binding('angle').makeTwoWay(), roleVisibleBinding(), // 绑定角色可见 goJS( go.Shape, 'Rectangle', { name: 'SHAPE', strokeWidth: 10, stroke: '#000000' }, new go.Binding('fill', 'fillColor').makeTwoWay(), new go.Binding('stroke').makeTwoWay(), new go.Binding('strokeWidth').makeTwoWay(), new go.Binding('desiredSize', 'size', go.Size.parse).makeTwoWay(go.Size.stringify), ), goJS( go.TextBlock, textStyle(), { margin: 5, maxSize: new go.Size(NaN, NaN), minSize: new go.Size(NaN, 1), wrap: go.TextBlock.WrapFit, textAlign: 'center', editable: true, font: 'bold 12px Helvetica, Arial, sans-serif', stroke: '#454545', }, new go.Binding('text').makeTwoWay(), new go.Binding('font', 'fontStyle'), new go.Binding('stroke', 'fontStroke').makeTwoWay(), new go.Binding('textAlign', 'fontAlign'), ), { click(e, node) { const { data } = node; nodeData = data; const list = bindData.find((item) => { return item.name === data.stationName; }); if (!list) return false; // 控制方法 if (data.ctName && data.ctType) { controlModalRender(data, list); return false; } switch (data.opType) { case '画板跳转': // 图片模型 drawBoardMethod(data); break; case '自定义交互': // 自定义交互 customBack(data); break; default: break; } }, }, ), ); // 公用管定义 myDiagram.nodeTemplateMap.add( 'HBar', goJS( go.Node, 'Auto', nodeStyle(), 'Spot', { locationSpot: go.Spot.Center, zOrder: 1 }, new go.Binding('zOrder', 'zOrder').makeTwoWay(), new go.Binding('location', 'loc', go.Point.parse).makeTwoWay(go.Point.stringify), new go.Binding('angle').makeTwoWay(), roleVisibleBinding(), // 绑定角色可见 goJS( go.Shape, 'Rectangle', { name: 'SHAPE', height: 0, width: 120, fill: '#41BFEC', stroke: null, strokeWidth: 0, minSize: new go.Size(20, 0), maxSize: new go.Size(Infinity, 0), }, new go.Binding('desiredSize', 'size', go.Size.parse).makeTwoWay(go.Size.stringify), new go.Binding('minSize', 'minSize').makeTwoWay(), new go.Binding('maxSize', 'maxSize').makeTwoWay(), new go.Binding('stroke', 'stroke').makeTwoWay(), new go.Binding('strokeWidth', 'strokeWidth').makeTwoWay(), ), goJS( go.Shape, { isPanelMain: true, stroke: 'white', strokeWidth: 3, height: 0, width: 100, name: 'PIPE', strokeDashArray: [20, 40], }, new go.Binding('width').makeTwoWay(), new go.Binding('stroke', 'waterStroke').makeTwoWay(), new go.Binding('strokeWidth', 'waterWidth').makeTwoWay(), new go.Binding('strokeDashArray', 'strokeDashArray').makeTwoWay(), { portId: '', toLinkable: true, fromLinkable: true, }, ), ), ); // 值定义 myDiagram.nodeTemplateMap.add( 'valCase', goJS( go.Node, 'Auto', nodeStyle(), 'Spot', { locationSpot: go.Spot.Center, zOrder: 2 }, new go.Binding('zOrder', 'zOrder').makeTwoWay(), new go.Binding('location', 'loc', go.Point.parse).makeTwoWay(go.Point.stringify), new go.Binding('angle').makeTwoWay(), roleVisibleBinding(), // 绑定角色可见 goJS( go.Shape, 'Rectangle', { name: 'SHAPE', strokeWidth: 10, stroke: '#000000' }, new go.Binding('fill', 'fillColor'), new go.Binding('stroke'), new go.Binding('strokeWidth'), new go.Binding('desiredSize', 'size', go.Size.parse).makeTwoWay(go.Size.stringify), ), goJS( go.TextBlock, textStyle(), { maxSize: new go.Size(NaN, NaN), minSize: new go.Size(NaN, 1), wrap: go.TextBlock.WrapFit, textAlign: 'center', editable: true, font: 'bold 12px Helvetica, Arial, sans-serif', stroke: '#454545', }, new go.Binding('text', 'showVal'), new go.Binding('font', 'fontStyle'), new go.Binding('stroke', 'fontStroke'), new go.Binding('textAlign', 'fontAlign'), ), { click(e, node) { const { data } = node; nodeData = data; const list = bindData.find((item) => { return item.name === data.stationName; }); if (!list) return false; // 控制方法 if (data.ctName && data.ctType) { controlModalRender(data, list); return false; } // 历史查看 if (data.opType) historyModalRender(data, list); }, }, ), ); // 连接点定义 myDiagram.nodeTemplateMap.add( 'linkPort', goJS( go.Node, 'Auto', nodeStyle(), 'Spot', { locationSpot: go.Spot.Center, zOrder: 1 }, new go.Binding('zOrder', 'zOrder').makeTwoWay(), new go.Binding('location', 'loc', go.Point.parse).makeTwoWay(go.Point.stringify), new go.Binding('angle').makeTwoWay(), roleVisibleBinding(), // 绑定角色 goJS( go.Panel, 'Auto', { name: 'PANEL', }, goJS(go.Shape, 'Rectangle', { fill: 'transparent', strokeWidth: 0, width: 8, height: 8, minSize: new go.Size(5, 5), }), ), ), ); // 水池动效 go.Shape.defineFigureGenerator('Pool', (shape, w, h) => { const geo = new go.Geometry(); const fig = new go.PathFigure(0, 0, true); // starting point geo.add(fig); fig.add(new go.PathSegment(go.PathSegment.Line, 0.75 * w, 0)); fig.add(new go.PathSegment(go.PathSegment.Line, w, 0.25 * h)); fig.add(new go.PathSegment(go.PathSegment.Line, w, h)); fig.add(new go.PathSegment(go.PathSegment.Line, 0, h).close()); return geo; }); // 定义水池 myDiagram.nodeTemplateMap.add( 'waterCase', goJS( go.Node, 'Auto', nodeStyle(), 'Spot', { locationSpot: go.Spot.Center, zOrder: 1 }, new go.Binding('zOrder', 'zOrder').makeTwoWay(), new go.Binding('location', 'loc', go.Point.parse).makeTwoWay(go.Point.stringify), new go.Binding('angle').makeTwoWay(), roleVisibleBinding(), // 绑定角色可见 goJS( go.Shape, 'Rectangle', { name: 'SHAPE', alignment: go.Spot.Bottom, alignmentFocus: go.Spot.Bottom, fill: 'transparent', strokeWidth: 10, stroke: 'red', desiredSize: new go.Size(NaN, 26), }, new go.Binding('width').makeTwoWay(), new go.Binding('height').makeTwoWay(), new go.Binding('stroke', 'stroke').makeTwoWay(), new go.Binding('strokeWidth', 'strokeWidth').makeTwoWay(), ), goJS( go.Shape, 'Rectangle', { name: 'SHAPE', alignment: go.Spot.Bottom, alignmentFocus: go.Spot.Bottom, fill: '#ccc', strokeWidth: 10, stroke: 'transparent', desiredSize: new go.Size(NaN, 26), }, new go.Binding('width').makeTwoWay(), new go.Binding('height').makeTwoWay(), new go.Binding('fill', 'waterColor').makeTwoWay(), new go.Binding('strokeWidth', 'strokeWidth').makeTwoWay(), ), goJS( go.Shape, 'Pool', { name: 'waterSvg', alignment: go.Spot.Bottom, alignmentFocus: go.Spot.Bottom, fill: '#DEE0A3', stroke: 'transparent', strokeWidth: 10, minSize: new go.Size(NaN, 5), desiredSize: new go.Size(NaN, 20), }, new go.Binding('width').makeTwoWay(), new go.Binding('height', 'waterHight').makeTwoWay(), new go.Binding('fill', 'fillColor').makeTwoWay(), new go.Binding('strokeWidth', 'strokeWidth').makeTwoWay(), ), ), ); // 进度条设置 go.Shape.defineFigureGenerator('RoundedRectanglePlus', (shape, w, h) => { // this figure takes one parameter, the size of the corner let p1 = Infinity; // default corner size if (shape !== null) { const param1 = shape.parameter1; if (!isNaN(param1) && param1 >= 0) p1 = param1; // can't be negative or NaN } p1 = Math.min(p1, w / 2); p1 = Math.min(p1, h / 2); // limit by whole height or by half height? const geo = new go.Geometry(); // a single figure consisting of straight lines and quarter-circle arcs geo.add( new go.PathFigure(0, p1) .add(new go.PathSegment(go.PathSegment.Arc, 180, 90, p1, p1, p1, p1)) .add(new go.PathSegment(go.PathSegment.Line, w - p1, 0)) .add(new go.PathSegment(go.PathSegment.Arc, 270, 90, w - p1, p1, p1, p1)) .add(new go.PathSegment(go.PathSegment.Arc, 0, 90, w - p1, h - p1, p1, p1)) .add(new go.PathSegment(go.PathSegment.Arc, 90, 90, p1, h - p1, p1, p1).close()), ); // don't intersect with two top corners when used in an "Auto" Panel geo.spot1 = new go.Spot(0, 0, 0.3 * p1, 0.3 * p1); geo.spot2 = new go.Spot(1, 1, -0.3 * p1, 0); return geo; }); // 定义进度条 myDiagram.nodeTemplateMap.add( 'speedCase', goJS( go.Node, 'Auto', nodeStyle(), 'Spot', { locationSpot: go.Spot.Center, zOrder: 1 }, new go.Binding('zOrder', 'zOrder').makeTwoWay(), new go.Binding('location', 'loc', go.Point.parse).makeTwoWay(go.Point.stringify), new go.Binding('angle').makeTwoWay(), roleVisibleBinding(), // 绑定角色可见 goJS( go.Shape, 'RoundedRectanglePlus', { name: 'SHAPE', alignment: go.Spot.Left, alignmentFocus: go.Spot.Left, strokeWidth: 2, stroke: '#FFFFFF', desiredSize: new go.Size(NaN, 26), fill: 'transparent', }, new go.Binding('width').makeTwoWay(), new go.Binding('height').makeTwoWay(), new go.Binding('strokeWidth', 'strokeWidth').makeTwoWay(), new go.Binding('stroke', 'stroke').makeTwoWay(), ), goJS( go.Shape, 'RoundedRectanglePlus', { name: 'SHAPE', alignment: go.Spot.Left, alignmentFocus: go.Spot.Left, fill: '#CCCCCC', strokeWidth: 2, stroke: 'transparent', desiredSize: new go.Size(NaN, 26), }, new go.Binding('width').makeTwoWay(), new go.Binding('height').makeTwoWay(), new go.Binding('fill', 'waterColor').makeTwoWay(), new go.Binding('strokeWidth', 'strokeWidth').makeTwoWay(), ), goJS( go.Shape, 'RoundedRectanglePlus', { name: 'speedSvg', alignment: go.Spot.Left, alignmentFocus: go.Spot.Left, fill: '#DEE0A3', stroke: 'transparent', strokeWidth: 2, minSize: new go.Size(NaN, 5), desiredSize: new go.Size(NaN, 20), }, new go.Binding('width', 'lineWidth').makeTwoWay(), new go.Binding('height', 'height').makeTwoWay(), new go.Binding('fill', 'fillColor').makeTwoWay(), new go.Binding('strokeWidth', 'strokeWidth'), ), ), ); // 泵状态设置 myDiagram.nodeTemplateMap.add( 'rotateCase', goJS( go.Node, 'Table', nodeStyle(), 'Spot', { locationSpot: go.Spot.Center, zOrder: 2 }, new go.Binding('zOrder', 'zOrder').makeTwoWay(), new go.Binding('location', 'loc', go.Point.parse).makeTwoWay(go.Point.stringify), { // 设置其可改变大小 resizeObjectName: 'SHAPE', rotatable: true, }, roleVisibleBinding(), // 绑定角色可见 goJS( go.Panel, 'Table', { name: 'PANEL', }, goJS( go.Shape, 'Ellipse', // 定义形状 { width: 37, height: 37, fill: 'transparent', stroke: 'transparent', strokeWidth: 1 }, new go.Binding('width', 'widthBox').makeTwoWay(), new go.Binding('height', 'heightBox').makeTwoWay(), ), new go.Binding('desiredSize', 'size', go.Size.parse).makeTwoWay(go.Size.stringify), goJS( go.Picture, { name: 'rotateSvg', width: 26, height: 26, column: 0, scale: 1, source: require('./images/组态/状态/泵离线.svg'), angle: 0, }, new go.Binding('source', 'imgSrc', (v) => { return require(`./images/组态/状态/${v.split('/').pop()}`); }).makeTwoWay(), new go.Binding('scale', 'scale').makeTwoWay(), new go.Binding('width', 'width').makeTwoWay(), new go.Binding('angle', 'angle').makeTwoWay(), new go.Binding('height', 'height').makeTwoWay(), ), ), ), ); // 点状态设置 myDiagram.nodeTemplateMap.add( 'pointCase', goJS( go.Node, 'Auto', nodeStyle(), 'Spot', { locationSpot: go.Spot.Center, zOrder: 2 }, new go.Binding('zOrder', 'zOrder').makeTwoWay(), new go.Binding('location', 'loc', go.Point.parse).makeTwoWay(go.Point.stringify), new go.Binding('angle').makeTwoWay(), roleVisibleBinding(), // 绑定角色可见 goJS( go.Shape, 'Ellipse', { width: 14, height: 14, name: 'SHAPE', fill: 'rgba(109, 122, 151, 1)', stroke: '#ffffff', }, new go.Binding('fill', 'fillColor').makeTwoWay(), new go.Binding('stroke').makeTwoWay(), new go.Binding('strokeWidth').makeTwoWay(), new go.Binding('height', 'height').makeTwoWay(), new go.Binding('width', 'height').makeTwoWay(), ), ), ); // 开关开设置 myDiagram.nodeTemplateMap.add( 'switchCase', goJS( go.Node, 'Auto', nodeStyle(), 'Spot', { locationSpot: go.Spot.Center, zOrder: 2 }, new go.Binding('zOrder', 'zOrder').makeTwoWay(), new go.Binding('location', 'loc', go.Point.parse).makeTwoWay(go.Point.stringify), new go.Binding('angle').makeTwoWay(), roleVisibleBinding(), // 绑定角色可见 goJS( go.Shape, 'RoundedRectangle', { name: 'SHAPE', strokeWidth: 10, stroke: '#000000' }, new go.Binding('fill', 'fillColor'), new go.Binding('stroke'), new go.Binding('strokeWidth'), new go.Binding('desiredSize', 'size', go.Size.parse).makeTwoWay(go.Size.stringify), ), goJS( go.TextBlock, textStyle(), { maxSize: new go.Size(NaN, NaN), minSize: new go.Size(NaN, 1), wrap: go.TextBlock.WrapFit, textAlign: 'center', editable: true, font: 'bold 12px Helvetica, Arial, sans-serif', stroke: '#454545', }, new go.Binding('text'), new go.Binding('font', 'fontStyle'), new go.Binding('stroke', 'fontStroke'), new go.Binding('textAlign', 'fontAlign'), ), { click(e, node) { const { data } = node; nodeData = data; const list = bindData.find((item) => { return item.name === data.stationName; }); if (!list) return false; // 控制方法 controlModalRender(data, list); }, }, ), ); // 搅拌机状态设置 myDiagram.nodeTemplateMap.add( 'blenderCase', goJS( go.Node, 'Table', nodeStyle(), 'Spot', { locationSpot: go.Spot.Center, zOrder: 2 }, new go.Binding('zOrder', 'zOrder').makeTwoWay(), new go.Binding('location', 'loc', go.Point.parse).makeTwoWay(go.Point.stringify), { // 设置其可改变大小 resizeObjectName: 'SHAPE', rotatable: true, }, new go.Binding('angle').makeTwoWay(), roleVisibleBinding(), // 绑定角色可见 goJS( go.Panel, 'Auto', { name: 'PANEL', }, new go.Binding('desiredSize', 'size', go.Size.parse).makeTwoWay(go.Size.stringify), goJS( go.Picture, { name: 'blenderSvg', width: 42.5, height: 56, column: 0, scale: 1, source: require('./images/组态/状态/搅拌机双头1.svg'), angle: 0, }, new go.Binding('source', 'imgSrc', (v) => { return require(`./images/组态/状态/${v.split('/').pop()}`); }).makeTwoWay(), new go.Binding('scale', 'scale').makeTwoWay(), new go.Binding('width', 'width').makeTwoWay(), new go.Binding('angle', 'angle').makeTwoWay(), new go.Binding('height', 'height').makeTwoWay(), ), ), ), ); // 连接线装饰模板 const linkSelectionAdornmentTemplate = goJS( go.Adornment, 'Link', goJS(go.Shape, { isPanelMain: true, fill: null, stroke: 'deepskyblue', strokeWidth: 0, }), ); /** *******************************单管连接方式****************************** */ myDiagram.linkTemplate = goJS( BarLink, { curve: go.Link.JumpOver, toShortLength: 0, fromShortLength: 0, layerName: 'Background', routing: go.Link.Orthogonal, // 不同的位置进行不同的routing corner: 2, reshapable: true, resegmentable: true, relinkableFrom: true, relinkableTo: true, }, new go.Binding('fromSpot', 'fromPort', (d) => { return spotConverter(d); }), new go.Binding('toSpot', 'toPort', (d) => { return spotConverter(d); }), new go.Binding('points').makeTwoWay(), roleVisibleBinding(), // 绑定角色可见 goJS( go.Shape, { isPanelMain: true, stroke: '#41BFEC' /* blue */, strokeWidth: 6, name: 'changecolor' }, new go.Binding('stroke', 'stroke'), new go.Binding('strokeWidth', 'strokeWidth'), ), goJS( go.Shape, { isPanelMain: true, stroke: 'white', strokeWidth: 3, name: 'PIPE', strokeDashArray: [20, 40], }, new go.Binding('strokeWidth', 'waterWidth'), new go.Binding('stroke', 'waterStroke'), ), ); /** *******************************sharpLine线条****************************** */ myDiagram.linkTemplateMap.add( 'sharpLine', goJS( BarLink, { curve: go.Link.JumpOver, resegmentable: true, adjusting: go.Link.Stretch, routing: go.Link.Normal, layerName: 'Background', routing: go.Link.Normal, //不同的位置进行不同的routing corner: 0, reshapable: true, resegmentable: true, relinkableFrom: true, relinkableTo: true, relinkableFrom: true, relinkableTo: true, }, new go.Binding('fromSpot', 'fromPort', function (d) { return spotConverter(d); }), new go.Binding('toSpot', 'toPort', function (d) { return spotConverter(d); }), new go.Binding('points').makeTwoWay(), roleVisibleBinding(), // 绑定角色可见 // mark each Shape to get the link geometry with isPanelMain: true goJS( go.Shape, { isPanelMain: true, stroke: '#41BFEC' /* blue*/, strokeWidth: 6, name: 'changecolor', }, new go.Binding('stroke', 'stroke'), new go.Binding('strokeWidth', 'strokeWidth'), ), goJS( go.Shape, { isPanelMain: true, stroke: 'white', strokeWidth: 3, name: 'PIPE', strokeDashArray: [20, 40], }, new go.Binding('strokeWidth', 'waterWidth'), new go.Binding('stroke', 'waterStroke'), ), ), ); /** **************************************合管连接方式****************************************** */ myDiagram.linkTemplateMap.add( 'linkToLink', goJS( 'Link', { relinkableFrom: true, relinkableTo: true }, goJS('Shape', { stroke: '#2D9945', strokeWidth: 2, }), ), ); const fromJson = JSON.parse(jsonStr); // const setTime = setTimeout(() => { myTimeout(() => { loop(); waterSvg(); rotateSvg(); blenderSvg(); animationSvg(); }, 100); const json = JSON.parse(JSON.stringify(fromJson)); json.linkDataArray.forEach((item) => { item.isHavingDash = flowShow; item.realVal = '--'; item.defaultWidth = item.waterWidth; }); json.nodeDataArray.forEach((item) => { item.showVal = '--'; item.realVal = '--'; item.realType = '离线'; item.Unit = ''; item.switchState = '开'; item.dtImgSrc = item.imgSrc || ''; if (item.category === 'HBar') { item.hBarClolor = item.waterStroke; item.typeDash = false; } if (item.category === 'nameCase') { item.dtFillColor = item.fillColor; item.dtStroke = item.stroke; item.dtFontStroke = item.fontStroke; item.dtText = item.text; } if (item.category === 'modelCase' || item.category === 'ellipseCase') { item.dtzOrder = item.zOrder; } if (item.category == 'deviceCase' && deviceName && deviceName.length) { var device = deviceName.find(function (arr, index) { return '设备' + stationList[index] == item.stationName; }); if (device) item.text = device; } }); myDiagram.model = go.Model.fromJson(json); }; return ( <div className={classNames(prefixCls)} ref={ConfigurationRef}> <div id={twoID} className={classNames('configurationView')}> <LoadBox spinning={spinning} /> {isEmpty && <Empty theme={'dark'} description={description} />} </div> {/* 远程控制 */} {isModalVisible && ( <Modal centered okText={'确定'} width={modalWidth} cancelText={'取消'} visible={isModalVisible} onOk={handleOk} onCancel={handleCancel} wrapClassName={classNames(`${prefixCls}-baseModal`)} getContainer={ConfigurationRef.current} {...modalProps} > {renderModalContent()} </Modal> )} {/* 权限登录 */} {isAuModalVisible && ( <Modal centered title={'权限认证'} okText={'确定'} cancelText={'取消'} visible={isAuModalVisible} onOk={handleAuOk} onCancel={() => setIsAuModalVisible(false)} getContainer={ConfigurationRef.current} wrapClassName={classNames(`${prefixCls}-baseModal`)} > <Form className={classNames('authorizeControlContent')} ref={AuthorFrom} name="loginForm"> <Form.Item className={classNames('authorizeControlItem')} name="userName" label="账户"> <Input placeholder="请输入用户名" /> </Form.Item> <Form.Item className={classNames('authorizeControlItem')} name="password" label="密码"> <Input placeholder="请输入密码" /> </Form.Item> </Form> </Modal> )} {/* 历史曲线 */} {isHIModalVisible && ( <Modal centered width={960} footer={null} visible={isHIModalVisible} onOk={() => setIsHIModalVisible(false)} onCancel={() => setIsHIModalVisible(false)} getContainer={ConfigurationRef.current} wrapClassName={classNames(`${prefixCls}-historyInfoModal`)} > <HistoryInfo title={''} tableProps={{ bordered: true, pagination: { pageSize: 20 } }} historyInfoService={getHistoryInfo} historyInfoParams={historyInfoParams} dictionaryService={getDictionaryList} dictionaryParams={ Object.keys(dictionaryParams).length ? dictionaryParams : { nodeID: 0 } } /> </Modal> )} {/* 画板跳转 */} {isJumpModalVisible && jumpModalProps && ( <DragModal centered width={jumpModalProps.width ? `${jumpModalProps.width}px` : '100%'} title={jumpModalProps.title} footer={null} visible={isJumpModalVisible} limit={true} onCancel={() => setIsJumpModalVisible(false)} wrapClassName={classNames(`${prefixCls}-jumpModal`)} getContainer={ConfigurationRef.current} componentPrefix={componentPrefix} style={{ height: jumpModalProps.height ? `${Number(jumpModalProps.height) + 103}px` : '100%', left: `calc(50% - ${jumpModalProps.width ? jumpModalProps.width / 2 + 'px' : '50%'})`, top: `calc(50% - ${ jumpModalProps.height ? (Number(jumpModalProps.height) + 103) / 2 + 'px' : '50%' })`, }} > <ConfigurationDetail {...props} name={jumpModalProps.name} devices={jumpModalProps.device} /> </DragModal> )} </div> ); }; ConfigurationView.defaultProps = { name: '', devices: [], deviceName: [], dictionaryParams: {}, config: {}, isZoom: false, flowShow: true, }; ConfigurationView.propTypes = { name: PropTypes.string, devices: PropTypes.array, deviceName: PropTypes.array, dictionaryParams: PropTypes.object, config: PropTypes.object, isZoom: PropTypes.bool, flowShow: PropTypes.bool, }; export default ConfigurationView;