Commit 674a7948 authored by 李纪文's avatar 李纪文

fix: 组态增加历史回放

parent e9adc860
...@@ -21,6 +21,10 @@ group: ...@@ -21,6 +21,10 @@ group:
<code src="./demos/Basic.tsx"> <code src="./demos/Basic.tsx">
## 工艺回放代码演示
<code src="./demos/Basic1.tsx">
## API ## API
| 参数 | 说明 | 类型 | 默认值 | | 参数 | 说明 | 类型 | 默认值 |
...@@ -31,3 +35,13 @@ group: ...@@ -31,3 +35,13 @@ group:
| config | 全局 globalConfig,没有时需要传递 | object | {} | | config | 全局 globalConfig,没有时需要传递 | object | {} |
| isZoom | 是否可缩放(手持上建议设置 true) | boolean | false | | isZoom | 是否可缩放(手持上建议设置 true) | boolean | false |
| flowShow | 是否水流效果(无数据表现) | boolean | true | | flowShow | 是否水流效果(无数据表现) | boolean | true |
### 工艺回放
| 参数 | 说明 | 类型 | 默认值 |
| -------- | ---------------------- | ------------------------------------ | ------ |
| speed | 历史数据播放当前进度值 | number | 0 |
| play | 历史数据是否播放 | boolean | false |
| times | 历史数据播放速度(s) | number | 2 |
| params | 历史数据服务参数 | object | {} |
| callback | 历史数据播放的回调 | function(speed, total, play, time){} | - |
/* eslint-disable */
import React, { useState, useEffect, useRef, useContext } from 'react';
import classNames from 'classnames';
import moment from 'moment';
import Empty from '@wisdom-components/empty';
import LoadBox from '@wisdom-components/loadbox';
import { message, Modal, ConfigProvider } from 'antd';
import PropTypes from 'prop-types';
import HistoryView from '@wisdom-components/ec_historyview';
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 { getSketchPadList, getSketchPadContent, getPointAddress, getHistoryInfo } from './apis';
import { deepCopy, hexToRgba, textStyle } from './js/utils';
import './index.less';
const goJS = go.GraphObject.make;
let online = false;
let imgUrl = null;
let historyInfoParams = [];
let twoID = '';
let myDiagram = null;
let editionArr = [];
const guidAggre = {};
const bindData = [];
const stationList = [];
let historyData = []; // 历史数据
let timeData = []; // 历史数据时间列表
let speed = 0; // 历史数据播放当前进度值
let times = 2; // 历史数据播放速度
let play = false; // 历史数据是否播放
let historyParams = {};
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) => {
const { getPrefixCls } = useContext(ConfigProvider.ConfigContext);
const prefixCls = getPrefixCls('ec-configuration-view');
const [isHIModalVisible, setIsHIModalVisible] = useState(false); // 历史曲线模态框
const [spinning, setSpinning] = useState(true); // 画板loading
const [isEmpty, setIsEmpty] = useState(false); // 画板无数据状态
const [description, setDescription] = useState(''); // 画板无数据描述
twoID = `TDG${Date.now().toString(36)}`;
const ConfigurationRef = useRef();
const customBack = props.customBack ? props.customBack : () => {};
const { devices = [], 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.LocalSite
? globalConfig.userInfo.LocalSite
: '',
});
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.LocalSite
? globalConfig.userInfo.LocalSite
: '',
});
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;
}
};
/** **************************************合管****************************************** */
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;
};
}, []);
useEffect(() => {
play = props.play || false;
times = props.times || 2;
}, [props.play, props.times]);
useEffect(() => {
speed = props.speed || 0;
}, [props.speed]);
useEffect(() => {
historyParams = props.params;
getHistoryData(false);
}, [props.params]);
/** ************************************获取画板JSON******************************* */
const getDiagramJson = async (list, siteInfo) => {
const response = await getSketchPadContent({
dimension: list.dimension,
siteCode: list.siteCode,
fileName: list.deployURL.split('\\').pop(),
_site:
globalConfig.userInfo && globalConfig.userInfo.LocalSite
? globalConfig.userInfo.LocalSite
: '',
});
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 : '',
});
});
diagramRender(typeof fromJson === 'string' ? fromJson : JSON.stringify(fromJson));
getHistoryData(true);
} else {
message.error(response.msg);
}
};
/** ************************************历史数据获取******************************* */
const getHistoryData = async (flag) => {
try {
speed = 0;
const json = JSON.parse(myDiagram.model.toJson());
const jsonCopy = JSON.parse(JSON.stringify(json));
const acrossTables = bindData.map((list) => {
let sensors = [];
jsonCopy.nodeDataArray.forEach((item) => {
item.shName && item.stationName === list.name && sensors.push(item.shName);
});
jsonCopy.linkDataArray.forEach((item) => {
item.shName && item.stationName === list.name && sensors.push(item.shName);
});
return {
deviceType: list.type,
sensors: sensors.join(','),
deviceCode: list.code,
};
});
const params = {
isDilute: true,
zoom: '1',
unit: 'h',
ignoreOutliers: false,
isVertical: false, // 是否查询竖表
dateFrom: moment(new Date()).format('yyyy-MM-DD 00:00:00'),
dateTo: moment(new Date()).format('yyyy-MM-DD 23:59:59'),
...historyParams,
acrossTables,
};
const results = await getHistoryInfo(params);
historyData = results?.data || [];
let timeArr = [];
historyData.forEach((item) => {
const timeList = item.dataModel.map((list) => {
return moment(list.pt).format('yyyy-MM-DD HH:mm');
});
timeArr = timeArr.concat(timeList);
});
const _timeData = dataUnique(timeArr);
timeData = _timeData.sort(function (a, b) {
return new Date(a).getTime() - new Date(b).getTime();
});
chartHistoryDataRender(historyData);
if (flag) historyTimeRender();
} catch (err) {}
};
/** ****************************************数据去重******************************* */
const dataUnique = (arr) => {
return Array.from(new Set(arr));
};
/** ***********************************图表历史数据处理**************************** */
const chartHistoryDataRender = (mqttData) => {
const time = timeData[speed];
loopLoadMethod(time);
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.stationCode;
});
const pvList = list.dataModel.find((arr) => {
return moment(arr.pt).format('yyyy-MM-DD HH:mm') === time;
});
if (!bindList || item.stationName !== bindList.name) return false;
if (
!pvList ||
pvList.PV === null ||
list.sensorName !== 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',
moment(list.pt).format('yyyy-MM-DD HH:mm:ss'),
);
return false;
}
const bindList = bindData.find((arr) => {
return arr.code === list.stationCode;
});
const pvList = list.dataModel.find((arr) => {
return moment(arr.pt).format('yyyy-MM-DD HH:mm') === time;
});
if (!bindList || item.stationName !== bindList.name) return false;
if (
!pvList ||
pvList.pv === null ||
list.sensorName !== 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 historyTimeRender = () => {
historyInterval(() => {
if (!play || !historyData.length || !timeData.length) return false;
speed = speed + 1;
if (speed >= timeData.length) {
play = false;
loopLoadMethod(timeData.pop());
return false;
}
chartHistoryDataRender(historyData);
});
};
/** **********************历史数据循环函数**************************** */
const historyInterval = (fn) => {
let timer;
let stime = +new Date();
let etime;
let myLoop = () => {
etime = +new Date();
if (isClose) return timer && cancelAnimationFrame(timer);
if (etime - stime >= times * 1000) {
stime = etime = +new Date();
fn();
}
timer = requestAnimationFrame(myLoop);
};
return requestAnimationFrame(myLoop);
};
// 数据回调
const loopLoadMethod = (time) => {
props.callback && props.callback(speed, timeData.length, play, time);
};
/** **************************************历史模态渲染****************************************** */
const historyModalRender = (data, list) => {
historyInfoParams = [
{
deviceCode: list.code,
sensors: data.shName,
deviceType: list.type,
},
];
setIsHIModalVisible(true);
};
/** **********************************画布渲染************************************ */
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;
// 画板跳转
switch (data.opType) {
case '画板跳转': // 图片模型
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;
const list = bindData.find((item) => {
return item.name === data.stationName;
});
if (!list) return false;
switch (data.opType) {
case '画板跳转': // 图片模型
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;
switch (data.opType) {
case '画板跳转': // 图片模型
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;
const list = bindData.find((item) => {
return item.name === data.stationName;
});
if (!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;
},
},
),
);
// 搅拌机状态设置
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);
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>
{/* 历史曲线 */}
{isHIModalVisible && (
<Modal
centered
width={1200}
footer={null}
open={isHIModalVisible}
onOk={() => setIsHIModalVisible(false)}
onCancel={() => setIsHIModalVisible(false)}
getContainer={ConfigurationRef.current}
wrapClassName={classNames(`${prefixCls}-historyInfoModal`)}
>
<HistoryView deviceParams={historyInfoParams} />
</Modal>
)}
</div>
);
};
ConfigurationView.defaultProps = {
name: '',
devices: [],
deviceName: [],
config: {},
isZoom: false,
flowShow: true,
speed: 0,
play: false,
times: 2,
callback: (speed, total, play, time) => {},
params: {},
};
ConfigurationView.propTypes = {
name: PropTypes.string,
devices: PropTypes.array,
deviceName: PropTypes.array,
config: PropTypes.object,
isZoom: PropTypes.bool,
flowShow: PropTypes.bool,
speed: PropTypes.number,
play: PropTypes.bool,
times: PropTypes.number,
callback: PropTypes.func,
params: PropTypes.object,
};
export default ConfigurationView;
/* 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 HistoryView from '@wisdom-components/ec_historyview';
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, 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 = [], 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.LocalSite
? globalConfig.userInfo.LocalSite
: '',
});
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.LocalSite
? globalConfig.userInfo.LocalSite
: '',
});
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.deployURL.split('\\').pop(),
_site:
globalConfig.userInfo && globalConfig.userInfo.LocalSite
? globalConfig.userInfo.LocalSite
: '',
});
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 realData = results && results.data && results.data.list ? results.data.list : [];
chartDataRender(flatten(realData));
} catch (err) {}
};
// 实时数据父子级平铺
const flatten = (arr) => {
return [].concat(
...arr.map((item) =>
item.child ? [].concat(item, ...flatten(item.child)) : [].concat(item),
),
);
};
/** ************************************图表数据处理******************************* */
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 = [
{
deviceCode: list.code,
sensors: data.shName,
deviceType: list.type,
},
];
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);
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={'取消'}
open={isModalVisible}
onOk={handleOk}
onCancel={handleCancel}
wrapClassName={classNames(`${prefixCls}-baseModal`)}
getContainer={ConfigurationRef.current}
{...modalProps}
>
{renderModalContent()}
</Modal>
)}
{/* 权限登录 */}
{isAuModalVisible && (
<Modal
centered
title={'权限认证'}
okText={'确定'}
cancelText={'取消'}
open={isAuModalVisible}
onOk={handleAuOk}
onCancel={() => setIsAuModalVisible(false)}
getContainer={ConfigurationRef.current}
width={520}
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.Password placeholder="请输入密码" />
</Form.Item>
</Form>
</Modal>
)}
{/* 历史曲线 */}
{isHIModalVisible && (
<Modal
centered
width={1200}
footer={null}
open={isHIModalVisible}
onOk={() => setIsHIModalVisible(false)}
onCancel={() => setIsHIModalVisible(false)}
getContainer={ConfigurationRef.current}
wrapClassName={classNames(`${prefixCls}-historyInfoModal`)}
>
<HistoryView deviceParams={historyInfoParams} />
</Modal>
)}
{/* 画板跳转 */}
{isJumpModalVisible && jumpModalProps && (
<DragModal
centered
width={jumpModalProps.width ? `${jumpModalProps.width}px` : '100vw'}
title={jumpModalProps.title}
footer={null}
visible={isJumpModalVisible}
limit={true}
onCancel={() => setIsJumpModalVisible(false)}
wrapClassName={classNames(`${prefixCls}-jumpModal`)}
getContainer={ConfigurationRef.current}
componentPrefix={componentPrefix}
destroyOnClose={true}
style={{
height: jumpModalProps.height ? `${Number(jumpModalProps.height) + 103}px` : '100vh',
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: [],
config: {},
isZoom: false,
flowShow: true,
};
ConfigurationView.propTypes = {
name: PropTypes.string,
devices: PropTypes.array,
deviceName: PropTypes.array,
config: PropTypes.object,
isZoom: PropTypes.bool,
flowShow: PropTypes.bool,
};
export default ConfigurationView;
...@@ -49,3 +49,12 @@ export function getDeviceRealInfo(data) { ...@@ -49,3 +49,12 @@ export function getDeviceRealInfo(data) {
data, data,
}); });
} }
// 获取历史数据
export function getHistoryInfo(data) {
return request({
url: `${baseURI}/PandaMonitor/Monitor/Device/GetSensorsDataForStation`,
method: REQUEST_METHOD_POST,
data,
});
}
import React from 'react'; import React from 'react';
import PandaConfigurationView from '../index'; import PandaConfiguration from '../index';
// import PandaConfigurationView from '../../es/index'; // import PandaConfigurationView from '../../es/index';
const Demo = () => { const Demo = () => {
return ( return (
<div style={{ width: '100%', height: '600px', background: '#242835' }}> <div style={{ width: '100%', height: '600px', background: '#242835' }}>
<PandaConfigurationView <PandaConfiguration
name={'水厂工艺流程段'} name={'水厂工艺流程段'}
devices={'EQZT00000008,EQZT00000007,CPDA00000001,JYBZ00000003,JYBZ00000005,JYBZ00000004,SC00000003'.split( devices={'EQZT00000008,EQZT00000007,CPDA00000001,JYBZ00000003,JYBZ00000005,JYBZ00000004,SC00000003'.split(
',', ',',
...@@ -15,7 +15,6 @@ const Demo = () => { ...@@ -15,7 +15,6 @@ const Demo = () => {
// )} // )}
// name={'丽江水厂原水提升泵D单元'} // name={'丽江水厂原水提升泵D单元'}
// devices={'CPAA00000001, CPAD00000001, LJSC00000002'.split(',')} // devices={'CPAA00000001, CPAD00000001, LJSC00000002'.split(',')}
// dictionaryParams={{nodeID: 149}}
config={globalConfig} config={globalConfig}
deviceName={['工艺流程1', '工艺流程2', '工艺流程3']} deviceName={['工艺流程1', '工艺流程2', '工艺流程3']}
// isZoom={true} // isZoom={true}
......
import React, { useState } from 'react';
import moment from 'moment';
import { Button } from 'antd';
import { PandaHistoryConfiguration } from '../index';
// import PandaConfigurationView from '../../es/index';
const Demo = () => {
const [speed, setSpeed] = useState(0);
const [play, setPlay] = useState(false);
const [times, setTimes] = useState(2);
const [obj, setObj] = useState({});
const [params, setParams] = useState({
isDilute: true,
zoom: '1',
unit: 'h',
ignoreOutliers: false,
isVertical: false, // 是否查询竖表
dateFrom: moment(new Date()).format('yyyy-MM-DD 00:00:00'),
dateTo: moment(new Date()).format('yyyy-MM-DD 23:59:59'),
});
return (
<>
<div style={{ width: '100%', height: '600px', background: '#242835' }}>
<PandaHistoryConfiguration
// name={'水厂工艺流程段'}
// devices={'EQZT00000008,EQZT00000007,CPDA00000001,JYBZ00000003,JYBZ00000005,JYBZ00000004'.split(
// ',',
// )}
name={'崇左丽江水厂原水泵房'}
devices={'EQZT00000007,CPBA00000001,CPAA00000001,EQZT00000008,CPDA00000001,CPAD00000001'.split(
',',
)}
// name={'丽江水厂原水提升泵D单元'}
// devices={'CPAA00000001, CPAD00000001, LJSC00000002'.split(',')}
config={globalConfig}
deviceName={['工艺流程1', '工艺流程2', '工艺流程3']}
speed={speed}
play={play}
times={times}
callback={(speed, total, play, time) => {
setObj({
speed,
total,
play,
time,
});
}}
params={params}
// isZoom={true}
// flowShow={false}
/>
</div>
<Button
onClick={() => {
setSpeed(20);
}}
style={{ margin: '10px' }}
>
改变speed
</Button>
<Button
onClick={() => {
setPlay(!play);
}}
style={{ margin: '10px' }}
>
改变play
</Button>
<Button
onClick={() => {
setTimes(5);
}}
style={{ margin: '10px' }}
>
改变times
</Button>
<Button
onClick={() => {
setParams({
isDilute: true,
zoom: '1',
unit: 'min',
ignoreOutliers: false,
isVertical: false, // 是否查询竖表
dateFrom: moment(new Date()).format('yyyy-MM-DD 00:00:00'),
dateTo: moment(new Date()).format('yyyy-MM-DD 23:59:59'),
});
}}
style={{ margin: '10px' }}
>
改变params
</Button>
<div
style={{
display: 'flex',
marginTop: '20px',
justifyContent: 'space-between',
flex: 'none',
}}
>
<span>speed:{obj?.speed || 0}</span>
<span>total:{obj?.total || 0}</span>
<span>play:{obj?.play ? '开' : '关'}</span>
<span>time:{obj?.time || ''}</span>
</div>
</>
);
};
export default Demo;
const globalConfig = {
token: 'a1372ef0ce7b4e4884d31cfd99fe92f6',
mqtt_iotIP: 'emqttd10.panda-water.cn:443',
mqtt_path: '/mqtt',
mqtt_IsSSL: true,
mqtt_site_code: 'site_dc8302ni',
mqtt_mess: {
MessageLevel: '1.0',
TcpIP: 'emqttd10.panda-water.cn',
TcpPort: 443,
site_code: 'site_dc8302ni',
},
userInfo: {
LocalSite: 'site_dc8302ni',
site: '',
},
};
/* eslint-disable */ import PandaConfiguration from './RealModel';
import React, { useState, useEffect, useRef, useContext } from 'react'; import PandaHistoryConfiguration from './HistoryModel';
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 HistoryView from '@wisdom-components/ec_historyview';
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, getDeviceRealInfo } from './apis';
import {
isNumber,
createGuid,
deepCopy,
hexToRgba,
addNumMethod,
hexSwitch,
textStyle,
} from './js/utils';
import './index.less';
const goJS = go.GraphObject.make; export default PandaConfiguration;
let online = false; export { PandaHistoryConfiguration };
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 = [], 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.LocalSite
? globalConfig.userInfo.LocalSite
: '',
});
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.LocalSite
? globalConfig.userInfo.LocalSite
: '',
});
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.deployURL.split('\\').pop(),
_site:
globalConfig.userInfo && globalConfig.userInfo.LocalSite
? globalConfig.userInfo.LocalSite
: '',
});
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 realData = results && results.data && results.data.list ? results.data.list : [];
chartDataRender(flatten(realData));
} catch (err) {}
};
// 实时数据父子级平铺
const flatten = (arr) => {
return [].concat(
...arr.map((item) =>
item.child ? [].concat(item, ...flatten(item.child)) : [].concat(item),
),
);
};
/** ************************************图表数据处理******************************* */
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 = [
{
deviceCode: list.code,
sensors: data.shName,
deviceType: list.type,
},
];
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);
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={'取消'}
open={isModalVisible}
onOk={handleOk}
onCancel={handleCancel}
wrapClassName={classNames(`${prefixCls}-baseModal`)}
getContainer={ConfigurationRef.current}
{...modalProps}
>
{renderModalContent()}
</Modal>
)}
{/* 权限登录 */}
{isAuModalVisible && (
<Modal
centered
title={'权限认证'}
okText={'确定'}
cancelText={'取消'}
open={isAuModalVisible}
onOk={handleAuOk}
onCancel={() => setIsAuModalVisible(false)}
getContainer={ConfigurationRef.current}
width={520}
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.Password placeholder="请输入密码" />
</Form.Item>
</Form>
</Modal>
)}
{/* 历史曲线 */}
{isHIModalVisible && (
<Modal
centered
width={1200}
footer={null}
open={isHIModalVisible}
onOk={() => setIsHIModalVisible(false)}
onCancel={() => setIsHIModalVisible(false)}
getContainer={ConfigurationRef.current}
wrapClassName={classNames(`${prefixCls}-historyInfoModal`)}
>
<HistoryView deviceParams={historyInfoParams} />
</Modal>
)}
{/* 画板跳转 */}
{isJumpModalVisible && jumpModalProps && (
<DragModal
centered
width={jumpModalProps.width ? `${jumpModalProps.width}px` : '100vw'}
title={jumpModalProps.title}
footer={null}
visible={isJumpModalVisible}
limit={true}
onCancel={() => setIsJumpModalVisible(false)}
wrapClassName={classNames(`${prefixCls}-jumpModal`)}
getContainer={ConfigurationRef.current}
componentPrefix={componentPrefix}
destroyOnClose={true}
style={{
height: jumpModalProps.height ? `${Number(jumpModalProps.height) + 103}px` : '100vh',
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: [],
config: {},
isZoom: false,
flowShow: true,
};
ConfigurationView.propTypes = {
name: PropTypes.string,
devices: PropTypes.array,
deviceName: PropTypes.array,
config: PropTypes.object,
isZoom: PropTypes.bool,
flowShow: PropTypes.bool,
};
export default ConfigurationView;
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment