@flexem/fc-gui 3.0.0-alpha.145 → 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.
@@ -42317,18 +42317,6 @@ class scroll_alarm_element_ScrollAlarmElement extends conditional_dynamic_displa
42317
42317
  this.initDisplayContainer();
42318
42318
  // 获取字体设置
42319
42319
  this.headerFont = ((_e = this.model.generalSetting) === null || _e === void 0 ? void 0 : _e.headerFont) || {};
42320
- // 构建符合 CSS font 属性规范的字符串
42321
- let fontString = '';
42322
- if (this.headerFont.isItalic) {
42323
- fontString += 'italic ';
42324
- }
42325
- if (this.headerFont.isBold) {
42326
- fontString += 'bold ';
42327
- }
42328
- const fontSize = this.headerFont.fontSize || '16px';
42329
- const lineHeight = parseInt(fontSize, 10) + 5;
42330
- fontString += `${fontSize}/${lineHeight}px ${this.headerFont.fontFamily || 'Microsoft YaHei'}`;
42331
- this.fontString = fontString;
42332
42320
  // 使用静态显示逻辑:只显示字段标签
42333
42321
  this.renderStaticDisplay();
42334
42322
  this.setStatusAsNormal();
@@ -42361,19 +42349,6 @@ class scroll_alarm_element_ScrollAlarmElement extends conditional_dynamic_displa
42361
42349
  this.initDisplayContainer();
42362
42350
  // 获取字体设置 - 参考 text-element.ts 的实现方式
42363
42351
  this.headerFont = ((_f = this.model.generalSetting) === null || _f === void 0 ? void 0 : _f.headerFont) || {};
42364
- // 构建符合 CSS font 属性规范的字符串
42365
- // 格式:font-style font-weight font-size/line-height font-family
42366
- let fontString = '';
42367
- if (this.headerFont.isItalic) {
42368
- fontString += 'italic ';
42369
- }
42370
- if (this.headerFont.isBold) {
42371
- fontString += 'bold ';
42372
- }
42373
- const fontSize = this.headerFont.fontSize || '16px';
42374
- const lineHeight = parseInt(fontSize, 10) + 5;
42375
- fontString += `${fontSize}/${lineHeight}px ${this.headerFont.fontFamily || 'Microsoft YaHei'}`;
42376
- this.fontString = fontString;
42377
42352
  this.getAlarmData();
42378
42353
  }
42379
42354
  }
@@ -42383,7 +42358,9 @@ class scroll_alarm_element_ScrollAlarmElement extends conditional_dynamic_displa
42383
42358
  // 初始化显示容器以显示空内容
42384
42359
  this.initDisplayContainer();
42385
42360
  if (this.allAlarmsContainer) {
42386
- this.allAlarmsContainer.innerHTML = '';
42361
+ while (this.allAlarmsContainer.firstChild) {
42362
+ this.allAlarmsContainer.removeChild(this.allAlarmsContainer.firstChild);
42363
+ }
42387
42364
  this.totalWidth = 0;
42388
42365
  this.pageWidths = [];
42389
42366
  }
@@ -42461,8 +42438,8 @@ class scroll_alarm_element_ScrollAlarmElement extends conditional_dynamic_displa
42461
42438
  const oldPageWidth = this.pageWidths.pop() || 0;
42462
42439
  this.totalWidth -= oldPageWidth;
42463
42440
  const elementsToRemove = Array.from(this.allAlarmsContainer.children).slice(startIndex, startIndex + itemsPerPage);
