@flexem/fc-gui 3.0.0-alpha.157 → 3.0.0-alpha.159

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (27) hide show
  1. package/bundles/@flexem/fc-gui.umd.js +358 -28
  2. package/bundles/@flexem/fc-gui.umd.js.map +1 -1
  3. package/bundles/@flexem/fc-gui.umd.min.js +4 -4
  4. package/bundles/@flexem/fc-gui.umd.min.js.map +1 -1
  5. package/communication/variable/variable-state-enum.d.ts +1 -0
  6. package/communication/variable/variable-state-enum.js +1 -0
  7. package/communication/variable/variable-state-enum.metadata.json +1 -1
  8. package/config/variable/variable-store.d.ts +1 -0
  9. package/elements/base/state-control-element.js +17 -4
  10. package/elements/historical-curve/historical-curve.element.d.ts +8 -1
  11. package/elements/historical-curve/historical-curve.element.js +306 -22
  12. package/elements/historical-curve/historical-curve.element.metadata.json +1 -1
  13. package/elements/switch-indicator-light/switch-indicator-light-element.js +9 -2
  14. package/gui/gui-context.d.ts +7 -0
  15. package/gui/gui-view.js +16 -1
  16. package/localization/localization.service.d.ts +4 -0
  17. package/localization/localization.service.js +4 -0
  18. package/localization/localization.service.metadata.json +1 -1
  19. package/localization/localization.service.zh_CN.js +4 -0
  20. package/localization/localization.service.zh_CN.metadata.json +1 -1
  21. package/model/shared/state/state.d.ts +1 -0
  22. package/model/shared/state/state.js +1 -0
  23. package/model/shared/state/state.metadata.json +1 -1
  24. package/package.json +1 -1
  25. package/service/system-text-library.service.d.ts +1 -0
  26. package/service/system-text-library.service.js +2 -1
  27. package/service/system-text-library.service.metadata.json +1 -1
@@ -21897,6 +21897,7 @@ var VariableStateEnum;
21897
21897
  VariableStateEnum[VariableStateEnum["Offline"] = 1] = "Offline";
21898
21898
  VariableStateEnum[VariableStateEnum["Unbind"] = 3] = "Unbind";
21899
21899
  VariableStateEnum[VariableStateEnum["DataNormal"] = 9] = "DataNormal";
21900
+ VariableStateEnum[VariableStateEnum["InvalidMonitor"] = 10] = "InvalidMonitor";
21900
21901
  VariableStateEnum[VariableStateEnum["Abnormal"] = 99] = "Abnormal";
21901
21902
  })(VariableStateEnum || (VariableStateEnum = {}));
21902
21903
 
