@flexem/fc-gui 3.0.0-alpha.121 → 3.0.0-alpha.122

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.
@@ -29,7 +29,6 @@ import { VideoElement } from './video/video-element';
29
29
  import { WeatherElement } from './weather/weater-element';
30
30
  import { AirQualityElement } from './air-quality/air-quality-element';
31
31
  import { AlarmElement } from './alarm/alarm-element';
32
- import { ScrollAlarmElement } from './scroll-alarm/scroll-alarm-element';
33
32
  export class MainElement {
34
33
  constructor(injector, bsModalService, context, variableCommunicator, popupViewService, signalRAppId) {
35
34
  this.injector = injector;
@@ -134,9 +133,6 @@ export class MainElement {
134
133
  case GuiConsts.components.alarmKey:
135
134
  this.elements.push(new AlarmElement(element, this.injector, this.context.permissionChecker, this.variableCommunicator, this.context.configStore.variableStore, this.context.configStore.alarmsStore, this.signalRAppId));
136
135
  break;
137
- case GuiConsts.components.scrollAlarmKey:
138
- this.elements.push(new ScrollAlarmElement(element, this.injector, this.context.permissionChecker, this.variableCommunicator, this.context.configStore.variableStore, this.context.configStore.alarmsStore, this.signalRAppId));
139
- break;
140
136
  }
141
137
  });
142
138
  this.initBackground();
@@ -302,7 +298,7 @@ export class MainElement {
302
298
  each(this.elements, e => {
303
299
  if (e instanceof HistoricalCurveElement || e instanceof VideoElement
304
300
  || e instanceof WeatherElement || e instanceof NumericalDisplayElement || e instanceof TextElement
305
- || e instanceof AirQualityElement || e instanceof ScrollAlarmElement) {
301
+ || e instanceof AirQualityElement || e instanceof SwitchIndicatorLightElement) {
306
302
  e.dispose();
307
303
  }
308
304
  });
@@ -1 +1 @@
1
- [{"__symbolic":"module","version":4,"metadata":{"MainElement":{"__symbolic":"class","members":{"__ctor__":[{"__symbolic":"constructor","parameters":[{"__symbolic":"reference","module":"@angular/core","name":"Injector","line":56,"character":43},{"__symbolic":"reference","module":"ngx-bootstrap/modal","name":"BsModalService","line":57,"character":41},{"__symbolic":"reference","module":"../gui/gui-context","name":"GuiContext","line":58,"character":34},{"__symbolic":"reference","module":"../communication","name":"VariableCommunicator","line":59,"character":47},{"__symbolic":"reference","module":"../view/popup-view.service","name":"PopupViewService","line":60,"character":43},null]}],"load":[{"__symbolic":"method"}],"uniformStretch":[{"__symbolic":"method"}],"changeVideoStyle":[{"__symbolic":"method"}],"horizontalStretch":[{"__symbolic":"method"}],"initElementState":[{"__symbolic":"method"}],"getVariableNames":[{"__symbolic":"method"}],"reportVariableStates":[{"__symbolic":"method"}],"getVirtualDeviceIdFromRect":[{"__symbolic":"method"}],"reportVariableValues":[{"__symbolic":"method"}],"dispose":[{"__symbolic":"method"}],"checkIsLoaded":[{"__symbolic":"method"}],"initBackground":[{"__symbolic":"method"}],"getImageEl":[{"__symbolic":"method"}]}}}}]
1
+ [{"__symbolic":"module","version":4,"metadata":{"MainElement":{"__symbolic":"class","members":{"__ctor__":[{"__symbolic":"constructor","parameters":[{"__symbolic":"reference","module":"@angular/core","name":"Injector","line":55,"character":43},{"__symbolic":"reference","module":"ngx-bootstrap/modal","name":"BsModalService","line":56,"character":41},{"__symbolic":"reference","module":"../gui/gui-context","name":"GuiContext","line":57,"character":34},{"__symbolic":"reference","module":"../communication","name":"VariableCommunicator","line":58,"character":47},{"__symbolic":"reference","module":"../view/popup-view.service","name":"PopupViewService","line":59,"character":43},null]}],"load":[{"__symbolic":"method"}],"uniformStretch":[{"__symbolic":"method"}],"changeVideoStyle":[{"__symbolic":"method"}],"horizontalStretch":[{"__symbolic":"method"}],"initElementState":[{"__symbolic":"method"}],"getVariableNames":[{"__symbolic":"method"}],"reportVariableStates":[{"__symbolic":"method"}],"getVirtualDeviceIdFromRect":[{"__symbolic":"method"}],"reportVariableValues":[{"__symbolic":"method"}],"dispose":[{"__symbolic":"method"}],"checkIsLoaded":[{"__symbolic":"method"}],"initBackground":[{"__symbolic":"method"}],"getImageEl":[{"__symbolic":"method"}]}}}}]
@@ -24,4 +24,5 @@ export declare class GraphStateElement {
24
24
  private removeImageElement;
25
25
  private doFaultFlicker;
26
26
  private clearFlickerInterval;
27
+ dispose(): void;
27
28
  }
@@ -107,4 +107,22 @@ export class GraphStateElement {
107
107
  }
108
108
  }
