|
@@ -166,8 +166,8 @@
|
|
|
|
|
|
|
|
.error-popover {
|
|
.error-popover {
|
|
|
display: none;
|
|
display: none;
|
|
|
- position: absolute;
|
|
|
|
|
- z-index: 1000;
|
|
|
|
|
|
|
+ position: fixed;
|
|
|
|
|
+ z-index: 9999;
|
|
|
background: var(--color-bg-card);
|
|
background: var(--color-bg-card);
|
|
|
border: 1px solid rgba(220, 53, 69, 0.3);
|
|
border: 1px solid rgba(220, 53, 69, 0.3);
|
|
|
border-radius: var(--radius-md);
|
|
border-radius: var(--radius-md);
|
|
@@ -459,18 +459,22 @@ function confirmDelete(id, name) {
|
|
|
let currentPopover = null;
|
|
let currentPopover = null;
|
|
|
|
|
|
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
|
- document.addEventListener('mouseenter', function(e) {
|
|
|
|
|
|
|
+ let hoveredIndicator = null;
|
|
|
|
|
+
|
|
|
|
|
+ document.addEventListener('mouseover', function(e) {
|
|
|
const indicator = e.target.closest('.error-indicator');
|
|
const indicator = e.target.closest('.error-indicator');
|
|
|
- if (indicator) {
|
|
|
|
|
|
|
+ if (indicator && indicator !== hoveredIndicator) {
|
|
|
|
|
+ hoveredIndicator = indicator;
|
|
|
showErrorPopover(indicator, e);
|
|
showErrorPopover(indicator, e);
|
|
|
}
|
|
}
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
- document.addEventListener('mouseleave', function(e) {
|
|
|
|
|
|
|
+ document.addEventListener('mouseout', function(e) {
|
|
|
const indicator = e.target.closest('.error-indicator');
|
|
const indicator = e.target.closest('.error-indicator');
|
|
|
if (indicator) {
|
|
if (indicator) {
|
|
|
const relatedTarget = e.relatedTarget;
|
|
const relatedTarget = e.relatedTarget;
|
|
|
- if (!relatedTarget || !relatedTarget.closest('.error-indicator') || !relatedTarget.closest('.error-popover')) {
|
|
|
|
|
|
|
+ if (!relatedTarget || !relatedTarget.closest('.error-indicator') && !relatedTarget.closest('.error-popover')) {
|
|
|
|
|
+ hoveredIndicator = null;
|
|
|
hideErrorPopover();
|
|
hideErrorPopover();
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
@@ -507,36 +511,60 @@ function showErrorPopover(indicator, event) {
|
|
|
<i class="bi bi-exclamation-circle"></i>
|
|
<i class="bi bi-exclamation-circle"></i>
|
|
|
<span>疑似错误</span>
|
|
<span>疑似错误</span>
|
|
|
</div>
|
|
</div>
|
|
|
- <div class="error-popover-content">${errorText}</div>
|
|
|
|
|
|
|
+ <div class="error-popover-content"></div>
|
|
|
`;
|
|
`;
|
|
|
|
|
|
|
|
- const rect = indicator.getBoundingClientRect();
|
|
|
|
|
- const arrowOffset = 12;
|
|
|
|
|
|
|
+ popover.querySelector('.error-popover-content').textContent = errorText;
|
|
|
|
|
+
|
|
|
|
|
+ document.body.appendChild(popover);
|
|
|
|
|
+
|
|
|
|
|
+ const popoverRect = popover.getBoundingClientRect();
|
|
|
const gap = 8;
|
|
const gap = 8;
|
|
|
|
|
|
|
|
- popover.style.left = rect.left + 'px';
|
|
|
|
|
- popover.style.top = (rect.bottom + gap) + 'px';
|
|
|
|
|
|
|
+ let left, top;
|
|
|
|
|
|
|
|
- const arrow = popover.querySelector('.error-popover-arrow');
|
|
|
|
|
- arrow.style.left = (rect.width / 2 - arrowOffset / 2) + 'px';
|
|
|
|
|
|
|
+ if (event && event.clientX !== undefined) {
|
|
|
|
|
+ left = event.clientX - popoverRect.width / 2;
|
|
|
|
|
+ top = event.clientY + gap;
|
|
|
|
|
+ } else {
|
|
|
|
|
+ const rect = indicator.getBoundingClientRect();
|
|
|
|
|
+ left = rect.left;
|
|
|
|
|
+ top = rect.bottom + gap;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- const popoverRect = popover.getBoundingClientRect();
|
|
|
|
|
const viewportWidth = window.innerWidth;
|
|
const viewportWidth = window.innerWidth;
|
|
|
const viewportHeight = window.innerHeight;
|
|
const viewportHeight = window.innerHeight;
|
|
|
|
|
|
|
|
- if (popoverRect.right > viewportWidth) {
|
|
|
|
|
- popover.style.left = (viewportWidth - popoverRect.width - 10) + 'px';
|
|
|
|
|
- arrow.style.left = (rect.left + rect.width / 2 - popoverRect.left - arrowOffset / 2) + 'px';
|
|
|
|
|
|
|
+ left = Math.max(10, Math.min(left, viewportWidth - popoverRect.width - 10));
|
|
|
|
|
+
|
|
|
|
|
+ if (top + popoverRect.height > viewportHeight) {
|
|
|
|
|
+ top = (event && event.clientY !== undefined ? event.clientY : indicator.getBoundingClientRect().top) - popoverRect.height - gap;
|
|
|
|
|
+ if (top < 10) top = 10;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- if (popoverRect.bottom > viewportHeight) {
|
|
|
|
|
- popover.style.top = (rect.top - popoverRect.height - gap) + 'px';
|
|
|
|
|
|
|
+ popover.style.left = left + 'px';
|
|
|
|
|
+ popover.style.top = top + 'px';
|
|
|
|
|
+
|
|
|
|
|
+ const arrow = popover.querySelector('.error-popover-arrow');
|
|
|
|
|
+ const arrowSize = 12;
|
|
|
|
|
+ const arrowGap = 6;
|
|
|
|
|
+
|
|
|
|
|
+ let arrowLeft = (event && event.clientX !== undefined ? event.clientX : indicator.getBoundingClientRect().left + indicator.getBoundingClientRect().width / 2) - popover.offsetLeft - arrowSize / 2;
|
|
|
|
|
+ arrowLeft = Math.max(arrowGap, Math.min(popoverRect.width - arrowSize - arrowGap, arrowLeft));
|
|
|
|
|
+
|
|
|
|
|
+ arrow.style.left = arrowLeft + 'px';
|
|
|
|
|
+
|
|
|
|
|
+ const indicatorRect = indicator.getBoundingClientRect();
|
|
|
|
|
+ if (top < indicatorRect.top) {
|
|
|
arrow.style.top = 'auto';
|
|
arrow.style.top = 'auto';
|
|
|
arrow.style.bottom = '-6px';
|
|
arrow.style.bottom = '-6px';
|
|
|
arrow.style.transform = 'rotate(225deg)';
|
|
arrow.style.transform = 'rotate(225deg)';
|
|
|
|
|
+ } else {
|
|
|
|
|
+ arrow.style.top = '-6px';
|
|
|
|
|
+ arrow.style.bottom = 'auto';
|
|
|
|
|
+ arrow.style.transform = 'rotate(45deg)';
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- document.body.appendChild(popover);
|
|
|
|
|
currentPopover = popover;
|
|
currentPopover = popover;
|
|
|
}
|
|
}
|
|
|
|
|
|