Commit 01bb7bfae33c4cd24f78c4bd916d4cef84a4fdb3

Authored by xp.Huang
2 parents 30353c89 1951f17a

Merge branch 'ww' into 'main'

feat: hidden file menu && hidden share button && add preview button && del test components

See merge request huang/thingskit-drawio!12

Too many changes to show.

To preserve performance only 10 of 14 files are displayed.

... ... @@ -16,6 +16,9 @@
16 16 <meta name="msapplication-config" content="images/browserconfig.xml">
17 17 <meta name="mobile-web-app-capable" content="yes">
18 18 <meta name="theme-color" content="#d89000">
  19 + <!-- 全局变量 -->
  20 + <script src="./js/const/const.js"></script>
  21 +
19 22 <script src="./plugins/axios.min.js"></script>
20 23 <!-- <script src="./js/jquery/jquery-3.3.1.min.js"></script>-->
21 24 <!-- <script src="./js/jquery.easyui.min.js"></script>-->
... ... @@ -32,11 +35,14 @@
32 35 <!-- <script type="text/javascript" src="./js/jquery.ztree.exhide.min.js"></script>-->
33 36 <!-- <script type="text/javascript" src="./js/jquery.select.zTree.v1.5.min.js"></script>-->
34 37
35   -<!-- Axios -->
  38 + <!-- Axios -->
36 39 <script src="./plugins/defHttp.js"></script>
37 40
38 41 <script src="./js/api/index.js"></script>
39 42
  43 + <!-- act editor -->
  44 + <script src="./js/plugin/ace/ace.js"></script>
  45 +