42464
- elementsToRemove.forEach(element => {
42465
- this.allAlarmsContainer.removeChild(element);
42441
+ elementsToRemove.forEach(el => {
42442
+ this.allAlarmsContainer.removeChild(el);
42466
42443
  });
42467
42444
  // 插入新的当前页数据
42468
42445
  this.displayedItems.splice(startIndex, 0, ...newPage);
@@ -42502,7 +42479,9 @@ class scroll_alarm_element_ScrollAlarmElement extends conditional_dynamic_displa
42502
42479
  // 清空显示
42503
42480
  this.displayedItems = [];
42504
42481
  if (this.allAlarmsContainer) {
42505
- this.allAlarmsContainer.innerHTML = '';
42482
+ while (this.allAlarmsContainer.firstChild) {
42483
+ this.allAlarmsContainer.removeChild(this.allAlarmsContainer.firstChild);
42484
+ }
42506
42485
  this.totalWidth = 0;
42507
42486
  this.pageWidths = [];
42508
42487
  }
@@ -42529,121 +42508,153 @@ class scroll_alarm_element_ScrollAlarmElement extends conditional_dynamic_displa
42529
42508
  var _a;
42530
42509
  const elementHeight = this.model.size.height;
42531
42510
  const elementWidth = this.model.size.width;
42532
- // 创建foreignObject作为容器
42533
- this.element = document.createElementNS('http://www.w3.org/2000/svg', 'foreignObject');
42534
- this.element.setAttribute('width', elementWidth.toString());
42535
- this.element.setAttribute('height', elementHeight.toString());
42536
- this.$element.append(this.element);
42537
- // 创建背景容器,应用headerFillColor背景色
42538
- this.container = document.createElement('div');
42539
- this.container.style.cssText = `
42540
- height: ${elementHeight}px;
42541
- width: 100%;
42542
- background-color: ${((_a = this.model.generalSetting) === null || _a === void 0 ? void 0 : _a.headerFillColor) || '#ffffff'};
42543
- display: flex;
42544
- align-items: center;
42545
- overflow: hidden;
42546
- position: relative;
42547
- border: 1px solid #8ea0aa;
42548
- border-radius: 2px;
42549
- `;
42550
- this.element.appendChild(this.container);
42551
- // 创建一个大容器来包含所有告警项,初始位置在容器右侧(从右边开始滚入)
42552
- this.allAlarmsContainer = document.createElement('div');
42553
- this.allAlarmsContainer.style.cssText = `
42554
- position: absolute;
42555
- top: 50%;
42556
- transform: translateY(-50%);
42557
- display: flex;
42558
- align-items: center;
42559
- gap: 80px;
42560
- `;
42561
- this.container.appendChild(this.allAlarmsContainer);
42562
- // 设置初始位置为容器宽度,让内容从右侧滚入
42511
+ const bgColor = ((_a = this.model.generalSetting) === null || _a === void 0 ? void 0 : _a.headerFillColor) || '#ffffff';
42512
+ const clipId = 'scroll-alarm-clip-' + Math.random().toString(36).slice(2);
42513
+ // 背景矩形
42514
+ this.bgRect = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
42515
+ this.bgRect.setAttribute('x', '0');
42516
+ this.bgRect.setAttribute('y', '0');
42517
+ this.bgRect.setAttribute('width', elementWidth.toString());
42518
+ this.bgRect.setAttribute('height', elementHeight.toString());
42519
+ this.bgRect.setAttribute('fill', bgColor);
42520
+ this.bgRect.setAttribute('stroke', '#8ea0aa');
42521
+ this.bgRect.setAttribute('stroke-width', '1');
42522
+ this.$element[0].appendChild(this.bgRect);
42523
+ // clipPath 限制文字滚动区域
42524
+ const defs = document.createElementNS('http://www.w3.org/2000/svg', 'defs');
42525
+ const clipPath = document.createElementNS('http://www.w3.org/2000/svg', 'clipPath');
42526
+ clipPath.setAttribute('id', clipId);
42527
+ const clipRect = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
42528
+ clipRect.setAttribute('x', '2');
42529
+ clipRect.setAttribute('y', '0');
42530
+ clipRect.setAttribute('width', (elementWidth - 4).toString());
42531
+ clipRect.setAttribute('height', elementHeight.toString());
42532
+ clipPath.appendChild(clipRect);
42533
+ defs.appendChild(clipPath);
42534
+ this.$element[0].appendChild(defs);
42535
+ // 滚动内容的 g 容器,套上 clipPath
42536
+ this.scrollGroup = document.createElementNS('http://www.w3.org/2000/svg', 'g');
42537
+ this.scrollGroup.setAttribute('clip-path', `url(#${clipId})`);
42538
+ this.$element[0].appendChild(this.scrollGroup);
42539
+ // 内部 g 用于整体平移(滚动动画改这个的 transform)
42540
+ this.allAlarmsContainer = document.createElementNS('http://www.w3.org/2000/svg', 'g');
42541
+ this.scrollGroup.appendChild(this.allAlarmsContainer);
42542
+ // 初始位置在右侧屏幕外
42563
42543
  this.currentLeft = elementWidth;
42564
- this.allAlarmsContainer.style.left = `${elementWidth}px`;
42565
- // 添加鼠标悬停暂停和恢复滚动功能
42566
- this.container.addEventListener('mouseenter', () => this.pauseScroll());
42567
- this.container.addEventListener('mouseleave', () => this.resumeScroll());
42544
+ this.allAlarmsContainer.setAttribute('transform', `translate(${elementWidth}, 0)`);
42545
+ }
42546
+ _buildFontAttrs() {
42547
+ const f = this.headerFont || {};
42548
+ const fontSize = parseInt((f.fontSize || '16px'), 10);
42549
+ return {
42550
+ fontSize,
42551
+ fontFamily: f.fontFamily || 'Microsoft YaHei',
42552
+ color: f.color || '#e33c39',
42553
+ isBold: !!f.isBold,
42554
+ isItalic: !!f.isItalic,
42555
+ isUnderline: !!f.isUnderline
42556
+ };
42557
+ }
42558
+ _createSvgTextNode(textContent) {
42559
+ const elementHeight = this.model.size.height;
42560
+ const fa = this._buildFontAttrs();
42561
+ const text = document.createElementNS('http://www.w3.org/2000/svg', 'text');
42562
+ text.setAttribute('y', (elementHeight / 2).toString());
42563
+ text.setAttribute('dominant-baseline', 'central');
42564
+ text.setAttribute('fill', fa.color);
42565
+ text.setAttribute('font-size', fa.fontSize.toString());
42566
+ text.setAttribute('font-family', fa.fontFamily);
42567
+ if (fa.isBold) {
42568
+ text.setAttribute('font-weight', 'bold');
42569
+ }
42570
+ if (fa.isItalic) {
42571
+ text.setAttribute('font-style', 'italic');
42572
+ }
42573
+ if (fa.isUnderline) {
42574
+ text.setAttribute('text-decoration', 'underline');
42575
+ }
42576
+ text.textContent = textContent;
42577
+ return text;
42568
42578
  }
42569
42579
  renderNewPage(pageData) {
42580
+ const GAP = 80;
42570
42581
  let pageWidth = 0;
42571
- // 为每个告警数据创建文本容器
42582
+ // 新页的起始 x = 已有总宽度 + gap(如果已有内容)
42583
+ let xOffset = this.totalWidth > 0 ? this.totalWidth + GAP : 0;
42572
42584
  pageData.forEach((alarm) => {
42573
42585
  var _a, _b, _c, _d, _e, _f, _g, _h;
42574
- // 创建告警文本容器
42575
- const textContainer = document.createElement('div');
42576
- textContainer.style.cssText = `
42577
- font: ${this.fontString};
42578
- color: ${this.headerFont.color || '#e33c39'};
42579
- white-space: nowrap;
42580
- overflow: visible;
42581
- `;
42582
- // 应用下划线样式(参考 text-element.ts 的实现)
42583
- if (this.headerFont.isUnderline) {
42584
- textContainer.style.textDecoration = 'underline';
42585
- }
42586
- // 构建告警信息内容,根据配置决定显示哪些字段
42587
42586
  const contentParts = [];
42588
- // 显示触发时间
42589
42587
  if (((_a = this.model.generalSetting) === null || _a === void 0 ? void 0 : _a.showTriggerTime) && alarm.triggeredTime) {
42590
- const formattedTime = moment(alarm.triggeredTime).format('YYYY/MM/DD HH:mm:ss');
42591
- contentParts.push(formattedTime);
42588
+ contentParts.push(moment(alarm.triggeredTime).format('YYYY/MM/DD HH:mm:ss'));
42592
42589
  }
42593
- // 获取当前语言环境
42594
42590
  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';
42595
42591
  const isChinese = language === 'zh-Hans' || language === 'zh';
42596
- // 显示告警等级
42597
42592
  if (((_e = this.model.generalSetting) === null || _e === void 0 ? void 0 : _e.showAlarmLevel) && alarm.alarmLevel !== undefined) {
42598
42593
  const levelMap = isChinese ? ['警告', '次要', '主要', '严重'] : ['Warning', 'Minor', 'Major', 'Critical'];
42599
- const alarmLevel = levelMap[alarm.alarmLevel] || (isChinese ? '警告' : 'Warning');
42600
- contentParts.push(alarmLevel);
42594
+ contentParts.push(levelMap[alarm.alarmLevel] || (isChinese ? '警告' : 'Warning'));
42601
42595
  }
42602
- // 显示告警名称
42603
42596
  if (((_f = this.model.generalSetting) === null || _f === void 0 ? void 0 : _f.showAlarmName) && alarm.name) {
42604
42597
  contentParts.push(alarm.name);
42605
42598
  }
42606
- // 显示告警内容
42607
42599
  if (((_g = this.model.generalSetting) === null || _g === void 0 ? void 0 : _g.showAlarmContent) && alarm.message) {
42608
42600
  contentParts.push(alarm.message);
42609
42601
  }
42610
- // 显示告警状态
42611
42602
  if (((_h = this.model.generalSetting) === null || _h === void 0 ? void 0 : _h.showAlarmState) && alarm.state !== undefined) {
42612
- const stateMap = isChinese ? ['触发/未确认', '触发/已确认', '恢复/未确认', '恢复/已确认'] : ['Triggered/Unconfirmed', 'Triggered/Confirmed', 'Restored/Unconfirmed', 'Restored/Confirmed'];
42613
- const alarmState = stateMap[alarm.state] || (isChinese ? '触发/未确认' : 'Triggered/Unconfirmed');
42614
- contentParts.push(alarmState);
42615
- }
42616
- // 将所有显示字段用空格连接,确保一行显示
42617
- const textContent = contentParts.join(' ');
42618
- textContainer.textContent = textContent;
42619
- this.allAlarmsContainer.appendChild(textContainer);
42620
- // 计算文本宽度
42621
- const textWidth = textContainer.offsetWidth;
42622
- pageWidth += textWidth + 80; // 80是gap大小
42603
+ const stateMap = isChinese
42604
+ ? ['触发/未确认', '触发/已确认', '恢复/未确认', '恢复/已确认']
42605
+ : ['Triggered/Unconfirmed', 'Triggered/Confirmed', 'Restored/Unconfirmed', 'Restored/Confirmed'];
42606
+ contentParts.push(stateMap[alarm.state] || (isChinese ? '触发/未确认' : 'Triggered/Unconfirmed'));
42607
+ }
42608
+ const textNode = this._createSvgTextNode(contentParts.join(' '));
42609
+ textNode.setAttribute('x', xOffset.toString());
42610
+ this.allAlarmsContainer.appendChild(textNode);
42611
+ const textWidth = textNode.getComputedTextLength
42612
+ ? textNode.getComputedTextLength()
42613
+ : (textNode.getBBox ? textNode.getBBox().width : 100);
42614
+ xOffset += textWidth + GAP;
42615
+ pageWidth += (pageWidth > 0 ? GAP : 0) + textWidth;
42623
42616
  });
42624
- // 移除最后一个gap
42625
- if (pageWidth > 0) {
42626
- pageWidth -= 80;
42627
- }
42628
- // 保存页宽度
42629
42617
  this.pageWidths.push(pageWidth);
42630
- this.totalWidth += pageWidth;
42618
+ this.totalWidth += (this.totalWidth > 0 && pageWidth > 0 ? GAP : 0) + pageWidth;
42619
+ }
42620
+ _rebaseTextNodes() {
42621
+ const GAP = 80;
42622
+ let x = 0;
42623
+ Array.from(this.allAlarmsContainer.children).forEach(node => {
42624
+ node.setAttribute('x', x.toString());
42625
+ const w = node.getComputedTextLength
42626
+ ? node.getComputedTextLength()
42627
+ : (node.getBBox ? node.getBBox().width : 100);
42628
+ x += w + GAP;
42629
+ });
42630
+ const newTotal = x > 0 ? x - GAP : 0;
42631
+ this.totalWidth = newTotal;
42632
+ this.pageWidths = [newTotal];
42631
42633
  }