109
109
  }
110
+ dispose() {
111
+ // 清理定时器
112
+ if (this.faultFlickerInterval) {
113
+ clearInterval(this.faultFlickerInterval);
114
+ this.faultFlickerInterval = undefined;
115
+ }
116
+ // 移除图片元素
117
+ this.removeImageElement();
118
+ // 清理图形缓存
119
+ if (this.graphs) {
120
+ this.graphs.clear();
121
+ }
122
+ // 清理 SVG 元素
123
+ if (this._element && this._element.parentNode) {
124
+ this._element.parentNode.removeChild(this._element);
125
+ }
126
+ this._element = null;
127
+ }
110
128
  }
@@ -1 +1 @@
1
- [{"__symbolic":"module","version":4,"metadata":{"GraphStateElement":{"__symbolic":"class","members":{"__ctor__":[{"__symbolic":"constructor","parameters":[{"__symbolic":"reference","module":"../../../model","name":"GraphSetting","line":21,"character":47},{"__symbolic":"reference","name":"number"},{"__symbolic":"reference","name":"number"},{"__symbolic":"reference","module":"../../../config","name":"GraphStore","line":24,"character":37},{"__symbolic":"reference","module":"../../../logger","name":"LoggerService","line":25,"character":33},{"__symbolic":"reference","name":"number"},{"__symbolic":"reference","name":"Array","arguments":[{"__symbolic":"reference","module":"../../../model/switch-indicator-light/indicator-light-fault-flicker","name":"IndicatorLightFaultFlicker","line":27,"character":41}]}]}],"switchToState":[{"__symbolic":"method"}],"changeGraph":[{"__symbolic":"method"}],"getImageElement":[{"__symbolic":"method"}],"removeImageElement":[{"__symbolic":"method"}],"doFaultFlicker":[{"__symbolic":"method"}],"clearFlickerInterval":[{"__symbolic":"method"}]}}}}]
1
+ [{"__symbolic":"module","version":4,"metadata":{"GraphStateElement":{"__symbolic":"class","members":{"__ctor__":[{"__symbolic":"constructor","parameters":[{"__symbolic":"reference","module":"../../../model","name":"GraphSetting","line":21,"character":47},{"__symbolic":"reference","name":"number"},{"__symbolic":"reference","name":"number"},{"__symbolic":"reference","module":"../../../config","name":"GraphStore","line":24,"character":37},{"__symbolic":"reference","module":"../../../logger","name":"LoggerService","line":25,"character":33},{"__symbolic":"reference","name":"number"},{"__symbolic":"reference","name":"Array","arguments":[{"__symbolic":"reference","module":"../../../model/switch-indicator-light/indicator-light-fault-flicker","name":"IndicatorLightFaultFlicker","line":27,"character":41}]}]}],"switchToState":[{"__symbolic":"method"}],"changeGraph":[{"__symbolic":"method"}],"getImageElement":[{"__symbolic":"method"}],"removeImageElement":[{"__symbolic":"method"}],"doFaultFlicker":[{"__symbolic":"method"}],"clearFlickerInterval":[{"__symbolic":"method"}],"dispose":[{"__symbolic":"method"}]}}}}]
@@ -24,6 +24,7 @@ export declare class SwitchIndicatorLightElement extends ConditionalEnableElemen
24
24
  private restorationTimer;
25
25
  private isWriteRestorationDownValue;
26
26
  private onDocMouseUp;
27
+ private indicatorLightSubscription;
27
28
  constructor(element: HTMLElement, injector: Injector, modalService: BsModalService, variableCommunicator: VariableCommunicator, graphStore: GraphStore, permissionChecker: PermissionChecker, operationRecordService: OperationRecordService, securityChecker: SecurityChecker, variableStore: VariableStore, localization: Localization, signalRAppId: string);
28
29
  handleMouseUp(): void;
29
30
  private initOnDocMouseUpEvent;
@@ -36,4 +37,5 @@ export declare class SwitchIndicatorLightElement extends ConditionalEnableElemen
36
37
  private switchToState;
37
38
  private initGraphAndText;
38
39
  private checkState;
40
+ dispose(): void;
39
41
  }
@@ -208,7 +208,7 @@ export class SwitchIndicatorLightElement extends ConditionalEnableElement {
208
208
  default:
209
209
  throw new Error(`Unknown switchType:${settings.type}`);
210
210
  }
