Commit a6d9ca17 authored by 涂茜's avatar 涂茜

feat: add ConfigurationView

parent 7524448e
Pipeline #31678 passed with stages
in 6 minutes 39 seconds
......@@ -105,13 +105,19 @@ export default {
'/extend-components': [
{
title: '业务数据展示',
children: ['EC_DeviceTree', 'EC_QuotaSelect', 'EC_HistoryInfo', 'EC_RealTimeInfo'],
children: [
'EC_DeviceTree',
'EC_QuotaSelect',
'EC_HistoryInfo',
'EC_RealTimeInfo',
'EC_ConfigurationView',
],
},
],
},
proxy: {
'/api': {
target: 'http://127.0.0.1:8888/',
target: 'http://192.168.12.71:8080',
changeOrigin: true,
pathRewrite: { '^/api': '' },
},
......
......@@ -34,6 +34,7 @@
"ie >= 11"
],
"devDependencies": {
"@ant-design/icons": "^4.6.2",
"@ant-design/pro-skeleton": "^1.0.0-beta.2",
"@babel/core": "^7.8.3",
"@babel/plugin-proposal-object-rest-spread": "^7.8.3",
......@@ -151,7 +152,8 @@
"js-export-excel": "^1.1.4",
"jszip": "^3.5.0",
"mqtt-client": "^1.0.12",
"parseForm": "0.0.8"
"parseForm": "0.0.8",
"sha1": "^1.1.1"
},
"size-limit": [
{
......
# `@wisdom-components/ec_configurationview`
> TODO: description
## Usage
```
import ecConfigurationView from '@wisdom-components/ec_configurationview');
// TODO: DEMONSTRATE API
```
{
"name": "@wisdom-components/ec_configurationview",
"version": "1.0.0",
"description": "> TODO: description",
"author": "tuqian <webtuqian@163.com>",
"homepage": "",
"license": "ISC",
"main": "lib/index.js",
"directories": {
"lib": "lib",
"test": "__tests__"
},
"files": [
"lib"
],
"publishConfig": {
"registry": "https://g.civnet.cn:4873/"
},
"repository": {
"type": "git",
"url": "https://g.civnet.cn:8443/ReactWeb5/wisdom-components.git"
},
"scripts": {
"test": "echo \"Error: run tests from root\" && exit 1"
}
}
---
title: EC_ConfigurationView - 组态查看
nav:
title: 业务组件
path: /extend-components
group:
path: /
---
# EC_ConfigurationView 组态查看
基础业务组件
- 组态查看
## 何时使用
- 在组态查看时。
## 代码演示
<code src="./demos/Basic.tsx">
## API
| 参数 | 说明 | 类型 | 默认值 |
| ------------------------------ | -------------------- | ------ | -------- |
| name `必需` | 画板名称 | string | '' |
| devices `必需` | 画板设备 | array | [] |
| pointAddressService `必需` | 获取点表地址信息接口 | func | () => {} |
| sketchPadListService `必需` | 获取画板列表接口 | func | () => {} |
| sketchPadListParams `必需` | 画板列表接口参数 | object | {} |
| sketchPadContentService `必需` | 获取画板 JSON 接口 | func | () => {} |
| historyInfoService `必需` | 获取历史信息接口 | func | () => {} |
| dictionaryService `必需` | 获取数据字典信息接口 | func | () => {} |
| dictionaryParams `必需` | 数据字典信息接口参数 | object | {} |
| globalConfig `必需` | 全局 config | object | {} |
import React from 'react';
import PandaConfigurationView from '../index';
import { service } from '@wisdom-utils/utils';
const REQUEST_HTTP = 'http';
const REQUEST_METHOD_GET = 'get';
const REQUEST_METHOD_POST = 'post';
const GET_SKETCHPAD_LIST =
'https://www.fastmock.site/mock/162c15dca15c4dba9ba51e0a0b76929b/api/PandaCore/GCK/SketchPad/List';
const GET_FILE_SKETCHPAD_CONTENT =
'https://www.fastmock.site/mock/162c15dca15c4dba9ba51e0a0b76929b/api/PandaCore/GCK/SketchPad/SketchContent';
const GET_POINT_ADDRESS =
'https://www.fastmock.site/mock/162c15dca15c4dba9ba51e0a0b76929b/api/PandaCore/GCK/PointAddress/GetPointAddress';
const GET_HISTORY_INFO =
'https://www.fastmock.site/mock/162c15dca15c4dba9ba51e0a0b76929b/api/PandaCore/Monitor/Device/SensorsDataForStation'; //获取历史信息
const GET_DICTIONARY_LIST =
'https://www.fastmock.site/mock/162c15dca15c4dba9ba51e0a0b76929b/api/PandaCore/OMS/Data/GetDataDictionaryList'; //获取数据字典信息
// const GET_SKETCHPAD_LIST = '/api/PandaCore/GCK/SketchPad/List'; //获取画板列表接口
// const GET_FILE_SKETCHPAD_CONTENT = '/api/PandaCore/GCK/SketchPad/SketchContent'; //获取画板JSON
// const GET_POINT_ADDRESS = '/api/PandaCore/GCK/PointAddress/GetPointAddress'; //获取点表地址信息
// const GET_HISTORY_INFO = '/api/PandaCore/GCK/Device/SensorsDataForStation'; //获取历史信息
// const GET_DICTIONARY_LIST = '/api/PandaCore/OMS/DataManger/GetDataDictionaryList'; //获取数据字典信息
const configurationService = {
getSketchPadList: {
url: GET_SKETCHPAD_LIST, // 获取画板列表接口
method: REQUEST_METHOD_GET,
type: REQUEST_HTTP,
},
getSketchPadContent: {
url: GET_FILE_SKETCHPAD_CONTENT, // 获取画板JSON
method: REQUEST_METHOD_GET,
type: REQUEST_HTTP,
},
getPointAddress: {
url: GET_POINT_ADDRESS, // 获取点表地址信息
method: REQUEST_METHOD_GET,
type: REQUEST_HTTP,
},
getHistoryInfo: {
url: GET_HISTORY_INFO,
method: REQUEST_METHOD_POST,
type: REQUEST_HTTP,
},
getDictionaryList: {
url: GET_DICTIONARY_LIST,
method: REQUEST_METHOD_GET,
type: REQUEST_HTTP,
},
};
const cvService = service(configurationService);
const getPointAddress = cvService.getPointAddress;
const getSketchPadContent = cvService.getSketchPadContent;
const getSketchPadList = cvService.getSketchPadList;
const getHistoryInfo = cvService.getHistoryInfo;
const getDictionaryList = cvService.getDictionaryList;
const Demo = () => {
return (
<div style={{ width: '100%', height: '600px', background: '#242835' }}>
<PandaConfigurationView
name={'组态测试'}
devices={['ZTCS00000001', 'ZTCS00000002', 'ZTCS00000003', 'ZTCS00000004']}
pointAddressService={getPointAddress}
sketchPadListService={getSketchPadList}
sketchPadContentService={getSketchPadContent}
sketchPadListParams={{
_site: '',
siteCode: '151_ReactWeb5',
queryInfo: '',
version: '全部',
name: '组态测试',
}}
historyInfoService={getHistoryInfo}
dictionaryService={getDictionaryList}
dictionaryParams={{ nodeID: 149 }}
globalConfig={globalConfig}
/>
</div>
);
};
export default Demo;
const globalConfig = {
baseURI: 'http://192.168.12.71:8080',
userInfo: {
site: '',
},
token: 'a1372ef0ce7b4e4884d31cfd99fe92f6',
mqtt_iotIP: '192.168.12.9:8083',
mqtt_path: '/mqtt',
mqtt_IsSSL: false,
mqtt_mess: {
MessageLevel: '1.0',
TcpIP: '192.168.12.9',
TcpPort: 8083,
site_code: '151_ReactWeb5',
},
};
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 24.1.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="46.69px" height="37px" viewBox="0 0 46.69 37" enable-background="new 0 0 46.69 37" xml:space="preserve">
<linearGradient id="shape1_2_" gradientUnits="userSpaceOnUse" x1="3188.7671" y1="100.6142" x2="3165.1602" y2="128.5116" gradientTransform="matrix(1 0 0 -1 -3152.22 145.2878)">
<stop offset="0" style="stop-color:#BAC0C1"/>
<stop offset="0.15" style="stop-color:#F4FAFC"/>
<stop offset="0.25" style="stop-color:#F8FCFD"/>
<stop offset="0.44" style="stop-color:#D5DBDD"/>
<stop offset="0.6" style="stop-color:#BDC3C4"/>
<stop offset="0.8" style="stop-color:#A0A4A6"/>
<stop offset="0.97" style="stop-color:#929697"/>
<stop offset="1" style="stop-color:#C2C7C9"/>
</linearGradient>
<path id="shape1_1_" fill="url(#shape1_2_)" d="M0.88,27.31H46.69v3.523L23.785,37L0,30.834V27.31H0.88z"/>
<linearGradient id="shape2_2_" gradientUnits="userSpaceOnUse" x1="2515.2495" y1="377.179" x2="2515.0549" y2="377.179" gradientTransform="matrix(33.5 0 0 -136.2 -84233.7969 51386.7539)">
<stop offset="0" style="stop-color:#BAC0C1"/>
<stop offset="0.15" style="stop-color:#F4FAFC"/>
<stop offset="0.25" style="stop-color:#F8FCFD"/>
<stop offset="0.44" style="stop-color:#D5DBDD"/>
<stop offset="0.6" style="stop-color:#BDC3C4"/>
<stop offset="0.8" style="stop-color:#A0A4A6"/>
<stop offset="0.97" style="stop-color:#929697"/>
<stop offset="1" style="stop-color:#C2C7C9"/>
</linearGradient>
<path id="shape2_1_" fill="url(#shape2_2_)" d="M20.262,1.762h6.166V28.19h-6.166V1.762z"/>
<linearGradient id="shape3_2_" gradientUnits="userSpaceOnUse" x1="2511.0767" y1="372.5573" x2="2510.8806" y2="372.5573" gradientTransform="matrix(44.6 0 0 -51 -111966.2969 19005.2656)">
<stop offset="0" style="stop-color:#ACBABD"/>
<stop offset="0.15" style="stop-color:#E3F3F7"/>
<stop offset="0.25" style="stop-color:#EFF8FB"/>
<stop offset="0.44" style="stop-color:#C5D4D8"/>
<stop offset="0.6" style="stop-color:#AFBDC0"/>
<stop offset="0.8" style="stop-color:#939FA2"/>
<stop offset="0.97" style="stop-color:#879194"/>
<stop offset="1" style="stop-color:#B3C1C5"/>
</linearGradient>
<path id="shape3_1_" fill="url(#shape3_2_)" d="M18.94,0h8.809v9.691H18.94V0z"/>
<linearGradient id="shape4_2_" gradientUnits="userSpaceOnUse" x1="2511.0767" y1="373.4229" x2="2510.8806" y2="373.4229" gradientTransform="matrix(44.6 0 0 -40.6 -111966.2969 15191.3604)">
<stop offset="0" style="stop-color:#9D9D9D"/>
<stop offset="0.15" style="stop-color:#D0D1D1"/>
<stop offset="0.25" style="stop-color:#E5E6E6"/>
<stop offset="0.44" style="stop-color:#B3B4B4"/>
<stop offset="0.6" style="stop-color:#9FA0A0"/>
<stop offset="0.8" style="stop-color:#868787"/>
<stop offset="0.97" style="stop-color:#7A7B7B"/>
<stop offset="1" style="stop-color:#A3A4A4"/>
</linearGradient>
<path id="shape4_1_" fill="url(#shape4_2_)" d="M18.94,26.428h8.809v7.928H18.94V26.428z"/>
<linearGradient id="shape5_2_" gradientUnits="userSpaceOnUse" x1="2511.0767" y1="355.048" x2="2510.8806" y2="355.048" gradientTransform="matrix(44.6 0 0 -12.9 -111966.2969 4593.7754)">
<stop offset="0" style="stop-color:#ACBABD"/>
<stop offset="0.15" style="stop-color:#E3F3F7"/>
<stop offset="0.25" style="stop-color:#EFF8FB"/>
<stop offset="0.44" style="stop-color:#C5D4D8"/>
<stop offset="0.6" style="stop-color:#AFBDC0"/>
<stop offset="0.8" style="stop-color:#939FA2"/>
<stop offset="0.97" style="stop-color:#879194"/>
<stop offset="1" style="stop-color:#B3C1C5"/>
</linearGradient>
<path id="shape5_1_" fill="url(#shape5_2_)" d="M18.94,12.334h8.809v2.643H18.94V12.334z"/>
<linearGradient id="shape6_2_" gradientUnits="userSpaceOnUse" x1="2525.8188" y1="374.3631" x2="2525.6233" y2="374.3631" gradientTransform="matrix(20.5 0 0 -47.3 -51754.3516 17739.0898)">
<stop offset="0" style="stop-color:#BAC0C1"/>
<stop offset="0.15" style="stop-color:#F4FAFC"/>
<stop offset="0.25" style="stop-color:#F8FCFD"/>
<stop offset="0.44" style="stop-color:#D5DBDD"/>
<stop offset="0.6" style="stop-color:#BDC3C4"/>
<stop offset="0.8" style="stop-color:#A0A4A6"/>
<stop offset="0.97" style="stop-color:#929697"/>
<stop offset="1" style="stop-color:#C2C7C9"/>
</linearGradient>
<path id="shape6_1_" fill="url(#shape6_2_)" d="M21.142,27.31h4.405v8.809h-4.405V27.31z"/>
</svg>
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 24.1.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="46.69px" height="37px" viewBox="0 0 46.69 37" enable-background="new 0 0 46.69 37" xml:space="preserve">
<linearGradient id="shape1_2_" gradientUnits="userSpaceOnUse" x1="3186.6902" y1="103.0686" x2="3166.7969" y2="126.5773" gradientTransform="matrix(1 0 0 -1 -3152.22 145.2878)">
<stop offset="0" style="stop-color:#BAC0C1"/>
<stop offset="0.15" style="stop-color:#F4FAFC"/>
<stop offset="0.25" style="stop-color:#F8FCFD"/>
<stop offset="0.44" style="stop-color:#D5DBDD"/>
<stop offset="0.6" style="stop-color:#BDC3C4"/>
<stop offset="0.8" style="stop-color:#A0A4A6"/>
<stop offset="0.97" style="stop-color:#929697"/>
<stop offset="1" style="stop-color:#C2C7C9"/>
</linearGradient>
<path id="shape1_1_" fill="url(#shape1_2_)" d="M4.88,27.31H42.69v3.523L23.785,37L4,30.834V27.31H4.88z"/>
<linearGradient id="shape2_2_" gradientUnits="userSpaceOnUse" x1="2515.2495" y1="377.179" x2="2515.0549" y2="377.179" gradientTransform="matrix(33.5 0 0 -136.2 -84233.7969 51386.7539)">
<stop offset="0" style="stop-color:#BAC0C1"/>
<stop offset="0.15" style="stop-color:#F4FAFC"/>
<stop offset="0.25" style="stop-color:#F8FCFD"/>
<stop offset="0.44" style="stop-color:#D5DBDD"/>
<stop offset="0.6" style="stop-color:#BDC3C4"/>
<stop offset="0.8" style="stop-color:#A0A4A6"/>
<stop offset="0.97" style="stop-color:#929697"/>
<stop offset="1" style="stop-color:#C2C7C9"/>
</linearGradient>
<path id="shape2_1_" fill="url(#shape2_2_)" d="M20.262,1.762h6.166V28.19h-6.166V1.762z"/>
<linearGradient id="shape3_2_" gradientUnits="userSpaceOnUse" x1="2511.0767" y1="372.5573" x2="2510.8806" y2="372.5573" gradientTransform="matrix(44.6 0 0 -51 -111966.2969 19005.2656)">
<stop offset="0" style="stop-color:#ACBABD"/>
<stop offset="0.15" style="stop-color:#E3F3F7"/>
<stop offset="0.25" style="stop-color:#EFF8FB"/>
<stop offset="0.44" style="stop-color:#C5D4D8"/>
<stop offset="0.6" style="stop-color:#AFBDC0"/>
<stop offset="0.8" style="stop-color:#939FA2"/>
<stop offset="0.97" style="stop-color:#879194"/>
<stop offset="1" style="stop-color:#B3C1C5"/>
</linearGradient>
<path id="shape3_1_" fill="url(#shape3_2_)" d="M18.94,0h8.809v9.691H18.94V0z"/>
<linearGradient id="shape4_2_" gradientUnits="userSpaceOnUse" x1="2511.0767" y1="373.4229" x2="2510.8806" y2="373.4229" gradientTransform="matrix(44.6 0 0 -40.6 -111966.2969 15191.3604)">
<stop offset="0" style="stop-color:#9D9D9D"/>
<stop offset="0.15" style="stop-color:#D0D1D1"/>
<stop offset="0.25" style="stop-color:#E5E6E6"/>
<stop offset="0.44" style="stop-color:#B3B4B4"/>
<stop offset="0.6" style="stop-color:#9FA0A0"/>
<stop offset="0.8" style="stop-color:#868787"/>
<stop offset="0.97" style="stop-color:#7A7B7B"/>
<stop offset="1" style="stop-color:#A3A4A4"/>
</linearGradient>
<path id="shape4_1_" fill="url(#shape4_2_)" d="M18.94,26.428h8.809v7.928H18.94V26.428z"/>
<linearGradient id="shape5_2_" gradientUnits="userSpaceOnUse" x1="2511.0767" y1="355.048" x2="2510.8806" y2="355.048" gradientTransform="matrix(44.6 0 0 -12.9 -111966.2969 4593.7754)">
<stop offset="0" style="stop-color:#ACBABD"/>
<stop offset="0.15" style="stop-color:#E3F3F7"/>
<stop offset="0.25" style="stop-color:#EFF8FB"/>
<stop offset="0.44" style="stop-color:#C5D4D8"/>
<stop offset="0.6" style="stop-color:#AFBDC0"/>
<stop offset="0.8" style="stop-color:#939FA2"/>
<stop offset="0.97" style="stop-color:#879194"/>
<stop offset="1" style="stop-color:#B3C1C5"/>
</linearGradient>
<path id="shape5_1_" fill="url(#shape5_2_)" d="M18.94,12.334h8.809v2.643H18.94V12.334z"/>
<linearGradient id="shape6_2_" gradientUnits="userSpaceOnUse" x1="2525.8188" y1="374.3631" x2="2525.6233" y2="374.3631" gradientTransform="matrix(20.5 0 0 -47.3 -51754.3516 17739.0898)">
<stop offset="0" style="stop-color:#BAC0C1"/>
<stop offset="0.15" style="stop-color:#F4FAFC"/>
<stop offset="0.25" style="stop-color:#F8FCFD"/>
<stop offset="0.44" style="stop-color:#D5DBDD"/>
<stop offset="0.6" style="stop-color:#BDC3C4"/>
<stop offset="0.8" style="stop-color:#A0A4A6"/>
<stop offset="0.97" style="stop-color:#929697"/>
<stop offset="1" style="stop-color:#C2C7C9"/>
</linearGradient>
<path id="shape6_1_" fill="url(#shape6_2_)" d="M21.142,27.31h4.405v8.809h-4.405V27.31z"/>
</svg>
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 24.1.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="46.69px" height="37px" viewBox="0 0 46.69 37" enable-background="new 0 0 46.69 37" xml:space="preserve">
<linearGradient id="shape1_2_" gradientUnits="userSpaceOnUse" x1="3184.6133" y1="105.523" x2="3168.4338" y2="124.643" gradientTransform="matrix(1 0 0 -1 -3152.22 145.2878)">
<stop offset="0" style="stop-color:#BAC0C1"/>
<stop offset="0.15" style="stop-color:#F4FAFC"/>
<stop offset="0.25" style="stop-color:#F8FCFD"/>
<stop offset="0.44" style="stop-color:#D5DBDD"/>
<stop offset="0.6" style="stop-color:#BDC3C4"/>
<stop offset="0.8" style="stop-color:#A0A4A6"/>
<stop offset="0.97" style="stop-color:#929697"/>
<stop offset="1" style="stop-color:#C2C7C9"/>
</linearGradient>
<path id="shape1_1_" fill="url(#shape1_2_)" d="M8.88,27.31H38.69v3.523L23.785,37L8,30.834V27.31H8.88z"/>
<linearGradient id="shape2_2_" gradientUnits="userSpaceOnUse" x1="2515.2495" y1="377.179" x2="2515.0549" y2="377.179" gradientTransform="matrix(33.5 0 0 -136.2 -84233.7969 51386.7539)">
<stop offset="0" style="stop-color:#BAC0C1"/>
<stop offset="0.15" style="stop-color:#F4FAFC"/>
<stop offset="0.25" style="stop-color:#F8FCFD"/>
<stop offset="0.44" style="stop-color:#D5DBDD"/>
<stop offset="0.6" style="stop-color:#BDC3C4"/>
<stop offset="0.8" style="stop-color:#A0A4A6"/>
<stop offset="0.97" style="stop-color:#929697"/>
<stop offset="1" style="stop-color:#C2C7C9"/>
</linearGradient>
<path id="shape2_1_" fill="url(#shape2_2_)" d="M20.262,1.762h6.166V28.19h-6.166V1.762z"/>
<linearGradient id="shape3_2_" gradientUnits="userSpaceOnUse" x1="2511.0767" y1="372.5573" x2="2510.8806" y2="372.5573" gradientTransform="matrix(44.6 0 0 -51 -111966.2969 19005.2656)">
<stop offset="0" style="stop-color:#ACBABD"/>
<stop offset="0.15" style="stop-color:#E3F3F7"/>
<stop offset="0.25" style="stop-color:#EFF8FB"/>
<stop offset="0.44" style="stop-color:#C5D4D8"/>
<stop offset="0.6" style="stop-color:#AFBDC0"/>
<stop offset="0.8" style="stop-color:#939FA2"/>
<stop offset="0.97" style="stop-color:#879194"/>
<stop offset="1" style="stop-color:#B3C1C5"/>
</linearGradient>
<path id="shape3_1_" fill="url(#shape3_2_)" d="M18.94,0h8.809v9.691H18.94V0z"/>
<linearGradient id="shape4_2_" gradientUnits="userSpaceOnUse" x1="2511.0767" y1="373.4229" x2="2510.8806" y2="373.4229" gradientTransform="matrix(44.6 0 0 -40.6 -111966.2969 15191.3604)">
<stop offset="0" style="stop-color:#9D9D9D"/>
<stop offset="0.15" style="stop-color:#D0D1D1"/>
<stop offset="0.25" style="stop-color:#E5E6E6"/>
<stop offset="0.44" style="stop-color:#B3B4B4"/>
<stop offset="0.6" style="stop-color:#9FA0A0"/>
<stop offset="0.8" style="stop-color:#868787"/>
<stop offset="0.97" style="stop-color:#7A7B7B"/>
<stop offset="1" style="stop-color:#A3A4A4"/>
</linearGradient>
<path id="shape4_1_" fill="url(#shape4_2_)" d="M18.94,26.428h8.809v7.928H18.94V26.428z"/>
<linearGradient id="shape5_2_" gradientUnits="userSpaceOnUse" x1="2511.0767" y1="355.048" x2="2510.8806" y2="355.048" gradientTransform="matrix(44.6 0 0 -12.9 -111966.2969 4593.7754)">
<stop offset="0" style="stop-color:#ACBABD"/>
<stop offset="0.15" style="stop-color:#E3F3F7"/>
<stop offset="0.25" style="stop-color:#EFF8FB"/>
<stop offset="0.44" style="stop-color:#C5D4D8"/>
<stop offset="0.6" style="stop-color:#AFBDC0"/>
<stop offset="0.8" style="stop-color:#939FA2"/>
<stop offset="0.97" style="stop-color:#879194"/>
<stop offset="1" style="stop-color:#B3C1C5"/>
</linearGradient>
<path id="shape5_1_" fill="url(#shape5_2_)" d="M18.94,12.334h8.809v2.643H18.94V12.334z"/>
<linearGradient id="shape6_2_" gradientUnits="userSpaceOnUse" x1="2525.8188" y1="374.3631" x2="2525.6233" y2="374.3631" gradientTransform="matrix(20.5 0 0 -47.3 -51754.3516 17739.0898)">
<stop offset="0" style="stop-color:#BAC0C1"/>
<stop offset="0.15" style="stop-color:#F4FAFC"/>
<stop offset="0.25" style="stop-color:#F8FCFD"/>
<stop offset="0.44" style="stop-color:#D5DBDD"/>
<stop offset="0.6" style="stop-color:#BDC3C4"/>
<stop offset="0.8" style="stop-color:#A0A4A6"/>
<stop offset="0.97" style="stop-color:#929697"/>
<stop offset="1" style="stop-color:#C2C7C9"/>
</linearGradient>
<path id="shape6_1_" fill="url(#shape6_2_)" d="M21.142,27.31h4.405v8.809h-4.405V27.31z"/>
</svg>
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 24.1.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="46.69px" height="37px" viewBox="0 0 46.69 37" enable-background="new 0 0 46.69 37" xml:space="preserve">
<linearGradient id="shape1_2_" gradientUnits="userSpaceOnUse" x1="3182.5364" y1="107.9773" x2="3170.0706" y2="122.7087" gradientTransform="matrix(1 0 0 -1 -3152.22 145.2878)">
<stop offset="0" style="stop-color:#BAC0C1"/>
<stop offset="0.15" style="stop-color:#F4FAFC"/>
<stop offset="0.25" style="stop-color:#F8FCFD"/>
<stop offset="0.44" style="stop-color:#D5DBDD"/>
<stop offset="0.6" style="stop-color:#BDC3C4"/>
<stop offset="0.8" style="stop-color:#A0A4A6"/>
<stop offset="0.97" style="stop-color:#929697"/>
<stop offset="1" style="stop-color:#C2C7C9"/>
</linearGradient>
<path id="shape1_1_" fill="url(#shape1_2_)" d="M12.88,27.31H34.69v3.523L23.785,37L12,30.834V27.31H12.88z"/>
<linearGradient id="shape2_2_" gradientUnits="userSpaceOnUse" x1="2515.2495" y1="377.179" x2="2515.0549" y2="377.179" gradientTransform="matrix(33.5 0 0 -136.2 -84233.7969 51386.7539)">
<stop offset="0" style="stop-color:#BAC0C1"/>
<stop offset="0.15" style="stop-color:#F4FAFC"/>
<stop offset="0.25" style="stop-color:#F8FCFD"/>
<stop offset="0.44" style="stop-color:#D5DBDD"/>
<stop offset="0.6" style="stop-color:#BDC3C4"/>
<stop offset="0.8" style="stop-color:#A0A4A6"/>
<stop offset="0.97" style="stop-color:#929697"/>
<stop offset="1" style="stop-color:#C2C7C9"/>
</linearGradient>
<path id="shape2_1_" fill="url(#shape2_2_)" d="M20.262,1.762h6.166V28.19h-6.166V1.762z"/>
<linearGradient id="shape3_2_" gradientUnits="userSpaceOnUse" x1="2511.0767" y1="372.5573" x2="2510.8806" y2="372.5573" gradientTransform="matrix(44.6 0 0 -51 -111966.2969 19005.2656)">
<stop offset="0" style="stop-color:#ACBABD"/>
<stop offset="0.15" style="stop-color:#E3F3F7"/>
<stop offset="0.25" style="stop-color:#EFF8FB"/>
<stop offset="0.44" style="stop-color:#C5D4D8"/>
<stop offset="0.6" style="stop-color:#AFBDC0"/>
<stop offset="0.8" style="stop-color:#939FA2"/>
<stop offset="0.97" style="stop-color:#879194"/>
<stop offset="1" style="stop-color:#B3C1C5"/>
</linearGradient>
<path id="shape3_1_" fill="url(#shape3_2_)" d="M18.94,0h8.809v9.691H18.94V0z"/>
<linearGradient id="shape4_2_" gradientUnits="userSpaceOnUse" x1="2511.0767" y1="373.4229" x2="2510.8806" y2="373.4229" gradientTransform="matrix(44.6 0 0 -40.6 -111966.2969 15191.3604)">
<stop offset="0" style="stop-color:#9D9D9D"/>
<stop offset="0.15" style="stop-color:#D0D1D1"/>
<stop offset="0.25" style="stop-color:#E5E6E6"/>
<stop offset="0.44" style="stop-color:#B3B4B4"/>
<stop offset="0.6" style="stop-color:#9FA0A0"/>
<stop offset="0.8" style="stop-color:#868787"/>
<stop offset="0.97" style="stop-color:#7A7B7B"/>
<stop offset="1" style="stop-color:#A3A4A4"/>
</linearGradient>
<path id="shape4_1_" fill="url(#shape4_2_)" d="M18.94,26.428h8.809v7.928H18.94V26.428z"/>
<linearGradient id="shape5_2_" gradientUnits="userSpaceOnUse" x1="2511.0767" y1="355.048" x2="2510.8806" y2="355.048" gradientTransform="matrix(44.6 0 0 -12.9 -111966.2969 4593.7754)">
<stop offset="0" style="stop-color:#ACBABD"/>
<stop offset="0.15" style="stop-color:#E3F3F7"/>
<stop offset="0.25" style="stop-color:#EFF8FB"/>
<stop offset="0.44" style="stop-color:#C5D4D8"/>
<stop offset="0.6" style="stop-color:#AFBDC0"/>
<stop offset="0.8" style="stop-color:#939FA2"/>
<stop offset="0.97" style="stop-color:#879194"/>
<stop offset="1" style="stop-color:#B3C1C5"/>
</linearGradient>
<path id="shape5_1_" fill="url(#shape5_2_)" d="M18.94,12.334h8.809v2.643H18.94V12.334z"/>
<linearGradient id="shape6_2_" gradientUnits="userSpaceOnUse" x1="2525.8188" y1="374.3631" x2="2525.6233" y2="374.3631" gradientTransform="matrix(20.5 0 0 -47.3 -51754.3516 17739.0898)">
<stop offset="0" style="stop-color:#BAC0C1"/>
<stop offset="0.15" style="stop-color:#F4FAFC"/>
<stop offset="0.25" style="stop-color:#F8FCFD"/>
<stop offset="0.44" style="stop-color:#D5DBDD"/>
<stop offset="0.6" style="stop-color:#BDC3C4"/>
<stop offset="0.8" style="stop-color:#A0A4A6"/>
<stop offset="0.97" style="stop-color:#929697"/>
<stop offset="1" style="stop-color:#C2C7C9"/>
</linearGradient>
<path id="shape6_1_" fill="url(#shape6_2_)" d="M21.142,27.31h4.405v8.809h-4.405V27.31z"/>
</svg>
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 24.1.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="46.69px" height="37px" viewBox="0 0 46.69 37" enable-background="new 0 0 46.69 37" xml:space="preserve">
<linearGradient id="shape2_2_" gradientUnits="userSpaceOnUse" x1="2515.2495" y1="377.179" x2="2515.0549" y2="377.179" gradientTransform="matrix(33.5 0 0 -136.2 -84233.7969 51386.7539)">
<stop offset="0" style="stop-color:#BAC0C1"/>
<stop offset="0.15" style="stop-color:#F4FAFC"/>
<stop offset="0.25" style="stop-color:#F8FCFD"/>
<stop offset="0.44" style="stop-color:#D5DBDD"/>
<stop offset="0.6" style="stop-color:#BDC3C4"/>
<stop offset="0.8" style="stop-color:#A0A4A6"/>
<stop offset="0.97" style="stop-color:#929697"/>
<stop offset="1" style="stop-color:#C2C7C9"/>
</linearGradient>
<path id="shape2_1_" fill="url(#shape2_2_)" d="M20.262,1.762h6.166V28.19h-6.166V1.762z"/>
<linearGradient id="shape3_2_" gradientUnits="userSpaceOnUse" x1="2511.0767" y1="372.5573" x2="2510.8806" y2="372.5573" gradientTransform="matrix(44.6 0 0 -51 -111966.2969 19005.2656)">
<stop offset="0" style="stop-color:#ACBABD"/>
<stop offset="0.15" style="stop-color:#E3F3F7"/>
<stop offset="0.25" style="stop-color:#EFF8FB"/>
<stop offset="0.44" style="stop-color:#C5D4D8"/>
<stop offset="0.6" style="stop-color:#AFBDC0"/>
<stop offset="0.8" style="stop-color:#939FA2"/>
<stop offset="0.97" style="stop-color:#879194"/>
<stop offset="1" style="stop-color:#B3C1C5"/>
</linearGradient>
<path id="shape3_1_" fill="url(#shape3_2_)" d="M18.94,0h8.809v9.691H18.94V0z"/>
<linearGradient id="shape4_2_" gradientUnits="userSpaceOnUse" x1="2511.0767" y1="373.4229" x2="2510.8806" y2="373.4229" gradientTransform="matrix(44.6 0 0 -40.6 -111966.2969 15191.3604)">
<stop offset="0" style="stop-color:#9D9D9D"/>
<stop offset="0.15" style="stop-color:#D0D1D1"/>
<stop offset="0.25" style="stop-color:#E5E6E6"/>
<stop offset="0.44" style="stop-color:#B3B4B4"/>
<stop offset="0.6" style="stop-color:#9FA0A0"/>
<stop offset="0.8" style="stop-color:#868787"/>
<stop offset="0.97" style="stop-color:#7A7B7B"/>
<stop offset="1" style="stop-color:#A3A4A4"/>
</linearGradient>
<path id="shape4_1_" fill="url(#shape4_2_)" d="M18.94,26.428h8.809v7.928H18.94V26.428z"/>
<linearGradient id="shape5_2_" gradientUnits="userSpaceOnUse" x1="2511.0767" y1="355.048" x2="2510.8806" y2="355.048" gradientTransform="matrix(44.6 0 0 -12.9 -111966.2969 4593.7754)">
<stop offset="0" style="stop-color:#ACBABD"/>
<stop offset="0.15" style="stop-color:#E3F3F7"/>
<stop offset="0.25" style="stop-color:#EFF8FB"/>
<stop offset="0.44" style="stop-color:#C5D4D8"/>
<stop offset="0.6" style="stop-color:#AFBDC0"/>
<stop offset="0.8" style="stop-color:#939FA2"/>
<stop offset="0.97" style="stop-color:#879194"/>
<stop offset="1" style="stop-color:#B3C1C5"/>
</linearGradient>
<path id="shape5_1_" fill="url(#shape5_2_)" d="M18.94,12.334h8.809v2.643H18.94V12.334z"/>
<linearGradient id="shape6_2_" gradientUnits="userSpaceOnUse" x1="2525.8188" y1="374.3631" x2="2525.6233" y2="374.3631" gradientTransform="matrix(20.5 0 0 -47.3 -51754.3516 17739.0898)">
<stop offset="0" style="stop-color:#BAC0C1"/>
<stop offset="0.15" style="stop-color:#F4FAFC"/>
<stop offset="0.25" style="stop-color:#F8FCFD"/>
<stop offset="0.44" style="stop-color:#D5DBDD"/>
<stop offset="0.6" style="stop-color:#BDC3C4"/>
<stop offset="0.8" style="stop-color:#A0A4A6"/>
<stop offset="0.97" style="stop-color:#929697"/>
<stop offset="1" style="stop-color:#C2C7C9"/>
</linearGradient>
<path id="shape6_1_" fill="url(#shape6_2_)" d="M21.142,27.31h4.405v8.809h-4.405V27.31z"/>
</svg>
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 24.1.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="42.526px" height="56px" viewBox="0 0 42.526 56" enable-background="new 0 0 42.526 56" xml:space="preserve">
<linearGradient id="shape1_3_" gradientUnits="userSpaceOnUse" x1="3185.3777" y1="162.5258" x2="3164.1086" y2="187.6605" gradientTransform="matrix(1 0 0 -1 -3152.22 208.532)">
<stop offset="0" style="stop-color:#BAC0C1"/>
<stop offset="0.15" style="stop-color:#F4FAFC"/>
<stop offset="0.25" style="stop-color:#F8FCFD"/>
<stop offset="0.44" style="stop-color:#D5DBDD"/>
<stop offset="0.6" style="stop-color:#BDC3C4"/>
<stop offset="0.8" style="stop-color:#A0A4A6"/>
<stop offset="0.97" style="stop-color:#929697"/>
<stop offset="1" style="stop-color:#C2C7C9"/>
</linearGradient>
<path id="shape1_2_" fill="url(#shape1_3_)" d="M0.802,30.557h41.724v2.785l-20.862,4.875L0,33.342v-2.785H0.802z"/>
<linearGradient id="shape1_4_" gradientUnits="userSpaceOnUse" x1="3185.3777" y1="145.1064" x2="3164.1086" y2="170.241" gradientTransform="matrix(1 0 0 -1 -3152.22 208.532)">
<stop offset="0" style="stop-color:#BAC0C1"/>
<stop offset="0.15" style="stop-color:#F4FAFC"/>
<stop offset="0.25" style="stop-color:#F8FCFD"/>
<stop offset="0.44" style="stop-color:#D5DBDD"/>
<stop offset="0.6" style="stop-color:#BDC3C4"/>
<stop offset="0.8" style="stop-color:#A0A4A6"/>
<stop offset="0.97" style="stop-color:#929697"/>
<stop offset="1" style="stop-color:#C2C7C9"/>
</linearGradient>
<path id="shape1_1_" fill="url(#shape1_4_)" d="M0.802,47.976h41.724v2.785l-20.862,4.875L0,50.762v-2.785H0.802z"/>
<linearGradient id="shape2_2_" gradientUnits="userSpaceOnUse" x1="2613.1711" y1="408.9612" x2="2612.9939" y2="408.9612" gradientTransform="matrix(33.5 0 0 -136.2 -87516.5859 55725.3047)">
<stop offset="0" style="stop-color:#BAC0C1"/>
<stop offset="0.15" style="stop-color:#F4FAFC"/>
<stop offset="0.25" style="stop-color:#F8FCFD"/>
<stop offset="0.44" style="stop-color:#D5DBDD"/>
<stop offset="0.6" style="stop-color:#BDC3C4"/>
<stop offset="0.8" style="stop-color:#A0A4A6"/>
<stop offset="0.97" style="stop-color:#929697"/>
<stop offset="1" style="stop-color:#C2C7C9"/>
</linearGradient>
<path id="shape2_1_" fill="url(#shape2_2_)" d="M18.455,1.605h5.616v46.372h-5.616V1.605z"/>
<linearGradient id="shape3_2_" gradientUnits="userSpaceOnUse" x1="2609.7654" y1="404.8079" x2="2609.5869" y2="404.8079" gradientTransform="matrix(44.6 0 0 -51 -116370.2891 20649.6133)">
<stop offset="0" style="stop-color:#ACBABD"/>
<stop offset="0.15" style="stop-color:#E3F3F7"/>
<stop offset="0.25" style="stop-color:#EFF8FB"/>
<stop offset="0.44" style="stop-color:#C5D4D8"/>
<stop offset="0.6" style="stop-color:#AFBDC0"/>
<stop offset="0.8" style="stop-color:#939FA2"/>
<stop offset="0.97" style="stop-color:#879194"/>
<stop offset="1" style="stop-color:#B3C1C5"/>
</linearGradient>
<path id="shape3_1_" fill="url(#shape3_2_)" d="M17.251,0h8.024v8.827h-8.024V0z"/>
<linearGradient id="shape4_2_" gradientUnits="userSpaceOnUse" x1="2609.7654" y1="405.3216" x2="2609.5869" y2="405.3216" gradientTransform="matrix(44.6 0 0 -40.6 -116370.2891 16506.8398)">
<stop offset="0" style="stop-color:#9D9D9D"/>
<stop offset="0.15" style="stop-color:#D0D1D1"/>
<stop offset="0.25" style="stop-color:#E5E6E6"/>
<stop offset="0.44" style="stop-color:#B3B4B4"/>
<stop offset="0.6" style="stop-color:#9FA0A0"/>
<stop offset="0.8" style="stop-color:#868787"/>
<stop offset="0.97" style="stop-color:#7A7B7B"/>
<stop offset="1" style="stop-color:#A3A4A4"/>
</linearGradient>
<path id="shape4_1_" fill="url(#shape4_2_)" d="M17.251,47.173h8.024v7.221h-8.024V47.173z"/>
<linearGradient id="shape5_2_" gradientUnits="userSpaceOnUse" x1="2609.7654" y1="389.2159" x2="2609.5869" y2="389.2159" gradientTransform="matrix(44.6 0 0 -12.9 -116370.2891 5033.3228)">
<stop offset="0" style="stop-color:#ACBABD"/>
<stop offset="0.15" style="stop-color:#E3F3F7"/>
<stop offset="0.25" style="stop-color:#EFF8FB"/>
<stop offset="0.44" style="stop-color:#C5D4D8"/>
<stop offset="0.6" style="stop-color:#AFBDC0"/>
<stop offset="0.8" style="stop-color:#939FA2"/>
<stop offset="0.97" style="stop-color:#879194"/>
<stop offset="1" style="stop-color:#B3C1C5"/>
</linearGradient>
<path id="shape5_1_" fill="url(#shape5_2_)" d="M17.251,11.234h8.024v2.407h-8.024V11.234z"/>
<linearGradient id="shape6_2_" gradientUnits="userSpaceOnUse" x1="2621.7922" y1="406.2251" x2="2621.614" y2="406.2251" gradientTransform="matrix(20.5 0 0 -47.3 -53724.0273 19266.4355)">
<stop offset="0" style="stop-color:#BAC0C1"/>
<stop offset="0.15" style="stop-color:#F4FAFC"/>
<stop offset="0.25" style="stop-color:#F8FCFD"/>
<stop offset="0.44" style="stop-color:#D5DBDD"/>
<stop offset="0.6" style="stop-color:#BDC3C4"/>
<stop offset="0.8" style="stop-color:#A0A4A6"/>
<stop offset="0.97" style="stop-color:#929697"/>
<stop offset="1" style="stop-color:#C2C7C9"/>
</linearGradient>
<path id="shape6_1_" fill="url(#shape6_2_)" d="M19.257,47.976h4.012V56h-4.012V47.976z"/>
</svg>
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 24.1.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="42.526px" height="56px" viewBox="0 0 42.526 56" enable-background="new 0 0 42.526 56" xml:space="preserve">
<linearGradient id="shape1_3_" gradientUnits="userSpaceOnUse" x1="3183.3008" y1="164.9802" x2="3165.7454" y2="185.7262" gradientTransform="matrix(1 0 0 -1 -3152.22 208.532)">
<stop offset="0" style="stop-color:#BAC0C1"/>
<stop offset="0.15" style="stop-color:#F4FAFC"/>
<stop offset="0.25" style="stop-color:#F8FCFD"/>
<stop offset="0.44" style="stop-color:#D5DBDD"/>
<stop offset="0.6" style="stop-color:#BDC3C4"/>
<stop offset="0.8" style="stop-color:#A0A4A6"/>
<stop offset="0.97" style="stop-color:#929697"/>
<stop offset="1" style="stop-color:#C2C7C9"/>
</linearGradient>
<path id="shape1_2_" fill="url(#shape1_3_)" d="M4.802,30.557h33.724v2.785l-16.862,4.875L4,33.342v-2.785H4.802z"/>
<linearGradient id="shape1_4_" gradientUnits="userSpaceOnUse" x1="3183.3008" y1="147.5607" x2="3165.7454" y2="168.3067" gradientTransform="matrix(1 0 0 -1 -3152.22 208.532)">
<stop offset="0" style="stop-color:#BAC0C1"/>
<stop offset="0.15" style="stop-color:#F4FAFC"/>
<stop offset="0.25" style="stop-color:#F8FCFD"/>
<stop offset="0.44" style="stop-color:#D5DBDD"/>
<stop offset="0.6" style="stop-color:#BDC3C4"/>
<stop offset="0.8" style="stop-color:#A0A4A6"/>
<stop offset="0.97" style="stop-color:#929697"/>
<stop offset="1" style="stop-color:#C2C7C9"/>
</linearGradient>
<path id="shape1_1_" fill="url(#shape1_4_)" d="M4.802,47.976h33.724v2.785l-16.862,4.875L4,50.762v-2.785H4.802z"/>
<linearGradient id="shape2_2_" gradientUnits="userSpaceOnUse" x1="2613.1711" y1="408.9612" x2="2612.9939" y2="408.9612" gradientTransform="matrix(33.5 0 0 -136.2 -87516.5859 55725.3047)">
<stop offset="0" style="stop-color:#BAC0C1"/>
<stop offset="0.15" style="stop-color:#F4FAFC"/>
<stop offset="0.25" style="stop-color:#F8FCFD"/>
<stop offset="0.44" style="stop-color:#D5DBDD"/>
<stop offset="0.6" style="stop-color:#BDC3C4"/>
<stop offset="0.8" style="stop-color:#A0A4A6"/>
<stop offset="0.97" style="stop-color:#929697"/>
<stop offset="1" style="stop-color:#C2C7C9"/>
</linearGradient>
<path id="shape2_1_" fill="url(#shape2_2_)" d="M18.455,1.605h5.616v46.372h-5.616V1.605z"/>
<linearGradient id="shape3_2_" gradientUnits="userSpaceOnUse" x1="2609.7654" y1="404.8079" x2="2609.5869" y2="404.8079" gradientTransform="matrix(44.6 0 0 -51 -116370.2891 20649.6133)">
<stop offset="0" style="stop-color:#ACBABD"/>
<stop offset="0.15" style="stop-color:#E3F3F7"/>
<stop offset="0.25" style="stop-color:#EFF8FB"/>
<stop offset="0.44" style="stop-color:#C5D4D8"/>
<stop offset="0.6" style="stop-color:#AFBDC0"/>
<stop offset="0.8" style="stop-color:#939FA2"/>
<stop offset="0.97" style="stop-color:#879194"/>
<stop offset="1" style="stop-color:#B3C1C5"/>
</linearGradient>
<path id="shape3_1_" fill="url(#shape3_2_)" d="M17.251,0h8.024v8.827h-8.024V0z"/>
<linearGradient id="shape4_2_" gradientUnits="userSpaceOnUse" x1="2609.7654" y1="405.3216" x2="2609.5869" y2="405.3216" gradientTransform="matrix(44.6 0 0 -40.6 -116370.2891 16506.8398)">
<stop offset="0" style="stop-color:#9D9D9D"/>
<stop offset="0.15" style="stop-color:#D0D1D1"/>
<stop offset="0.25" style="stop-color:#E5E6E6"/>
<stop offset="0.44" style="stop-color:#B3B4B4"/>
<stop offset="0.6" style="stop-color:#9FA0A0"/>
<stop offset="0.8" style="stop-color:#868787"/>
<stop offset="0.97" style="stop-color:#7A7B7B"/>
<stop offset="1" style="stop-color:#A3A4A4"/>
</linearGradient>
<path id="shape4_1_" fill="url(#shape4_2_)" d="M17.251,47.173h8.024v7.221h-8.024V47.173z"/>
<linearGradient id="shape5_2_" gradientUnits="userSpaceOnUse" x1="2609.7654" y1="389.2159" x2="2609.5869" y2="389.2159" gradientTransform="matrix(44.6 0 0 -12.9 -116370.2891 5033.3228)">
<stop offset="0" style="stop-color:#ACBABD"/>
<stop offset="0.15" style="stop-color:#E3F3F7"/>
<stop offset="0.25" style="stop-color:#EFF8FB"/>
<stop offset="0.44" style="stop-color:#C5D4D8"/>
<stop offset="0.6" style="stop-color:#AFBDC0"/>
<stop offset="0.8" style="stop-color:#939FA2"/>
<stop offset="0.97" style="stop-color:#879194"/>
<stop offset="1" style="stop-color:#B3C1C5"/>
</linearGradient>
<path id="shape5_1_" fill="url(#shape5_2_)" d="M17.251,11.234h8.024v2.407h-8.024V11.234z"/>
<linearGradient id="shape6_2_" gradientUnits="userSpaceOnUse" x1="2621.7922" y1="406.2251" x2="2621.614" y2="406.2251" gradientTransform="matrix(20.5 0 0 -47.3 -53724.0273 19266.4355)">
<stop offset="0" style="stop-color:#BAC0C1"/>
<stop offset="0.15" style="stop-color:#F4FAFC"/>
<stop offset="0.25" style="stop-color:#F8FCFD"/>
<stop offset="0.44" style="stop-color:#D5DBDD"/>
<stop offset="0.6" style="stop-color:#BDC3C4"/>
<stop offset="0.8" style="stop-color:#A0A4A6"/>
<stop offset="0.97" style="stop-color:#929697"/>
<stop offset="1" style="stop-color:#C2C7C9"/>
</linearGradient>
<path id="shape6_1_" fill="url(#shape6_2_)" d="M19.257,47.976h4.012V56h-4.012V47.976z"/>
</svg>
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 24.1.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="42.526px" height="56px" viewBox="0 0 42.526 56" enable-background="new 0 0 42.526 56" xml:space="preserve">
<linearGradient id="shape1_3_" gradientUnits="userSpaceOnUse" x1="3181.2239" y1="167.4346" x2="3167.3823" y2="183.7919" gradientTransform="matrix(1 0 0 -1 -3152.22 208.532)">
<stop offset="0" style="stop-color:#BAC0C1"/>
<stop offset="0.15" style="stop-color:#F4FAFC"/>
<stop offset="0.25" style="stop-color:#F8FCFD"/>
<stop offset="0.44" style="stop-color:#D5DBDD"/>
<stop offset="0.6" style="stop-color:#BDC3C4"/>
<stop offset="0.8" style="stop-color:#A0A4A6"/>
<stop offset="0.97" style="stop-color:#929697"/>
<stop offset="1" style="stop-color:#C2C7C9"/>
</linearGradient>
<path id="shape1_2_" fill="url(#shape1_3_)" d="M8.802,30.557h25.724v2.785l-12.862,4.875L8,33.342v-2.785H8.802z"/>
<linearGradient id="shape1_4_" gradientUnits="userSpaceOnUse" x1="3181.2239" y1="150.0151" x2="3167.3823" y2="166.3725" gradientTransform="matrix(1 0 0 -1 -3152.22 208.532)">
<stop offset="0" style="stop-color:#BAC0C1"/>
<stop offset="0.15" style="stop-color:#F4FAFC"/>
<stop offset="0.25" style="stop-color:#F8FCFD"/>
<stop offset="0.44" style="stop-color:#D5DBDD"/>
<stop offset="0.6" style="stop-color:#BDC3C4"/>
<stop offset="0.8" style="stop-color:#A0A4A6"/>
<stop offset="0.97" style="stop-color:#929697"/>
<stop offset="1" style="stop-color:#C2C7C9"/>
</linearGradient>
<path id="shape1_1_" fill="url(#shape1_4_)" d="M8.802,47.976h25.724v2.785l-12.862,4.875L8,50.762v-2.785H8.802z"/>
<linearGradient id="shape2_2_" gradientUnits="userSpaceOnUse" x1="2613.1711" y1="408.9612" x2="2612.9939" y2="408.9612" gradientTransform="matrix(33.5 0 0 -136.2 -87516.5859 55725.3047)">
<stop offset="0" style="stop-color:#BAC0C1"/>
<stop offset="0.15" style="stop-color:#F4FAFC"/>
<stop offset="0.25" style="stop-color:#F8FCFD"/>
<stop offset="0.44" style="stop-color:#D5DBDD"/>
<stop offset="0.6" style="stop-color:#BDC3C4"/>
<stop offset="0.8" style="stop-color:#A0A4A6"/>
<stop offset="0.97" style="stop-color:#929697"/>
<stop offset="1" style="stop-color:#C2C7C9"/>
</linearGradient>
<path id="shape2_1_" fill="url(#shape2_2_)" d="M18.455,1.605h5.616v46.372h-5.616V1.605z"/>
<linearGradient id="shape3_2_" gradientUnits="userSpaceOnUse" x1="2609.7654" y1="404.8079" x2="2609.5869" y2="404.8079" gradientTransform="matrix(44.6 0 0 -51 -116370.2891 20649.6133)">
<stop offset="0" style="stop-color:#ACBABD"/>
<stop offset="0.15" style="stop-color:#E3F3F7"/>
<stop offset="0.25" style="stop-color:#EFF8FB"/>
<stop offset="0.44" style="stop-color:#C5D4D8"/>
<stop offset="0.6" style="stop-color:#AFBDC0"/>
<stop offset="0.8" style="stop-color:#939FA2"/>
<stop offset="0.97" style="stop-color:#879194"/>
<stop offset="1" style="stop-color:#B3C1C5"/>
</linearGradient>
<path id="shape3_1_" fill="url(#shape3_2_)" d="M17.251,0h8.024v8.827h-8.024V0z"/>
<linearGradient id="shape4_2_" gradientUnits="userSpaceOnUse" x1="2609.7654" y1="405.3216" x2="2609.5869" y2="405.3216" gradientTransform="matrix(44.6 0 0 -40.6 -116370.2891 16506.8398)">
<stop offset="0" style="stop-color:#9D9D9D"/>
<stop offset="0.15" style="stop-color:#D0D1D1"/>
<stop offset="0.25" style="stop-color:#E5E6E6"/>
<stop offset="0.44" style="stop-color:#B3B4B4"/>
<stop offset="0.6" style="stop-color:#9FA0A0"/>
<stop offset="0.8" style="stop-color:#868787"/>
<stop offset="0.97" style="stop-color:#7A7B7B"/>
<stop offset="1" style="stop-color:#A3A4A4"/>
</linearGradient>
<path id="shape4_1_" fill="url(#shape4_2_)" d="M17.251,47.173h8.024v7.221h-8.024V47.173z"/>
<linearGradient id="shape5_2_" gradientUnits="userSpaceOnUse" x1="2609.7654" y1="389.2159" x2="2609.5869" y2="389.2159" gradientTransform="matrix(44.6 0 0 -12.9 -116370.2891 5033.3228)">
<stop offset="0" style="stop-color:#ACBABD"/>
<stop offset="0.15" style="stop-color:#E3F3F7"/>
<stop offset="0.25" style="stop-color:#EFF8FB"/>
<stop offset="0.44" style="stop-color:#C5D4D8"/>
<stop offset="0.6" style="stop-color:#AFBDC0"/>
<stop offset="0.8" style="stop-color:#939FA2"/>
<stop offset="0.97" style="stop-color:#879194"/>
<stop offset="1" style="stop-color:#B3C1C5"/>
</linearGradient>
<path id="shape5_1_" fill="url(#shape5_2_)" d="M17.251,11.234h8.024v2.407h-8.024V11.234z"/>
<linearGradient id="shape6_2_" gradientUnits="userSpaceOnUse" x1="2621.7922" y1="406.2251" x2="2621.614" y2="406.2251" gradientTransform="matrix(20.5 0 0 -47.3 -53724.0273 19266.4355)">
<stop offset="0" style="stop-color:#BAC0C1"/>
<stop offset="0.15" style="stop-color:#F4FAFC"/>
<stop offset="0.25" style="stop-color:#F8FCFD"/>
<stop offset="0.44" style="stop-color:#D5DBDD"/>
<stop offset="0.6" style="stop-color:#BDC3C4"/>
<stop offset="0.8" style="stop-color:#A0A4A6"/>
<stop offset="0.97" style="stop-color:#929697"/>
<stop offset="1" style="stop-color:#C2C7C9"/>
</linearGradient>
<path id="shape6_1_" fill="url(#shape6_2_)" d="M19.257,47.976h4.012V56h-4.012V47.976z"/>
</svg>
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 24.1.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="42.526px" height="56px" viewBox="0 0 42.526 56" enable-background="new 0 0 42.526 56" xml:space="preserve">
<linearGradient id="shape1_3_" gradientUnits="userSpaceOnUse" x1="3179.147" y1="169.8889" x2="3169.019" y2="181.8576" gradientTransform="matrix(1 0 0 -1 -3152.22 208.532)">
<stop offset="0" style="stop-color:#BAC0C1"/>
<stop offset="0.15" style="stop-color:#F4FAFC"/>
<stop offset="0.25" style="stop-color:#F8FCFD"/>
<stop offset="0.44" style="stop-color:#D5DBDD"/>
<stop offset="0.6" style="stop-color:#BDC3C4"/>
<stop offset="0.8" style="stop-color:#A0A4A6"/>
<stop offset="0.97" style="stop-color:#929697"/>
<stop offset="1" style="stop-color:#C2C7C9"/>
</linearGradient>
<path id="shape1_2_" fill="url(#shape1_3_)" d="M12.802,30.557h17.724v2.785l-8.862,4.875L12,33.342v-2.785H12.802z"/>
<linearGradient id="shape1_4_" gradientUnits="userSpaceOnUse" x1="3179.147" y1="152.4695" x2="3169.019" y2="164.4382" gradientTransform="matrix(1 0 0 -1 -3152.22 208.532)">
<stop offset="0" style="stop-color:#BAC0C1"/>
<stop offset="0.15" style="stop-color:#F4FAFC"/>
<stop offset="0.25" style="stop-color:#F8FCFD"/>
<stop offset="0.44" style="stop-color:#D5DBDD"/>
<stop offset="0.6" style="stop-color:#BDC3C4"/>
<stop offset="0.8" style="stop-color:#A0A4A6"/>
<stop offset="0.97" style="stop-color:#929697"/>
<stop offset="1" style="stop-color:#C2C7C9"/>
</linearGradient>
<path id="shape1_1_" fill="url(#shape1_4_)" d="M12.802,47.976h17.724v2.785l-8.862,4.875L12,50.762v-2.785H12.802z"/>
<linearGradient id="shape2_2_" gradientUnits="userSpaceOnUse" x1="2613.1711" y1="408.9612" x2="2612.9939" y2="408.9612" gradientTransform="matrix(33.5 0 0 -136.2 -87516.5859 55725.3047)">
<stop offset="0" style="stop-color:#BAC0C1"/>
<stop offset="0.15" style="stop-color:#F4FAFC"/>
<stop offset="0.25" style="stop-color:#F8FCFD"/>
<stop offset="0.44" style="stop-color:#D5DBDD"/>
<stop offset="0.6" style="stop-color:#BDC3C4"/>
<stop offset="0.8" style="stop-color:#A0A4A6"/>
<stop offset="0.97" style="stop-color:#929697"/>
<stop offset="1" style="stop-color:#C2C7C9"/>
</linearGradient>
<path id="shape2_1_" fill="url(#shape2_2_)" d="M18.455,1.605h5.616v46.372h-5.616V1.605z"/>
<linearGradient id="shape3_2_" gradientUnits="userSpaceOnUse" x1="2609.7654" y1="404.8079" x2="2609.5869" y2="404.8079" gradientTransform="matrix(44.6 0 0 -51 -116370.2891 20649.6133)">
<stop offset="0" style="stop-color:#ACBABD"/>
<stop offset="0.15" style="stop-color:#E3F3F7"/>
<stop offset="0.25" style="stop-color:#EFF8FB"/>
<stop offset="0.44" style="stop-color:#C5D4D8"/>
<stop offset="0.6" style="stop-color:#AFBDC0"/>
<stop offset="0.8" style="stop-color:#939FA2"/>
<stop offset="0.97" style="stop-color:#879194"/>
<stop offset="1" style="stop-color:#B3C1C5"/>
</linearGradient>
<path id="shape3_1_" fill="url(#shape3_2_)" d="M17.251,0h8.024v8.827h-8.024V0z"/>
<linearGradient id="shape4_2_" gradientUnits="userSpaceOnUse" x1="2609.7654" y1="405.3216" x2="2609.5869" y2="405.3216" gradientTransform="matrix(44.6 0 0 -40.6 -116370.2891 16506.8398)">
<stop offset="0" style="stop-color:#9D9D9D"/>
<stop offset="0.15" style="stop-color:#D0D1D1"/>
<stop offset="0.25" style="stop-color:#E5E6E6"/>
<stop offset="0.44" style="stop-color:#B3B4B4"/>
<stop offset="0.6" style="stop-color:#9FA0A0"/>
<stop offset="0.8" style="stop-color:#868787"/>
<stop offset="0.97" style="stop-color:#7A7B7B"/>
<stop offset="1" style="stop-color:#A3A4A4"/>
</linearGradient>
<path id="shape4_1_" fill="url(#shape4_2_)" d="M17.251,47.173h8.024v7.221h-8.024V47.173z"/>
<linearGradient id="shape5_2_" gradientUnits="userSpaceOnUse" x1="2609.7654" y1="389.2159" x2="2609.5869" y2="389.2159" gradientTransform="matrix(44.6 0 0 -12.9 -116370.2891 5033.3228)">
<stop offset="0" style="stop-color:#ACBABD"/>
<stop offset="0.15" style="stop-color:#E3F3F7"/>
<stop offset="0.25" style="stop-color:#EFF8FB"/>
<stop offset="0.44" style="stop-color:#C5D4D8"/>
<stop offset="0.6" style="stop-color:#AFBDC0"/>
<stop offset="0.8" style="stop-color:#939FA2"/>
<stop offset="0.97" style="stop-color:#879194"/>
<stop offset="1" style="stop-color:#B3C1C5"/>
</linearGradient>
<path id="shape5_1_" fill="url(#shape5_2_)" d="M17.251,11.234h8.024v2.407h-8.024V11.234z"/>
<linearGradient id="shape6_2_" gradientUnits="userSpaceOnUse" x1="2621.7922" y1="406.2251" x2="2621.614" y2="406.2251" gradientTransform="matrix(20.5 0 0 -47.3 -53724.0273 19266.4355)">
<stop offset="0" style="stop-color:#BAC0C1"/>
<stop offset="0.15" style="stop-color:#F4FAFC"/>
<stop offset="0.25" style="stop-color:#F8FCFD"/>
<stop offset="0.44" style="stop-color:#D5DBDD"/>
<stop offset="0.6" style="stop-color:#BDC3C4"/>
<stop offset="0.8" style="stop-color:#A0A4A6"/>
<stop offset="0.97" style="stop-color:#929697"/>
<stop offset="1" style="stop-color:#C2C7C9"/>
</linearGradient>
<path id="shape6_1_" fill="url(#shape6_2_)" d="M19.257,47.976h4.012V56h-4.012V47.976z"/>
</svg>
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 24.1.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="42.526px" height="56px" viewBox="0 0 42.526 56" enable-background="new 0 0 42.526 56" xml:space="preserve">
<linearGradient id="shape2_2_" gradientUnits="userSpaceOnUse" x1="2613.1711" y1="408.9612" x2="2612.9939" y2="408.9612" gradientTransform="matrix(33.5 0 0 -136.2 -87516.5859 55725.3047)">
<stop offset="0" style="stop-color:#BAC0C1"/>
<stop offset="0.15" style="stop-color:#F4FAFC"/>
<stop offset="0.25" style="stop-color:#F8FCFD"/>
<stop offset="0.44" style="stop-color:#D5DBDD"/>
<stop offset="0.6" style="stop-color:#BDC3C4"/>
<stop offset="0.8" style="stop-color:#A0A4A6"/>
<stop offset="0.97" style="stop-color:#929697"/>
<stop offset="1" style="stop-color:#C2C7C9"/>
</linearGradient>
<path id="shape2_1_" fill="url(#shape2_2_)" d="M18.455,1.605h5.616v46.372h-5.616V1.605z"/>
<linearGradient id="shape3_2_" gradientUnits="userSpaceOnUse" x1="2609.7654" y1="404.8079" x2="2609.5869" y2="404.8079" gradientTransform="matrix(44.6 0 0 -51 -116370.2891 20649.6133)">
<stop offset="0" style="stop-color:#ACBABD"/>
<stop offset="0.15" style="stop-color:#E3F3F7"/>
<stop offset="0.25" style="stop-color:#EFF8FB"/>
<stop offset="0.44" style="stop-color:#C5D4D8"/>
<stop offset="0.6" style="stop-color:#AFBDC0"/>
<stop offset="0.8" style="stop-color:#939FA2"/>
<stop offset="0.97" style="stop-color:#879194"/>
<stop offset="1" style="stop-color:#B3C1C5"/>
</linearGradient>
<path id="shape3_1_" fill="url(#shape3_2_)" d="M17.251,0h8.024v8.827h-8.024V0z"/>
<linearGradient id="shape4_2_" gradientUnits="userSpaceOnUse" x1="2609.7654" y1="405.3216" x2="2609.5869" y2="405.3216" gradientTransform="matrix(44.6 0 0 -40.6 -116370.2891 16506.8398)">
<stop offset="0" style="stop-color:#9D9D9D"/>
<stop offset="0.15" style="stop-color:#D0D1D1"/>
<stop offset="0.25" style="stop-color:#E5E6E6"/>
<stop offset="0.44" style="stop-color:#B3B4B4"/>
<stop offset="0.6" style="stop-color:#9FA0A0"/>
<stop offset="0.8" style="stop-color:#868787"/>
<stop offset="0.97" style="stop-color:#7A7B7B"/>
<stop offset="1" style="stop-color:#A3A4A4"/>
</linearGradient>
<path id="shape4_1_" fill="url(#shape4_2_)" d="M17.251,47.173h8.024v7.221h-8.024V47.173z"/>
<linearGradient id="shape5_2_" gradientUnits="userSpaceOnUse" x1="2609.7654" y1="389.2159" x2="2609.5869" y2="389.2159" gradientTransform="matrix(44.6 0 0 -12.9 -116370.2891 5033.3228)">
<stop offset="0" style="stop-color:#ACBABD"/>
<stop offset="0.15" style="stop-color:#E3F3F7"/>
<stop offset="0.25" style="stop-color:#EFF8FB"/>
<stop offset="0.44" style="stop-color:#C5D4D8"/>
<stop offset="0.6" style="stop-color:#AFBDC0"/>
<stop offset="0.8" style="stop-color:#939FA2"/>
<stop offset="0.97" style="stop-color:#879194"/>
<stop offset="1" style="stop-color:#B3C1C5"/>
</linearGradient>
<path id="shape5_1_" fill="url(#shape5_2_)" d="M17.251,11.234h8.024v2.407h-8.024V11.234z"/>
<linearGradient id="shape6_2_" gradientUnits="userSpaceOnUse" x1="2621.7922" y1="406.2251" x2="2621.614" y2="406.2251" gradientTransform="matrix(20.5 0 0 -47.3 -53724.0273 19266.4355)">
<stop offset="0" style="stop-color:#BAC0C1"/>
<stop offset="0.15" style="stop-color:#F4FAFC"/>
<stop offset="0.25" style="stop-color:#F8FCFD"/>
<stop offset="0.44" style="stop-color:#D5DBDD"/>
<stop offset="0.6" style="stop-color:#BDC3C4"/>
<stop offset="0.8" style="stop-color:#A0A4A6"/>
<stop offset="0.97" style="stop-color:#929697"/>
<stop offset="1" style="stop-color:#C2C7C9"/>
</linearGradient>
<path id="shape6_1_" fill="url(#shape6_2_)" d="M19.257,47.976h4.012V56h-4.012V47.976z"/>
</svg>
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 23.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="56px" height="56px" viewBox="0 0 56 56" enable-background="new 0 0 56 56" xml:space="preserve">
<path fill="#DC1A1A" d="M20.912,27.662c0,2.554,1.36,4.914,3.568,6.191s4.929,1.277,7.137,0s3.569-3.637,3.569-6.191
c0-3.948-3.195-7.149-7.137-7.149S20.912,23.713,20.912,27.662L20.912,27.662z"/>
<path fill="#DC1A1A" d="M25.058,16.6c0,0,4.195-2.029,9.693,1.643c0,0,3.279-2.271,6.22-8.647c0,0,2.267-4.637-2.748-7.004
c0,0-12.634-7.536-27.872,3.092c0,0-2.604,1.256,1.254,3.188l7.233,2.174C18.79,11.045,24.431,12.253,25.058,16.6L25.058,16.6z
M30.893,39.4c0,0-4.195,2.029-9.692-1.642c0,0-3.279,2.27-6.221,8.647c0,0-2.266,4.637,2.749,7.004c0,0,12.634,7.536,27.872-3.091
c0,0,2.604-1.256-1.254-3.188l-7.233-2.173C37.162,44.955,31.52,43.747,30.893,39.4L30.893,39.4z M16.572,30.898
c0,0-2.025-4.202,1.639-9.709c0,0-2.267-3.285-8.632-6.231c0,0-4.629-2.27-6.992,2.753c0,0-7.523,12.656,3.086,27.92
c0,0,1.254,2.608,3.182-1.256l2.17-7.246C11.026,37.178,12.231,31.526,16.572,30.898L16.572,30.898z M39.428,25.101
c0,0,2.025,4.203-1.639,9.71c0,0,2.266,3.285,8.631,6.231c0,0,4.63,2.271,6.992-2.753c0,0,7.523-12.655-3.086-27.92
c0,0-1.254-2.609-3.183,1.256l-2.17,7.246C44.974,18.822,43.768,24.425,39.428,25.101L39.428,25.101z"/>
</svg>
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 23.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="56px" height="56px" viewBox="0 0 56 56" enable-background="new 0 0 56 56" xml:space="preserve">
<path fill="#516687" d="M20.912,27.662c0,2.554,1.36,4.914,3.568,6.191c2.208,1.277,4.929,1.277,7.137,0
c2.208-1.277,3.569-3.637,3.569-6.191c0-3.948-3.195-7.149-7.137-7.149C24.107,20.513,20.912,23.713,20.912,27.662L20.912,27.662z
M20.912,27.662"/>
<path fill="#516687" d="M25.058,16.6c0,0,4.195-2.029,9.693,1.643c0,0,3.279-2.271,6.22-8.647c0,0,2.267-4.637-2.748-7.004
c0,0-12.634-7.536-27.872,3.092c0,0-2.604,1.256,1.254,3.188l7.233,2.174C18.79,11.045,24.431,12.253,25.058,16.6L25.058,16.6z
M30.893,39.4c0,0-4.195,2.029-9.692-1.642c0,0-3.279,2.27-6.221,8.647c0,0-2.266,4.637,2.749,7.004c0,0,12.634,7.536,27.872-3.091
c0,0,2.604-1.256-1.254-3.188l-7.233-2.173C37.162,44.955,31.52,43.747,30.893,39.4L30.893,39.4z M16.572,30.898
c0,0-2.025-4.202,1.639-9.709c0,0-2.267-3.285-8.632-6.231c0,0-4.629-2.27-6.992,2.753c0,0-7.523,12.656,3.086,27.92
c0,0,1.254,2.608,3.182-1.256l2.17-7.246C11.026,37.178,12.231,31.526,16.572,30.898L16.572,30.898z M39.428,25.101
c0,0,2.025,4.203-1.639,9.71c0,0,2.266,3.285,8.631,6.231c0,0,4.63,2.271,6.992-2.753c0,0,7.523-12.655-3.086-27.92
c0,0-1.254-2.609-3.183,1.256l-2.17,7.246C44.974,18.822,43.768,24.425,39.428,25.101L39.428,25.101z M39.428,25.101"/>
</svg>
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 23.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="56px" height="56px" viewBox="0 0 56 56" enable-background="new 0 0 56 56" xml:space="preserve">
<path fill="#13E8DC" d="M20.912,27.662c0,2.554,1.36,4.914,3.568,6.191c2.208,1.277,4.929,1.277,7.137,0
c2.208-1.277,3.569-3.637,3.569-6.191c0-3.948-3.195-7.149-7.137-7.149C24.107,20.513,20.912,23.713,20.912,27.662L20.912,27.662z
M20.912,27.662"/>
<path fill="#13E8DC" d="M25.058,16.6c0,0,4.195-2.029,9.693,1.643c0,0,3.279-2.271,6.22-8.647c0,0,2.267-4.637-2.748-7.004
c0,0-12.634-7.536-27.872,3.092c0,0-2.604,1.256,1.254,3.188l7.233,2.174C18.79,11.045,24.431,12.253,25.058,16.6L25.058,16.6z
M30.893,39.4c0,0-4.195,2.029-9.692-1.642c0,0-3.279,2.27-6.221,8.647c0,0-2.266,4.637,2.749,7.004c0,0,12.634,7.536,27.872-3.091
c0,0,2.604-1.256-1.254-3.188l-7.233-2.173C37.162,44.955,31.52,43.747,30.893,39.4L30.893,39.4z M16.572,30.898
c0,0-2.025-4.202,1.639-9.709c0,0-2.267-3.285-8.632-6.231c0,0-4.629-2.27-6.992,2.753c0,0-7.523,12.656,3.086,27.92
c0,0,1.254,2.608,3.182-1.256l2.17-7.246C11.026,37.178,12.231,31.526,16.572,30.898L16.572,30.898z M39.428,25.101
c0,0,2.025,4.203-1.639,9.71c0,0,2.266,3.285,8.631,6.231c0,0,4.63,2.271,6.992-2.753c0,0,7.523-12.655-3.086-27.92
c0,0-1.254-2.609-3.183,1.256l-2.17,7.246C44.974,18.822,43.768,24.425,39.428,25.101L39.428,25.101z M39.428,25.101"/>
</svg>
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 23.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="56px" height="56px" viewBox="0 0 56 56" enable-background="new 0 0 56 56" xml:space="preserve">
<path fill="#1B91FF" d="M28,0C12.6,0,0,12.6,0,28s12.6,28,28,28s28-12.6,28-28S43.4,0,28,0z M28,51.8C14.84,51.8,4.2,41.16,4.06,28
c0-13.16,10.64-23.8,23.8-23.94c13.16,0,23.8,10.64,23.94,23.8l0,0C51.8,41.16,41.16,51.8,28,51.8z"/>
<path fill="#1B91FF" d="M22.96,28c0,2.8,2.24,5.04,5.04,5.04s5.04-2.24,5.04-5.04S30.8,22.96,28,22.96S22.96,25.2,22.96,28z"/>
<path fill="#1B91FF" d="M25.9,20.16c0,0,2.94-1.4,6.86,1.12c0,0,2.38-1.54,4.34-6.16c0.84-1.82,0.14-3.92-1.68-4.76
c-0.14,0-0.14-0.14-0.28-0.14c0,0-8.96-5.32-19.6,2.24c0,0-1.82,0.84,0.84,2.24l5.04,1.54C21.56,16.24,25.48,17.22,25.9,20.16z
M29.96,36.26c0,0-2.94,1.4-6.86-1.12c0,0-2.24,1.54-4.34,6.16c-0.84,1.82-0.14,3.92,1.68,4.76c0.14,0,0.14,0.14,0.28,0.14
c0,0,8.96,5.32,19.74-2.1c0,0,1.82-0.84-0.84-2.24l-5.04-1.54C34.44,40.18,30.52,39.34,29.96,36.26L29.96,36.26z M19.88,30.24
c0,0-1.4-2.94,1.12-6.86c0,0-1.54-2.24-6.16-4.34c-1.82-0.84-3.92-0.14-4.76,1.68c0,0.14-0.14,0.14-0.14,0.28
c0,0-5.32,8.96,2.24,19.6c0,0,0.84,1.82,2.24-0.84l1.54-5.18C15.96,34.72,16.8,30.66,19.88,30.24L19.88,30.24z M35.98,26.18
c0,0,1.4,2.94-1.12,6.86c0,0,1.54,2.38,6.02,4.34c1.82,0.84,3.92,0.14,4.76-1.68c0-0.14,0.14-0.14,0.14-0.28
c0,0,5.32-8.96-2.24-19.6c0,0-0.84-1.82-2.24,0.84l-1.4,5.04C40.04,21.84,39.06,25.76,35.98,26.18z"/>
</svg>
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 23.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="56px" height="56px" viewBox="0 0 56 56" enable-background="new 0 0 56 56" xml:space="preserve">
<path fill="#F92E57" d="M28,0C12.6,0,0,12.6,0,28s12.6,28,28,28s28-12.6,28-28S43.4,0,28,0z M28,51.8C14.84,51.8,4.2,41.16,4.06,28
c0-13.16,10.64-23.8,23.8-23.94c13.16,0,23.8,10.64,23.94,23.8l0,0C51.8,41.16,41.16,51.8,28,51.8z"/>
<path fill="#F92E57" d="M22.96,28c0,2.8,2.24,5.04,5.04,5.04s5.04-2.24,5.04-5.04S30.8,22.96,28,22.96S22.96,25.2,22.96,28z"/>
<path fill="#F92E57" d="M25.9,20.16c0,0,2.94-1.4,6.86,1.12c0,0,2.38-1.54,4.34-6.16c0.84-1.82,0.14-3.92-1.68-4.76
c-0.14,0-0.14-0.14-0.28-0.14c0,0-8.96-5.32-19.6,2.24c0,0-1.82,0.84,0.84,2.24l5.04,1.54C21.56,16.24,25.48,17.22,25.9,20.16z
M29.96,36.26c0,0-2.94,1.4-6.86-1.12c0,0-2.24,1.54-4.34,6.16c-0.84,1.82-0.14,3.92,1.68,4.76c0.14,0,0.14,0.14,0.28,0.14
c0,0,8.96,5.32,19.74-2.1c0,0,1.82-0.84-0.84-2.24l-5.04-1.54C34.44,40.18,30.52,39.34,29.96,36.26L29.96,36.26z M19.88,30.24
c0,0-1.4-2.94,1.12-6.86c0,0-1.54-2.24-6.16-4.34c-1.82-0.84-3.92-0.14-4.76,1.68c0,0.14-0.14,0.14-0.14,0.28
c0,0-5.32,8.96,2.24,19.6c0,0,0.84,1.82,2.24-0.84l1.54-5.18C15.96,34.72,16.8,30.66,19.88,30.24L19.88,30.24z M35.98,26.18
c0,0,1.4,2.94-1.12,6.86c0,0,1.54,2.38,6.02,4.34c1.82,0.84,3.92,0.14,4.76-1.68c0-0.14,0.14-0.14,0.14-0.28
c0,0,5.32-8.96-2.24-19.6c0,0-0.84-1.82-2.24,0.84l-1.4,5.04C40.04,21.84,39.06,25.76,35.98,26.18z"/>
</svg>
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 23.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="56px" height="56px" viewBox="0 0 56 56" enable-background="new 0 0 56 56" xml:space="preserve">
<path fill="#999DAA" d="M28,0C12.6,0,0,12.6,0,28s12.6,28,28,28s28-12.6,28-28S43.4,0,28,0z M28,51.8C14.84,51.8,4.2,41.16,4.06,28
c0-13.16,10.64-23.8,23.8-23.94c13.16,0,23.8,10.64,23.94,23.8l0,0C51.8,41.16,41.16,51.8,28,51.8z"/>
<path fill="#999DAA" d="M22.96,28c0,2.8,2.24,5.04,5.04,5.04s5.04-2.24,5.04-5.04S30.8,22.96,28,22.96S22.96,25.2,22.96,28z"/>
<path fill="#999DAA" d="M25.9,20.16c0,0,2.94-1.4,6.86,1.12c0,0,2.38-1.54,4.34-6.16c0.84-1.82,0.14-3.92-1.68-4.76
c-0.14,0-0.14-0.14-0.28-0.14c0,0-8.96-5.32-19.6,2.24c0,0-1.82,0.84,0.84,2.24l5.04,1.54C21.56,16.24,25.48,17.22,25.9,20.16z
M29.96,36.26c0,0-2.94,1.4-6.86-1.12c0,0-2.24,1.54-4.34,6.16c-0.84,1.82-0.14,3.92,1.68,4.76c0.14,0,0.14,0.14,0.28,0.14
c0,0,8.96,5.32,19.74-2.1c0,0,1.82-0.84-0.84-2.24l-5.04-1.54C34.44,40.18,30.52,39.34,29.96,36.26L29.96,36.26z M19.88,30.24
c0,0-1.4-2.94,1.12-6.86c0,0-1.54-2.24-6.16-4.34c-1.82-0.84-3.92-0.14-4.76,1.68c0,0.14-0.14,0.14-0.14,0.28
c0,0-5.32,8.96,2.24,19.6c0,0,0.84,1.82,2.24-0.84l1.54-5.18C15.96,34.72,16.8,30.66,19.88,30.24L19.88,30.24z M35.98,26.18
c0,0,1.4,2.94-1.12,6.86c0,0,1.54,2.38,6.02,4.34c1.82,0.84,3.92,0.14,4.76-1.68c0-0.14,0.14-0.14,0.14-0.28
c0,0,5.32-8.96-2.24-19.6c0,0-0.84-1.82-2.24,0.84l-1.4,5.04C40.04,21.84,39.06,25.76,35.98,26.18z"/>
</svg>
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 23.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="56px" height="56px" viewBox="0 0 56 56" enable-background="new 0 0 56 56" xml:space="preserve">
<path fill="#1ad90b" d="M28,0C12.6,0,0,12.6,0,28s12.6,28,28,28s28-12.6,28-28S43.4,0,28,0z M28,51.8C14.84,51.8,4.2,41.16,4.06,28
c0-13.16,10.64-23.8,23.8-23.94c13.16,0,23.8,10.64,23.94,23.8l0,0C51.8,41.16,41.16,51.8,28,51.8z"/>
<path fill="#1ad90b" d="M22.96,28c0,2.8,2.24,5.04,5.04,5.04s5.04-2.24,5.04-5.04S30.8,22.96,28,22.96S22.96,25.2,22.96,28z"/>
<path fill="#1ad90b" d="M25.9,20.16c0,0,2.94-1.4,6.86,1.12c0,0,2.38-1.54,4.34-6.16c0.84-1.82,0.14-3.92-1.68-4.76
c-0.14,0-0.14-0.14-0.28-0.14c0,0-8.96-5.32-19.6,2.24c0,0-1.82,0.84,0.84,2.24l5.04,1.54C21.56,16.24,25.48,17.22,25.9,20.16z
M29.96,36.26c0,0-2.94,1.4-6.86-1.12c0,0-2.24,1.54-4.34,6.16c-0.84,1.82-0.14,3.92,1.68,4.76c0.14,0,0.14,0.14,0.28,0.14
c0,0,8.96,5.32,19.74-2.1c0,0,1.82-0.84-0.84-2.24l-5.04-1.54C34.44,40.18,30.52,39.34,29.96,36.26L29.96,36.26z M19.88,30.24
c0,0-1.4-2.94,1.12-6.86c0,0-1.54-2.24-6.16-4.34c-1.82-0.84-3.92-0.14-4.76,1.68c0,0.14-0.14,0.14-0.14,0.28
c0,0-5.32,8.96,2.24,19.6c0,0,0.84,1.82,2.24-0.84l1.54-5.18C15.96,34.72,16.8,30.66,19.88,30.24L19.88,30.24z M35.98,26.18
c0,0,1.4,2.94-1.12,6.86c0,0,1.54,2.38,6.02,4.34c1.82,0.84,3.92,0.14,4.76-1.68c0-0.14,0.14-0.14,0.14-0.28
c0,0,5.32-8.96-2.24-19.6c0,0-0.84-1.82-2.24,0.84l-1.4,5.04C40.04,21.84,39.06,25.76,35.98,26.18z"/>
</svg>
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 23.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="56px" height="56px" viewBox="0 0 56 56" enable-background="new 0 0 56 56" xml:space="preserve">
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="18.1743" y1="48.5671" x2="37.7194" y2="48.5671" gradientTransform="matrix(1 0 0 -1 0 59.3279)">
<stop offset="0.2039" style="stop-color:#AC3A54"/>
<stop offset="0.75" style="stop-color:#FFB6C7"/>
<stop offset="1" style="stop-color:#C6546E"/>
</linearGradient>
<polygon fill="url(#SVGID_1_)" points="33.38,21.522 22.62,21.522 18.227,0 37.773,0 "/>
<linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="18.1743" y1="829.6729" x2="37.7194" y2="829.6729" gradientTransform="matrix(1 0 0 1 0 -784.5435)">
<stop offset="0.2039" style="stop-color:#AC3A54"/>
<stop offset="0.75" style="stop-color:#FFB6C7"/>
<stop offset="1" style="stop-color:#C6546E"/>
</linearGradient>
<polygon fill="url(#SVGID_2_)" points="33.38,34.259 22.62,34.259 18.227,56 37.773,56 "/>
<linearGradient id="SVGID_3_" gradientUnits="userSpaceOnUse" x1="193.7608" y1="659.749" x2="174.2157" y2="659.749" gradientTransform="matrix(0 1 1 0 -614.6196 -155.9348)">
<stop offset="0.2039" style="stop-color:#AC3A54"/>
<stop offset="0.75" style="stop-color:#FFB6C7"/>
<stop offset="1" style="stop-color:#C6546E"/>
</linearGradient>
<polygon fill="url(#SVGID_3_)" points="34.259,33.38 34.259,22.62 56,18.227 56,37.773 "/>
<linearGradient id="SVGID_4_" gradientUnits="userSpaceOnUse" x1="193.7608" y1="218.491" x2="174.2157" y2="218.491" gradientTransform="matrix(0 1 -1 0 229.2517 -155.9348)">
<stop offset="0.2039" style="stop-color:#AC3A54"/>
<stop offset="0.75" style="stop-color:#FFB6C7"/>
<stop offset="1" style="stop-color:#C6546E"/>
</linearGradient>
<polygon fill="url(#SVGID_4_)" points="21.522,33.38 21.522,22.62 0,18.227 0,37.773 "/>
<linearGradient id="SVGID_5_" gradientUnits="userSpaceOnUse" x1="22.5948" y1="31.2181" x2="33.3007" y2="31.2181" gradientTransform="matrix(1 0 0 -1 0 59.3279)">
<stop offset="0" style="stop-color:#9C9FA6"/>
<stop offset="0.5391" style="stop-color:#848890"/>
<stop offset="0.9832" style="stop-color:#D2D5DB"/>
</linearGradient>
<path fill="url(#SVGID_5_)" d="M30.745,33.38h-5.71c-1.318,0-2.416-1.098-2.416-2.416v-5.71c0-1.318,1.098-2.416,2.416-2.416h5.71
c1.318,0,2.416,1.098,2.416,2.416v5.71C33.38,32.282,32.282,33.38,30.745,33.38z"/>
</svg>
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 23.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="56px" height="56px" viewBox="0 0 56 56" enable-background="new 0 0 56 56" xml:space="preserve">
<g>
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="18.1743" y1="54.7873" x2="37.7194" y2="54.7873" gradientTransform="matrix(1 0 0 -1 0 65.5481)">
<stop offset="0" style="stop-color:#9A9DA0"/>
<stop offset="0.5391" style="stop-color:#DBDCE0"/>
<stop offset="1" style="stop-color:#F1F3F6"/>
</linearGradient>
<polygon fill="url(#SVGID_1_)" points="33.38,21.522 22.62,21.522 18.227,0 37.773,0 "/>
<linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="18.1743" y1="829.6729" x2="37.7194" y2="829.6729" gradientTransform="matrix(1 0 0 1 0 -784.5435)">
<stop offset="0" style="stop-color:#9A9DA0"/>
<stop offset="0.5391" style="stop-color:#DBDCE0"/>
<stop offset="1" style="stop-color:#F1F3F6"/>
</linearGradient>
<polygon fill="url(#SVGID_2_)" points="33.38,34.259 22.62,34.259 18.227,56 37.773,56 "/>
<linearGradient id="SVGID_3_" gradientUnits="userSpaceOnUse" x1="177.8098" y1="656.048" x2="197.3549" y2="656.048" gradientTransform="matrix(0 1 1 0 -610.9186 -159.6358)">
<stop offset="0" style="stop-color:#9A9DA0"/>
<stop offset="0.5391" style="stop-color:#DBDCE0"/>
<stop offset="1" style="stop-color:#F1F3F6"/>
</linearGradient>
<polygon fill="url(#SVGID_3_)" points="34.259,33.38 34.259,22.62 56,18.227 56,37.773 "/>
<linearGradient id="SVGID_4_" gradientUnits="userSpaceOnUse" x1="177.8098" y1="228.4122" x2="197.3549" y2="228.4122" gradientTransform="matrix(0 1 -1 0 239.173 -159.6358)">
<stop offset="0" style="stop-color:#9A9DA0"/>
<stop offset="0.5391" style="stop-color:#DBDCE0"/>
<stop offset="1" style="stop-color:#F1F3F6"/>
</linearGradient>
<polygon fill="url(#SVGID_4_)" points="21.522,33.38 21.522,22.62 0,18.227 0,37.773 "/>
<linearGradient id="SVGID_5_" gradientUnits="userSpaceOnUse" x1="22.5948" y1="37.4383" x2="33.3007" y2="37.4383" gradientTransform="matrix(1 0 0 -1 0 65.5481)">
<stop offset="0" style="stop-color:#9C9FA6"/>
<stop offset="0.5391" style="stop-color:#848890"/>
<stop offset="0.9832" style="stop-color:#D2D5DB"/>
</linearGradient>
<path fill="url(#SVGID_5_)" d="M30.745,33.38h-5.71c-1.318,0-2.416-1.098-2.416-2.416v-5.71c0-1.318,1.098-2.416,2.416-2.416h5.71
c1.318,0,2.416,1.098,2.416,2.416v5.71C33.38,32.282,32.282,33.38,30.745,33.38z"/>
</g>
</svg>
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 23.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="56px" height="56px" viewBox="0 0 56 56" enable-background="new 0 0 56 56" xml:space="preserve">
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="18.1743" y1="48.9032" x2="37.7194" y2="48.9032" gradientTransform="matrix(1 0 0 -1 0 59.664)">
<stop offset="0.2039" style="stop-color:#01AC7A"/>
<stop offset="0.75" style="stop-color:#96FFE0"/>
<stop offset="1" style="stop-color:#04A073"/>
</linearGradient>
<polygon fill="url(#SVGID_1_)" points="33.38,21.522 22.62,21.522 18.227,0 37.773,0 "/>
<linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="18.1743" y1="829.6729" x2="37.7194" y2="829.6729" gradientTransform="matrix(1 0 0 1 0 -784.5435)">
<stop offset="0.2039" style="stop-color:#04A073"/>
<stop offset="0.75" style="stop-color:#A2F9CD"/>
<stop offset="1" style="stop-color:#04A073"/>
</linearGradient>
<polygon fill="url(#SVGID_2_)" points="33.38,34.259 22.62,34.259 18.227,56 37.773,56 "/>
<linearGradient id="SVGID_3_" gradientUnits="userSpaceOnUse" x1="193.8145" y1="659.6953" x2="174.2694" y2="659.6953" gradientTransform="matrix(0 1 1 0 -614.5659 -155.9885)">
<stop offset="0.2039" style="stop-color:#04A073"/>
<stop offset="0.75" style="stop-color:#A2F9CD"/>
<stop offset="1" style="stop-color:#04A073"/>
</linearGradient>
<polygon fill="url(#SVGID_3_)" points="34.259,33.38 34.259,22.62 56,18.227 56,37.773 "/>
<linearGradient id="SVGID_4_" gradientUnits="userSpaceOnUse" x1="193.8145" y1="218.8807" x2="174.2694" y2="218.8807" gradientTransform="matrix(0 1 -1 0 229.6415 -155.9885)">
<stop offset="0.2039" style="stop-color:#04A073"/>
<stop offset="0.75" style="stop-color:#A2F9CD"/>
<stop offset="1" style="stop-color:#04A073"/>
</linearGradient>
<polygon fill="url(#SVGID_4_)" points="21.522,33.38 21.522,22.62 0,18.227 0,37.773 "/>
<linearGradient id="SVGID_5_" gradientUnits="userSpaceOnUse" x1="22.5948" y1="31.5541" x2="33.3007" y2="31.5541" gradientTransform="matrix(1 0 0 -1 0 59.664)">
<stop offset="0" style="stop-color:#9C9FA6"/>
<stop offset="0.5391" style="stop-color:#848890"/>
<stop offset="0.9832" style="stop-color:#D2D5DB"/>
</linearGradient>
<path fill="url(#SVGID_5_)" d="M30.745,33.38h-5.71c-1.318,0-2.416-1.098-2.416-2.416v-5.71c0-1.318,1.098-2.416,2.416-2.416h5.71
c1.318,0,2.416,1.098,2.416,2.416v5.71C33.38,32.282,32.282,33.38,30.745,33.38z"/>
</svg>
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;
@import (reference) '../../../../node_modules/antd/es/style/themes/default';
@ec-configuration-view-prefix-cls: ~'@{ant-prefix}-ec-configuration-view';
.@{ec-configuration-view-prefix-cls} {
width: 100%;
height: 100%;
.configurationView {
width: 100%;
height: 100%;
canvas {
border: 0;
outline: none;
}
}
&-modal {
color: white;
.switchControlContent {
display: flex;
align-items: center;
:global {
.anticon.anticon-exclamation-circle {
margin-top: 2px;
margin-right: 10px;
color: #fd5e72;
font-size: 18px;
}
}
}
.moreControlContent {
display: flex;
flex-direction: column;
.moreControlList {
display: flex;
span {
margin-right: 30px;
white-space: nowrap;
}
div {
margin-bottom: 20px;
padding: 2px 10px;
border: 1px solid #6d7da2;
border-radius: 6px;
}
&:last-of-type {
div {
margin-bottom: 0;
}
}
}
}
.adjustControlContent {
display: flex;
align-items: center;
.label {
margin-right: 30px;
white-space: nowrap;
}
//:global {
.ant-input-affix-wrapper {
background: #1c202c;
border: none;
}
.ant-input-affix-wrapper:focus,
.ant-input-affix-wrapper-focused {
box-shadow: none;
}
.ant-input:focus {
border: none;
box-shadow: none;
}
.ant-input,
.ant-btn {
color: white;
background: #1c202c;
border: none;
}
.ant-input-group-addon {
background: #1c202c;
border: none;
}
.ant-input-suffix {
color: #646977;
}
//}
}
.authorizeControlContent {
display: flex;
flex-direction: column;
.authorizeControlItem {
display: flex;
align-items: center;
margin-bottom: 20px;
//:global {
.ant-col.ant-form-item-label {
margin-right: 10px;
label {
color: white;
}
}
.ant-form-item-control-input-content {
display: flex;
align-items: center;
}
.ant-input-affix-wrapper {
background: #1c202c;
border: none;
}
.ant-input-affix-wrapper:focus,
.ant-input-affix-wrapper-focused {
box-shadow: none;
}
.ant-input:focus {
border: none;
box-shadow: none;
}
.ant-input,
.ant-btn {
color: white;
background: #1c202c;
border: none;
}
.ant-input-group-addon {
background: #1c202c;
border: none;
}
.ant-input-suffix {
color: #646977;
}
}
&:last-of-type {
margin-bottom: 0;
}
//}
}
//:global{
.ant-modal-content {
color: white;
background: #282d3b;
border: 1px solid #31374a;
.ant-modal-close {
color: white;
}
.ant-modal-close-x {
line-height: 42px;
}
.ant-modal-header {
background: none;
border-color: #1c202c;
.ant-modal-title {
color: white;
}
}
.ant-modal-body {
}
.ant-modal-footer {
background: none;
border-color: #1c202c;
.ant-btn:first-of-type {
color: white;
background-color: #838a9d;
border: none;
&:hover {
background-color: #9ba3b6;
}
}
}
}
//}
}
.historyInfoModal {
//:global {
.ant-modal-body {
height: 680px;
}
//}
}
.jumpModal {
color: white;
//:global {
.ant-modal {
padding-bottom: 0;
}
.ant-modal,
.ant-modal-content {
background: #282d3b;
}
.ant-modal-content {
height: 100%;
}
.ant-modal-header {
background: #282d3b;
}
.ant-modal-title,
.ant-modal-close-x {
color: white;
}
.ant-modal-body {
height: calc(100% - 55px);
}
}
.configurationView {
width: 100%;
height: 100%;
canvas {
border: 0;
outline: none;
}
}
//}
}
import * as go from './go';
export default class BarLink extends go.Link {
constructor() {
super(...arguments);
go.Link.call(this);
}
getLinkPoint(node, port, spot, from, ortho, othernode, otherport) {
if (node.category === 'HBar') {
window.οncοntextmenu = function (event) {
var e = event || window.event;
document.getElementById('Menu').style.left = e.clientX + 'px';
document.getElementById('Menu').style.top = e.clientY + 'px';
document.getElementById('Menu').style.display = 'block';
return false;
};
var op = go.Link.prototype.getLinkPoint.call(
this,
othernode,
otherport,
this.computeSpot(!from),
!from,
ortho,
node,
port,
);
var r = port.getDocumentBounds();
// 横向合管
var r = port.getDocumentBounds();
var angle = node.angle;
var spare = (angle / 90) % 2;
if (!spare) {
var y = op.y > r.centerY ? r.bottom : r.top;
if (op.x < r.left) return new go.Point(r.left, y);
if (op.x > r.right) return new go.Point(r.right, y);
return new go.Point(op.x, y);
}
// 纵向合管
var x = op.x > r.centerX ? r.right : r.left;
if (op.y < r.top) return new go.Point(x, r.top);
if (op.y > r.bottom) return new go.Point(x, r.bottom);
// return new go.Point(x, op.y - r.width / 2 + 3);
return new go.Point(x, op.y);
} else {
return go.Link.prototype.getLinkPoint.call(
this,
node,
port,
spot,
from,
ortho,
othernode,
otherport,
);
}
}
}
// function BarLink() {
// go.Link.call(this);
// }
// go.Diagram.inherit(BarLink, go.Link);
// BarLink.prototype.getLinkPoint = function(node, port, spot, from, ortho, othernode, otherport) {
// if (node.category === "HBar") {
// window.οncοntextmenu = function(event) {
// var e = event || window.event;
// document.getElementById("Menu").style.left = e.clientX + "px";
// document.getElementById("Menu").style.top = e.clientY + "px";
// document.getElementById("Menu").style.display = "block";
// return false;
// }
// var op = go.Link.prototype.getLinkPoint.call(this, othernode, otherport, this.computeSpot(!from), !from, ortho, node, port);
// var r = port.getDocumentBounds();
// // 横向合管
// var r = port.getDocumentBounds();
// var angle = node.angle;
// var spare = (angle / 90) % 2;
// if (!spare) {
// var y = (op.y > r.centerY) ? r.bottom : r.top;
// if (op.x < r.left) return new go.Point(r.left, y);
// if (op.x > r.right) return new go.Point(r.right, y);
// return new go.Point(op.x, y);
// }
// // 纵向合管
// var x = (op.x > r.centerX) ? r.right : r.left;
// if (op.y < r.top) return new go.Point(x, r.top);
// if (op.y > r.bottom) return new go.Point(x, r.bottom);
// // return new go.Point(x, op.y - r.width / 2 + 3);
// return new go.Point(x, op.y);
// } else {
// return go.Link.prototype.getLinkPoint.call(this, node, port, spot, from, ortho, othernode, otherport);
// }
// };
/*
* Copyright (C) 1998-2021 by Northwoods Software Corporation. All Rights Reserved.
*/
/*
* This is an extension and not part of the main GoJS library.
* Note that the API for this class may change with any version, even point releases.
* If you intend to use an extension in production, you should copy the code to your own source directory.
* Extensions can be found in the GoJS kit under the extensions or extensionsTS folders.
* See the Extensions intro page (https://gojs.net/latest/intro/extensions.html) for more information.
*/
import * as go from './go';
/**
* This CommandHandler class allows the user to position selected Parts in a diagram relative to the
* first part selected, in addition to overriding the doKeyDown method of the CommandHandler for
* handling the arrow keys in additional manners.
*
* Typical usage: ```js $(go.Diagram, "myDiagramDiv",
* {
* commandHandler: $(DrawCommandHandler),
* . . .
* } ) ``` or: ```js
* myDiagram.commandHandler = new DrawCommandHandler(); ```
*
* If you want to experiment with this extension, try the <a
* href="../../extensionsTS/DrawCommandHandler.html">Drawing Commands</a> sample.
*/
export default class DrawCommandHandler extends go.CommandHandler {
constructor() {
super(...arguments);
this._arrowKeyBehavior = 'move';
this._pasteOffset = new go.Point(10, 10);
this._lastPasteOffset = new go.Point(0, 0);
}
/**
* Gets or sets the arrow key behavior. Possible values are "move", "select", and "scroll".
*
* The default value is "move".
*/
get arrowKeyBehavior() {
return this._arrowKeyBehavior;
}
set arrowKeyBehavior(val) {
if (val !== 'move' && val !== 'select' && val !== 'scroll' && val !== 'none') {
throw new Error(
'DrawCommandHandler.arrowKeyBehavior must be either "move", "select", "scroll", or "none", not: ' +
val,
);
}
this._arrowKeyBehavior = val;
}
/**
* Gets or sets the offset at which each repeated {@link #pasteSelection} puts the new copied
* parts from the clipboard.
*/
get pasteOffset() {
return this._pasteOffset;
}
set pasteOffset(val) {
if (!(val instanceof go.Point))
throw new Error('DrawCommandHandler.pasteOffset must be a Point, not: ' + val);
this._pasteOffset.set(val);
}
/**
* This controls whether or not the user can invoke the {@link #alignLeft}, {@link #alignRight},
* {@link #alignTop}, {@link #alignBottom}, {@link #alignCenterX}, {@link #alignCenterY} commands.
*
* @returns {boolean} This returns true:
* if the diagram is not {@link Diagram#isReadOnly},
* if the model is not {@link Model#isReadOnly}, and
* if there are at least two selected {@link Part}s.
*/
canAlignSelection() {
const diagram = this.diagram;
if (diagram.isReadOnly || diagram.isModelReadOnly) return false;
if (diagram.selection.count < 2) return false;
return true;
}
/** Aligns selected parts along the left-most edge of the left-most part. */
alignLeft() {
const diagram = this.diagram;
diagram.startTransaction('aligning left');
let minPosition = Infinity;
diagram.selection.each((current) => {
if (current instanceof go.Link) return; // skips over go.Link
minPosition = Math.min(current.position.x, minPosition);
});
diagram.selection.each((current) => {
if (current instanceof go.Link) return; // skips over go.Link
current.move(new go.Point(minPosition, current.position.y));
});
diagram.commitTransaction('aligning left');
}
/** Aligns selected parts at the right-most edge of the right-most part. */
alignRight() {
const diagram = this.diagram;
diagram.startTransaction('aligning right');
let maxPosition = -Infinity;
diagram.selection.each((current) => {
if (current instanceof go.Link) return; // skips over go.Link
const rightSideLoc = current.actualBounds.x + current.actualBounds.width;
maxPosition = Math.max(rightSideLoc, maxPosition);
});
diagram.selection.each((current) => {
if (current instanceof go.Link) return; // skips over go.Link
current.move(new go.Point(maxPosition - current.actualBounds.width, current.position.y));
});
diagram.commitTransaction('aligning right');
}
/** Aligns selected parts at the top-most edge of the top-most part. */
alignTop() {
const diagram = this.diagram;
diagram.startTransaction('alignTop');
let minPosition = Infinity;
diagram.selection.each((current) => {
if (current instanceof go.Link) return; // skips over go.Link
minPosition = Math.min(current.position.y, minPosition);
});
diagram.selection.each((current) => {
if (current instanceof go.Link) return; // skips over go.Link
current.move(new go.Point(current.position.x, minPosition));
});
diagram.commitTransaction('alignTop');
}
/** Aligns selected parts at the bottom-most edge of the bottom-most part. */
alignBottom() {
const diagram = this.diagram;
diagram.startTransaction('aligning bottom');
let maxPosition = -Infinity;
diagram.selection.each((current) => {
if (current instanceof go.Link) return; // skips over go.Link
const bottomSideLoc = current.actualBounds.y + current.actualBounds.height;
maxPosition = Math.max(bottomSideLoc, maxPosition);
});
diagram.selection.each((current) => {
if (current instanceof go.Link) return; // skips over go.Link
current.move(new go.Point(current.actualBounds.x, maxPosition - current.actualBounds.height));
});
diagram.commitTransaction('aligning bottom');
}
/** Aligns selected parts at the x-value of the center point of the first selected part. */
alignCenterX() {
const diagram = this.diagram;
const firstSelection = diagram.selection.first();
if (!firstSelection) return;
diagram.startTransaction('aligning Center X');
const centerX = firstSelection.actualBounds.x + firstSelection.actualBounds.width / 2;
diagram.selection.each((current) => {
if (current instanceof go.Link) return; // skips over go.Link
current.move(new go.Point(centerX - current.actualBounds.width / 2, current.actualBounds.y));
});
diagram.commitTransaction('aligning Center X');
}
/** Aligns selected parts at the y-value of the center point of the first selected part. */
alignCenterY() {
const diagram = this.diagram;
const firstSelection = diagram.selection.first();
if (!firstSelection) return;
diagram.startTransaction('aligning Center Y');
const centerY = firstSelection.actualBounds.y + firstSelection.actualBounds.height / 2;
diagram.selection.each((current) => {
if (current instanceof go.Link) return; // skips over go.Link
current.move(new go.Point(current.actualBounds.x, centerY - current.actualBounds.height / 2));
});
diagram.commitTransaction('aligning Center Y');
}
/**
* Aligns selected parts top-to-bottom in order of the order selected. Distance between parts
* can be specified. Default distance is 0.
*/
alignColumn(distance) {
const diagram = this.diagram;
diagram.startTransaction('align Column');
if (distance === undefined) distance = 0; // for aligning edge to edge
distance = parseFloat(distance.toString());
const selectedParts = new Array();
diagram.selection.each((current) => {
if (current instanceof go.Link) return; // skips over go.Link
selectedParts.push(current);
});
for (let i = 0; i < selectedParts.length - 1; i++) {
const current = selectedParts[i];
// adds distance specified between parts
const curBottomSideLoc = current.actualBounds.y + current.actualBounds.height + distance;
const next = selectedParts[i + 1];
next.move(new go.Point(current.actualBounds.x, curBottomSideLoc));
}
diagram.commitTransaction('align Column');
}
/**
* Aligns selected parts left-to-right in order of the order selected. Distance between parts
* can be specified. Default distance is 0.
*/
alignRow(distance) {
if (distance === undefined) distance = 0; // for aligning edge to edge
distance = parseFloat(distance.toString());
const diagram = this.diagram;
diagram.startTransaction('align Row');
const selectedParts = new Array();
diagram.selection.each((current) => {
if (current instanceof go.Link) return; // skips over go.Link
selectedParts.push(current);
});
for (let i = 0; i < selectedParts.length - 1; i++) {
const current = selectedParts[i];
// adds distance specified between parts
const curRightSideLoc = current.actualBounds.x + current.actualBounds.width + distance;
const next = selectedParts[i + 1];
next.move(new go.Point(curRightSideLoc, current.actualBounds.y));
}
diagram.commitTransaction('align Row');
}
/**
* This controls whether or not the user can invoke the {@link #rotate} command.
*
* @returns {boolean} This returns true:
* if the diagram is not {@link Diagram#isReadOnly},
* if the model is not {@link Model#isReadOnly}, and
* if there is at least one selected {@link Part}.
*/
canRotate() {
const diagram = this.diagram;
if (diagram.isReadOnly || diagram.isModelReadOnly) return false;
if (diagram.selection.count < 1) return false;
return true;
}
/**
* Change the angle of the parts connected with the given part. This is in the command handler
* so it can be easily accessed for the purpose of creating commands that change the rotation of a part.
*
* @param {number} angle The positive (clockwise) or negative (counter-clockwise) change in the
* rotation angle of each Part, in degrees.
*/
rotate(angle) {
if (angle === undefined) angle = 90;
const diagram = this.diagram;
diagram.startTransaction('rotate ' + angle.toString());
diagram.selection.each((current) => {
if (current instanceof go.Link || current instanceof go.Group) return; // skips over Links and Groups
current.angle += angle;
});
diagram.commitTransaction('rotate ' + angle.toString());
}
/**
* Change the z-ordering of selected parts to pull them forward, in front of all other parts in
* their respective layers. All unselected parts in each layer with a selected Part with a
* non-numeric {@link Part#zOrder} will get a zOrder of zero.
*
* @this {DrawCommandHandler}
*/
pullToFront() {
const diagram = this.diagram;
diagram.startTransaction('pullToFront');
// find the affected Layers
const layers = new go.Map();
diagram.selection.each(function (part) {
if (part.layer !== null) layers.set(part.layer, 0);
});
// find the maximum zOrder in each Layer
layers.iteratorKeys.each(function (layer) {
let max = 0;
layer.parts.each(function (part) {
if (part.isSelected) return;
const z = part.zOrder;
if (isNaN(z)) {
part.zOrder = 0;
} else {
max = Math.max(max, z);
}
});
layers.set(layer, max);
});
// assign each selected Part.zOrder to the computed value for each Layer
diagram.selection.each(function (part) {
const z = layers.get(part.layer) || 0;
DrawCommandHandler._assignZOrder(part, z + 1);
});
diagram.commitTransaction('pullToFront');
}
/**
* Change the z-ordering of selected parts to push them backward, behind of all other parts in
* their respective layers. All unselected parts in each layer with a selected Part with a
* non-numeric {@link Part#zOrder} will get a zOrder of zero.
*
* @this {DrawCommandHandler}
*/
pushToBack() {
const diagram = this.diagram;
diagram.startTransaction('pushToBack');
// find the affected Layers
const layers = new go.Map();
diagram.selection.each(function (part) {
if (part.layer !== null) layers.set(part.layer, 0);
});
// find the minimum zOrder in each Layer
layers.iteratorKeys.each(function (layer) {
let min = 0;
layer.parts.each(function (part) {
if (part.isSelected) return;
const z = part.zOrder;
if (isNaN(z)) {
part.zOrder = 0;
} else {
min = Math.min(min, z);
}
});
layers.set(layer, min);
});
// assign each selected Part.zOrder to the computed value for each Layer
diagram.selection.each(function (part) {
const z = layers.get(part.layer) || 0;
DrawCommandHandler._assignZOrder(
part,
// make sure a group's nested nodes are also behind everything else
z - 1 - DrawCommandHandler._findGroupDepth(part),
);
});
diagram.commitTransaction('pushToBack');
}
static _assignZOrder(part, z, root) {
if (root === undefined) root = part;
if (part.layer === root.layer) part.zOrder = z;
if (part instanceof go.Group) {
part.memberParts.each(function (m) {
DrawCommandHandler._assignZOrder(m, z + 1, root);
});
}
}
static _findGroupDepth(part) {
if (part instanceof go.Group) {
let d = 0;
part.memberParts.each(function (m) {
d = Math.max(d, DrawCommandHandler._findGroupDepth(m));
});
return d + 1;
} else {
return 0;
}
}
/**
* This implements custom behaviors for arrow key keyboard events. Set {@link #arrowKeyBehavior}
* to "select", "move" (the default), "scroll" (the standard behavior), or "none" to affect the
* behavior when the user types an arrow key.
*/
doKeyDown() {
const diagram = this.diagram;
const e = diagram.lastInput;
// determines the function of the arrow keys
if (e.key === 'Up' || e.key === 'Down' || e.key === 'Left' || e.key === 'Right') {
const behavior = this.arrowKeyBehavior;
if (behavior === 'none') {
// no-op
return;
} else if (behavior === 'select') {
this._arrowKeySelect();
return;
} else if (behavior === 'move') {
this._arrowKeyMove();
return;
}
// otherwise drop through to get the default scrolling behavior
}
// otherwise still does all standard commands
super.doKeyDown();
}
/** Collects in an Array all of the non-Link Parts currently in the Diagram. */
_getAllParts() {
const allParts = new Array();
this.diagram.nodes.each((node) => {
allParts.push(node);
});
this.diagram.parts.each((part) => {
allParts.push(part);
});
// note that this ignores Links
return allParts;
}
/** To be called when arrow keys should move the Diagram.selection. */
_arrowKeyMove() {
const diagram = this.diagram;
const e = diagram.lastInput;
// moves all selected parts in the specified direction
let vdistance = 0;
let hdistance = 0;
// if control is being held down, move pixel by pixel. Else, moves by grid cell size
if (e.control || e.meta) {
vdistance = 1;
hdistance = 1;
} else if (diagram.grid !== null) {
const cellsize = diagram.grid.gridCellSize;
hdistance = cellsize.width;
vdistance = cellsize.height;
}
diagram.startTransaction('arrowKeyMove');
diagram.selection.each((part) => {
if (e.key === 'Up') {
part.move(new go.Point(part.actualBounds.x, part.actualBounds.y - vdistance));
} else if (e.key === 'Down') {
part.move(new go.Point(part.actualBounds.x, part.actualBounds.y + vdistance));
} else if (e.key === 'Left') {
part.move(new go.Point(part.actualBounds.x - hdistance, part.actualBounds.y));
} else if (e.key === 'Right') {
part.move(new go.Point(part.actualBounds.x + hdistance, part.actualBounds.y));
}
});
diagram.commitTransaction('arrowKeyMove');
}
/** To be called when arrow keys should change selection. */
_arrowKeySelect() {
const diagram = this.diagram;
const e = diagram.lastInput;
// with a part selected, arrow keys change the selection
// arrow keys + shift selects the additional part in the specified direction
// arrow keys + control toggles the selection of the additional part
let nextPart = null;
if (e.key === 'Up') {
nextPart = this._findNearestPartTowards(270);
} else if (e.key === 'Down') {
nextPart = this._findNearestPartTowards(90);
} else if (e.key === 'Left') {
nextPart = this._findNearestPartTowards(180);
} else if (e.key === 'Right') {
nextPart = this._findNearestPartTowards(0);
}
if (nextPart !== null) {
if (e.shift) {
nextPart.isSelected = true;
} else if (e.control || e.meta) {
nextPart.isSelected = !nextPart.isSelected;
} else {
diagram.select(nextPart);
}
}
}
/**
* Finds the nearest Part in the specified direction, based on their center points. if it
* doesn't find anything, it just returns the current Part.
*
* @param {number} dir The direction, in degrees
* @returns {Part} The closest Part found in the given direction
*/
_findNearestPartTowards(dir) {
const originalPart = this.diagram.selection.first();
if (originalPart === null) return null;
const originalPoint = originalPart.actualBounds.center;
const allParts = this._getAllParts();
let closestDistance = Infinity;
let closest = originalPart; // if no parts meet the criteria, the same part remains selected
for (let i = 0; i < allParts.length; i++) {
const nextPart = allParts[i];
if (nextPart === originalPart) continue; // skips over currently selected part
const nextPoint = nextPart.actualBounds.center;
const angle = originalPoint.directionPoint(nextPoint);
const anglediff = this._angleCloseness(angle, dir);
if (anglediff <= 45) {
// if this part's center is within the desired direction's sector,
let distance = originalPoint.distanceSquaredPoint(nextPoint);
distance *= 1 + Math.sin((anglediff * Math.PI) / 180); // the more different from the intended angle, the further it is
if (distance < closestDistance) {
// and if it's closer than any other part,
closestDistance = distance; // remember it as a better choice
closest = nextPart;
}
}
}
return closest;
}
_angleCloseness(a, dir) {
return Math.min(Math.abs(dir - a), Math.min(Math.abs(dir + 360 - a), Math.abs(dir - 360 - a)));
}
/**
* Reset the last offset for pasting.
*
* @param {Iterable<Part>} coll A collection of {@link Part}s.
*/
copyToClipboard(coll) {
super.copyToClipboard(coll);
this._lastPasteOffset.set(this.pasteOffset);
}
/**
* Paste from the clipboard with an offset incremented on each paste, and reset when copied.
*
* @returns {Set<Part>} A collection of newly pasted {@link Part}s
*/
pasteFromClipboard() {
const coll = super.pasteFromClipboard();
this.diagram.moveParts(coll, this._lastPasteOffset, false);
this._lastPasteOffset.add(this.pasteOffset);
return coll;
}
}
This source diff could not be displayed because it is too large. You can view the blob instead.
/*
* Copyright (C) 1998-2021 by Northwoods Software Corporation. All Rights Reserved.
*/
/*
* This is an extension and not part of the main GoJS library.
* Note that the API for this class may change with any version, even point releases.
* If you intend to use an extension in production, you should copy the code to your own source directory.
* Extensions can be found in the GoJS kit under the extensions or extensionsTS folders.
* See the Extensions intro page (https://gojs.net/latest/intro/extensions.html) for more information.
*/
import * as go from './go.js';
/**
* The GuidedDraggingTool class makes guidelines visible as the parts are dragged around a diagram
* when the selected part is nearly aligned with another part.
*
* If you want to experiment with this extension, try the <a
* href="../../extensionsTS/GuidedDragging.html">Guided Dragging</a> sample.
*
* @category Tool Extension
*/
export default class GuidedDraggingTool extends go.DraggingTool {
/** Constructs a GuidedDraggingTool and sets up the temporary guideline parts. */
constructor() {
super();
// properties that the programmer can modify
this._guidelineSnapDistance = 6;
this._isGuidelineEnabled = true;
this._horizontalGuidelineColor = 'gray';
this._verticalGuidelineColor = 'gray';
this._centerGuidelineColor = 'gray';
this._guidelineWidth = 1;
this._searchDistance = 1000;
this._isGuidelineSnapEnabled = true;
const partProperties = { layerName: 'Tool', isInDocumentBounds: false };
const shapeProperties = { stroke: 'gray', isGeometryPositioned: true };
const $ = go.GraphObject.make;
// temporary parts for horizonal guidelines
this.guidelineHtop = $(
go.Part,
partProperties,
$(go.Shape, shapeProperties, { geometryString: 'M0 0 100 0' }),
);
this.guidelineHbottom = $(
go.Part,
partProperties,
$(go.Shape, shapeProperties, { geometryString: 'M0 0 100 0' }),
);
this.guidelineHcenter = $(
go.Part,
partProperties,
$(go.Shape, shapeProperties, { geometryString: 'M0 0 100 0' }),
);
// temporary parts for vertical guidelines
this.guidelineVleft = $(
go.Part,
partProperties,
$(go.Shape, shapeProperties, { geometryString: 'M0 0 0 100' }),
);
this.guidelineVright = $(
go.Part,
partProperties,
$(go.Shape, shapeProperties, { geometryString: 'M0 0 0 100' }),
);
this.guidelineVcenter = $(
go.Part,
partProperties,
$(go.Shape, shapeProperties, { geometryString: 'M0 0 0 100' }),
);
}
/**
* Gets or sets the margin of error for which guidelines show up.
*
* The default value is 6. Guidelines will show up when the aligned nods are ± 6px away from
* perfect alignment.
*/
get guidelineSnapDistance() {
return this._guidelineSnapDistance;
}
set guidelineSnapDistance(val) {
if (typeof val !== 'number' || isNaN(val) || val < 0)
throw new Error(
'new value for GuideddraggingTool.guidelineSnapDistance must be a non-negative number',
);
if (this._guidelineSnapDistance !== val) {
this._guidelineSnapDistance = val;
}
}
/**
* Gets or sets whether the guidelines are enabled or disable.
*
* The default value is true.
*/
get isGuidelineEnabled() {
return this._isGuidelineEnabled;
}
set isGuidelineEnabled(val) {
if (typeof val !== 'boolean')
throw new Error(
'new value for GuidedDraggingTool.isGuidelineEnabled must be a boolean value.',
);
if (this._isGuidelineEnabled !== val) {
this._isGuidelineEnabled = val;
}
}
/**
* Gets or sets the color of horizontal guidelines.
*
* The default value is "gray".
*/
get horizontalGuidelineColor() {
return this._horizontalGuidelineColor;
}
set horizontalGuidelineColor(val) {
if (this._horizontalGuidelineColor !== val) {
this._horizontalGuidelineColor = val;
this.guidelineHbottom.elements.first().stroke = this._horizontalGuidelineColor;
this.guidelineHtop.elements.first().stroke = this._horizontalGuidelineColor;
}
}
/**
* Gets or sets the color of vertical guidelines.
*
* The default value is "gray".
*/
get verticalGuidelineColor() {
return this._verticalGuidelineColor;
}
set verticalGuidelineColor(val) {
if (this._verticalGuidelineColor !== val) {
this._verticalGuidelineColor = val;
this.guidelineVleft.elements.first().stroke = this._verticalGuidelineColor;
this.guidelineVright.elements.first().stroke = this._verticalGuidelineColor;
}
}
/**
* Gets or sets the color of center guidelines.
*
* The default value is "gray".
*/
get centerGuidelineColor() {
return this._centerGuidelineColor;
}
set centerGuidelineColor(val) {
if (this._centerGuidelineColor !== val) {
this._centerGuidelineColor = val;
this.guidelineVcenter.elements.first().stroke = this._centerGuidelineColor;
this.guidelineHcenter.elements.first().stroke = this._centerGuidelineColor;
}
}
/**
* Gets or sets the width guidelines.
*
* The default value is 1.
*/
get guidelineWidth() {
return this._guidelineWidth;
}
set guidelineWidth(val) {
if (typeof val !== 'number' || isNaN(val) || val < 0)
throw new Error(
'New value for GuidedDraggingTool.guidelineWidth must be a non-negative number.',
);
if (this._guidelineWidth !== val) {
this._guidelineWidth = val;
this.guidelineVcenter.elements.first().strokeWidth = val;
this.guidelineHcenter.elements.first().strokeWidth = val;
this.guidelineVleft.elements.first().strokeWidth = val;
this.guidelineVright.elements.first().strokeWidth = val;
this.guidelineHbottom.elements.first().strokeWidth = val;
this.guidelineHtop.elements.first().strokeWidth = val;
}
}
/**
* Gets or sets the distance around the selected part to search for aligned parts.
*
* The default value is 1000. Set this to Infinity if you want to search the entire diagram no
* matter how far away.
*/
get searchDistance() {
return this._searchDistance;
}
set searchDistance(val) {
if (typeof val !== 'number' || isNaN(val) || val <= 0)
throw new Error('new value for GuidedDraggingTool.searchDistance must be a positive number.');
if (this._searchDistance !== val) {
this._searchDistance = val;
}
}
/**
* Gets or sets whether snapping to guidelines is enabled.
*
* The default value is true.
*/
get isGuidelineSnapEnabled() {
return this._isGuidelineSnapEnabled;
}
set isGuidelineSnapEnabled(val) {
if (typeof val !== 'boolean')
throw new Error('new value for GuidedDraggingTool.isGuidelineSnapEnabled must be a boolean.');
if (this._isGuidelineSnapEnabled !== val) {
this._isGuidelineSnapEnabled = val;
}
}
/** Removes all of the guidelines from the grid. */
clearGuidelines() {
this.diagram.remove(this.guidelineHbottom);
this.diagram.remove(this.guidelineHcenter);
this.diagram.remove(this.guidelineHtop);
this.diagram.remove(this.guidelineVleft);
this.diagram.remove(this.guidelineVright);
this.diagram.remove(this.guidelineVcenter);
}
/** Calls the base method and removes the guidelines from the graph. */
doDeactivate() {
super.doDeactivate();
// clear any guidelines when dragging is done
this.clearGuidelines();
}
/** Shows vertical and horizontal guidelines for the dragged part. */
doDragOver(pt, obj) {
// clear all existing guidelines in case either show... method decides to show a guideline
this.clearGuidelines();
// gets the selected part
const draggingParts = this.copiedParts || this.draggedParts;
if (draggingParts === null) return;
const partItr = draggingParts.iterator;
if (partItr.next()) {
const part = partItr.key;
this.showHorizontalMatches(part, this.isGuidelineEnabled, false);
this.showVerticalMatches(part, this.isGuidelineEnabled, false);
}
}
/**
* On a mouse-up, snaps the selected part to the nearest guideline. If not snapping, the part
* remains at its position.
*/
doDropOnto(pt, obj) {
this.clearGuidelines();
// gets the selected (perhaps copied) Part
const draggingParts = this.copiedParts || this.draggedParts;
if (draggingParts === null) return;
const partItr = draggingParts.iterator;
if (partItr.next()) {
const part = partItr.key;
// snaps only when the mouse is released without shift modifier
const e = this.diagram.lastInput;
const snap = this.isGuidelineSnapEnabled && !e.shift;
this.showHorizontalMatches(part, false, snap); // false means don't show guidelines
this.showVerticalMatches(part, false, snap);
}
}
/**
* When nodes are shifted due to being guided upon a drop, make sure all connected link routes
* are invalidated, since the node is likely to have moved a different amount than all its
* connected links in the regular operation of the DraggingTool.
*/
invalidateLinks(node) {
if (node instanceof go.Node) node.invalidateConnectedLinks();
}
/**
* This predicate decides whether or not the given Part should guide the dragged part.
*
* @param {Part} part A stationary Part to which the dragged part might be aligned
* @param {Part} guidedpart The Part being dragged
*/
isGuiding(part, guidedpart) {
return (
part instanceof go.Part &&
!part.isSelected &&
!(part instanceof go.Link) &&
guidedpart instanceof go.Part &&
part.containingGroup === guidedpart.containingGroup &&
part.layer !== null &&
!part.layer.isTemporary
);
}
/**
* This finds parts that are aligned near the selected part along horizontal lines. It compares
* the selected part to all parts within a rectangle approximately twice the {@link
* #searchDistance} wide. The guidelines appear when a part is aligned within a margin-of-error
* equal to {@link #guidelineSnapDistance}.
*
* @param {Node} part
* @param {boolean} guideline If true, show guideline
* @param {boolean} snap If true, snap the part to where the guideline would be
*/
showHorizontalMatches(part, guideline, snap) {
const objBounds = part.locationObject.getDocumentBounds();
const p0 = objBounds.y;
const p1 = objBounds.y + objBounds.height / 2;
const p2 = objBounds.y + objBounds.height;
const marginOfError = this.guidelineSnapDistance;
const distance = this.searchDistance;
// compares with parts within narrow vertical area
const area = objBounds.copy();
area.inflate(distance, marginOfError + 1);
const otherObjs = this.diagram.findObjectsIn(
area,
(obj) => obj.part,
(p) => this.isGuiding(p, part),
true,
);
let bestDiff = marginOfError;
let bestObj = null; // TS 2.6 won't let this be go.Part | null
let bestSpot = go.Spot.Default;
let bestOtherSpot = go.Spot.Default;
// horizontal line -- comparing y-values
otherObjs.each((other) => {
if (other === part) return; // ignore itself
const otherBounds = other.locationObject.getDocumentBounds();
const q0 = otherBounds.y;
const q1 = otherBounds.y + otherBounds.height / 2;
const q2 = otherBounds.y + otherBounds.height;
// compare center with center of OTHER part
if (Math.abs(p1 - q1) < bestDiff) {
bestDiff = Math.abs(p1 - q1);
bestObj = other;
bestSpot = go.Spot.Center;
bestOtherSpot = go.Spot.Center;
}
// compare top side with top and bottom sides of OTHER part
if (Math.abs(p0 - q0) < bestDiff) {
bestDiff = Math.abs(p0 - q0);
bestObj = other;
bestSpot = go.Spot.Top;
bestOtherSpot = go.Spot.Top;
} else if (Math.abs(p0 - q2) < bestDiff) {
bestDiff = Math.abs(p0 - q2);
bestObj = other;
bestSpot = go.Spot.Top;
bestOtherSpot = go.Spot.Bottom;
}
// compare bottom side with top and bottom sides of OTHER part
if (Math.abs(p2 - q0) < bestDiff) {
bestDiff = Math.abs(p2 - q0);
bestObj = other;
bestSpot = go.Spot.Bottom;
bestOtherSpot = go.Spot.Top;
} else if (Math.abs(p2 - q2) < bestDiff) {
bestDiff = Math.abs(p2 - q2);
bestObj = other;
bestSpot = go.Spot.Bottom;
bestOtherSpot = go.Spot.Bottom;
}
});
if (bestObj !== null) {
const offsetX = objBounds.x - part.actualBounds.x;
const offsetY = objBounds.y - part.actualBounds.y;
const bestBounds = bestObj.locationObject.getDocumentBounds();
// line extends from x0 to x2
const x0 = Math.min(objBounds.x, bestBounds.x) - 10;
const x2 = Math.max(objBounds.x + objBounds.width, bestBounds.x + bestBounds.width) + 10;
// find bestObj's desired Y
const bestPoint = new go.Point().setRectSpot(bestBounds, bestOtherSpot);
if (bestSpot === go.Spot.Center) {
if (snap) {
// call Part.move in order to automatically move member Parts of Groups
part.move(
new go.Point(objBounds.x - offsetX, bestPoint.y - objBounds.height / 2 - offsetY),
);
this.invalidateLinks(part);
}
if (guideline) {
this.guidelineHcenter.position = new go.Point(x0, bestPoint.y);
this.guidelineHcenter.elt(0).width = x2 - x0;
this.diagram.add(this.guidelineHcenter);
}
} else if (bestSpot === go.Spot.Top) {
if (snap) {
part.move(new go.Point(objBounds.x - offsetX, bestPoint.y - offsetY));
this.invalidateLinks(part);
}
if (guideline) {
this.guidelineHtop.position = new go.Point(x0, bestPoint.y);
this.guidelineHtop.elt(0).width = x2 - x0;
this.diagram.add(this.guidelineHtop);
}
} else if (bestSpot === go.Spot.Bottom) {
if (snap) {
part.move(new go.Point(objBounds.x - offsetX, bestPoint.y - objBounds.height - offsetY));
this.invalidateLinks(part);
}
if (guideline) {
this.guidelineHbottom.position = new go.Point(x0, bestPoint.y);
this.guidelineHbottom.elt(0).width = x2 - x0;
this.diagram.add(this.guidelineHbottom);
}
}
}
}
/**
* This finds parts that are aligned near the selected part along vertical lines. It compares
* the selected part to all parts within a rectangle approximately twice the {@link
* #searchDistance} tall. The guidelines appear when a part is aligned within a margin-of-error
* equal to {@link #guidelineSnapDistance}.
*
* @param {Part} part
* @param {boolean} guideline If true, show guideline
* @param {boolean} snap If true, don't show guidelines but just snap the part to where the
* guideline would be
*/
showVerticalMatches(part, guideline, snap) {
const objBounds = part.locationObject.getDocumentBounds();
const p0 = objBounds.x;
const p1 = objBounds.x + objBounds.width / 2;
const p2 = objBounds.x + objBounds.width;
const marginOfError = this.guidelineSnapDistance;
const distance = this.searchDistance;
// compares with parts within narrow vertical area
const area = objBounds.copy();
area.inflate(marginOfError + 1, distance);
const otherObjs = this.diagram.findObjectsIn(
area,
(obj) => obj.part,
(p) => this.isGuiding(p, part),
true,
);
let bestDiff = marginOfError;
let bestObj = null; // TS 2.6 won't let this be go.Part | null
let bestSpot = go.Spot.Default;
let bestOtherSpot = go.Spot.Default;
// vertical line -- comparing x-values
otherObjs.each((other) => {
if (other === part) return; // ignore itself
const otherBounds = other.locationObject.getDocumentBounds();
const q0 = otherBounds.x;
const q1 = otherBounds.x + otherBounds.width / 2;
const q2 = otherBounds.x + otherBounds.width;
// compare center with center of OTHER part
if (Math.abs(p1 - q1) < bestDiff) {
bestDiff = Math.abs(p1 - q1);
bestObj = other;
bestSpot = go.Spot.Center;
bestOtherSpot = go.Spot.Center;
}
// compare left side with left and right sides of OTHER part
if (Math.abs(p0 - q0) < bestDiff) {
bestDiff = Math.abs(p0 - q0);
bestObj = other;
bestSpot = go.Spot.Left;
bestOtherSpot = go.Spot.Left;
} else if (Math.abs(p0 - q2) < bestDiff) {
bestDiff = Math.abs(p0 - q2);
bestObj = other;
bestSpot = go.Spot.Left;
bestOtherSpot = go.Spot.Right;
}
// compare right side with left and right sides of OTHER part
if (Math.abs(p2 - q0) < bestDiff) {
bestDiff = Math.abs(p2 - q0);
bestObj = other;
bestSpot = go.Spot.Right;
bestOtherSpot = go.Spot.Left;
} else if (Math.abs(p2 - q2) < bestDiff) {
bestDiff = Math.abs(p2 - q2);
bestObj = other;
bestSpot = go.Spot.Right;
bestOtherSpot = go.Spot.Right;
}
});
if (bestObj !== null) {
const offsetX = objBounds.x - part.actualBounds.x;
const offsetY = objBounds.y - part.actualBounds.y;
const bestBounds = bestObj.locationObject.getDocumentBounds();
// line extends from y0 to y2
const y0 = Math.min(objBounds.y, bestBounds.y) - 10;
const y2 = Math.max(objBounds.y + objBounds.height, bestBounds.y + bestBounds.height) + 10;
// find bestObj's desired X
const bestPoint = new go.Point().setRectSpot(bestBounds, bestOtherSpot);
if (bestSpot === go.Spot.Center) {
if (snap) {
// call Part.move in order to automatically move member Parts of Groups
part.move(
new go.Point(bestPoint.x - objBounds.width / 2 - offsetX, objBounds.y - offsetY),
);
this.invalidateLinks(part);
}
if (guideline) {
this.guidelineVcenter.position = new go.Point(bestPoint.x, y0);
this.guidelineVcenter.elt(0).height = y2 - y0;
this.diagram.add(this.guidelineVcenter);
}
} else if (bestSpot === go.Spot.Left) {
if (snap) {
part.move(new go.Point(bestPoint.x - offsetX, objBounds.y - offsetY));
this.invalidateLinks(part);
}
if (guideline) {
this.guidelineVleft.position = new go.Point(bestPoint.x, y0);
this.guidelineVleft.elt(0).height = y2 - y0;
this.diagram.add(this.guidelineVleft);
}
} else if (bestSpot === go.Spot.Right) {
if (snap) {
part.move(new go.Point(bestPoint.x - objBounds.width - offsetX, objBounds.y - offsetY));
this.invalidateLinks(part);
}
if (guideline) {
this.guidelineVright.position = new go.Point(bestPoint.x, y0);
this.guidelineVright.elt(0).height = y2 - y0;
this.diagram.add(this.guidelineVright);
}
}
}
}
}
function TopRotatingTool() {
go.RotatingTool.call(this);
}
go.Diagram.inherit(TopRotatingTool, go.RotatingTool);
/** @override */
TopRotatingTool.prototype.updateAdornments = function (part) {
go.RotatingTool.prototype.updateAdornments.call(this, part);
var adornment = part.findAdornment('Rotating');
if (adornment !== null) {
adornment.location = part.rotateObject.getDocumentPoint(new go.Spot(0.5, 0, 0, -30)); // above middle top
}
};
/** @override */
TopRotatingTool.prototype.rotate = function (newangle) {
go.RotatingTool.prototype.rotate.call(this, newangle + 90);
};
// end of TopRotatingTool class
export default TopRotatingTool;
class WaterFlowControlView {
constructor(options) {
this.linkDataArray = [];
this.browserArray = [];
this.hBarArray = [];
this.allClose = [];
this.myDiagram = null;
}
/** 获取处理好的json************************************************* */
waterFlowControlByDiagramJson(oldJson, myDiagrams) {
this.myDiagram = myDiagrams;
this.hBarArray = this.getAllNodeByCategory('HBar');
if (!this.hBarArray.length) return null;
let newnodeDataArray = JSON.parse(this.myDiagram.model.toJson()).nodeDataArray;
this.newJson = JSON.parse(this.myDiagram.model.toJson());
let oldnodeDataArray = oldJson.nodeDataArray;
let _oldControlArray = oldnodeDataArray.filter(function (item) {
return item.switch == '是' && item.category != 'switchCase';
});
let _newControlArray = newnodeDataArray.filter(function (item) {
return item.switch == '是' && item.category != 'switchCase' && item.realVal != '--';
});
let diffentArr = this.diffent(_oldControlArray, _newControlArray, 'key', 'switchState');
if (!diffentArr.length) return null;
this.linkDataArray = JSON.parse(this.myDiagram.model.toJson()).linkDataArray;
this.flag = false;
for (let j = 0; j < newnodeDataArray.length; j++) {
if (
newnodeDataArray[j].switch == '是' &&
newnodeDataArray[j].category != 'switchCase' &&
oldnodeDataArray[j].switchState &&
newnodeDataArray[j].realVal != '--'
) {
//代表控制属性值有修改
this.flag = true;
let controlValue = newnodeDataArray[j].switchState;
let isHavingDash = controlValue == '开' ? true : false;
let key = newnodeDataArray[j].key;
this.browserArray = [];
this.browserArray.push(key);
this.changWaterFlow(key, isHavingDash);
//判断此条线路上面是否还有其他的控制开关
let otherControl = false;
for (let k = 0; k < newnodeDataArray.length; k++) {
for (let i = 1; i < this.browserArray.length; i++) {
if (
newnodeDataArray[k].key == this.browserArray[i] &&
newnodeDataArray[k].switchState == '关' &&
controlValue == '开'
) {
otherControl = true;
break;
}
}
}
if (!otherControl) {
this.newJson.linkDataArray = this.linkDataArray;
//如果从全关状态下 开启摸个按钮
this.hBarArray.map((obj, index) => {
if (obj == key) {
// 合管和状态管是同一个元器件
this.allClose[index] = isHavingDash;
for (let temp of this.newJson.linkDataArray) {
if (temp.from == obj) {
this.browserArray = [];
this.browserArray.push(temp.to);
this.changWaterFlow(temp.to, isHavingDash);
this.newJson.linkDataArray = this.linkDataArray;
}
if (temp.to == obj) {
this.browserArray = [];
this.browserArray.push(temp.from);
this.changWaterFlow(temp.from, isHavingDash);
this.newJson.linkDataArray = this.linkDataArray;
}
}
} else if (this.allClose[index] && controlValue == '开') {
//合管周边管子水流开启
this.allClose[index] = false; //现在不是全部关闭
if (this.isIn(obj, key)) {
for (let temp of this.newJson.linkDataArray) {
if (temp.from == obj) {
this.browserArray = [];
this.browserArray.push(temp.to);
this.changWaterFlow(temp.to, isHavingDash);
this.newJson.linkDataArray = this.linkDataArray;
}
}
} else if (this.isOut(obj, key)) {
for (let temp of this.newJson.linkDataArray) {
if (temp.to == obj) {
this.browserArray = [];
this.browserArray.push(temp.from);
this.changWaterFlow(temp.from, isHavingDash);
this.newJson.linkDataArray = this.linkDataArray;
}
}
}
}
});
}
}
}
if (!this.flag) {
return null;
}
//判断合节点的连接个数
let te = [];
this.hBarArray.map((data) => {
te.push(data);
});
for (let z = 0; z < te.length; z++) {
let key = te[z];
let open = 0;
let close = 0;
let inArray = [];
let outArray = [];
this._hBarArray = this.hBarArray.concat();
delete this._hBarArray[z];
for (let temp of this.newJson.linkDataArray) {
if (temp.from == key) inArray.push(temp);
if (temp.to == key) outArray.push(temp);
}
//全部关闭
let inarrTemp = inArray.filter((obj) => {
return obj.isHavingDash == false;
});
if (inarrTemp.length == inArray.length && inArray.length != 0) {
this.browserArray = [];
this.browserArray.push(key);
this.changWaterFlow(key, false, this._hBarArray);
this.newJson.linkDataArray = this.linkDataArray;
this.allClose[z] = true;
}
let outarrTemp = outArray.filter((obj) => {
return obj.isHavingDash == false;
});
if (outarrTemp.length == outArray.length && outArray.length != 0) {
this.browserArray = [];
this.browserArray.push(key);
this.changWaterFlow(key, false, this._hBarArray);
this.newJson.linkDataArray = this.linkDataArray;
this.allClose[z] = true;
}
}
this.newJson.nodeDataArray.forEach(
function (item) {
for (let i = 0; i < te.length; i++) {
if (item.key == te[i]) {
item.typeDash = this.allClose[i];
return false;
}
}
}.bind(this),
);
return this.newJson;
}
/** 获取所有合管id************************************************* */
getAllNodeByCategory(category) {
let nodeDataArray = JSON.parse(this.myDiagram.model.toJson()).nodeDataArray;
let retVal = [];
for (let j = 0; j < nodeDataArray.length; j++) {
if (
nodeDataArray[j].category == category ||
(nodeDataArray[j].hbControl && nodeDataArray[j].hbControl == '是')
) {
retVal.push(nodeDataArray[j].key);
if (this.allClose[retVal.length - 1] == undefined) this.allClose.push(false);
}
}
return retVal;
}
/***/
changWaterFlow(key, isHavingDash, hBarArray) {
hBarArray = hBarArray ? hBarArray : this.hBarArray.concat();
if (this.isInArray(hBarArray, key)) {
//判断key是否是合管
return;
}
for (let j = 0; j < this.linkDataArray.length; j++) {
let temp = this.linkDataArray[j];
if (temp.from == key && temp.from != temp.to) {
this.linkDataArray[j].isHavingDash = isHavingDash;
if (!this.isInArray(this.browserArray, temp.to)) {
this.browserArray.push(temp.to);
this.changWaterFlow(temp.to, isHavingDash, hBarArray);
}
} else if (temp.to == key && temp.to != temp.from) {
this.linkDataArray[j].isHavingDash = isHavingDash;
if (!this.isInArray(this.browserArray, temp.from)) {
this.browserArray.push(temp.from);
this.changWaterFlow(temp.from, isHavingDash, hBarArray);
}
}
}
}
/***/
isInArray(array, key) {
let retValue = false;
for (let j = 0; j < array.length; j++) {
if (array[j] == key) {
retValue = true;
break;
}
}
return retValue;
}
isIn(hBarKey, nodeKey) {
let val = false;
if (hBarKey == nodeKey) {
//判断key是否是合管
val = true;
return val;
}
for (let j = 0; j < this.linkDataArray.length; j++) {
let temp = this.linkDataArray[j];
if (temp.from && temp.from == nodeKey && temp.from != temp.to) {
val = val == true ? true : this.isIn(hBarKey, temp.to);
}
}
return val;
}
isOut(hBarKey, nodeKey) {
let val = false;
if (hBarKey == nodeKey) {
//判断key是否是合管
val = true;
return val;
}
for (let j = 0; j < this.linkDataArray.length; j++) {
let temp = this.linkDataArray[j];
if (temp.to && temp.to == nodeKey && temp.to != temp.from) {
val = val == true ? true : this.isOut(hBarKey, temp.from);
}
}
return val;
}
diffent(fArr, cArr, key, field) {
let diffRes = [];
let fDatas = [];
let cDatas = [];
for (let i in fArr) {
let flg = false;
for (let j in cArr) {
if (cArr[j][key] === fArr[i][key] && cArr[j][field] === fArr[i][field]) {
flg = true;
break;
}
}
if (!flg) {
fDatas.push(fArr[i]);
}
}
for (let i in cArr) {
let flg = false;
for (let j in fArr) {
if (fArr[j][field] === cArr[i][field] && fArr[j][field] === cArr[i][field]) {
flg = true;
break;
}
}
if (!flg) {
cDatas.push(cArr[i]);
}
}
diffRes.push(...cDatas.concat(fDatas));
return diffRes;
}
}
export default WaterFlowControlView;
No preview for this file type
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