@flexem/fc-gui 3.0.0-alpha.144 → 3.0.0-alpha.146
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 +190 -248
- 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/elements/scroll-alarm/scroll-alarm-element.d.ts +5 -4
- package/elements/scroll-alarm/scroll-alarm-element.js +174 -240
- package/elements/scroll-alarm/scroll-alarm-element.metadata.json +1 -1
- package/elements/shared/text/text-state-element.js +15 -7
- package/package.json +1 -1
|
@@ -47,18 +47,6 @@ export class ScrollAlarmElement extends ConditionalDynamicDisplayElement {
|
|
|
47
47
|
this.initDisplayContainer();
|
|
48
48
|
// 获取字体设置
|
|
49
49
|
this.headerFont = ((_e = this.model.generalSetting) === null || _e === void 0 ? void 0 : _e.headerFont) || {};
|
|
50
|
-
// 构建符合 CSS font 属性规范的字符串
|
|
51
|
-
let fontString = '';
|
|
52
|
-
if (this.headerFont.isItalic) {
|
|
53
|
-
fontString += 'italic ';
|
|
54
|
-
}
|
|
55
|
-
if (this.headerFont.isBold) {
|
|
56
|
-
fontString += 'bold ';
|
|
57
|
-
}
|
|
58
|
-
const fontSize = this.headerFont.fontSize || '16px';
|
|
59
|
-
const lineHeight = parseInt(fontSize, 10) + 5;
|
|
60
|
-
fontString += `${fontSize}/${lineHeight}px ${this.headerFont.fontFamily || 'Microsoft YaHei'}`;
|
|
61
|
-
this.fontString = fontString;
|
|
62
50
|
// 使用静态显示逻辑:只显示字段标签
|
|
63
51
|
this.renderStaticDisplay();
|
|
64
52
|
this.setStatusAsNormal();
|
|
@@ -91,19 +79,6 @@ export class ScrollAlarmElement extends ConditionalDynamicDisplayElement {
|
|
|
91
79
|
this.initDisplayContainer();
|
|
92
80
|
// 获取字体设置 - 参考 text-element.ts 的实现方式
|
|
93
81
|
this.headerFont = ((_f = this.model.generalSetting) === null || _f === void 0 ? void 0 : _f.headerFont) || {};
|
|
94
|
-
// 构建符合 CSS font 属性规范的字符串
|
|
95
|
-
// 格式:font-style font-weight font-size/line-height font-family
|
|
96
|
-
let fontString = '';
|
|
97
|
-
if (this.headerFont.isItalic) {
|
|
98
|
-
fontString += 'italic ';
|
|
99
|
-
}
|
|
100
|
-
if (this.headerFont.isBold) {
|
|
101
|
-
fontString += 'bold ';
|
|
102
|
-
}
|
|
103
|
-
const fontSize = this.headerFont.fontSize || '16px';
|
|
104
|
-
const lineHeight = parseInt(fontSize, 10) + 5;
|
|
105
|
-
fontString += `${fontSize}/${lineHeight}px ${this.headerFont.fontFamily || 'Microsoft YaHei'}`;
|
|
106
|
-
this.fontString = fontString;
|
|
107
82
|
this.getAlarmData();
|
|
108
83
|
}
|
|
109
84
|
}
|
|
@@ -113,7 +88,9 @@ export class ScrollAlarmElement extends ConditionalDynamicDisplayElement {
|
|
|
113
88
|
// 初始化显示容器以显示空内容
|
|
114
89
|
this.initDisplayContainer();
|
|
115
90
|
if (this.allAlarmsContainer) {
|
|
116
|
-
this.allAlarmsContainer.
|
|
91
|
+
while (this.allAlarmsContainer.firstChild) {
|
|
92
|
+
this.allAlarmsContainer.removeChild(this.allAlarmsContainer.firstChild);
|
|
93
|
+
}
|
|
117
94
|
this.totalWidth = 0;
|
|
118
95
|
this.pageWidths = [];
|
|
119
96
|
}
|
|
@@ -191,8 +168,8 @@ export class ScrollAlarmElement extends ConditionalDynamicDisplayElement {
|
|
|
191
168
|
const oldPageWidth = this.pageWidths.pop() || 0;
|
|
192
169
|
this.totalWidth -= oldPageWidth;
|
|
193
170
|
const elementsToRemove = Array.from(this.allAlarmsContainer.children).slice(startIndex, startIndex + itemsPerPage);
|
|
194
|
-
elementsToRemove.forEach(
|
|
195
|
-
this.allAlarmsContainer.removeChild(
|
|
171
|
+
elementsToRemove.forEach(el => {
|
|
172
|
+
this.allAlarmsContainer.removeChild(el);
|
|
196
173
|
});
|
|
197
174
|
// 插入新的当前页数据
|
|
198
175
|
this.displayedItems.splice(startIndex, 0, ...newPage);
|
|
@@ -232,7 +209,9 @@ export class ScrollAlarmElement extends ConditionalDynamicDisplayElement {
|
|
|
232
209
|
// 清空显示
|
|
233
210
|
this.displayedItems = [];
|
|
234
211
|
if (this.allAlarmsContainer) {
|
|
235
|
-
this.allAlarmsContainer.
|
|
212
|
+
while (this.allAlarmsContainer.firstChild) {
|
|
213
|
+
this.allAlarmsContainer.removeChild(this.allAlarmsContainer.firstChild);
|
|
214
|
+
}
|
|
236
215
|
this.totalWidth = 0;
|
|
237
216
|
this.pageWidths = [];
|
|
238
217
|
}
|
|
@@ -259,121 +238,153 @@ export class ScrollAlarmElement extends ConditionalDynamicDisplayElement {
|
|
|
259
238
|
var _a;
|
|
260
239
|
const elementHeight = this.model.size.height;
|
|
261
240
|
const elementWidth = this.model.size.width;
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
this.
|
|
266
|
-
this
|
|
267
|
-
|
|
268
|
-
this.
|
|
269
|
-
this.
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
this.
|
|
292
|
-
|
|
241
|
+
const bgColor = ((_a = this.model.generalSetting) === null || _a === void 0 ? void 0 : _a.headerFillColor) || '#ffffff';
|
|
242
|
+
const clipId = 'scroll-alarm-clip-' + Math.random().toString(36).slice(2);
|
|
243
|
+
// 背景矩形
|
|
244
|
+
this.bgRect = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
|
|
245
|
+
this.bgRect.setAttribute('x', '0');
|
|
246
|
+
this.bgRect.setAttribute('y', '0');
|
|
247
|
+
this.bgRect.setAttribute('width', elementWidth.toString());
|
|
248
|
+
this.bgRect.setAttribute('height', elementHeight.toString());
|
|
249
|
+
this.bgRect.setAttribute('fill', bgColor);
|
|
250
|
+
this.bgRect.setAttribute('stroke', '#8ea0aa');
|
|
251
|
+
this.bgRect.setAttribute('stroke-width', '1');
|
|
252
|
+
this.$element[0].appendChild(this.bgRect);
|
|
253
|
+
// clipPath 限制文字滚动区域
|
|
254
|
+
const defs = document.createElementNS('http://www.w3.org/2000/svg', 'defs');
|
|
255
|
+
const clipPath = document.createElementNS('http://www.w3.org/2000/svg', 'clipPath');
|
|
256
|
+
clipPath.setAttribute('id', clipId);
|
|
257
|
+
const clipRect = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
|
|
258
|
+
clipRect.setAttribute('x', '2');
|
|
259
|
+
clipRect.setAttribute('y', '0');
|
|
260
|
+
clipRect.setAttribute('width', (elementWidth - 4).toString());
|
|
261
|
+
clipRect.setAttribute('height', elementHeight.toString());
|
|
262
|
+
clipPath.appendChild(clipRect);
|
|
263
|
+
defs.appendChild(clipPath);
|
|
264
|
+
this.$element[0].appendChild(defs);
|
|
265
|
+
// 滚动内容的 g 容器,套上 clipPath
|
|
266
|
+
this.scrollGroup = document.createElementNS('http://www.w3.org/2000/svg', 'g');
|
|
267
|
+
this.scrollGroup.setAttribute('clip-path', `url(#${clipId})`);
|
|
268
|
+
this.$element[0].appendChild(this.scrollGroup);
|
|
269
|
+
// 内部 g 用于整体平移(滚动动画改这个的 transform)
|
|
270
|
+
this.allAlarmsContainer = document.createElementNS('http://www.w3.org/2000/svg', 'g');
|
|
271
|
+
this.scrollGroup.appendChild(this.allAlarmsContainer);
|
|
272
|
+
// 初始位置在右侧屏幕外
|
|
293
273
|
this.currentLeft = elementWidth;
|
|
294
|
-
this.allAlarmsContainer.
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
274
|
+
this.allAlarmsContainer.setAttribute('transform', `translate(${elementWidth}, 0)`);
|
|
275
|
+
}
|
|
276
|
+
_buildFontAttrs() {
|
|
277
|
+
const f = this.headerFont || {};
|
|
278
|
+
const fontSize = parseInt((f.fontSize || '16px'), 10);
|
|
279
|
+
return {
|
|
280
|
+
fontSize,
|
|
281
|
+
fontFamily: f.fontFamily || 'Microsoft YaHei',
|
|
282
|
+
color: f.color || '#e33c39',
|
|
283
|
+
isBold: !!f.isBold,
|
|
284
|
+
isItalic: !!f.isItalic,
|
|
285
|
+
isUnderline: !!f.isUnderline
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
_createSvgTextNode(textContent) {
|
|
289
|
+
const elementHeight = this.model.size.height;
|
|
290
|
+
const fa = this._buildFontAttrs();
|
|
291
|
+
const text = document.createElementNS('http://www.w3.org/2000/svg', 'text');
|
|
292
|
+
text.setAttribute('y', (elementHeight / 2).toString());
|
|
293
|
+
text.setAttribute('dominant-baseline', 'central');
|
|
294
|
+
text.setAttribute('fill', fa.color);
|
|
295
|
+
text.setAttribute('font-size', fa.fontSize.toString());
|
|
296
|
+
text.setAttribute('font-family', fa.fontFamily);
|
|
297
|
+
if (fa.isBold) {
|
|
298
|
+
text.setAttribute('font-weight', 'bold');
|
|
299
|
+
}
|
|
300
|
+
if (fa.isItalic) {
|
|
301
|
+
text.setAttribute('font-style', 'italic');
|
|
302
|
+
}
|
|
303
|
+
if (fa.isUnderline) {
|
|
304
|
+
text.setAttribute('text-decoration', 'underline');
|
|
305
|
+
}
|
|
306
|
+
text.textContent = textContent;
|
|
307
|
+
return text;
|
|
298
308
|
}
|
|
299
309
|
renderNewPage(pageData) {
|
|
310
|
+
const GAP = 80;
|
|
300
311
|
let pageWidth = 0;
|
|
301
|
-
//
|
|
312
|
+
// 新页的起始 x = 已有总宽度 + gap(如果已有内容)
|
|
313
|
+
let xOffset = this.totalWidth > 0 ? this.totalWidth + GAP : 0;
|
|
302
314
|
pageData.forEach((alarm) => {
|
|
303
315
|
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
304
|
-
// 创建告警文本容器
|
|
305
|
-
const textContainer = document.createElement('div');
|
|
306
|
-
textContainer.style.cssText = `
|
|
307
|
-
font: ${this.fontString};
|
|
308
|
-
color: ${this.headerFont.color || '#e33c39'};
|
|
309
|
-
white-space: nowrap;
|
|
310
|
-
overflow: visible;
|
|
311
|
-
`;
|
|
312
|
-
// 应用下划线样式(参考 text-element.ts 的实现)
|
|
313
|
-
if (this.headerFont.isUnderline) {
|
|
314
|
-
textContainer.style.textDecoration = 'underline';
|
|
315
|
-
}
|
|
316
|
-
// 构建告警信息内容,根据配置决定显示哪些字段
|
|
317
316
|
const contentParts = [];
|
|
318
|
-
// 显示触发时间
|
|
319
317
|
if (((_a = this.model.generalSetting) === null || _a === void 0 ? void 0 : _a.showTriggerTime) && alarm.triggeredTime) {
|
|
320
|
-
|
|
321
|
-
contentParts.push(formattedTime);
|
|
318
|
+
contentParts.push(moment(alarm.triggeredTime).format('YYYY/MM/DD HH:mm:ss'));
|
|
322
319
|
}
|
|
323
|
-
// 获取当前语言环境
|
|
324
320
|
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';
|
|
325
321
|
const isChinese = language === 'zh-Hans' || language === 'zh';
|
|
326
|
-
// 显示告警等级
|
|
327
322
|
if (((_e = this.model.generalSetting) === null || _e === void 0 ? void 0 : _e.showAlarmLevel) && alarm.alarmLevel !== undefined) {
|
|
328
323
|
const levelMap = isChinese ? ['警告', '次要', '主要', '严重'] : ['Warning', 'Minor', 'Major', 'Critical'];
|
|
329
|
-
|
|
330
|
-
contentParts.push(alarmLevel);
|
|
324
|
+
contentParts.push(levelMap[alarm.alarmLevel] || (isChinese ? '警告' : 'Warning'));
|
|
331
325
|
}
|
|
332
|
-
// 显示告警名称
|
|
333
326
|
if (((_f = this.model.generalSetting) === null || _f === void 0 ? void 0 : _f.showAlarmName) && alarm.name) {
|
|
334
327
|
contentParts.push(alarm.name);
|
|
335
328
|
}
|
|
336
|
-
// 显示告警内容
|
|
337
329
|
if (((_g = this.model.generalSetting) === null || _g === void 0 ? void 0 : _g.showAlarmContent) && alarm.message) {
|
|
338
330
|
contentParts.push(alarm.message);
|
|
339
331
|
}
|
|
340
|
-
// 显示告警状态
|
|
341
332
|
if (((_h = this.model.generalSetting) === null || _h === void 0 ? void 0 : _h.showAlarmState) && alarm.state !== undefined) {
|
|
342
|
-
const stateMap = isChinese
|
|
343
|
-
|
|
344
|
-
|
|
333
|
+
const stateMap = isChinese
|
|
334
|
+
? ['触发/未确认', '触发/已确认', '恢复/未确认', '恢复/已确认']
|
|
335
|
+
: ['Triggered/Unconfirmed', 'Triggered/Confirmed', 'Restored/Unconfirmed', 'Restored/Confirmed'];
|
|
336
|
+
contentParts.push(stateMap[alarm.state] || (isChinese ? '触发/未确认' : 'Triggered/Unconfirmed'));
|
|
345
337
|
}
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
338
|
+
const textNode = this._createSvgTextNode(contentParts.join(' '));
|
|
339
|
+
textNode.setAttribute('x', xOffset.toString());
|
|
340
|
+
this.allAlarmsContainer.appendChild(textNode);
|
|
341
|
+
const textWidth = textNode.getComputedTextLength
|
|
342
|
+
? textNode.getComputedTextLength()
|
|
343
|
+
: (textNode.getBBox ? textNode.getBBox().width : 100);
|
|
344
|
+
xOffset += textWidth + GAP;
|
|
345
|
+
pageWidth += (pageWidth > 0 ? GAP : 0) + textWidth;
|
|
353
346
|
});
|
|
354
|
-
// 移除最后一个gap
|
|
355
|
-
if (pageWidth > 0) {
|
|
356
|
-
pageWidth -= 80;
|
|
357
|
-
}
|
|
358
|
-
// 保存页宽度
|
|
359
347
|
this.pageWidths.push(pageWidth);
|
|
360
|
-
this.totalWidth += pageWidth;
|
|
348
|
+
this.totalWidth += (this.totalWidth > 0 && pageWidth > 0 ? GAP : 0) + pageWidth;
|
|
349
|
+
}
|
|
350
|
+
_rebaseTextNodes() {
|
|
351
|
+
const GAP = 80;
|
|
352
|
+
let x = 0;
|
|
353
|
+
Array.from(this.allAlarmsContainer.children).forEach(node => {
|
|
354
|
+
node.setAttribute('x', x.toString());
|
|
355
|
+
const w = node.getComputedTextLength
|
|
356
|
+
? node.getComputedTextLength()
|
|
357
|
+
: (node.getBBox ? node.getBBox().width : 100);
|
|
358
|
+
x += w + GAP;
|
|
359
|
+
});
|
|
360
|
+
const newTotal = x > 0 ? x - GAP : 0;
|
|
361
|
+
this.totalWidth = newTotal;
|
|
362
|
+
this.pageWidths = [newTotal];
|
|
361
363
|
}
|
|
362
364
|
removeOldestPage() {
|
|
363
365
|
// 移除最旧的一页数据
|
|
364
366
|
this.displayedItems.splice(0, this.maxResultCount);
|
|
365
367
|
const oldPageWidth = this.pageWidths.shift() || 0;
|
|
366
|
-
|
|
367
|
-
this.totalWidth -= oldPageWidth;
|
|
368
|
+
this.totalWidth -= oldPageWidth + (this.pageWidths.length > 0 ? 80 : 0);
|
|
368
369
|
// 从DOM中移除最旧的元素
|
|
369
370
|
const elementsToRemove = Array.from(this.allAlarmsContainer.children).slice(0, this.maxResultCount);
|
|
370
|
-
elementsToRemove.forEach(
|
|
371
|
-
this.allAlarmsContainer.removeChild(
|
|
371
|
+
elementsToRemove.forEach(el => {
|
|
372
|
+
this.allAlarmsContainer.removeChild(el);
|
|
373
|
+
});
|
|
374
|
+
// SVG text 的 x 坐标从 0 重排(DOM删除后剩余节点要重新编排 x)
|
|
375
|
+
const GAP = 80;
|
|
376
|
+
let x = 0;
|
|
377
|
+
Array.from(this.allAlarmsContainer.children).forEach(node => {
|
|
378
|
+
node.setAttribute('x', x.toString());
|
|
379
|
+
const w = node.getComputedTextLength
|
|
380
|
+
? node.getComputedTextLength()
|
|
381
|
+
: (node.getBBox ? node.getBBox().width : 100);
|
|
382
|
+
x += w + GAP;
|
|
372
383
|
});
|
|
373
|
-
//
|
|
384
|
+
// currentLeft 补偿被移除页的宽度(含 gap),保持视觉位置不变
|
|
374
385
|
requestAnimationFrame(() => {
|
|
375
|
-
this.currentLeft += oldPageWidth;
|
|
376
|
-
this.allAlarmsContainer.
|
|
386
|
+
this.currentLeft += oldPageWidth + 80;
|
|
387
|
+
this.allAlarmsContainer.setAttribute('transform', `translate(${this.currentLeft}, 0)`);
|
|
377
388
|
});
|
|
378
389
|
}
|
|
379
390
|
scrollContent() {
|
|
@@ -396,21 +407,19 @@ export class ScrollAlarmElement extends ConditionalDynamicDisplayElement {
|
|
|
396
407
|
// 说明所有内容都已经滚出视图(不开启自动循环时多滚动50px确保最后一个字完全滚出)
|
|
397
408
|
if (this.currentLeft + this.totalWidth < -50) {
|
|
398
409
|
if (this.autoCycle) {
|
|
399
|
-
// 自动循环模式:无缝衔接回到容器右侧
|
|
400
410
|
if (this.hasMoreData) {
|
|
401
|
-
//
|
|
402
|
-
|
|
403
|
-
this.currentLeft = this.container.clientWidth;
|
|
411
|
+
// 有更多数据:重置到容器宽度,让内容从右侧重新滚入
|
|
412
|
+
this.currentLeft = this.model.size.width;
|
|
404
413
|
}
|
|
405
414
|
else {
|
|
406
|
-
// 没有更多数据了:重置
|
|
407
415
|
if (this.currentPage > 2) {
|
|
408
416
|
// 数据总数超过一页:重置到第一页并重新查询
|
|
409
417
|
this.resetToFirstPage();
|
|
410
418
|
}
|
|
411
419
|
else {
|
|
412
|
-
//
|
|
413
|
-
this.
|
|
420
|
+
// 单页循环:重排 x 从 0 开始,currentLeft 重置到右侧
|
|
421
|
+
this._rebaseTextNodes();
|
|
422
|
+
this.currentLeft = this.model.size.width;
|
|
414
423
|
}
|
|
415
424
|
}
|
|
416
425
|
}
|
|
@@ -422,7 +431,7 @@ export class ScrollAlarmElement extends ConditionalDynamicDisplayElement {
|
|
|
422
431
|
}
|
|
423
432
|
}
|
|
424
433
|
// 更新显示位置
|
|
425
|
-
this.allAlarmsContainer.
|
|
434
|
+
this.allAlarmsContainer.setAttribute('transform', `translate(${this.currentLeft}, 0)`);
|
|
426
435
|
}
|
|
427
436
|
initScrolling() {
|
|
428
437
|
clearInterval(this.scrollIntervalId);
|
|
@@ -433,8 +442,8 @@ export class ScrollAlarmElement extends ConditionalDynamicDisplayElement {
|
|
|
433
442
|
// 确保初始位置在容器右侧(从右边滚入)
|
|
434
443
|
if (this.currentPage === 1 && this.displayedItems.length <= this.maxResultCount) {
|
|
435
444
|
// 第一页初始加载时,确保从右侧开始
|
|
436
|
-
this.currentLeft = this.
|
|
437
|
-
this.allAlarmsContainer.
|
|
445
|
+
this.currentLeft = this.model.size.width;
|
|
446
|
+
this.allAlarmsContainer.setAttribute('transform', `translate(${this.currentLeft}, 0)`);
|
|
438
447
|
}
|
|
439
448
|
const scrollInterval = 100; // 默认100ms,滚动更流畅
|
|
440
449
|
// 延迟启动滚动确保内容渲染完成
|
|
@@ -447,12 +456,6 @@ export class ScrollAlarmElement extends ConditionalDynamicDisplayElement {
|
|
|
447
456
|
}, scrollInterval);
|
|
448
457
|
}, 500);
|
|
449
458
|
}
|
|
450
|
-
pauseScroll() {
|
|
451
|
-
this.isScrolling = false;
|
|
452
|
-
}
|
|
453
|
-
resumeScroll() {
|
|
454
|
-
this.isScrolling = true;
|
|
455
|
-
}
|
|
456
459
|
resetToFirstPage() {
|
|
457
460
|
// 重置到第一页并重新查询数据
|
|
458
461
|
this.currentPage = 1;
|
|
@@ -460,13 +463,15 @@ export class ScrollAlarmElement extends ConditionalDynamicDisplayElement {
|
|
|
460
463
|
this.hasTriedFirstPage = false;
|
|
461
464
|
this.displayedItems = [];
|
|
462
465
|
if (this.allAlarmsContainer) {
|
|
463
|
-
this.allAlarmsContainer.
|
|
466
|
+
while (this.allAlarmsContainer.firstChild) {
|
|
467
|
+
this.allAlarmsContainer.removeChild(this.allAlarmsContainer.firstChild);
|
|
468
|
+
}
|
|
464
469
|
this.totalWidth = 0;
|
|
465
470
|
this.pageWidths = [];
|
|
466
471
|
}
|
|
467
472
|
// 重置到容器右侧,让内容从右边滚入
|
|
468
|
-
this.currentLeft = this.
|
|
469
|
-
this.allAlarmsContainer.
|
|
473
|
+
this.currentLeft = this.model.size.width;
|
|
474
|
+
this.allAlarmsContainer.setAttribute('transform', `translate(${this.currentLeft}, 0)`);
|
|
470
475
|
this.getAlarmData();
|
|
471
476
|
}
|
|
472
477
|
updateQueryTimeRange() {
|
|
@@ -510,16 +515,18 @@ export class ScrollAlarmElement extends ConditionalDynamicDisplayElement {
|
|
|
510
515
|
// 确保宽度和高度为正值,避免 SVG 错误
|
|
511
516
|
const width = Math.max(this.model.size.width || 100, 0);
|
|
512
517
|
const height = Math.max(this.model.size.height || 50, 0);
|
|
518
|
+
// 先移除旧的 StateFrame,避免重复追加
|
|
519
|
+
this.$element.find('rect#StateFrame').remove();
|
|
513
520
|
this.rootElement.append('rect').attr('id', 'StateFrame').attr('fill', 'transparent')
|
|
514
521
|
.attr('width', width)
|
|
515
522
|
.attr('height', height);
|
|
516
|
-
const
|
|
523
|
+
const doc = this.$element[0].ownerDocument;
|
|
517
524
|
const currentRect = this.$element.find('rect#StateFrame').first();
|
|
518
525
|
if (!currentRect.length) {
|
|
519
526
|
return;
|
|
520
527
|
}
|
|
521
528
|
this.$element.find('image#StateImage').remove();
|
|
522
|
-
const imgObj =
|
|
529
|
+
const imgObj = doc.createElementNS('http://www.w3.org/2000/svg', 'image');
|
|
523
530
|
if (imgObj) {
|
|
524
531
|
let x = Number(currentRect[0].getAttribute('width')) - 20;
|
|
525
532
|
const currentRectX = currentRect[0].getAttribute('x');
|
|
@@ -534,20 +541,13 @@ export class ScrollAlarmElement extends ConditionalDynamicDisplayElement {
|
|
|
534
541
|
imgObj.setAttributeNS(null, 'y', '0');
|
|
535
542
|
imgObj.setAttributeNS(null, 'height', '20px');
|
|
536
543
|
imgObj.setAttributeNS(null, 'width', '20px');
|
|
537
|
-
const titleElement =
|
|
544
|
+
const titleElement = doc.createElementNS('http://www.w3.org/2000/svg', 'title');
|
|
538
545
|
imgObj.appendChild(titleElement);
|
|
539
546
|
this.$element.append(imgObj);
|
|
540
547
|
}
|
|
541
548
|
}
|
|
542
549
|
clearStatus() {
|
|
543
|
-
|
|
544
|
-
if (!currentRect.length) {
|
|
545
|
-
return;
|
|
546
|
-
}
|
|
547
|
-
const stroke = currentRect[0].getAttribute('stroke');
|
|
548
|
-
if (stroke) {
|
|
549
|
-
currentRect[0].removeAttribute('stroke');
|
|
550
|
-
}
|
|
550
|
+
this.$element.find('rect#StateFrame').remove();
|
|
551
551
|
this.$element.find('image#StateImage').remove();
|
|
552
552
|
}
|
|
553
553
|
/**
|
|
@@ -586,36 +586,20 @@ export class ScrollAlarmElement extends ConditionalDynamicDisplayElement {
|
|
|
586
586
|
const isChinese = language === 'zh-Hans' || language === 'zh';
|
|
587
587
|
textParts.push(isChinese ? '触发/未确认' : 'Triggered/Unconfirmed');
|
|
588
588
|
}
|
|
589
|
-
//
|
|
590
|
-
const
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
//
|
|
602
|
-
|
|
603
|
-
// 使用配置的宽度,而不是 clientWidth(因为DOM可能还没渲染完成)
|
|
604
|
-
const containerWidth = this.model.size.width;
|
|
605
|
-
// 先设置容器位置到右侧(屏幕外),这样添加元素时不会闪烁
|
|
606
|
-
this.currentLeft = containerWidth;
|
|
607
|
-
this.allAlarmsContainer.style.left = `${this.currentLeft}px`;
|
|
608
|
-
// 添加到DOM以便计算宽度
|
|
609
|
-
this.allAlarmsContainer.appendChild(textContainer);
|
|
610
|
-
// 使用 setTimeout 确保 DOM 渲染完成后再计算宽度
|
|
611
|
-
setTimeout(() => {
|
|
612
|
-
// 计算文本宽度
|
|
613
|
-
const textWidth = textContainer.offsetWidth;
|
|
614
|
-
this.totalWidth = textWidth;
|
|
615
|
-
this.pageWidths.push(textWidth);
|
|
616
|
-
// 启动滚动(autoCycle 只控制是否循环,不控制是否滚动)
|
|
617
|
-
this.initStaticScrolling();
|
|
618
|
-
}, 50);
|
|
589
|
+
// 创建 SVG text 节点(与真实运行模式一致,不依赖 foreignObject)
|
|
590
|
+
const textNode = this._createSvgTextNode(textParts.join(' '));
|
|
591
|
+
textNode.setAttribute('x', '0');
|
|
592
|
+
this.currentLeft = this.model.size.width;
|
|
593
|
+
this.allAlarmsContainer.setAttribute('transform', `translate(${this.currentLeft}, 0)`);
|
|
594
|
+
this.allAlarmsContainer.appendChild(textNode);
|
|
595
|
+
// SVG text 宽度可直接通过 getComputedTextLength 同步获取,无需 setTimeout
|
|
596
|
+
const textWidth = textNode.getComputedTextLength
|
|
597
|
+
? textNode.getComputedTextLength()
|
|
598
|
+
: (textNode.getBBox ? textNode.getBBox().width : 200);
|
|
599
|
+
this.totalWidth = textWidth;
|
|
600
|
+
this.pageWidths.push(textWidth);
|
|
601
|
+
// 启动滚动(autoCycle 只控制是否循环,不控制是否滚动)
|
|
602
|
+
this.initStaticScrolling();
|
|
619
603
|
}
|
|
620
604
|
/**
|
|
621
605
|
* 模拟运行时的静态滚动逻辑
|
|
@@ -642,7 +626,7 @@ export class ScrollAlarmElement extends ConditionalDynamicDisplayElement {
|
|
|
642
626
|
// 更新位置 - 从右往左滚动
|
|
643
627
|
this.currentLeft -= scrollStep;
|
|
644
628
|
// 更新显示位置
|
|
645
|
-
this.allAlarmsContainer.
|
|
629
|
+
this.allAlarmsContainer.setAttribute('transform', `translate(${this.currentLeft}, 0)`);
|
|
646
630
|
// 当内容完全滚出容器左侧时(内容右边缘完全移出容器左边缘)
|
|
647
631
|
// currentLeft + totalWidth 表示内容右边缘的位置
|
|
648
632
|
// 当这个值 <= -50 时,表示内容完全不可见(不开启自动循环时多滚动50px确保最后一个字完全滚出)
|
|
@@ -651,7 +635,7 @@ export class ScrollAlarmElement extends ConditionalDynamicDisplayElement {
|
|
|
651
635
|
if (this.autoCycle) {
|
|
652
636
|
// 自动循环模式:重置到容器右侧(使用配置宽度)
|
|
653
637
|
this.currentLeft = this.model.size.width;
|
|
654
|
-
this.allAlarmsContainer.
|
|
638
|
+
this.allAlarmsContainer.setAttribute('transform', `translate(${this.currentLeft}, 0)`);
|
|
655
639
|
}
|
|
656
640
|
else {
|
|
657
641
|
// 非循环模式:停止滚动
|
|
@@ -688,7 +672,6 @@ export class ScrollAlarmElement extends ConditionalDynamicDisplayElement {
|
|
|
688
672
|
const input = new GetAlarmsArgs(this.alarmNames, this.startTime, this.endTime, queryCount, 0, // skipCount
|
|
689
673
|
stateFilter, sorting);
|
|
690
674
|
this.alarmsStore.getHistoryAlarms(input).subscribe(result => {
|
|
691
|
-
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
692
675
|
if (!result.error && result.items) {
|
|
693
676
|
const newItems = result.items;
|
|
694
677
|
// 如果没有数据,清空显示
|
|
@@ -701,24 +684,27 @@ export class ScrollAlarmElement extends ConditionalDynamicDisplayElement {
|
|
|
701
684
|
this.hasMoreData = true;
|
|
702
685
|
// 清空DOM
|
|
703
686
|
if (this.allAlarmsContainer) {
|
|
704
|
-
this.allAlarmsContainer.
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
this.
|
|
687
|
+
while (this.allAlarmsContainer.firstChild) {
|
|
688
|
+
this.allAlarmsContainer.removeChild(this.allAlarmsContainer.firstChild);
|
|
689
|
+
}
|
|
690
|
+
this.currentLeft = this.model.size.width;
|
|
691
|
+
this.allAlarmsContainer.setAttribute('transform', `translate(${this.currentLeft}, 0)`);
|
|
708
692
|
}
|
|
709
693
|
return;
|
|
710
694
|
}
|
|
711
695
|
// 如果是首次加载或当前没有数据,直接渲染并启动滚动
|
|
712
696
|
if (this.displayedItems.length === 0) {
|
|
713
697
|
this.displayedItems = newItems;
|
|
714
|
-
this.allAlarmsContainer.
|
|
698
|
+
while (this.allAlarmsContainer.firstChild) {
|
|
699
|
+
this.allAlarmsContainer.removeChild(this.allAlarmsContainer.firstChild);
|
|
700
|
+
}
|
|
715
701
|
this.totalWidth = 0;
|
|
716
702
|
this.pageWidths = [];
|
|
717
703
|
// 设置 hasMoreData 状态,防止滚动时误触发 getAlarmData
|
|
718
704
|
this.hasMoreData = result.totalCount > newItems.length;
|
|
719
705
|
// 设置初始位置到容器右侧
|
|
720
|
-
this.currentLeft = this.
|
|
721
|
-
this.allAlarmsContainer.
|
|
706
|
+
this.currentLeft = this.model.size.width;
|
|
707
|
+
this.allAlarmsContainer.setAttribute('transform', `translate(${this.currentLeft}, 0)`);
|
|
722
708
|
this.renderNewPage(newItems);
|
|
723
709
|
// 启动滚动
|
|
724
710
|
if (!this.isScrolling) {
|
|
@@ -728,71 +714,19 @@ export class ScrollAlarmElement extends ConditionalDynamicDisplayElement {
|
|
|
728
714
|
}
|
|
729
715
|
// 保存当前的滚动位置
|
|
730
716
|
const currentScrollPosition = this.currentLeft;
|
|
731
|
-
// 清空所有
|
|
732
|
-
this.allAlarmsContainer.
|
|
733
|
-
|
|
734
|
-
const language = ((_c = (_b = (_a = window.abp) === null || _a === void 0 ? void 0 : _a.localization) === null || _b === void 0 ? void 0 : _b.currentLanguage) === null || _c === void 0 ? void 0 : _c.name) || 'zh-Hans';
|
|
735
|
-
const isChinese = language === 'zh-Hans' || language === 'zh';
|
|
736
|
-
// 重新创建所有新数据的DOM元素
|
|
737
|
-
for (let i = 0; i < newItems.length; i++) {
|
|
738
|
-
const alarm = newItems[i];
|
|
739
|
-
const textContainer = document.createElement('div');
|
|
740
|
-
textContainer.style.cssText = `
|
|
741
|
-
font: ${this.fontString};
|
|
742
|
-
color: ${this.headerFont.color || '#e33c39'};
|
|
743
|
-
white-space: nowrap;
|
|
744
|
-
overflow: visible;
|
|
745
|
-
`;
|
|
746
|
-
if (this.headerFont.isUnderline) {
|
|
747
|
-
textContainer.style.textDecoration = 'underline';
|
|
748
|
-
}
|
|
749
|
-
const contentParts = [];
|
|
750
|
-
// 显示触发时间
|
|
751
|
-
if (((_d = this.model.generalSetting) === null || _d === void 0 ? void 0 : _d.showTriggerTime) && alarm.triggeredTime) {
|
|
752
|
-
const formattedTime = moment(alarm.triggeredTime).format('YYYY/MM/DD HH:mm:ss');
|
|
753
|
-
contentParts.push(formattedTime);
|
|
754
|
-
}
|
|
755
|
-
// 显示告警等级
|
|
756
|
-
if (((_e = this.model.generalSetting) === null || _e === void 0 ? void 0 : _e.showAlarmLevel) && alarm.alarmLevel !== undefined) {
|
|
757
|
-
const levelMap = isChinese ? ['警告', '次要', '主要', '严重'] : ['Warning', 'Minor', 'Major', 'Critical'];
|
|
758
|
-
const alarmLevel = levelMap[alarm.alarmLevel] || (isChinese ? '警告' : 'Warning');
|
|
759
|
-
contentParts.push(alarmLevel);
|
|
760
|
-
}
|
|
761
|
-
// 显示告警名称
|
|
762
|
-
if (((_f = this.model.generalSetting) === null || _f === void 0 ? void 0 : _f.showAlarmName) && alarm.name) {
|
|
763
|
-
contentParts.push(alarm.name);
|
|
764
|
-
}
|
|
765
|
-
// 显示告警内容
|
|
766
|
-
if (((_g = this.model.generalSetting) === null || _g === void 0 ? void 0 : _g.showAlarmContent) && alarm.message) {
|
|
767
|
-
contentParts.push(alarm.message);
|
|
768
|
-
}
|
|
769
|
-
// 显示告警状态
|
|
770
|
-
if (((_h = this.model.generalSetting) === null || _h === void 0 ? void 0 : _h.showAlarmState) && alarm.state !== undefined) {
|
|
771
|
-
const stateMap = isChinese ? ['触发/未确认', '触发/已确认', '恢复/未确认', '恢复/已确认'] : ['Triggered/Unconfirmed', 'Triggered/Confirmed', 'Restored/Unconfirmed', 'Restored/Confirmed'];
|
|
772
|
-
const alarmState = stateMap[alarm.state] || (isChinese ? '触发/未确认' : 'Triggered/Unconfirmed');
|
|
773
|
-
contentParts.push(alarmState);
|
|
774
|
-
}
|
|
775
|
-
textContainer.textContent = contentParts.join(' ');
|
|
776
|
-
textContainer.setAttribute('data-index', i.toString());
|
|
777
|
-
this.allAlarmsContainer.appendChild(textContainer);
|
|
778
|
-
}
|
|
779
|
-
// 重新计算totalWidth
|
|
780
|
-
const allChildren = Array.from(this.allAlarmsContainer.children);
|
|
781
|
-
let newTotalWidth = 0;
|
|
782
|
-
allChildren.forEach(child => {
|
|
783
|
-
newTotalWidth += child.offsetWidth + 80;
|
|
784
|
-
});
|
|
785
|
-
if (newTotalWidth > 0) {
|
|
786
|
-
newTotalWidth -= 80; // 移除最后一个gap
|
|
717
|
+
// 清空所有SVG text节点,重新用 renderNewPage 渲染
|
|
718
|
+
while (this.allAlarmsContainer.firstChild) {
|
|
719
|
+
this.allAlarmsContainer.removeChild(this.allAlarmsContainer.firstChild);
|
|
787
720
|
}
|
|
721
|
+
this.totalWidth = 0;
|
|
722
|
+
this.pageWidths = [];
|
|
723
|
+
this.renderNewPage(newItems);
|
|
788
724
|
// 更新状态
|
|
789
725
|
this.displayedItems = newItems;
|
|
790
|
-
this.totalWidth = newTotalWidth;
|
|
791
|
-
this.pageWidths = [newTotalWidth]; // 重置为单页
|
|
792
726
|
this.hasMoreData = result.totalCount > newItems.length;
|
|
793
727
|
// 保持滚动位置不变,继续滚动
|
|
794
728
|
this.currentLeft = currentScrollPosition;
|
|
795
|
-
this.allAlarmsContainer.
|
|
729
|
+
this.allAlarmsContainer.setAttribute('transform', `translate(${this.currentLeft}, 0)`);
|
|
796
730
|
}
|
|
797
731
|
});
|
|
798
732
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
[{"__symbolic":"module","version":4,"metadata":{"ScrollAlarmElement":{"__symbolic":"class","extends":{"__symbolic":"reference","module":"../base/conditional-dynamic-display-element","name":"ConditionalDynamicDisplayElement","line":17,"character":40},"members":{"__ctor__":[{"__symbolic":"constructor","parameters":[{"__symbolic":"error","message":"Could not resolve type","line":52,"character":25,"context":{"typeName":"HTMLElement"}},{"__symbolic":"reference","module":"@angular/core","name":"Injector","line":53,"character":18},{"__symbolic":"reference","module":"../../service","name":"PermissionChecker","line":54,"character":27},{"__symbolic":"reference","module":"../../communication","name":"VariableCommunicator","line":55,"character":30},{"__symbolic":"reference","module":"../../config","name":"VariableStore","line":56,"character":23},{"__symbolic":"reference","module":"../../config","name":"AlarmsStore","line":57,"character":38},{"__symbolic":"reference","name":"string"}]}],"dispose":[{"__symbolic":"method"}],"getAlarmData":[{"__symbolic":"method"}],"initDisplayContainer":[{"__symbolic":"method"}],"
|
|
1
|
+
[{"__symbolic":"module","version":4,"metadata":{"ScrollAlarmElement":{"__symbolic":"class","extends":{"__symbolic":"reference","module":"../base/conditional-dynamic-display-element","name":"ConditionalDynamicDisplayElement","line":17,"character":40},"members":{"__ctor__":[{"__symbolic":"constructor","parameters":[{"__symbolic":"error","message":"Could not resolve type","line":52,"character":25,"context":{"typeName":"HTMLElement"}},{"__symbolic":"reference","module":"@angular/core","name":"Injector","line":53,"character":18},{"__symbolic":"reference","module":"../../service","name":"PermissionChecker","line":54,"character":27},{"__symbolic":"reference","module":"../../communication","name":"VariableCommunicator","line":55,"character":30},{"__symbolic":"reference","module":"../../config","name":"VariableStore","line":56,"character":23},{"__symbolic":"reference","module":"../../config","name":"AlarmsStore","line":57,"character":38},{"__symbolic":"reference","name":"string"}]}],"dispose":[{"__symbolic":"method"}],"getAlarmData":[{"__symbolic":"method"}],"initDisplayContainer":[{"__symbolic":"method"}],"_buildFontAttrs":[{"__symbolic":"method"}],"_createSvgTextNode":[{"__symbolic":"method"}],"renderNewPage":[{"__symbolic":"method"}],"_rebaseTextNodes":[{"__symbolic":"method"}],"removeOldestPage":[{"__symbolic":"method"}],"scrollContent":[{"__symbolic":"method"}],"initScrolling":[{"__symbolic":"method"}],"resetToFirstPage":[{"__symbolic":"method"}],"updateQueryTimeRange":[{"__symbolic":"method"}],"setStatusAsNormal":[{"__symbolic":"method"}],"setStatusAsLoading":[{"__symbolic":"method"}],"renderStatus":[{"__symbolic":"method"}],"clearStatus":[{"__symbolic":"method"}],"renderStaticDisplay":[{"__symbolic":"method"}],"initStaticScrolling":[{"__symbolic":"method"}],"scrollStaticContent":[{"__symbolic":"method"}],"replaceCurrentScrollingContent":[{"__symbolic":"method"}]}}}}]
|