@@ -22343,6 +22344,7 @@ const Localization_zh_CN = {
22343
22344
  offline: '离线',
22344
22345
  abnormal: '数据异常',
22345
22346
  disable: '禁用',
22347
+ invalidMonitor: '元件绑定的监控点无效',
22346
22348
  permissiontip: '您无权限执行此操作',
22347
22349
  conditionIsNotMetTip: '操作条件不满足或逻辑控制变量异常',
22348
22350
  chartNoData: '无数据',
@@ -22353,6 +22355,9 @@ const Localization_zh_CN = {
22353
22355
  lastSevenDays: '最近7天',
22354
22356
  lastThirtyDays: '最近30天',
22355
22357
  lastOneYear: '最近1年',
22358
+ customTimeRange: '自定义',
22359
+ startTime: '开始时间',
22360
+ endTime: '结束时间',
22356
22361
  grouped: '分组',
22357
22362
  stacked: '叠加',
22358
22363
  passwordVerify: '密码校验',
@@ -32538,6 +32543,7 @@ const DefaultLocalization = {
32538
32543
  offline: 'Offline',
32539
32544
  abnormal: 'Data abnormal',
32540
32545
  disable: 'Disable',
32546
+ invalidMonitor: 'Element binding monitor point is invalid',
32541
32547
  permissiontip: 'You have no permission to operate.',
32542
32548
  conditionIsNotMetTip: 'Operation conditions not met or variable anomalies.',
32543
32549
  chartNoData: 'No Data Available',
@@ -32548,6 +32554,9 @@ const DefaultLocalization = {
32548
32554
  lastSevenDays: 'Last 7 days',
32549
32555
  lastThirtyDays: 'Last 30 days',
32550
32556
  lastOneYear: 'Last 1 year',
32557
+ customTimeRange: 'Custom',
32558
+ startTime: 'Start Time',
32559
+ endTime: 'End Time',
32551
32560
  grouped: 'Grouped',
32552
32561
  stacked: 'Stacked',
32553
32562
  passwordVerify: 'Password verifiers',
@@ -35087,26 +35096,34 @@ class state_control_element_StateControlElement extends conditional_dynamic_disp
35087
35096
  case communication["d" /* VariableStateEnum */].Abnormal:
35088
35097
  currentState = _tmp_model["State"].Abnormal;
35089
35098
  break;
35099
+ case communication["d" /* VariableStateEnum */].InvalidMonitor:
35100
+ currentState = _tmp_model["State"].InvalidMonitor;
35101
+ break;
35090
35102
  }
35091
35103
  return currentState;
35092
35104
  }
35093
35105
  changeState(state) {
35094
35106
  switch (state) {
35107
+ case _tmp_model["State"].InvalidMonitor:
35108
+ this.state = _tmp_model["State"].InvalidMonitor;
35109
+ break;
35095
35110
  case _tmp_model["State"].Unbind:
35096
- this.state = _tmp_model["State"].Unbind;
35111
+ if (this.state !== _tmp_model["State"].InvalidMonitor) {
35112
+ this.state = _tmp_model["State"].Unbind;
35113
+ }
35097
35114
  break;
35098
35115
  case _tmp_model["State"].Offline:
35099
- if (this.state !== _tmp_model["State"].Unbind) {
35116
+ if (this.state !== _tmp_model["State"].Unbind && this.state !== _tmp_model["State"].InvalidMonitor) {
35100
35117
  this.state = _tmp_model["State"].Offline;
35101
35118
  }
35102
35119
  break;
35103
35120
  case _tmp_model["State"].Loading:
35104
- if (this.state !== _tmp_model["State"].Unbind && this.state !== _tmp_model["State"].Offline) {
35121
+ if (this.state !== _tmp_model["State"].Unbind && this.state !== _tmp_model["State"].Offline && this.state !== _tmp_model["State"].InvalidMonitor) {
35105
35122
  this.state = _tmp_model["State"].Loading;
35106
35123
  }
35107
35124
  break;
35108
35125
  case _tmp_model["State"].Abnormal:
35109
- if (this.state !== _tmp_model["State"].Unbind && this.state !== _tmp_model["State"].Offline && this.state !== _tmp_model["State"].Loading) {
35126
+ if (this.state !== _tmp_model["State"].Unbind && this.state !== _tmp_model["State"].Offline && this.state !== _tmp_model["State"].Loading && this.state !== _tmp_model["State"].InvalidMonitor) {
35110
35127
  this.state = _tmp_model["State"].Abnormal;
35111
35128
  }
35112
35129
  break;
@@ -35145,6 +35162,11 @@ class state_control_element_StateControlElement extends conditional_dynamic_disp
35145
35162
  title = this.localization.disable;
35146
35163
  stroke = '#ff4444';
35147
35164
  break;
35165
+ case _tmp_model["State"].InvalidMonitor:
35166
+ url = 'assets/img/loading.svg';
35167
+ title = this.localization.invalidMonitor;
35168
+ stroke = '#226abc';
35169
+ break;
35148
35170
  default:
35149
35171
  url = 'assets/img/loading.svg';
35150
35172
  title = this.localization.loading;
@@ -37157,9 +37179,13 @@ class historical_curve_element_HistoricalCurveElement extends conditional_displa
37157
37179
  operationButtonHeight: 24,
37158
37180
  operationButtonMargin: 4
37159
37181
  };
37182
+ this.customStartTime = null;
37183
+ this.customEndTime = null;
37160
37184
  this.elementStatus = HistoricalCurveElementStatus.Loading;
37161
37185
  this.data = [];
37162
37186
  this.needResize = true;
37187
+ this.dropdownListEl = null;
37188
+ this.dropdownTriggerEl = null;
37163
37189
  this.setNeedResize = () => {
37164
37190
  this.needResize = false;
37165
37191
  setTimeout(() => this.needResize = true, 500);
@@ -37243,21 +37269,43 @@ class historical_curve_element_HistoricalCurveElement extends conditional_displa
37243
37269
  * 更新语种相关的文案(时间段选择器)
37244
37270
  */
37245
37271
  updateLanguageTexts() {
37246
- // 重新生成时间段数据
37247
37272
  const updatedTimePeriods = this.getValidTimePeriods();
37248
37273
  this.timePeriods = updatedTimePeriods;
37249
- // select 在 foreignObject 内部的 HTML 命名空间中,D3 的 rootElement.select('select') 无法跨命名空间查找
37250
- // 改用 jQuery 查找
37251
- const nativeSelectEl = this.$element && this.$element.find('select');
37252
- if (nativeSelectEl && nativeSelectEl.length > 0) {
37253
- const options = nativeSelectEl.find('option');
37254
- options.each(function (i) {
37274
+ // 更新下拉列表各选项文字
37275
+ if (this.dropdownListEl) {
37276
+ const items = this.dropdownListEl.querySelectorAll('.hc-dropdown-item');
37277
+ items.forEach((item, i) => {
37255
37278
  if (i < updatedTimePeriods.length) {
37256
- this.text = updatedTimePeriods[i].name;
37279
+ item.textContent = updatedTimePeriods[i].name;
37257
37280
  }
37258
37281
  });
37282
+ // 文字更新后重新测量宽度,修正首次加载时文字为空导致宽度过小的问题
37283
+ const prevDisplay = this.dropdownListEl.style.display;
37284
+ const prevVisibility = this.dropdownListEl.style.visibility;
37285
+ this.dropdownListEl.style.display = 'block';
37286
+ this.dropdownListEl.style.visibility = 'hidden';
37287
+ this.dropdownListEl.style.width = '';
37288
+ const newWidth = this.dropdownListEl.offsetWidth;
37289
+ this.dropdownListEl.style.display = prevDisplay;
37290
+ this.dropdownListEl.style.visibility = prevVisibility;
37291
+ this.dropdownListEl.style.width = newWidth + 'px';
37292
+ if (this.dropdownTriggerEl) {
37293
+ this.dropdownTriggerEl.style.width = newWidth + 'px';
37294
+ }
37295
+ }
37296
+ // 更新触发按钮文字(显示当前选中项的最新语言文案)
37297
+ if (this.dropdownTriggerEl) {
37298
+ const selected = updatedTimePeriods.find(p => p.key === Number(this.currentTimePeriod));
37299
+ if (selected) {
37300
+ const textNode = Array.from(this.dropdownTriggerEl.childNodes).find(n => n.nodeType === Node.TEXT_NODE);
37301
+ if (textNode) {
37302
+ textNode.textContent = selected.name;
37303
+ }
37304
+ else {
37305
+ this.dropdownTriggerEl.insertBefore(document.createTextNode(selected.name), this.dropdownTriggerEl.firstChild);
37306
+ }
37307
+ }
37259
37308
  }
37260
- // 如果 select 元素不存在,timePeriods 已更新,下次 renderOperationArea 时会使用新的文本
37261
37309
  }
37262
37310
  /**
37263
37311
  * 获取当前语种的 culture 代码
@@ -37293,12 +37341,13 @@ class historical_curve_element_HistoricalCurveElement extends conditional_displa
37293
37341
  timePeriods.push({ key: 3, name: this.getTimePeriodText(service["TIME_PERIOD_KEYS"].LAST_SEVEN_DAYS) });
37294
37342
  timePeriods.push({ key: 4, name: this.getTimePeriodText(service["TIME_PERIOD_KEYS"].LAST_THIRTY_DAYS) });
37295
37343
  timePeriods.push({ key: 5, name: this.getTimePeriodText(service["TIME_PERIOD_KEYS"].LAST_ONE_YEAR) });
37344
+ timePeriods.push({ key: 8, name: this.getTimePeriodText(service["TIME_PERIOD_KEYS"].CUSTOM, this.localization.customTimeRange) });
37296
37345
  return timePeriods;
37297
37346
  }
37298
37347
  /**
37299
- * 获取时间段文案(从系统文本库获取多语种翻译)
37348
+ * 获取时间段文案(从系统文本库获取多语种翻译,fallback 到 localization)
37300
37349
  */
37301
- getTimePeriodText(textKey) {
37350
+ getTimePeriodText(textKey, fallback = '') {
37302
37351
  const currentCulture = this.getCurrentCulture();
37303
37352
  const systemType = service["SYSTEM_TEXT_LIBRARY_TYPES"].COMPONENT_BUILTIN;
37304
37353
  if (this.systemTextLibraryService) {
@@ -37307,13 +37356,20 @@ class historical_curve_element_HistoricalCurveElement extends conditional_displa
37307
37356
  return translation;
37308
37357
  }
37309
37358
  }
37310
- return '';
37359
+ return fallback;
37311
37360
  }
37312
37361
  updateTimeRange(timePeriodType) {
37313
37362
  this.currentTimePeriod = +timePeriodType;
37314
37363
  this.updateQueryTimeRange();
37315
37364
  }
37316
37365
  updateQueryTimeRange() {
37366
+ if (this.currentTimePeriod === 8) {
37367
+ if (this.customStartTime && this.customEndTime) {
37368
+ this.startTime = this.customStartTime.clone();
37369
+ this.endTime = this.customEndTime.clone();
37370
+ }
37371
+ return;
37372
+ }
37317
37373
  this.endTime = moment();
37318
37374
  switch (this.currentTimePeriod) {
37319
37375
  case 1:
@@ -37688,18 +37744,143 @@ class historical_curve_element_HistoricalCurveElement extends conditional_displa
37688
37744
  const operationArea = this.rootElement.append('g').attr('transform', `translate(0,${chartHeight + this.displayOption.operationAreaMarginTop})`)
37689
37745
  .append('foreignObject').attr('width', chartWidth).attr('height', this.displayOption.operationAreaHeight).attr('fill', 'none')
37690
37746
  .append('xhtml:div').style('height', (this.displayOption.operationAreaHeight - 4) + 'px').style('overflow', 'hidden').style('margin-top', '4px');
37691
- const selectElement = operationArea.append('select').style('margin-left', this.displayOption.marginLeft + 'px')
37692
- .style('background-color', backgroundColor)
37693
- .style('font-size', this.displayOption.operationSelectFontSize).on('change', () => {
37694
- const displayTimePeriod = this.rootElement.select('select').property('value');
37695
- this.updateTimeRange(displayTimePeriod);
37696
- this.reRenderElement(this.startTime, this.endTime, this.displayOption.dataLimit, HistoricalCurveTimeRange.BeginOpenEndOpen);
37697
- });
37698
37747
  const rect = this.$element.parent().parent().find('rect');
37699
37748
  const fillColor = rect.attr('fill');
37700
- const options = selectElement.selectAll('option').data(this.timePeriods).enter().append('option');
37701
- options.text(d => d.name).attr('value', d => d.key).property('selected', d => d.key === Number(this.currentTimePeriod))
37702
- .style('background-color', this.model.displaySetting.axisSetting.filterBackgroudColor || fillColor);
37749
+ const dropdownBg = this.model.displaySetting.axisSetting.filterBackgroudColor || fillColor || '#fff';
37750
+ const dropdownWrapper = operationArea.append('div')
37751
+ .style('display', 'inline-block')
37752
+ .style('position', 'relative')
37753
+ .style('margin-left', this.displayOption.marginLeft + 'px')
37754
+ .style('vertical-align', 'middle');
37755
+ const selectedText = this.timePeriods.find(t => t.key === Number(this.currentTimePeriod));
37756
+ const dropdownTrigger = dropdownWrapper.append('div')
37757
+ .attr('class', 'hc-dropdown-trigger')
37758
+ .style('background-color', backgroundColor)
37759
+ .style('font-size', this.displayOption.operationSelectFontSize)
37760
+ .style('cursor', 'pointer')
37761
+ .style('padding', '0 18px 0 4px')
37762
+ .style('border', '1px solid #ccc')
37763
+ .style('border-radius', '2px')
37764
+ .style('position', 'relative')
37765
+ .style('white-space', 'nowrap')
37766
+ .style('line-height', (this.displayOption.operationAreaHeight - 8) + 'px')
37767
+ .style('min-height', (this.displayOption.operationAreaHeight - 8) + 'px')
37768
+ .text(selectedText ? selectedText.name : '');
37769
+ dropdownTrigger.append('span')
37770
+ .style('position', 'absolute')
37771
+ .style('right', '4px')
37772
+ .style('top', '50%')
37773
+ .style('transform', 'translateY(-50%)')
37774
+ .style('font-size', '10px')
37775
+ .style('pointer-events', 'none')
37776
+ .text('▼');
37777
+ const dropdownListEl = document.createElement('div');
37778
+ dropdownListEl.style.cssText = 'display:none;position:fixed;background:' + dropdownBg
37779
+ + ';border:1px solid #ccc;border-radius:2px;z-index:9999;box-shadow:0 2px 6px rgba(0,0,0,0.15);';
37780
+ document.body.appendChild(dropdownListEl);
37781
+ this.dropdownListEl = dropdownListEl;
37782
+ this.dropdownTriggerEl = dropdownTrigger.node();
37783
+ const dropdownList = d3["select"](dropdownListEl);
37784
+ this.timePeriods.forEach(tp => {
37785
+ dropdownList.append('div')
37786
+ .attr('class', 'hc-dropdown-item')
37787
+ .style('padding', '4px 8px')
37788
+ .style('cursor', 'pointer')
37789
+ .style('white-space', 'nowrap')
37790
+ .style('font-size', this.displayOption.operationSelectFontSize)
37791
+ .style('line-height', (this.displayOption.operationAreaHeight - 8) + 'px')
37792
+ .style('min-height', (this.displayOption.operationAreaHeight - 8) + 'px')
37793
+ .style('background', tp.key === Number(this.currentTimePeriod) ? '#1890ff' : 'transparent')
37794
+ .style('color', tp.key === Number(this.currentTimePeriod) ? '#fff' : '#333')
37795
+ .text(tp.name)
37796
+ .on('mouseover', function () {
37797
+ const el = d3["select"](this);
37798
+ if (!el.classed('hc-dropdown-selected')) {
37799
+ el.style('background', '#e6f7ff').style('color', '#333');
37800
+ }
37801
+ })
37802
+ .on('mouseout', function () {
37803
+ const el = d3["select"](this);
37804
+ if (!el.classed('hc-dropdown-selected')) {
37805
+ el.style('background', 'transparent').style('color', '#333');
37806
+ }
37807
+ })
37808
+ .on('click', () => {
37809
+ dropdownListEl.style.display = 'none';
37810
+ // 从 this.timePeriods 实时查找,确保语种切换后显示最新文案
37811
+ const currentPeriod = this.timePeriods.find(p => p.key === tp.key);
37812
+ const currentName = currentPeriod ? currentPeriod.name : tp.name;
37813
+ dropdownTrigger.text(currentName);
37814
+ dropdownTrigger.append('span')
37815
+ .style('position', 'absolute')
37816
+ .style('right', '4px')
37817
+ .style('top', '50%')
37818
+ .style('transform', 'translateY(-50%)')
37819
+ .style('font-size', '10px')
37820
+ .style('pointer-events', 'none')
37821
+ .text('▼');
37822
+ // 更新选中状态
37823
+ dropdownList.selectAll('.hc-dropdown-item')
37824
+ .classed('hc-dropdown-selected', false)
37825
+ .style('background', 'transparent')
37826
+ .style('color', '#333');
37827
+ d3["select"](d3["event"].currentTarget)
37828
+ .classed('hc-dropdown-selected', true)
37829
+ .style('background', '#1890ff')
37830
+ .style('color', '#fff');
37831
+ if (tp.key === 8) {
37832
+ this.showCustomTimeRangeModal();
37833
+ return;
37834
+ }
37835
+ this.updateTimeRange(tp.key);
37836
+ this.reRenderElement(this.startTime, this.endTime, this.displayOption.dataLimit, HistoricalCurveTimeRange.BeginOpenEndOpen);
37837
+ });
37838
+ });
37839
+ // 测量下拉列表最大宽度,让 trigger 和列表宽度一致
37840
+ dropdownListEl.style.display = 'block';
37841
+ dropdownListEl.style.visibility = 'hidden';
37842
+ const listContentWidth = dropdownListEl.offsetWidth;
37843
+ dropdownListEl.style.display = 'none';
37844
+ dropdownListEl.style.visibility = '';
37845
+ dropdownListEl.style.width = listContentWidth + 'px';
37846
+ dropdownTrigger.node().style.width = listContentWidth + 'px';
37847
+ dropdownTrigger.node().style.boxSizing = 'border-box';
37848
+ const hideDropdown = () => { dropdownListEl.style.display = 'none'; };
37849
+ dropdownTrigger.on('click', () => {
37850
+ const isVisible = dropdownListEl.style.display !== 'none';
37851
+ if (isVisible) {
37852
+ hideDropdown();
37853
+ }
37854
+ else {
37855
+ const triggerNode = dropdownTrigger.node();
37856
+ const triggerRect = triggerNode.getBoundingClientRect();
37857
+ // 设置宽度至少和 trigger 一样宽
37858
+ dropdownListEl.style.minWidth = triggerRect.width + 'px';
37859
+ dropdownListEl.style.left = triggerRect.left + 'px';
37860
+ dropdownListEl.style.display = 'block';
37861
+ const listHeight = dropdownListEl.offsetHeight;
37862
+ const spaceBelow = window.innerHeight - triggerRect.bottom;
37863
+ if (spaceBelow < listHeight) {
37864
+ // 向上展开
37865
+ dropdownListEl.style.top = '';
37866
+ dropdownListEl.style.bottom = (window.innerHeight - triggerRect.top) + 'px';
37867
+ }
37868
+ else {
37869
+ // 向下展开
37870
+ dropdownListEl.style.bottom = '';
37871
+ dropdownListEl.style.top = triggerRect.bottom + 'px';
37872
+ }
37873
+ }
37874
+ });
37875
+ // 点击外部收起
37876
+ document.addEventListener('click', (event) => {
37877
+ const triggerNode = dropdownTrigger.node();
37878
+ if (!dropdownListEl.contains(event.target) && !triggerNode.contains(event.target)) {
37879
+ hideDropdown();
37880
+ }
37881
+ });
37882
+ // 滚动时收起
37883
+ document.addEventListener('scroll', hideDropdown, true);
37703
37884
  const buttonWidth = this.displayOption.operationButtonWidth + 'px', buttonHeight = this.displayOption.operationButtonHeight + 'px';
37704
37885
  operationArea.append('button').style('width', buttonWidth).style('height', buttonHeight).style('border', 'none')
37705
37886
  .style('float', 'right').style('background-image', 'url(assets/img/black_last_page.png)')
@@ -37724,6 +37905,131 @@ class historical_curve_element_HistoricalCurveElement extends conditional_displa
37724
37905
  timeFormat(datetime, specifier) {
37725
37906
  return d3["time"].format(specifier)(new Date(datetime));
37726
37907
  }
37908
+ fmtDatetimeLocal(d) {
37909
+ const p2 = (n) => (n < 10 ? '0' : '') + n;
37910
+ return d.getFullYear() + '-' + p2(d.getMonth() + 1) + '-' + p2(d.getDate())
37911
+ + 'T' + p2(d.getHours()) + ':' + p2(d.getMinutes()) + ':' + p2(d.getSeconds());
37912
+ }
37913
+ showCustomTimeRangeModal() {
37914
+ const now = new Date();
37915
+ const defaultStart = this.customStartTime ? this.customStartTime.toDate()
37916
+ : new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0, 0, 0);
37917
+ const defaultEnd = this.customEndTime ? this.customEndTime.toDate()
37918
+ : new Date(now.getFullYear(), now.getMonth(), now.getDate(), 23, 59, 59);
37919
+ if (this.guiContext && this.guiContext.showCustomTimeRangeModal) {
37920
+ this.guiContext.showCustomTimeRangeModal({ startTime: defaultStart, endTime: defaultEnd }).then(result => {
37921
+ if (result) {
37922
+ const momentAny = moment;
37923
+ this.customStartTime = momentAny(result.startTime);
37924
+ this.customEndTime = momentAny(result.endTime);
37925
+ this.updateTimeRange(8);
37926
+ this.reRenderElement(this.startTime, this.endTime, this.displayOption.dataLimit, HistoricalCurveTimeRange.BeginOpenEndOpen);
37927
+ }
37928
+ });
37929
+ return;
37930
+ }
37931
+ this.showCustomTimeRangeModalFallback();
37932
+ }
37933
+ showCustomTimeRangeModalFallback() {
37934
+ const prevTimePeriod = this.currentTimePeriod;
37935
+ const now = new Date();
37936
+ const defaultStart = this.fmtDatetimeLocal(this.customStartTime ? this.customStartTime.toDate()
37937
+ : new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0, 0, 0));
37938
+ const defaultEnd = this.fmtDatetimeLocal(this.customEndTime ? this.customEndTime.toDate()
37939
+ : new Date(now.getFullYear(), now.getMonth(), now.getDate(), 23, 59, 59));
37940
+ const overlay = document.createElement('div');
37941
+ overlay.style.cssText = 'position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.5);z-index:9999;';
37942
+ const modal = document.createElement('div');
37943
+ const modalCss = 'position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);'
37944
+ + 'background:#fff;border-radius:4px;min-width:460px;'
37945
+ + 'box-shadow:0 4px 12px rgba(0,0,0,0.15);font-family:inherit;font-size:14px;';
37946
+ modal.style.cssText = modalCss;
37947
+ const header = document.createElement('div');
37948
+ header.style.cssText = 'display:flex;align-items:center;justify-content:space-between;padding:12px 16px;border-bottom:1px solid #e8e8e8;';
37949
+ const title = document.createElement('span');
37950
+ title.style.cssText = 'font-size:16px;font-weight:500;color:#333;';
37951
+ title.textContent = this.localization.customTimeRange || '自定义';
37952
+ const closeBtn = document.createElement('span');
37953
+ closeBtn.style.cssText = 'cursor:pointer;font-size:18px;color:#999;line-height:1;';
37954
+ closeBtn.textContent = '×';
37955
+ header.appendChild(title);
37956
+ header.appendChild(closeBtn);
37957
+ const body = document.createElement('div');
37958
+ body.style.cssText = 'padding:20px 16px;display:flex;align-items:center;flex-wrap:wrap;gap:8px;';
37959
+ const label = document.createElement('span');
37960
+ label.style.cssText = 'color:#333;white-space:nowrap;';
37961
+ label.textContent = '时间范围:';
37962
+ const inputStyle = 'border:1px solid #d9d9d9;border-radius:4px;padding:4px 8px;font-size:14px;height:32px;outline:none;color:#333;';
37963
+ const startInput = document.createElement('input');
37964
+ startInput.type = 'datetime-local';
37965
+ startInput.setAttribute('step', '1');
37966
+ startInput.value = defaultStart;
37967
+ startInput.style.cssText = inputStyle;
37968
+ const separator = document.createElement('span');
37969
+ separator.textContent = ' - ';
37970
+ separator.style.cssText = 'color:#333;';
37971
+ const endInput = document.createElement('input');
37972
+ endInput.type = 'datetime-local';
37973
+ endInput.setAttribute('step', '1');
37974
+ endInput.value = defaultEnd;
37975
+ endInput.style.cssText = inputStyle;
37976
+ body.appendChild(label);
37977
+ body.appendChild(startInput);
37978
+ body.appendChild(separator);
37979
+ body.appendChild(endInput);
37980
+ const footer = document.createElement('div');
37981
+ footer.style.cssText = 'display:flex;justify-content:flex-end;gap:8px;padding:12px 16px;border-top:1px solid #e8e8e8;';
37982
+ const cancelBtn = document.createElement('button');
37983
+ cancelBtn.textContent = this.localization.cancel || '取消';
37984
+ cancelBtn.style.cssText = 'padding:5px 16px;border:1px solid #d9d9d9;border-radius:4px;background:#fff;cursor:pointer;font-size:14px;color:#333;';
37985
+ const saveBtn = document.createElement('button');
37986
+ saveBtn.textContent = '保存';
37987
+ saveBtn.style.cssText = 'padding:5px 16px;border:none;border-radius:4px;background:#1890ff;color:#fff;cursor:pointer;font-size:14px;';
37988
+ footer.appendChild(cancelBtn);
37989
+ footer.appendChild(saveBtn);
37990
+ modal.appendChild(header);
37991
+ modal.appendChild(body);
37992
+ modal.appendChild(footer);
37993
+ overlay.appendChild(modal);
37994
+ document.body.appendChild(overlay);
37995
+ const close = (revert) => {
37996
+ document.body.removeChild(overlay);
37997
+ if (revert) {
37998
+ const selectEl = this.$element && this.$element.find('select');
37999
+ if (selectEl && selectEl.length) {
38000
+ selectEl.val(prevTimePeriod.toString());
38001
+ }
38002
+ }
38003
+ };
38004
+ closeBtn.addEventListener('click', () => close(true));
38005
+ cancelBtn.addEventListener('click', () => close(true));
38006
+ saveBtn.addEventListener('click', () => {
38007
+ const startVal = startInput.value;
38008
+ const endVal = endInput.value;
38009
+ if (!startVal) {
38010
+ startInput.style.borderColor = 'red';
38011
+ return;
38012
+ }
38013
+ const startDate = new Date(startVal);
38014
+ const endDate = endVal
38015
+ ? new Date(endVal)
38016
+ : new Date(startDate.getFullYear(), startDate.getMonth(), startDate.getDate(), 23, 59, 59);
38017
+ if (isNaN(startDate.getTime())) {
38018
+ startInput.style.borderColor = 'red';
38019
+ return;
38020
+ }
38021
+ if (endDate.getTime() <= startDate.getTime()) {
38022
+ endInput.style.borderColor = 'red';
38023
+ return;
38024
+ }
38025
+ const momentAny = moment;
38026
+ this.customStartTime = momentAny(startDate);
38027
+ this.customEndTime = momentAny(endDate);
38028
+ close(false);
38029
+ this.updateTimeRange(8);
38030
+ this.reRenderElement(this.startTime, this.endTime, this.displayOption.dataLimit, HistoricalCurveTimeRange.BeginOpenEndOpen);
38031
+ });
38032
+ }
37727
38033
  loadFirstPage() {
37728
38034
  this.updateQueryTimeRange();
37729
38035
  this.reRenderElement(this.startTime, this.endTime, this.displayOption.dataLimit, HistoricalCurveTimeRange.BeginOpenEndOpen);
@@ -40156,11 +40462,18 @@ class switch_indicator_light_element_SwitchIndicatorLightElement extends conditi
40156
40462
  }
40157
40463
  }
40158
40464
  initIndictorLightOperator() {
40465
+ var _a, _b, _c, _d;
40159
40466
  const settings = this.model.indicatorLightSettings;
40160
40467
  if (settings.settings.variableName) {
40161
40468
  const variable = new variable_definition["a" /* VariableDefinition */](settings.settings.variableName, settings.settings.variableGroupName, settings.settings.dataSourceCode, settings.settings.variableVersion);
40162
- this.addElementState(new communication["c" /* VariableState */](variable_util["a" /* VariableUtil */].getConvertedVariableName(this.variableStore, variable), undefined));
40469
+ const convertedName = variable_util["a" /* VariableUtil */].getConvertedVariableName(this.variableStore, variable);
40470
+ this.addElementState(new communication["c" /* VariableState */](convertedName, undefined));
40163
40471
  this.initState();
40472
+ const validNames = (_d = (_c = (_b = (_a = this.guiContext) === null || _a === void 0 ? void 0 : _a.configStore) === null || _b === void 0 ? void 0 : _b.variableStore) === null || _c === void 0 ? void 0 : _c.getAllVariableNames) === null || _d === void 0 ? void 0 : _d.call(_c);
40473
+ if (validNames && !validNames.includes(convertedName)) {
40474
+ this.updateElementStates([new communication["c" /* VariableState */](convertedName, communication["d" /* VariableStateEnum */].InvalidMonitor)]);
40475
+ return;
40476
+ }
40164
40477
  }
40165
40478
  switch (settings.type) {
40166
40479
  case _tmp_model["IndicatorLightType"].Bit:
@@ -43675,6 +43988,7 @@ class gui_view_GuiView {
43675
43988
  this.logger.debug('[GUI] View loaded.');
43676
43989
  }
43677
43990
  loadElementState() {
43991
+ var _a, _b;
43678
43992
  if (!this.mainElement) {
43679
43993
  return;
43680
43994
  }
@@ -43719,6 +44033,20 @@ class gui_view_GuiView {
43719
44033
  });
43720
44034
  normalVariablesForState.splice(normalVariablesForState.indexOf('设备状态'), 1);
43721
44035
  }
44036
+ const validVariableNames = (_b = (_a = this.context.configStore.variableStore).getAllVariableNames) === null || _b === void 0 ? void 0 : _b.call(_a);
44037
+ if (validVariableNames) {
44038
+ const invalidVariables = normalVariablesForState.filter(name => !validVariableNames.includes(name));
44039
+ if (invalidVariables.length > 0) {
44040
+ const unbindStates = invalidVariables.map(name => new communication["c" /* VariableState */](name, communication["d" /* VariableStateEnum */].InvalidMonitor));
44041
+ this.mainElement.reportVariableStates(unbindStates);
44042
+ invalidVariables.forEach(name => {
44043
+ const idx = normalVariablesForState.indexOf(name);
44044
+ if (idx !== -1) {
44045
+ normalVariablesForState.splice(idx, 1);
44046
+ }
44047
+ });
44048
+ }
44049
+ }
43722
44050
  if (normalVariablesForState.length === 0) {
43723
44051
  return;
43724
44052
  }
@@ -67137,6 +67465,7 @@ var State;
67137
67465
  State[State["Unbind"] = 2] = "Unbind";
67138
67466
  State[State["Abnormal"] = 3] = "Abnormal";
67139
67467
  State[State["Loading"] = 4] = "Loading";
67468
+ State[State["InvalidMonitor"] = 5] = "InvalidMonitor";
67140
67469
  State[State["Disable"] = 9] = "Disable";
67141
67470
  })(State || (State = {}));
67142
67471
 
@@ -74412,7 +74741,8 @@ const TIME_PERIOD_KEYS = {
74412
74741
  LAST_TWENTY_FOUR_HOURS: 'HistoricalCurve.TimeFilter.Last24Hours',
74413
74742
  LAST_SEVEN_DAYS: 'HistoricalCurve.TimeFilter.Last7Days',
74414
74743
  LAST_THIRTY_DAYS: 'HistoricalCurve.TimeFilter.Last30Days',
74415
- LAST_ONE_YEAR: 'HistoricalCurve.TimeFilter.Last1Year'
74744
+ LAST_ONE_YEAR: 'HistoricalCurve.TimeFilter.Last1Year',
74745
+ CUSTOM: 'HistoricalCurve.TimeFilter.Custom'
74416
74746
  };
74417
74747
 
74418
74748