Commit 0fe6b0e9323fd5ead5c696ecf96338e90256d62d

Authored by xp.Huang
2 parents 31edb9d6 391c03d4

Merge branch 'ww' into 'main'

perf: fix bug && add lockUnlock button && add switch to variable image library

See merge request huang/thingskit-drawio!36
  1 +<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1659059076466" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2250" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css">@font-face { font-family: feedback-iconfont; src: url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.woff2?t=1630033759944") format("woff2"), url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.woff?t=1630033759944") format("woff"), url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.ttf?t=1630033759944") format("truetype"); }
  2 +</style></defs><path d="M512 64C264.96 64 64 264.96 64 512s200.96 448 448 448 448-200.96 448-448S759.04 64 512 64zM512 832.352c-26.496 0-48-21.504-48-48s21.504-48 48-48 48 21.504 48 48S538.496 832.352 512 832.352zM600.576 505.184C572.736 532.992 544 561.728 544 587.552l0 54.112c0 17.664-14.336 32-32 32s-32-14.336-32-32l0-54.112c0-52.352 40-92.352 75.328-127.648C581.216 434.016 608 407.264 608 385.92c0-53.344-43.072-96.736-96-96.736-53.824 0-96 41.536-96 94.56 0 17.664-14.336 32-32 32s-32-14.336-32-32c0-87.424 71.776-158.56 160-158.56s160 72.096 160 160.736C672 433.792 635.68 470.08 600.576 505.184z" p-id="2251" fill="#dbdbdb"></path></svg>
\ No newline at end of file
... ...
... ... @@ -306,7 +306,7 @@
306 306 var supportedDomain = (hostName.substring(hostName.length - 8, hostName.length) === '.draw.io') ||
307 307 (hostName.substring(hostName.length - 13, hostName.length) === '.diagrams.net');
308 308
309   - const releaseVersion = '1658915861841'
  309 + const releaseVersion = '1658971884984'