42632
42634
  removeOldestPage() {
42633
42635
  // 移除最旧的一页数据
42634
42636
  this.displayedItems.splice(0, this.maxResultCount);
42635
42637
  const oldPageWidth = this.pageWidths.shift() || 0;
42636
- // 更新总宽度
42637
- this.totalWidth -= oldPageWidth;
42638
+ this.totalWidth -= oldPageWidth + (this.pageWidths.length > 0 ? 80 : 0);
42638
42639
  // 从DOM中移除最旧的元素
42639
42640
  const elementsToRemove = Array.from(this.allAlarmsContainer.children).slice(0, this.maxResultCount);
42640
- elementsToRemove.forEach(element => {
42641
- this.allAlarmsContainer.removeChild(element);
42641
+ elementsToRemove.forEach(el => {
42642
+ this.allAlarmsContainer.removeChild(el);
42642
42643
  });
42643
- // 调整当前left位置(保持视觉位置不变)- 这里需要等DOM更新完成后再调整
42644
+ // SVG text 的 x 坐标从 0 重排(DOM删除后剩余节点要重新编排 x)
42645
+ const GAP = 80;
42646
+ let x = 0;
42647
+ Array.from(this.allAlarmsContainer.children).forEach(node => {
42648
+ node.setAttribute('x', x.toString());
42649
+ const w = node.getComputedTextLength
42650
+ ? node.getComputedTextLength()
42651
+ : (node.getBBox ? node.getBBox().width : 100);
42652
+ x += w + GAP;
42653
+ });
42654
+ // currentLeft 补偿被移除页的宽度(含 gap),保持视觉位置不变
42644
42655
  requestAnimationFrame(() => {
42645
- this.currentLeft += oldPageWidth;
42646
- this.allAlarmsContainer.style.left = `${this.currentLeft}px`;
42656
+ this.currentLeft += oldPageWidth + 80;
42657
+ this.allAlarmsContainer.setAttribute('transform', `translate(${this.currentLeft}, 0)`);
42647
42658
  });
42648
42659
  }
42649
42660
  scrollContent() {
@@ -42666,21 +42677,19 @@ class scroll_alarm_element_ScrollAlarmElement extends conditional_dynamic_displa
42666
42677
  // 说明所有内容都已经滚出视图(不开启自动循环时多滚动50px确保最后一个字完全滚出)
42667
42678
  if (this.currentLeft + this.totalWidth < -50) {
42668
42679
  if (this.autoCycle) {
42669
- // 自动循环模式:无缝衔接回到容器右侧
42670
42680
  if (this.hasMoreData) {
42671
- // 有更多数据:继续加载(但实际上已经在上面预加载了)
42672
- // 重置到容器宽度,让内容从右侧重新滚入
42673
- this.currentLeft = this.container.clientWidth;
42681
+ // 有更多数据:重置到容器宽度,让内容从右侧重新滚入
42682
+ this.currentLeft = this.model.size.width;
42674
42683
  }
42675
42684
  else {
42676
- // 没有更多数据了:重置
42677
42685
  if (this.currentPage > 2) {
42678
42686
  // 数据总数超过一页:重置到第一页并重新查询
42679
42687
  this.resetToFirstPage();
42680
42688
  }
42681
42689
  else {
42682
- // 数据总数只有一页:直接重置到容器右侧,循环滚动当前数据
42683
- this.currentLeft = this.container.clientWidth;
42690
+ // 单页循环:重排 x 从 0 开始,currentLeft 重置到右侧
42691
+ this._rebaseTextNodes();
42692
+ this.currentLeft = this.model.size.width;
42684
42693
  }
42685
42694
  }
42686
42695
  }
@@ -42692,7 +42701,7 @@ class scroll_alarm_element_ScrollAlarmElement extends conditional_dynamic_displa
42692
42701
  }
42693
42702
  }
42694
42703
  // 更新显示位置
42695
- this.allAlarmsContainer.style.left = `${this.currentLeft}px`;
42704
+ this.allAlarmsContainer.setAttribute('transform', `translate(${this.currentLeft}, 0)`);
42696
42705
  }
42697
42706
  initScrolling() {
42698
42707
  clearInterval(this.scrollIntervalId);
@@ -42703,8 +42712,8 @@ class scroll_alarm_element_ScrollAlarmElement extends conditional_dynamic_displa
42703
42712
  // 确保初始位置在容器右侧(从右边滚入)
42704
42713
  if (this.currentPage === 1 && this.displayedItems.length <= this.maxResultCount) {
42705
42714
  // 第一页初始加载时,确保从右侧开始
42706
- this.currentLeft = this.container.clientWidth;
42707
- this.allAlarmsContainer.style.left = `${this.currentLeft}px`;
42715
+ this.currentLeft = this.model.size.width;
42716
+ this.allAlarmsContainer.setAttribute('transform', `translate(${this.currentLeft}, 0)`);
42708
42717
  }
42709
42718
  const scrollInterval = 100; // 默认100ms,滚动更流畅
42710
42719
  // 延迟启动滚动确保内容渲染完成
@@ -42717,12 +42726,6 @@ class scroll_alarm_element_ScrollAlarmElement extends conditional_dynamic_displa
42717
42726
  }, scrollInterval);
