import React, { useState, useEffect, useRef, useContext } from 'react';
import classNames from 'classnames';
import moment from 'moment';
import sha1 from 'sha1';
import { Input, message, Modal, Form, ConfigProvider } from 'antd';
import { ExclamationCircleOutlined, SearchOutlined } from '@ant-design/icons';
import MqttView from '@wisdom-components/mqttview';
import PropTypes from 'prop-types';
import HistoryInfo from '@wisdom-components/ec_historyinfo';
import 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 './index.less';

const goJS = go.GraphObject.make;
let twoID = `TDG${Date.now().toString(36)}`;
let online = false;
let myDiagram = null;
let imgUrl = null;
let modalComponent = null; // 点击节点展示的模态框内容
let modalConfirmFn = null; // 点击节点展示的模态框的确定事件
let auModalConfirmFn = null; // 登录模态框的确定事件
let jumpModalProps = null;
let nodeData = null; // 选中节点的数据
const guidAggre = {};
const bindData = [];
const stationList = [];
let mqttView = null;
let modalProps = {};
let historyInfoParams = {};
let editionArr = [];
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 [isModalVisible, setIsModalVisible] = useState(false);
  const [isAuModalVisible, setIsAuModalVisible] = useState(false); // 登录模态框
  const [isHIModalVisible, setIsHIModalVisible] = useState(false); // 历史曲线模态框
  const [isJumpModalVisible, setIsJumpModalVisible] = useState(false); // 画板跳转模态框

  twoID = `TDG${Date.now().toString(36)}`;

  const AdjustControlInput = useRef();
  const AuthorFrom = useRef();

  const flowShow = props.flowShow ? props.flowShow : true;
  const customBack = props.customBack ? props.customBack : () => {};

  const {
    devices = [],
    pointAddressService,
    sketchPadListService,
    sketchPadListParams,
    sketchPadContentService,
    historyInfoService,
    dictionaryService,
    dictionaryParams,
    globalConfig,
  } = props;

  /** ********************************************判断是否是数字*************************************************** */
  const isNumber = (val) => {
    const regPos = /^\d+(\.\d+)?$/; // 非负浮点数
    const regNeg =
      /^(-(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*)))$/; // 负浮点数
    return regPos.test(val) || regNeg.test(val);
  };

  /** ********************************************创造guid*************************************************** */
  const createGuid = () => {
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'
      .replace(/[xy]/g, (c) => {
        const r = (Math.random() * 16) | 0;
        const v = c === 'x' ? r : (r & 0x3) | 0x8;
        return v.toString(16);
      })
      .toUpperCase();
  };

  /** ************************************************深拷贝************************************************ */
  const deepCopy = (p, c) => {
    c = c || {};
    for (const i in p) {
      if (typeof p[i] === 'object') {
        c[i] = p[i].constructor === Array ? [] : {};
        deepCopy(p[i], c[i]);
      } else {
        c[i] = p[i];
      }
    }
    return c;
  };

  /** **************************************rgba颜色转换****************************************** */
  const hexToRgba = (hex, opacity) => {
    return `rgba(${parseInt(`0x${hex.slice(1, 3)}`)},${parseInt(`0x${hex.slice(3, 5)}`)},${parseInt(
      `0x${hex.slice(5, 7)}`,
    )},${opacity})`;
  };

  /** *********************************节点展示逻辑****************************** */
  const showNodeMethod = (node, list) => {
    const realVal = list.Value * 1;
    let switchState;
    myDiagram.model.setDataProperty(node, 'realVal', realVal);
    if (node.switch === '是') {
      switchState =
        node.openVal.toString().split(',').indexOf(realVal.toString()) > -1 ? '开' : '关';
      myDiagram.model.setDataProperty(node, 'switchState', switchState);
    }
    if (!node.shType) return false;
    let shRule = [];
    switch (node.category) {
      case 'svgCase': // 图片模型
        shRule = JSON.parse(node.shRule).find((rule) => {
          return rule.val.toString().split(',').indexOf(realVal.toString()) > -1;
        });
        myDiagram.model.setDataProperty(node, 'imgSrc', shRule ? shRule.attr : node.dtImgSrc);
        break;
      case 'nameCase': // 名称模型
        if (node.shType === '文本变化') {
          shRule = JSON.parse(node.shRule).find((rule) => {
            return rule.val.toString().split(',').indexOf(realVal.toString()) > -1;
          });
          myDiagram.model.setDataProperty(
            node,
            'fontStroke',
            shRule ? shRule.attr : node.dtFontStroke,
          );
          myDiagram.model.setDataProperty(node, 'text', shRule ? shRule.text : node.dtText);
        } else {
          shRule = JSON.parse(node.shRule).find((rule) => {
            return rule.val.toString().split(',').indexOf(realVal.toString()) > -1;
          });
          myDiagram.model.setDataProperty(
            node,
            'fillColor',
            hexToRgba(shRule ? shRule.attr : node.fill, node.opacity),
          );
        }
        break;
      case 'valCase': // 实时值模型
        myDiagram.model.setDataProperty(node, 'showVal', realVal < 0 ? 0 : 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);
        break;
      case 'switchCase': // 开关模型
        shRule = JSON.parse(node.shRule).find((rule) => {
          return rule.val.toString().split(',').indexOf(realVal.toString()) > -1;
        });
        myDiagram.model.setDataProperty(
          node,
          'fillColor',
          hexToRgba(shRule ? shRule.attr : node.fill, node.opacity),
        );
        myDiagram.model.setDataProperty(node, 'switch', shRule ? '是' : '否');
        break;
      case 'rotateCase': // 状态模型
        shRule = JSON.parse(node.shRule).find((rule) => {
          return rule.val.toString().split(',').indexOf(realVal.toString()) > -1;
        });
        myDiagram.model.setDataProperty(
          node,
          'imgSrc',
          shRule ? `assets/images/组态/状态/${shRule.attr}` : node.dtImgSrc,
        );
        break;
      case 'pointCase': // 点状态模型
        shRule = JSON.parse(node.shRule).find((rule) => {
          return rule.val.toString().split(',').indexOf(realVal.toString()) > -1;
        });
        myDiagram.model.setDataProperty(
          node,
          'fillColor',
          hexToRgba(shRule ? shRule.attr : node.fill, node.opacity),
        );
        break;
      case 'blenderCase': // 搅拌机模型
        break;
      case 'HBar': // 合管模型
        shRule = JSON.parse(node.shRule).find((rule) => {
          return rule.val.toString().split(',').indexOf(realVal.toString()) > -1;
        });
        if (shRule) {
          myDiagram.model.setDataProperty(node, 'stroke', shRule.attr);
          myDiagram.model.setDataProperty(node, 'waterStroke', shRule.text);
        } else {
          myDiagram.model.setDataProperty(node, 'stroke', node.stroke);
          myDiagram.model.setDataProperty(node, 'waterStroke', node.waterStroke);
        }
        break;
      case 'speedCase': // 名称模型
        shRule = JSON.parse(node.shRule).find((rule) => {
          return rule.val.toString().split(',').indexOf(realVal.toString()) > -1;
        });
        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 = JSON.parse(node.shRule).find((rule) => {
          return rule.val.toString().split(',').indexOf(realVal.toString()) > -1;
        });
        myDiagram.model.setDataProperty(node, 'zOrder', shRule ? shRule.text : node.dtzOrder);
        break;
      case 'ellipseCase': // 圆形模型
        shRule = JSON.parse(node.shRule).find((rule) => {
          return rule.val.toString().split(',').indexOf(realVal.toString()) > -1;
        });
        myDiagram.model.setDataProperty(
          node,
          'zOrder',
          shRule ? shRule.text * 1 || 0 : node.dtzOrder,
        );
        break;
      default:
        break;
    }
  };

  /** ***********************************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}控制下发成功。`);
        // guidCode = guid.code;
        // isNum = 0;
      }
      delete guidAggre[code];
    }
  };

  /** *********************************MQTT请求数据回调****************************** */
  const refreshData = (mqttDatas, code) => {
    const bindList = bindData.find((item) => {
      return item.code === code;
    });
    let oldJson = {};
    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));
    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 = JSON.parse(item.shRule).find((rule) => {
            return rule.val.toString().split(',').indexOf(item.realVal.toString()) > -1;
          });
          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;
    }
  };

  /** ********************************************获取工艺图画板信息***************************************** */
  const getConfiguraList = () => {
    imgUrl = online
      ? 'https://panda-water.cn/Publish/Web/'
      : `${globalConfig.baseURI}/Publish/Web/`;
    sketchPadListService(sketchPadListParams)
      .then((response) => {
        if (response.code === 0) {
          const data = response.data ? (response.data.list ? response.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 {
            message.info('咦~未查询到工艺图画板信息哦~');
          }
        } else {
          message.error(response.msg);
        }
      })
      .catch(() => {});
  };

  /** ************************************创建连接点*********************************** */
  // 创建一个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 waterSvg = () => {
    const diagram = myDiagram;
    const poolWater = setInterval(() => {
      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 me = this;
    const diagram = myDiagram;
    const tubeWater = setInterval(() => {
      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;
    const pumpType = setInterval(() => {
      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;
    const blenderType = setInterval(() => {
      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 nodeStyle = () => {
    return [
      new go.Binding('location', 'loc', go.Point.parse).makeTwoWay(go.Point.stringify),
      {
        locationSpot: go.Spot.Center,
      },
    ];
  };

  /** ****************************************文本样式****************************** */
  const textStyle = () => {
    return {
      font: 'bold 11pt Helvetica, Arial, sans-serif',
      stroke: 'whitesmoke',
    };
  };

  /** ************************************************联网判断********************************************* */
  const onlineMethod = (pathImg) => {
    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();
    };
  };

  const getPointAddress = () => {
    pointAddressService({ code: devices.join(',') }).then((response) => {
      if (response.code === 0) {
        editionArr = deepCopy(response.data, []);
      } else {
        message.error(response.msg);
      }
    });
  };

  useEffect(() => {
    onlineMethod('https://panda-water.cn/web4/assets/images/bootPage/熊猫图标.png');
    devices.length > 0 && getPointAddress();
    return () => {
      mqttView && mqttView.disSaveWaconnect();
      mqttView = null;
    };
  }, []);

  useEffect(() => {
    if (!isModalVisible) {
      modalConfirmFn = null;
      modalComponent = null;
      modalProps = {};
    }
  }, [isModalVisible]);

  useEffect(() => {
    if (!isAuModalVisible) {
      auModalConfirmFn = null;
    }
  }, [isAuModalVisible]);

  const getDiagramJson = (list, siteInfo) => {
    sketchPadContentService({
      dimension: list.dimension,
      siteCode: list.siteCode,
      fileName: `${list.name}.json`,
      _site: globalConfig.userInfo.site || '',
    }).then((response) => {
      if (response.code === 0) {
        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,
        });
        mqttView.saveWaterMqtt();
        diagramRender(typeof fromJson === 'string' ? fromJson : JSON.stringify(fromJson));
      } else {
        message.error(response.msg);
      }
    });
  };

  /** **************************************历史模态渲染****************************************** */
  const historyModalRender = (data, list) => {
    historyInfoParams = {
      stream: [
        {
          stationCode: list.code,
          sensors: data.shName,
          pointVersions: list.type,
          dateFrom: '',
          dateTo: '',
        },
      ],
      ignoreOutliers: false, // 过滤异常值
      isVertical: false, // 是否展示竖表
      zoom: '', // 数据抽稀
      unit: '', // 数据抽稀 min h
    };
    setIsHIModalVisible(true);
  };

  /** **************************************渲染按钮控制****************************************** */
  const renderSwitchControlModal = () => {
    return (
      <div className={classNames('switchControlContent')}>
        <ExclamationCircleOutlined />
        {`确定要${nodeData.text}${nodeData.ctName}？`}
      </div>
    );
  };

  /** **************************************渲染输入控制****************************************** */
  const renderAdjustControlModal = () => {
    const ctRule = nodeData.ctRule ? JSON.parse(nodeData.ctRule) : [];
    return (
      <div className={classNames('adjustControlContent')}>
        <div className={classNames('label')}>设置</div>
        <Input
          placeholder="请输入设置值"
          ref={AdjustControlInput}
          defaultValue={nodeData.realVal}
          suffix={ctRule.length ? ctRule[0].text : ''}
        />
      </div>
    );
  };

  /** **************************************权限控制确认****************************************** */
  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 value = AdjustControlInput.current.state.value || '';
    if (!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;
    }
    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 = nodeData && nodeData.ctRule ? JSON.parse(nodeData.ctRule) : '';

    switch (nodeData.ctType) {
      case '按钮控制':
        if (nodeData.switch === '是')
          message.warning(`当前设备已是${nodeData.text}状态，请勿重复操作！`);
        if (
          nodeData.realVal === '--' ||
          nodeData.switch === '是' ||
          !nodeData.ctName ||
          !nodeData.ctName.length ||
          ctRule[0].val === ''
        )
          return false;
        modalComponent = renderSwitchControlModal;
        modalConfirmFn = () => defineSwitch(list.code, data.ctName, data);
        modalProps = { title: '状态控制' };
        setIsModalVisible(true);
        break;
      case '输入控制':
        if (nodeData.realVal === '--' || !nodeData.ctName) return false;
        modalComponent = renderAdjustControlModal;
        modalConfirmFn = () => controlMethod(list.code, data.ctName, data);
        modalProps = { title: `${nodeData.ctName}设置` };
        setIsModalVisible(true);
        break;
      case '多选控制':
        if (!nodeData.ctName) return false;
        modalComponent = renderMoreControlModal;
        modalProps = { footer: null, title: `${nodeData.ctName}设置` };
        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 : '';
    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,
    };
    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: false,
        allowSelect: false,
        'draggingTool.dragsLink': true,
        isReadOnly: true,
        autoScale: go.Diagram.Uniform, // 自适应,默认不自适应
        initialAutoScale: go.Diagram.Uniform, // 自适应,默认不自适应
        'draggingTool.isGridSnapEnabled': true,
        'linkingTool.isUnconnectedLinkValid': true,
        'animationManager.duration': 100,
        allowHorizontalScroll: false,
        padding: 20,
        allowVerticalScroll: 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(),

        goJS(
          go.Panel,
          'Auto',
          {
            name: 'PANEL',
          },
          new go.Binding('desiredSize', 'size', go.Size.parse).makeTwoWay(go.Size.stringify),

          goJS(
            go.Picture,
            { 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(),
        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(),
        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: 2 },
        new go.Binding('zOrder', 'zOrder').makeTwoWay(),
        new go.Binding('location', 'loc', go.Point.parse).makeTwoWay(go.Point.stringify),
        new go.Binding('angle').makeTwoWay(),
        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'),
        ),
      ),
    );

    // 名称定义
    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(),
        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(),
        new go.Binding('angle').makeTwoWay(),
        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(),
        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(),
        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(),
        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(),
        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,
        },
        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(),
        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(),
        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(),
        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(),
      goJS(
        go.Shape,
        { isPanelMain: true, stroke: '#41BFEC' /* blue */, strokeWidth: 6, name: 'changecolor' },
        new go.Binding('stroke', 'stroke'),
        new go.Binding('strokeWidth', 'strokeWidth'),
      ),
      goJS(
        go.Shape,
        {
          isPanelMain: true,
          stroke: 'white',
          strokeWidth: 3,
          name: 'PIPE',
          strokeDashArray: [20, 40],
        },
        new go.Binding('strokeWidth', 'waterWidth'),
        new go.Binding('stroke', 'waterStroke'),
      ),
    );

    /** **************************************合管连接方式****************************************** */
    myDiagram.linkTemplateMap.add(
      'linkToLink',
      goJS(
        'Link',
        { relinkableFrom: true, relinkableTo: true },
        goJS('Shape', { stroke: '#2D9945', strokeWidth: 2 }),
      ),
    );
    const fromJson = JSON.parse(jsonStr);
    const setTime = setTimeout(() => {
      loop();
      waterSvg();
      rotateSvg();
      blenderSvg();
    }, 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;
      }
    });
    myDiagram.model = go.Model.fromJson(json);
  };

  return (
    <div className={classNames(prefixCls)}>
      <div id={twoID} className={classNames('configurationView')}></div>
      {/* 远程控制 */}
      {isModalVisible && (
        <Modal
          centered
          okText={'确定'}
          cancelText={'取消'}
          visible={isModalVisible}
          onOk={handleOk}
          onCancel={handleCancel}
          wrapClassName={classNames(`${prefixCls}-modal`)}
          {...modalProps}
        >
          {renderModalContent()}
        </Modal>
      )}
      {/* 权限登录 */}
      {isAuModalVisible && (
        <Modal
          centered
          title={'权限认证'}
          okText={'确定'}
          cancelText={'取消'}
          visible={isAuModalVisible}
          onOk={handleAuOk}
          onCancel={() => setIsAuModalVisible(false)}
          wrapClassName={classNames(`${prefixCls}-modal`)}
        >
          <Form className={classNames('authorizeControlContent')} ref={AuthorFrom} name="loginForm">
            <Form.Item className={classNames('authorizeControlItem')} name="userName" label="账户">
              <Input placeholder="请输入用户名" />
            </Form.Item>
            <Form.Item className={classNames('authorizeControlItem')} name="password" label="密码">
              <Input placeholder="请输入密码" />
            </Form.Item>
          </Form>
        </Modal>
      )}
      {/* 历史曲线 */}
      {isHIModalVisible && (
        <Modal
          centered
          width={960}
          footer={null}
          visible={isHIModalVisible}
          onOk={() => setIsHIModalVisible(false)}
          onCancel={() => setIsHIModalVisible(false)}
          wrapClassName={classNames('historyInfoModal')}
        >
          <HistoryInfo
            title={''}
            tableProps={{ bordered: true, pagination: { pageSize: 20 } }}
            historyInfoService={historyInfoService}
            historyInfoParams={historyInfoParams}
            dictionaryService={dictionaryService}
            dictionaryParams={dictionaryParams}
          />
        </Modal>
      )}
      {/* 画板跳转 */}
      {isJumpModalVisible && jumpModalProps && (
        <Modal
          centered
          width={jumpModalProps.width ? `${jumpModalProps.width}px` : '100%'}
          title={jumpModalProps.title}
          footer={null}
          visible={isJumpModalVisible}
          onCancel={() => setIsJumpModalVisible(false)}
          wrapClassName={classNames('jumpModal')}
          style={{
            height: jumpModalProps.height ? `${Number(jumpModalProps.height) + 103}px` : '100%',
          }}
        >
          <ConfigurationView name={jumpModalProps.name} devices={jumpModalProps.device} />
        </Modal>
      )}
    </div>
  );
};

ConfigurationView.defaultProps = {
  name: '',
  devices: [],
  pointAddressService: () => {},
  sketchPadListService: () => {},
  sketchPadContentService: () => {},
  sketchPadListParams: {},
  historyInfoService: () => {},
  dictionaryService: () => {},
  dictionaryParams: {},
  globalConfig: {},
};

ConfigurationView.propTypes = {
  name: PropTypes.string,
  devices: PropTypes.array,
  pointAddressService: PropTypes.func,
  sketchPadListService: PropTypes.func,
  sketchPadContentService: PropTypes.func,
  sketchPadListParams: PropTypes.object,
  historyInfoService: PropTypes.func,
  dictionaryService: PropTypes.func,
  dictionaryParams: PropTypes.object,
  globalConfig: PropTypes.object,
};

export default ConfigurationView;