211
- this.indicatorLightOperator.currentStateIdChanged.subscribe(statusIdValue => {
211
+ this.indicatorLightSubscription = this.indicatorLightOperator.currentStateIdChanged.subscribe(statusIdValue => {
212
212
  this.currentStateIdChange(statusIdValue);
213
213
  });
214
214
  this.indicatorLightOperator.requestData(this.signalRAppId);
@@ -249,4 +249,28 @@ export class SwitchIndicatorLightElement extends ConditionalEnableElement {
249
249
  throw new Error('The switch indicator light\'s states must greater than 2.');
250
250
  }
251
251
  }
252
+ dispose() {
253
+ // 清理 document 级别的事件监听器
254
+ if (this.onDocMouseUp) {
255
+ document.removeEventListener(this.isMobileMode ? 'touchend' : 'mouseup', this.onDocMouseUp);
256
+ }
257
+ // 清理定时器
258
+ if (this.restorationTimer) {
259
+ clearTimeout(this.restorationTimer);
260
+ this.restorationTimer = undefined;
261
+ }
262
+ // 清理 indicatorLightOperator 订阅
263
+ if (this.indicatorLightSubscription) {
264
+ this.indicatorLightSubscription.unsubscribe();
265
+ }
266
+ // 清理图形元素(释放 SVG 内存)
267
+ if (this.graphStateElement) {
268
+ this.graphStateElement.dispose();
269
+ }
270
+ // 清理文本元素
271
+ if (this.textStateElement) {
272
+ // TextStateElement 可能也需要 dispose,暂时先清理引用
273
+ this.textStateElement = null;
274
+ }
275
+ }
252
276
  }
@@ -1 +1 @@
1
- [{"__symbolic":"module","version":4,"metadata":{"SwitchIndicatorLightElement":{"__symbolic":"class","extends":{"__symbolic":"reference","module":"../base/conditional-enable-element","name":"ConditionalEnableElement","line":32,"character":49},"members":{"__ctor__":[{"__symbolic":"constructor","parameters":[{"__symbolic":"error","message":"Could not resolve type","line":50,"character":25,"context":{"typeName":"HTMLElement"}},{"__symbolic":"reference","module":"@angular/core","name":"Injector","line":51,"character":18},{"__symbolic":"reference","module":"ngx-bootstrap/modal","name":"BsModalService","line":52,"character":39},{"__symbolic":"reference","module":"../../communication","name":"VariableCommunicator","line":53,"character":30},{"__symbolic":"reference","module":"../../config","name":"GraphStore","line":54,"character":37},{"__symbolic":"reference","module":"../../service","name":"PermissionChecker","line":55,"character":27},{"__symbolic":"reference","module":"../../service","name":"OperationRecordService","line":56,"character":49},{"__symbolic":"reference","module":"../../security","name":"SecurityChecker","line":57,"character":42},{"__symbolic":"reference","module":"../../config","name":"VariableStore","line":58,"character":23},{"__symbolic":"reference","module":"../../localization","name":"Localization","line":59,"character":22},{"__symbolic":"reference","name":"string"}]}],"handleMouseUp":[{"__symbolic":"method"}],"initOnDocMouseUpEvent":[{"__symbolic":"method"}],"checkElementPassword":[{"__symbolic":"method"}],"doSwitchOperator":[{"__symbolic":"method"}],"writeValue":[{"__symbolic":"method"}],"initSwitchOperator":[{"__symbolic":"method"}],"initIndictorLightOperator":[{"__symbolic":"method"}],"currentStateIdChange":[{"__symbolic":"method"}],"switchToState":[{"__symbolic":"method"}],"initGraphAndText":[{"__symbolic":"method"}],"checkState":[{"__symbolic":"method"}]}}}}]
1
+ [{"__symbolic":"module","version":4,"metadata":{"SwitchIndicatorLightElement":{"__symbolic":"class","extends":{"__symbolic":"reference","module":"../base/conditional-enable-element","name":"ConditionalEnableElement","line":32,"character":49},"members":{"__ctor__":[{"__symbolic":"constructor","parameters":[{"__symbolic":"error","message":"Could not resolve type","line":51,"character":25,"context":{"typeName":"HTMLElement"}},{"__symbolic":"reference","module":"@angular/core","name":"Injector","line":52,"character":18},{"__symbolic":"reference","module":"ngx-bootstrap/modal","name":"BsModalService","line":53,"character":39},{"__symbolic":"reference","module":"../../communication","name":"VariableCommunicator","line":54,"character":30},{"__symbolic":"reference","module":"../../config","name":"GraphStore","line":55,"character":37},{"__symbolic":"reference","module":"../../service","name":"PermissionChecker","line":56,"character":27},{"__symbolic":"reference","module":"../../service","name":"OperationRecordService","line":57,"character":49},{"__symbolic":"reference","module":"../../security","name":"SecurityChecker","line":58,"character":42},{"__symbolic":"reference","module":"../../config","name":"VariableStore","line":59,"character":23},{"__symbolic":"reference","module":"../../localization","name":"Localization","line":60,"character":22},{"__symbolic":"reference","name":"string"}]}],"handleMouseUp":[{"__symbolic":"method"}],"initOnDocMouseUpEvent":[{"__symbolic":"method"}],"checkElementPassword":[{"__symbolic":"method"}],"doSwitchOperator":[{"__symbolic":"method"}],"writeValue":[{"__symbolic":"method"}],"initSwitchOperator":[{"__symbolic":"method"}],"initIndictorLightOperator":[{"__symbolic":"method"}],"currentStateIdChange":[{"__symbolic":"method"}],"switchToState":[{"__symbolic":"method"}],"initGraphAndText":[{"__symbolic":"method"}],"checkState":[{"__symbolic":"method"}],"dispose":[{"__symbolic":"method"}]}}}}]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "main": "bundles/fc-gui.umd.js",
3
- "version": "3.0.0-alpha.121",
3
+ "version": "3.0.0-alpha.122",
4
4
  "module": "public_api.js",