42718
42727
  }, 500);
42719
42728
  }
42720
- pauseScroll() {
42721
- this.isScrolling = false;
42722
- }
42723
- resumeScroll() {
42724
- this.isScrolling = true;
42725
- }
42726
42729
  resetToFirstPage() {
42727
42730
  // 重置到第一页并重新查询数据
42728
42731
  this.currentPage = 1;
@@ -42730,13 +42733,15 @@ class scroll_alarm_element_ScrollAlarmElement extends conditional_dynamic_displa
42730
42733
  this.hasTriedFirstPage = false;
42731
42734
  this.displayedItems = [];
42732
42735
  if (this.allAlarmsContainer) {
42733
- this.allAlarmsContainer.innerHTML = '';
42736
+ while (this.allAlarmsContainer.firstChild) {
42737
+ this.allAlarmsContainer.removeChild(this.allAlarmsContainer.firstChild);
42738
+ }
42734
42739
  this.totalWidth = 0;
42735
42740
  this.pageWidths = [];
42736
42741
  }
42737
42742
  // 重置到容器右侧,让内容从右边滚入
42738
- this.currentLeft = this.container.clientWidth;
42739
- this.allAlarmsContainer.style.left = `${this.currentLeft}px`;
42743
+ this.currentLeft = this.model.size.width;
42744
+ this.allAlarmsContainer.setAttribute('transform', `translate(${this.currentLeft}, 0)`);
42740
42745
  this.getAlarmData();
42741
42746
  }
