@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.
- package/bundles/@flexem/fc-gui.umd.js +358 -28
- package/bundles/@flexem/fc-gui.umd.js.map +1 -1
- package/bundles/@flexem/fc-gui.umd.min.js +4 -4
- package/bundles/@flexem/fc-gui.umd.min.js.map +1 -1
- package/communication/variable/variable-state-enum.d.ts +1 -0
- package/communication/variable/variable-state-enum.js +1 -0
- package/communication/variable/variable-state-enum.metadata.json +1 -1
- package/config/variable/variable-store.d.ts +1 -0
- package/elements/base/state-control-element.js +17 -4
- package/elements/historical-curve/historical-curve.element.d.ts +8 -1
- package/elements/historical-curve/historical-curve.element.js +306 -22
- package/elements/historical-curve/historical-curve.element.metadata.json +1 -1
- package/elements/switch-indicator-light/switch-indicator-light-element.js +9 -2
- package/gui/gui-context.d.ts +7 -0
- package/gui/gui-view.js +16 -1
- package/localization/localization.service.d.ts +4 -0
- package/localization/localization.service.js +4 -0
- package/localization/localization.service.metadata.json +1 -1
- package/localization/localization.service.zh_CN.js +4 -0
- package/localization/localization.service.zh_CN.metadata.json +1 -1
- package/model/shared/state/state.d.ts +1 -0
- package/model/shared/state/state.js +1 -0
- package/model/shared/state/state.metadata.json +1 -1
- package/package.json +1 -1
- package/service/system-text-library.service.d.ts +1 -0
- package/service/system-text-library.service.js +2 -1
- package/service/system-text-library.service.metadata.json +1 -1
|
@@ -4,5 +4,6 @@ export var VariableStateEnum;
|
|
|
4
4
|
VariableStateEnum[VariableStateEnum["Offline"] = 1] = "Offline";
|
|
5
5
|
VariableStateEnum[VariableStateEnum["Unbind"] = 3] = "Unbind";
|
|
6
6
|
VariableStateEnum[VariableStateEnum["DataNormal"] = 9] = "DataNormal";
|
|
7
|
+
VariableStateEnum[VariableStateEnum["InvalidMonitor"] = 10] = "InvalidMonitor";
|
|
7
8
|
VariableStateEnum[VariableStateEnum["Abnormal"] = 99] = "Abnormal";
|
|
8
9
|
})(VariableStateEnum || (VariableStateEnum = {}));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
[{"__symbolic":"module","version":4,"metadata":{"VariableStateEnum":{"Normal":0,"Offline":1,"Unbind":3,"DataNormal":9,"Abnormal":99}}}]
|
|
1
|
+
[{"__symbolic":"module","version":4,"metadata":{"VariableStateEnum":{"Normal":0,"Offline":1,"Unbind":3,"DataNormal":9,"InvalidMonitor":10,"Abnormal":99}}}]
|
|
@@ -65,26 +65,34 @@ export class StateControlElement extends ConditionalDynamicDisplayElement {
|
|
|
65
65
|
case VariableStateEnum.Abnormal:
|
|
66
66
|
currentState = State.Abnormal;
|
|
67
67
|
break;
|
|
68
|
+
case VariableStateEnum.InvalidMonitor:
|
|
69
|
+
currentState = State.InvalidMonitor;
|
|
70
|
+
break;
|
|
68
71
|
}
|
|
69
72
|
return currentState;
|
|
70
73
|
}
|
|
71
74
|
changeState(state) {
|
|
72
75
|
switch (state) {
|
|
76
|
+
case State.InvalidMonitor:
|
|
77
|
+
this.state = State.InvalidMonitor;
|
|
78
|
+
break;
|
|
73
79
|
case State.Unbind:
|
|
74
|
-
this.state
|
|
80
|
+
if (this.state !== State.InvalidMonitor) {
|
|
81
|
+
this.state = State.Unbind;
|
|
82
|
+
}
|
|
75
83
|
break;
|
|
76
84
|
case State.Offline:
|
|
77
|
-
if (this.state !== State.Unbind) {
|
|
85
|
+
if (this.state !== State.Unbind && this.state !== State.InvalidMonitor) {
|
|
78
86
|
this.state = State.Offline;
|
|
79
87
|
}
|
|
80
88
|
break;
|
|
81
89
|
case State.Loading:
|
|
82
|
-
if (this.state !== State.Unbind && this.state !== State.Offline) {
|
|
90
|
+
if (this.state !== State.Unbind && this.state !== State.Offline && this.state !== State.InvalidMonitor) {
|
|
83
91
|
this.state = State.Loading;
|
|
84
92
|
}
|
|
85
93
|
break;
|
|
86
94
|
case State.Abnormal:
|
|
87
|
-
if (this.state !== State.Unbind && this.state !== State.Offline && this.state !== State.Loading) {
|
|
95
|
+
if (this.state !== State.Unbind && this.state !== State.Offline && this.state !== State.Loading && this.state !== State.InvalidMonitor) {
|
|
88
96
|
this.state = State.Abnormal;
|
|
89
97
|
}
|
|
90
98
|
break;
|
|
@@ -123,6 +131,11 @@ export class StateControlElement extends ConditionalDynamicDisplayElement {
|
|
|
123
131
|
title = this.localization.disable;
|
|
124
132
|
stroke = '#ff4444';
|
|
125
133
|
break;
|
|
134
|
+
case State.InvalidMonitor:
|
|
135
|
+
url = 'assets/img/loading.svg';
|
|
136
|
+
title = this.localization.invalidMonitor;
|
|
137
|
+
stroke = '#226abc';
|
|
138
|
+
break;
|
|
126
139
|
default:
|
|
127
140
|
url = 'assets/img/loading.svg';
|
|
128
141
|
title = this.localization.loading;
|
|
@@ -33,6 +33,8 @@ export declare class HistoricalCurveElement extends ConditionalDisplayElement {
|
|
|
33
33
|
*/
|
|
34
34
|
private currentEndTime;
|
|
35
35
|
private currentTimePeriod;
|
|
36
|
+
private customStartTime;
|
|
37
|
+
private customEndTime;
|
|
36
38
|
private refreshIntervalId;
|
|
37
39
|
private elementStatus;
|
|
38
40
|
private chartElement;
|
|
@@ -42,6 +44,8 @@ export declare class HistoricalCurveElement extends ConditionalDisplayElement {
|
|
|
42
44
|
private resizeEventListener;
|
|
43
45
|
private isAndroid;
|
|
44
46
|
private needResize;
|
|
47
|
+
private dropdownListEl;
|
|
48
|
+
private dropdownTriggerEl;
|
|
45
49
|
constructor(element: HTMLElement, injector: Injector, permissionChecker: PermissionChecker, variableCommunicator: VariableCommunicator, variableStore: VariableStore, historyDataStore: HistoryDataStore, signalRAppId: string, systemTextLibraryService?: SystemTextLibraryService, languageService?: LanguageService, guiContext?: GuiContext);
|
|
46
50
|
dispose(): void;
|
|
47
51
|
private initKeyboardListener;
|
|
@@ -60,7 +64,7 @@ export declare class HistoricalCurveElement extends ConditionalDisplayElement {
|
|
|
60
64
|
private getCurrentCulture;
|
|
61
65
|
private getValidTimePeriods;
|
|
62
66
|
/**
|
|
63
|
-
*
|
|
67
|
+
* 获取时间段文案(从系统文本库获取多语种翻译,fallback 到 localization)
|
|
64
68
|
*/
|
|
65
69
|
private getTimePeriodText;
|
|
66
70
|
private updateTimeRange;
|
|
@@ -75,6 +79,9 @@ export declare class HistoricalCurveElement extends ConditionalDisplayElement {
|
|
|
75
79
|
private renderCommonProperty;
|
|
76
80
|
private renderOperationArea;
|
|
77
81
|
private timeFormat;
|
|
82
|
+
private fmtDatetimeLocal;
|
|
83
|
+
private showCustomTimeRangeModal;
|
|
84
|
+
private showCustomTimeRangeModalFallback;
|
|
78
85
|
private loadFirstPage;
|
|
79
86
|
private loadNextPage;
|
|
80
87
|
private loadPreviousPage;
|
|
@@ -32,9 +32,13 @@ export class HistoricalCurveElement extends ConditionalDisplayElement {
|
|
|
32
32
|
operationButtonHeight: 24,
|
|
33
33
|
operationButtonMargin: 4
|
|
34
34
|
};
|
|
35
|
+
this.customStartTime = null;
|
|
36
|
+
this.customEndTime = null;
|
|
35
37
|
this.elementStatus = HistoricalCurveElementStatus.Loading;
|
|
36
38
|
this.data = [];
|
|
37
39
|
this.needResize = true;
|
|
40
|
+
this.dropdownListEl = null;
|
|
41
|
+
this.dropdownTriggerEl = null;
|
|
38
42
|
this.setNeedResize = () => {
|
|
39
43
|
this.needResize = false;
|
|
40
44
|
setTimeout(() => this.needResize = true, 500);
|
|
@@ -118,21 +122,43 @@ export class HistoricalCurveElement extends ConditionalDisplayElement {
|
|
|
118
122
|
* 更新语种相关的文案(时间段选择器)
|
|
119
123
|
*/
|
|
120
124
|
updateLanguageTexts() {
|
|
121
|
-
// 重新生成时间段数据
|
|
122
125
|
const updatedTimePeriods = this.getValidTimePeriods();
|
|
123
126
|
this.timePeriods = updatedTimePeriods;
|
|
124
|
-
//
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
const options = nativeSelectEl.find('option');
|
|
129
|
-
options.each(function (i) {
|
|
127
|
+
// 更新下拉列表各选项文字
|
|
128
|
+
if (this.dropdownListEl) {
|
|
129
|
+
const items = this.dropdownListEl.querySelectorAll('.hc-dropdown-item');
|
|
130
|
+
items.forEach((item, i) => {
|
|
130
131
|
if (i < updatedTimePeriods.length) {
|
|
131
|
-
|
|
132
|
+
item.textContent = updatedTimePeriods[i].name;
|
|
132
133
|
}
|
|
133
134
|
});
|
|
135
|
+
// 文字更新后重新测量宽度,修正首次加载时文字为空导致宽度过小的问题
|
|
136
|
+
const prevDisplay = this.dropdownListEl.style.display;
|
|
137
|
+
const prevVisibility = this.dropdownListEl.style.visibility;
|
|
138
|
+
this.dropdownListEl.style.display = 'block';
|
|
139
|
+
this.dropdownListEl.style.visibility = 'hidden';
|
|
140
|
+
this.dropdownListEl.style.width = '';
|
|
141
|
+
const newWidth = this.dropdownListEl.offsetWidth;
|
|
142
|
+
this.dropdownListEl.style.display = prevDisplay;
|
|
143
|
+
this.dropdownListEl.style.visibility = prevVisibility;
|
|
144
|
+
this.dropdownListEl.style.width = newWidth + 'px';
|
|
145
|
+
if (this.dropdownTriggerEl) {
|
|
146
|
+
this.dropdownTriggerEl.style.width = newWidth + 'px';
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
// 更新触发按钮文字(显示当前选中项的最新语言文案)
|
|
150
|
+
if (this.dropdownTriggerEl) {
|
|
151
|
+
const selected = updatedTimePeriods.find(p => p.key === Number(this.currentTimePeriod));
|
|
152
|
+
if (selected) {
|
|
153
|
+
const textNode = Array.from(this.dropdownTriggerEl.childNodes).find(n => n.nodeType === Node.TEXT_NODE);
|
|
154
|
+
if (textNode) {
|
|
155
|
+
textNode.textContent = selected.name;
|
|
156
|
+
}
|
|
157
|
+
else {
|
|
158
|
+
this.dropdownTriggerEl.insertBefore(document.createTextNode(selected.name), this.dropdownTriggerEl.firstChild);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
134
161
|
}
|
|
135
|
-
// 如果 select 元素不存在,timePeriods 已更新,下次 renderOperationArea 时会使用新的文本
|
|
136
162
|
}
|
|
137
163
|
/**
|
|
138
164
|
* 获取当前语种的 culture 代码
|
|
@@ -168,12 +194,13 @@ export class HistoricalCurveElement extends ConditionalDisplayElement {
|
|
|
168
194
|
timePeriods.push({ key: 3, name: this.getTimePeriodText(TIME_PERIOD_KEYS.LAST_SEVEN_DAYS) });
|
|
169
195
|
timePeriods.push({ key: 4, name: this.getTimePeriodText(TIME_PERIOD_KEYS.LAST_THIRTY_DAYS) });
|
|
170
196
|
timePeriods.push({ key: 5, name: this.getTimePeriodText(TIME_PERIOD_KEYS.LAST_ONE_YEAR) });
|
|
197
|
+
timePeriods.push({ key: 8, name: this.getTimePeriodText(TIME_PERIOD_KEYS.CUSTOM, this.localization.customTimeRange) });
|
|
171
198
|
return timePeriods;
|
|
172
199
|
}
|
|
173
200
|
/**
|
|
174
|
-
*
|
|
201
|
+
* 获取时间段文案(从系统文本库获取多语种翻译,fallback 到 localization)
|
|
175
202
|
*/
|
|
176
|
-
getTimePeriodText(textKey) {
|
|
203
|
+
getTimePeriodText(textKey, fallback = '') {
|
|
177
204
|
const currentCulture = this.getCurrentCulture();
|
|
178
205
|
const systemType = SYSTEM_TEXT_LIBRARY_TYPES.COMPONENT_BUILTIN;
|
|
179
206
|
if (this.systemTextLibraryService) {
|
|
@@ -182,13 +209,20 @@ export class HistoricalCurveElement extends ConditionalDisplayElement {
|
|
|
182
209
|
return translation;
|
|
183
210
|
}
|
|
184
211
|
}
|
|
185
|
-
return
|
|
212
|
+
return fallback;
|
|
186
213
|
}
|
|
187
214
|
updateTimeRange(timePeriodType) {
|
|
188
215
|
this.currentTimePeriod = +timePeriodType;
|
|
189
216
|
this.updateQueryTimeRange();
|
|
190
217
|
}
|
|
191
218
|
updateQueryTimeRange() {
|
|
219
|
+
if (this.currentTimePeriod === 8) {
|
|
220
|
+
if (this.customStartTime && this.customEndTime) {
|
|
221
|
+
this.startTime = this.customStartTime.clone();
|
|
222
|
+
this.endTime = this.customEndTime.clone();
|
|
223
|
+
}
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
192
226
|
this.endTime = moment();
|
|
193
227
|
switch (this.currentTimePeriod) {
|
|
194
228
|
case 1:
|
|
@@ -563,18 +597,143 @@ export class HistoricalCurveElement extends ConditionalDisplayElement {
|
|
|
563
597
|
const operationArea = this.rootElement.append('g').attr('transform', `translate(0,${chartHeight + this.displayOption.operationAreaMarginTop})`)
|
|
564
598
|
.append('foreignObject').attr('width', chartWidth).attr('height', this.displayOption.operationAreaHeight).attr('fill', 'none')
|
|
565
599
|
.append('xhtml:div').style('height', (this.displayOption.operationAreaHeight - 4) + 'px').style('overflow', 'hidden').style('margin-top', '4px');
|
|
566
|
-
const selectElement = operationArea.append('select').style('margin-left', this.displayOption.marginLeft + 'px')
|
|
567
|
-
.style('background-color', backgroundColor)
|
|
568
|
-
.style('font-size', this.displayOption.operationSelectFontSize).on('change', () => {
|
|
569
|
-
const displayTimePeriod = this.rootElement.select('select').property('value');
|
|
570
|
-
this.updateTimeRange(displayTimePeriod);
|
|
571
|
-
this.reRenderElement(this.startTime, this.endTime, this.displayOption.dataLimit, HistoricalCurveTimeRange.BeginOpenEndOpen);
|
|
572
|
-
});
|
|
573
600
|
const rect = this.$element.parent().parent().find('rect');
|
|
574
601
|
const fillColor = rect.attr('fill');
|
|
575
|
-
const
|
|
576
|
-
|
|
577
|
-
.style('
|
|
602
|
+
const dropdownBg = this.model.displaySetting.axisSetting.filterBackgroudColor || fillColor || '#fff';
|
|
603
|
+
const dropdownWrapper = operationArea.append('div')
|
|
604
|
+
.style('display', 'inline-block')
|
|
605
|
+
.style('position', 'relative')
|
|
606
|
+
.style('margin-left', this.displayOption.marginLeft + 'px')
|
|
607
|
+
.style('vertical-align', 'middle');
|
|
608
|
+
const selectedText = this.timePeriods.find(t => t.key === Number(this.currentTimePeriod));
|
|
609
|
+
const dropdownTrigger = dropdownWrapper.append('div')
|
|
610
|
+
.attr('class', 'hc-dropdown-trigger')
|
|
611
|
+
.style('background-color', backgroundColor)
|
|
612
|
+
.style('font-size', this.displayOption.operationSelectFontSize)
|
|
613
|
+
.style('cursor', 'pointer')
|
|
614
|
+
.style('padding', '0 18px 0 4px')
|
|
615
|
+
.style('border', '1px solid #ccc')
|
|
616
|
+
.style('border-radius', '2px')
|
|
617
|
+
.style('position', 'relative')
|
|
618
|
+
.style('white-space', 'nowrap')
|
|
619
|
+
.style('line-height', (this.displayOption.operationAreaHeight - 8) + 'px')
|
|
620
|
+
.style('min-height', (this.displayOption.operationAreaHeight - 8) + 'px')
|
|
621
|
+
.text(selectedText ? selectedText.name : '');
|
|
622
|
+
dropdownTrigger.append('span')
|
|
623
|
+
.style('position', 'absolute')
|
|
624
|
+
.style('right', '4px')
|
|
625
|
+
.style('top', '50%')
|
|
626
|
+
.style('transform', 'translateY(-50%)')
|
|
627
|
+
.style('font-size', '10px')
|
|
628
|
+
.style('pointer-events', 'none')
|
|
629
|
+
.text('▼');
|
|
630
|
+
const dropdownListEl = document.createElement('div');
|
|
631
|
+
dropdownListEl.style.cssText = 'display:none;position:fixed;background:' + dropdownBg
|
|
632
|
+
+ ';border:1px solid #ccc;border-radius:2px;z-index:9999;box-shadow:0 2px 6px rgba(0,0,0,0.15);';
|
|
633
|
+
document.body.appendChild(dropdownListEl);
|
|
634
|
+
this.dropdownListEl = dropdownListEl;
|
|
635
|
+
this.dropdownTriggerEl = dropdownTrigger.node();
|
|
636
|
+
const dropdownList = d3.select(dropdownListEl);
|
|
637
|
+
this.timePeriods.forEach(tp => {
|
|
638
|
+
dropdownList.append('div')
|
|
639
|
+
.attr('class', 'hc-dropdown-item')
|
|
640
|
+
.style('padding', '4px 8px')
|
|
641
|
+
.style('cursor', 'pointer')
|
|
642
|
+
.style('white-space', 'nowrap')
|
|
643
|
+
.style('font-size', this.displayOption.operationSelectFontSize)
|
|
644
|
+
.style('line-height', (this.displayOption.operationAreaHeight - 8) + 'px')
|
|
645
|
+
.style('min-height', (this.displayOption.operationAreaHeight - 8) + 'px')
|
|
646
|
+
.style('background', tp.key === Number(this.currentTimePeriod) ? '#1890ff' : 'transparent')
|
|
647
|
+
.style('color', tp.key === Number(this.currentTimePeriod) ? '#fff' : '#333')
|
|
648
|
+
.text(tp.name)
|
|
649
|
+
.on('mouseover', function () {
|
|
650
|
+
const el = d3.select(this);
|
|
651
|
+
if (!el.classed('hc-dropdown-selected')) {
|
|
652
|
+
el.style('background', '#e6f7ff').style('color', '#333');
|
|
653
|
+
}
|
|
654
|
+
})
|
|
655
|
+
.on('mouseout', function () {
|
|
656
|
+
const el = d3.select(this);
|
|
657
|
+
if (!el.classed('hc-dropdown-selected')) {
|
|
658
|
+
el.style('background', 'transparent').style('color', '#333');
|
|
659
|
+
}
|
|
660
|
+
})
|
|
661
|
+
.on('click', () => {
|
|
662
|
+
dropdownListEl.style.display = 'none';
|
|
663
|
+
// 从 this.timePeriods 实时查找,确保语种切换后显示最新文案
|
|
664
|
+
const currentPeriod = this.timePeriods.find(p => p.key === tp.key);
|
|
665
|
+
const currentName = currentPeriod ? currentPeriod.name : tp.name;
|
|
666
|
+
dropdownTrigger.text(currentName);
|
|
667
|
+
dropdownTrigger.append('span')
|
|
668
|
+
.style('position', 'absolute')
|
|
669
|
+
.style('right', '4px')
|
|
670
|
+
.style('top', '50%')
|
|
671
|
+
.style('transform', 'translateY(-50%)')
|
|
672
|
+
.style('font-size', '10px')
|
|
673
|
+
.style('pointer-events', 'none')
|
|
674
|
+
.text('▼');
|
|
675
|
+
// 更新选中状态
|
|
676
|
+
dropdownList.selectAll('.hc-dropdown-item')
|
|
677
|
+
.classed('hc-dropdown-selected', false)
|
|
678
|
+
.style('background', 'transparent')
|
|
679
|
+
.style('color', '#333');
|
|
680
|
+
d3.select(d3.event.currentTarget)
|
|
681
|
+
.classed('hc-dropdown-selected', true)
|
|
682
|
+
.style('background', '#1890ff')
|
|
683
|
+
.style('color', '#fff');
|
|
684
|
+
if (tp.key === 8) {
|
|
685
|
+
this.showCustomTimeRangeModal();
|
|
686
|
+
return;
|
|
687
|
+
}
|
|
688
|
+
this.updateTimeRange(tp.key);
|
|
689
|
+
this.reRenderElement(this.startTime, this.endTime, this.displayOption.dataLimit, HistoricalCurveTimeRange.BeginOpenEndOpen);
|
|
690
|
+
});
|
|
691
|
+
});
|
|
692
|
+
// 测量下拉列表最大宽度,让 trigger 和列表宽度一致
|
|
693
|
+
dropdownListEl.style.display = 'block';
|
|
694
|
+
dropdownListEl.style.visibility = 'hidden';
|
|
695
|
+
const listContentWidth = dropdownListEl.offsetWidth;
|
|
696
|
+
dropdownListEl.style.display = 'none';
|
|
697
|
+
dropdownListEl.style.visibility = '';
|
|
698
|
+
dropdownListEl.style.width = listContentWidth + 'px';
|
|
699
|
+
dropdownTrigger.node().style.width = listContentWidth + 'px';
|
|
700
|
+
dropdownTrigger.node().style.boxSizing = 'border-box';
|
|
701
|
+
const hideDropdown = () => { dropdownListEl.style.display = 'none'; };
|
|
702
|
+
dropdownTrigger.on('click', () => {
|
|
703
|
+
const isVisible = dropdownListEl.style.display !== 'none';
|
|
704
|
+
if (isVisible) {
|
|
705
|
+
hideDropdown();
|
|
706
|
+
}
|
|
707
|
+
else {
|
|
708
|
+
const triggerNode = dropdownTrigger.node();
|
|
709
|
+
const triggerRect = triggerNode.getBoundingClientRect();
|
|
710
|
+
// 设置宽度至少和 trigger 一样宽
|
|
711
|
+
dropdownListEl.style.minWidth = triggerRect.width + 'px';
|
|
712
|
+
dropdownListEl.style.left = triggerRect.left + 'px';
|
|
713
|
+
dropdownListEl.style.display = 'block';
|
|
714
|
+
const listHeight = dropdownListEl.offsetHeight;
|
|
715
|
+
const spaceBelow = window.innerHeight - triggerRect.bottom;
|
|
716
|
+
if (spaceBelow < listHeight) {
|
|
717
|
+
// 向上展开
|
|
718
|
+
dropdownListEl.style.top = '';
|
|
719
|
+
dropdownListEl.style.bottom = (window.innerHeight - triggerRect.top) + 'px';
|
|
720
|
+
}
|
|
721
|
+
else {
|
|
722
|
+
// 向下展开
|
|
723
|
+
dropdownListEl.style.bottom = '';
|
|
724
|
+
dropdownListEl.style.top = triggerRect.bottom + 'px';
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
});
|
|
728
|
+
// 点击外部收起
|
|
729
|
+
document.addEventListener('click', (event) => {
|
|
730
|
+
const triggerNode = dropdownTrigger.node();
|
|
731
|
+
if (!dropdownListEl.contains(event.target) && !triggerNode.contains(event.target)) {
|
|
732
|
+
hideDropdown();
|
|
733
|
+
}
|
|
734
|
+
});
|
|
735
|
+
// 滚动时收起
|
|
736
|
+
document.addEventListener('scroll', hideDropdown, true);
|
|
578
737
|
const buttonWidth = this.displayOption.operationButtonWidth + 'px', buttonHeight = this.displayOption.operationButtonHeight + 'px';
|
|
579
738
|
operationArea.append('button').style('width', buttonWidth).style('height', buttonHeight).style('border', 'none')
|
|
580
739
|
.style('float', 'right').style('background-image', 'url(assets/img/black_last_page.png)')
|
|
@@ -599,6 +758,131 @@ export class HistoricalCurveElement extends ConditionalDisplayElement {
|
|
|
599
758
|
timeFormat(datetime, specifier) {
|
|
600
759
|
return d3.time.format(specifier)(new Date(datetime));
|
|
601
760
|
}
|
|
761
|
+
fmtDatetimeLocal(d) {
|
|
762
|
+
const p2 = (n) => (n < 10 ? '0' : '') + n;
|
|
763
|
+
return d.getFullYear() + '-' + p2(d.getMonth() + 1) + '-' + p2(d.getDate())
|
|
764
|
+
+ 'T' + p2(d.getHours()) + ':' + p2(d.getMinutes()) + ':' + p2(d.getSeconds());
|
|
765
|
+
}
|
|
766
|
+
showCustomTimeRangeModal() {
|
|
767
|
+
const now = new Date();
|
|
768
|
+
const defaultStart = this.customStartTime ? this.customStartTime.toDate()
|
|
769
|
+
: new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0, 0, 0);
|
|
770
|
+
const defaultEnd = this.customEndTime ? this.customEndTime.toDate()
|
|
771
|
+
: new Date(now.getFullYear(), now.getMonth(), now.getDate(), 23, 59, 59);
|
|
772
|
+
if (this.guiContext && this.guiContext.showCustomTimeRangeModal) {
|
|
773
|
+
this.guiContext.showCustomTimeRangeModal({ startTime: defaultStart, endTime: defaultEnd }).then(result => {
|
|
774
|
+
if (result) {
|
|
775
|
+
const momentAny = moment;
|
|
776
|
+
this.customStartTime = momentAny(result.startTime);
|
|
777
|
+
this.customEndTime = momentAny(result.endTime);
|
|
778
|
+
this.updateTimeRange(8);
|
|
779
|
+
this.reRenderElement(this.startTime, this.endTime, this.displayOption.dataLimit, HistoricalCurveTimeRange.BeginOpenEndOpen);
|
|
780
|
+
}
|
|
781
|
+
});
|
|
782
|
+
return;
|
|
783
|
+
}
|
|
784
|
+
this.showCustomTimeRangeModalFallback();
|
|
785
|
+
}
|
|
786
|
+
showCustomTimeRangeModalFallback() {
|
|
787
|
+
const prevTimePeriod = this.currentTimePeriod;
|
|
788
|
+
const now = new Date();
|
|
789
|
+
const defaultStart = this.fmtDatetimeLocal(this.customStartTime ? this.customStartTime.toDate()
|
|
790
|
+
: new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0, 0, 0));
|
|
791
|
+
const defaultEnd = this.fmtDatetimeLocal(this.customEndTime ? this.customEndTime.toDate()
|
|
792
|
+
: new Date(now.getFullYear(), now.getMonth(), now.getDate(), 23, 59, 59));
|
|
793
|
+
const overlay = document.createElement('div');
|
|
794
|
+
overlay.style.cssText = 'position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.5);z-index:9999;';
|
|
795
|
+
const modal = document.createElement('div');
|
|
796
|
+
const modalCss = 'position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);'
|
|
797
|
+
+ 'background:#fff;border-radius:4px;min-width:460px;'
|
|
798
|
+
+ 'box-shadow:0 4px 12px rgba(0,0,0,0.15);font-family:inherit;font-size:14px;';
|
|
799
|
+
modal.style.cssText = modalCss;
|
|
800
|
+
const header = document.createElement('div');
|
|
801
|
+
header.style.cssText = 'display:flex;align-items:center;justify-content:space-between;padding:12px 16px;border-bottom:1px solid #e8e8e8;';
|
|
802
|
+
const title = document.createElement('span');
|
|
803
|
+
title.style.cssText = 'font-size:16px;font-weight:500;color:#333;';
|
|
804
|
+
title.textContent = this.localization.customTimeRange || '自定义';
|
|
805
|
+
const closeBtn = document.createElement('span');
|
|
806
|
+
closeBtn.style.cssText = 'cursor:pointer;font-size:18px;color:#999;line-height:1;';
|
|
807
|
+
closeBtn.textContent = '×';
|
|
808
|
+
header.appendChild(title);
|
|
809
|
+
header.appendChild(closeBtn);
|
|
810
|
+
const body = document.createElement('div');
|
|
811
|
+
body.style.cssText = 'padding:20px 16px;display:flex;align-items:center;flex-wrap:wrap;gap:8px;';
|
|
812
|
+
const label = document.createElement('span');
|
|
813
|
+
label.style.cssText = 'color:#333;white-space:nowrap;';
|
|
814
|
+
label.textContent = '时间范围:';
|
|
815
|
+
const inputStyle = 'border:1px solid #d9d9d9;border-radius:4px;padding:4px 8px;font-size:14px;height:32px;outline:none;color:#333;';
|
|
816
|
+
const startInput = document.createElement('input');
|
|
817
|
+
startInput.type = 'datetime-local';
|
|
818
|
+
startInput.setAttribute('step', '1');
|
|
819
|
+
startInput.value = defaultStart;
|
|
820
|
+
startInput.style.cssText = inputStyle;
|
|
821
|
+
const separator = document.createElement('span');
|
|
822
|
+
separator.textContent = ' - ';
|
|
823
|
+
separator.style.cssText = 'color:#333;';
|
|
824
|
+
const endInput = document.createElement('input');
|
|
825
|
+
endInput.type = 'datetime-local';
|
|
826
|
+
endInput.setAttribute('step', '1');
|
|
827
|
+
endInput.value = defaultEnd;
|
|
828
|
+
endInput.style.cssText = inputStyle;
|
|
829
|
+
body.appendChild(label);
|
|
830
|
+
body.appendChild(startInput);
|
|
831
|
+
body.appendChild(separator);
|
|
832
|
+
body.appendChild(endInput);
|
|
833
|
+
const footer = document.createElement('div');
|
|
834
|
+
footer.style.cssText = 'display:flex;justify-content:flex-end;gap:8px;padding:12px 16px;border-top:1px solid #e8e8e8;';
|
|
835
|
+
const cancelBtn = document.createElement('button');
|
|
836
|
+
cancelBtn.textContent = this.localization.cancel || '取消';
|
|
837
|
+
cancelBtn.style.cssText = 'padding:5px 16px;border:1px solid #d9d9d9;border-radius:4px;background:#fff;cursor:pointer;font-size:14px;color:#333;';
|
|
838
|
+
const saveBtn = document.createElement('button');
|
|
839
|
+
saveBtn.textContent = '保存';
|
|
840
|
+
saveBtn.style.cssText = 'padding:5px 16px;border:none;border-radius:4px;background:#1890ff;color:#fff;cursor:pointer;font-size:14px;';
|
|
841
|
+
footer.appendChild(cancelBtn);
|
|
842
|
+
footer.appendChild(saveBtn);
|
|
843
|
+
modal.appendChild(header);
|
|
844
|
+
modal.appendChild(body);
|
|
845
|
+
modal.appendChild(footer);
|
|
846
|
+
overlay.appendChild(modal);
|
|
847
|
+
document.body.appendChild(overlay);
|
|
848
|
+
const close = (revert) => {
|
|
849
|
+
document.body.removeChild(overlay);
|
|
850
|
+
if (revert) {
|
|
851
|
+
const selectEl = this.$element && this.$element.find('select');
|
|
852
|
+
if (selectEl && selectEl.length) {
|
|
853
|
+
selectEl.val(prevTimePeriod.toString());
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
};
|
|
857
|
+
closeBtn.addEventListener('click', () => close(true));
|
|
858
|
+
cancelBtn.addEventListener('click', () => close(true));
|
|
859
|
+
saveBtn.addEventListener('click', () => {
|
|
860
|
+
const startVal = startInput.value;
|
|
861
|
+
const endVal = endInput.value;
|
|
862
|
+
if (!startVal) {
|
|
863
|
+
startInput.style.borderColor = 'red';
|
|
864
|
+
return;
|
|
865
|
+
}
|
|
866
|
+
const startDate = new Date(startVal);
|
|
867
|
+
const endDate = endVal
|
|
868
|
+
? new Date(endVal)
|
|
869
|
+
: new Date(startDate.getFullYear(), startDate.getMonth(), startDate.getDate(), 23, 59, 59);
|
|
870
|
+
if (isNaN(startDate.getTime())) {
|
|
871
|
+
startInput.style.borderColor = 'red';
|
|
872
|
+
return;
|
|
873
|
+
}
|
|
874
|
+
if (endDate.getTime() <= startDate.getTime()) {
|
|
875
|
+
endInput.style.borderColor = 'red';
|
|
876
|
+
return;
|
|
877
|
+
}
|
|
878
|
+
const momentAny = moment;
|
|
879
|
+
this.customStartTime = momentAny(startDate);
|
|
880
|
+
this.customEndTime = momentAny(endDate);
|
|
881
|
+
close(false);
|
|
882
|
+
this.updateTimeRange(8);
|
|
883
|
+
this.reRenderElement(this.startTime, this.endTime, this.displayOption.dataLimit, HistoricalCurveTimeRange.BeginOpenEndOpen);
|
|
884
|
+
});
|
|
885
|
+
}
|
|
602
886
|
loadFirstPage() {
|
|
603
887
|
this.updateQueryTimeRange();
|
|
604
888
|
this.reRenderElement(this.startTime, this.endTime, this.displayOption.dataLimit, HistoricalCurveTimeRange.BeginOpenEndOpen);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
[{"__symbolic":"module","version":4,"metadata":{"HistoricalCurveElement":{"__symbolic":"class","extends":{"__symbolic":"reference","module":"../base/conditional-display-element","name":"ConditionalDisplayElement","line":23,"character":44},"members":{"__ctor__":[{"__symbolic":"constructor","parameters":[{"__symbolic":"error","message":"Could not resolve type","line":
|
|
1
|
+
[{"__symbolic":"module","version":4,"metadata":{"HistoricalCurveElement":{"__symbolic":"class","extends":{"__symbolic":"reference","module":"../base/conditional-display-element","name":"ConditionalDisplayElement","line":23,"character":44},"members":{"__ctor__":[{"__symbolic":"constructor","parameters":[{"__symbolic":"error","message":"Could not resolve type","line":75,"character":25,"context":{"typeName":"HTMLElement"}},{"__symbolic":"reference","module":"@angular/core","name":"Injector","line":76,"character":18},{"__symbolic":"reference","module":"../../service","name":"PermissionChecker","line":77,"character":27},{"__symbolic":"reference","module":"../../communication","name":"VariableCommunicator","line":78,"character":30},{"__symbolic":"reference","module":"../../config","name":"VariableStore","line":79,"character":23},{"__symbolic":"reference","module":"../../config","name":"HistoryDataStore","line":80,"character":43},{"__symbolic":"reference","name":"string"},{"__symbolic":"reference","module":"../../service","name":"SystemTextLibraryService","line":82,"character":52},{"__symbolic":"reference","module":"../../service","name":"LanguageService","line":83,"character":43},{"__symbolic":"reference","module":"../../gui/gui-context","name":"GuiContext","line":84,"character":38}]}],"dispose":[{"__symbolic":"method"}],"initKeyboardListener":[{"__symbolic":"method"}],"subscribeLanguageChange":[{"__symbolic":"method"}],"updateLanguageTexts":[{"__symbolic":"method"}],"getCurrentCulture":[{"__symbolic":"method"}],"getValidTimePeriods":[{"__symbolic":"method"}],"getTimePeriodText":[{"__symbolic":"method"}],"updateTimeRange":[{"__symbolic":"method"}],"updateQueryTimeRange":[{"__symbolic":"method"}],"reRenderElement":[{"__symbolic":"method"}],"renderElement":[{"__symbolic":"method"}],"setupTooltipAutoHide":[{"__symbolic":"method"}],"renderChart":[{"__symbolic":"method"}],"initPoint":[{"__symbolic":"method"}],"getLineChart":[{"__symbolic":"method"}],"getMultiBarWithFocusChart":[{"__symbolic":"method"}],"renderCommonProperty":[{"__symbolic":"method"}],"renderOperationArea":[{"__symbolic":"method"}],"timeFormat":[{"__symbolic":"method"}],"fmtDatetimeLocal":[{"__symbolic":"method"}],"showCustomTimeRangeModal":[{"__symbolic":"method"}],"showCustomTimeRangeModalFallback":[{"__symbolic":"method"}],"loadFirstPage":[{"__symbolic":"method"}],"loadNextPage":[{"__symbolic":"method"}],"loadPreviousPage":[{"__symbolic":"method"}],"loadLastPage":[{"__symbolic":"method"}],"initElementStatus":[{"__symbolic":"method"}],"updateElementStatus":[{"__symbolic":"method"}],"setStatusAsUnbound":[{"__symbolic":"method"}],"setStatusAsLoading":[{"__symbolic":"method"}],"setStatusAsLoadFailed":[{"__symbolic":"method"}],"renderStatus":[{"__symbolic":"method"}],"clearStatus":[{"__symbolic":"method"}]}}}}]
|
|
@@ -2,7 +2,7 @@ import { LOGGER_SERVICE_TOKEN } from '../../logger';
|
|
|
2
2
|
import * as d3 from 'd3-selection';
|
|
3
3
|
import { isUndefined } from 'lodash';
|
|
4
4
|
import { IndicatorLightType, SwitchType, State, BitSwitchOperation } from '../../model';
|
|
5
|
-
import { VariableState } from '../../communication';
|
|
5
|
+
import { VariableState, VariableStateEnum } from '../../communication';
|
|
6
6
|
import { ConditionalEnableElement } from '../base/conditional-enable-element';
|
|
7
7
|
import { GraphStateElement } from '../shared/graph/graph-state-element';
|
|
8
8
|
import { TextStateElement } from '../shared/text/text-state-element';
|
|
@@ -195,11 +195,18 @@ export class SwitchIndicatorLightElement extends ConditionalEnableElement {
|
|
|
195
195
|
}
|
|
196
196
|
}
|
|
197
197
|
initIndictorLightOperator() {
|
|
198
|
+
var _a, _b, _c, _d;
|
|
198
199
|
const settings = this.model.indicatorLightSettings;
|
|
199
200
|
if (settings.settings.variableName) {
|
|
200
201
|
const variable = new VariableDefinition(settings.settings.variableName, settings.settings.variableGroupName, settings.settings.dataSourceCode, settings.settings.variableVersion);
|
|
201
|
-
|
|
202
|
+
const convertedName = VariableUtil.getConvertedVariableName(this.variableStore, variable);
|
|
203
|
+
this.addElementState(new VariableState(convertedName, undefined));
|
|
202
204
|
this.initState();
|
|
205
|
+
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);
|
|
206
|
+
if (validNames && !validNames.includes(convertedName)) {
|
|
207
|
+
this.updateElementStates([new VariableState(convertedName, VariableStateEnum.InvalidMonitor)]);
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
203
210
|
}
|
|
204
211
|
switch (settings.type) {
|
|
205
212
|
case IndicatorLightType.Bit:
|
package/gui/gui-context.d.ts
CHANGED
|
@@ -22,5 +22,12 @@ export interface GuiContext {
|
|
|
22
22
|
getDefaultLanguageId?(): number;
|
|
23
23
|
getLanguageCultureById?(languageId: number | null): string | null;
|
|
24
24
|
updateCurrentLanguageId?(languageId: number | null): Promise<void>;
|
|
25
|
+
showCustomTimeRangeModal?(config: {
|
|
26
|
+
startTime?: Date;
|
|
27
|
+
endTime?: Date;
|
|
28
|
+
}): Promise<{
|
|
29
|
+
startTime: Date;
|
|
30
|
+
endTime: Date;
|
|
31
|
+
} | null>;
|
|
25
32
|
dispose(): void;
|
|
26
33
|
}
|
package/gui/gui-view.js
CHANGED
|
@@ -2,7 +2,7 @@ import { LOGGER_SERVICE_TOKEN } from '../logger';
|
|
|
2
2
|
import * as d3 from 'd3-selection';
|
|
3
3
|
import { each, forEach } from 'lodash';
|
|
4
4
|
import { map } from 'rxjs/operators';
|
|
5
|
-
import { VariableStateEnum } from '../communication';
|
|
5
|
+
import { VariableStateEnum, VariableState } from '../communication';
|
|
6
6
|
import { MainElement } from '../elements/main-element';
|
|
7
7
|
import { PerViewVariableCommunicator } from '../elements/per-view-variable-communicator';
|
|
8
8
|
import { ViewPopupBackdropType, ViewPopupLocationType } from '../model';
|
|
@@ -64,6 +64,7 @@ export class GuiView {
|
|
|
64
64
|
this.logger.debug('[GUI] View loaded.');
|
|
65
65
|
}
|
|
66
66
|
loadElementState() {
|
|
67
|
+
var _a, _b;
|
|
67
68
|
if (!this.mainElement) {
|
|
68
69
|
return;
|
|
69
70
|
}
|
|
@@ -108,6 +109,20 @@ export class GuiView {
|
|
|
108
109
|
});
|
|
109
110
|
normalVariablesForState.splice(normalVariablesForState.indexOf('设备状态'), 1);
|
|
110
111
|
}
|
|
112
|
+
const validVariableNames = (_b = (_a = this.context.configStore.variableStore).getAllVariableNames) === null || _b === void 0 ? void 0 : _b.call(_a);
|
|
113
|
+
if (validVariableNames) {
|
|
114
|
+
const invalidVariables = normalVariablesForState.filter(name => !validVariableNames.includes(name));
|
|
115
|
+
if (invalidVariables.length > 0) {
|
|
116
|
+
const unbindStates = invalidVariables.map(name => new VariableState(name, VariableStateEnum.InvalidMonitor));
|
|
117
|
+
this.mainElement.reportVariableStates(unbindStates);
|
|
118
|
+
invalidVariables.forEach(name => {
|
|
119
|
+
const idx = normalVariablesForState.indexOf(name);
|
|
120
|
+
if (idx !== -1) {
|
|
121
|
+
normalVariablesForState.splice(idx, 1);
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
}
|
|
111
126
|
if (normalVariablesForState.length === 0) {
|
|
112
127
|
return;
|
|
113
128
|
}
|
|
@@ -29,6 +29,7 @@ export interface Localization {
|
|
|
29
29
|
offline: any;
|
|
30
30
|
abnormal: any;
|
|
31
31
|
disable: any;
|
|
32
|
+
invalidMonitor: any;
|
|
32
33
|
permissiontip: any;
|
|
33
34
|
conditionIsNotMetTip: any;
|
|
34
35
|
chartNoData: any;
|
|
@@ -39,6 +40,9 @@ export interface Localization {
|
|
|
39
40
|
lastSevenDays: any;
|
|
40
41
|
lastThirtyDays: any;
|
|
41
42
|
lastOneYear: any;
|
|
43
|
+
customTimeRange: any;
|
|
44
|
+
startTime: any;
|
|
45
|
+
endTime: any;
|
|
42
46
|
grouped: any;
|
|
43
47
|
stacked: any;
|
|
44
48
|
passwordVerify: any;
|
|
@@ -29,6 +29,7 @@ export const DefaultLocalization = {
|
|
|
29
29
|
offline: 'Offline',
|
|
30
30
|
abnormal: 'Data abnormal',
|
|
31
31
|
disable: 'Disable',
|
|
32
|
+
invalidMonitor: 'Element binding monitor point is invalid',
|
|
32
33
|
permissiontip: 'You have no permission to operate.',
|
|
33
34
|
conditionIsNotMetTip: 'Operation conditions not met or variable anomalies.',
|
|
34
35
|
chartNoData: 'No Data Available',
|
|
@@ -39,6 +40,9 @@ export const DefaultLocalization = {
|
|
|
39
40
|
lastSevenDays: 'Last 7 days',
|
|
40
41
|
lastThirtyDays: 'Last 30 days',
|
|
41
42
|
lastOneYear: 'Last 1 year',
|
|
43
|
+
customTimeRange: 'Custom',
|
|
44
|
+
startTime: 'Start Time',
|
|
45
|
+
endTime: 'End Time',
|
|
42
46
|
grouped: 'Grouped',
|
|
43
47
|
stacked: 'Stacked',
|
|
44
48
|
passwordVerify: 'Password verifiers',
|