5
5
  "typings": "public_api.d.ts",
6
6
  "license": "UNLICENSED",
@@ -28,6 +28,5 @@ export declare class GuiConsts {
28
28
  weatherKey: string;
29
29
  airQualityKey: string;
30
30
  alarmKey: string;
31
- scrollAlarmKey: string;
32
31
  };
33
32
  }
@@ -28,6 +28,5 @@ GuiConsts.components = {
28
28
  tableKey: 'Table',
29
29
  weatherKey: 'Weather',
30
30
  airQualityKey: 'AirQualityIndex',
31
- alarmKey: 'Alarm',
32
- scrollAlarmKey: 'ScrollAlarm'
31
+ alarmKey: 'Alarm'
33
32
  };
@@ -1 +1 @@
1
- [{"__symbolic":"module","version":4,"metadata":{"GuiConsts":{"__symbolic":"class","statics":{"components":{"imageKey":"Image","numericalDisplayKey":"NumericalDisplay","textKey":"Text","hyperlinkKey":"Hyperlink","meterKey":"Meter","pipeKey":"Pipe","switchIndicatorLightKey":"SwitchIndicatorLight","barGraphKey":"BarGraph","toggleViewKey":"ToggleView","characterKey":"Character","straightLineKey":"StraightLine","polyLineKey":"PolyLine","rectangleKey":"Rectangle","sectorkey":"Sector","ellipseKey":"Ellipse","datetimeDisplayKey":"DatetimeDisplay","historicalCurveKey":"HistoricalCurve","ringGraphKey":"RingGraph","viewOperationElement":"ViewOperation","polygonKey":"Polygon","videokey":"Video","tableKey":"Table","weatherKey":"Weather","airQualityKey":"AirQualityIndex","alarmKey":"Alarm","scrollAlarmKey":"ScrollAlarm"}}}}}]
1
+ [{"__symbolic":"module","version":4,"metadata":{"GuiConsts":{"__symbolic":"class","statics":{"components":{"imageKey":"Image","numericalDisplayKey":"NumericalDisplay","textKey":"Text","hyperlinkKey":"Hyperlink","meterKey":"Meter","pipeKey":"Pipe","switchIndicatorLightKey":"SwitchIndicatorLight","barGraphKey":"BarGraph","toggleViewKey":"ToggleView","characterKey":"Character","straightLineKey":"StraightLine","polyLineKey":"PolyLine","rectangleKey":"Rectangle","sectorkey":"Sector","ellipseKey":"Ellipse","datetimeDisplayKey":"DatetimeDisplay","historicalCurveKey":"HistoricalCurve","ringGraphKey":"RingGraph","viewOperationElement":"ViewOperation","polygonKey":"Polygon","videokey":"Video","tableKey":"Table","weatherKey":"Weather","airQualityKey":"AirQualityIndex","alarmKey":"Alarm"}}}}}]
@@ -1,50 +0,0 @@
1
- import { Injector } from '@angular/core';
2
- import { PermissionChecker } from '../../service';
3
- import { VariableCommunicator } from '../../communication';
4
- import { ConditionalDynamicDisplayElement } from '../base/conditional-dynamic-display-element';
5
- import { ScrollAlarmModel } from '../../model/scroll-alarm/scroll-alarm.model';
6
- import { AlarmsStore, VariableStore } from '../../config';
7
- export declare class ScrollAlarmElement extends ConditionalDynamicDisplayElement {
8
- private readonly alarmsStore;
9
- readonly model: ScrollAlarmModel;
10
- private readonly logger;
11
- readonly variableCommunicator: VariableCommunicator;
12
- private elementStatus;
13
- private element;
14
- private scrollIntervalId;
15
- private alarmNames;
16
- private startTime;
17
- private endTime;
18
- private getAlarmDataId;
19
- private isScrolling;
20
- private isDisposed;
21
- private currentPage;
22
- private maxResultCount;
23
- private displayedItems;
24
- private pageWidths;
25
- private totalWidth;
26
- private container;
27
- private allAlarmsContainer;
28
- private currentLeft;
29
- private autoCycle;
30
- private hasMoreData;
31
- private isLoadingNextPage;
32
- private headerFont;
33
- private fontString;
34
- constructor(element: HTMLElement, injector: Injector, permissionChecker: PermissionChecker, variableCommunicator: VariableCommunicator, variableStore: VariableStore, alarmsStore: AlarmsStore, signalRAppId: string);
35
- dispose(): void;
36
- private getAlarmData;
37
- private initDisplayContainer;
38
- private renderNewPage;
39
- private removeOldestPage;
40
- private resetToFirstPage;
41
- private scrollContent;
42
- private initScrolling;
43
- private pauseScroll;
44
- private resumeScroll;
45
- private updateQueryTimeRange;
46
- private setStatusAsNormal;
47
- private setStatusAsLoading;
48
- private renderStatus;
49
- private clearStatus;
50
- }
@@ -1,421 +0,0 @@
1
- import * as d3 from 'd3';
2
- import { ConditionalDynamicDisplayElement } from '../base/conditional-dynamic-display-element';
3
- import { GetAlarmsArgs } from '../../config';
4
- import * as moment from 'moment';
5
- import { LOGGER_SERVICE_TOKEN } from '../../logger';
6
- var ScrollAlarmElementStatus;
7
- (function (ScrollAlarmElementStatus) {
8
- ScrollAlarmElementStatus[ScrollAlarmElementStatus["Normal"] = 0] = "Normal";
9
- ScrollAlarmElementStatus[ScrollAlarmElementStatus["Loading"] = 1] = "Loading"; // 加载中
10
- })(ScrollAlarmElementStatus || (ScrollAlarmElementStatus = {}));
11
- export class ScrollAlarmElement extends ConditionalDynamicDisplayElement {
12
- constructor(element, injector, permissionChecker, variableCommunicator, variableStore, alarmsStore, signalRAppId) {
13
- var _a, _b, _c, _d, _e;
14
- super(element, permissionChecker, variableCommunicator, variableStore, signalRAppId);
15
- this.alarmsStore = alarmsStore;
16
- this.elementStatus = ScrollAlarmElementStatus.Loading;
17
- this.alarmNames = [];
18
- this.isScrolling = false;
19
- this.isDisposed = false;
20
- // 新的分页和滚动逻辑变量
21
- this.currentPage = 1;
22
- this.maxResultCount = 3; // 每页数据量
23
- this.displayedItems = []; // 当前显示的所有数据
24
- this.pageWidths = []; // 存储每页的宽度
25
- this.totalWidth = 0; // 所有显示数据的总宽度
26
- this.currentLeft = 0;
27
- this.autoCycle = true;
28
- this.hasMoreData = true;
29
- this.isLoadingNextPage = false;
30
- this.rootElement.selectAll('*').remove();
31
- this.setStatusAsLoading();
32
- this.logger = injector.get(LOGGER_SERVICE_TOKEN);
33
- this.variableCommunicator = variableCommunicator;
34
- this.autoCycle = (_b = (_a = this.model.generalSetting) === null || _a === void 0 ? void 0 : _a.autoCycle) !== null && _b !== void 0 ? _b : true;
35
- this.maxResultCount = (_d = (_c = this.model.generalSetting) === null || _c === void 0 ? void 0 : _c.pageSize) !== null && _d !== void 0 ? _d : 3;
36
- if (this.model.filterSetting) {
37
- this.alarmNames = this.model.filterSetting.detailsData.map(item => item.name);
38
- this.updateQueryTimeRange();
39
- // 监听告警更新
40
- // variableCommunicator.subscribeUserDeviceAlarms(signalRAppId).subscribe(alarms => {
41
- // alarms.forEach(alarm => {
42
- // if (this.alarmNames.indexOf(alarm.name) !== -1) {
43
- // this.getAlarmData();
44
- // return;
45
- // }
46
- // });
47
- // });
48
- // 初始化显示容器
49
- this.initDisplayContainer();
50
- // 获取字体设置
51
- this.headerFont = ((_e = this.model.generalSetting) === null || _e === void 0 ? void 0 : _e.headerFont) || {};
52
- const fontStyle = [];
53
- if (this.headerFont.isBold)
54
- fontStyle.push('bold');
55
- if (this.headerFont.isItalic)
56
- fontStyle.push('italic');
57
- if (this.headerFont.isUnderline)
58
- fontStyle.push('underline');
59
- fontStyle.push(`${this.headerFont.fontSize || '16px'}`);
60
- fontStyle.push(`${this.headerFont.fontFamily || 'Microsoft YaHei'}`);
61
- this.fontString = fontStyle.join(' ');
62
- this.getAlarmData();
63
- }
64
- else {
65
- this.displayedItems = [];
66
- if (this.allAlarmsContainer) {
67
- this.allAlarmsContainer.innerHTML = '';
68
- this.totalWidth = 0;
69
- this.pageWidths = [];
70
- }
71
- }
72
- }
73
- dispose() {
74
- this.isDisposed = true;
75
- clearInterval(this.scrollIntervalId);
76
- clearTimeout(this.getAlarmDataId);
77
- if (this.element && this.element.tooltip) {
78
- this.element.tooltip.hidden(true);
79
- }
80
- this.logger.debug(`[GUI]Dispose Scroll Alarm Refresh Interval:${d3.time.format('%x %X')(new Date())}`);
81
- // 重置所有状态
82
- this.isScrolling = false;
83
- }
84
- getAlarmData() {
85
- if (this.isDisposed || this.isLoadingNextPage)
86
- return;
87
- this.isLoadingNextPage = true;
88
- // Only show loading for the first page load
89
- if (this.currentPage === 1 && this.displayedItems.length === 0) {
90
- this.setStatusAsLoading();
91
- }
92
- clearTimeout(this.getAlarmDataId);
93
- this.getAlarmDataId = setTimeout(() => {
94
- this.updateQueryTimeRange();
95
- const skipCount = (this.currentPage - 1) * this.maxResultCount;
96
- const input = new GetAlarmsArgs(this.alarmNames, this.startTime, this.endTime, this.maxResultCount, skipCount);
97
- this.alarmsStore.getHistoryAlarms(input).subscribe(result => {
98
- this.isLoadingNextPage = false;
99
- if (!result.error && result.items && result.items.length > 0) {
100
- const newPage = result.items;
101
- // 检查是否还有更多数据
102
- if (!this.autoCycle && newPage.length < this.maxResultCount) {
103
- this.hasMoreData = false;
104
- }
105
- else {
106
- this.hasMoreData = true;
107
- }
108
- // 添加新页数据
109
- this.displayedItems = this.displayedItems.concat(newPage);
110
- // 渲染新页
111
- this.renderNewPage(newPage);
112
- // 更新页码
113
- this.currentPage++;
114
- // 检查是否需要删除旧页(保持最多3页)
115
- if (this.currentPage > 4) {
116
- this.removeOldestPage();
117
- }
118
- // 如果是首次加载或还没有开始滚动,初始化滚动
119
- if (!this.isScrolling && this.displayedItems.length > 0) {
120
- this.initScrolling();
121
- }
122
- this.setStatusAsNormal();
123
- }
124
- else {
125
- // 如果没有数据且自动循环开启,循环回到第一页而不清空数据
126
- if (this.autoCycle) {
127
- // 直接跳转到第一页
128
- this.currentPage = 1;
129
- // 继续加载数据(会自动添加到末尾)
130
- this.getAlarmData();
131
- }
132
- else {
133
- this.hasMoreData = false;
134
- this.setStatusAsNormal();
135
- }
136
- }
137
- }, error => {
138
- this.isLoadingNextPage = false;
139
- this.setStatusAsNormal();
140
- this.logger.error('Failed to get alarm data:', error);
141
- });
142
- }, 500);
143
- }
144
- initDisplayContainer() {
145
- var _a;
146
- const elementHeight = this.model.size.height;
147
- const elementWidth = this.model.size.width;
148
- // 创建foreignObject作为容器
149
- this.element = document.createElementNS('http://www.w3.org/2000/svg', 'foreignObject');
150
- this.element.setAttribute('width', elementWidth.toString());
151
- this.element.setAttribute('height', elementHeight.toString());
152
- this.$element.append(this.element);
153
- // 创建背景容器,应用headerFillColor背景色
154
- this.container = document.createElement('div');
155
- this.container.style.cssText = `
156
- height: ${elementHeight}px;
157
- width: 100%;
158
- background-color: ${((_a = this.model.generalSetting) === null || _a === void 0 ? void 0 : _a.headerFillColor) || '#ffffff'};
159
- display: flex;
160
- align-items: center;
161
- overflow: hidden;
162
- position: relative;
163
- border: 1px solid #8ea0aa;
164
- `;
165
- this.element.appendChild(this.container);
166
- // 创建一个大容器来包含所有告警项,初始位置在左侧
167
- this.allAlarmsContainer = document.createElement('div');
168
- this.allAlarmsContainer.style.cssText = `
169
- position: absolute;
170
- left: 0px;
171
- top: 50%;
172
- transform: translateY(-50%);
173
- display: flex;
174
- align-items: center;
175
- gap: 80px;
176
- `;
177
- this.container.appendChild(this.allAlarmsContainer);
178
- // 添加鼠标悬停暂停和恢复滚动功能
179
- this.container.addEventListener('mouseenter', () => this.pauseScroll());
180
- this.container.addEventListener('mouseleave', () => this.resumeScroll());
181
- }
182
- renderNewPage(pageData) {
183
- let pageWidth = 0;
184
- // 为每个告警数据创建文本容器
185
- pageData.forEach((alarm) => {
186
- var _a, _b, _c, _d, _e, _f, _g, _h;
187
- // 创建告警文本容器
188
- const textContainer = document.createElement('div');
189
- textContainer.style.cssText = `
190
- font: ${this.fontString};
191
- color: ${this.headerFont.color || '#E95F5F'};
192
- white-space: nowrap;
193
- overflow: visible;
194
- `;
195
- // 构建告警信息内容,根据配置决定显示哪些字段
196
- const contentParts = [];
197
- // 显示触发时间
198
- if (((_a = this.model.generalSetting) === null || _a === void 0 ? void 0 : _a.showTriggerTime) && alarm.triggeredTime) {
199
- const formattedTime = moment(alarm.triggeredTime).format('YYYY/MM/DD HH:mm:ss');
200
- contentParts.push(formattedTime);
201
- }
202
- // 获取当前语言环境
203
- const language = ((_d = (_c = (_b = window.abp) === null || _b === void 0 ? void 0 : _b.localization) === null || _c === void 0 ? void 0 : _c.currentLanguage) === null || _d === void 0 ? void 0 : _d.name) || 'zh-Hans';
204
- const isChinese = language === 'zh-Hans' || language === 'zh';
205
- // 显示告警等级
206
- if (((_e = this.model.generalSetting) === null || _e === void 0 ? void 0 : _e.showAlarmLevel) && alarm.alarmLevel !== undefined) {
207
- const levelMap = isChinese ? ['警告', '次要', '主要', '严重'] : ['Warning', 'Minor', 'Major', 'Critical'];
208
- const alarmLevel = levelMap[alarm.alarmLevel] || (isChinese ? '警告' : 'Warning');
209
- contentParts.push(alarmLevel);
210
- }
211
- // 显示告警名称
212
- if (((_f = this.model.generalSetting) === null || _f === void 0 ? void 0 : _f.showAlarmName) && alarm.name) {
213
- contentParts.push(alarm.name);
214
- }
215
- // 显示告警状态
216
- if (((_g = this.model.generalSetting) === null || _g === void 0 ? void 0 : _g.showAlarmState) && alarm.state !== undefined) {
217
- const stateMap = isChinese ? ['触发/未确认', '触发/已确认', '恢复/未确认', '恢复/已确认'] : ['Triggered/Unconfirmed', 'Triggered/Confirmed', 'Restored/Unconfirmed', 'Restored/Confirmed'];
218
- const alarmState = stateMap[alarm.state] || (isChinese ? '触发/未确认' : 'Triggered/Unconfirmed');
219
- contentParts.push(alarmState);
220
- }
221
- // 显示告警内容
222
- if (((_h = this.model.generalSetting) === null || _h === void 0 ? void 0 : _h.showAlarmContent) && alarm.message) {
223
- contentParts.push(alarm.message);
224
- }
225
- // 将所有显示字段用空格连接,确保一行显示
226
- const textContent = contentParts.join(' ');
227
- textContainer.textContent = textContent;
228
- this.allAlarmsContainer.appendChild(textContainer);
229
- // 计算文本宽度
230
- const textWidth = textContainer.offsetWidth;
231
- pageWidth += textWidth + 80; // 80是gap大小
232
- });
233
- // 移除最后一个gap
234
- if (pageWidth > 0) {
235
- pageWidth -= 80;
236
- }
237
- // 保存页宽度
238
- this.pageWidths.push(pageWidth);
239
- this.totalWidth += pageWidth;
240
- }
241
- removeOldestPage() {
242
- // 移除最旧的一页数据
243
- this.displayedItems.splice(0, this.maxResultCount);
244
- const oldPageWidth = this.pageWidths.shift() || 0;
245
- // 更新总宽度
246
- this.totalWidth -= oldPageWidth;
247
- // 从DOM中移除最旧的元素
248
- const elementsToRemove = Array.from(this.allAlarmsContainer.children).slice(0, this.maxResultCount);
249
- elementsToRemove.forEach(element => {
250
- this.allAlarmsContainer.removeChild(element);
251
- });
252
- // 调整当前left位置(保持视觉位置不变)- 这里需要等DOM更新完成后再调整
253
- requestAnimationFrame(() => {
254
- this.currentLeft += oldPageWidth;
255
- this.allAlarmsContainer.style.left = `${this.currentLeft}px`;
256
- });
257
- }
258
- resetToFirstPage() {
259
- // 重置到第一页,但保持现有数据和位置(无缝循环)
260
- this.currentPage = 1;
261
- this.hasMoreData = true;
262
- // 直接加载第一页数据,不需要清空现有内容
263
- this.getAlarmData();
264
- }
265
- scrollContent() {
266
- if (this.displayedItems.length <= 0)
267
- return;
268
- // 每次滚动的距离
269
- const scrollStep = 2; // 减小滚动步长,使滚动更平滑
270
- // 更新位置 - 从右往左滚动
271
- this.currentLeft -= scrollStep;
272
- // 检查是否需要加载下一页
273
- if (this.hasMoreData && !this.isLoadingNextPage) {
274
- const currentPosition = Math.abs(this.currentLeft);
275
- const loadedWidth = this.totalWidth - (this.pageWidths[this.pageWidths.length - 1] || 0);
276
- // 当滚动到已加载内容的60%时,加载下一页(提前预加载,确保无缝衔接)
277
- if (currentPosition > loadedWidth * 0.6) {
278
- this.getAlarmData();
279
- }
280
- }
281
- // 如果所有内容完全滚动出容器左侧,根据autoCycle决定是否重置
282
- // 添加额外的偏移量(比如100px),确保最后两个字也能完全滚出视图
283
- if (Math.abs(this.currentLeft) > this.totalWidth + 100) {
284
- if (this.autoCycle) {
285
- if (this.hasMoreData) {
286
- // 加载下一页
287
- this.getAlarmData();
288
- }
289
- else {
290
- // 重置到第一页
291
- this.resetToFirstPage();
292
- }
293
- // 计算新加载页面的宽度(如果有)
294
- const newPageWidth = this.pageWidths[this.pageWidths.length - 1] || 0;
295
- // 设置位置到新加载页面的起始位置,实现无缝衔接
296
- this.currentLeft = -(this.totalWidth - newPageWidth);
297
- this.allAlarmsContainer.style.left = `${this.currentLeft}px`;
298
- }
299
- else {
300
- // 非循环滚动:停止滚动
301
- clearInterval(this.scrollIntervalId);
302
- this.isScrolling = false;
303
- }
304
- }
305
- else {
306
- this.allAlarmsContainer.style.left = `${this.currentLeft}px`;
307
- }
308
- }
309
- initScrolling() {
310
- clearInterval(this.scrollIntervalId);
311
- // 如果没有滚动设置或自动播放为false,则不启动滚动
312
- if (this.displayedItems.length === 0) {
313
- return;
314
- }
315
- const scrollInterval = 100; // 默认100ms,滚动更流畅
316
- // 如果当前位置在容器右侧,延迟启动滚动确保内容渲染完成
317
- if (this.currentLeft > this.container.clientWidth * 0.5) {
318
- setTimeout(() => {
319
- this.isScrolling = true;
320
- this.scrollIntervalId = setInterval(() => {
321
- if (this.isScrolling) {
322
- this.scrollContent();
323
- }
324
- }, scrollInterval);
325
- }, 500);
326
- }
327
- else {
328
- this.isScrolling = true;
329
- this.scrollIntervalId = setInterval(() => {
330
- if (this.isScrolling) {
331
- this.scrollContent();
332
- }
333
- }, scrollInterval);
334
- }
335
- }
336
- pauseScroll() {
337
- this.isScrolling = false;
338
- }
339
- resumeScroll() {
340
- this.isScrolling = true;
341
- }
342
- updateQueryTimeRange() {
343
- this.endTime = moment();
344
- console.log(this.model.generalSetting, 1);
345
- switch (this.model.generalSetting.displayPeriod) {
346
- case 1:
347
- this.startTime = moment().subtract(1, 'hours');
348
- break;
349
- case 3:
350
- this.startTime = moment().subtract(7, 'days');
351
- break;
352
- case 4:
353
- this.startTime = moment().subtract(30, 'days');
354
- break;
355
- case 5:
356
- this.startTime = moment().subtract(1, 'years');
357
- break;
358
- case 6:
359
- this.startTime = moment().subtract(30, 'minutes');
360
- break;
361
- case 7:
362
- this.startTime = moment().subtract(8, 'hours');
363
- break;
364
- default:
365
- this.startTime = moment().subtract(1, 'days');
366
- }
367
- }
368
- setStatusAsNormal() {
369
- this.elementStatus = ScrollAlarmElementStatus.Normal;
370
- this.clearStatus();
371
- }
372
- setStatusAsLoading() {
373
- this.elementStatus = ScrollAlarmElementStatus.Loading;
374
- this.renderStatus('assets/img/loading.svg', '#226abc');
375
- }
376
- renderStatus(icon, stroke) {
377
- if (this.elementStatus === ScrollAlarmElementStatus.Normal) {
378
- this.clearStatus();
379
- return;
380
- }
381
- this.rootElement.append('rect').attr('id', 'StateFrame').attr('fill', 'transparent')
382
- .attr('width', this.model.size.width)
383
- .attr('height', this.model.size.height);
384
- const document = this.$element[0].ownerDocument;
385
- const currentRect = this.$element.find('rect#StateFrame').first();
386
- if (!currentRect.length) {
387
- return;
388
- }
389
- this.$element.find('image#StateImage').remove();
390
- const imgObj = document.createElementNS('http://www.w3.org/2000/svg', 'image');
391
- if (imgObj) {
392
- let x = Number(currentRect[0].getAttribute('width')) - 20;
393
- const currentRectX = currentRect[0].getAttribute('x');
394
- if (currentRectX !== null) {
395
- x += Number(currentRectX);
396
- }
397
- currentRect[0].setAttribute('stroke', stroke);
398
- currentRect[0].setAttribute('stroke-opacity', '0.5');
399
- imgObj.href.baseVal = icon;
400
- imgObj.setAttributeNS(null, 'id', 'StateImage');
401
- imgObj.setAttributeNS(null, 'x', x.toString());
402
- imgObj.setAttributeNS(null, 'y', '0');
403
- imgObj.setAttributeNS(null, 'height', '20px');
404
- imgObj.setAttributeNS(null, 'width', '20px');
405
- const titleElement = document.createElementNS('http://www.w3.org/2000/svg', 'title');
406
- imgObj.appendChild(titleElement);
407
- this.$element.append(imgObj);
408
- }
409
- }
410
- clearStatus() {
411
- const currentRect = this.$element.find('rect#StateFrame').first();
412
- if (!currentRect.length) {
413
- return;
414
- }
415
- const stroke = currentRect[0].getAttribute('stroke');
416
- if (stroke) {
417
- currentRect[0].removeAttribute('stroke');
418
- }
419
- this.$element.find('image#StateImage').remove();
420
- }
421
- }