42742
42747
  updateQueryTimeRange() {
@@ -42780,16 +42785,18 @@ class scroll_alarm_element_ScrollAlarmElement extends conditional_dynamic_displa
42780
42785
  // 确保宽度和高度为正值,避免 SVG 错误
42781
42786
  const width = Math.max(this.model.size.width || 100, 0);
42782
42787
  const height = Math.max(this.model.size.height || 50, 0);
42788
+ // 先移除旧的 StateFrame,避免重复追加
42789
+ this.$element.find('rect#StateFrame').remove();
42783
42790
  this.rootElement.append('rect').attr('id', 'StateFrame').attr('fill', 'transparent')
42784
42791
  .attr('width', width)
42785
42792
  .attr('height', height);
42786
- const document = this.$element[0].ownerDocument;
42793
+ const doc = this.$element[0].ownerDocument;
42787
42794
  const currentRect = this.$element.find('rect#StateFrame').first();
42788
42795
  if (!currentRect.length) {
42789
42796
  return;
42790
42797
  }
42791
42798
  this.$element.find('image#StateImage').remove();
42792
- const imgObj = document.createElementNS('http://www.w3.org/2000/svg', 'image');
42799
+ const imgObj = doc.createElementNS('http://www.w3.org/2000/svg', 'image');
42793
42800
  if (imgObj) {
42794
42801
  let x = Number(currentRect[0].getAttribute('width')) - 20;
42795
42802
  const currentRectX = currentRect[0].getAttribute('x');
@@ -42804,20 +42811,13 @@ class scroll_alarm_element_ScrollAlarmElement extends conditional_dynamic_displa
42804
42811
  imgObj.setAttributeNS(null, 'y', '0');
42805
42812
  imgObj.setAttributeNS(null, 'height', '20px');
42806
42813
  imgObj.setAttributeNS(null, 'width', '20px');
42807
- const titleElement = document.createElementNS('http://www.w3.org/2000/svg', 'title');
42814
+ const titleElement = doc.createElementNS('http://www.w3.org/2000/svg', 'title');
42808
42815
  imgObj.appendChild(titleElement);
42809
42816
  this.$element.append(imgObj);
42810
42817
  }
42811
42818
  }
