@flexem/fc-gui 3.0.0-alpha.182 → 3.0.0-alpha.183
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 +227 -75
- package/bundles/@flexem/fc-gui.umd.js.map +1 -1
- package/bundles/@flexem/fc-gui.umd.min.js +1 -1
- package/bundles/@flexem/fc-gui.umd.min.js.map +1 -1
- package/elements/alarm/alarm-element.d.ts +22 -1
- package/elements/alarm/alarm-element.js +225 -67
- package/elements/alarm/alarm-element.metadata.json +1 -1
- package/elements/shared/text/text-element.js +1 -7
- package/modal/verify-password/verify-password-modal.component.js +1 -1
- package/modal/verify-password/verify-password-modal.component.less +1 -1
- package/modal/verify-password/verify-password-modal.component.metadata.json +1 -1
- package/package.json +1 -1
|
@@ -31,9 +31,17 @@ export declare class AlarmElement extends ConditionalDisplayElement {
|
|
|
31
31
|
private getAlarmDataId;
|
|
32
32
|
private readonly maxVisibleRows;
|
|
33
33
|
private scrollIntervalId;
|
|
34
|
-
private
|
|
34
|
+
private scrollContent;
|
|
35
|
+
private scrollWindowStart;
|
|
35
36
|
private hoverTarget;
|
|
36
37
|
private rowHeight;
|
|
38
|
+
private touchStartY;
|
|
39
|
+
private touchScrollAccumulator;
|
|
40
|
+
private scrollTrack;
|
|
41
|
+
private scrollThumb;
|
|
42
|
+
private thumbDragStartY;
|
|
43
|
+
private thumbDragStartWindow;
|
|
44
|
+
private thumbDragging;
|
|
37
45
|
private isDisposed;
|
|
38
46
|
constructor(element: HTMLElement, injector: Injector, permissionChecker: PermissionChecker, variableCommunicator: VariableCommunicator, variableStore: VariableStore, alarmsStore: AlarmsStore, signalRAppId: string, systemTextLibraryService?: SystemTextLibraryService, languageService?: LanguageService, guiContext?: GuiContext);
|
|
39
47
|
dispose(): void;
|
|
@@ -62,6 +70,8 @@ export declare class AlarmElement extends ConditionalDisplayElement {
|
|
|
62
70
|
private getAlarmData;
|
|
63
71
|
private refreshCurrentPageData;
|
|
64
72
|
private updateTableContent;
|
|
73
|
+
private renderScrollWindow;
|
|
74
|
+
private updateScrollThumb;
|
|
65
75
|
private getIconScale;
|
|
66
76
|
private renderElement;
|
|
67
77
|
private buildHeaderRow;
|
|
@@ -70,8 +80,19 @@ export declare class AlarmElement extends ConditionalDisplayElement {
|
|
|
70
80
|
private renderScrollableTable;
|
|
71
81
|
private bindScrollHoverEvents;
|
|
72
82
|
private unbindScrollHoverEvents;
|
|
83
|
+
private moveScrollWindowBy;
|
|
84
|
+
private readonly handleScrollWheel;
|
|
85
|
+
private readonly handleScrollTouchStart;
|
|
86
|
+
private readonly handleScrollTouchMove;
|
|
73
87
|
private readonly handleScrollMouseEnter;
|
|
74
88
|
private readonly handleScrollMouseLeave;
|
|
89
|
+
private bindScrollbarEvents;
|
|
90
|
+
private unbindScrollbarEvents;
|
|
91
|
+
private getClientY;
|
|
92
|
+
private readonly handleThumbDragStart;
|
|
93
|
+
private readonly handleThumbDragMove;
|
|
94
|
+
private readonly handleThumbDragEnd;
|
|
95
|
+
private readonly handleTrackClick;
|
|
75
96
|
private startAutoScroll;
|
|
76
97
|
private scrollOneRow;
|
|
77
98
|
private autoNextPage;
|
|
@@ -38,14 +38,102 @@ export class AlarmElement extends ConditionalDisplayElement {
|
|
|
38
38
|
this.totalCount = 0;
|
|
39
39
|
this.pageSize = 5;
|
|
40
40
|
this.maxVisibleRows = 15;
|
|
41
|
+
this.scrollWindowStart = 0;
|
|
41
42
|
this.rowHeight = 0;
|
|
43
|
+
this.touchStartY = 0;
|
|
44
|
+
this.touchScrollAccumulator = 0;
|
|
45
|
+
this.thumbDragStartY = 0;
|
|
46
|
+
this.thumbDragStartWindow = 0;
|
|
47
|
+
this.thumbDragging = false;
|
|
42
48
|
this.isDisposed = false;
|
|
49
|
+
this.handleScrollWheel = (event) => {
|
|
50
|
+
if (!this.rowHeight)
|
|
51
|
+
return;
|
|
52
|
+
event.preventDefault();
|
|
53
|
+
this.touchScrollAccumulator += event.deltaY;
|
|
54
|
+
const rowDelta = Math.trunc(this.touchScrollAccumulator / this.rowHeight);
|
|
55
|
+
if (rowDelta !== 0) {
|
|
56
|
+
this.touchScrollAccumulator -= rowDelta * this.rowHeight;
|
|
57
|
+
this.moveScrollWindowBy(rowDelta);
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
this.handleScrollTouchStart = (event) => {
|
|
61
|
+
this.touchStartY = event.touches[0].clientY;
|
|
62
|
+
this.touchScrollAccumulator = 0;
|
|
63
|
+
};
|
|
64
|
+
this.handleScrollTouchMove = (event) => {
|
|
65
|
+
if (!this.rowHeight)
|
|
66
|
+
return;
|
|
67
|
+
event.preventDefault();
|
|
68
|
+
const currentY = event.touches[0].clientY;
|
|
69
|
+
const deltaY = this.touchStartY - currentY;
|
|
70
|
+
this.touchStartY = currentY;
|
|
71
|
+
this.touchScrollAccumulator += deltaY;
|
|
72
|
+
const rowDelta = Math.trunc(this.touchScrollAccumulator / this.rowHeight);
|
|
73
|
+
if (rowDelta !== 0) {
|
|
74
|
+
this.touchScrollAccumulator -= rowDelta * this.rowHeight;
|
|
75
|
+
this.moveScrollWindowBy(rowDelta);
|
|
76
|
+
}
|
|
77
|
+
};
|
|
43
78
|
this.handleScrollMouseEnter = () => {
|
|
44
79
|
clearInterval(this.scrollIntervalId);
|
|
45
80
|
};
|
|
46
81
|
this.handleScrollMouseLeave = () => {
|
|
82
|
+
if (!this.thumbDragging)
|
|
83
|
+
this.startAutoScroll();
|
|
84
|
+
};
|
|
85
|
+
// 拖拽滑块时挂全局 mousemove/mouseup,允许拖出滚动条区域也能继续跟手,松开时才解绑
|
|
86
|
+
this.handleThumbDragStart = (event) => {
|
|
87
|
+
event.preventDefault();
|
|
88
|
+
event.stopPropagation();
|
|
89
|
+
this.thumbDragging = true;
|
|
90
|
+
clearInterval(this.scrollIntervalId);
|
|
91
|
+
this.thumbDragStartY = this.getClientY(event);
|
|
92
|
+
this.thumbDragStartWindow = this.scrollWindowStart;
|
|
93
|
+
document.addEventListener('mousemove', this.handleThumbDragMove);
|
|
94
|
+
document.addEventListener('mouseup', this.handleThumbDragEnd);
|
|
95
|
+
document.addEventListener('touchmove', this.handleThumbDragMove, { passive: false });
|
|
96
|
+
document.addEventListener('touchend', this.handleThumbDragEnd);
|
|
97
|
+
};
|
|
98
|
+
this.handleThumbDragMove = (event) => {
|
|
99
|
+
if (!this.thumbDragging || !this.scrollTrack)
|
|
100
|
+
return;
|
|
101
|
+
event.preventDefault();
|
|
102
|
+
const maxWindowStart = Math.max(0, this.pageSize - this.maxVisibleRows);
|
|
103
|
+
if (maxWindowStart <= 0)
|
|
104
|
+
return;
|
|
105
|
+
const trackHeight = this.scrollTrack.clientHeight;
|
|
106
|
+
const thumbHeightRatio = Math.min(1, this.maxVisibleRows / this.pageSize);
|
|
107
|
+
const thumbHeight = Math.max(20, trackHeight * thumbHeightRatio);
|
|
108
|
+
const maxThumbTop = trackHeight - thumbHeight;
|
|
109
|
+
if (maxThumbTop <= 0)
|
|
110
|
+
return;
|
|
111
|
+
const deltaY = this.getClientY(event) - this.thumbDragStartY;
|
|
112
|
+
const deltaWindow = Math.round((deltaY / maxThumbTop) * maxWindowStart);
|
|
113
|
+
const nextStart = Math.min(maxWindowStart, Math.max(0, this.thumbDragStartWindow + deltaWindow));
|
|
114
|
+
if (nextStart === this.scrollWindowStart)
|
|
115
|
+
return;
|
|
116
|
+
this.scrollWindowStart = nextStart;
|
|
117
|
+
this.renderScrollWindow(this.scrollWindowStart);
|
|
118
|
+
};
|
|
119
|
+
this.handleThumbDragEnd = () => {
|
|
120
|
+
this.thumbDragging = false;
|
|
121
|
+
document.removeEventListener('mousemove', this.handleThumbDragMove);
|
|
122
|
+
document.removeEventListener('mouseup', this.handleThumbDragEnd);
|
|
123
|
+
document.removeEventListener('touchmove', this.handleThumbDragMove);
|
|
124
|
+
document.removeEventListener('touchend', this.handleThumbDragEnd);
|
|
47
125
|
this.startAutoScroll();
|
|
48
126
|
};
|
|
127
|
+
// 点击轨道空白处(非滑块)时整页跳转,方向取决于点击位置在滑块上方还是下方
|
|
128
|
+
this.handleTrackClick = (event) => {
|
|
129
|
+
if (event.target !== this.scrollTrack || !this.scrollTrack)
|
|
130
|
+
return;
|
|
131
|
+
const trackRect = this.scrollTrack.getBoundingClientRect();
|
|
132
|
+
const clickTop = event.clientY - trackRect.top;
|
|
133
|
+
const thumbTop = parseFloat(this.scrollThumb.style.top) || 0;
|
|
134
|
+
const rowDelta = clickTop < thumbTop ? -this.maxVisibleRows : this.maxVisibleRows;
|
|
135
|
+
this.moveScrollWindowBy(rowDelta);
|
|
136
|
+
};
|
|
49
137
|
this.rootElement.selectAll('*').remove();
|
|
50
138
|
this.setStatusAsLoading();
|
|
51
139
|
this.logger = injector.get(LOGGER_SERVICE_TOKEN);
|
|
@@ -276,10 +364,8 @@ export class AlarmElement extends ConditionalDisplayElement {
|
|
|
276
364
|
}, 500);
|
|
277
365
|
}
|
|
278
366
|
refreshCurrentPageData() {
|
|
279
|
-
var _a;
|
|
280
367
|
if (this.isDisposed)
|
|
281
368
|
return;
|
|
282
|
-
const currentScrollTop = ((_a = this.scrollContainer) === null || _a === void 0 ? void 0 : _a.scrollTop) || 0;
|
|
283
369
|
if (this.model.filterSetting.alarmType) {
|
|
284
370
|
this.updateQueryTimeRange();
|
|
285
371
|
const input = new GetAlarmsArgs(this.alarmNames, this.startTime, this.endTime, this.pageSize, this.page * this.pageSize);
|
|
@@ -295,9 +381,6 @@ export class AlarmElement extends ConditionalDisplayElement {
|
|
|
295
381
|
item.triggeredTime.format('YYYY-MM-DD HH:mm:ss')
|
|
296
382
|
]);
|
|
297
383
|
this.updateTableContent();
|
|
298
|
-
if (this.scrollContainer) {
|
|
299
|
-
this.scrollContainer.scrollTop = currentScrollTop;
|
|
300
|
-
}
|
|
301
384
|
}
|
|
302
385
|
});
|
|
303
386
|
}
|
|
@@ -321,9 +404,6 @@ export class AlarmElement extends ConditionalDisplayElement {
|
|
|
321
404
|
item.triggeredTime.format('YYYY-MM-DD HH:mm:ss')
|
|
322
405
|
]);
|
|
323
406
|
this.updateTableContent();
|
|
324
|
-
if (this.scrollContainer) {
|
|
325
|
-
this.scrollContainer.scrollTop = currentScrollTop;
|
|
326
|
-
}
|
|
327
407
|
}
|
|
328
408
|
});
|
|
329
409
|
}
|
|
@@ -332,36 +412,62 @@ export class AlarmElement extends ConditionalDisplayElement {
|
|
|
332
412
|
if (!this.element)
|
|
333
413
|
return;
|
|
334
414
|
const useScroll = this.pageSize > this.maxVisibleRows;
|
|
335
|
-
const dataRowHeight = this.model.heights[1] || this.model.heights[0];
|
|
336
|
-
// 查找表格主体
|
|
337
|
-
let tbody;
|
|
338
415
|
if (useScroll) {
|
|
339
|
-
|
|
340
|
-
if (!bodyContainer)
|
|
416
|
+
if (!this.scrollContent)
|
|
341
417
|
return;
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
tbody = bodyTable;
|
|
346
|
-
}
|
|
347
|
-
else {
|
|
348
|
-
const table = this.element.querySelector('table');
|
|
349
|
-
if (!table)
|
|
350
|
-
return;
|
|
351
|
-
tbody = table;
|
|
418
|
+
this.scrollWindowStart = Math.min(this.scrollWindowStart, Math.max(0, this.pageSize - this.maxVisibleRows));
|
|
419
|
+
this.renderScrollWindow(this.scrollWindowStart);
|
|
420
|
+
return;
|
|
352
421
|
}
|
|
422
|
+
const table = this.element.querySelector('table');
|
|
423
|
+
if (!table)
|
|
424
|
+
return;
|
|
353
425
|
// 清除现有数据行(保留表头)
|
|
354
|
-
const rows = Array.from(
|
|
426
|
+
const rows = Array.from(table.querySelectorAll('tr'));
|
|
355
427
|
rows.forEach((row, index) => {
|
|
356
|
-
if (index > 0
|
|
428
|
+
if (index > 0) {
|
|
357
429
|
row.remove();
|
|
358
430
|
}
|
|
359
431
|
});
|
|
360
432
|
// 重新生成数据行
|
|
361
433
|
for (let row = 0; row < this.pageSize; row++) {
|
|
362
|
-
|
|
363
|
-
|
|
434
|
+
table.appendChild(this.buildDataRow(row, this.model.heights[row + 1]));
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
renderScrollWindow(startRow) {
|
|
438
|
+
const table = this.scrollContent;
|
|
439
|
+
if (!table)
|
|
440
|
+
return;
|
|
441
|
+
// 清除现有数据行(保留表头,即第一个 <tr>)
|
|
442
|
+
const rows = Array.from(table.querySelectorAll('tr'));
|
|
443
|
+
rows.forEach((row, index) => {
|
|
444
|
+
if (index > 0) {
|
|
445
|
+
row.remove();
|
|
446
|
+
}
|
|
447
|
+
});
|
|
448
|
+
for (let i = 0; i < this.maxVisibleRows; i++) {
|
|
449
|
+
table.appendChild(this.buildDataRow(startRow + i, this.rowHeight));
|
|
364
450
|
}
|
|
451
|
+
this.updateScrollThumb();
|
|
452
|
+
}
|
|
453
|
+
// 滑块高度按"可见行数/总行数"的比例算,位置按当前窗口起始行占可滚动范围的比例算,
|
|
454
|
+
// 只用 top/height 两个数值属性更新,不涉及 transform,不会触发合成层
|
|
455
|
+
updateScrollThumb() {
|
|
456
|
+
if (!this.scrollTrack || !this.scrollThumb)
|
|
457
|
+
return;
|
|
458
|
+
const maxWindowStart = Math.max(0, this.pageSize - this.maxVisibleRows);
|
|
459
|
+
if (maxWindowStart <= 0) {
|
|
460
|
+
this.scrollThumb.style.display = 'none';
|
|
461
|
+
return;
|
|
462
|
+
}
|
|
463
|
+
this.scrollThumb.style.display = 'block';
|
|
464
|
+
const trackHeight = this.scrollTrack.clientHeight;
|
|
465
|
+
const thumbHeightRatio = Math.min(1, this.maxVisibleRows / this.pageSize);
|
|
466
|
+
const thumbHeight = Math.max(20, trackHeight * thumbHeightRatio);
|
|
467
|
+
const maxThumbTop = trackHeight - thumbHeight;
|
|
468
|
+
const thumbTop = maxThumbTop * (this.scrollWindowStart / maxWindowStart);
|
|
469
|
+
this.scrollThumb.style.height = `${thumbHeight}px`;
|
|
470
|
+
this.scrollThumb.style.top = `${thumbTop}px`;
|
|
365
471
|
}
|
|
366
472
|
getIconScale() {
|
|
367
473
|
const initSize = this.model.initSize;
|
|
@@ -485,7 +591,8 @@ export class AlarmElement extends ConditionalDisplayElement {
|
|
|
485
591
|
return tr;
|
|
486
592
|
}
|
|
487
593
|
renderPlainTable(elementHeight, operationAreaReservedHeight) {
|
|
488
|
-
this.
|
|
594
|
+
this.scrollContent = null;
|
|
595
|
+
this.scrollWindowStart = 0;
|
|
489
596
|
const table = document.createElement('table');
|
|
490
597
|
table.style.cssText = `border: 2px solid ${this.model.generalSetting.stroke};
|
|
491
598
|
height: ${elementHeight - operationAreaReservedHeight}px;`;
|
|
@@ -501,42 +608,41 @@ export class AlarmElement extends ConditionalDisplayElement {
|
|
|
501
608
|
renderScrollableTable(elementHeight, operationAreaReservedHeight) {
|
|
502
609
|
const dataRowHeight = this.model.heights[1] || this.model.heights[0];
|
|
503
610
|
this.rowHeight = dataRowHeight;
|
|
611
|
+
this.scrollWindowStart = 0;
|
|
612
|
+
// 之前用"表头/表体分两个 table + flex 包裹容器 + overflow/transform 滚动"的结构,
|
|
613
|
+
// 在 iOS WKWebView 上表体会明显放大错位,换了两种滚动实现方式(原生 overflow:auto、
|
|
614
|
+
// JS transform 平移)都复现同样的问题,怀疑是这套多层 div + 双 table 结构本身的问题。
|
|
615
|
+
// 这里改成和 renderPlainTable() 完全同构的单 table 结构(已验证在所有平台上都正常),
|
|
616
|
+
// DOM 里始终只保留 maxVisibleRows 行数据,滚动时只增删 <tr> 内容,不做任何位移/滚动。
|
|
617
|
+
// 自定义滚动条(轨道+滑块)只用 position + top/height 定位,不用 overflow/transform/
|
|
618
|
+
// will-change,这些属性都不会触发 WebKit 合成层提升,不会重新引入 iOS 缩放错位问题。
|
|
619
|
+
const scrollbarWidth = 6;
|
|
504
620
|
const wrapper = document.createElement('div');
|
|
505
|
-
wrapper.style.cssText = `
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
621
|
+
wrapper.style.cssText = `position: relative; width: ${this.model.size.width}px;
|
|
622
|
+
height: ${elementHeight - operationAreaReservedHeight}px;`;
|
|
623
|
+
const table = document.createElement('table');
|
|
624
|
+
table.style.cssText = `border: 2px solid ${this.model.generalSetting.stroke};
|
|
509
625
|
height: ${elementHeight - operationAreaReservedHeight}px;
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
const
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
height: ${dataRowHeight * this.maxVisibleRows}px;`;
|
|
522
|
-
const bodyTable = document.createElement('table');
|
|
523
|
-
bodyTable.style.cssText = 'width: 100%; table-layout: fixed;';
|
|
524
|
-
for (let row = 0; row < this.pageSize; row++) {
|
|
525
|
-
bodyTable.appendChild(this.buildDataRow(row, dataRowHeight));
|
|
526
|
-
}
|
|
527
|
-
bodyContainer.appendChild(bodyTable);
|
|
528
|
-
wrapper.appendChild(headerWrapper);
|
|
529
|
-
wrapper.appendChild(bodyContainer);
|
|
626
|
+
width: calc(100% - ${scrollbarWidth}px);`;
|
|
627
|
+
table.appendChild(this.buildHeaderRow());
|
|
628
|
+
wrapper.appendChild(table);
|
|
629
|
+
const track = document.createElement('div');
|
|
630
|
+
track.style.cssText = `position: absolute; top: 0; right: 0; width: ${scrollbarWidth}px;
|
|
631
|
+
height: 100%; background: rgba(0,0,0,0.06); border-radius: ${scrollbarWidth / 2}px;`;
|
|
632
|
+
const thumb = document.createElement('div');
|
|
633
|
+
thumb.style.cssText = `position: absolute; left: 0; width: 100%;
|
|
634
|
+
background: rgba(0,0,0,0.35); border-radius: ${scrollbarWidth / 2}px; cursor: pointer;`;
|
|
635
|
+
track.appendChild(thumb);
|
|
636
|
+
wrapper.appendChild(track);
|
|
530
637
|
this.element.appendChild(wrapper);
|
|
531
|
-
this.
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
});
|
|
538
|
-
this.hoverTarget = bodyContainer;
|
|
638
|
+
this.scrollContent = table;
|
|
639
|
+
this.scrollTrack = track;
|
|
640
|
+
this.scrollThumb = thumb;
|
|
641
|
+
this.renderScrollWindow(0);
|
|
642
|
+
this.updateScrollThumb();
|
|
643
|
+
this.hoverTarget = table;
|
|
539
644
|
this.bindScrollHoverEvents();
|
|
645
|
+
this.bindScrollbarEvents();
|
|
540
646
|
this.startAutoScroll();
|
|
541
647
|
}
|
|
542
648
|
bindScrollHoverEvents() {
|
|
@@ -544,41 +650,93 @@ export class AlarmElement extends ConditionalDisplayElement {
|
|
|
544
650
|
return;
|
|
545
651
|
this.hoverTarget.addEventListener('mouseenter', this.handleScrollMouseEnter);
|
|
546
652
|
this.hoverTarget.addEventListener('mouseleave', this.handleScrollMouseLeave);
|
|
653
|
+
if (this.scrollContent) {
|
|
654
|
+
this.hoverTarget.addEventListener('wheel', this.handleScrollWheel, { passive: false });
|
|
655
|
+
this.hoverTarget.addEventListener('touchstart', this.handleScrollTouchStart, { passive: true });
|
|
656
|
+
this.hoverTarget.addEventListener('touchmove', this.handleScrollTouchMove, { passive: false });
|
|
657
|
+
}
|
|
547
658
|
}
|
|
548
659
|
unbindScrollHoverEvents() {
|
|
660
|
+
this.unbindScrollbarEvents();
|
|
549
661
|
if (!this.hoverTarget)
|
|
550
662
|
return;
|
|
551
663
|
this.hoverTarget.removeEventListener('mouseenter', this.handleScrollMouseEnter);
|
|
552
664
|
this.hoverTarget.removeEventListener('mouseleave', this.handleScrollMouseLeave);
|
|
665
|
+
this.hoverTarget.removeEventListener('wheel', this.handleScrollWheel);
|
|
666
|
+
this.hoverTarget.removeEventListener('touchstart', this.handleScrollTouchStart);
|
|
667
|
+
this.hoverTarget.removeEventListener('touchmove', this.handleScrollTouchMove);
|
|
553
668
|
this.hoverTarget = null;
|
|
554
669
|
}
|
|
670
|
+
// 手动滚动只在当前可见窗口范围内移动(不触发翻页),到顶/到底停住,
|
|
671
|
+
// 和自动滚动定时器(会在到底后自动翻页)职责区分开
|
|
672
|
+
moveScrollWindowBy(rowDelta) {
|
|
673
|
+
if (!this.scrollContent)
|
|
674
|
+
return;
|
|
675
|
+
const maxWindowStart = Math.max(0, this.pageSize - this.maxVisibleRows);
|
|
676
|
+
const nextStart = Math.min(maxWindowStart, Math.max(0, this.scrollWindowStart + rowDelta));
|
|
677
|
+
if (nextStart === this.scrollWindowStart)
|
|
678
|
+
return;
|
|
679
|
+
this.scrollWindowStart = nextStart;
|
|
680
|
+
this.renderScrollWindow(this.scrollWindowStart);
|
|
681
|
+
}
|
|
682
|
+
bindScrollbarEvents() {
|
|
683
|
+
if (!this.scrollTrack || !this.scrollThumb)
|
|
684
|
+
return;
|
|
685
|
+
this.scrollThumb.addEventListener('mousedown', this.handleThumbDragStart);
|
|
686
|
+
this.scrollThumb.addEventListener('touchstart', this.handleThumbDragStart, { passive: true });
|
|
687
|
+
this.scrollTrack.addEventListener('mousedown', this.handleTrackClick);
|
|
688
|
+
}
|
|
689
|
+
unbindScrollbarEvents() {
|
|
690
|
+
if (this.scrollThumb) {
|
|
691
|
+
this.scrollThumb.removeEventListener('mousedown', this.handleThumbDragStart);
|
|
692
|
+
this.scrollThumb.removeEventListener('touchstart', this.handleThumbDragStart);
|
|
693
|
+
}
|
|
694
|
+
if (this.scrollTrack) {
|
|
695
|
+
this.scrollTrack.removeEventListener('mousedown', this.handleTrackClick);
|
|
696
|
+
}
|
|
697
|
+
document.removeEventListener('mousemove', this.handleThumbDragMove);
|
|
698
|
+
document.removeEventListener('mouseup', this.handleThumbDragEnd);
|
|
699
|
+
document.removeEventListener('touchmove', this.handleThumbDragMove);
|
|
700
|
+
document.removeEventListener('touchend', this.handleThumbDragEnd);
|
|
701
|
+
this.scrollTrack = null;
|
|
702
|
+
this.scrollThumb = null;
|
|
703
|
+
}
|
|
704
|
+
getClientY(event) {
|
|
705
|
+
return 'touches' in event ? event.touches[0].clientY : event.clientY;
|
|
706
|
+
}
|
|
555
707
|
startAutoScroll() {
|
|
556
708
|
clearInterval(this.scrollIntervalId);
|
|
557
709
|
if (!this.model.generalSetting.autoScroll)
|
|
558
710
|
return;
|
|
559
711
|
const totalPages = Math.max(1, Math.ceil(this.totalCount / this.pageSize));
|
|
560
|
-
if (totalPages <= 1 && !this.
|
|
712
|
+
if (totalPages <= 1 && !this.scrollContent)
|
|
561
713
|
return;
|
|
562
714
|
const duration = (this.model.generalSetting.scrollDuration || 10) * 1000;
|
|
563
715
|
this.scrollIntervalId = setInterval(() => this.scrollOneRow(), duration);
|
|
564
716
|
}
|
|
565
717
|
scrollOneRow() {
|
|
566
|
-
|
|
567
|
-
if (!el) {
|
|
718
|
+
if (!this.scrollContent) {
|
|
568
719
|
this.autoNextPage();
|
|
569
720
|
return;
|
|
570
721
|
}
|
|
571
|
-
const
|
|
572
|
-
if (
|
|
722
|
+
const maxWindowStart = this.pageSize - this.maxVisibleRows;
|
|
723
|
+
if (maxWindowStart <= 0 || this.scrollWindowStart >= maxWindowStart) {
|
|
573
724
|
this.autoNextPage();
|
|
574
725
|
return;
|
|
575
726
|
}
|
|
576
|
-
|
|
727
|
+
this.scrollWindowStart += 1;
|
|
728
|
+
this.renderScrollWindow(this.scrollWindowStart);
|
|
577
729
|
}
|
|
578
730
|
autoNextPage() {
|
|
579
731
|
const totalPages = Math.max(1, Math.ceil(this.totalCount / this.pageSize));
|
|
580
|
-
if (totalPages <= 1)
|
|
732
|
+
if (totalPages <= 1) {
|
|
733
|
+
// 只有一页数据:没有下一页可翻,循环回本页顶部继续滚动
|
|
734
|
+
if (this.scrollContent) {
|
|
735
|
+
this.scrollWindowStart = 0;
|
|
736
|
+
this.renderScrollWindow(0);
|
|
737
|
+
}
|
|
581
738
|
return;
|
|
739
|
+
}
|
|
582
740
|
const lastPage = totalPages - 1;
|
|
583
741
|
this.page = this.page < lastPage ? this.page + 1 : 0;
|
|
584
742
|
this.getAlarmData();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
[{"__symbolic":"module","version":4,"metadata":{"AlarmElement":{"__symbolic":"class","extends":{"__symbolic":"reference","module":"../base/conditional-display-element","name":"ConditionalDisplayElement","line":21,"character":34},"members":{"__ctor__":[{"__symbolic":"constructor","parameters":[{"__symbolic":"error","message":"Could not resolve type","line":
|
|
1
|
+
[{"__symbolic":"module","version":4,"metadata":{"AlarmElement":{"__symbolic":"class","extends":{"__symbolic":"reference","module":"../base/conditional-display-element","name":"ConditionalDisplayElement","line":21,"character":34},"members":{"__ctor__":[{"__symbolic":"constructor","parameters":[{"__symbolic":"error","message":"Could not resolve type","line":69,"character":25,"context":{"typeName":"HTMLElement"}},{"__symbolic":"reference","module":"@angular/core","name":"Injector","line":70,"character":18},{"__symbolic":"reference","module":"../../service","name":"PermissionChecker","line":71,"character":27},{"__symbolic":"reference","module":"../../communication","name":"VariableCommunicator","line":72,"character":30},{"__symbolic":"reference","module":"../../config","name":"VariableStore","line":73,"character":23},{"__symbolic":"reference","module":"../../config","name":"AlarmsStore","line":74,"character":38},{"__symbolic":"reference","name":"string"},{"__symbolic":"reference","module":"../../service","name":"SystemTextLibraryService","line":76,"character":52},{"__symbolic":"reference","module":"../../service","name":"LanguageService","line":77,"character":43},{"__symbolic":"reference","module":"../../gui/gui-context","name":"GuiContext","line":78,"character":38}]}],"dispose":[{"__symbolic":"method"}],"subscribeLanguageChange":[{"__symbolic":"method"}],"updateLanguageTexts":[{"__symbolic":"method"}],"getCurrentCulture":[{"__symbolic":"method"}],"getHeaderTextByColumn":[{"__symbolic":"method"}],"getValidTimePeriods":[{"__symbolic":"method"}],"getTimePeriodText":[{"__symbolic":"method"}],"getAlarmData":[{"__symbolic":"method"}],"refreshCurrentPageData":[{"__symbolic":"method"}],"updateTableContent":[{"__symbolic":"method"}],"renderScrollWindow":[{"__symbolic":"method"}],"updateScrollThumb":[{"__symbolic":"method"}],"getIconScale":[{"__symbolic":"method"}],"renderElement":[{"__symbolic":"method"}],"buildHeaderRow":[{"__symbolic":"method"}],"buildDataRow":[{"__symbolic":"method"}],"renderPlainTable":[{"__symbolic":"method"}],"renderScrollableTable":[{"__symbolic":"method"}],"bindScrollHoverEvents":[{"__symbolic":"method"}],"unbindScrollHoverEvents":[{"__symbolic":"method"}],"moveScrollWindowBy":[{"__symbolic":"method"}],"bindScrollbarEvents":[{"__symbolic":"method"}],"unbindScrollbarEvents":[{"__symbolic":"method"}],"getClientY":[{"__symbolic":"method"}],"startAutoScroll":[{"__symbolic":"method"}],"scrollOneRow":[{"__symbolic":"method"}],"autoNextPage":[{"__symbolic":"method"}],"renderOperationArea":[{"__symbolic":"method"}],"updateTimeRange":[{"__symbolic":"method"}],"updateQueryTimeRange":[{"__symbolic":"method"}],"loadFirstPage":[{"__symbolic":"method"}],"loadNextPage":[{"__symbolic":"method"}],"loadPreviousPage":[{"__symbolic":"method"}],"loadLastPage":[{"__symbolic":"method"}],"setStatusAsNormal":[{"__symbolic":"method"}],"setStatusAsLoading":[{"__symbolic":"method"}],"renderStatus":[{"__symbolic":"method"}],"clearStatus":[{"__symbolic":"method"}]}}}}]
|
|
@@ -6,9 +6,6 @@ export class TextElementModal {
|
|
|
6
6
|
this.width = width;
|
|
7
7
|
this.height = height;
|
|
8
8
|
this.isVariableText = isVariableText;
|
|
9
|
-
if (/iPhone|iPod/i.test(navigator.userAgent)) {
|
|
10
|
-
width += 10;
|
|
11
|
-
}
|
|
12
9
|
this._element = this.getforeignObjectElement(width, height);
|
|
13
10
|
this._element.innerHTML = '';
|
|
14
11
|
const text = this.createNewForeignObjectText(content, font, width, height, isVariableText);
|
|
@@ -32,10 +29,7 @@ export class TextElementModal {
|
|
|
32
29
|
// 清空现有内容
|
|
33
30
|
this._element.innerHTML = '';
|
|
34
31
|
// 创建新的文本元素
|
|
35
|
-
|
|
36
|
-
if (/iPhone|iPod/i.test(navigator.userAgent)) {
|
|
37
|
-
width += 10;
|
|
38
|
-
}
|
|
32
|
+
const width = this.width;
|
|
39
33
|
const text = this.createNewForeignObjectText(content, this.font, width, this.height, this.isVariableText);
|
|
40
34
|
this._element.appendChild(text);
|
|
41
35
|
}
|
|
@@ -64,7 +64,7 @@ VerifyPasswordModalComponent = __decorate([
|
|
|
64
64
|
Component({
|
|
65
65
|
selector: 'verify-password',
|
|
66
66
|
template: "<form #verifyPasswordForm=\"ngForm\" novalidate (ngSubmit)=\"checkSecurity()\" bs-modal-drag> <div class=\"modal-header\"> <h4 class=\"modal-title\"> <span>{{localization.passwordVerify}}</span> </h4> <button type=\"button\" class=\"close pull-right\" aria-label=\"Close\" (click)=\"close()\"> <span aria-hidden=\"true\">×</span> </button> </div> <div class=\"modal-body\"> <span class=\"password-span\">{{localization.password}}: </span> <input type=\"password\" name=\"password\" autoFocus [class.verify-password-input]=\"!isMobileMode\" class=\"form-control element-password\" [(ngModel)]=\"password\" (keyup)=\"validate()\" autocomplete=\"off\"> <span class=\"help-block text-danger\" [hidden]=\"!passwordError\">{{validationErrorText}}</span> </div> <div class=\"modal-footer\" [class.verify-password-footer]=\"!isMobileMode\"> <button type=\"button\" class=\"btn md-skip btn-cancel\" (click)=\"close()\">{{localization.cancel}} </button> <button type=\"submit\" class=\"btn md-skip btn-primary\" [disabled]=\"passwordError\">{{localization.submit}}</button> </div> </form> ",
|
|
67
|
-
styles: [".modal-header { padding: 10px; border-color: transparent; } .modal-body { position: relative; padding: 0px 5px !important; padding-top: 10px !important; } .modal-title { display: unset; margin-left: -6px; font-size: 16px !important; } .form-control { margin: 0 5%; float: none; width: 90%; } .modal-footer { padding: 10px 4px 20px 5px !important; text-align: right; border-color: transparent; color: #fff; } .text-danger { display: block; color: #ed6b75; font-size: 14px; margin: 5px 0px 0px 15px; } .btn-primary { color: #fff; height: 32px; min-width: 71px; margin-right: 10px; line-height: 0px } .password-span { color: #7f939e; font-size: 14px; margin-left: 15px; } .btn-cancel { color: #fff; height: 32px; min-width: 71px; margin-right: 6px; background-color: #dddddd; line-height: 0px } .element-password { padding-left: 8px; height: 32px; min-width: 71px; margin-left: 16px; } .verify-password-input { width: 600px; } .verify-password-footer { padding-right: 18px !important; }"]
|
|
67
|
+
styles: [".modal-header { padding: 10px; border-color: transparent; } .modal-body { position: relative; padding: 0px 5px !important; padding-top: 10px !important; } .modal-title { display: unset; margin-left: -6px; font-size: 16px !important; } .form-control { margin: 0 5%; float: none; width: 90%; } .modal-footer { padding: 10px 4px 20px 5px !important; text-align: right; border-color: transparent; color: #fff; } .text-danger { display: block; color: #ed6b75; font-size: 14px; margin: 5px 0px 0px 15px; } .btn-primary { color: #fff; height: 32px; min-width: 71px; margin-right: 10px; line-height: 0px } .password-span { color: #7f939e; font-size: 14px; margin-left: 15px; } .btn-cancel { color: #fff; height: 32px; min-width: 71px; margin-right: 6px; background-color: #dddddd; line-height: 0px } .element-password { padding-left: 8px; height: 32px; min-width: 71px; margin-left: 16px; } .verify-password-input { width: 600px; } .verify-password-footer { padding-right: 18px !important; } "]
|
|
68
68
|
}),
|
|
69
69
|
__param(0, Inject(LOCALIZATION)),
|
|
70
70
|
__metadata("design:paramtypes", [Object, Injector])
|
|
@@ -1 +1 @@
|
|
|
1
|
-
[{"__symbolic":"module","version":4,"metadata":{"VerifyPasswordModalComponent":{"__symbolic":"class","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"Component","line":9,"character":1},"arguments":[{"selector":"verify-password","template":"<form #verifyPasswordForm=\"ngForm\" novalidate (ngSubmit)=\"checkSecurity()\" bs-modal-drag> <div class=\"modal-header\"> <h4 class=\"modal-title\"> <span>{{localization.passwordVerify}}</span> </h4> <button type=\"button\" class=\"close pull-right\" aria-label=\"Close\" (click)=\"close()\"> <span aria-hidden=\"true\">×</span> </button> </div> <div class=\"modal-body\"> <span class=\"password-span\">{{localization.password}}: </span> <input type=\"password\" name=\"password\" autoFocus [class.verify-password-input]=\"!isMobileMode\" class=\"form-control element-password\" [(ngModel)]=\"password\" (keyup)=\"validate()\" autocomplete=\"off\"> <span class=\"help-block text-danger\" [hidden]=\"!passwordError\">{{validationErrorText}}</span> </div> <div class=\"modal-footer\" [class.verify-password-footer]=\"!isMobileMode\"> <button type=\"button\" class=\"btn md-skip btn-cancel\" (click)=\"close()\">{{localization.cancel}} </button> <button type=\"submit\" class=\"btn md-skip btn-primary\" [disabled]=\"passwordError\">{{localization.submit}}</button> </div> </form> ","styles":[".modal-header { padding: 10px; border-color: transparent; } .modal-body { position: relative; padding: 0px 5px !important; padding-top: 10px !important; } .modal-title { display: unset; margin-left: -6px; font-size: 16px !important; } .form-control { margin: 0 5%; float: none; width: 90%; } .modal-footer { padding: 10px 4px 20px 5px !important; text-align: right; border-color: transparent; color: #fff; } .text-danger { display: block; color: #ed6b75; font-size: 14px; margin: 5px 0px 0px 15px; } .btn-primary { color: #fff; height: 32px; min-width: 71px; margin-right: 10px; line-height: 0px } .password-span { color: #7f939e; font-size: 14px; margin-left: 15px; } .btn-cancel { color: #fff; height: 32px; min-width: 71px; margin-right: 6px; background-color: #dddddd; line-height: 0px } .element-password { padding-left: 8px; height: 32px; min-width: 71px; margin-left: 16px; } .verify-password-input { width: 600px; } .verify-password-footer { padding-right: 18px !important; }"]}]}],"members":{"__ctor__":[{"__symbolic":"constructor","parameterDecorators":[[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"Inject","line":29,"character":17},"arguments":[{"__symbolic":"reference","module":"../../localization","name":"LOCALIZATION","line":29,"character":24}]}],null],"parameters":[{"__symbolic":"reference","module":"../../localization","name":"Localization","line":29,"character":59},{"__symbolic":"reference","module":"@angular/core","name":"Injector","line":29,"character":83}]}],"ngOnInit":[{"__symbolic":"method"}],"validate":[{"__symbolic":"method"}],"checkSecurity":[{"__symbolic":"method"}],"close":[{"__symbolic":"method"}]}}}}]
|
|
1
|
+
[{"__symbolic":"module","version":4,"metadata":{"VerifyPasswordModalComponent":{"__symbolic":"class","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"Component","line":9,"character":1},"arguments":[{"selector":"verify-password","template":"<form #verifyPasswordForm=\"ngForm\" novalidate (ngSubmit)=\"checkSecurity()\" bs-modal-drag> <div class=\"modal-header\"> <h4 class=\"modal-title\"> <span>{{localization.passwordVerify}}</span> </h4> <button type=\"button\" class=\"close pull-right\" aria-label=\"Close\" (click)=\"close()\"> <span aria-hidden=\"true\">×</span> </button> </div> <div class=\"modal-body\"> <span class=\"password-span\">{{localization.password}}: </span> <input type=\"password\" name=\"password\" autoFocus [class.verify-password-input]=\"!isMobileMode\" class=\"form-control element-password\" [(ngModel)]=\"password\" (keyup)=\"validate()\" autocomplete=\"off\"> <span class=\"help-block text-danger\" [hidden]=\"!passwordError\">{{validationErrorText}}</span> </div> <div class=\"modal-footer\" [class.verify-password-footer]=\"!isMobileMode\"> <button type=\"button\" class=\"btn md-skip btn-cancel\" (click)=\"close()\">{{localization.cancel}} </button> <button type=\"submit\" class=\"btn md-skip btn-primary\" [disabled]=\"passwordError\">{{localization.submit}}</button> </div> </form> ","styles":[".modal-header { padding: 10px; border-color: transparent; } .modal-body { position: relative; padding: 0px 5px !important; padding-top: 10px !important; } .modal-title { display: unset; margin-left: -6px; font-size: 16px !important; } .form-control { margin: 0 5%; float: none; width: 90%; } .modal-footer { padding: 10px 4px 20px 5px !important; text-align: right; border-color: transparent; color: #fff; } .text-danger { display: block; color: #ed6b75; font-size: 14px; margin: 5px 0px 0px 15px; } .btn-primary { color: #fff; height: 32px; min-width: 71px; margin-right: 10px; line-height: 0px } .password-span { color: #7f939e; font-size: 14px; margin-left: 15px; } .btn-cancel { color: #fff; height: 32px; min-width: 71px; margin-right: 6px; background-color: #dddddd; line-height: 0px } .element-password { padding-left: 8px; height: 32px; min-width: 71px; margin-left: 16px; } .verify-password-input { width: 600px; } .verify-password-footer { padding-right: 18px !important; } "]}]}],"members":{"__ctor__":[{"__symbolic":"constructor","parameterDecorators":[[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"Inject","line":29,"character":17},"arguments":[{"__symbolic":"reference","module":"../../localization","name":"LOCALIZATION","line":29,"character":24}]}],null],"parameters":[{"__symbolic":"reference","module":"../../localization","name":"Localization","line":29,"character":59},{"__symbolic":"reference","module":"@angular/core","name":"Injector","line":29,"character":83}]}],"ngOnInit":[{"__symbolic":"method"}],"validate":[{"__symbolic":"method"}],"checkSecurity":[{"__symbolic":"method"}],"close":[{"__symbolic":"method"}]}}}}]
|