310 310 const appMinSrc = Enable_OSS ? `${OSS_Prefix}app.min.js?v=${releaseVersion}` : `js/app.min.js?v=${releaseVersion}`
311 311 function loadAppJS() {
312 312 mxscript(appMinSrc, function () {
... ...
... ... @@ -5918,6 +5918,27 @@ App.prototype.updateButtonContainer = function()
5918 5918 {
5919 5919 if (this.shareButton == null)
5920 5920 {
  5921 + // TODO thingsKit 锁定 / 解锁 按钮
  5922 + this.lockButton = document.createElement('div');
  5923 + this.lockButton.className = 'geBtn gePrimaryBtn';
  5924 + this.lockButton.style.display = 'inline-block';
  5925 + this.lockButton.style.backgroundColor = '#F2931E';
  5926 + this.lockButton.style.borderColor = '#F08705';
  5927 + this.lockButton.style.backgroundImage = 'none';
  5928 + this.lockButton.style.marginTop = '-10px';
  5929 + this.lockButton.style.lineHeight = '28px';
  5930 + this.lockButton.style.minWidth = '0px';
  5931 + this.lockButton.style.cssFloat = 'right';
  5932 + this.lockButton.setAttribute('title', '锁定 / 解锁');
  5933 + mxUtils.write(this.lockButton, '锁定 / 解锁');
  5934 + mxEvent.addListener(this.lockButton, 'click', mxUtils.bind(this, function()
  5935 + {
  5936 + if (this.actions.actions.lockUnlock.enabled){
  5937 + this.actions.actions.lockUnlock.funct()
  5938 + }
  5939 + }));
  5940 + this.buttonContainer.appendChild(this.lockButton);
  5941 +
5921 5942 // TODO thingsKit 预览模式按钮
5922 5943 this.shareButton = document.createElement('div');
5923 5944 this.shareButton.className = 'geBtn gePrimaryBtn';
... ... @@ -6005,6 +6026,8 @@ App.prototype.updateButtonContainer = function()
6005 6026 this.shareButton = null;
6006 6027 this.saveButton.parentNode.removeChild(this.saveButton);
6007 6028 this.saveButton = null;
  6029 + this.lockButton.parentNode.removeChild(this.lockButton);
  6030 + this.lockButton = null;
6008 6031 }
6009 6032
6010 6033 //Fetch notifications
... ...
... ... @@ -321,9 +321,14 @@
321 321 SWITCH_STATE_SETTING: 'stateSetting',
322 322
323 323 /**
324   - * @description 只有单事件
  324 + * @description 只有单事件
325 325 */
326   - ONLY_SINGLE_EVENT: 'onlySingleEvent'
  326 + ONLY_SINGLE_EVENT: 'onlySingleEvent',
  327 +
  328 + /**
  329 + * @description 运行于停止
  330 + */
  331 + RUNNING_AND_STOP: 'runningAndStop'
327 332 }
328 333
329 334 /**
... ... @@ -680,9 +685,9 @@
680 685 //更多图形,显示出来的的标题跟id,同时包括图片
681 686
682 687 // TODO thingsKit 设置数据绑定展示面板
683   - const { LINE_CHART_EXPAND, BAR_CHART_EXPAND, DYNAMIC_EFFECT, DATA_SOURCE, VAR_IMAGE, INTERACTION, VIDEO: VIDEO_PANEL, SWITCH_STATE_SETTING, ONLY_SINGLE_EVENT } = this.enumPermissionPanel
  688 + const { LINE_CHART_EXPAND, BAR_CHART_EXPAND, DYNAMIC_EFFECT, DATA_SOURCE, VAR_IMAGE, INTERACTION, VIDEO: VIDEO_PANEL, SWITCH_STATE_SETTING, ONLY_SINGLE_EVENT, RUNNING_AND_STOP } = this.enumPermissionPanel
684 689 const { LINE, LINE_CHART, REAL_TIME, TITLE, VARIABLE, DEFAULT, BAR_CHART, VIDEO, SWITCH, PARAMS_SETTING_BUTTON } = this.enumComponentType
685   - this.setComponentPermission(LINE, [DYNAMIC_EFFECT])
  690 + this.setComponentPermission(LINE, [RUNNING_AND_STOP, DYNAMIC_EFFECT])
686 691 this.setComponentPermission(DEFAULT, [DYNAMIC_EFFECT])
687 692 this.setComponentPermission(REAL_TIME, [DYNAMIC_EFFECT])
688 693 this.setComponentPermission(TITLE, [INTERACTION, DYNAMIC_EFFECT])
... ... @@ -697,6 +702,7 @@
697 702 var thingskitEntries = [
698 703 { title: mxResources.get('general'), id: 'general', image: IMAGE_PATH + '/sidebar-general.png' },
699 704 { title: mxResources.get('arrows'), id: 'arrows2', image: IMAGE_PATH + '/sidebar-arrows2.png' },
  705 + { title: '控制元件', id: 'control', image: IMAGE_PATH + '/thingskit/控制元件.png' },
700 706 { title: "风机", id: 'fan', image: IMAGE_PATH + '/thingskit/风机.png' },
701 707 { title: "发动机", id: 'engine', image: IMAGE_PATH + '/thingskit/发动机.png' },
702 708 { title: "阀门", id: 'valve', image: IMAGE_PATH + '/thingskit/阀门.png' },
... ...
... ... @@ -40,7 +40,7 @@
40 40 const cell = new mxCell(template, new mxGeometry(0, 0, 180, 60), 'text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;overflow=hidden;');
41 41 cell.vertex = true;
42 42 this.setCellAttributes(cell, {
43   - [basicAttr.COMPONENT_TYPE]: componentType.LINE,
  43 + [basicAttr.COMPONENT_TYPE]: componentType.REAL_TIME,
44 44 placeholders: '1',
45 45 currentDate: currentDate,
46 46 })
... ...
... ... @@ -55,6 +55,11 @@
55 55 }));
56 56 })
57 57
  58 + this.setVariableImageLib('switch', '开关', [
  59 + { name: 'switch-on', path: '/images/thingskit/switch-on.svg', staticPath: `${Proxy_Prefix}/images/thingskit/switch-on.svg` },
  60 + { name: 'switch-off', path: '/images/thingskit/switch-on.svg', staticPath: `${Proxy_Prefix}/images/thingskit/switch-off.svg` },
  61 + ])
  62 +
58 63 this.setVariableImageLib(dt, label, lib)
59 64
60 65 this.addPaletteFunctions(dt, label, false, fns);
... ...
... ... @@ -588,6 +588,17 @@ Format.prototype.immediateRefresh = function () {
588 588 addClickHandler(label, stylePanel, idx++);
589 589 }
590 590
  591 + if (validateHasDataSourcePanel()) {
  592 + // bind data
  593 + mxUtils.write(label4, "数据绑定");
  594 + div.appendChild(label4);
  595 +
  596 + var dataPanel = div.cloneNode(false);
  597 + dataPanel.style.display = "none";
  598 + this.panels.push(new DataFormatPanel(this, ui, dataPanel));
  599 + this.container.appendChild(dataPanel);
  600 + }
  601 +
591 602 // Text
592 603 mxUtils.write(label2, mxResources.get("text"));
593 604 div.appendChild(label2);
... ... @@ -606,17 +617,6 @@ Format.prototype.immediateRefresh = function () {
606 617 this.panels.push(new ArrangePanel(this, ui, arrangePanel));
607 618 this.container.appendChild(arrangePanel);
608 619
609   - if (validateHasDataSourcePanel()) {
610   - // bind data
611   - mxUtils.write(label4, "数据绑定");
612   - div.appendChild(label4);
613   -
614   - var dataPanel = div.cloneNode(false);
615   - dataPanel.style.display = "none";
616   - this.panels.push(new DataFormatPanel(this, ui, dataPanel));
617   - this.container.appendChild(dataPanel);
618   - }
619   -
620 620 if (ss.cells.length > 0) {
621 621 addClickHandler(label2, textPanel, idx++);
622 622 } else {
... ... @@ -5016,7 +5016,8 @@ DataFormatPanel.prototype.addDataFont = function (container) {
5016 5016 FLASH: 'FLASH',
5017 5017 ROTATE: 'ROTATE',
5018 5018 IMAGE: 'IMAGE',
5019   - SWITCH: 'SWITCH'
  5019 + SWITCH: 'SWITCH',
  5020 + RUNNING: 'RUNNING'
5020 5021 }
5021 5022
5022 5023 const interactionList = [
... ... @@ -5133,7 +5134,8 @@ DataFormatPanel.prototype.addDataFont = function (container) {
5133 5134 [permissionKey.VAR_IMAGE]: createVarImagePanel,
5134 5135 [permissionKey.VIDEO]: createVideoBindPanel,
5135 5136 [permissionKey.SWITCH_STATE_SETTING]: createSwitchStateSettingPanel,
5136   - [permissionKey.ONLY_SINGLE_EVENT]: createParamsSettingButtonPanel
  5137 + [permissionKey.ONLY_SINGLE_EVENT]: createParamsSettingButtonPanel,
  5138 + [permissionKey.RUNNING_AND_STOP]: createRunningAndStopPanel
5137 5139 }
5138 5140
5139 5141
... ... @@ -5404,6 +5406,17 @@ DataFormatPanel.prototype.addDataFont = function (container) {
5404 5406 }
5405 5407
5406 5408 /**
  5409 + * @description 水流动效
  5410 + */
  5411 + function createRunningAndStopPanel() {
  5412 + dynamicEffectList.push({
  5413 + label: '水流动效',
  5414 + type: enumDynamicEffectType.RUNNING,
  5415 + category: enumCategory.ACT
  5416 + })
  5417 + }
  5418 +
  5419 + /**
5407 5420 * @description 是否是折线图
5408 5421 * @param {boolean} isLineChart
5409 5422 */
... ... @@ -6412,7 +6425,7 @@ DataFormatPanel.prototype.addDataFont = function (container) {
6412 6425 }
6413 6426
6414 6427 const sendInstructionWay = {
6415   - ONE_WAR: 'oneway',
  6428 + ONE_WAY: 'oneway',
6416 6429 TWO_WAY: 'twoway',
6417 6430 }
6418 6431
... ... @@ -6493,8 +6506,8 @@ DataFormatPanel.prototype.addDataFont = function (container) {
6493 6506 <td>
6494 6507 <form action="" style="display: flex">
6495 6508 <div class="override__radio-default">
6496   - <input id="${getRowFilter(addRowNumber)}${sendInstructionWay.ONE_WAR}" type="radio" name="${enumConst.WAY}" lay-ignore value="${sendInstructionWay.ONE_WAR}" title="单向" checked="">
6497   - <label for="${getRowFilter(addRowNumber)}${sendInstructionWay.ONE_WAR}" class="override__radio-label">单向</label>
  6509 + <input id="${getRowFilter(addRowNumber)}${sendInstructionWay.ONE_WAY}" type="radio" name="${enumConst.WAY}" lay-ignore value="${sendInstructionWay.ONE_WAY}" title="单向" checked="">
  6510 + <label for="${getRowFilter(addRowNumber)}${sendInstructionWay.ONE_WAY}" class="override__radio-label">单向</label>
6498 6511 </div>
6499 6512 <div class="override__radio-default">
6500 6513 <input id="${getRowFilter(addRowNumber)}${sendInstructionWay.TWO_WAY}" type="radio" name="${enumConst.WAY}" lay-ignore value="${sendInstructionWay.TWO_WAY}" title="双向">
... ... @@ -6784,6 +6797,18 @@ DataFormatPanel.prototype.addDataFont = function (container) {
6784 6797 ACTION: 'actionType',
6785 6798 PAGE_VALUE: 'pageValue',
6786 6799 LINK_VALUE: 'linkValue',
  6800 +
  6801 + /**
  6802 + * @description 下发指令
  6803 + */
  6804 + COMMAND: 'command',
  6805 +
  6806 + /**
  6807 + * @description 属性占位符
  6808 + */
  6809 + ATTR_PLACEHOLDER: 'attrPlaceholder',
  6810 +
  6811 + WAY: 'way'
6787 6812 }
6788 6813
6789 6814 /**
... ... @@ -6796,6 +6821,11 @@ DataFormatPanel.prototype.addDataFont = function (container) {
6796 6821 [enumActionType.LINK]: enumConst.LINK_VALUE,
6797 6822 }
6798 6823
  6824 + const enumWayType = {
  6825 + ONE_WAY: 'oneway',
  6826 + TWO_WAY: 'twoway'
  6827 + }
  6828 +
6799 6829 const enumActionEl = {
6800 6830 /**
6801 6831 * @description 表单 lay-filter
... ... @@ -6821,6 +6851,18 @@ DataFormatPanel.prototype.addDataFont = function (container) {
6821 6851 * @description layer submit filter
6822 6852 */
6823 6853 LAYER_SUBMIT_FILTER: 'dynamicLinkLayerFilter',
  6854 +
  6855 + /**
  6856 + * @description JSON 编辑器容器
  6857 + */
  6858 + EDITOR_CONTAINER: 'editorContainerEL',
  6859 +
  6860 + /**
  6861 + * @description JSON 编辑器
  6862 + */
  6863 + EDITOR: 'EDITOR',
  6864 +
  6865 + WAY_SELECT: 'dynamicWaySelectEl'
6824 6866 }
6825 6867
6826 6868 /**
... ... @@ -6838,15 +6880,33 @@ DataFormatPanel.prototype.addDataFont = function (container) {
6838 6880 const val = {
6839 6881 [enumConst.ACTION]: content.type,
6840 6882 [enumGetValue[content.type]]: content.value,
  6883 + [enumConst.WAY]: content[enumConst.WAY]
6841 6884 }
6842   - if (content.type === enumActionType.PAGE) {
6843   - $(`#${enumActionEl.PAGE_EL_ID}`).css({ display: 'block' })
  6885 + controlFormDisplay(content.type)
  6886 + form.val(enumActionEl.FORM_FILTER, val)
  6887 + }
  6888 +
  6889 + /**
  6890 + * @description 控制form
  6891 + * @param {enumActionType} value
  6892 + */
  6893 + function controlFormDisplay(value) {
  6894 + if (value === enumActionType.PAGE) {
6844 6895 $(`#${enumActionEl.LINK_EL_ID}`).css({ display: 'none' })
6845   - } else if (content.type === enumActionType.PARAMS_SETTING) {
  6896 + $(`#${enumActionEl.PAGE_EL_ID}`).css({ display: 'block' })
  6897 + $(`#${enumActionEl.EDITOR_CONTAINER}`).css({ display: 'none' })
  6898 + $(`#${enumActionEl.WAY_SELECT}`).css({ display: 'none' })
  6899 + } else if (value === enumActionType.LINK) {
6846 6900 $(`#${enumActionEl.PAGE_EL_ID}`).css({ display: 'none' })
  6901 + $(`#${enumActionEl.LINK_EL_ID}`).css({ display: 'block' })
  6902 + $(`#${enumActionEl.EDITOR_CONTAINER}`).css({ display: 'none' })
  6903 + $(`#${enumActionEl.WAY_SELECT}`).css({ display: 'none' })
  6904 + } else if (value === enumActionType.PARAMS_SETTING) {
6847 6905 $(`#${enumActionEl.LINK_EL_ID}`).css({ display: 'none' })
  6906 + $(`#${enumActionEl.PAGE_EL_ID}`).css({ display: 'none' })
  6907 + $(`#${enumActionEl.EDITOR_CONTAINER}`).css({ display: 'flex' })
  6908 + $(`#${enumActionEl.WAY_SELECT}`).css({ display: 'block' })
6848 6909 }
6849   - form.val(enumActionEl.FORM_FILTER, val)
6850 6910 }
6851 6911
6852 6912 /**
... ... @@ -6854,6 +6914,15 @@ DataFormatPanel.prototype.addDataFont = function (container) {
6854 6914 */
6855 6915 async function submit(callback) {
6856 6916 const formVal = form.val(enumActionEl.FORM_FILTER)
  6917 + const isParamsSetting = formVal[enumConst.ACTION] === enumActionType.PARAMS_SETTING
  6918 + if (isParamsSetting) {
  6919 + if (!isJson(formVal[enumConst.COMMAND])) {
  6920 + console.log()
  6921 + UseLayUi.topErrorMsg('命令配置存在错误')
  6922 + return
  6923 + }
  6924 + }
  6925 +
6857 6926 const data = {
6858 6927 type: event.data.type,
6859 6928 configurationId,
... ... @@ -6864,6 +6933,10 @@ DataFormatPanel.prototype.addDataFont = function (container) {
6864 6933 content: {
6865 6934 type: formVal[enumConst.ACTION],
6866 6935 value: formVal[enumGetValue[formVal[enumConst.ACTION]]],
  6936 + ...(isParamsSetting ? {
  6937 + [enumConst.COMMAND]: formVal[enumConst.COMMAND],
  6938 + [enumConst.WAY]: formVal[enumConst.WAY]
  6939 + } : {}),
6867 6940 },
6868 6941 }
6869 6942 await to(autoSaveGraphInfo())
... ... @@ -6899,16 +6972,53 @@ DataFormatPanel.prototype.addDataFont = function (container) {
6899 6972 function generatorEventListen() {
6900 6973 form.on(`select(${enumActionEl.ACTION_SELECT_FILTER})`, (data) => {
6901 6974 const { value } = data
6902   - if (value === enumActionType.PAGE) {
6903   - $(`#${enumActionEl.LINK_EL_ID}`).css({ display: 'none' })
6904   - $(`#${enumActionEl.PAGE_EL_ID}`).css({ display: 'block' })
6905   - } else if (value === enumActionType.LINK) {
6906   - $(`#${enumActionEl.PAGE_EL_ID}`).css({ display: 'none' })
6907   - $(`#${enumActionEl.LINK_EL_ID}`).css({ display: 'block' })
6908   - } else if (value === enumActionType.PARAMS_SETTING) {
6909   - $(`#${enumActionEl.LINK_EL_ID}`).css({ display: 'none' })
6910   - $(`#${enumActionEl.PAGE_EL_ID}`).css({ display: 'none' })
  6975 + controlFormDisplay(value)
  6976 + })
  6977 + }
  6978 +
  6979 + function isJson(string) {
  6980 + if (typeof string === 'string') {
  6981 + try {
  6982 + const obj = JSON.parse(string)
  6983 + if (typeof obj === 'object' && obj !== null) {
  6984 + return true
  6985 + }
  6986 + } catch (e) {
  6987 + return false
6911 6988 }
  6989 + }
  6990 + return false
  6991 + }
  6992 +
  6993 + function jsonParse(value) {
  6994 + try {
  6995 + return JSON.parse(value)
  6996 + } catch (error) {
  6997 + return {}
  6998 + }
  6999 + }
  7000 +
  7001 +
  7002 + /**
  7003 + * @description 创建JSON编辑器
  7004 + * @param el
  7005 + * @param datum
  7006 + */
  7007 + function createEditor(record) {
  7008 + let defaultValue = { [enumConst.ATTR_PLACEHOLDER]: 0 }
  7009 + const editor = ace.edit(enumActionEl.EDITOR, {
  7010 + maxLines: 18, // 最大行数,超过会自动出现滚动条
  7011 + minLines: 10, // 最小行数,还未到最大行数时,编辑器会自动伸缩大小
  7012 + fontSize: 14, // 编辑器内字体大小
  7013 + tabSize: 2, // 制表符设置为 4 个空格大小
  7014 + });
  7015 + if (record.content && record.content[enumConst.COMMAND]) defaultValue = jsonParse(record.content[enumConst.COMMAND])
  7016 + const stringValue = JSON.stringify(defaultValue, null, 2)
  7017 + editor.insert(stringValue)
  7018 + $(`#${enumActionEl.EDITOR_CONTAINER}`).parent().find(`textarea[name="${enumConst.COMMAND}"]`).val(stringValue)
  7019 + editor.session.setMode("ace/mode/json");
  7020 + editor.getSession().on('change', (event, editor) => {
  7021 + $(`#${enumActionEl.EDITOR_CONTAINER}`).parent().find(`textarea[name="${enumConst.COMMAND}"]`).val(editor.getValue())
6912 7022 })
6913 7023 }
6914 7024
... ... @@ -6919,7 +7029,7 @@ DataFormatPanel.prototype.addDataFont = function (container) {
6919 7029
6920 7030 const content = `
6921 7031 <form class="layui-form" lay-filter="${enumActionEl.FORM_FILTER}">
6922   - <div style="width:400px">
  7032 + <div style="width: 450px">
6923 7033 <div class="layui-form-item">
6924 7034 <label class="layui-form-label">事件</label>
6925 7035 <div class="layui-input-block">
... ... @@ -6948,6 +7058,18 @@ DataFormatPanel.prototype.addDataFont = function (container) {
6948 7058 </select>
6949 7059 </div>
6950 7060 </div>
  7061 + <div class="layui-form-item" id="${enumActionEl.WAY_SELECT}" style="display:none">
  7062 + <label class="layui-form-label">单向/双向</label>
  7063 + <div class="layui-input-block">
  7064 + <input type="radio" name="${enumConst.WAY}" value="${enumWayType.ONE_WAY}" title="单向" checked="">
  7065 + <input type="radio" name="${enumConst.WAY}" value="${enumWayType.TWO_WAY}" title="双向">
  7066 + </div>
  7067 + </div>
  7068 + <div id="${enumActionEl.EDITOR_CONTAINER}" style="display: none;">
  7069 + <div style="width: 80px; text-align: right; padding: 9px 15px;flex: 0 0 80px;">命令</div>
  7070 + <div id="${enumActionEl.EDITOR}" style="width: 100%; height: 100%;border: 2px solid #eee;"></div>
  7071 + <textarea name="${enumConst.COMMAND}" style="display: none;" />
  7072 + </div>
6951 7073 </div>
6952 7074 </form>
6953 7075 `
... ... @@ -6976,6 +7098,7 @@ DataFormatPanel.prototype.addDataFont = function (container) {
6976 7098 generatorEventListen()
6977 7099 const info = getLayerBindInfo('event', type)
6978 7100 Object.assign(recordData, { enabled: info.enabled })
  7101 + createEditor(info)
6979 7102 form.render(null, enumActionEl.FORM_FILTER)
6980 7103 if (info) echoFormData(info)
6981 7104 },
... ... @@ -6991,12 +7114,14 @@ DataFormatPanel.prototype.addDataFont = function (container) {
6991 7114 */
6992 7115 function handleDataDynamicEffect(event) {
6993 7116
6994   - const IS_DISPLAY = event.data.type === 'DISPLAY'
  7117 + const IS_DISPLAY = event.data.type === enumDynamicEffectType.DISPLAY
  7118 + const IS_RUNNING = event.data.type === enumDynamicEffectType.RUNNING
6995 7119
6996 7120 const enumEventType = {
6997 7121 FLASH: '闪烁',
6998 7122 DISPLAY: '显示/隐藏',
6999 7123 ROTATE: '旋转',
  7124 + RUNNING: '水流动效'
7000 7125 }
7001 7126
7002 7127 const enumActionEl = {
... ... @@ -7031,6 +7156,18 @@ DataFormatPanel.prototype.addDataFont = function (container) {
7031 7156
7032 7157 const enumDisplayType = HandleDynamicEffect.enumDisplayType
7033 7158
  7159 + const enumRunningType = HandleDynamicEffect.enumRunningType
  7160 +
  7161 + const displayOptions = [
  7162 + { name: '显示', id: enumDisplayType.SHOW },
  7163 + { name: '隐藏', id: enumDisplayType.HIDDEN },
  7164 + ]
  7165 +
  7166 + const runningOptions = [
  7167 + { name: '流动', id: enumRunningType.RUN },
  7168 + { name: '静止', id: enumRunningType.STOP },
  7169 + ]
  7170 +
7034 7171 /**
7035 7172 * @description
7036 7173 */
... ... @@ -7040,12 +7177,8 @@ DataFormatPanel.prototype.addDataFont = function (container) {
7040 7177 enabled: false
7041 7178 }
7042 7179
7043   - function generatorDisplayOptions() {
7044   - const options = [
7045   - { name: '显示', id: enumDisplayType.SHOW },
7046   - { name: '隐藏', id: enumDisplayType.HIDDEN },
7047   - ]
7048   - const template = UseLayUi.generateOptionTemplate({ dataSource: options })
  7180 + function generateStateOptions(options = []) {
  7181 + const template = UseLayUi.generateOptionTemplate({ dataSource: options, addPlaceholderOption: false })
7049 7182 return `
7050 7183 <div class="layui-form-item" style="margin-bottom: 0px">
7051 7184 <div class="layui-input-block" style="margin-left: 0px;">
... ... @@ -7061,7 +7194,8 @@ DataFormatPanel.prototype.addDataFont = function (container) {
7061 7194 function addRecord() {
7062 7195 const content = `
7063 7196 <tr class="layui-form" lay-filter="${getRowFilter(addRowNumber)}">
7064   - ${IS_DISPLAY && `<td>${generatorDisplayOptions()}</td>`}
  7197 + ${IS_DISPLAY && `<td>${generateStateOptions(displayOptions)}</td>`}
  7198 + ${IS_RUNNING && `<td>${generateStateOptions(runningOptions)}</td>`}
7065 7199 <td>
7066 7200 <input autocomplete="off" lay-verType="tips" lay-verify="required" type="number" name="${enumConst.MIN}" class="layui-input ${enumActionEl.MIN_FILTER}">
7067 7201 </td>
... ... @@ -7075,7 +7209,7 @@ DataFormatPanel.prototype.addDataFont = function (container) {
7075 7209 `
7076 7210 addRowNumber++
7077 7211 $(`#${enumActionEl.TABLE_BODY_EL}`).append(content)
7078   - if (IS_DISPLAY) {
  7212 + if (IS_DISPLAY || IS_RUNNING) {
7079 7213 form.render()
7080 7214 }
7081 7215 }
... ... @@ -7232,6 +7366,7 @@ DataFormatPanel.prototype.addDataFont = function (container) {
7232 7366 <thead>
7233 7367 <tr>
7234 7368 ${IS_DISPLAY ? '<th style="text-align:center">类型</th>' : ''}
  7369 + ${IS_RUNNING ? '<th style="text-align:center">类型</th>' : ''}
7235 7370 <th style="text-align:center">最小值(>=)</th>
7236 7371 <th style="text-align:center">最大值(<=)</th>
7237 7372 <th style="text-align:center">操作</th>
... ... @@ -7251,7 +7386,7 @@ DataFormatPanel.prototype.addDataFont = function (container) {
7251 7386 skin: 'event-layer__override',
7252 7387 btn: ['保存', '取消'],
7253 7388 offset: '100px',
7254   - area: IS_DISPLAY ? '1000px' : '800PX',
  7389 + area: (IS_DISPLAY || IS_RUNNING) ? '1000px' : '800PX',
7255 7390 success(layero) {
7256 7391 $(layero).addClass('layui-form').find('.layui-layer-btn0').attr({
7257 7392 'lay-submit': '',
... ... @@ -7447,6 +7582,7 @@ DataFormatPanel.prototype.addDataFont = function (container) {
7447 7582 const [err, res] = await to(ConfigurationNodeApi.updateNodeAct(formModel))
7448 7583 if (err) return
7449 7584 overrideCurrentData('act', 'type', res)
  7585 + echoActionType()
7450 7586 UseLayUi.successMsg()
7451 7587 callback()
7452 7588 }
... ... @@ -8129,7 +8265,6 @@ DataFormatPanel.prototype.addDataFont = function (container) {
8129 8265 generateUploadLayerComponent((imageState) => {
8130 8266 $(el).find('img').attr('src', imageState[enumConst.IMAGE_GALLERY_IMAGE_PATH])
8131 8267 form.val(getFormFilter, imageState)
8132   - console.log(form.val(getFormFilter))
8133 8268 })
8134 8269 })
8135 8270 }
... ... @@ -8138,6 +8273,10 @@ DataFormatPanel.prototype.addDataFont = function (container) {
8138 8273 return { getValue, setValue }
8139 8274 }
8140 8275
  8276 + function createHelpMessage() {
  8277 + return `<span class="thingskit-help-message"><img src="${Proxy_Prefix}/images/thingskit/question.svg" /></span>`
  8278 + }
  8279 +
8141 8280 // 异步设置此处才能生效 -- 设置默认select和样式和初始化侧边栏生成组件和事件绑定
8142 8281 setTimeout(() => {
8143 8282
... ... @@ -8166,8 +8305,11 @@ DataFormatPanel.prototype.addDataFont = function (container) {
8166 8305 $(`#${enumDynamicEffectType.FLASH}`).click({ type: enumDynamicEffectType.FLASH }, proxyFn(handleDataDynamicEffect));
8167 8306 $(`#${enumDynamicEffectType.DISPLAY}`).click({ type: enumDynamicEffectType.DISPLAY }, proxyFn(handleDataDynamicEffect));
8168 8307 $(`#${enumDynamicEffectType.ROTATE}`).click({ type: enumDynamicEffectType.ROTATE }, proxyFn(handleDataDynamicEffect));
  8308 + $(`#${enumDynamicEffectType.RUNNING}`).click({ type: enumDynamicEffectType.RUNNING }, proxyFn(handleDataDynamicEffect))
8169 8309
8170 8310 $(`#${enumDynamicEffectType.SWITCH}`).click({ type: enumDynamicEffectType.SWITCH }, proxyFn(handleStateSetting))
  8311 +
  8312 +
8171 8313 });
8172 8314 };
8173 8315
... ... @@ -12379,14 +12521,21 @@ class UseLayUi {
12379 12521 UseLayUi.msg(msg, { ...options, icon: 5 })
12380 12522 }
12381 12523
12382   - static topSuccessMsg(msg = '操作成功', options) {
  12524 + static topMsg(msg, options, icon) {
12383 12525 const { layer } = layui
12384   - layer.msg(`<div style="padding: 20px; display: flex; align-items: center;"><i class="layui-layer-ico layui-layer-ico6" style="width: 30px;height: 30px;"></i><span style="margin-left: 5px">${msg}</span></div>`, { ...options, type: 1, icon: 6, time: 2000, })
  12526 + layer.msg(`<div style="padding: 20px; display: flex; align-items: center;"><i class="layui-layer-ico layui-layer-ico6" style="width: 30px;height: 30px;"></i><span style="margin-left: 5px">${msg}</span></div>`, { ...options, type: 1, icon, time: 2000, })
  12527 + }
  12528 +
  12529 + static topSuccessMsg(msg = '操作成功', options) {
  12530 + this.topMsg(msg, options, 6)
12385 12531 }
12386 12532
12387 12533 static topErrorMsg(msg = '操作失败', options) {
12388   - const { layer } = layui
12389   - layer.msg(`<div style="padding: 20px; display: flex; align-items: center;"><i class="layui-layer-ico layui-layer-ico5" style="width: 30px;height: 30px;"></i><span style="margin-left: 5px">${msg}</span></div>`, { ...options, type: 1, icon: 5, time: 2000, })
  12534 + this.topMsg(msg, options, 5)
  12535 + }
  12536 +
  12537 + static topInfoMsg(msg = '提示', options) {
  12538 + this.topMsg(msg, options, 0)
12390 12539 }
12391 12540 }
12392 12541
... ... @@ -13230,20 +13379,24 @@ class HandleDataSource {
13230 13379 const [[timespan, receiveValue] = []] = data[attr] || []
13231 13380 const switchConfig = this.DispatchInstance.contentData.act.find(item => item.id === nodeId && item.type === 'SWITCH')
13232 13381 const { condition = [] } = switchConfig || {}
13233   - let reg = /image=images[^;]+/g
  13382 + let reg = /image=[^;]+/g
13234 13383 let flag = false
13235 13384 for (const item of condition) {
13236 13385 const { value, imagePath } = item || {}
13237 13386 if (Number(receiveValue) === Number(value)) {
13238 13387 flag = true
13239   - const style = node.getStyle()
13240   - node.setStyle(style.replace(reg, `image=${imagePath}`))
  13388 + this.updatePage(() => {
  13389 + const style = node.getStyle()
  13390 + node.setStyle(style.replace(reg, `image=${imagePath}`))
  13391 + }, node)
13241 13392 break
13242 13393 }
13243 13394 }
13244 13395 if (!flag) {
13245   - const style = node.getStyle()
13246   - node.setStyle(style.replace(reg, `image=images/thingskit/not-standard-value.svg`))
  13396 + this.updatePage(() => {
  13397 + const style = node.getStyle()
  13398 + node.setStyle(style.replace(reg, `image=images/thingskit/not-standard-value.svg`))
  13399 + }, node)
13247 13400 }
13248 13401 }
13249 13402
... ... @@ -13252,7 +13405,9 @@ class HandleDataSource {
13252 13405 const node = this.getNodeByCmdId(subscriptionId)
13253 13406 const { attr } = this.getBindData(subscriptionId)
13254 13407 const [[timespan, receiveValue] = []] = data[attr] || []
13255   - node.setAttribute('label', `<button class="param-setting-button">${receiveValue}</button>`)
  13408 + this.updatePage(() => {
  13409 + node.setAttribute('label', `<button class="param-setting-button">${receiveValue}</button>`)
  13410 + }, node)
13256 13411 }
13257 13412
13258 13413 /**
... ... @@ -13521,9 +13676,6 @@ class HandleDataSource {
13521 13676 }
13522 13677
13523 13678 instance.setOption(chartOption)
13524   - instance.on('dataZoom', () => {
13525   - console.log(instance.getOption())
13526   - })
13527 13679 // instance.on('mouseover', stop)
13528 13680 // instance.on('mouseout', goMove)
13529 13681 // autoMove()
... ... @@ -13641,6 +13793,13 @@ class HandleDataInteraction {
13641 13793 }
13642 13794
13643 13795 /**
  13796 + * @description 获取页面数据
  13797 + */
  13798 + get contentData() {
  13799 + return DispatchCenter.instance.contentData
  13800 + }
  13801 +
  13802 + /**
13644 13803 * @description 事件映射
13645 13804 */
13646 13805 generatorEventMapping() {
... ... @@ -13741,7 +13900,7 @@ class HandleDataInteraction {
13741 13900 } else if (type === DispatchCenter.enumPageType.LINK && value) {
13742 13901 window.open(value)
13743 13902 } else if (type === DispatchCenter.enumPageType.PARAMS_SETTING) {
13744   - this.paramsSetting(id)
  13903 + this.paramsSetting(id, content)
13745 13904 }
13746 13905 }
13747 13906 }
... ... @@ -13789,15 +13948,20 @@ class HandleDataInteraction {
13789 13948 method: "methodThingskit",
13790 13949 params: JSON.parse(value),
13791 13950 }
13792   - if (slaveDeviceId) {
13793   - queue.push(() => {
13794   - fn(way, slaveDeviceId, data)
13795   - })
13796   - } else if (deviceId) {
  13951 + if (deviceId) {
13797 13952 queue.push(() => {
13798 13953 fn(way, deviceId, data)
13799 13954 })
13800 13955 }
  13956 + // if (slaveDeviceId) {
  13957 + // queue.push(() => {
  13958 + // fn(way, slaveDeviceId, data)
  13959 + // })
  13960 + // } else if (deviceId) {
  13961 + // queue.push(() => {
  13962 + // fn(way, deviceId, data)
  13963 + // })
  13964 + // }
13801 13965 }
13802 13966
13803 13967 Promise.all(queue.map(fn => fn()))
... ... @@ -13829,13 +13993,15 @@ class HandleDataInteraction {
13829 13993 /**
13830 13994 * @description 参数设置
13831 13995 */
13832   - paramsSetting(nodeId) {
  13996 + paramsSetting(nodeId, content) {
13833 13997 const { layer, jquery: $, form } = layui
  13998 + const contentData = this.contentData
13834 13999 const enumConst = {
13835 14000 VALUE: 'value',
13836 14001 ISSUED_WAY: 'way',
13837   - ONE_WAR: 'oneway',
13838   - TWO_WAY: 'twoway'
  14002 + ONE_WAY: 'oneway',
  14003 + TWO_WAY: 'twoway',
  14004 + ATTR_PLACEHOLDER: 'attrPlaceholder'
13839 14005 }
13840 14006
13841 14007 const enumActionEl = {
... ... @@ -13845,40 +14011,17 @@ class HandleDataInteraction {
13845 14011
13846 14012 }
13847 14013
13848   - /**
13849   - * @description 创建JSON编辑器
13850   - * @param el
13851   - * @param datum
13852   - */
13853   - function createEditor() {
13854   - const editor = ace.edit(enumActionEl.EDITOR, {
13855   - maxLines: 18, // 最大行数,超过会自动出现滚动条
13856   - minLines: 10, // 最小行数,还未到最大行数时,编辑器会自动伸缩大小
13857   - fontSize: 14, // 编辑器内字体大小
13858   - tabSize: 2, // 制表符设置为 4 个空格大小
13859   - });
13860   - editor.session.setMode("ace/mode/json");
13861   - editor.getSession().on('change', (event, editor) => {
13862   - $(`#${enumActionEl.CONTAINER}`).parent().find(`textarea[name="${enumConst.VALUE}"]`).val(editor.getValue())
13863   - })
13864   - }
13865   -
13866 14014 function createContent() {
13867 14015 return `
13868 14016 <div>
13869 14017 <div class="layui-form" lay-filter="${enumActionEl.ISSUED_WAY_FILTER}">
13870 14018 <div class="layui-form-item">
13871   - <label class="layui-form-label">单向/双向</label>
  14019 + <label class="layui-form-label">下发值</label>
13872 14020 <div class="layui-input-block">
13873   - <input type="radio" name="${enumConst.ISSUED_WAY}" value="${enumConst.ONE_WAR}" title="单向" checked="">
13874   - <input type="radio" name="${enumConst.ISSUED_WAY}" value="${enumConst.TWO_WAY}" title="双向">
  14021 + <input type="text" name="${enumConst.VALUE}" lay-verify="required" autocomplete="off" placeholder="请输入下发值" class="layui-input">
13875 14022 </div>
13876 14023 </div>
13877 14024 </div>
13878   - <div id="${enumActionEl.CONTAINER}">
13879   - <div id="${enumActionEl.EDITOR}"></div>
13880   - <textarea name="${enumConst.VALUE}" style="display: none;" />
13881   - </div>
13882 14025 </div>`
13883 14026 }
13884 14027
... ... @@ -13895,25 +14038,52 @@ class HandleDataInteraction {
13895 14038 }
13896 14039 return false
13897 14040 }
13898   - const submitThrottle = this.throttle(submit)
13899   - async function submit(callback) {
13900   - const value = $(`#${enumActionEl.CONTAINER}`).parent().find(`textarea[name="${enumConst.VALUE}"]`).val() || ''
13901   - if (!isJson(value)) {
13902   - UseLayUi.topErrorMsg('下发值不正确')
13903   - return
  14041 +
  14042 + function jsonParse(value) {
  14043 + try {
  14044 + return JSON.parse(value)
  14045 + } catch (error) {
  14046 + return {}
13904 14047 }
13905   - const { way } = form.val(enumActionEl.ISSUED_WAY_FILTER)
13906   - const data = JSON.parse(value)
13907   - let { deviceId, slaveDeviceId } = DispatchCenter.instance.contentData.dataSources.find(item => item.nodeId === nodeId) || {}
  14048 + }
13908 14049
13909   - if (!value || !deviceId) return
  14050 + function replaceAttrPlaceholder(oldValue = {}, replaceAttr = '', replaceValue = '', newValue = {},) {
  14051 + if (typeof oldValue !== 'object') return newValue
  14052 +
  14053 + for (const key of Object.keys(oldValue)) {
  14054 + if (key === enumConst.ATTR_PLACEHOLDER) {
  14055 + newValue[replaceAttr] = replaceValue
  14056 + continue
  14057 + }
  14058 + if (typeof oldValue[key] === 'object') {
  14059 + newValue[key] = replaceAttrPlaceholder(oldValue[key], replaceAttr, replaceValue)
  14060 + continue
  14061 + }
  14062 + newValue[key] = oldValue[key]
  14063 + }
  14064 +
  14065 + return newValue
  14066 + }
  14067 +
  14068 + const submitThrottle = this.throttle(submit)
  14069 + async function submit(callback) {
  14070 + const { value } = form.val(enumActionEl.ISSUED_WAY_FILTER)
  14071 + let { deviceId, attr } = contentData.dataSources.find(item => item.nodeId === nodeId) || {}
  14072 + let { command, way } = content
  14073 + const validate = new Validate([
  14074 + { value, required: true, message: '下发值是必填项' },
  14075 + { value: deviceId, required: true, message: '未绑定设备' },
  14076 + { value: way, required: true, message: '未绑定指令下发方式(单向/双向)' },
  14077 + { value: command, required: true, message: '未设置下发命令' },
  14078 + { value: attr, required: true, message: '未绑定设备属性' },
  14079 + ])
  14080 + if (!validate.begin()) return
  14081 + if (typeof command === 'string') command = jsonParse(command)
  14082 + const data = replaceAttrPlaceholder(command, attr, value)
13910 14083 const instructionData = {
13911 14084 method: "methodThingskit",
13912 14085 params: data,
13913 14086 }
13914   - if (slaveDeviceId) {
13915   - deviceId = slaveDeviceId
13916   - }
13917 14087
13918 14088 const [err, res = []] = await to(ConfigurationNodeApi.deviceIsOnLine(deviceId))
13919 14089 const { value: onlineFlag } = res[0] || {}
... ... @@ -13933,7 +14103,7 @@ class HandleDataInteraction {
13933 14103 layer.open({
13934 14104 title: '参数设置',
13935 14105 content: createContent(),
13936   - area: '600px',
  14106 + area: '400px',
13937 14107 btn: ["应用", "取消"],
13938 14108 yes(index) {
13939 14109 submitThrottle(() => {
... ... @@ -13944,12 +14114,7 @@ class HandleDataInteraction {
13944 14114
13945 14115 },
13946 14116 async success(layero, index) {
13947   - createEditor(enumActionEl.EDITOR)
13948 14117 form.render()
13949   - // $(layero).addClass('layui-form').find('.layui-layer-btn0').attr({
13950   - // 'lay-submit': '',
13951   - // 'lay-filter': enumActionEl.IMAGE_LAYER_FILTER,
13952   - // })
13953 14118 },
13954 14119 })
13955 14120 }
... ... @@ -14001,6 +14166,7 @@ class HandleDynamicEffect {
14001 14166 DISPLAY: 'DISPLAY',
14002 14167 ROTATE: 'ROTATE',
14003 14168 IMAGE: 'IMAGE',
  14169 + RUNNING: 'RUNNING'
14004 14170 }
14005 14171
14006 14172 static enumDisplayType = {
... ... @@ -14008,6 +14174,11 @@ class HandleDynamicEffect {
14008 14174 HIDDEN: 'hidden',
14009 14175 }
14010 14176
  14177 + static enumRunningType = {
  14178 + RUN: 'run',
  14179 + STOP: 'stop'
  14180 + }
  14181 +
14011 14182 static enumVideoConst = {
14012 14183 ORG_ID: 'orgId',
14013 14184 RECORD_ID: 'id',
... ... @@ -14199,6 +14370,9 @@ class HandleDynamicEffect {
14199 14370 case HandleDynamicEffect.enumActType.IMAGE:
14200 14371 invoke = this.varImage.bind(this)
14201 14372 break
  14373 + case HandleDynamicEffect.enumActType.RUNNING:
  14374 + invoke = this.running.bind(this)
  14375 + break
14202 14376 }
14203 14377 return invoke
14204 14378 }
... ... @@ -14327,15 +14501,35 @@ class HandleDynamicEffect {
14327 14501 }
14328 14502 }
14329 14503
  14504 + running(message) {
  14505 + const { subscriptionId, data = {} } = message
  14506 + const { flag, condition } = this.validate(subscriptionId, HandleDynamicEffect.enumActType.RUNNING, data)
  14507 + if (!flag) return
  14508 + const node = this.getNodeByCmdId(subscriptionId)
  14509 + let isRun = false
  14510 + if (condition.type === HandleDynamicEffect.enumRunningType.RUN) {
  14511 + isRun = true
  14512 + } else if (condition.type === HandleDynamicEffect.enumRunningType.STOP) {
  14513 + isRun = false
  14514 + }
  14515 +
  14516 + const updateFn = () => {
  14517 + const reg = /flowAnimation[^;]+/
  14518 + const style = node.getStyle()
  14519 + node.setStyle(style.replace(reg, `flowAnimation=${isRun ? 1 : 0}`))
  14520 + }
  14521 + this.insertOnceUpdateFn(node, updateFn)
  14522 + }
  14523 +
14330 14524 /**
14331 14525 * @description 播放视频
14332 14526 */
14333 14527 videoPlay() {
14334 14528 const basicAttr = Sidebar.prototype.enumCellBasicAttribute
14335 14529 const enumAccessMode = HandleDynamicEffect.enumVideoAccessMode
14336   -
14337 14530 const videoPlayConfig = {
14338 14531 controls: true,
  14532 + autoPlay: true,
14339 14533 // bigPlayButton: true,
14340 14534 // textTrackDisplay: false,
14341 14535 // posterImage: false,
... ... @@ -14362,7 +14556,6 @@ class HandleDynamicEffect {
14362 14556 ...videoPlayConfig
14363 14557 },
14364 14558 function () {
14365   - console.log(idEl)
14366 14559 this.play()
14367 14560 })
14368 14561 }
... ... @@ -14677,3 +14870,37 @@ function RAFSetInterval(callback, time) {
14677 14870 }
14678 14871
14679 14872
  14873 +class Validate {
  14874 + /**
  14875 + * @description
  14876 + * @type {{value: any, message: string, required?: boolean, validator?: any}[]} list
  14877 + */
  14878 + list = []
  14879 +
  14880 + /**
  14881 + * @description
  14882 + * @param {{value: any, message: string, required?: boolean, validator?: any}[]} ruleList
  14883 + */
  14884 + constructor(ruleList = []) {
  14885 + this.list = ruleList
  14886 + }
  14887 +
  14888 + /**
  14889 + * @description 设置规则
  14890 + * @param {{value: any, message: string, required?: boolean, validator?: any}} rule
  14891 + */
  14892 + set(rule) {
  14893 + this.list.push(rule)
  14894 + }
  14895 +
  14896 + begin() {
  14897 + for (const rule of this.list) {
  14898 + const { required, value, message, validator } = rule
  14899 + if (required && !value) {
  14900 + UseLayUi.topErrorMsg(message)
  14901 + return false
  14902 + }
  14903 + }
  14904 + return true
  14905 + }
  14906 +}
... ...