42812
42819
  clearStatus() {
42813
- const currentRect = this.$element.find('rect#StateFrame').first();
42814
- if (!currentRect.length) {
42815
- return;
42816
- }
42817
- const stroke = currentRect[0].getAttribute('stroke');
42818
- if (stroke) {
42819
- currentRect[0].removeAttribute('stroke');
42820
- }
42820
+ this.$element.find('rect#StateFrame').remove();
42821
42821
  this.$element.find('image#StateImage').remove();
42822
42822
  }
42823
42823
  /**
@@ -42856,36 +42856,20 @@ class scroll_alarm_element_ScrollAlarmElement extends conditional_dynamic_displa
42856
42856
  const isChinese = language === 'zh-Hans' || language === 'zh';
42857
42857
  textParts.push(isChinese ? '触发/未确认' : 'Triggered/Unconfirmed');
42858
42858
  }
42859
- // 创建文本容器
42860
- const textContainer = document.createElement('div');
42861
- textContainer.style.cssText = `
42862
- font: ${this.fontString};
42863
- color: ${this.headerFont.color || '#e33c39'};
42864
- white-space: nowrap;
42865
- overflow: visible;
42866
- `;
42867
- // 应用下划线样式
42868
- if (this.headerFont.isUnderline) {
42869
- textContainer.style.textDecoration = 'underline';
42870
- }
42871
- // 设置文本内容
42872
- textContainer.textContent = textParts.join(' ');
42873
- // 使用配置的宽度,而不是 clientWidth(因为DOM可能还没渲染完成)
42874
- const containerWidth = this.model.size.width;
42875
- // 先设置容器位置到右侧(屏幕外),这样添加元素时不会闪烁
42876
- this.currentLeft = containerWidth;
42877
- this.allAlarmsContainer.style.left = `${this.currentLeft}px`;
42878
- // 添加到DOM以便计算宽度
42879
- this.allAlarmsContainer.appendChild(textContainer);
42880
- // 使用 setTimeout 确保 DOM 渲染完成后再计算宽度
42881
- setTimeout(() => {
42882
- // 计算文本宽度
42883
- const textWidth = textContainer.offsetWidth;
42884
- this.totalWidth = textWidth;
42885
- this.pageWidths.push(textWidth);
42886
- // 启动滚动(autoCycle 只控制是否循环,不控制是否滚动)
42887
- this.initStaticScrolling();
42888
- }, 50);
42859
+ // 创建 SVG text 节点(与真实运行模式一致,不依赖 foreignObject)
42860
+ const textNode = this._createSvgTextNode(textParts.join(' '));
42861
+ textNode.setAttribute('x', '0');
42862
+ this.currentLeft = this.model.size.width;
42863
+ this.allAlarmsContainer.setAttribute('transform', `translate(${this.currentLeft}, 0)`);
42864
+ this.allAlarmsContainer.appendChild(textNode);
42865
+ // SVG text 宽度可直接通过 getComputedTextLength 同步获取,无需 setTimeout
42866
+ const textWidth = textNode.getComputedTextLength
42867
+ ? textNode.getComputedTextLength()
42868
+ : (textNode.getBBox ? textNode.getBBox().width : 200);
42869
+ this.totalWidth = textWidth;
42870
+ this.pageWidths.push(textWidth);
42871
+ // 启动滚动(autoCycle 只控制是否循环,不控制是否滚动)
42872
+ this.initStaticScrolling();
42889
42873
  }
42890
42874
  /**
42891
42875
  * 模拟运行时的静态滚动逻辑
@@ -42912,7 +42896,7 @@ class scroll_alarm_element_ScrollAlarmElement extends conditional_dynamic_displa
42912
42896
  // 更新位置 - 从右往左滚动
42913
42897
  this.currentLeft -= scrollStep;
42914
42898
  // 更新显示位置
42915
- this.allAlarmsContainer.style.left = `${this.currentLeft}px`;
42899
+ this.allAlarmsContainer.setAttribute('transform', `translate(${this.currentLeft}, 0)`);
42916
42900
  // 当内容完全滚出容器左侧时(内容右边缘完全移出容器左边缘)
42917
42901
  // currentLeft + totalWidth 表示内容右边缘的位置
42918
42902
  // 当这个值 <= -50 时,表示内容完全不可见(不开启自动循环时多滚动50px确保最后一个字完全滚出)
@@ -42921,7 +42905,7 @@ class scroll_alarm_element_ScrollAlarmElement extends conditional_dynamic_displa
42921
42905
  if (this.autoCycle) {
42922
42906
  // 自动循环模式:重置到容器右侧(使用配置宽度)
42923
42907
  this.currentLeft = this.model.size.width;
42924
- this.allAlarmsContainer.style.left = `${this.currentLeft}px`;
42908
+ this.allAlarmsContainer.setAttribute('transform', `translate(${this.currentLeft}, 0)`);
42925
42909
  }
42926
42910
  else {
42927
42911
  // 非循环模式:停止滚动
@@ -42958,7 +42942,6 @@ class scroll_alarm_element_ScrollAlarmElement extends conditional_dynamic_displa
42958
42942
  const input = new _tmp_config["c" /* GetAlarmsArgs */](this.alarmNames, this.startTime, this.endTime, queryCount, 0, // skipCount
42959
42943
  stateFilter, sorting);