40 46 <script type="text/javascript">
41 47 /**
42 48 * URL Parameters and protocol description are here:
... ...
... ... @@ -5,7 +5,7 @@ class ConfigurationNodeApi {
5 5 * @param {string} levelId - 组态资源ID
6 6 */
7 7 static getConfigurationInfo(levelType, levelId) {
8   - return defHttp.get(`/yt/configuration/node/${levelType}/${levelId}`)
  8 + return defHttp.get(`/yt/configuration/node/${ levelType }/${ levelId }`)
9 9 }
10 10
11 11 /**
... ... @@ -22,7 +22,7 @@ class ConfigurationNodeApi {
22 22 * @returns {Promise<*>}
23 23 */
24 24 static getDeviceAttr(tbDeviceId) {
25   - return defHttp.get(`/plugins/telemetry/DEVICE/${tbDeviceId}/keys/timeseries`)
  25 + return defHttp.get(`/plugins/telemetry/DEVICE/${ tbDeviceId }/keys/timeseries`)
26 26 }
27 27
28 28 /**
... ... @@ -32,7 +32,7 @@ class ConfigurationNodeApi {
32 32 * @returns {Promise<*>}
33 33 */
34 34 static getDeviceUnderTheOrg(deviceType, orgId) {
35   - return defHttp.get(`/yt/device/list/${deviceType}?organizationId=${orgId}`)
  35 + return defHttp.get(`/yt/device/list/${ deviceType }?organizationId=${ orgId }`)
36 36 }
37 37
38 38 /**
... ... @@ -41,7 +41,7 @@ class ConfigurationNodeApi {
41 41 * @returns {Promise<*>}
42 42 */
43 43 static getDeviceChildDevice(deviceId) {
44   - return defHttp.get(`/yt/device/relation?page=1&pageSize=10&fromId=${deviceId}`)
  44 + return defHttp.get(`/yt/device/relation?page=1&pageSize=10&fromId=${ deviceId }`)
45 45 }
46 46
47 47 /**
... ... @@ -50,7 +50,7 @@ class ConfigurationNodeApi {
50 50 * @returns {Promise<*>}
51 51 */
52 52 static getMasterDevice(orgId) {
53   - return defHttp.get(`/yt/device/list/master/${orgId}`)
  53 + return defHttp.get(`/yt/device/list/master/${ orgId }`)
54 54 }
55 55
56 56 /**
... ... @@ -60,7 +60,7 @@ class ConfigurationNodeApi {
60 60 * @returns {Promise<*>}
61 61 */
62 62 static getSlaveDevice(orgId, masterDeviceId) {
63   - return defHttp.get(`/yt/device/list/slave/${orgId}?masterId=${masterDeviceId}`)
  63 + return defHttp.get(`/yt/device/list/slave/${ orgId }?masterId=${ masterDeviceId }`)
64 64 }
65 65
66 66 /**
... ... @@ -72,8 +72,8 @@ class ConfigurationNodeApi {
72 72
73 73 /**
74 74 * @description 编辑动画效果
75   - * @param {*} data
76   - * @returns
  75 + * @param {*} data
  76 + * @returns
77 77 */
78 78 static updateNodeAct(data) {
79 79 return defHttp.post('/yt/configuration/node/act', data)
... ... @@ -81,13 +81,49 @@ class ConfigurationNodeApi {
81 81
82 82 /**
83 83 * @description 更新节点绑定信息
84   - * @param {*} data
85   - * @returns
  84 + * @param {*} data
  85 + * @returns
86 86 */
87 87 static updateNodeInfo(data) {
88 88 return defHttp.post('/yt/configuration/node', data)
89 89 }
90 90
  91 + /**
  92 + * @description 下发指令 单向
  93 + * @param {string} deviceId - tbDeviceId
  94 + * @param {object} data - 数据
  95 + */
  96 + static sendInstructionOneWay(deviceId, data) {
  97 + return defHttp.post(`/rpc/oneway/${ deviceId }`, data)
  98 + }
  99 +
  100 + /**
  101 + * @description 下发指令 单向
  102 + * @param {string} deviceId - tbDeviceId
  103 + * @param {object} data - 数据
  104 + */
  105 + static sendInstructionTwoWay(deviceId, data) {
  106 + return defHttp.post(`/rpc/twoway/${ deviceId }`, data)
  107 + }
  108 +
  109 + /**
  110 + * @description 下发指令
  111 + * @param {'oneway' | 'twoway'} way
  112 + * @param deviceId
  113 + * @param data
  114 + * @return {*}
  115 + */
  116 + static sendInstruction(way,deviceId, data) {
  117 + return defHttp.post(`/rpc/${way}/${ deviceId }`, data)
  118 + }
  119 +
  120 + /**
  121 + * @description 判断设备是否在线
  122 + * @param deviceId
  123 + * @return {*}
  124 + */
  125 + static deviceIsOnLine(deviceId){
  126 + return defHttp.get(`/plugins/telemetry/DEVICE/${deviceId}/values/attributes?keys=active`)
  127 + }
91 128
92   -
93 129 }
... ...
  1 +const GLOBAL_TOKEN = JSON.parse(localStorage.getItem("UNDEFINED__DEVELOPMENT__2.7.1__COMMON__LOCAL__KEY__")).value.JWT_TOKEN.value
  2 +
  3 +const GLOBAL_WS_URL = (() => {
  4 + const { host, href } = location
  5 + const reg = /^https/
  6 + return `${ reg.test(href) ? 'wss' : 'ws' }://${ host }/api/ws/plugins/telemetry?token=${GLOBAL_TOKEN}`
  7 +})()
  8 +
  9 +// const GLOBAL_WS_URL = `ws://47.99.141.212:8080/api/ws/plugins/telemetry?token=${ GLOBAL_TOKEN }`
\ No newline at end of file
... ...
... ... @@ -5839,41 +5839,62 @@ App.prototype.updateButtonContainer = function()
5839 5839 {
5840 5840 if (this.shareButton == null)
5841 5841 {
  5842 + // TODO 预览模式按钮
5842 5843 this.shareButton = document.createElement('div');
5843 5844 this.shareButton.className = 'geBtn gePrimaryBtn';
5844 5845 this.shareButton.style.display = 'inline-block';
5845 5846 this.shareButton.style.backgroundColor = '#F2931E';
5846 5847 this.shareButton.style.borderColor = '#F08705';
5847 5848 this.shareButton.style.backgroundImage = 'none';
5848   - this.shareButton.style.padding = '2px 10px 0 10px';
5849 5849 this.shareButton.style.marginTop = '-10px';
5850   - this.shareButton.style.height = '28px';
5851 5850 this.shareButton.style.lineHeight = '28px';
5852 5851 this.shareButton.style.minWidth = '0px';
5853 5852 this.shareButton.style.cssFloat = 'right';
5854   - this.shareButton.setAttribute('title', mxResources.get('share'));
5855   -
5856   - var icon = document.createElement('img');
5857   - icon.setAttribute('src', this.shareImage);
5858   - icon.setAttribute('align', 'absmiddle');
5859   - icon.style.marginRight = '4px';
5860   - icon.style.marginTop = '-3px';
5861   - this.shareButton.appendChild(icon);
5862   -
5863   - if (!Editor.isDarkMode() && uiTheme != 'atlas')
5864   - {
5865   - this.shareButton.style.color = 'black';
5866   - icon.style.filter = 'invert(100%)';
5867   - }
5868   -
5869   - mxUtils.write(this.shareButton, mxResources.get('share'));
5870   -
  5853 + this.shareButton.setAttribute('title', '预览');
  5854 + mxUtils.write(this.shareButton, '预览');
5871 5855 mxEvent.addListener(this.shareButton, 'click', mxUtils.bind(this, function()
5872 5856 {
5873   - this.actions.get('share').funct();
  5857 + const href = window.location.href + '&lightbox=1'
  5858 + window.open(href)
5874 5859 }));
5875   -
5876 5860 this.buttonContainer.appendChild(this.shareButton);
  5861 +
  5862 +
  5863 + // this.shareButton = document.createElement('div');
  5864 + // this.shareButton.className = 'geBtn gePrimaryBtn';
  5865 + // this.shareButton.style.display = 'inline-block';
  5866 + // this.shareButton.style.backgroundColor = '#F2931E';
  5867 + // this.shareButton.style.borderColor = '#F08705';
  5868 + // this.shareButton.style.backgroundImage = 'none';
  5869 + // this.shareButton.style.padding = '2px 10px 0 10px';
  5870 + // this.shareButton.style.marginTop = '-10px';
  5871 + // this.shareButton.style.height = '28px';
  5872 + // this.shareButton.style.lineHeight = '28px';
  5873 + // this.shareButton.style.minWidth = '0px';
  5874 + // this.shareButton.style.cssFloat = 'right';
  5875 + // this.shareButton.setAttribute('title', mxResources.get('share'));
  5876 + //
  5877 + // var icon = document.createElement('img');
  5878 + // icon.setAttribute('src', this.shareImage);
  5879 + // icon.setAttribute('align', 'absmiddle');
  5880 + // icon.style.marginRight = '4px';
  5881 + // icon.style.marginTop = '-3px';
  5882 + // this.shareButton.appendChild(icon);
  5883 + //
  5884 + // if (!Editor.isDarkMode() && uiTheme != 'atlas')
  5885 + // {
  5886 + // this.shareButton.style.color = 'black';
  5887 + // icon.style.filter = 'invert(100%)';
  5888 + // }
  5889 + //
  5890 + // mxUtils.write(this.shareButton, mxResources.get('share'));
  5891 + //
  5892 + // mxEvent.addListener(this.shareButton, 'click', mxUtils.bind(this, function()
  5893 + // {
  5894 + // this.actions.get('share').funct();
  5895 + // }));
  5896 + //
  5897 + // this.buttonContainer.appendChild(this.shareButton);
5877 5898 }
5878 5899 }
5879 5900 else if (this.shareButton != null)
... ...
... ... @@ -315,4 +315,6 @@ mxscript(drawDevUrl + 'js/diagramly/sidebar/thingskit/Sidebar-Engine.js');
315 315 mxscript(drawDevUrl + 'js/diagramly/sidebar/thingskit/Sidebar-Basic-Components.js');
316 316 mxscript(drawDevUrl + 'js/diagramly/sidebar/thingskit/Sidebar-Controller-Components.js');
317 317 mxscript(drawDevUrl + 'js/diagramly/sidebar/thingskit/Sidebar-Valve.js');
318   -mxscript(drawDevUrl + 'js/diagramly/sidebar/thingskit/Sidebar-Fan.js');
\ No newline at end of file
  318 +mxscript(drawDevUrl + 'js/diagramly/sidebar/thingskit/Sidebar-Fan.js');
  319 +
  320 +
... ...
... ... @@ -1203,46 +1203,47 @@
1203 1203 // in older browsers. URL param has precedence over the saved setting.
1204 1204 if (mxClient.IS_CHROMEAPP || isLocalStorage)
1205 1205 {
1206   - this.put('language', new Menu(mxUtils.bind(this, function(menu, parent)
1207   - {
1208   - var addLangItem = mxUtils.bind(this, function (id)
1209   - {
1210   - var lang = (id == '') ? mxResources.get('automatic') : mxLanguageMap[id];
1211   - var item = null;
1212   -
1213   - if (lang != '')
1214   - {
1215   - item = menu.addItem(lang, null, mxUtils.bind(this, function()
1216   - {
1217   - mxSettings.setLanguage(id);
1218   - mxSettings.save();
1219   -
1220   - // Shows dialog in new language
1221   - mxClient.language = id;
1222   - mxResources.loadDefaultBundle = false;
1223   - mxResources.add(RESOURCE_BASE);
1224   -
1225   - editorUi.alert(mxResources.get('restartForChangeRequired'));
1226   - }), parent);
1227   -
1228   - if (id == mxLanguage || (id == '' && mxLanguage == null))
1229   - {
1230   - menu.addCheckmark(item, Editor.checkmarkImage);
1231   - }
1232   - }
1233   -
1234   - return item;
1235   - });
1236   -
1237   - var item = addLangItem('');
1238   - menu.addSeparator(parent);
1239   -
1240   - // LATER: Sort menu by language name
1241   - for(var langId in mxLanguageMap)
1242   - {
1243   - addLangItem(langId);
1244   - }
1245   - })));
  1206 + // TODO switch language 切换语言按钮 多语言切换
  1207 + // this.put('language', new Menu(mxUtils.bind(this, function(menu, parent)
  1208 + // {
  1209 + // var addLangItem = mxUtils.bind(this, function (id)
  1210 + // {
  1211 + // var lang = (id == '') ? mxResources.get('automatic') : mxLanguageMap[id];
  1212 + // var item = null;
  1213 + //
  1214 + // if (lang != '')
  1215 + // {
  1216 + // item = menu.addItem(lang, null, mxUtils.bind(this, function()
  1217 + // {
  1218 + // mxSettings.setLanguage(id);
  1219 + // mxSettings.save();
  1220 + //
  1221 + // // Shows dialog in new language
  1222 + // mxClient.language = id;
  1223 + // mxResources.loadDefaultBundle = false;
  1224 + // mxResources.add(RESOURCE_BASE);
  1225 + //
  1226 + // editorUi.alert(mxResources.get('restartForChangeRequired'));
  1227 + // }), parent);
  1228 + //
  1229 + // if (id == mxLanguage || (id == '' && mxLanguage == null))
  1230 + // {
  1231 + // menu.addCheckmark(item, Editor.checkmarkImage);
  1232 + // }
  1233 + // }
  1234 + //
  1235 + // return item;
  1236 + // });
  1237 + //
  1238 + // var item = addLangItem('');
  1239 + // menu.addSeparator(parent);
  1240 + //
  1241 + // // LATER: Sort menu by language name
  1242 + // for(var langId in mxLanguageMap)
  1243 + // {
  1244 + // addLangItem(langId);
  1245 + // }
  1246 + // })));
1246 1247
1247 1248 // Extends the menubar with the language menu
1248 1249 var menusCreateMenuBar = Menus.prototype.createMenubar;
... ...
... ... @@ -458,7 +458,6 @@ EditorUi.prototype.initPages = function()
458 458
459 459 // Updates scrollbar positions and backgrounds after validation
460 460 var p = this.currentPage;
461   - console.log(this)
462 461 previewAction(this, this.currentPage)
463 462
464 463 if (p != null && p != lastPage)
... ...
... ... @@ -9,6 +9,7 @@
9 9 var currentDate = getCurrentDate();
10 10 var fns = [
11 11 this.createVertexTemplateEntry('text;strokeColor=none;fillColor=none;html=1;fontSize=24;fontStyle=1;verticalAlign=middle;align=center;', 100, 40, 'Title', 'Title', null, null, 'text heading title'),
  12 + this.createVertexTemplateEntry('text;strokeColor=none;fillColor=none;html=1;fontSize=24;fontStyle=1;verticalAlign=middle;align=center;', 100, 40, '变量', '变量', null, null, '变量'),
12 13 this.createEdgeTemplateEntry('shape=filledEdge;rounded=1;fixDash=1;endArrow=none;strokeWidth=10;fillColor=#BAFDFF;edgeStyle=orthogonalEdgeStyle;flowAnimation=1;strokeColor=#6666FF;endFill=1;metaEdit=0;backgroundOutline=0;', 60, 40, '', '线条'),
13 14 this.addEntry('timestamp date time text label', mxUtils.bind(this, function () {
14 15 var cell = new mxCell('%date{yyyy-mm-dd ddd HH:MM:ss}%', new mxGeometry(0, 0, 160, 20), 'text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;overflow=hidden;');
... ...
... ... @@ -4880,7 +4880,9 @@ DataFormatPanel.prototype.addDataFont = function (container) {
4880 4880 const vertices = ss.vertices || []
4881 4881
4882 4882 console.log(this.editorUi)
4883   - console.log(ss.vertices)
  4883 + console.log(vertices)
  4884 +
  4885 + // console.log(vertices[0]?.get('bindType'))
4884 4886 /**
4885 4887 * @description 不是单一节点则不进入数据绑定
4886 4888 */
... ... @@ -4932,7 +4934,7 @@ DataFormatPanel.prototype.addDataFont = function (container) {
4932 4934
4933 4935 /**
4934 4936 * @description 当前节点绑定数据
4935   - * @type {null}
  4937 + * @type {null | object}
4936 4938 */
4937 4939 let currentNodeData = null
4938 4940
... ... @@ -4992,21 +4994,21 @@ DataFormatPanel.prototype.addDataFont = function (container) {
4992 4994 ];
4993 4995
4994 4996 const dynamicEffectList = [
4995   - {
4996   - label: "闪烁",
4997   - type: enumDynamicEffectType.FLASH,
4998   - category: enumCategory.ACT
4999   - },
  4997 + // {
  4998 + // label: "闪烁",
  4999 + // type: enumDynamicEffectType.FLASH,
  5000 + // category: enumCategory.ACT
  5001 + // },
5000 5002 {
5001 5003 label: "显示/隐藏",
5002 5004 type: enumDynamicEffectType.DISPLAY,
5003 5005 category: enumCategory.ACT
5004 5006 },
5005   - {
5006   - label: "旋转",
5007   - type: enumDynamicEffectType.ROTATE,
5008   - category: enumCategory.ACT
5009   - },
  5007 + // {
  5008 + // label: "旋转",
  5009 + // type: enumDynamicEffectType.ROTATE,
  5010 + // category: enumCategory.ACT
  5011 + // },
5010 5012 ];
5011 5013
5012 5014 const enumDataSourceConst = {
... ... @@ -5205,7 +5207,7 @@ DataFormatPanel.prototype.addDataFont = function (container) {
5205 5207 /**
5206 5208 * @description 生成从设备选择器
5207 5209 */
5208   - function generatoSlaveDevice() {
  5210 + function generatorSlaveDevice() {
5209 5211 slaveDevicePanel = defaultPanel.cloneNode(false)
5210 5212 const slaveDeviceSelect = UseLayUi.createSelect({
5211 5213 label: '子设备',
... ... @@ -5312,9 +5314,23 @@ DataFormatPanel.prototype.addDataFont = function (container) {
5312 5314 }
5313 5315
5314 5316 async function echoActionType() {
5315   - const all = [...(currentNodeData.act ?? []), ...(currentNodeData.event ?? [])]
  5317 + const act = currentNodeData.act ?? []
  5318 + const event = currentNodeData.event ?? []
5316 5319 const actionType = {}
5317   - for (const item of all) {
  5320 + for (const item of act) {
  5321 + if (!item.condition || !item.condition?.length) {
  5322 + $(`.interaction__container input[name="${ item.type }"]`).attr('disabled', true)
  5323 + } else {
  5324 + $(`.interaction__container input[name="${ item.type }"]`).attr('disabled', false)
  5325 + }
  5326 + actionType[item.type] = item.enabled
  5327 + }
  5328 + for (const item of event) {
  5329 + if (!item.content) {
  5330 + $(`.interaction__container input[name="${ item.type }"]`).attr('disabled', true)
  5331 + } else {
  5332 + $(`.interaction__container input[name="${ item.type }"]`).attr('disabled', false)
  5333 + }
5318 5334 actionType[item.type] = item.enabled
5319 5335 }
5320 5336 form.val(CONTAINER_FILTER, actionType)
... ... @@ -5324,7 +5340,7 @@ DataFormatPanel.prototype.addDataFont = function (container) {
5324 5340 function mount() {
5325 5341 generatorOrgTres()
5326 5342 generatorDeviceSelect()
5327   - generatoSlaveDevice()
  5343 + generatorSlaveDevice()
5328 5344 generatorAttrSelect()
5329 5345 echoData()
5330 5346
... ... @@ -5352,6 +5368,11 @@ DataFormatPanel.prototype.addDataFont = function (container) {
5352 5368 $(panel).addClass('override__panel--default').append(item)
5353 5369 $(fragment).append(panel)
5354 5370 })
  5371 + // Object.keys(enumInteractionType).forEach(key => {
  5372 + // form.on(`checkbox(${ key })`, event => {
  5373 + // const isChecked = $(event.othis).hasClass('layui-form-checked')
  5374 + // })
  5375 + // })
5355 5376 $(container).append(fragment)
5356 5377 }
5357 5378
... ... @@ -5430,7 +5451,7 @@ DataFormatPanel.prototype.addDataFont = function (container) {
5430 5451 return
5431 5452 }
5432 5453 // 事件类型
5433   - const enumenumEventType = {
  5454 + const enumEventType = {
5434 5455 DOWN: "按下",
5435 5456 UP: "抬起",
5436 5457 SINGLE: "单击",
... ... @@ -5459,9 +5480,19 @@ DataFormatPanel.prototype.addDataFont = function (container) {
5459 5480 ROW_FILTER: 'interactionRowFilter',
5460 5481
5461 5482 /**
  5483 + * @description json editor
  5484 + */
  5485 + EDITOR_JSON: 'editor__json-',
  5486 +
  5487 + /**
5462 5488 * @description 弹出层保存 filter
5463 5489 */
5464   - LAYER_SUBMIT_FILTER: 'interactionLayerSubmit'
  5490 + LAYER_SUBMIT_FILTER: 'interactionLayerSubmit',
  5491 +
  5492 + /**
  5493 + * @description ace builder
  5494 + */
  5495 + JSON: 'ace__builder-json'
5465 5496 }
5466 5497
5467 5498
... ... @@ -5495,7 +5526,17 @@ DataFormatPanel.prototype.addDataFont = function (container) {
5495 5526 /**
5496 5527 * @description 下发值
5497 5528 */
5498   - VALUE: 'value'
  5529 + VALUE: 'value',
  5530 +
  5531 + /**
  5532 + * @description 方式
  5533 + */
  5534 + WAY: 'way'
  5535 + }
  5536 +
  5537 + const sendInstructionWay = {
  5538 + ONE_WAR: 'oneway',
  5539 + TWO_WAY: 'twoway'
5499 5540 }
5500 5541
5501 5542 /**
... ... @@ -5507,9 +5548,23 @@ DataFormatPanel.prototype.addDataFont = function (container) {
5507 5548 allDeviceOptions = res
5508 5549 }
5509 5550
5510   - function addRecord() {
  5551 + function createEditor(el, datum = {}) {
  5552 + const editor = ace.edit(el, {
  5553 + maxLines: 10, // 最大行数,超过会自动出现滚动条
  5554 + minLines: 5, // 最小行数,还未到最大行数时,编辑器会自动伸缩大小
  5555 + fontSize: 14, // 编辑器内字体大小
  5556 + tabSize: 2, // 制表符设置为 4 个空格大小
  5557 + });
  5558 + editor.session.setMode("ace/mode/json");
  5559 + editor.getSession().on('change', (event, editor) => {
  5560 + $(`#${ el }`).parent().find(`textarea[name="${ enumConst.VALUE }"]`).val(editor.getValue())
  5561 + })
  5562 + editor.setValue(datum[enumConst.VALUE] ? datum[enumConst.VALUE] : "{}")
  5563 + }
  5564 +
  5565 + function addRecord(datum) {
5511 5566 const content = `
5512   - <tr class="layui-form" lay-filter="${ enumActionEl.ROW_FILTER }${ addRowNumber }">
  5567 + <tr class="layui-form" lay-filter="${ getRowFilter(addRowNumber) }">
5513 5568 <td>
5514 5569 <select name="${ enumConst.DEVICE }" lay-filter="${ enumConst.DEVICE }" lay-verType="tips" lay-verify="required"></select>
5515 5570 </td>
... ... @@ -5517,10 +5572,22 @@ DataFormatPanel.prototype.addDataFont = function (container) {
5517 5572 <select name="${ enumConst.SLAVE_DEVICE }" lay-filter="${ enumConst.SLAVE_DEVICE }" lay-verType="tips"></select>
5518 5573 </td>
5519 5574 <td>
5520   - <select name="${ enumConst.ATTR }" lay-verType="tips" lay-verify="required"></select>
  5575 + <form action="" style="display: flex">
  5576 + <div class="override__radio-default">
  5577 + <input id="${ getRowFilter(addRowNumber) }${ sendInstructionWay.ONE_WAR }" type="radio" name="${ enumConst.WAY }" lay-ignore value="${ sendInstructionWay.ONE_WAR }" title="单向" checked="">
  5578 + <label for="${ getRowFilter(addRowNumber) }${ sendInstructionWay.ONE_WAR }" class="override__radio-label">单向</label>
  5579 + </div>
  5580 + <div class="override__radio-default">
  5581 + <input id="${ getRowFilter(addRowNumber) }${ sendInstructionWay.TWO_WAY }" type="radio" name="${ enumConst.WAY }" lay-ignore value="${ sendInstructionWay.TWO_WAY }" title="双向">
  5582 + <label for="${ getRowFilter(addRowNumber) }${ sendInstructionWay.TWO_WAY }" class="override__radio-label">双向</label>
  5583 + </div>
  5584 + </form>
5521 5585 </td>
5522   - <td>
5523   - <textarea name="${ enumConst.VALUE }" placeholder="请输入命令" lay-verType="tips" class="layui-textarea" ></textarea>
  5586 + <td class="${enumActionEl.JSON}">
  5587 + <div style="width: 100%;height: 100%;">
  5588 + <div id="${ enumActionEl.EDITOR_JSON }${ addRowNumber }"></div>
  5589 + <textarea style="display: none" name="${ enumConst.VALUE }" placeholder="请输入命令" lay-verType="tips" class="layui-textarea"></textarea>
  5590 + </div>
5524 5591 </td>
5525 5592 <td>
5526 5593 <button type="button" class="layui-btn layui-btn-primary layui-border-red ${ enumActionEl.DEL_ROW_EL }">删除</button>
... ... @@ -5529,6 +5596,7 @@ DataFormatPanel.prototype.addDataFont = function (container) {
5529 5596 `
5530 5597 $(`#${ enumActionEl.DEVICE_DATA_BODY_EL }`).append(content)
5531 5598 setDeviceOptions(addRowNumber)
  5599 + createEditor(`${ enumActionEl.EDITOR_JSON }${ addRowNumber }`, datum)
5532 5600 form.render('select', getRowFilter(addRowNumber))
5533 5601 addRowNumber++
5534 5602 }
... ... @@ -5557,14 +5625,15 @@ DataFormatPanel.prototype.addDataFont = function (container) {
5557 5625 if (!res) return
5558 5626 const generateOption = UseLayUi.generateOptionTemplate({ dataSource: res })
5559 5627 $(data.elem).parents('tr').find(`select[name="${ enumConst.SLAVE_DEVICE }"]`).html(generateOption)
5560   - } else {
5561   - updateVariableOptions(data)
5562 5628 }
  5629 + // else {
  5630 + // updateVariableOptions(data)
  5631 + // }
5563 5632 form.render('select')
5564 5633 })
5565   - form.on(`select(${ enumConst.SLAVE_DEVICE })`, (data) => {
5566   - updateVariableOptions(data)
5567   - })
  5634 + // form.on(`select(${ enumConst.SLAVE_DEVICE })`, (data) => {
  5635 + // updateVariableOptions(data)
  5636 + // })
5568 5637 }
5569 5638
5570 5639 /**
... ... @@ -5572,6 +5641,7 @@ DataFormatPanel.prototype.addDataFont = function (container) {
5572 5641 */
5573 5642 function createDeleteRowListenEvent() {
5574 5643 $(`.${ enumActionEl.DEL_ROW_EL }`).click((event) => {
  5644 + // $(event.target).parents('tr').find('editor')
5575 5645 $(event.target).parents('tr').remove()
5576 5646 })
5577 5647 }
... ... @@ -5645,17 +5715,18 @@ DataFormatPanel.prototype.addDataFont = function (container) {
5645 5715 * @description 回显每条数据
5646 5716 */
5647 5717 function echoEachData(datum = {}, row) {
5648   - addRecord()
  5718 + addRecord(datum)
5649 5719 const deviceId = datum[enumConst.DEVICE]
5650 5720 const slaveDeviceId = datum[enumConst.SLAVE_DEVICE]
5651 5721 const queue = []
5652 5722
5653 5723 if (slaveDeviceId) {
5654 5724 queue.push(() => getSlaveDeviceByMasterDevice(deviceId, row))
5655   - queue.push(() => getDeviceAttrByDeviceId(slaveDeviceId, row))
5656   - } else {
5657   - queue.push(() => getDeviceAttrByDeviceId(deviceId, row))
  5725 + // queue.push(() => getDeviceAttrByDeviceId(slaveDeviceId, row))
5658 5726 }
  5727 + // else {
  5728 + // queue.push(() => getDeviceAttrByDeviceId(deviceId, row))
  5729 + // }
5659 5730
5660 5731 Promise
5661 5732 .all(queue.map(item => item()))
... ... @@ -5664,11 +5735,39 @@ DataFormatPanel.prototype.addDataFont = function (container) {
5664 5735 })
5665 5736 }
5666 5737
  5738 + function isJson(string) {
  5739 + if (typeof string === 'string') {
  5740 + try {
  5741 + const obj = JSON.parse(string)
  5742 + if (typeof obj === 'object' && obj !== null) {
  5743 + return true
  5744 + }
  5745 + } catch (e) {
  5746 + return false
  5747 + }
  5748 + }
  5749 + return false
  5750 + }
  5751 +
  5752 + function validate(tableData) {
  5753 + let validateFlag = true
  5754 + for (let i = 0; i < tableData.length; i++) {
  5755 + const { value } = tableData[i]
  5756 + if (!isJson(value)) {
  5757 + validateFlag = false
  5758 + layer.tips('下发值不正确', $(`#${ enumActionEl.DEVICE_DATA_BODY_EL } tr`).eq(i).find(`td.${enumActionEl.JSON}`), { tips: 1 })
  5759 + break
  5760 + }
  5761 + }
  5762 + return validateFlag
  5763 + }
  5764 +
5667 5765 /**
5668 5766 * @description 保存
5669 5767 */
5670 5768 async function submit(callback) {
5671 5769 const data = Array.from({ length: addRowNumber }).map((_, row) => form.val(getRowFilter(row))).filter(item => Object.keys(item).length)
  5770 + if (!validate(data)) return
5672 5771 const formModal = {
5673 5772 configurationId,
5674 5773 contentId: currentPageId.id,
... ... @@ -5695,7 +5794,7 @@ DataFormatPanel.prototype.addDataFont = function (container) {
5695 5794 <div class="layui-form-item">
5696 5795 <label class="layui-form-label">事件</label>
5697 5796 <div class="layui-input-block">
5698   - <input type="text" name="event" class="layui-input" value="${ enumenumEventType[type] }" disabled>
  5797 + <input type="text" name="event" class="layui-input" value="${ enumEventType[type] }" disabled>
5699 5798 </div>
5700 5799 </div>
5701 5800 <div class="layui-form-item">
... ... @@ -5714,38 +5813,31 @@ DataFormatPanel.prototype.addDataFont = function (container) {
5714 5813 </div>
5715 5814 </div>
5716 5815 </div>
5717   - <div id="tableContent">
5718   - <table class="layui-table" >
5719   - <colgroup>
5720   - <col width="240">
5721   - <col width="240">
5722   - <col width="240">
5723   - <col width="240">
5724   - <col width="60">
5725   - </colgroup>
5726   - <thead>
5727   - <tr>
5728   - <th style="text-align:center">选择设备</th>
5729   - <th style="text-align:center">选择子设备</th>
5730   - <th style="text-align:center">变量</th>
5731   - <th style="text-align:center">下发值</th>
5732   - <th style="text-align:center">操作</th>
5733   - </tr>
5734   - </thead>
5735   - <tbody id="${ enumActionEl.DEVICE_DATA_BODY_EL }"></tbody>
5736   - </table>
5737   - <div style="display:flex;justify-content:center;">
5738   - <button type="button" class="layui-btn layui-btn-primary layui-border-blue" id="${ enumActionEl.ADD_ROW_EL }">添加一条</button>
5739   - </div>
  5816 + </form>
  5817 + <div class="override__table">
  5818 + <table class="layui-table" >
  5819 + <thead>
  5820 + <tr>
  5821 + <th style="text-align:center">选择设备</th>
  5822 + <th style="text-align:center">选择子设备</th>
  5823 + <th style="text-align:center">单向 / 双向</th>
  5824 + <th style="text-align:center">下发值</th>
  5825 + <th style="text-align:center">操作</th>
  5826 + </tr>
  5827 + </thead>
  5828 + <tbody id="${ enumActionEl.DEVICE_DATA_BODY_EL }"></tbody>
  5829 + </table>
  5830 + <div style="display:flex;justify-content:center;">
  5831 + <button type="button" class="layui-btn layui-btn-primary layui-border-blue" id="${ enumActionEl.ADD_ROW_EL }">添加一条</button>
5740 5832 </div>
5741   - </form>`
  5833 + </div>`
5742 5834
5743 5835 layer.open({
5744 5836 title: '创建交互',
5745 5837 content,
5746 5838 skin: 'event-layer__override',
5747   - // area: ["800px", "600px"],
5748   - area: '1100px',
  5839 + // area: ["1100px", "700px"],
  5840 + area: '1200px',
5749 5841 btn: ["保存", "取消"],
5750 5842 shade: ["0.7", "#fafafa"],
5751 5843 yes(index) {
... ... @@ -5950,8 +6042,6 @@ DataFormatPanel.prototype.addDataFont = function (container) {
5950 6042 </div>
5951 6043 </div>
5952 6044 </div>
5953   - <div style="height:200px;overflow-y:scroll" id="tableContent">
5954   - </div>
5955 6045 </form>
5956 6046 `
5957 6047
... ... @@ -6014,7 +6104,9 @@ DataFormatPanel.prototype.addDataFont = function (container) {
6014 6104 DEL_BTN_EL: 'dataDynamicEffectDelBtn',
6015 6105 ADD_BTN_EL: 'dataDynamicEffectAddBtn',
6016 6106 DISPLAY_SWITCH_EL: 'visibleOrHidden',
6017   - LAYER_SUBMIT_FILTER: 'dynamicEffectLayerFilter'
  6107 + LAYER_SUBMIT_FILTER: 'dynamicEffectLayerFilter',
  6108 + MIN_FILTER: 'dynamicEffectMinFilter',
  6109 + MAX_FILTER: 'dynamicEffectMaxFilter',
6018 6110 }
6019 6111
6020 6112 const getRowFilter = (rowNumber) => `${ enumActionEl.ROW_FILTER }${ rowNumber }`
... ... @@ -6033,6 +6125,8 @@ DataFormatPanel.prototype.addDataFont = function (container) {
6033 6125 GATEWAY: 'GATEWAY'
6034 6126 }
6035 6127
  6128 + const enumDisplayType = HandleDynamicEffect.enumDisplayType
  6129 +
6036 6130 /**
6037 6131 * @description 设备列表
6038 6132 */
... ... @@ -6075,19 +6169,20 @@ DataFormatPanel.prototype.addDataFont = function (container) {
6075 6169 * @description 通过组织获取设备
6076 6170 */
6077 6171 async function getDeviceByOrg(id) {
  6172 + if (!id) return
6078 6173 const [err, res] = await to(ConfigurationNodeApi.getMasterDevice(id))
6079   - if (res) {
6080   - deviceList = res
6081   - const template = UseLayUi.generateOptionTemplate({ dataSource: res })
6082   - $(`#${ enumActionEl.DEVICE_EL } select`).html(template)
6083   - form.render('select', enumActionEl.FORM_FILTER)
6084   - }
  6174 + if (!res) return
  6175 + deviceList = res
  6176 + const template = UseLayUi.generateOptionTemplate({ dataSource: res })
  6177 + $(`#${ enumActionEl.DEVICE_EL } select`).html(template)
  6178 + form.render('select', enumActionEl.FORM_FILTER)
6085 6179 }
6086 6180
6087 6181 /**
6088 6182 * @description 通过主设备ID获取从设备
6089 6183 */
6090 6184 async function getSlaveDeviceByMasterDevice(orgId, id) {
  6185 + if (!orgId || !id) return
6091 6186 const [err, res] = await to(ConfigurationNodeApi.getSlaveDevice(orgId, id))
6092 6187 if (res) {
6093 6188 const template = UseLayUi.generateOptionTemplate({ dataSource: res })
... ... @@ -6100,6 +6195,7 @@ DataFormatPanel.prototype.addDataFont = function (container) {
6100 6195 * @description 通过设备ID获取设备属性
6101 6196 */
6102 6197 async function getAttrsByDevice(id) {
  6198 + if (!id) return
6103 6199 const [err, res] = await to(ConfigurationNodeApi.getDeviceAttr(id))
6104 6200 if (res) {
6105 6201 const template = UseLayUi.generateOptionTemplate({ dataSource: res })
... ... @@ -6111,8 +6207,8 @@ DataFormatPanel.prototype.addDataFont = function (container) {
6111 6207
6112 6208 function generatorDisplayOptions() {
6113 6209 const options = [
6114   - { name: '显示', id: 'show' },
6115   - { name: '隐藏', id: 'hidden' }
  6210 + { name: '显示', id: enumDisplayType.SHOW },
  6211 + { name: '隐藏', id: enumDisplayType.HIDDEN }
6116 6212 ]
6117 6213 const template = UseLayUi.generateOptionTemplate({ dataSource: options })
6118 6214 return `
... ... @@ -6132,10 +6228,10 @@ DataFormatPanel.prototype.addDataFont = function (container) {
6132 6228 <tr class="layui-form" lay-filter="${ getRowFilter(addRowNumber) }">
6133 6229 ${ IS_DISPLAY && `<td>${ generatorDisplayOptions() }</td>` }
6134 6230 <td>
6135   - <input lay-verType="tips" lay-verify="required" type="text" name="${ enumConst.MIN }" class="layui-input">
  6231 + <input lay-verType="tips" lay-verify="required" type="number" name="${ enumConst.MIN }" class="layui-input ${ enumActionEl.MIN_FILTER }">
6136 6232 </td>
6137 6233 <td>
6138   - <input lay-verType="tips" lay-verify="required" type="text" name="${ enumConst.MAX }" class="layui-input">
  6234 + <input lay-verType="tips" lay-verify="required" type="number" name="${ enumConst.MAX }" class="layui-input ${ enumActionEl.MAX_FILTER }">
6139 6235 </td>
6140 6236 <td style="text-align: center;">
6141 6237 <button type="button" class="layui-btn layui-btn-primary layui-border-red ${ enumActionEl.DEL_BTN_EL }">删除</button>
... ... @@ -6191,9 +6287,35 @@ DataFormatPanel.prototype.addDataFont = function (container) {
6191 6287 }
6192 6288
6193 6289 /**
  6290 + * @description 创建输入监听
  6291 + */
  6292 + function createInputListener() {
  6293 + $(`#${ enumActionEl.TABLE_BODY_EL }`)
  6294 + .on('input', `.${ enumActionEl.MIN_FILTER }`, event => {
  6295 + const minVal = $(event.target).val()
  6296 + const maxVal = $(event.target).parents('tr').find(`input.${ enumActionEl.MAX_FILTER }`).val()
  6297 + if (maxVal !== '' && Number(minVal) > Number(maxVal)) {
  6298 + layer.tips('输入值大于最大值', $(event.target), {
  6299 + tips: 1
  6300 + });
  6301 + }
  6302 + })
  6303 + .on('input', `.${ enumActionEl.MAX_FILTER }`, event => {
  6304 + const maxVal = $(event.target).val()
  6305 + const minVal = $(event.target).parents('tr').find(`input.${ enumActionEl.MIN_FILTER }`).val()
  6306 + if (minVal !== '' && Number(maxVal) < Number(minVal)) {
  6307 + layer.tips('输入值小于最小值', $(event.target), {
  6308 + tips: 1
  6309 + });
  6310 + }
  6311 + })
  6312 + }
  6313 +
  6314 + /**
6194 6315 * @description 创建事件监听
6195 6316 */
6196 6317 function createEventListen() {
  6318 + createInputListener()
6197 6319 createSelectLinkageListenEvent()
6198 6320 createAddRowListenEvent()
6199 6321 createDeleteRowListenEvent()
... ... @@ -6237,12 +6359,29 @@ DataFormatPanel.prototype.addDataFont = function (container) {
6237 6359 */
6238 6360 function echoOrgTree(id) {
6239 6361 const node = UseLayUi.findTreeObjectByField(treeList, id)
6240   - console.log(node)
6241 6362 $(`#${ enumActionEl.ORG_EL }`).find(`input[name="${ enumConst.ORG_ID }"]`).parent().find('span').html(node?.name)
6242 6363 }
6243 6364
  6365 + function validate(tableData) {
  6366 + let validateFlag = true
  6367 + for (let i = 0; i < tableData.length; i++) {
  6368 + const { min, max } = tableData[i]
  6369 + if (Number(min) > Number(max)) {
  6370 + validateFlag = false
  6371 + layer.tips('输入值大于最大值', $(`#${ enumActionEl.TABLE_BODY_EL } tr`).eq(i).find(`input[name="${ enumConst.MIN }"]`), { tips: 1 })
  6372 + break
  6373 + } else if (Number(max) < Number(min)) {
  6374 + validateFlag = false
  6375 + layer.tips('输入值小于最小值', $(`#${ enumActionEl.TABLE_BODY_EL } tr`).eq(i).find(`input[name="${ enumConst.MAX }"]`), { tips: 1 })
  6376 + break
  6377 + }
  6378 + }
  6379 + return validateFlag
  6380 + }
  6381 +
6244 6382 async function submit(callback) {
6245 6383 const tableData = Array.from({ length: addRowNumber }).map((_, index) => form.val(getRowFilter(index))).filter(obj => Object.keys(obj).length)
  6384 + if (!validate(tableData)) return
6246 6385 const formVal = form.val(enumActionEl.FORM_FILTER)
6247 6386 const formModel = {
6248 6387 configurationId,
... ... @@ -6258,6 +6397,10 @@ DataFormatPanel.prototype.addDataFont = function (container) {
6258 6397 callback()
6259 6398 }
6260 6399
  6400 + function isExistInArea(min, max, value) {
  6401 + return Number(value) >= Number(min) && Number(value) <= Number(max)
  6402 + }
  6403 +
6261 6404
6262 6405 function createLayerForm(type) {
6263 6406 const content = `
... ... @@ -6297,14 +6440,8 @@ DataFormatPanel.prototype.addDataFont = function (container) {
6297 6440 </div>
6298 6441 </div>
6299 6442 </form>
6300   - <div>
  6443 + <div class="override__table">
6301 6444 <table class="layui-table" >
6302   - <colgroup>
6303   - ${ IS_DISPLAY ? '<col width="240">' : '' }
6304   - <col width="240">
6305   - <col width="240">
6306   - <col>
6307   - </colgroup>
6308 6445 <thead>
6309 6446 <tr>
6310 6447 ${ IS_DISPLAY ? '<th style="text-align:center">类型</th>' : '' }
... ... @@ -10568,6 +10705,9 @@ class UseLayUi {
10568 10705 UseLayUi.msg(msg, { ...options, icon: 6 })
10569 10706 }
10570 10707
  10708 + static errorMsg(msg = '操作失败', options) {
  10709 + UseLayUi.msg(msg, { ...options, icon: 5 })
  10710 + }
10571 10711 }
10572 10712
10573 10713
... ... @@ -10910,6 +11050,12 @@ class DispatchCenter {
10910 11050 nodeMapping
10911 11051
10912 11052 /**
  11053 + * @description cmd ID 与 node 映射关系
  11054 + * @type {Map<number, string>}
  11055 + */
  11056 + cmdIdMapping = new Map()
  11057 +
  11058 + /**
10913 11059 * @description
10914 11060 */
10915 11061 editorUi
... ... @@ -10942,7 +11088,30 @@ class DispatchCenter {
10942 11088 eventBus
10943 11089
10944 11090 /**
  11091 + * @description 页面数据
  11092 + */
  11093 + contentData
  11094 +
  11095 + /**
  11096 + * @description 处理数据动效实例
  11097 + * @type {HandleDynamicEffect}
  11098 + */
  11099 + dynamicEffectInstance
  11100 +
  11101 + /**
  11102 + * @description 处理数据交互实例
  11103 + * @type {HandleDataInteraction}
  11104 + */
  11105 + dataInteractionInstance
  11106 +
  11107 + /**
  11108 + * @description cmd id
  11109 + */
  11110 + cmdIdPrimaryKey = 0
  11111 +
  11112 + /**
10945 11113 * @description 当前实例
  11114 + * @type {DispatchCenter}
10946 11115 */
10947 11116 static instance
10948 11117
... ... @@ -10979,8 +11148,6 @@ class DispatchCenter {
10979 11148 constructor(editorUi, currentPage) {
10980 11149 this.nodeMapping = new Map()
10981 11150 this.editorUi = editorUi
10982   -
10983   - // mxEvent.addListener(document, (mxClient.IS_POINTER) ? 'pointerup' : 'mouseup', this.pointerUpHandler);
10984 11151 this.init(editorUi, currentPage)
10985 11152 }
10986 11153
... ... @@ -10989,12 +11156,13 @@ class DispatchCenter {
10989 11156 * @param editorUi
10990 11157 * @param currentPage
10991 11158 */
10992   - init(editorUi, currentPage) {
  11159 + async init(editorUi, currentPage) {
10993 11160 this.createEventBus()
10994 11161 this.saveContentInfo(editorUi, currentPage)
10995   - this.createGraphEventListener()
10996 11162 this.connectSocket()
10997   - this.getContentDataNode()
  11163 + await this.getContentDataNode()
  11164 + this.dataInteractionInstance = new HandleDataInteraction(this)
  11165 + this.dynamicEffectInstance = new HandleDynamicEffect(this)
10998 11166 }
10999 11167
11000 11168 /**
... ... @@ -11002,15 +11170,7 @@ class DispatchCenter {
11002 11170 */
11003 11171 connectSocket() {
11004 11172 const GLOBAL_TOKEN = JSON.parse(localStorage.getItem("UNDEFINED__DEVELOPMENT__2.7.1__COMMON__LOCAL__KEY__")).value.JWT_TOKEN.value
11005   -
11006   - // const { host, href } = location
11007   - // const reg = /^https/
11008   - // const wsUrl = `${reg.test(href) ? 'wss' : 'ws'}://${host}/api/ws/plugins/telemetry?token=${GLOBAL_TOKEN}`
11009   -
11010   - const wsUrl = `ws://47.99.141.212:8080/api/ws/plugins/telemetry?token=${ GLOBAL_TOKEN }`
11011   - // const wsUrl = `ws://192.168.10.115:8080/api/ws/plugins/telemetry?token=${GLOBAL_TOKEN}`
11012   -
11013   - this.socket = Ws.getInstance({ url: wsUrl, onmessageCallback: this.socketOnmessage })
  11173 + this.socket = Ws.getInstance({ url: GLOBAL_WS_URL, onmessageCallback: this.socketOnmessage })
11014 11174 }
11015 11175
11016 11176 /**
... ... @@ -11021,7 +11181,7 @@ class DispatchCenter {
11021 11181 */
11022 11182 socketOnmessage(message, event, ws) {
11023 11183 const { subscriptionId, data } = message
11024   - DispatchCenter.instance.publishEvent(subscriptionId, data)
  11184 + DispatchCenter.instance.publishEvent(subscriptionId, data, message, event, ws)
11025 11185 }
11026 11186
11027 11187 /**
... ... @@ -11032,39 +11192,6 @@ class DispatchCenter {
11032 11192 }
11033 11193
11034 11194 /**
11035   - * @description 创建图层事件监听器
11036   - */
11037   - createGraphEventListener() {
11038   - if (DispatchCenter.eventListenerIsExist) return
11039   -
11040   - const graphDblClick = this.graph.dblClick;
11041   - this.graph.dblClick = (...args) => {
11042   - this.handleDoubleClickEvent(...args)
11043   - graphDblClick.apply(this.graph, args)
11044   - }
11045   -
11046   -
11047   - const graphClick = this.graph.click;
11048   - this.graph.click = (...args) => {
11049   - this.handleClickEvent(...args)
11050   - graphClick.apply(this.graph, args)
11051   - }
11052   -
11053   - const graphFireMouseEvent = this.graph.fireMouseEvent;
11054   - this.graph.fireMouseEvent = (eventName, event, sender) => {
11055   - if (eventName === mxEvent.MOUSE_DOWN) {
11056   - this.handleMouseDownEvent(eventName, event, sender)
11057   - }
11058   - if (eventName === mxEvent.MOUSE_UP) {
11059   - this.handleMouseUpEvent(eventName, event, sender)
11060   - }
11061   - graphFireMouseEvent.apply(this.graph, [eventName, event, sender]);
11062   - };
11063   -
11064   - DispatchCenter.eventListenerIsExist = true
11065   - }
11066   -
11067   - /**
11068 11195 * @description 保存部分页面信息到实例上
11069 11196 * @param editorUi
11070 11197 * @param currentPage
... ... @@ -11084,14 +11211,9 @@ class DispatchCenter {
11084 11211 const { node: { id } = {} } = this.currentPage
11085 11212 if (!id) return
11086 11213 const [err, res] = await to(ConfigurationNodeApi.getConfigurationInfo('CONTENT', id))
11087   - const { dataSources, event, act } = res
11088   - const sendMsg = {
11089   - tsSubCmds: this.generatorDataSourceMapping(dataSources)
11090   - }
11091   - this.generatorEventMapping(event)
11092   - this.generatorActionEffectMapping(act)
11093   - this.sendMessageToGetRealTimeData(sendMsg)
11094   - console.log(this.nodeMapping)
  11214 + const { dataSources, event, act } = this.contentData = res
  11215 + const tsSubCmds = this.generatorDataSourceMapping(dataSources)
  11216 + this.sendMessageToGetRealTimeData({ tsSubCmds })
11095 11217 }
11096 11218
11097 11219 /**
... ... @@ -11103,61 +11225,43 @@ class DispatchCenter {
11103 11225 }
11104 11226
11105 11227 /**
  11228 + * @description 通过传入NodeId获取cmdId
  11229 + * @param nodeId
  11230 + * @return {number}
  11231 + */
  11232 + getCmdId(nodeId) {
  11233 + const cmdId = this.cmdIdPrimaryKey++
  11234 + this.cmdIdMapping.set(cmdId, nodeId)
  11235 + return cmdId
  11236 + }
  11237 +
  11238 + /**
11106 11239 * @description 生成节点映射表
11107 11240 * @param dataSources
11108 11241 * @return {{cmdId: number, entityType: string, keys: *, scope: string, entityId: *}[]}
11109 11242 */
11110 11243 generatorDataSourceMapping(dataSources = []) {
11111   - return dataSources.map((datum, eventName) => {
11112   - const { deviceId, attr } = datum
  11244 + return dataSources.map((datum) => {
  11245 + const { deviceId, attr, nodeId } = datum
  11246 + const cmdId = this.getCmdId(nodeId)
11113 11247 const sendMsgTemplate = {
11114 11248 entityType: "DEVICE",
11115 11249 entityId: deviceId,
11116 11250 scope: "LATEST_TELEMETRY",
11117   - cmdId: eventName,
  11251 + cmdId,
11118 11252 keys: attr
11119 11253 }
11120   -
11121   - this.subscribeDataSources(datum, eventName, attr)
  11254 + this.subscribeDataSources(datum, cmdId, attr)
11122 11255 return sendMsgTemplate
11123 11256 })
11124 11257 }
11125 11258
11126 11259 /**
11127   - * @description 事件映射
11128   - * @param event
11129   - */
11130   - generatorEventMapping(event = []) {
11131   - for (const item of event) {
11132   - const { content, id: nodeId, enabled, type } = item
11133   - if (!enabled) continue
11134   - if (!this.nodeMapping.has(nodeId)) this.nodeMapping.set(nodeId, new Map())
11135   - const temp = this.nodeMapping.get(nodeId)
11136   - temp.set(type, content)
11137   - }
11138   - }
11139   -
11140   - /**
11141   - * @description 动效映射
11142   - * @param act
11143   - */
11144   - generatorActionEffectMapping(act = []) {
11145   - for (const item of act) {
11146   - const { condition, id: nodeId, enabled, type } = item
11147   - if (!enabled) continue
11148   - if (!this.nodeMapping.has(nodeId)) this.nodeMapping.set(nodeId, new Map())
11149   - const temp = this.nodeMapping.get(nodeId)
11150   - temp.set(type, condition)
11151   - }
11152   - }
11153   -
11154   - /**
11155 11260 * @description 分发事件
11156 11261 */
11157   - publishEvent(eventName, data) {
  11262 + publishEvent(eventName, data, message, event, ws) {
11158 11263 Object.keys(data).forEach(() => {
11159   - this.eventBus.emit(eventName, data)
11160   -
  11264 + this.eventBus.emit(eventName, message, event, ws)
11161 11265 })
11162 11266 }
11163 11267
... ... @@ -11170,8 +11274,9 @@ class DispatchCenter {
11170 11274 subscribeDataSources(datum, eventName, key) {
11171 11275 const node = this.contentAllCell.find(item => item.id === datum.nodeId)
11172 11276 this.eventBus.on(eventName, (message) => {
11173   - this.updatePage(node, () => {
11174   - const [[timespan, value]] = message[key]
  11277 + this.updatePage(() => {
  11278 + const { data } = message
  11279 + const [[timespan, value]] = data[key]
11175 11280 node.setValue(value)
11176 11281 })
11177 11282 })
... ... @@ -11179,19 +11284,132 @@ class DispatchCenter {
11179 11284
11180 11285 /**
11181 11286 * @description 更新页面
11182   - * @param node
11183 11287 * @param callback
11184 11288 */
11185   - updatePage(node, callback) {
  11289 + updatePage(callback) {
11186 11290 this.graph.getModel().beginUpdate()
11187 11291 try {
11188 11292 callback()
11189   - this.graph.insertVertex(node, null);
  11293 + this.graph.refresh();
11190 11294 } finally {
11191 11295 this.graph.getModel().endUpdate()
11192 11296 }
11193 11297 }
11194 11298
  11299 +
  11300 + /**
  11301 + * @description 返回 DispatchCenter 实例 当contentID变化时重新创建实例
  11302 + * @param editorUi
  11303 + * @param currentPage
  11304 + * @return {*}
  11305 + */
  11306 + static getInstance(editorUi, currentPage = {}) {
  11307 + const { node: { id } = {} } = currentPage
  11308 + if (!id) return
  11309 + if (!DispatchCenter.instance || DispatchCenter.rawContentId !== id) {
  11310 + DispatchCenter.instance?.dynamicEffectInstance?.cleanSetInterval?.()
  11311 + DispatchCenter.instance = new DispatchCenter(editorUi, currentPage)
  11312 + DispatchCenter.rawContentId = id
  11313 + }
  11314 +
  11315 + return DispatchCenter.instance
  11316 + }
  11317 +
  11318 +}
  11319 +
  11320 +class HandleDataInteraction {
  11321 + /**
  11322 + * @description 事件分发中心实例
  11323 + * @type {DispatchCenter}
  11324 + */
  11325 + DispatchInstance
  11326 +
  11327 + /**
  11328 + * @description 事件映射
  11329 + * @type {Map<>}
  11330 + */
  11331 + eventMapping = new Map()
  11332 +
  11333 + constructor(DispatchInstance) {
  11334 + this.DispatchInstance = DispatchInstance
  11335 + this.init()
  11336 + }
  11337 +
  11338 + init() {
  11339 + this.generatorEventMapping()
  11340 + this.createGraphEventListener()
  11341 + }
  11342 +
  11343 + /**
  11344 + * @description DispatchCenter 实例中保存的 graph 对象
  11345 + * @return {*}
  11346 + */
  11347 + get graph() {
  11348 + return this.DispatchInstance.graph
  11349 + }
  11350 +
  11351 + /**
  11352 + * @description DispatchCenter 实例中保存的 editorUi 对象
  11353 + * @return {*}
  11354 + */
  11355 + get editorUi() {
  11356 + return this.DispatchInstance.editorUi
  11357 + }
  11358 +
  11359 + /**
  11360 + * @description DispatchCenter 实例中保存的 contentAllCell 对象
  11361 + * @return {*}
  11362 + */
  11363 + get eventList() {
  11364 + const { event = [] } = this.DispatchInstance.contentData
  11365 + return event
  11366 + }
  11367 +
  11368 + /**
  11369 + * @description 事件映射
  11370 + */
  11371 + generatorEventMapping() {
  11372 + const event = this.eventList
  11373 + console.log(event)
  11374 + for (const item of event) {
  11375 + const { content, id: nodeId, enabled, type } = item
  11376 + if (!enabled) continue
  11377 + if (!this.eventMapping.has(nodeId)) this.eventMapping.set(nodeId, new Map())
  11378 + const temp = this.eventMapping.get(nodeId)
  11379 + temp.set(type, content)
  11380 + }
  11381 + }
  11382 +
  11383 + createGraphEventListener() {
  11384 + if (DispatchCenter.eventListenerIsExist) return
  11385 +
  11386 + const graphDblClick = this.graph.dblClick;
  11387 + this.graph.dblClick = (...args) => {
  11388 + this.handleDoubleClickEvent(...args)
  11389 + graphDblClick.apply(this.graph, args)
  11390 + }
  11391 +
  11392 +
  11393 + const graphClick = this.graph.click;
  11394 + this.graph.click = (...args) => {
  11395 + this.handleClickEvent(...args)
  11396 + graphClick.apply(this.graph, args)
  11397 + }
  11398 +
  11399 + const graphFireMouseEvent = this.graph.fireMouseEvent;
  11400 + this.graph.fireMouseEvent = (eventName, event, sender) => {
  11401 + if (eventName === mxEvent.MOUSE_DOWN) {
  11402 + this.handleMouseDownEvent(eventName, event, sender)
  11403 + }
  11404 + if (eventName === mxEvent.MOUSE_UP) {
  11405 + this.handleMouseUpEvent(eventName, event, sender)
  11406 + }
  11407 + graphFireMouseEvent.apply(this.graph, [eventName, event, sender]);
  11408 + };
  11409 +
  11410 + DispatchCenter.eventListenerIsExist = true
  11411 + }
  11412 +
11195 11413 /**
11196 11414 * @description 处理按下事件
11197 11415 * @param eventName
... ... @@ -11200,10 +11418,10 @@ class DispatchCenter {
11200 11418 */
11201 11419 handleMouseDownEvent(eventName, event, sender) {
11202 11420 const { state: { cell: { id } = {} } = {} } = event
11203   - const temp = this.nodeMapping.get(id)
  11421 + const temp = this.eventMapping.get(id)
11204 11422 if (temp && temp.has(DispatchCenter.enumEventType.DOWN)) {
11205 11423 const content = temp.get(DispatchCenter.enumEventType.DOWN)
11206   - console.log('mouse down event', content)
  11424 + this.sendInstruction(content.data)
11207 11425 }
11208 11426 }
11209 11427
... ... @@ -11215,10 +11433,10 @@ class DispatchCenter {
11215 11433 */
11216 11434 handleMouseUpEvent(eventName, event, sender) {
11217 11435 const { state: { cell: { id } = {} } = {} } = event
11218   - const temp = this.nodeMapping.get(id)
  11436 + const temp = this.eventMapping.get(id)
11219 11437 if (temp && temp.has(DispatchCenter.enumEventType.UP)) {
11220 11438 const content = temp.get(DispatchCenter.enumEventType.UP)
11221   - console.log('mouse up event', content)
  11439 + this.sendInstruction(content.data)
11222 11440 }
11223 11441 }
11224 11442
... ... @@ -11228,7 +11446,7 @@ class DispatchCenter {
11228 11446 */
11229 11447 handleClickEvent(event) {
11230 11448 const { state: { cell: { id } = {} } = {} } = event
11231   - const temp = this.nodeMapping.get(id)
  11449 + const temp = this.eventMapping.get(id)
11232 11450 if (temp && temp.has(DispatchCenter.enumEventType.SINGLE)) {
11233 11451 const content = temp.get(DispatchCenter.enumEventType.SINGLE)
11234 11452 const { type, value } = content
... ... @@ -11247,7 +11465,7 @@ class DispatchCenter {
11247 11465 */
11248 11466 handleDoubleClickEvent(event, cell = {}) {
11249 11467 const { id } = cell
11250   - const temp = this.nodeMapping.get(id)
  11468 + const temp = this.eventMapping.get(id)
11251 11469 if (temp && temp.has(DispatchCenter.enumEventType.DOUBLE)) {
11252 11470 const content = temp.get(DispatchCenter.enumEventType.DOUBLE)
11253 11471 const { type, value } = content
... ... @@ -11259,34 +11477,385 @@ class DispatchCenter {
11259 11477 }
11260 11478 }
11261 11479
  11480 +
  11481 + /**
  11482 + * @description 下发指令
  11483 + * @param list
  11484 + */
  11485 + sendInstruction(list = []) {
  11486 + const queue = []
  11487 + const fn = async (way, deviceId, data) => {
  11488 + const [err, res = {}] = await to(ConfigurationNodeApi.deviceIsOnLine(deviceId))
  11489 + const { value } = res
  11490 + if (value) {
  11491 + await to(ConfigurationNodeApi.sendInstruction(way, deviceId, data))
  11492 + } else {
  11493 + UseLayUi.errorMsg('设备不在线!')
  11494 + }
  11495 + }
  11496 + for (const item of list) {
  11497 + const { deviceId, slaveDeviceId, value, way } = item
  11498 + console.log(item)
  11499 + if (!value || !deviceId) continue
  11500 + const data = {
  11501 + method: "methodThingskit",
  11502 + params: JSON.parse(value)
  11503 + }
  11504 + if (slaveDeviceId) {
  11505 + queue.push(() => {
  11506 + fn(way, slaveDeviceId, data)
  11507 + })
  11508 + } else if (deviceId) {
  11509 + queue.push(() => {
  11510 + fn(way, deviceId, data)
  11511 + })
  11512 + }
  11513 + }
  11514 +
  11515 + Promise.all(queue.map(fn => fn())).then(res => {
  11516 + console.log(res)
  11517 + })
  11518 + }
  11519 +
11262 11520 /**
11263 11521 * @description 跳转页面
11264 11522 */
11265 11523 jumpPage(page) {
11266   - // const page = 'ikp4NlRjQpI8WxeSibFj'
11267 11524 this.editorUi.handleCustomLink(`data:page/id,${ page }`)
11268 11525 }
  11526 +}
11269 11527
  11528 +class HandleDynamicEffect {
11270 11529
11271 11530 /**
11272   - * @description 返回 DispatchCenter 实例 当contentID变化时重新创建实例
11273   - * @param editorUi
11274   - * @param currentPage
11275   - * @return {*}
  11531 + * @description 事件分发中心实例
  11532 + * @type {DispatchCenter}
11276 11533 */
11277   - static getInstance(editorUi, currentPage = {}) {
11278   - const { node: { id } = {} } = currentPage
11279   - if (!id) return
11280   - if (!DispatchCenter.instance || DispatchCenter.rawContentId !== id) {
11281   - DispatchCenter.instance = new DispatchCenter(editorUi, currentPage)
11282   - DispatchCenter.rawContentId = id
  11534 + DispatchInstance
  11535 +
  11536 + /**
  11537 + * @description 开启的数据动效
  11538 + * @type {any[]}
  11539 + */
  11540 + enableActList
  11541 +
  11542 + /**
  11543 + * @description 动效节点映射
  11544 + * @type {Map<string, Map<string, any>>}
  11545 + */
  11546 + actNodeMapping = new Map()
  11547 +
  11548 + /**
  11549 + * @description cmdID 与 nodeID 关系映射
  11550 + * @type {Map<number, string>}
  11551 + */
  11552 + cmdIdMapping = new Map()
  11553 +
  11554 + /**
  11555 + * @description clear setInterval
  11556 + */
  11557 + cleanSetInterval
  11558 +
  11559 + static enumConst = {
  11560 + MAX: 'max',
  11561 + MIN: 'min',
  11562 + }
  11563 +
  11564 + static enumActType = {
  11565 + FLASH: 'FLASH',
  11566 + DISPLAY: 'DISPLAY',
  11567 + ROTATE: 'ROTATE'
  11568 + }
  11569 +
  11570 + static enumDisplayType = {
  11571 + SHOW: 'show',
  11572 + HIDDEN: 'hidden'
  11573 + }
  11574 +
  11575 + constructor(DispatchInstance) {
  11576 + this.DispatchInstance = DispatchInstance
  11577 + this.init()
  11578 + }
  11579 +
  11580 + init() {
  11581 + this.getEnableActList()
  11582 + this.generatorMappingRelation()
  11583 + }
  11584 +
  11585 + get graph() {
  11586 + return this.DispatchInstance.graph
  11587 + }
  11588 +
  11589 + /**
  11590 + * @description 获取已开启的数据动效
  11591 + */
  11592 + getEnableActList() {
  11593 + const { act = [] } = this.DispatchInstance.contentData
  11594 + this.enableActList = act.filter(item => item.enabled)
  11595 + }
  11596 +
  11597 + /**
  11598 + * @description 生成映射关系 && 初始化推送消息
  11599 + */
  11600 + generatorMappingRelation() {
  11601 + const tsSubCmds = []
  11602 + this.enableActList.forEach(each => {
  11603 + const { id, type, attr, deviceId } = each
  11604 +
  11605 + if (!this.actNodeMapping.has(id)) this.actNodeMapping.set(id, new Map())
  11606 + const temp = this.actNodeMapping.get(id)
  11607 + temp.set(type, each)
  11608 +
  11609 + const cmdId = this.DispatchInstance.getCmdId(id)
  11610 +
  11611 + tsSubCmds.push(this.generatorMessage(deviceId, cmdId, attr))
  11612 +
  11613 + this.subscribeEvent(cmdId, this.dispatch(type))
  11614 + })
  11615 + this.sendMsg({ tsSubCmds })
  11616 + }
  11617 +
  11618 + /**
  11619 + * @description 推送消息
  11620 + * @param msg
  11621 + */
  11622 + sendMsg(msg) {
  11623 + this.DispatchInstance.sendMessageToGetRealTimeData(msg)
  11624 + }
  11625 +
  11626 + /**
  11627 + * @description 订阅事件 绑定回调
  11628 + * @param eventName
  11629 + * @param callback
  11630 + */
  11631 + subscribeEvent(eventName, callback) {
  11632 + this.DispatchInstance.eventBus.on(eventName, callback)
  11633 + }
  11634 +
  11635 + /**
  11636 + * @description 创建消息
  11637 + * @param deviceId
  11638 + * @param cmdId
  11639 + * @param attr
  11640 + * @return {{cmdId, entityType: string, keys, scope: string, entityId}}
  11641 + */
  11642 + generatorMessage(deviceId, cmdId, attr) {
  11643 + return {
  11644 + entityType: "DEVICE",
  11645 + entityId: deviceId,
  11646 + scope: "LATEST_TELEMETRY",
  11647 + cmdId,
  11648 + keys: attr
11283 11649 }
  11650 + }
11284 11651
11285   - return DispatchCenter.instance
  11652 + /**
  11653 + * @description 分发事件
  11654 + * @param type
  11655 + * @return Function
  11656 + */
  11657 + dispatch(type) {
  11658 + let invoke = () => {
  11659 + }
  11660 + switch (type) {
  11661 + case HandleDynamicEffect.enumActType.ROTATE:
  11662 + // invoke = this.rotate.bind(this)
  11663 + break
  11664 + case HandleDynamicEffect.enumActType.DISPLAY:
  11665 + invoke = this.display.bind(this)
  11666 + break
  11667 + case HandleDynamicEffect.enumActType.FLASH:
  11668 + break
  11669 + }
  11670 + return invoke
  11671 + }
  11672 +
  11673 + /**
  11674 + * @description 旋转
  11675 + * @param message
  11676 + * @param data
  11677 + */
  11678 + rotate(data) {
  11679 + const { subscriptionId } = data
  11680 + console.log(data)
  11681 + const node = this.getNodeByCmdId(subscriptionId)
  11682 + let deg = 0
  11683 + this.cleanSetInterval = RAFSetInterval(() => {
  11684 + // if (deg === 360) deg = 0
  11685 + // deg += 20
  11686 + // let style = node.getStyle()
  11687 + // const reg = /rotation=(-?)\w+(;?)/g
  11688 + // style = style.replace(reg, `rotation=${ deg }`)
  11689 + // // node.setStyle(style)
  11690 + // console.log(node)
  11691 + // this.graph.getModel().beginUpdate()
  11692 + // try {
  11693 + // node.setStyle(style)
  11694 + // // this.graph.refresh();
  11695 + // } finally {
  11696 + // this.graph.getModel().endUpdate()
  11697 + // }
  11698 + this.DispatchInstance.updatePage(() => {
  11699 + if (deg === 360) deg = 0
  11700 + deg += 20
  11701 + let style = node.getStyle()
  11702 + const reg = /rotation=(-?)\w+(;?)/g
  11703 + style = style.replace(reg, `rotation=${ deg }`)
  11704 + node.setStyle(style)
  11705 + this.graph.updateCellStyles(style, node)
  11706 + })
  11707 + }, 100)
  11708 + }
  11709 +
  11710 + /**
  11711 + * @description 显示与隐藏
  11712 + * @param _
  11713 + * @param message
  11714 + */
  11715 + display(message) {
  11716 + const { subscriptionId, data = {} } = message
  11717 + const { flag, condition } = this.validate(subscriptionId, HandleDynamicEffect.enumActType.DISPLAY, data)
  11718 + if (!flag) return
  11719 + const node = this.getNodeByCmdId(subscriptionId)
  11720 + let isShow = false
  11721 + if (node.visible && condition.type === HandleDynamicEffect.enumDisplayType.SHOW) {
  11722 + return
  11723 + } else if (condition.type === HandleDynamicEffect.enumDisplayType.SHOW) {
  11724 + isShow = true
  11725 + } else if (condition.type === HandleDynamicEffect.enumDisplayType.HIDDEN) {
  11726 + isShow = false
  11727 + }
  11728 + this.DispatchInstance.updatePage(() => {
  11729 + node.setVisible(isShow)
  11730 + })
  11731 + }
  11732 +
  11733 + /**
  11734 + * @description 验证是否满足条件列表中的任意一条
  11735 + * @param subscriptionId
  11736 + * @param type
  11737 + * @param value
  11738 + * @return {{flag: boolean, condition: {}}}
  11739 + */
  11740 + validate(subscriptionId, type, value) {
  11741 + const { condition = [], attr } = this.getBindData(subscriptionId, type)
  11742 + const result = { condition: {}, flag: false }
  11743 + for (let i = 0; i < condition.length; i++) {
  11744 + const { min, max } = condition[i]
  11745 + const [timespan, realValue] = value[attr][0]
  11746 + result.flag = this.isExistInArea(min, max, realValue)
  11747 + if (result.flag) {
  11748 + result.condition = condition[i]
  11749 + break
  11750 + }
  11751 + }
  11752 + return result
  11753 + }
  11754 +
  11755 + /**
  11756 + * @description 判断一个数是否在区间范围内
  11757 + * @param min 最小值
  11758 + * @param max 最大值
  11759 + * @param value 值
  11760 + * @return {boolean}
  11761 + */
  11762 + isExistInArea(min, max, value) {
  11763 + return Number(value) >= Number(min) && Number(value) <= Number(max)
  11764 + }
  11765 +
  11766 + /**
  11767 + * @description 获取绑定的数据
  11768 + * @param subscriptionId
  11769 + * @param actionType
  11770 + * @return {*}
  11771 + */
  11772 + getBindData(subscriptionId, actionType) {
  11773 + const nodeId = this.getNodeIdByCmdId(subscriptionId)
  11774 + const temp = this.actNodeMapping.get(nodeId)
  11775 + return temp.get(actionType)
  11776 + }
  11777 +
  11778 + /**
  11779 + * @description 通过cmdID获取节点id
  11780 + * @param subscriptionId
  11781 + * @return {string}
  11782 + */
  11783 + getNodeIdByCmdId(subscriptionId) {
  11784 + return this.DispatchInstance.cmdIdMapping.get(subscriptionId)
11286 11785 }
11287 11786
  11787 + /**
  11788 + * @description 通过cmdID 获取节点
  11789 + * @param subscriptionId
  11790 + * @return {*}
  11791 + */
  11792 + getNodeByCmdId(subscriptionId) {
  11793 + const nodeId = this.getNodeIdByCmdId(subscriptionId)
  11794 + return this.DispatchInstance.contentAllCell.find(item => item.id === nodeId)
  11795 + }
  11796 +
  11797 +}
  11798 +
  11799 +class RAFSetTimeoutImp {
  11800 + constructor(callback, time = 0) {
  11801 + this.callback = callback;
  11802 + this.time = time;
  11803 + this.now = Date.now;
  11804 + this.current = this.now();
  11805 + this.old = this.now();
  11806 + const fn = () => {
  11807 + if (this.current - this.old > this.time) {
  11808 + this.callback();
  11809 + this.old = this.now();
  11810 + this.clear();
  11811 + return;
  11812 + }
  11813 + this.current = this.now();
  11814 + this.instance = window.requestAnimationFrame(fn);
  11815 + };
  11816 + this.instance = window.requestAnimationFrame(fn);
  11817 + }
  11818 +
  11819 + clear() {
  11820 + window.cancelAnimationFrame(this.instance);
  11821 + this.instance = null;
  11822 + }
  11823 +};
  11824 +
  11825 +function RAFSetTimeout(callback, time) {
  11826 + const instance = new RAFSetTimeoutImp(callback, time);
  11827 + return instance.clear.bind(instance);
  11828 +}
  11829 +
  11830 +class RAFSetIntervalImp {
  11831 + constructor(callback, time = 0) {
  11832 + this.callback = callback;
  11833 + this.time = time;
  11834 + this.now = Date.now;
  11835 + this.current = this.now();
  11836 + this.old = this.now();
  11837 + const fn = () => {
  11838 + if (this.current - this.old > this.time) {
  11839 + this.callback();
  11840 + this.old = this.now();
  11841 + }
  11842 + this.current = this.now();
  11843 + this.instance = window.requestAnimationFrame(fn);
  11844 + };
  11845 + this.instance = window.requestAnimationFrame(fn);
  11846 + }
  11847 +
  11848 + clear() {
  11849 + window.cancelAnimationFrame(this.instance);
  11850 + }
  11851 +};
  11852 +
  11853 +function RAFSetInterval(callback, time) {
  11854 + const instance = new RAFSetIntervalImp(callback, time);
  11855 + return instance.clear.bind(instance);
11288 11856 }
11289 11857
  11858 +
11290 11859 function globalInit() {
11291 11860 init()
11292 11861
... ... @@ -11295,14 +11864,14 @@ function globalInit() {
11295 11864 }
11296 11865
11297 11866 function initRealTime() {
11298   - setInterval(() => {
  11867 + RAFSetInterval(() => {
11299 11868 const allTimeNode = document.querySelectorAll('.thingKit-component__real-time .real-time__now')
11300 11869 for (const time of allTimeNode) {
11301 11870 const date = new Date()
11302   - time.innerHTML = `${ date.getHours() }:${ date.getMinutes() < 10 ? '0' : '' }${ date.getMinutes() }:${ date.getSeconds() < 10 ? '0' : '' }${ date.getSeconds() }`
  11871 + time.innerHTML = `${ date.getHours() < 10 ? '0' : '' }${ date.getHours() }:${ date.getMinutes() < 10 ? '0' : '' }${ date.getMinutes() }:${ date.getSeconds() < 10 ? '0' : '' }${ date.getSeconds() }`
11303 11872 }
11304 11873 }, 1000)
11305 11874 }
11306 11875 }
11307 11876
11308   -globalInit()
  11877 +globalInit()
\ No newline at end of file
... ...
... ... @@ -30,7 +30,9 @@ Menus.prototype.defaultFontSize = '12';
30 30 /**
31 31 * Sets the default font size.
32 32 */
33   -Menus.prototype.defaultMenuItems = ['file', 'edit', 'view', 'arrange', 'extras', 'help'];
  33 +// Menus.prototype.defaultMenuItems = ['file', 'edit', 'view', 'arrange', 'extras', 'help'];
  34 +// TODO 工具栏 文件选项隐藏
  35 +Menus.prototype.defaultMenuItems = ['edit', 'view', 'arrange', 'extras', 'help'];
34 36
35 37 /**
36 38 * Adds the label menu items to the given menu and parent.
... ...