42960
42944
  this.alarmsStore.getHistoryAlarms(input).subscribe(result => {
42961
- var _a, _b, _c, _d, _e, _f, _g, _h;
42962
42945
  if (!result.error && result.items) {
42963
42946
  const newItems = result.items;
42964
42947
  // 如果没有数据,清空显示
@@ -42971,24 +42954,27 @@ class scroll_alarm_element_ScrollAlarmElement extends conditional_dynamic_displa
42971
42954
  this.hasMoreData = true;
42972
42955
  // 清空DOM
42973
42956
  if (this.allAlarmsContainer) {
42974
- this.allAlarmsContainer.innerHTML = '';
42975
- const containerWidth = this.model.size.width;
42976
- this.currentLeft = containerWidth;
42977
- this.allAlarmsContainer.style.left = `${containerWidth}px`;
42957
+ while (this.allAlarmsContainer.firstChild) {
42958
+ this.allAlarmsContainer.removeChild(this.allAlarmsContainer.firstChild);
42959
+ }
42960
+ this.currentLeft = this.model.size.width;
42961
+ this.allAlarmsContainer.setAttribute('transform', `translate(${this.currentLeft}, 0)`);
42978
42962
  }
42979
42963
  return;
42980
42964
  }
42981
42965
  // 如果是首次加载或当前没有数据,直接渲染并启动滚动
42982
42966
  if (this.displayedItems.length === 0) {
42983
42967
  this.displayedItems = newItems;
42984
- this.allAlarmsContainer.innerHTML = '';
42968
+ while (this.allAlarmsContainer.firstChild) {
42969
+ this.allAlarmsContainer.removeChild(this.allAlarmsContainer.firstChild);
42970
+ }
42985
42971
  this.totalWidth = 0;
42986
42972
  this.pageWidths = [];
42987
42973
  // 设置 hasMoreData 状态,防止滚动时误触发 getAlarmData
42988
42974
  this.hasMoreData = result.totalCount > newItems.length;
42989
42975
  // 设置初始位置到容器右侧
42990
- this.currentLeft = this.container.clientWidth;
42991
- this.allAlarmsContainer.style.left = `${this.currentLeft}px`;
42976
+ this.currentLeft = this.model.size.width;
42977
+ this.allAlarmsContainer.setAttribute('transform', `translate(${this.currentLeft}, 0)`);
42992
42978
  this.renderNewPage(newItems);
42993
42979
  // 启动滚动
42994
42980
  if (!this.isScrolling) {
@@ -42998,71 +42984,19 @@ class scroll_alarm_element_ScrollAlarmElement extends conditional_dynamic_displa
42998
42984
  }
42999
42985
  // 保存当前的滚动位置
43000
42986
  const currentScrollPosition = this.currentLeft;
43001
- // 清空所有DOM元素
43002
- this.allAlarmsContainer.innerHTML = '';
43003
- // 获取语言设置
43004
- 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';
43005
- const isChinese = language === 'zh-Hans' || language === 'zh';
43006
- // 重新创建所有新数据的DOM元素
43007
- for (let i = 0; i < newItems.length; i++) {
43008
- const alarm = newItems[i];
43009
- const textContainer = document.createElement('div');
43010
- textContainer.style.cssText = `
43011
- font: ${this.fontString};
43012
- color: ${this.headerFont.color || '#e33c39'};
43013
- white-space: nowrap;
43014
- overflow: visible;
43015
- `;
43016
- if (this.headerFont.isUnderline) {
43017
- textContainer.style.textDecoration = 'underline';
43018
- }
43019
- const contentParts = [];
43020
- // 显示触发时间
43021
- if (((_d = this.model.generalSetting) === null || _d === void 0 ? void 0 : _d.showTriggerTime) && alarm.triggeredTime) {
43022
- const formattedTime = moment(alarm.triggeredTime).format('YYYY/MM/DD HH:mm:ss');
43023
- contentParts.push(formattedTime);
43024
- }
43025
- // 显示告警等级
43026
- if (((_e = this.model.generalSetting) === null || _e === void 0 ? void 0 : _e.showAlarmLevel) && alarm.alarmLevel !== undefined) {
43027
- const levelMap = isChinese ? ['警告', '次要', '主要', '严重'] : ['Warning', 'Minor', 'Major', 'Critical'];
43028
- const alarmLevel = levelMap[alarm.alarmLevel] || (isChinese ? '警告' : 'Warning');
43029
- contentParts.push(alarmLevel);
43030
- }
43031
- // 显示告警名称
43032
- if (((_f = this.model.generalSetting) === null || _f === void 0 ? void 0 : _f.showAlarmName) && alarm.name) {
43033
- contentParts.push(alarm.name);
43034
- }
43035
- // 显示告警内容
43036
- if (((_g = this.model.generalSetting) === null || _g === void 0 ? void 0 : _g.showAlarmContent) && alarm.message) {
43037
- contentParts.push(alarm.message);
43038
- }
43039
- // 显示告警状态
43040
- if (((_h = this.model.generalSetting) === null || _h === void 0 ? void 0 : _h.showAlarmState) && alarm.state !== undefined) {
43041
- const stateMap = isChinese ? ['触发/未确认', '触发/已确认', '恢复/未确认', '恢复/已确认'] : ['Triggered/Unconfirmed', 'Triggered/Confirmed', 'Restored/Unconfirmed', 'Restored/Confirmed'];
43042
- const alarmState = stateMap[alarm.state] || (isChinese ? '触发/未确认' : 'Triggered/Unconfirmed');
43043
- contentParts.push(alarmState);
43044
- }
43045
- textContainer.textContent = contentParts.join(' ');
43046
- textContainer.setAttribute('data-index', i.toString());
43047
- this.allAlarmsContainer.appendChild(textContainer);
43048
- }
43049
- // 重新计算totalWidth
43050
- const allChildren = Array.from(this.allAlarmsContainer.children);
43051
- let newTotalWidth = 0;
43052
- allChildren.forEach(child => {
43053
- newTotalWidth += child.offsetWidth + 80;
43054
- });
43055
- if (newTotalWidth > 0) {
43056
- newTotalWidth -= 80; // 移除最后一个gap
42987
+ // 清空所有SVG text节点,重新用 renderNewPage 渲染
42988
+ while (this.allAlarmsContainer.firstChild) {
42989
+ this.allAlarmsContainer.removeChild(this.allAlarmsContainer.firstChild);
43057
42990
  }
42991
+ this.totalWidth = 0;
42992
+ this.pageWidths = [];
42993
+ this.renderNewPage(newItems);
43058
42994
  // 更新状态
43059
42995
  this.displayedItems = newItems;
43060
- this.totalWidth = newTotalWidth;
43061
- this.pageWidths = [newTotalWidth]; // 重置为单页
43062
42996
  this.hasMoreData = result.totalCount > newItems.length;
43063
42997
  // 保持滚动位置不变,继续滚动
43064
42998
  this.currentLeft = currentScrollPosition;
43065
- this.allAlarmsContainer.style.left = `${this.currentLeft}px`;
42999
+ this.allAlarmsContainer.setAttribute('transform', `translate(${this.currentLeft}, 0)`);
43066
43000
  }
43067
43001
  });
43068
43002
  }