myio-js-library 0.1.197 → 0.1.199
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/dist/index.cjs +1381 -372
- package/dist/index.d.cts +96 -1
- package/dist/index.js +1380 -372
- package/dist/myio-js-library.umd.js +1380 -372
- package/dist/myio-js-library.umd.min.js +1 -1
- package/package.json +1 -1
|
@@ -8863,8 +8863,8 @@
|
|
|
8863
8863
|
return "dot--offline";
|
|
8864
8864
|
}
|
|
8865
8865
|
}
|
|
8866
|
-
function buildDOM(
|
|
8867
|
-
const { entityObject, i18n, enableSelection, enableDragDrop } =
|
|
8866
|
+
function buildDOM(state6) {
|
|
8867
|
+
const { entityObject, i18n, enableSelection, enableDragDrop } = state6;
|
|
8868
8868
|
const root = document.createElement("div");
|
|
8869
8869
|
root.className = "myio-ho-card";
|
|
8870
8870
|
root.setAttribute("role", "group");
|
|
@@ -9020,7 +9020,7 @@
|
|
|
9020
9020
|
return root;
|
|
9021
9021
|
}
|
|
9022
9022
|
function buildDebugTooltipInfo(entityObject, statusInfo, stateClass, statusDecisionSource, delayTimeConnectionInMins) {
|
|
9023
|
-
const
|
|
9023
|
+
const formatTimestamp6 = (ts) => {
|
|
9024
9024
|
if (!ts) return "N/A";
|
|
9025
9025
|
const d = new Date(ts);
|
|
9026
9026
|
return d.toLocaleString("pt-BR", {
|
|
@@ -9047,8 +9047,8 @@
|
|
|
9047
9047
|
chipClass: statusInfo.chipClass,
|
|
9048
9048
|
chipLabel: statusInfo.label,
|
|
9049
9049
|
// Connection timestamps
|
|
9050
|
-
lastConnectTime:
|
|
9051
|
-
lastDisconnectTime:
|
|
9050
|
+
lastConnectTime: formatTimestamp6(entityObject.lastConnectTime),
|
|
9051
|
+
lastDisconnectTime: formatTimestamp6(entityObject.lastDisconnectTime),
|
|
9052
9052
|
delayTimeConnectionInMins,
|
|
9053
9053
|
// Raw values
|
|
9054
9054
|
val: entityObject.val,
|
|
@@ -9190,8 +9190,8 @@
|
|
|
9190
9190
|
}
|
|
9191
9191
|
return isOffline;
|
|
9192
9192
|
}
|
|
9193
|
-
function paint(root,
|
|
9194
|
-
const { entityObject, i18n, delayTimeConnectionInMins, isSelected, LogHelper: LogHelper2, activeTooltipDebug } =
|
|
9193
|
+
function paint(root, state6) {
|
|
9194
|
+
const { entityObject, i18n, delayTimeConnectionInMins, isSelected, LogHelper: LogHelper2, activeTooltipDebug } = state6;
|
|
9195
9195
|
let statusDecisionSource = "unknown";
|
|
9196
9196
|
if (entityObject.connectionStatus) {
|
|
9197
9197
|
if (entityObject.connectionStatus === "offline") {
|
|
@@ -9243,7 +9243,7 @@
|
|
|
9243
9243
|
numSpan.textContent = primaryValue;
|
|
9244
9244
|
const barContainer = root.querySelector(".bar");
|
|
9245
9245
|
const effContainer = root.querySelector(".myio-ho-card__eff");
|
|
9246
|
-
if (
|
|
9246
|
+
if (state6.enableSelection) {
|
|
9247
9247
|
const checkbox = root.querySelector('.myio-ho-card__select input[type="checkbox"]');
|
|
9248
9248
|
if (checkbox) {
|
|
9249
9249
|
checkbox.checked = !!isSelected;
|
|
@@ -9291,8 +9291,8 @@
|
|
|
9291
9291
|
statusDot.className = `status-dot ${dotClass}`;
|
|
9292
9292
|
}
|
|
9293
9293
|
}
|
|
9294
|
-
function bindEvents(root,
|
|
9295
|
-
const { entityObject } =
|
|
9294
|
+
function bindEvents(root, state6, callbacks) {
|
|
9295
|
+
const { entityObject } = state6;
|
|
9296
9296
|
const kebabBtn = root.querySelector(".myio-ho-card__kebab");
|
|
9297
9297
|
const menu = root.querySelector(".myio-ho-card__menu");
|
|
9298
9298
|
function toggleMenu() {
|
|
@@ -9348,9 +9348,9 @@
|
|
|
9348
9348
|
const onSelectionChange = () => {
|
|
9349
9349
|
const selectedIds = MyIOSelectionStore2.getSelectedIds();
|
|
9350
9350
|
const isSelected = selectedIds.includes(entityObject.entityId);
|
|
9351
|
-
if (
|
|
9352
|
-
|
|
9353
|
-
paint(root,
|
|
9351
|
+
if (state6.isSelected !== isSelected) {
|
|
9352
|
+
state6.isSelected = isSelected;
|
|
9353
|
+
paint(root, state6);
|
|
9354
9354
|
}
|
|
9355
9355
|
};
|
|
9356
9356
|
MyIOSelectionStore2.on("selection:change", onSelectionChange);
|
|
@@ -9363,7 +9363,7 @@
|
|
|
9363
9363
|
clearTimeout(TempRangeTooltip._hideTimer);
|
|
9364
9364
|
TempRangeTooltip._hideTimer = null;
|
|
9365
9365
|
}
|
|
9366
|
-
TempRangeTooltip.show(root,
|
|
9366
|
+
TempRangeTooltip.show(root, state6.entityObject, e);
|
|
9367
9367
|
};
|
|
9368
9368
|
const hideTooltip = () => {
|
|
9369
9369
|
TempRangeTooltip._startDelayedHide();
|
|
@@ -9381,7 +9381,7 @@
|
|
|
9381
9381
|
clearTimeout(EnergyRangeTooltip._hideTimer);
|
|
9382
9382
|
EnergyRangeTooltip._hideTimer = null;
|
|
9383
9383
|
}
|
|
9384
|
-
EnergyRangeTooltip.show(root,
|
|
9384
|
+
EnergyRangeTooltip.show(root, state6.entityObject, e);
|
|
9385
9385
|
};
|
|
9386
9386
|
const hideEnergyTooltip = () => {
|
|
9387
9387
|
EnergyRangeTooltip._startDelayedHide();
|
|
@@ -9433,7 +9433,7 @@
|
|
|
9433
9433
|
}
|
|
9434
9434
|
});
|
|
9435
9435
|
}
|
|
9436
|
-
if (
|
|
9436
|
+
if (state6.enableDragDrop) {
|
|
9437
9437
|
root.addEventListener("dragstart", (e) => {
|
|
9438
9438
|
root.classList.add("is-dragging");
|
|
9439
9439
|
e.dataTransfer.setData("text/plain", entityObject.entityId);
|
|
@@ -9475,17 +9475,17 @@
|
|
|
9475
9475
|
throw new Error("renderCardComponentHeadOffice: containerEl is required");
|
|
9476
9476
|
}
|
|
9477
9477
|
ensureCss();
|
|
9478
|
-
const
|
|
9479
|
-
const root = buildDOM(
|
|
9480
|
-
|
|
9478
|
+
const state6 = normalizeParams(params);
|
|
9479
|
+
const root = buildDOM(state6);
|
|
9480
|
+
state6.isSelected = params.isSelected || false;
|
|
9481
9481
|
containerEl.appendChild(root);
|
|
9482
|
-
bindEvents(root,
|
|
9483
|
-
paint(root,
|
|
9482
|
+
bindEvents(root, state6, state6.callbacks);
|
|
9483
|
+
paint(root, state6);
|
|
9484
9484
|
return {
|
|
9485
9485
|
update(next) {
|
|
9486
9486
|
if (next) {
|
|
9487
|
-
Object.assign(
|
|
9488
|
-
paint(root,
|
|
9487
|
+
Object.assign(state6.entityObject, next);
|
|
9488
|
+
paint(root, state6);
|
|
9489
9489
|
}
|
|
9490
9490
|
},
|
|
9491
9491
|
destroy() {
|
|
@@ -11215,6 +11215,15 @@
|
|
|
11215
11215
|
return { deviation: absDeviation, sign: "-", status: "below", statusText: "Abaixo da media", statusIcon: "\u{1F53B}" };
|
|
11216
11216
|
}
|
|
11217
11217
|
}
|
|
11218
|
+
function calculateRangeStatus(currentTemp, minTemp, maxTemp) {
|
|
11219
|
+
if (currentTemp >= minTemp && currentTemp <= maxTemp) {
|
|
11220
|
+
return { status: "ok", statusText: "Dentro da faixa", statusIcon: "\u2713" };
|
|
11221
|
+
} else if (currentTemp > maxTemp) {
|
|
11222
|
+
return { status: "above", statusText: "Acima da faixa", statusIcon: "\u{1F53A}" };
|
|
11223
|
+
} else {
|
|
11224
|
+
return { status: "below", statusText: "Abaixo da faixa", statusIcon: "\u{1F53B}" };
|
|
11225
|
+
}
|
|
11226
|
+
}
|
|
11218
11227
|
function calcTempBarPosition(temp, minRange, maxRange) {
|
|
11219
11228
|
const rangeSize = maxRange - minRange;
|
|
11220
11229
|
const extendedMin = minRange - rangeSize * 0.3;
|
|
@@ -11257,8 +11266,10 @@
|
|
|
11257
11266
|
const { device, average, lastUpdated } = data;
|
|
11258
11267
|
const timestamp = formatTimestamp2(lastUpdated);
|
|
11259
11268
|
const tempStatus = calculateTempStatus(device.currentTemp, average.value);
|
|
11269
|
+
const rangeStatus = calculateRangeStatus(device.currentTemp, device.minTemp, device.maxTemp);
|
|
11260
11270
|
const deviceBarPos = calcTempBarPosition(device.currentTemp, device.minTemp, device.maxTemp);
|
|
11261
11271
|
const avgBarPos = calcTempBarPosition(average.value, device.minTemp, device.maxTemp);
|
|
11272
|
+
const rangeStatusClass = rangeStatus.status === "ok" ? "normal" : rangeStatus.status;
|
|
11262
11273
|
return `
|
|
11263
11274
|
<div class="myio-temp-comparison-tooltip__body">
|
|
11264
11275
|
<!-- Main Stats -->
|
|
@@ -11273,12 +11284,18 @@
|
|
|
11273
11284
|
</div>
|
|
11274
11285
|
</div>
|
|
11275
11286
|
|
|
11276
|
-
<!-- Configured Range -->
|
|
11287
|
+
<!-- Configured Range with Status -->
|
|
11277
11288
|
<div class="myio-temp-comparison-tooltip__range">
|
|
11278
11289
|
<span class="myio-temp-comparison-tooltip__range-label">Faixa Ideal:</span>
|
|
11279
11290
|
<span class="myio-temp-comparison-tooltip__range-value">${formatTemp(device.minTemp)} - ${formatTemp(device.maxTemp)}</span>
|
|
11280
11291
|
</div>
|
|
11281
11292
|
|
|
11293
|
+
<!-- Range Status Indicator -->
|
|
11294
|
+
<div class="myio-temp-comparison-tooltip__status ${rangeStatusClass}">
|
|
11295
|
+
<span class="myio-temp-comparison-tooltip__status-icon">${rangeStatus.statusIcon}</span>
|
|
11296
|
+
<span>${rangeStatus.statusText}</span>
|
|
11297
|
+
</div>
|
|
11298
|
+
|
|
11282
11299
|
<!-- Section: Average Comparison -->
|
|
11283
11300
|
<div class="myio-temp-comparison-tooltip__section-title">
|
|
11284
11301
|
<span class="myio-temp-comparison-tooltip__section-icon">\u{1F4CA}</span>
|
|
@@ -30614,7 +30631,7 @@
|
|
|
30614
30631
|
const defaultDateRange = getTodaySoFar();
|
|
30615
30632
|
const startTs = params.startDate ? new Date(params.startDate).getTime() : defaultDateRange.startTs;
|
|
30616
30633
|
const endTs = params.endDate ? new Date(params.endDate).getTime() : defaultDateRange.endTs;
|
|
30617
|
-
const
|
|
30634
|
+
const state6 = {
|
|
30618
30635
|
token: params.token,
|
|
30619
30636
|
deviceId: params.deviceId,
|
|
30620
30637
|
label: params.label || "Sensor de Temperatura",
|
|
@@ -30637,58 +30654,58 @@
|
|
|
30637
30654
|
};
|
|
30638
30655
|
const savedGranularity = localStorage.getItem("myio-temp-modal-granularity");
|
|
30639
30656
|
const savedTheme = localStorage.getItem("myio-temp-modal-theme");
|
|
30640
|
-
if (savedGranularity)
|
|
30641
|
-
if (savedTheme)
|
|
30657
|
+
if (savedGranularity) state6.granularity = savedGranularity;
|
|
30658
|
+
if (savedTheme) state6.theme = savedTheme;
|
|
30642
30659
|
const modalContainer = document.createElement("div");
|
|
30643
30660
|
modalContainer.id = modalId;
|
|
30644
30661
|
document.body.appendChild(modalContainer);
|
|
30645
|
-
renderModal(modalContainer,
|
|
30662
|
+
renderModal(modalContainer, state6, modalId);
|
|
30646
30663
|
try {
|
|
30647
|
-
|
|
30648
|
-
|
|
30649
|
-
|
|
30650
|
-
renderModal(modalContainer,
|
|
30651
|
-
drawChart(modalId,
|
|
30664
|
+
state6.data = await fetchTemperatureData(state6.token, state6.deviceId, state6.startTs, state6.endTs);
|
|
30665
|
+
state6.stats = calculateStats(state6.data, state6.clampRange);
|
|
30666
|
+
state6.isLoading = false;
|
|
30667
|
+
renderModal(modalContainer, state6, modalId);
|
|
30668
|
+
drawChart(modalId, state6);
|
|
30652
30669
|
} catch (error) {
|
|
30653
30670
|
console.error("[TemperatureModal] Error fetching data:", error);
|
|
30654
|
-
|
|
30655
|
-
renderModal(modalContainer,
|
|
30671
|
+
state6.isLoading = false;
|
|
30672
|
+
renderModal(modalContainer, state6, modalId, error);
|
|
30656
30673
|
}
|
|
30657
|
-
await setupEventListeners(modalContainer,
|
|
30674
|
+
await setupEventListeners(modalContainer, state6, modalId, params.onClose);
|
|
30658
30675
|
return {
|
|
30659
30676
|
destroy: () => {
|
|
30660
30677
|
modalContainer.remove();
|
|
30661
30678
|
params.onClose?.();
|
|
30662
30679
|
},
|
|
30663
30680
|
updateData: async (startDate, endDate, granularity) => {
|
|
30664
|
-
|
|
30665
|
-
|
|
30666
|
-
if (granularity)
|
|
30667
|
-
|
|
30668
|
-
renderModal(modalContainer,
|
|
30681
|
+
state6.startTs = new Date(startDate).getTime();
|
|
30682
|
+
state6.endTs = new Date(endDate).getTime();
|
|
30683
|
+
if (granularity) state6.granularity = granularity;
|
|
30684
|
+
state6.isLoading = true;
|
|
30685
|
+
renderModal(modalContainer, state6, modalId);
|
|
30669
30686
|
try {
|
|
30670
|
-
|
|
30671
|
-
|
|
30672
|
-
|
|
30673
|
-
renderModal(modalContainer,
|
|
30674
|
-
drawChart(modalId,
|
|
30687
|
+
state6.data = await fetchTemperatureData(state6.token, state6.deviceId, state6.startTs, state6.endTs);
|
|
30688
|
+
state6.stats = calculateStats(state6.data, state6.clampRange);
|
|
30689
|
+
state6.isLoading = false;
|
|
30690
|
+
renderModal(modalContainer, state6, modalId);
|
|
30691
|
+
drawChart(modalId, state6);
|
|
30675
30692
|
} catch (error) {
|
|
30676
30693
|
console.error("[TemperatureModal] Error updating data:", error);
|
|
30677
|
-
|
|
30678
|
-
renderModal(modalContainer,
|
|
30694
|
+
state6.isLoading = false;
|
|
30695
|
+
renderModal(modalContainer, state6, modalId, error);
|
|
30679
30696
|
}
|
|
30680
30697
|
}
|
|
30681
30698
|
};
|
|
30682
30699
|
}
|
|
30683
|
-
function renderModal(container,
|
|
30684
|
-
const colors = getThemeColors(
|
|
30685
|
-
const startDateStr = new Date(
|
|
30686
|
-
const endDateStr = new Date(
|
|
30687
|
-
const statusText =
|
|
30688
|
-
const statusColor =
|
|
30689
|
-
const rangeText =
|
|
30690
|
-
new Date(
|
|
30691
|
-
new Date(
|
|
30700
|
+
function renderModal(container, state6, modalId, error) {
|
|
30701
|
+
const colors = getThemeColors(state6.theme);
|
|
30702
|
+
const startDateStr = new Date(state6.startTs).toLocaleDateString(state6.locale);
|
|
30703
|
+
const endDateStr = new Date(state6.endTs).toLocaleDateString(state6.locale);
|
|
30704
|
+
const statusText = state6.temperatureStatus === "ok" ? "Dentro da faixa" : state6.temperatureStatus === "above" ? "Acima do limite" : state6.temperatureStatus === "below" ? "Abaixo do limite" : "N/A";
|
|
30705
|
+
const statusColor = state6.temperatureStatus === "ok" ? colors.success : state6.temperatureStatus === "above" ? colors.danger : state6.temperatureStatus === "below" ? colors.primary : colors.textMuted;
|
|
30706
|
+
const rangeText = state6.temperatureMin !== null && state6.temperatureMax !== null ? `${state6.temperatureMin}\xB0C - ${state6.temperatureMax}\xB0C` : "N\xE3o definida";
|
|
30707
|
+
new Date(state6.startTs).toISOString().slice(0, 16);
|
|
30708
|
+
new Date(state6.endTs).toISOString().slice(0, 16);
|
|
30692
30709
|
const isMaximized = container.__isMaximized || false;
|
|
30693
30710
|
const contentMaxWidth = isMaximized ? "100%" : "900px";
|
|
30694
30711
|
const contentMaxHeight = isMaximized ? "100vh" : "95vh";
|
|
@@ -30715,7 +30732,7 @@
|
|
|
30715
30732
|
min-height: 20px;
|
|
30716
30733
|
">
|
|
30717
30734
|
<h2 style="margin: 6px; font-size: 18px; font-weight: 600; color: white; line-height: 2;">
|
|
30718
|
-
\u{1F321}\uFE0F ${
|
|
30735
|
+
\u{1F321}\uFE0F ${state6.label} - Hist\xF3rico de Temperatura
|
|
30719
30736
|
</h2>
|
|
30720
30737
|
<div style="display: flex; gap: 4px; align-items: center;">
|
|
30721
30738
|
<!-- Theme Toggle -->
|
|
@@ -30723,7 +30740,7 @@
|
|
|
30723
30740
|
background: none; border: none; font-size: 16px; cursor: pointer;
|
|
30724
30741
|
padding: 4px 8px; border-radius: 6px; color: rgba(255,255,255,0.8);
|
|
30725
30742
|
transition: background-color 0.2s;
|
|
30726
|
-
">${
|
|
30743
|
+
">${state6.theme === "dark" ? "\u2600\uFE0F" : "\u{1F319}"}</button>
|
|
30727
30744
|
<!-- Maximize Button -->
|
|
30728
30745
|
<button id="${modalId}-maximize" title="${isMaximized ? "Restaurar" : "Maximizar"}" style="
|
|
30729
30746
|
background: none; border: none; font-size: 16px; cursor: pointer;
|
|
@@ -30745,7 +30762,7 @@
|
|
|
30745
30762
|
<!-- Controls Row -->
|
|
30746
30763
|
<div style="
|
|
30747
30764
|
display: flex; gap: 16px; flex-wrap: wrap; align-items: flex-end;
|
|
30748
|
-
margin-bottom: 16px; padding: 16px; background: ${
|
|
30765
|
+
margin-bottom: 16px; padding: 16px; background: ${state6.theme === "dark" ? "rgba(255,255,255,0.05)" : "#f7f7f7"};
|
|
30749
30766
|
border-radius: 6px; border: 1px solid ${colors.border};
|
|
30750
30767
|
">
|
|
30751
30768
|
<!-- Granularity Select -->
|
|
@@ -30758,8 +30775,8 @@
|
|
|
30758
30775
|
font-size: 14px; color: ${colors.text}; background: ${colors.surface};
|
|
30759
30776
|
cursor: pointer; min-width: 130px;
|
|
30760
30777
|
">
|
|
30761
|
-
<option value="hour" ${
|
|
30762
|
-
<option value="day" ${
|
|
30778
|
+
<option value="hour" ${state6.granularity === "hour" ? "selected" : ""}>Hora (30 min)</option>
|
|
30779
|
+
<option value="day" ${state6.granularity === "day" ? "selected" : ""}>Dia (m\xE9dia)</option>
|
|
30763
30780
|
</select>
|
|
30764
30781
|
</div>
|
|
30765
30782
|
<!-- Day Period Filter (Multiselect) -->
|
|
@@ -30773,7 +30790,7 @@
|
|
|
30773
30790
|
cursor: pointer; min-width: 180px; text-align: left;
|
|
30774
30791
|
display: flex; align-items: center; justify-content: space-between; gap: 8px;
|
|
30775
30792
|
">
|
|
30776
|
-
<span>${getSelectedPeriodsLabel(
|
|
30793
|
+
<span>${getSelectedPeriodsLabel(state6.selectedPeriods)}</span>
|
|
30777
30794
|
<span style="font-size: 10px;">\u25BC</span>
|
|
30778
30795
|
</button>
|
|
30779
30796
|
<div id="${modalId}-period-dropdown" style="
|
|
@@ -30786,12 +30803,12 @@
|
|
|
30786
30803
|
<label style="
|
|
30787
30804
|
display: flex; align-items: center; gap: 8px; padding: 8px 12px;
|
|
30788
30805
|
cursor: pointer; font-size: 13px; color: ${colors.text};
|
|
30789
|
-
" onmouseover="this.style.background='${
|
|
30806
|
+
" onmouseover="this.style.background='${state6.theme === "dark" ? "rgba(255,255,255,0.1)" : "#f0f0f0"}'"
|
|
30790
30807
|
onmouseout="this.style.background='transparent'">
|
|
30791
30808
|
<input type="checkbox"
|
|
30792
30809
|
name="${modalId}-period"
|
|
30793
30810
|
value="${period.id}"
|
|
30794
|
-
${
|
|
30811
|
+
${state6.selectedPeriods.includes(period.id) ? "checked" : ""}
|
|
30795
30812
|
style="width: 16px; height: 16px; cursor: pointer; accent-color: #3e1a7d;">
|
|
30796
30813
|
${period.label}
|
|
30797
30814
|
</label>
|
|
@@ -30799,13 +30816,13 @@
|
|
|
30799
30816
|
<div style="border-top: 1px solid ${colors.border}; margin-top: 8px; padding-top: 8px;">
|
|
30800
30817
|
<button id="${modalId}-period-select-all" type="button" style="
|
|
30801
30818
|
width: calc(100% - 16px); margin: 0 8px 4px; padding: 6px;
|
|
30802
|
-
background: ${
|
|
30819
|
+
background: ${state6.theme === "dark" ? "rgba(255,255,255,0.1)" : "#f0f0f0"};
|
|
30803
30820
|
border: none; border-radius: 4px; cursor: pointer;
|
|
30804
30821
|
font-size: 12px; color: ${colors.text};
|
|
30805
30822
|
">Selecionar Todos</button>
|
|
30806
30823
|
<button id="${modalId}-period-clear" type="button" style="
|
|
30807
30824
|
width: calc(100% - 16px); margin: 0 8px; padding: 6px;
|
|
30808
|
-
background: ${
|
|
30825
|
+
background: ${state6.theme === "dark" ? "rgba(255,255,255,0.1)" : "#f0f0f0"};
|
|
30809
30826
|
border: none; border-radius: 4px; cursor: pointer;
|
|
30810
30827
|
font-size: 12px; color: ${colors.text};
|
|
30811
30828
|
">Limpar Sele\xE7\xE3o</button>
|
|
@@ -30830,8 +30847,8 @@
|
|
|
30830
30847
|
font-size: 14px; font-weight: 500; height: 38px;
|
|
30831
30848
|
display: flex; align-items: center; gap: 8px;
|
|
30832
30849
|
font-family: 'Roboto', Arial, sans-serif;
|
|
30833
|
-
" ${
|
|
30834
|
-
${
|
|
30850
|
+
" ${state6.isLoading ? "disabled" : ""}>
|
|
30851
|
+
${state6.isLoading ? '<span style="animation: spin 1s linear infinite; display: inline-block;">\u21BB</span> Carregando...' : "Carregar"}
|
|
30835
30852
|
</button>
|
|
30836
30853
|
</div>
|
|
30837
30854
|
|
|
@@ -30842,40 +30859,40 @@
|
|
|
30842
30859
|
">
|
|
30843
30860
|
<!-- Current Temperature -->
|
|
30844
30861
|
<div style="
|
|
30845
|
-
padding: 16px; background: ${
|
|
30862
|
+
padding: 16px; background: ${state6.theme === "dark" ? "rgba(255,255,255,0.05)" : "#fafafa"};
|
|
30846
30863
|
border-radius: 12px; border: 1px solid ${colors.border};
|
|
30847
30864
|
">
|
|
30848
30865
|
<span style="color: ${colors.textMuted}; font-size: 12px; font-weight: 500;">Temperatura Atual</span>
|
|
30849
30866
|
<div style="font-weight: 700; font-size: 24px; color: ${statusColor}; margin-top: 4px;">
|
|
30850
|
-
${
|
|
30867
|
+
${state6.currentTemperature !== null ? formatTemperature(state6.currentTemperature) : "N/A"}
|
|
30851
30868
|
</div>
|
|
30852
30869
|
<div style="font-size: 11px; color: ${statusColor}; margin-top: 2px;">${statusText}</div>
|
|
30853
30870
|
</div>
|
|
30854
30871
|
<!-- Average -->
|
|
30855
30872
|
<div style="
|
|
30856
|
-
padding: 16px; background: ${
|
|
30873
|
+
padding: 16px; background: ${state6.theme === "dark" ? "rgba(255,255,255,0.05)" : "#fafafa"};
|
|
30857
30874
|
border-radius: 12px; border: 1px solid ${colors.border};
|
|
30858
30875
|
">
|
|
30859
30876
|
<span style="color: ${colors.textMuted}; font-size: 12px; font-weight: 500;">M\xE9dia do Per\xEDodo</span>
|
|
30860
30877
|
<div id="${modalId}-avg" style="font-weight: 600; font-size: 20px; color: ${colors.text}; margin-top: 4px;">
|
|
30861
|
-
${
|
|
30878
|
+
${state6.stats.count > 0 ? formatTemperature(state6.stats.avg) : "N/A"}
|
|
30862
30879
|
</div>
|
|
30863
30880
|
<div style="font-size: 11px; color: ${colors.textMuted}; margin-top: 2px;">${startDateStr} - ${endDateStr}</div>
|
|
30864
30881
|
</div>
|
|
30865
30882
|
<!-- Min/Max -->
|
|
30866
30883
|
<div style="
|
|
30867
|
-
padding: 16px; background: ${
|
|
30884
|
+
padding: 16px; background: ${state6.theme === "dark" ? "rgba(255,255,255,0.05)" : "#fafafa"};
|
|
30868
30885
|
border-radius: 12px; border: 1px solid ${colors.border};
|
|
30869
30886
|
">
|
|
30870
30887
|
<span style="color: ${colors.textMuted}; font-size: 12px; font-weight: 500;">Min / Max</span>
|
|
30871
30888
|
<div id="${modalId}-minmax" style="font-weight: 600; font-size: 20px; color: ${colors.text}; margin-top: 4px;">
|
|
30872
|
-
${
|
|
30889
|
+
${state6.stats.count > 0 ? `${formatTemperature(state6.stats.min)} / ${formatTemperature(state6.stats.max)}` : "N/A"}
|
|
30873
30890
|
</div>
|
|
30874
|
-
<div style="font-size: 11px; color: ${colors.textMuted}; margin-top: 2px;">${
|
|
30891
|
+
<div style="font-size: 11px; color: ${colors.textMuted}; margin-top: 2px;">${state6.stats.count} leituras</div>
|
|
30875
30892
|
</div>
|
|
30876
30893
|
<!-- Ideal Range -->
|
|
30877
30894
|
<div style="
|
|
30878
|
-
padding: 16px; background: ${
|
|
30895
|
+
padding: 16px; background: ${state6.theme === "dark" ? "rgba(255,255,255,0.05)" : "#fafafa"};
|
|
30879
30896
|
border-radius: 12px; border: 1px solid ${colors.border};
|
|
30880
30897
|
">
|
|
30881
30898
|
<span style="color: ${colors.textMuted}; font-size: 12px; font-weight: 500;">Faixa Ideal</span>
|
|
@@ -30891,18 +30908,18 @@
|
|
|
30891
30908
|
Hist\xF3rico de Temperatura
|
|
30892
30909
|
</h3>
|
|
30893
30910
|
<div id="${modalId}-chart" style="
|
|
30894
|
-
height: 320px; background: ${
|
|
30911
|
+
height: 320px; background: ${state6.theme === "dark" ? "rgba(255,255,255,0.03)" : "#fafafa"};
|
|
30895
30912
|
border-radius: 12px; display: flex; justify-content: center; align-items: center;
|
|
30896
30913
|
border: 1px solid ${colors.border}; position: relative;
|
|
30897
30914
|
">
|
|
30898
|
-
${
|
|
30915
|
+
${state6.isLoading ? `<div style="text-align: center; color: ${colors.textMuted};">
|
|
30899
30916
|
<div style="animation: spin 1s linear infinite; font-size: 32px; margin-bottom: 8px;">\u21BB</div>
|
|
30900
30917
|
<div>Carregando dados...</div>
|
|
30901
30918
|
</div>` : error ? `<div style="text-align: center; color: ${colors.danger};">
|
|
30902
30919
|
<div style="font-size: 32px; margin-bottom: 8px;">\u26A0\uFE0F</div>
|
|
30903
30920
|
<div>Erro ao carregar dados</div>
|
|
30904
30921
|
<div style="font-size: 12px; margin-top: 4px;">${error.message}</div>
|
|
30905
|
-
</div>` :
|
|
30922
|
+
</div>` : state6.data.length === 0 ? `<div style="text-align: center; color: ${colors.textMuted};">
|
|
30906
30923
|
<div style="font-size: 32px; margin-bottom: 8px;">\u{1F4ED}</div>
|
|
30907
30924
|
<div>Sem dados para o per\xEDodo selecionado</div>
|
|
30908
30925
|
</div>` : `<canvas id="${modalId}-canvas" style="width: 100%; height: 100%;"></canvas>`}
|
|
@@ -30912,12 +30929,12 @@
|
|
|
30912
30929
|
<!-- Actions -->
|
|
30913
30930
|
<div style="display: flex; justify-content: flex-end; gap: 12px;">
|
|
30914
30931
|
<button id="${modalId}-export" style="
|
|
30915
|
-
background: ${
|
|
30932
|
+
background: ${state6.theme === "dark" ? "rgba(255,255,255,0.1)" : "#f7f7f7"};
|
|
30916
30933
|
color: ${colors.text}; border: 1px solid ${colors.border};
|
|
30917
30934
|
padding: 8px 16px; border-radius: 6px; cursor: pointer;
|
|
30918
30935
|
font-size: 14px; display: flex; align-items: center; gap: 8px;
|
|
30919
30936
|
font-family: 'Roboto', Arial, sans-serif;
|
|
30920
|
-
" ${
|
|
30937
|
+
" ${state6.data.length === 0 ? "disabled" : ""}>
|
|
30921
30938
|
\u{1F4E5} Exportar CSV
|
|
30922
30939
|
</button>
|
|
30923
30940
|
<button id="${modalId}-close-btn" style="
|
|
@@ -30968,14 +30985,14 @@
|
|
|
30968
30985
|
</style>
|
|
30969
30986
|
`;
|
|
30970
30987
|
}
|
|
30971
|
-
function drawChart(modalId,
|
|
30988
|
+
function drawChart(modalId, state6) {
|
|
30972
30989
|
const chartContainer = document.getElementById(`${modalId}-chart`);
|
|
30973
30990
|
const canvas = document.getElementById(`${modalId}-canvas`);
|
|
30974
|
-
if (!chartContainer || !canvas ||
|
|
30991
|
+
if (!chartContainer || !canvas || state6.data.length === 0) return;
|
|
30975
30992
|
const ctx = canvas.getContext("2d");
|
|
30976
30993
|
if (!ctx) return;
|
|
30977
|
-
const colors = getThemeColors(
|
|
30978
|
-
const filteredData = filterByDayPeriods(
|
|
30994
|
+
const colors = getThemeColors(state6.theme);
|
|
30995
|
+
const filteredData = filterByDayPeriods(state6.data, state6.selectedPeriods);
|
|
30979
30996
|
if (filteredData.length === 0) {
|
|
30980
30997
|
canvas.width = chartContainer.clientWidth;
|
|
30981
30998
|
canvas.height = chartContainer.clientHeight;
|
|
@@ -30986,14 +31003,14 @@
|
|
|
30986
31003
|
return;
|
|
30987
31004
|
}
|
|
30988
31005
|
let chartData;
|
|
30989
|
-
if (
|
|
31006
|
+
if (state6.granularity === "hour") {
|
|
30990
31007
|
const interpolated = interpolateTemperature(filteredData, {
|
|
30991
31008
|
intervalMinutes: 30,
|
|
30992
|
-
startTs:
|
|
30993
|
-
endTs:
|
|
30994
|
-
clampRange:
|
|
31009
|
+
startTs: state6.startTs,
|
|
31010
|
+
endTs: state6.endTs,
|
|
31011
|
+
clampRange: state6.clampRange
|
|
30995
31012
|
});
|
|
30996
|
-
const filteredInterpolated = filterByDayPeriods(interpolated,
|
|
31013
|
+
const filteredInterpolated = filterByDayPeriods(interpolated, state6.selectedPeriods);
|
|
30997
31014
|
chartData = filteredInterpolated.map((item) => ({
|
|
30998
31015
|
x: item.ts,
|
|
30999
31016
|
y: Number(item.value),
|
|
@@ -31001,7 +31018,7 @@
|
|
|
31001
31018
|
screenY: 0
|
|
31002
31019
|
}));
|
|
31003
31020
|
} else {
|
|
31004
|
-
const daily = aggregateByDay(filteredData,
|
|
31021
|
+
const daily = aggregateByDay(filteredData, state6.clampRange);
|
|
31005
31022
|
chartData = daily.map((item) => ({
|
|
31006
31023
|
x: item.dateTs,
|
|
31007
31024
|
y: item.avg,
|
|
@@ -31019,12 +31036,12 @@
|
|
|
31019
31036
|
const paddingRight = 20;
|
|
31020
31037
|
const paddingTop = 20;
|
|
31021
31038
|
const paddingBottom = 55;
|
|
31022
|
-
const isPeriodsFiltered =
|
|
31039
|
+
const isPeriodsFiltered = state6.selectedPeriods.length < 4 && state6.selectedPeriods.length > 0;
|
|
31023
31040
|
const values = chartData.map((d) => d.y);
|
|
31024
31041
|
const dataMin = Math.min(...values);
|
|
31025
31042
|
const dataMax = Math.max(...values);
|
|
31026
|
-
const thresholdMin =
|
|
31027
|
-
const thresholdMax =
|
|
31043
|
+
const thresholdMin = state6.temperatureMin !== null ? state6.temperatureMin : dataMin;
|
|
31044
|
+
const thresholdMax = state6.temperatureMax !== null ? state6.temperatureMax : dataMax;
|
|
31028
31045
|
const minY = Math.min(dataMin, thresholdMin) - 1;
|
|
31029
31046
|
const maxY = Math.max(dataMax, thresholdMax) + 1;
|
|
31030
31047
|
const chartWidth = width - paddingLeft - paddingRight;
|
|
@@ -31056,9 +31073,9 @@
|
|
|
31056
31073
|
ctx.lineTo(width - paddingRight, y);
|
|
31057
31074
|
ctx.stroke();
|
|
31058
31075
|
}
|
|
31059
|
-
if (
|
|
31060
|
-
const rangeMinY = height - paddingBottom - (
|
|
31061
|
-
const rangeMaxY = height - paddingBottom - (
|
|
31076
|
+
if (state6.temperatureMin !== null && state6.temperatureMax !== null) {
|
|
31077
|
+
const rangeMinY = height - paddingBottom - (state6.temperatureMin - minY) * scaleY;
|
|
31078
|
+
const rangeMaxY = height - paddingBottom - (state6.temperatureMax - minY) * scaleY;
|
|
31062
31079
|
ctx.fillStyle = "rgba(76, 175, 80, 0.1)";
|
|
31063
31080
|
ctx.fillRect(paddingLeft, rangeMaxY, chartWidth, rangeMinY - rangeMaxY);
|
|
31064
31081
|
ctx.strokeStyle = colors.success;
|
|
@@ -31100,10 +31117,10 @@
|
|
|
31100
31117
|
const point = chartData[i];
|
|
31101
31118
|
const date = new Date(point.x);
|
|
31102
31119
|
let label;
|
|
31103
|
-
if (
|
|
31104
|
-
label = date.toLocaleTimeString(
|
|
31120
|
+
if (state6.granularity === "hour") {
|
|
31121
|
+
label = date.toLocaleTimeString(state6.locale, { hour: "2-digit", minute: "2-digit" });
|
|
31105
31122
|
} else {
|
|
31106
|
-
label = date.toLocaleDateString(
|
|
31123
|
+
label = date.toLocaleDateString(state6.locale, { day: "2-digit", month: "2-digit" });
|
|
31107
31124
|
}
|
|
31108
31125
|
ctx.strokeStyle = colors.chartGrid;
|
|
31109
31126
|
ctx.lineWidth = 1;
|
|
@@ -31121,16 +31138,16 @@
|
|
|
31121
31138
|
ctx.lineTo(paddingLeft, height - paddingBottom);
|
|
31122
31139
|
ctx.lineTo(width - paddingRight, height - paddingBottom);
|
|
31123
31140
|
ctx.stroke();
|
|
31124
|
-
setupChartTooltip(canvas, chartContainer, chartData,
|
|
31141
|
+
setupChartTooltip(canvas, chartContainer, chartData, state6, colors);
|
|
31125
31142
|
}
|
|
31126
|
-
function setupChartTooltip(canvas, container, chartData,
|
|
31143
|
+
function setupChartTooltip(canvas, container, chartData, state6, colors) {
|
|
31127
31144
|
const existingTooltip = container.querySelector(".myio-chart-tooltip");
|
|
31128
31145
|
if (existingTooltip) existingTooltip.remove();
|
|
31129
31146
|
const tooltip = document.createElement("div");
|
|
31130
31147
|
tooltip.className = "myio-chart-tooltip";
|
|
31131
31148
|
tooltip.style.cssText = `
|
|
31132
31149
|
position: absolute;
|
|
31133
|
-
background: ${
|
|
31150
|
+
background: ${state6.theme === "dark" ? "rgba(30, 30, 40, 0.95)" : "rgba(255, 255, 255, 0.98)"};
|
|
31134
31151
|
border: 1px solid ${colors.border};
|
|
31135
31152
|
border-radius: 8px;
|
|
31136
31153
|
padding: 10px 14px;
|
|
@@ -31167,17 +31184,17 @@
|
|
|
31167
31184
|
if (point) {
|
|
31168
31185
|
const date = new Date(point.x);
|
|
31169
31186
|
let dateStr;
|
|
31170
|
-
if (
|
|
31171
|
-
dateStr = date.toLocaleDateString(
|
|
31187
|
+
if (state6.granularity === "hour") {
|
|
31188
|
+
dateStr = date.toLocaleDateString(state6.locale, {
|
|
31172
31189
|
day: "2-digit",
|
|
31173
31190
|
month: "2-digit",
|
|
31174
31191
|
year: "numeric"
|
|
31175
|
-
}) + " " + date.toLocaleTimeString(
|
|
31192
|
+
}) + " " + date.toLocaleTimeString(state6.locale, {
|
|
31176
31193
|
hour: "2-digit",
|
|
31177
31194
|
minute: "2-digit"
|
|
31178
31195
|
});
|
|
31179
31196
|
} else {
|
|
31180
|
-
dateStr = date.toLocaleDateString(
|
|
31197
|
+
dateStr = date.toLocaleDateString(state6.locale, {
|
|
31181
31198
|
day: "2-digit",
|
|
31182
31199
|
month: "2-digit",
|
|
31183
31200
|
year: "numeric"
|
|
@@ -31215,7 +31232,7 @@
|
|
|
31215
31232
|
canvas.style.cursor = "default";
|
|
31216
31233
|
});
|
|
31217
31234
|
}
|
|
31218
|
-
async function setupEventListeners(container,
|
|
31235
|
+
async function setupEventListeners(container, state6, modalId, onClose) {
|
|
31219
31236
|
const closeModal = () => {
|
|
31220
31237
|
container.remove();
|
|
31221
31238
|
onClose?.();
|
|
@@ -31226,19 +31243,19 @@
|
|
|
31226
31243
|
document.getElementById(`${modalId}-close`)?.addEventListener("click", closeModal);
|
|
31227
31244
|
document.getElementById(`${modalId}-close-btn`)?.addEventListener("click", closeModal);
|
|
31228
31245
|
const dateRangeInput = document.getElementById(`${modalId}-date-range`);
|
|
31229
|
-
if (dateRangeInput && !
|
|
31246
|
+
if (dateRangeInput && !state6.dateRangePicker) {
|
|
31230
31247
|
try {
|
|
31231
|
-
|
|
31232
|
-
presetStart: new Date(
|
|
31233
|
-
presetEnd: new Date(
|
|
31248
|
+
state6.dateRangePicker = await createDateRangePicker2(dateRangeInput, {
|
|
31249
|
+
presetStart: new Date(state6.startTs).toISOString(),
|
|
31250
|
+
presetEnd: new Date(state6.endTs).toISOString(),
|
|
31234
31251
|
includeTime: true,
|
|
31235
31252
|
timePrecision: "minute",
|
|
31236
31253
|
maxRangeDays: 90,
|
|
31237
|
-
locale:
|
|
31254
|
+
locale: state6.locale,
|
|
31238
31255
|
parentEl: container.querySelector(".myio-temp-modal-content"),
|
|
31239
31256
|
onApply: (result) => {
|
|
31240
|
-
|
|
31241
|
-
|
|
31257
|
+
state6.startTs = new Date(result.startISO).getTime();
|
|
31258
|
+
state6.endTs = new Date(result.endISO).getTime();
|
|
31242
31259
|
console.log("[TemperatureModal] Date range applied:", result);
|
|
31243
31260
|
}
|
|
31244
31261
|
});
|
|
@@ -31247,19 +31264,19 @@
|
|
|
31247
31264
|
}
|
|
31248
31265
|
}
|
|
31249
31266
|
document.getElementById(`${modalId}-theme-toggle`)?.addEventListener("click", async () => {
|
|
31250
|
-
|
|
31251
|
-
localStorage.setItem("myio-temp-modal-theme",
|
|
31252
|
-
|
|
31253
|
-
renderModal(container,
|
|
31254
|
-
if (
|
|
31255
|
-
await setupEventListeners(container,
|
|
31267
|
+
state6.theme = state6.theme === "dark" ? "light" : "dark";
|
|
31268
|
+
localStorage.setItem("myio-temp-modal-theme", state6.theme);
|
|
31269
|
+
state6.dateRangePicker = null;
|
|
31270
|
+
renderModal(container, state6, modalId);
|
|
31271
|
+
if (state6.data.length > 0) drawChart(modalId, state6);
|
|
31272
|
+
await setupEventListeners(container, state6, modalId, onClose);
|
|
31256
31273
|
});
|
|
31257
31274
|
document.getElementById(`${modalId}-maximize`)?.addEventListener("click", async () => {
|
|
31258
31275
|
container.__isMaximized = !container.__isMaximized;
|
|
31259
|
-
|
|
31260
|
-
renderModal(container,
|
|
31261
|
-
if (
|
|
31262
|
-
await setupEventListeners(container,
|
|
31276
|
+
state6.dateRangePicker = null;
|
|
31277
|
+
renderModal(container, state6, modalId);
|
|
31278
|
+
if (state6.data.length > 0) drawChart(modalId, state6);
|
|
31279
|
+
await setupEventListeners(container, state6, modalId, onClose);
|
|
31263
31280
|
});
|
|
31264
31281
|
const periodBtn = document.getElementById(`${modalId}-period-btn`);
|
|
31265
31282
|
const periodDropdown = document.getElementById(`${modalId}-period-dropdown`);
|
|
@@ -31278,71 +31295,71 @@
|
|
|
31278
31295
|
periodCheckboxes.forEach((checkbox) => {
|
|
31279
31296
|
checkbox.addEventListener("change", () => {
|
|
31280
31297
|
const checked = Array.from(periodCheckboxes).filter((cb) => cb.checked).map((cb) => cb.value);
|
|
31281
|
-
|
|
31298
|
+
state6.selectedPeriods = checked;
|
|
31282
31299
|
const btnLabel = periodBtn?.querySelector("span:first-child");
|
|
31283
31300
|
if (btnLabel) {
|
|
31284
|
-
btnLabel.textContent = getSelectedPeriodsLabel(
|
|
31301
|
+
btnLabel.textContent = getSelectedPeriodsLabel(state6.selectedPeriods);
|
|
31285
31302
|
}
|
|
31286
|
-
if (
|
|
31303
|
+
if (state6.data.length > 0) drawChart(modalId, state6);
|
|
31287
31304
|
});
|
|
31288
31305
|
});
|
|
31289
31306
|
document.getElementById(`${modalId}-period-select-all`)?.addEventListener("click", () => {
|
|
31290
31307
|
periodCheckboxes.forEach((cb) => {
|
|
31291
31308
|
cb.checked = true;
|
|
31292
31309
|
});
|
|
31293
|
-
|
|
31310
|
+
state6.selectedPeriods = ["madrugada", "manha", "tarde", "noite"];
|
|
31294
31311
|
const btnLabel = periodBtn?.querySelector("span:first-child");
|
|
31295
31312
|
if (btnLabel) {
|
|
31296
|
-
btnLabel.textContent = getSelectedPeriodsLabel(
|
|
31313
|
+
btnLabel.textContent = getSelectedPeriodsLabel(state6.selectedPeriods);
|
|
31297
31314
|
}
|
|
31298
|
-
if (
|
|
31315
|
+
if (state6.data.length > 0) drawChart(modalId, state6);
|
|
31299
31316
|
});
|
|
31300
31317
|
document.getElementById(`${modalId}-period-clear`)?.addEventListener("click", () => {
|
|
31301
31318
|
periodCheckboxes.forEach((cb) => {
|
|
31302
31319
|
cb.checked = false;
|
|
31303
31320
|
});
|
|
31304
|
-
|
|
31321
|
+
state6.selectedPeriods = [];
|
|
31305
31322
|
const btnLabel = periodBtn?.querySelector("span:first-child");
|
|
31306
31323
|
if (btnLabel) {
|
|
31307
|
-
btnLabel.textContent = getSelectedPeriodsLabel(
|
|
31324
|
+
btnLabel.textContent = getSelectedPeriodsLabel(state6.selectedPeriods);
|
|
31308
31325
|
}
|
|
31309
|
-
if (
|
|
31326
|
+
if (state6.data.length > 0) drawChart(modalId, state6);
|
|
31310
31327
|
});
|
|
31311
31328
|
document.getElementById(`${modalId}-granularity`)?.addEventListener("change", (e) => {
|
|
31312
|
-
|
|
31313
|
-
localStorage.setItem("myio-temp-modal-granularity",
|
|
31314
|
-
if (
|
|
31329
|
+
state6.granularity = e.target.value;
|
|
31330
|
+
localStorage.setItem("myio-temp-modal-granularity", state6.granularity);
|
|
31331
|
+
if (state6.data.length > 0) drawChart(modalId, state6);
|
|
31315
31332
|
});
|
|
31316
31333
|
document.getElementById(`${modalId}-query`)?.addEventListener("click", async () => {
|
|
31317
|
-
if (
|
|
31334
|
+
if (state6.startTs >= state6.endTs) {
|
|
31318
31335
|
alert("Por favor, selecione um per\xEDodo v\xE1lido");
|
|
31319
31336
|
return;
|
|
31320
31337
|
}
|
|
31321
|
-
|
|
31322
|
-
|
|
31323
|
-
renderModal(container,
|
|
31338
|
+
state6.isLoading = true;
|
|
31339
|
+
state6.dateRangePicker = null;
|
|
31340
|
+
renderModal(container, state6, modalId);
|
|
31324
31341
|
try {
|
|
31325
|
-
|
|
31326
|
-
|
|
31327
|
-
|
|
31328
|
-
renderModal(container,
|
|
31329
|
-
drawChart(modalId,
|
|
31330
|
-
await setupEventListeners(container,
|
|
31342
|
+
state6.data = await fetchTemperatureData(state6.token, state6.deviceId, state6.startTs, state6.endTs);
|
|
31343
|
+
state6.stats = calculateStats(state6.data, state6.clampRange);
|
|
31344
|
+
state6.isLoading = false;
|
|
31345
|
+
renderModal(container, state6, modalId);
|
|
31346
|
+
drawChart(modalId, state6);
|
|
31347
|
+
await setupEventListeners(container, state6, modalId, onClose);
|
|
31331
31348
|
} catch (error) {
|
|
31332
31349
|
console.error("[TemperatureModal] Error fetching data:", error);
|
|
31333
|
-
|
|
31334
|
-
renderModal(container,
|
|
31335
|
-
await setupEventListeners(container,
|
|
31350
|
+
state6.isLoading = false;
|
|
31351
|
+
renderModal(container, state6, modalId, error);
|
|
31352
|
+
await setupEventListeners(container, state6, modalId, onClose);
|
|
31336
31353
|
}
|
|
31337
31354
|
});
|
|
31338
31355
|
document.getElementById(`${modalId}-export`)?.addEventListener("click", () => {
|
|
31339
|
-
if (
|
|
31340
|
-
const startDateStr = new Date(
|
|
31341
|
-
const endDateStr = new Date(
|
|
31356
|
+
if (state6.data.length === 0) return;
|
|
31357
|
+
const startDateStr = new Date(state6.startTs).toLocaleDateString(state6.locale).replace(/\//g, "-");
|
|
31358
|
+
const endDateStr = new Date(state6.endTs).toLocaleDateString(state6.locale).replace(/\//g, "-");
|
|
31342
31359
|
exportTemperatureCSV(
|
|
31343
|
-
|
|
31344
|
-
|
|
31345
|
-
|
|
31360
|
+
state6.data,
|
|
31361
|
+
state6.label,
|
|
31362
|
+
state6.stats,
|
|
31346
31363
|
startDateStr,
|
|
31347
31364
|
endDateStr
|
|
31348
31365
|
);
|
|
@@ -31355,7 +31372,7 @@
|
|
|
31355
31372
|
const defaultDateRange = getTodaySoFar();
|
|
31356
31373
|
const startTs = params.startDate ? new Date(params.startDate).getTime() : defaultDateRange.startTs;
|
|
31357
31374
|
const endTs = params.endDate ? new Date(params.endDate).getTime() : defaultDateRange.endTs;
|
|
31358
|
-
const
|
|
31375
|
+
const state6 = {
|
|
31359
31376
|
token: params.token,
|
|
31360
31377
|
devices: params.devices,
|
|
31361
31378
|
startTs,
|
|
@@ -31374,44 +31391,44 @@
|
|
|
31374
31391
|
};
|
|
31375
31392
|
const savedGranularity = localStorage.getItem("myio-temp-comparison-granularity");
|
|
31376
31393
|
const savedTheme = localStorage.getItem("myio-temp-comparison-theme");
|
|
31377
|
-
if (savedGranularity)
|
|
31378
|
-
if (savedTheme)
|
|
31394
|
+
if (savedGranularity) state6.granularity = savedGranularity;
|
|
31395
|
+
if (savedTheme) state6.theme = savedTheme;
|
|
31379
31396
|
const modalContainer = document.createElement("div");
|
|
31380
31397
|
modalContainer.id = modalId;
|
|
31381
31398
|
document.body.appendChild(modalContainer);
|
|
31382
|
-
renderModal2(modalContainer,
|
|
31383
|
-
await fetchAllDevicesData(
|
|
31384
|
-
renderModal2(modalContainer,
|
|
31385
|
-
drawComparisonChart(modalId,
|
|
31386
|
-
await setupEventListeners2(modalContainer,
|
|
31399
|
+
renderModal2(modalContainer, state6, modalId);
|
|
31400
|
+
await fetchAllDevicesData(state6);
|
|
31401
|
+
renderModal2(modalContainer, state6, modalId);
|
|
31402
|
+
drawComparisonChart(modalId, state6);
|
|
31403
|
+
await setupEventListeners2(modalContainer, state6, modalId, params.onClose);
|
|
31387
31404
|
return {
|
|
31388
31405
|
destroy: () => {
|
|
31389
31406
|
modalContainer.remove();
|
|
31390
31407
|
params.onClose?.();
|
|
31391
31408
|
},
|
|
31392
31409
|
updateData: async (startDate, endDate, granularity) => {
|
|
31393
|
-
|
|
31394
|
-
|
|
31395
|
-
if (granularity)
|
|
31396
|
-
|
|
31397
|
-
renderModal2(modalContainer,
|
|
31398
|
-
await fetchAllDevicesData(
|
|
31399
|
-
renderModal2(modalContainer,
|
|
31400
|
-
drawComparisonChart(modalId,
|
|
31401
|
-
setupEventListeners2(modalContainer,
|
|
31410
|
+
state6.startTs = new Date(startDate).getTime();
|
|
31411
|
+
state6.endTs = new Date(endDate).getTime();
|
|
31412
|
+
if (granularity) state6.granularity = granularity;
|
|
31413
|
+
state6.isLoading = true;
|
|
31414
|
+
renderModal2(modalContainer, state6, modalId);
|
|
31415
|
+
await fetchAllDevicesData(state6);
|
|
31416
|
+
renderModal2(modalContainer, state6, modalId);
|
|
31417
|
+
drawComparisonChart(modalId, state6);
|
|
31418
|
+
setupEventListeners2(modalContainer, state6, modalId, params.onClose);
|
|
31402
31419
|
}
|
|
31403
31420
|
};
|
|
31404
31421
|
}
|
|
31405
|
-
async function fetchAllDevicesData(
|
|
31406
|
-
|
|
31407
|
-
|
|
31422
|
+
async function fetchAllDevicesData(state6) {
|
|
31423
|
+
state6.isLoading = true;
|
|
31424
|
+
state6.deviceData = [];
|
|
31408
31425
|
try {
|
|
31409
31426
|
const results = await Promise.all(
|
|
31410
|
-
|
|
31427
|
+
state6.devices.map(async (device, index) => {
|
|
31411
31428
|
const deviceId = device.tbId || device.id;
|
|
31412
31429
|
try {
|
|
31413
|
-
const data = await fetchTemperatureData(
|
|
31414
|
-
const stats = calculateStats(data,
|
|
31430
|
+
const data = await fetchTemperatureData(state6.token, deviceId, state6.startTs, state6.endTs);
|
|
31431
|
+
const stats = calculateStats(data, state6.clampRange);
|
|
31415
31432
|
return {
|
|
31416
31433
|
device,
|
|
31417
31434
|
data,
|
|
@@ -31429,21 +31446,21 @@
|
|
|
31429
31446
|
}
|
|
31430
31447
|
})
|
|
31431
31448
|
);
|
|
31432
|
-
|
|
31449
|
+
state6.deviceData = results;
|
|
31433
31450
|
} catch (error) {
|
|
31434
31451
|
console.error("[TemperatureComparisonModal] Error fetching data:", error);
|
|
31435
31452
|
}
|
|
31436
|
-
|
|
31453
|
+
state6.isLoading = false;
|
|
31437
31454
|
}
|
|
31438
|
-
function renderModal2(container,
|
|
31439
|
-
const colors = getThemeColors(
|
|
31440
|
-
new Date(
|
|
31441
|
-
new Date(
|
|
31442
|
-
new Date(
|
|
31443
|
-
new Date(
|
|
31444
|
-
const legendHTML =
|
|
31455
|
+
function renderModal2(container, state6, modalId) {
|
|
31456
|
+
const colors = getThemeColors(state6.theme);
|
|
31457
|
+
new Date(state6.startTs).toLocaleDateString(state6.locale);
|
|
31458
|
+
new Date(state6.endTs).toLocaleDateString(state6.locale);
|
|
31459
|
+
new Date(state6.startTs).toISOString().slice(0, 16);
|
|
31460
|
+
new Date(state6.endTs).toISOString().slice(0, 16);
|
|
31461
|
+
const legendHTML = state6.deviceData.map((dd) => `
|
|
31445
31462
|
<div style="display: flex; align-items: center; gap: 8px; padding: 8px 12px;
|
|
31446
|
-
background: ${
|
|
31463
|
+
background: ${state6.theme === "dark" ? "rgba(255,255,255,0.05)" : "rgba(0,0,0,0.03)"};
|
|
31447
31464
|
border-radius: 8px;">
|
|
31448
31465
|
<span style="width: 12px; height: 12px; border-radius: 50%; background: ${dd.color};"></span>
|
|
31449
31466
|
<span style="color: ${colors.text}; font-size: 13px;">${dd.device.label}</span>
|
|
@@ -31452,9 +31469,9 @@
|
|
|
31452
31469
|
</span>
|
|
31453
31470
|
</div>
|
|
31454
31471
|
`).join("");
|
|
31455
|
-
const statsHTML =
|
|
31472
|
+
const statsHTML = state6.deviceData.map((dd) => `
|
|
31456
31473
|
<div style="
|
|
31457
|
-
padding: 12px; background: ${
|
|
31474
|
+
padding: 12px; background: ${state6.theme === "dark" ? "rgba(255,255,255,0.05)" : "#fafafa"};
|
|
31458
31475
|
border-radius: 10px; border-left: 4px solid ${dd.color};
|
|
31459
31476
|
min-width: 150px;
|
|
31460
31477
|
">
|
|
@@ -31505,7 +31522,7 @@
|
|
|
31505
31522
|
min-height: 20px;
|
|
31506
31523
|
">
|
|
31507
31524
|
<h2 style="margin: 6px; font-size: 18px; font-weight: 600; color: white; line-height: 2;">
|
|
31508
|
-
\u{1F321}\uFE0F Compara\xE7\xE3o de Temperatura - ${
|
|
31525
|
+
\u{1F321}\uFE0F Compara\xE7\xE3o de Temperatura - ${state6.devices.length} sensores
|
|
31509
31526
|
</h2>
|
|
31510
31527
|
<div style="display: flex; gap: 4px; align-items: center;">
|
|
31511
31528
|
<!-- Theme Toggle -->
|
|
@@ -31513,7 +31530,7 @@
|
|
|
31513
31530
|
background: none; border: none; font-size: 16px; cursor: pointer;
|
|
31514
31531
|
padding: 4px 8px; border-radius: 6px; color: rgba(255,255,255,0.8);
|
|
31515
31532
|
transition: background-color 0.2s;
|
|
31516
|
-
">${
|
|
31533
|
+
">${state6.theme === "dark" ? "\u2600\uFE0F" : "\u{1F319}"}</button>
|
|
31517
31534
|
<!-- Maximize Button -->
|
|
31518
31535
|
<button id="${modalId}-maximize" title="${isMaximized ? "Restaurar" : "Maximizar"}" style="
|
|
31519
31536
|
background: none; border: none; font-size: 16px; cursor: pointer;
|
|
@@ -31536,7 +31553,7 @@
|
|
|
31536
31553
|
<div style="
|
|
31537
31554
|
display: flex; gap: 16px; flex-wrap: wrap; align-items: flex-end;
|
|
31538
31555
|
margin-bottom: 16px; padding: 16px;
|
|
31539
|
-
background: ${
|
|
31556
|
+
background: ${state6.theme === "dark" ? "rgba(255,255,255,0.05)" : "#f7f7f7"};
|
|
31540
31557
|
border-radius: 6px; border: 1px solid ${colors.border};
|
|
31541
31558
|
">
|
|
31542
31559
|
<!-- Granularity Select -->
|
|
@@ -31549,8 +31566,8 @@
|
|
|
31549
31566
|
font-size: 14px; color: ${colors.text}; background: ${colors.surface};
|
|
31550
31567
|
cursor: pointer; min-width: 130px;
|
|
31551
31568
|
">
|
|
31552
|
-
<option value="hour" ${
|
|
31553
|
-
<option value="day" ${
|
|
31569
|
+
<option value="hour" ${state6.granularity === "hour" ? "selected" : ""}>Hora (30 min)</option>
|
|
31570
|
+
<option value="day" ${state6.granularity === "day" ? "selected" : ""}>Dia (m\xE9dia)</option>
|
|
31554
31571
|
</select>
|
|
31555
31572
|
</div>
|
|
31556
31573
|
<!-- Day Period Filter (Multiselect) -->
|
|
@@ -31564,7 +31581,7 @@
|
|
|
31564
31581
|
cursor: pointer; min-width: 180px; text-align: left;
|
|
31565
31582
|
display: flex; align-items: center; justify-content: space-between; gap: 8px;
|
|
31566
31583
|
">
|
|
31567
|
-
<span>${getSelectedPeriodsLabel(
|
|
31584
|
+
<span>${getSelectedPeriodsLabel(state6.selectedPeriods)}</span>
|
|
31568
31585
|
<span style="font-size: 10px;">\u25BC</span>
|
|
31569
31586
|
</button>
|
|
31570
31587
|
<div id="${modalId}-period-dropdown" style="
|
|
@@ -31577,12 +31594,12 @@
|
|
|
31577
31594
|
<label style="
|
|
31578
31595
|
display: flex; align-items: center; gap: 8px; padding: 8px 12px;
|
|
31579
31596
|
cursor: pointer; font-size: 13px; color: ${colors.text};
|
|
31580
|
-
" onmouseover="this.style.background='${
|
|
31597
|
+
" onmouseover="this.style.background='${state6.theme === "dark" ? "rgba(255,255,255,0.1)" : "#f0f0f0"}'"
|
|
31581
31598
|
onmouseout="this.style.background='transparent'">
|
|
31582
31599
|
<input type="checkbox"
|
|
31583
31600
|
name="${modalId}-period"
|
|
31584
31601
|
value="${period.id}"
|
|
31585
|
-
${
|
|
31602
|
+
${state6.selectedPeriods.includes(period.id) ? "checked" : ""}
|
|
31586
31603
|
style="width: 16px; height: 16px; cursor: pointer; accent-color: #3e1a7d;">
|
|
31587
31604
|
${period.label}
|
|
31588
31605
|
</label>
|
|
@@ -31590,13 +31607,13 @@
|
|
|
31590
31607
|
<div style="border-top: 1px solid ${colors.border}; margin-top: 8px; padding-top: 8px;">
|
|
31591
31608
|
<button id="${modalId}-period-select-all" type="button" style="
|
|
31592
31609
|
width: calc(100% - 16px); margin: 0 8px 4px; padding: 6px;
|
|
31593
|
-
background: ${
|
|
31610
|
+
background: ${state6.theme === "dark" ? "rgba(255,255,255,0.1)" : "#f0f0f0"};
|
|
31594
31611
|
border: none; border-radius: 4px; cursor: pointer;
|
|
31595
31612
|
font-size: 12px; color: ${colors.text};
|
|
31596
31613
|
">Selecionar Todos</button>
|
|
31597
31614
|
<button id="${modalId}-period-clear" type="button" style="
|
|
31598
31615
|
width: calc(100% - 16px); margin: 0 8px; padding: 6px;
|
|
31599
|
-
background: ${
|
|
31616
|
+
background: ${state6.theme === "dark" ? "rgba(255,255,255,0.1)" : "#f0f0f0"};
|
|
31600
31617
|
border: none; border-radius: 4px; cursor: pointer;
|
|
31601
31618
|
font-size: 12px; color: ${colors.text};
|
|
31602
31619
|
">Limpar Sele\xE7\xE3o</button>
|
|
@@ -31621,8 +31638,8 @@
|
|
|
31621
31638
|
font-size: 14px; font-weight: 500; height: 38px;
|
|
31622
31639
|
display: flex; align-items: center; gap: 8px;
|
|
31623
31640
|
font-family: 'Roboto', Arial, sans-serif;
|
|
31624
|
-
" ${
|
|
31625
|
-
${
|
|
31641
|
+
" ${state6.isLoading ? "disabled" : ""}>
|
|
31642
|
+
${state6.isLoading ? '<span style="animation: spin 1s linear infinite; display: inline-block;">\u21BB</span> Carregando...' : "Carregar"}
|
|
31626
31643
|
</button>
|
|
31627
31644
|
</div>
|
|
31628
31645
|
|
|
@@ -31638,14 +31655,14 @@
|
|
|
31638
31655
|
<div style="margin-bottom: 24px;">
|
|
31639
31656
|
<div id="${modalId}-chart" style="
|
|
31640
31657
|
height: 380px;
|
|
31641
|
-
background: ${
|
|
31658
|
+
background: ${state6.theme === "dark" ? "rgba(255,255,255,0.03)" : "#fafafa"};
|
|
31642
31659
|
border-radius: 14px; display: flex; justify-content: center; align-items: center;
|
|
31643
31660
|
border: 1px solid ${colors.border}; position: relative;
|
|
31644
31661
|
">
|
|
31645
|
-
${
|
|
31662
|
+
${state6.isLoading ? `<div style="text-align: center; color: ${colors.textMuted};">
|
|
31646
31663
|
<div style="animation: spin 1s linear infinite; font-size: 36px; margin-bottom: 12px;">\u21BB</div>
|
|
31647
|
-
<div style="font-size: 15px;">Carregando dados de ${
|
|
31648
|
-
</div>` :
|
|
31664
|
+
<div style="font-size: 15px;">Carregando dados de ${state6.devices.length} sensores...</div>
|
|
31665
|
+
</div>` : state6.deviceData.every((dd) => dd.data.length === 0) ? `<div style="text-align: center; color: ${colors.textMuted};">
|
|
31649
31666
|
<div style="font-size: 48px; margin-bottom: 12px;">\u{1F4ED}</div>
|
|
31650
31667
|
<div style="font-size: 16px;">Sem dados para o per\xEDodo selecionado</div>
|
|
31651
31668
|
</div>` : `<canvas id="${modalId}-canvas" style="width: 100%; height: 100%;"></canvas>`}
|
|
@@ -31663,12 +31680,12 @@
|
|
|
31663
31680
|
<!-- Actions -->
|
|
31664
31681
|
<div style="display: flex; justify-content: flex-end; gap: 12px;">
|
|
31665
31682
|
<button id="${modalId}-export" style="
|
|
31666
|
-
background: ${
|
|
31683
|
+
background: ${state6.theme === "dark" ? "rgba(255,255,255,0.1)" : "#f7f7f7"};
|
|
31667
31684
|
color: ${colors.text}; border: 1px solid ${colors.border};
|
|
31668
31685
|
padding: 8px 16px; border-radius: 6px; cursor: pointer;
|
|
31669
31686
|
font-size: 14px; display: flex; align-items: center; gap: 8px;
|
|
31670
31687
|
font-family: 'Roboto', Arial, sans-serif;
|
|
31671
|
-
" ${
|
|
31688
|
+
" ${state6.deviceData.every((dd) => dd.data.length === 0) ? "disabled" : ""}>
|
|
31672
31689
|
\u{1F4E5} Exportar CSV
|
|
31673
31690
|
</button>
|
|
31674
31691
|
<button id="${modalId}-close-btn" style="
|
|
@@ -31703,15 +31720,15 @@
|
|
|
31703
31720
|
</style>
|
|
31704
31721
|
`;
|
|
31705
31722
|
}
|
|
31706
|
-
function drawComparisonChart(modalId,
|
|
31723
|
+
function drawComparisonChart(modalId, state6) {
|
|
31707
31724
|
const chartContainer = document.getElementById(`${modalId}-chart`);
|
|
31708
31725
|
const canvas = document.getElementById(`${modalId}-canvas`);
|
|
31709
31726
|
if (!chartContainer || !canvas) return;
|
|
31710
|
-
const hasData =
|
|
31727
|
+
const hasData = state6.deviceData.some((dd) => dd.data.length > 0);
|
|
31711
31728
|
if (!hasData) return;
|
|
31712
31729
|
const ctx = canvas.getContext("2d");
|
|
31713
31730
|
if (!ctx) return;
|
|
31714
|
-
const colors = getThemeColors(
|
|
31731
|
+
const colors = getThemeColors(state6.theme);
|
|
31715
31732
|
const width = chartContainer.clientWidth - 2;
|
|
31716
31733
|
const height = 380;
|
|
31717
31734
|
canvas.width = width;
|
|
@@ -31722,19 +31739,19 @@
|
|
|
31722
31739
|
const paddingBottom = 55;
|
|
31723
31740
|
ctx.clearRect(0, 0, width, height);
|
|
31724
31741
|
const processedData = [];
|
|
31725
|
-
|
|
31742
|
+
state6.deviceData.forEach((dd) => {
|
|
31726
31743
|
if (dd.data.length === 0) return;
|
|
31727
|
-
const filteredData = filterByDayPeriods(dd.data,
|
|
31744
|
+
const filteredData = filterByDayPeriods(dd.data, state6.selectedPeriods);
|
|
31728
31745
|
if (filteredData.length === 0) return;
|
|
31729
31746
|
let points;
|
|
31730
|
-
if (
|
|
31747
|
+
if (state6.granularity === "hour") {
|
|
31731
31748
|
const interpolated = interpolateTemperature(filteredData, {
|
|
31732
31749
|
intervalMinutes: 30,
|
|
31733
|
-
startTs:
|
|
31734
|
-
endTs:
|
|
31735
|
-
clampRange:
|
|
31750
|
+
startTs: state6.startTs,
|
|
31751
|
+
endTs: state6.endTs,
|
|
31752
|
+
clampRange: state6.clampRange
|
|
31736
31753
|
});
|
|
31737
|
-
const filteredInterpolated = filterByDayPeriods(interpolated,
|
|
31754
|
+
const filteredInterpolated = filterByDayPeriods(interpolated, state6.selectedPeriods);
|
|
31738
31755
|
points = filteredInterpolated.map((item) => ({
|
|
31739
31756
|
x: item.ts,
|
|
31740
31757
|
y: Number(item.value),
|
|
@@ -31744,7 +31761,7 @@
|
|
|
31744
31761
|
deviceColor: dd.color
|
|
31745
31762
|
}));
|
|
31746
31763
|
} else {
|
|
31747
|
-
const daily = aggregateByDay(filteredData,
|
|
31764
|
+
const daily = aggregateByDay(filteredData, state6.clampRange);
|
|
31748
31765
|
points = daily.map((item) => ({
|
|
31749
31766
|
x: item.dateTs,
|
|
31750
31767
|
y: item.avg,
|
|
@@ -31765,7 +31782,7 @@
|
|
|
31765
31782
|
ctx.fillText("Nenhum dado para os per\xEDodos selecionados", width / 2, height / 2);
|
|
31766
31783
|
return;
|
|
31767
31784
|
}
|
|
31768
|
-
const isPeriodsFiltered =
|
|
31785
|
+
const isPeriodsFiltered = state6.selectedPeriods.length < 4 && state6.selectedPeriods.length > 0;
|
|
31769
31786
|
let dataMinY = Infinity;
|
|
31770
31787
|
let dataMaxY = -Infinity;
|
|
31771
31788
|
processedData.forEach(({ points }) => {
|
|
@@ -31775,7 +31792,7 @@
|
|
|
31775
31792
|
});
|
|
31776
31793
|
});
|
|
31777
31794
|
const rangeMap = /* @__PURE__ */ new Map();
|
|
31778
|
-
|
|
31795
|
+
state6.deviceData.forEach((dd, index) => {
|
|
31779
31796
|
const device = dd.device;
|
|
31780
31797
|
const min = device.temperatureMin;
|
|
31781
31798
|
const max = device.temperatureMax;
|
|
@@ -31794,10 +31811,10 @@
|
|
|
31794
31811
|
}
|
|
31795
31812
|
}
|
|
31796
31813
|
});
|
|
31797
|
-
if (rangeMap.size === 0 &&
|
|
31814
|
+
if (rangeMap.size === 0 && state6.temperatureMin !== null && state6.temperatureMax !== null) {
|
|
31798
31815
|
rangeMap.set("global", {
|
|
31799
|
-
min:
|
|
31800
|
-
max:
|
|
31816
|
+
min: state6.temperatureMin,
|
|
31817
|
+
max: state6.temperatureMax,
|
|
31801
31818
|
customerName: "Global",
|
|
31802
31819
|
color: colors.success,
|
|
31803
31820
|
deviceLabels: []
|
|
@@ -31918,10 +31935,10 @@
|
|
|
31918
31935
|
const point = xAxisPoints[i];
|
|
31919
31936
|
const date = new Date(point.x);
|
|
31920
31937
|
let label;
|
|
31921
|
-
if (
|
|
31922
|
-
label = date.toLocaleTimeString(
|
|
31938
|
+
if (state6.granularity === "hour") {
|
|
31939
|
+
label = date.toLocaleTimeString(state6.locale, { hour: "2-digit", minute: "2-digit" });
|
|
31923
31940
|
} else {
|
|
31924
|
-
label = date.toLocaleDateString(
|
|
31941
|
+
label = date.toLocaleDateString(state6.locale, { day: "2-digit", month: "2-digit" });
|
|
31925
31942
|
}
|
|
31926
31943
|
ctx.strokeStyle = colors.chartGrid;
|
|
31927
31944
|
ctx.lineWidth = 1;
|
|
@@ -31940,16 +31957,16 @@
|
|
|
31940
31957
|
ctx.lineTo(width - paddingRight, height - paddingBottom);
|
|
31941
31958
|
ctx.stroke();
|
|
31942
31959
|
const allChartPoints = processedData.flatMap((pd) => pd.points);
|
|
31943
|
-
setupComparisonChartTooltip(canvas, chartContainer, allChartPoints,
|
|
31960
|
+
setupComparisonChartTooltip(canvas, chartContainer, allChartPoints, state6, colors);
|
|
31944
31961
|
}
|
|
31945
|
-
function setupComparisonChartTooltip(canvas, container, chartData,
|
|
31962
|
+
function setupComparisonChartTooltip(canvas, container, chartData, state6, colors) {
|
|
31946
31963
|
const existingTooltip = container.querySelector(".myio-chart-tooltip");
|
|
31947
31964
|
if (existingTooltip) existingTooltip.remove();
|
|
31948
31965
|
const tooltip = document.createElement("div");
|
|
31949
31966
|
tooltip.className = "myio-chart-tooltip";
|
|
31950
31967
|
tooltip.style.cssText = `
|
|
31951
31968
|
position: absolute;
|
|
31952
|
-
background: ${
|
|
31969
|
+
background: ${state6.theme === "dark" ? "rgba(30, 30, 40, 0.95)" : "rgba(255, 255, 255, 0.98)"};
|
|
31953
31970
|
border: 1px solid ${colors.border};
|
|
31954
31971
|
border-radius: 8px;
|
|
31955
31972
|
padding: 10px 14px;
|
|
@@ -31986,17 +32003,17 @@
|
|
|
31986
32003
|
if (point) {
|
|
31987
32004
|
const date = new Date(point.x);
|
|
31988
32005
|
let dateStr;
|
|
31989
|
-
if (
|
|
31990
|
-
dateStr = date.toLocaleDateString(
|
|
32006
|
+
if (state6.granularity === "hour") {
|
|
32007
|
+
dateStr = date.toLocaleDateString(state6.locale, {
|
|
31991
32008
|
day: "2-digit",
|
|
31992
32009
|
month: "2-digit",
|
|
31993
32010
|
year: "numeric"
|
|
31994
|
-
}) + " " + date.toLocaleTimeString(
|
|
32011
|
+
}) + " " + date.toLocaleTimeString(state6.locale, {
|
|
31995
32012
|
hour: "2-digit",
|
|
31996
32013
|
minute: "2-digit"
|
|
31997
32014
|
});
|
|
31998
32015
|
} else {
|
|
31999
|
-
dateStr = date.toLocaleDateString(
|
|
32016
|
+
dateStr = date.toLocaleDateString(state6.locale, {
|
|
32000
32017
|
day: "2-digit",
|
|
32001
32018
|
month: "2-digit",
|
|
32002
32019
|
year: "numeric"
|
|
@@ -32038,7 +32055,7 @@
|
|
|
32038
32055
|
canvas.style.cursor = "default";
|
|
32039
32056
|
});
|
|
32040
32057
|
}
|
|
32041
|
-
async function setupEventListeners2(container,
|
|
32058
|
+
async function setupEventListeners2(container, state6, modalId, onClose) {
|
|
32042
32059
|
const closeModal = () => {
|
|
32043
32060
|
container.remove();
|
|
32044
32061
|
onClose?.();
|
|
@@ -32049,19 +32066,19 @@
|
|
|
32049
32066
|
document.getElementById(`${modalId}-close`)?.addEventListener("click", closeModal);
|
|
32050
32067
|
document.getElementById(`${modalId}-close-btn`)?.addEventListener("click", closeModal);
|
|
32051
32068
|
const dateRangeInput = document.getElementById(`${modalId}-date-range`);
|
|
32052
|
-
if (dateRangeInput && !
|
|
32069
|
+
if (dateRangeInput && !state6.dateRangePicker) {
|
|
32053
32070
|
try {
|
|
32054
|
-
|
|
32055
|
-
presetStart: new Date(
|
|
32056
|
-
presetEnd: new Date(
|
|
32071
|
+
state6.dateRangePicker = await createDateRangePicker2(dateRangeInput, {
|
|
32072
|
+
presetStart: new Date(state6.startTs).toISOString(),
|
|
32073
|
+
presetEnd: new Date(state6.endTs).toISOString(),
|
|
32057
32074
|
includeTime: true,
|
|
32058
32075
|
timePrecision: "minute",
|
|
32059
32076
|
maxRangeDays: 90,
|
|
32060
|
-
locale:
|
|
32077
|
+
locale: state6.locale,
|
|
32061
32078
|
parentEl: container.querySelector(".myio-temp-comparison-content"),
|
|
32062
32079
|
onApply: (result) => {
|
|
32063
|
-
|
|
32064
|
-
|
|
32080
|
+
state6.startTs = new Date(result.startISO).getTime();
|
|
32081
|
+
state6.endTs = new Date(result.endISO).getTime();
|
|
32065
32082
|
console.log("[TemperatureComparisonModal] Date range applied:", result);
|
|
32066
32083
|
}
|
|
32067
32084
|
});
|
|
@@ -32070,23 +32087,23 @@
|
|
|
32070
32087
|
}
|
|
32071
32088
|
}
|
|
32072
32089
|
document.getElementById(`${modalId}-theme-toggle`)?.addEventListener("click", async () => {
|
|
32073
|
-
|
|
32074
|
-
localStorage.setItem("myio-temp-comparison-theme",
|
|
32075
|
-
|
|
32076
|
-
renderModal2(container,
|
|
32077
|
-
if (
|
|
32078
|
-
drawComparisonChart(modalId,
|
|
32079
|
-
}
|
|
32080
|
-
await setupEventListeners2(container,
|
|
32090
|
+
state6.theme = state6.theme === "dark" ? "light" : "dark";
|
|
32091
|
+
localStorage.setItem("myio-temp-comparison-theme", state6.theme);
|
|
32092
|
+
state6.dateRangePicker = null;
|
|
32093
|
+
renderModal2(container, state6, modalId);
|
|
32094
|
+
if (state6.deviceData.some((dd) => dd.data.length > 0)) {
|
|
32095
|
+
drawComparisonChart(modalId, state6);
|
|
32096
|
+
}
|
|
32097
|
+
await setupEventListeners2(container, state6, modalId, onClose);
|
|
32081
32098
|
});
|
|
32082
32099
|
document.getElementById(`${modalId}-maximize`)?.addEventListener("click", async () => {
|
|
32083
32100
|
container.__isMaximized = !container.__isMaximized;
|
|
32084
|
-
|
|
32085
|
-
renderModal2(container,
|
|
32086
|
-
if (
|
|
32087
|
-
drawComparisonChart(modalId,
|
|
32101
|
+
state6.dateRangePicker = null;
|
|
32102
|
+
renderModal2(container, state6, modalId);
|
|
32103
|
+
if (state6.deviceData.some((dd) => dd.data.length > 0)) {
|
|
32104
|
+
drawComparisonChart(modalId, state6);
|
|
32088
32105
|
}
|
|
32089
|
-
await setupEventListeners2(container,
|
|
32106
|
+
await setupEventListeners2(container, state6, modalId, onClose);
|
|
32090
32107
|
});
|
|
32091
32108
|
const periodBtn = document.getElementById(`${modalId}-period-btn`);
|
|
32092
32109
|
const periodDropdown = document.getElementById(`${modalId}-period-dropdown`);
|
|
@@ -32105,13 +32122,13 @@
|
|
|
32105
32122
|
periodCheckboxes.forEach((checkbox) => {
|
|
32106
32123
|
checkbox.addEventListener("change", () => {
|
|
32107
32124
|
const checked = Array.from(periodCheckboxes).filter((cb) => cb.checked).map((cb) => cb.value);
|
|
32108
|
-
|
|
32125
|
+
state6.selectedPeriods = checked;
|
|
32109
32126
|
const btnLabel = periodBtn?.querySelector("span:first-child");
|
|
32110
32127
|
if (btnLabel) {
|
|
32111
|
-
btnLabel.textContent = getSelectedPeriodsLabel(
|
|
32128
|
+
btnLabel.textContent = getSelectedPeriodsLabel(state6.selectedPeriods);
|
|
32112
32129
|
}
|
|
32113
|
-
if (
|
|
32114
|
-
drawComparisonChart(modalId,
|
|
32130
|
+
if (state6.deviceData.some((dd) => dd.data.length > 0)) {
|
|
32131
|
+
drawComparisonChart(modalId, state6);
|
|
32115
32132
|
}
|
|
32116
32133
|
});
|
|
32117
32134
|
});
|
|
@@ -32119,77 +32136,77 @@
|
|
|
32119
32136
|
periodCheckboxes.forEach((cb) => {
|
|
32120
32137
|
cb.checked = true;
|
|
32121
32138
|
});
|
|
32122
|
-
|
|
32139
|
+
state6.selectedPeriods = ["madrugada", "manha", "tarde", "noite"];
|
|
32123
32140
|
const btnLabel = periodBtn?.querySelector("span:first-child");
|
|
32124
32141
|
if (btnLabel) {
|
|
32125
|
-
btnLabel.textContent = getSelectedPeriodsLabel(
|
|
32142
|
+
btnLabel.textContent = getSelectedPeriodsLabel(state6.selectedPeriods);
|
|
32126
32143
|
}
|
|
32127
|
-
if (
|
|
32128
|
-
drawComparisonChart(modalId,
|
|
32144
|
+
if (state6.deviceData.some((dd) => dd.data.length > 0)) {
|
|
32145
|
+
drawComparisonChart(modalId, state6);
|
|
32129
32146
|
}
|
|
32130
32147
|
});
|
|
32131
32148
|
document.getElementById(`${modalId}-period-clear`)?.addEventListener("click", () => {
|
|
32132
32149
|
periodCheckboxes.forEach((cb) => {
|
|
32133
32150
|
cb.checked = false;
|
|
32134
32151
|
});
|
|
32135
|
-
|
|
32152
|
+
state6.selectedPeriods = [];
|
|
32136
32153
|
const btnLabel = periodBtn?.querySelector("span:first-child");
|
|
32137
32154
|
if (btnLabel) {
|
|
32138
|
-
btnLabel.textContent = getSelectedPeriodsLabel(
|
|
32155
|
+
btnLabel.textContent = getSelectedPeriodsLabel(state6.selectedPeriods);
|
|
32139
32156
|
}
|
|
32140
|
-
if (
|
|
32141
|
-
drawComparisonChart(modalId,
|
|
32157
|
+
if (state6.deviceData.some((dd) => dd.data.length > 0)) {
|
|
32158
|
+
drawComparisonChart(modalId, state6);
|
|
32142
32159
|
}
|
|
32143
32160
|
});
|
|
32144
32161
|
document.getElementById(`${modalId}-granularity`)?.addEventListener("change", (e) => {
|
|
32145
|
-
|
|
32146
|
-
localStorage.setItem("myio-temp-comparison-granularity",
|
|
32147
|
-
if (
|
|
32148
|
-
drawComparisonChart(modalId,
|
|
32162
|
+
state6.granularity = e.target.value;
|
|
32163
|
+
localStorage.setItem("myio-temp-comparison-granularity", state6.granularity);
|
|
32164
|
+
if (state6.deviceData.some((dd) => dd.data.length > 0)) {
|
|
32165
|
+
drawComparisonChart(modalId, state6);
|
|
32149
32166
|
}
|
|
32150
32167
|
});
|
|
32151
32168
|
document.getElementById(`${modalId}-query`)?.addEventListener("click", async () => {
|
|
32152
|
-
if (
|
|
32169
|
+
if (state6.startTs >= state6.endTs) {
|
|
32153
32170
|
alert("Por favor, selecione um per\xEDodo v\xE1lido");
|
|
32154
32171
|
return;
|
|
32155
32172
|
}
|
|
32156
|
-
|
|
32157
|
-
|
|
32158
|
-
renderModal2(container,
|
|
32159
|
-
await fetchAllDevicesData(
|
|
32160
|
-
renderModal2(container,
|
|
32161
|
-
drawComparisonChart(modalId,
|
|
32162
|
-
await setupEventListeners2(container,
|
|
32173
|
+
state6.isLoading = true;
|
|
32174
|
+
state6.dateRangePicker = null;
|
|
32175
|
+
renderModal2(container, state6, modalId);
|
|
32176
|
+
await fetchAllDevicesData(state6);
|
|
32177
|
+
renderModal2(container, state6, modalId);
|
|
32178
|
+
drawComparisonChart(modalId, state6);
|
|
32179
|
+
await setupEventListeners2(container, state6, modalId, onClose);
|
|
32163
32180
|
});
|
|
32164
32181
|
document.getElementById(`${modalId}-export`)?.addEventListener("click", () => {
|
|
32165
|
-
if (
|
|
32166
|
-
exportComparisonCSV(
|
|
32182
|
+
if (state6.deviceData.every((dd) => dd.data.length === 0)) return;
|
|
32183
|
+
exportComparisonCSV(state6);
|
|
32167
32184
|
});
|
|
32168
32185
|
}
|
|
32169
|
-
function exportComparisonCSV(
|
|
32170
|
-
const startDateStr = new Date(
|
|
32171
|
-
const endDateStr = new Date(
|
|
32186
|
+
function exportComparisonCSV(state6) {
|
|
32187
|
+
const startDateStr = new Date(state6.startTs).toLocaleDateString(state6.locale).replace(/\//g, "-");
|
|
32188
|
+
const endDateStr = new Date(state6.endTs).toLocaleDateString(state6.locale).replace(/\//g, "-");
|
|
32172
32189
|
const BOM = "\uFEFF";
|
|
32173
32190
|
let csvContent = BOM;
|
|
32174
32191
|
csvContent += `Compara\xE7\xE3o de Temperatura
|
|
32175
32192
|
`;
|
|
32176
32193
|
csvContent += `Per\xEDodo: ${startDateStr} at\xE9 ${endDateStr}
|
|
32177
32194
|
`;
|
|
32178
|
-
csvContent += `Sensores: ${
|
|
32195
|
+
csvContent += `Sensores: ${state6.devices.map((d) => d.label).join(", ")}
|
|
32179
32196
|
`;
|
|
32180
32197
|
csvContent += "\n";
|
|
32181
32198
|
csvContent += "Estat\xEDsticas por Sensor:\n";
|
|
32182
32199
|
csvContent += "Sensor,M\xE9dia (\xB0C),Min (\xB0C),Max (\xB0C),Leituras\n";
|
|
32183
|
-
|
|
32200
|
+
state6.deviceData.forEach((dd) => {
|
|
32184
32201
|
csvContent += `"${dd.device.label}",${dd.stats.avg.toFixed(2)},${dd.stats.min.toFixed(2)},${dd.stats.max.toFixed(2)},${dd.stats.count}
|
|
32185
32202
|
`;
|
|
32186
32203
|
});
|
|
32187
32204
|
csvContent += "\n";
|
|
32188
32205
|
csvContent += "Dados Detalhados:\n";
|
|
32189
32206
|
csvContent += "Data/Hora,Sensor,Temperatura (\xB0C)\n";
|
|
32190
|
-
|
|
32207
|
+
state6.deviceData.forEach((dd) => {
|
|
32191
32208
|
dd.data.forEach((item) => {
|
|
32192
|
-
const date = new Date(item.ts).toLocaleString(
|
|
32209
|
+
const date = new Date(item.ts).toLocaleString(state6.locale);
|
|
32193
32210
|
const temp = Number(item.value).toFixed(2);
|
|
32194
32211
|
csvContent += `"${date}","${dd.device.label}",${temp}
|
|
32195
32212
|
`;
|
|
@@ -32297,10 +32314,10 @@
|
|
|
32297
32314
|
throw new Error(`Failed to save attributes: ${response.status}`);
|
|
32298
32315
|
}
|
|
32299
32316
|
}
|
|
32300
|
-
function renderModal3(container,
|
|
32301
|
-
const colors = getColors(
|
|
32302
|
-
const minValue =
|
|
32303
|
-
const maxValue =
|
|
32317
|
+
function renderModal3(container, state6, modalId, onClose, onSave) {
|
|
32318
|
+
const colors = getColors(state6.theme);
|
|
32319
|
+
const minValue = state6.minTemperature !== null ? state6.minTemperature : "";
|
|
32320
|
+
const maxValue = state6.maxTemperature !== null ? state6.maxTemperature : "";
|
|
32304
32321
|
container.innerHTML = `
|
|
32305
32322
|
<style>
|
|
32306
32323
|
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
|
|
@@ -32565,23 +32582,23 @@
|
|
|
32565
32582
|
</div>
|
|
32566
32583
|
|
|
32567
32584
|
<div class="modal-body">
|
|
32568
|
-
${
|
|
32585
|
+
${state6.isLoading ? `
|
|
32569
32586
|
<div class="loading-overlay">
|
|
32570
32587
|
<div class="loading-spinner"></div>
|
|
32571
32588
|
<div>Carregando configura\xE7\xF5es...</div>
|
|
32572
32589
|
</div>
|
|
32573
32590
|
` : `
|
|
32574
|
-
${
|
|
32575
|
-
<div class="message message-error">${
|
|
32591
|
+
${state6.error ? `
|
|
32592
|
+
<div class="message message-error">${state6.error}</div>
|
|
32576
32593
|
` : ""}
|
|
32577
32594
|
|
|
32578
|
-
${
|
|
32579
|
-
<div class="message message-success">${
|
|
32595
|
+
${state6.successMessage ? `
|
|
32596
|
+
<div class="message message-success">${state6.successMessage}</div>
|
|
32580
32597
|
` : ""}
|
|
32581
32598
|
|
|
32582
32599
|
<div class="customer-info">
|
|
32583
32600
|
<div class="customer-label">Shopping / Cliente</div>
|
|
32584
|
-
<div class="customer-name">${
|
|
32601
|
+
<div class="customer-name">${state6.customerName || "N\xE3o identificado"}</div>
|
|
32585
32602
|
</div>
|
|
32586
32603
|
|
|
32587
32604
|
<div class="form-group">
|
|
@@ -32625,11 +32642,11 @@
|
|
|
32625
32642
|
`}
|
|
32626
32643
|
</div>
|
|
32627
32644
|
|
|
32628
|
-
${!
|
|
32645
|
+
${!state6.isLoading ? `
|
|
32629
32646
|
<div class="modal-footer">
|
|
32630
32647
|
<button class="btn btn-secondary" id="${modalId}-cancel">Cancelar</button>
|
|
32631
|
-
<button class="btn btn-primary" id="${modalId}-save" ${
|
|
32632
|
-
${
|
|
32648
|
+
<button class="btn btn-primary" id="${modalId}-save" ${state6.isSaving ? "disabled" : ""}>
|
|
32649
|
+
${state6.isSaving ? '<div class="spinner"></div> Salvando...' : "Salvar"}
|
|
32633
32650
|
</button>
|
|
32634
32651
|
</div>
|
|
32635
32652
|
` : ""}
|
|
@@ -32666,18 +32683,18 @@
|
|
|
32666
32683
|
const min = parseFloat(minInput.value);
|
|
32667
32684
|
const max = parseFloat(maxInput.value);
|
|
32668
32685
|
if (isNaN(min) || isNaN(max)) {
|
|
32669
|
-
|
|
32670
|
-
renderModal3(container,
|
|
32686
|
+
state6.error = "Por favor, preencha ambos os valores.";
|
|
32687
|
+
renderModal3(container, state6, modalId, onClose, onSave);
|
|
32671
32688
|
return;
|
|
32672
32689
|
}
|
|
32673
32690
|
if (min >= max) {
|
|
32674
|
-
|
|
32675
|
-
renderModal3(container,
|
|
32691
|
+
state6.error = "A temperatura m\xEDnima deve ser menor que a m\xE1xima.";
|
|
32692
|
+
renderModal3(container, state6, modalId, onClose, onSave);
|
|
32676
32693
|
return;
|
|
32677
32694
|
}
|
|
32678
32695
|
if (min < 0 || max > 50) {
|
|
32679
|
-
|
|
32680
|
-
renderModal3(container,
|
|
32696
|
+
state6.error = "Os valores devem estar entre 0\xB0C e 50\xB0C.";
|
|
32697
|
+
renderModal3(container, state6, modalId, onClose, onSave);
|
|
32681
32698
|
return;
|
|
32682
32699
|
}
|
|
32683
32700
|
await onSave(min, max);
|
|
@@ -32685,7 +32702,7 @@
|
|
|
32685
32702
|
}
|
|
32686
32703
|
function openTemperatureSettingsModal(params) {
|
|
32687
32704
|
const modalId = `myio-temp-settings-${Date.now()}`;
|
|
32688
|
-
const
|
|
32705
|
+
const state6 = {
|
|
32689
32706
|
customerId: params.customerId,
|
|
32690
32707
|
customerName: params.customerName || "",
|
|
32691
32708
|
token: params.token,
|
|
@@ -32705,37 +32722,37 @@
|
|
|
32705
32722
|
params.onClose?.();
|
|
32706
32723
|
};
|
|
32707
32724
|
const handleSave = async (min, max) => {
|
|
32708
|
-
|
|
32709
|
-
|
|
32710
|
-
|
|
32711
|
-
renderModal3(container,
|
|
32725
|
+
state6.isSaving = true;
|
|
32726
|
+
state6.error = null;
|
|
32727
|
+
state6.successMessage = null;
|
|
32728
|
+
renderModal3(container, state6, modalId, destroy, handleSave);
|
|
32712
32729
|
try {
|
|
32713
|
-
await saveCustomerAttributes(
|
|
32714
|
-
|
|
32715
|
-
|
|
32716
|
-
|
|
32717
|
-
|
|
32718
|
-
renderModal3(container,
|
|
32730
|
+
await saveCustomerAttributes(state6.customerId, state6.token, min, max, params.onError);
|
|
32731
|
+
state6.minTemperature = min;
|
|
32732
|
+
state6.maxTemperature = max;
|
|
32733
|
+
state6.isSaving = false;
|
|
32734
|
+
state6.successMessage = "Configura\xE7\xF5es salvas com sucesso!";
|
|
32735
|
+
renderModal3(container, state6, modalId, destroy, handleSave);
|
|
32719
32736
|
params.onSave?.({ minTemperature: min, maxTemperature: max });
|
|
32720
32737
|
setTimeout(() => {
|
|
32721
32738
|
destroy();
|
|
32722
32739
|
}, 1500);
|
|
32723
32740
|
} catch (error) {
|
|
32724
|
-
|
|
32725
|
-
|
|
32726
|
-
renderModal3(container,
|
|
32741
|
+
state6.isSaving = false;
|
|
32742
|
+
state6.error = `Erro ao salvar: ${error.message}`;
|
|
32743
|
+
renderModal3(container, state6, modalId, destroy, handleSave);
|
|
32727
32744
|
}
|
|
32728
32745
|
};
|
|
32729
|
-
renderModal3(container,
|
|
32730
|
-
fetchCustomerAttributes(
|
|
32731
|
-
|
|
32732
|
-
|
|
32733
|
-
|
|
32734
|
-
renderModal3(container,
|
|
32746
|
+
renderModal3(container, state6, modalId, destroy, handleSave);
|
|
32747
|
+
fetchCustomerAttributes(state6.customerId, state6.token, params.onError).then(({ minTemperature, maxTemperature }) => {
|
|
32748
|
+
state6.minTemperature = minTemperature;
|
|
32749
|
+
state6.maxTemperature = maxTemperature;
|
|
32750
|
+
state6.isLoading = false;
|
|
32751
|
+
renderModal3(container, state6, modalId, destroy, handleSave);
|
|
32735
32752
|
}).catch((error) => {
|
|
32736
|
-
|
|
32737
|
-
|
|
32738
|
-
renderModal3(container,
|
|
32753
|
+
state6.isLoading = false;
|
|
32754
|
+
state6.error = `Erro ao carregar: ${error.message}`;
|
|
32755
|
+
renderModal3(container, state6, modalId, destroy, handleSave);
|
|
32739
32756
|
});
|
|
32740
32757
|
return { destroy };
|
|
32741
32758
|
}
|
|
@@ -34005,7 +34022,7 @@
|
|
|
34005
34022
|
* RFC-0105 Enhancement: Now fetches device lists from MyIOOrchestratorData
|
|
34006
34023
|
* to populate device lists for status popup display
|
|
34007
34024
|
*/
|
|
34008
|
-
buildSummaryFromState(
|
|
34025
|
+
buildSummaryFromState(state6, receivedData, domain = "energy") {
|
|
34009
34026
|
const summary = {
|
|
34010
34027
|
totalDevices: 0,
|
|
34011
34028
|
totalConsumption: 0,
|
|
@@ -34028,22 +34045,22 @@
|
|
|
34028
34045
|
},
|
|
34029
34046
|
lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
|
|
34030
34047
|
};
|
|
34031
|
-
if (!
|
|
34048
|
+
if (!state6) return summary;
|
|
34032
34049
|
const entrada = {
|
|
34033
34050
|
id: "entrada",
|
|
34034
34051
|
name: "Entrada",
|
|
34035
34052
|
icon: CATEGORY_ICONS.entrada,
|
|
34036
|
-
deviceCount:
|
|
34037
|
-
consumption:
|
|
34053
|
+
deviceCount: state6.entrada?.devices?.length || (receivedData?.entrada_total?.device_count || 0),
|
|
34054
|
+
consumption: state6.entrada?.total || 0,
|
|
34038
34055
|
percentage: 100
|
|
34039
34056
|
};
|
|
34040
34057
|
const lojas = {
|
|
34041
34058
|
id: "lojas",
|
|
34042
34059
|
name: "Lojas",
|
|
34043
34060
|
icon: CATEGORY_ICONS.lojas,
|
|
34044
|
-
deviceCount:
|
|
34045
|
-
consumption:
|
|
34046
|
-
percentage:
|
|
34061
|
+
deviceCount: state6.consumidores?.lojas?.devices?.length || (receivedData?.lojas_total?.device_count || 0),
|
|
34062
|
+
consumption: state6.consumidores?.lojas?.total || 0,
|
|
34063
|
+
percentage: state6.consumidores?.lojas?.perc || 0
|
|
34047
34064
|
};
|
|
34048
34065
|
const climatizacaoData = receivedData?.climatizacao || {};
|
|
34049
34066
|
const elevadoresData = receivedData?.elevadores || {};
|
|
@@ -34054,9 +34071,9 @@
|
|
|
34054
34071
|
id: "climatizacao",
|
|
34055
34072
|
name: "Climatizacao",
|
|
34056
34073
|
icon: CATEGORY_ICONS.climatizacao,
|
|
34057
|
-
deviceCount: climatizacaoData.count ||
|
|
34058
|
-
consumption:
|
|
34059
|
-
percentage:
|
|
34074
|
+
deviceCount: climatizacaoData.count || state6.consumidores?.climatizacao?.devices?.length || 0,
|
|
34075
|
+
consumption: state6.consumidores?.climatizacao?.total || 0,
|
|
34076
|
+
percentage: state6.consumidores?.climatizacao?.perc || 0
|
|
34060
34077
|
};
|
|
34061
34078
|
if (climatizacaoData.subcategories) {
|
|
34062
34079
|
climatizacao.children = [];
|
|
@@ -34107,40 +34124,40 @@
|
|
|
34107
34124
|
id: "elevadores",
|
|
34108
34125
|
name: "Elevadores",
|
|
34109
34126
|
icon: CATEGORY_ICONS.elevadores,
|
|
34110
|
-
deviceCount: elevadoresData.count ||
|
|
34111
|
-
consumption:
|
|
34112
|
-
percentage:
|
|
34127
|
+
deviceCount: elevadoresData.count || state6.consumidores?.elevadores?.devices?.length || 0,
|
|
34128
|
+
consumption: state6.consumidores?.elevadores?.total || 0,
|
|
34129
|
+
percentage: state6.consumidores?.elevadores?.perc || 0
|
|
34113
34130
|
});
|
|
34114
34131
|
areaComumChildren.push({
|
|
34115
34132
|
id: "escadasRolantes",
|
|
34116
34133
|
name: "Esc. Rolantes",
|
|
34117
34134
|
icon: CATEGORY_ICONS.escadas,
|
|
34118
|
-
deviceCount: escadasData.count ||
|
|
34119
|
-
consumption:
|
|
34120
|
-
percentage:
|
|
34135
|
+
deviceCount: escadasData.count || state6.consumidores?.escadasRolantes?.devices?.length || 0,
|
|
34136
|
+
consumption: state6.consumidores?.escadasRolantes?.total || 0,
|
|
34137
|
+
percentage: state6.consumidores?.escadasRolantes?.perc || 0
|
|
34121
34138
|
});
|
|
34122
34139
|
areaComumChildren.push({
|
|
34123
34140
|
id: "outros",
|
|
34124
34141
|
name: "Outros",
|
|
34125
34142
|
icon: CATEGORY_ICONS.outros,
|
|
34126
|
-
deviceCount: outrosData.count ||
|
|
34127
|
-
consumption:
|
|
34128
|
-
percentage:
|
|
34143
|
+
deviceCount: outrosData.count || state6.consumidores?.outros?.devices?.length || 0,
|
|
34144
|
+
consumption: state6.consumidores?.outros?.total || 0,
|
|
34145
|
+
percentage: state6.consumidores?.outros?.perc || 0
|
|
34129
34146
|
});
|
|
34130
34147
|
const areaComumDeviceCount = areaComumChildren.reduce((sum, c) => sum + c.deviceCount, 0);
|
|
34131
|
-
const areaComumConsumption =
|
|
34148
|
+
const areaComumConsumption = state6.consumidores?.areaComum?.total || areaComumChildren.reduce((sum, c) => sum + c.consumption, 0);
|
|
34132
34149
|
const areaComum = {
|
|
34133
34150
|
id: "areaComum",
|
|
34134
34151
|
name: "Area Comum",
|
|
34135
34152
|
icon: CATEGORY_ICONS.areaComum,
|
|
34136
34153
|
deviceCount: areaComumDeviceCount,
|
|
34137
34154
|
consumption: areaComumConsumption,
|
|
34138
|
-
percentage:
|
|
34155
|
+
percentage: state6.consumidores?.areaComum?.perc || 0,
|
|
34139
34156
|
children: areaComumChildren
|
|
34140
34157
|
};
|
|
34141
34158
|
summary.byCategory = [entrada, lojas, areaComum];
|
|
34142
34159
|
summary.totalDevices = entrada.deviceCount + lojas.deviceCount + areaComumDeviceCount;
|
|
34143
|
-
summary.totalConsumption =
|
|
34160
|
+
summary.totalConsumption = state6.grandTotal || entrada.consumption;
|
|
34144
34161
|
const widgetAggregation = receivedData?.deviceStatusAggregation;
|
|
34145
34162
|
if (widgetAggregation && widgetAggregation.hasData) {
|
|
34146
34163
|
summary.byStatus = {
|
|
@@ -35428,7 +35445,7 @@
|
|
|
35428
35445
|
* RFC-0105 Enhancement: Now fetches device lists from MyIOOrchestratorData
|
|
35429
35446
|
* to populate device lists for status popup display
|
|
35430
35447
|
*/
|
|
35431
|
-
buildSummaryFromState(
|
|
35448
|
+
buildSummaryFromState(state6, receivedData, includeBathrooms = false, domain = "water") {
|
|
35432
35449
|
const summary = {
|
|
35433
35450
|
totalDevices: 0,
|
|
35434
35451
|
totalConsumption: 0,
|
|
@@ -35452,22 +35469,22 @@
|
|
|
35452
35469
|
lastUpdated: (/* @__PURE__ */ new Date()).toISOString(),
|
|
35453
35470
|
includeBathrooms
|
|
35454
35471
|
};
|
|
35455
|
-
if (!
|
|
35472
|
+
if (!state6) return summary;
|
|
35456
35473
|
const entrada = {
|
|
35457
35474
|
id: "entrada",
|
|
35458
35475
|
name: "Entrada",
|
|
35459
35476
|
icon: WATER_CATEGORY_ICONS.entrada,
|
|
35460
|
-
deviceCount:
|
|
35461
|
-
consumption:
|
|
35477
|
+
deviceCount: state6.entrada?.devices?.length || (receivedData?.entrada_total?.device_count || 0),
|
|
35478
|
+
consumption: state6.entrada?.total || 0,
|
|
35462
35479
|
percentage: 100
|
|
35463
35480
|
};
|
|
35464
35481
|
const lojas = {
|
|
35465
35482
|
id: "lojas",
|
|
35466
35483
|
name: "Lojas",
|
|
35467
35484
|
icon: WATER_CATEGORY_ICONS.lojas,
|
|
35468
|
-
deviceCount:
|
|
35469
|
-
consumption:
|
|
35470
|
-
percentage:
|
|
35485
|
+
deviceCount: state6.lojas?.devices?.length || (receivedData?.lojas_total?.device_count || 0),
|
|
35486
|
+
consumption: state6.lojas?.total || 0,
|
|
35487
|
+
percentage: state6.lojas?.perc || 0
|
|
35471
35488
|
};
|
|
35472
35489
|
summary.byCategory = [entrada, lojas];
|
|
35473
35490
|
if (includeBathrooms) {
|
|
@@ -35475,9 +35492,9 @@
|
|
|
35475
35492
|
id: "banheiros",
|
|
35476
35493
|
name: "Banheiros",
|
|
35477
35494
|
icon: WATER_CATEGORY_ICONS.banheiros,
|
|
35478
|
-
deviceCount:
|
|
35479
|
-
consumption:
|
|
35480
|
-
percentage:
|
|
35495
|
+
deviceCount: state6.banheiros?.devices?.length || (receivedData?.banheiros_total?.device_count || 0),
|
|
35496
|
+
consumption: state6.banheiros?.total || 0,
|
|
35497
|
+
percentage: state6.banheiros?.perc || 0
|
|
35481
35498
|
};
|
|
35482
35499
|
summary.byCategory.push(banheiros);
|
|
35483
35500
|
}
|
|
@@ -35485,24 +35502,24 @@
|
|
|
35485
35502
|
id: "areaComum",
|
|
35486
35503
|
name: "\xC1rea Comum",
|
|
35487
35504
|
icon: WATER_CATEGORY_ICONS.areaComum,
|
|
35488
|
-
deviceCount:
|
|
35489
|
-
consumption:
|
|
35490
|
-
percentage:
|
|
35505
|
+
deviceCount: state6.areaComum?.devices?.length || (receivedData?.area_comum_total?.device_count || 0),
|
|
35506
|
+
consumption: state6.areaComum?.total || 0,
|
|
35507
|
+
percentage: state6.areaComum?.perc || 0
|
|
35491
35508
|
};
|
|
35492
35509
|
summary.byCategory.push(areaComum);
|
|
35493
|
-
if (
|
|
35510
|
+
if (state6.pontosNaoMapeados && state6.pontosNaoMapeados.total > 0) {
|
|
35494
35511
|
const pontosNaoMapeados = {
|
|
35495
35512
|
id: "pontosNaoMapeados",
|
|
35496
35513
|
name: "Pontos N\xE3o Mapeados",
|
|
35497
35514
|
icon: WATER_CATEGORY_ICONS.pontosNaoMapeados,
|
|
35498
|
-
deviceCount:
|
|
35499
|
-
consumption:
|
|
35500
|
-
percentage:
|
|
35515
|
+
deviceCount: state6.pontosNaoMapeados?.devices?.length || 0,
|
|
35516
|
+
consumption: state6.pontosNaoMapeados?.total || 0,
|
|
35517
|
+
percentage: state6.pontosNaoMapeados?.perc || 0
|
|
35501
35518
|
};
|
|
35502
35519
|
summary.byCategory.push(pontosNaoMapeados);
|
|
35503
35520
|
}
|
|
35504
35521
|
summary.totalDevices = summary.byCategory.reduce((sum, cat) => sum + cat.deviceCount, 0);
|
|
35505
|
-
summary.totalConsumption =
|
|
35522
|
+
summary.totalConsumption = state6.entrada?.total || 0;
|
|
35506
35523
|
const widgetAggregation = receivedData?.deviceStatusAggregation;
|
|
35507
35524
|
if (widgetAggregation && widgetAggregation.hasData) {
|
|
35508
35525
|
summary.byStatus = {
|
|
@@ -37039,6 +37056,996 @@
|
|
|
37039
37056
|
}
|
|
37040
37057
|
};
|
|
37041
37058
|
|
|
37059
|
+
// src/utils/ContractSummaryTooltip.ts
|
|
37060
|
+
var CONTRACT_SUMMARY_TOOLTIP_CSS = `
|
|
37061
|
+
/* ============================================
|
|
37062
|
+
Contract Summary Tooltip (RFC-0107)
|
|
37063
|
+
Premium draggable tooltip with dark theme
|
|
37064
|
+
============================================ */
|
|
37065
|
+
|
|
37066
|
+
.myio-contract-summary-tooltip {
|
|
37067
|
+
position: fixed;
|
|
37068
|
+
z-index: 99999;
|
|
37069
|
+
pointer-events: none;
|
|
37070
|
+
opacity: 0;
|
|
37071
|
+
transition: opacity 0.25s ease, transform 0.25s ease;
|
|
37072
|
+
transform: translateY(5px);
|
|
37073
|
+
}
|
|
37074
|
+
|
|
37075
|
+
.myio-contract-summary-tooltip.visible {
|
|
37076
|
+
opacity: 1;
|
|
37077
|
+
pointer-events: auto;
|
|
37078
|
+
transform: translateY(0);
|
|
37079
|
+
}
|
|
37080
|
+
|
|
37081
|
+
.myio-contract-summary-tooltip.closing {
|
|
37082
|
+
opacity: 0;
|
|
37083
|
+
transform: translateY(8px);
|
|
37084
|
+
transition: opacity 0.4s ease, transform 0.4s ease;
|
|
37085
|
+
}
|
|
37086
|
+
|
|
37087
|
+
.myio-contract-summary-tooltip.pinned {
|
|
37088
|
+
box-shadow: 0 0 0 2px #9684B5, 0 10px 40px rgba(0, 0, 0, 0.3);
|
|
37089
|
+
border-radius: 16px;
|
|
37090
|
+
}
|
|
37091
|
+
|
|
37092
|
+
.myio-contract-summary-tooltip.dragging {
|
|
37093
|
+
transition: none !important;
|
|
37094
|
+
cursor: move;
|
|
37095
|
+
}
|
|
37096
|
+
|
|
37097
|
+
.myio-contract-summary-tooltip.maximized {
|
|
37098
|
+
top: 20px !important;
|
|
37099
|
+
left: 20px !important;
|
|
37100
|
+
right: 20px !important;
|
|
37101
|
+
bottom: 20px !important;
|
|
37102
|
+
width: auto !important;
|
|
37103
|
+
max-width: none !important;
|
|
37104
|
+
}
|
|
37105
|
+
|
|
37106
|
+
.myio-contract-summary-tooltip.maximized .myio-contract-summary-tooltip__panel {
|
|
37107
|
+
width: 100%;
|
|
37108
|
+
height: 100%;
|
|
37109
|
+
max-width: none;
|
|
37110
|
+
display: flex;
|
|
37111
|
+
flex-direction: column;
|
|
37112
|
+
}
|
|
37113
|
+
|
|
37114
|
+
.myio-contract-summary-tooltip.maximized .myio-contract-summary-tooltip__body {
|
|
37115
|
+
flex: 1;
|
|
37116
|
+
overflow-y: auto;
|
|
37117
|
+
}
|
|
37118
|
+
|
|
37119
|
+
.myio-contract-summary-tooltip__panel {
|
|
37120
|
+
background: #2d1458;
|
|
37121
|
+
border: 1px solid rgba(255, 255, 255, 0.1);
|
|
37122
|
+
border-radius: 16px;
|
|
37123
|
+
box-shadow:
|
|
37124
|
+
0 20px 60px rgba(0, 0, 0, 0.4),
|
|
37125
|
+
0 8px 20px rgba(0, 0, 0, 0.25),
|
|
37126
|
+
0 0 0 1px rgba(255, 255, 255, 0.05);
|
|
37127
|
+
min-width: 320px;
|
|
37128
|
+
max-width: 380px;
|
|
37129
|
+
font-family: Inter, system-ui, -apple-system, sans-serif;
|
|
37130
|
+
font-size: 12px;
|
|
37131
|
+
color: #ffffff;
|
|
37132
|
+
overflow: hidden;
|
|
37133
|
+
}
|
|
37134
|
+
|
|
37135
|
+
/* Header */
|
|
37136
|
+
.myio-contract-summary-tooltip__header {
|
|
37137
|
+
display: flex;
|
|
37138
|
+
align-items: center;
|
|
37139
|
+
gap: 10px;
|
|
37140
|
+
padding: 14px 16px;
|
|
37141
|
+
background: linear-gradient(135deg, #9684B5 0%, #2d1458 100%);
|
|
37142
|
+
border-radius: 16px 16px 0 0;
|
|
37143
|
+
position: relative;
|
|
37144
|
+
overflow: hidden;
|
|
37145
|
+
cursor: move;
|
|
37146
|
+
user-select: none;
|
|
37147
|
+
}
|
|
37148
|
+
|
|
37149
|
+
.myio-contract-summary-tooltip__header::before {
|
|
37150
|
+
content: '';
|
|
37151
|
+
position: absolute;
|
|
37152
|
+
top: 0;
|
|
37153
|
+
left: 0;
|
|
37154
|
+
right: 0;
|
|
37155
|
+
bottom: 0;
|
|
37156
|
+
background: url("data:image/svg+xml,%3Csvg width='60' height='60' viewBox='0 0 60 60' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='none' fill-rule='evenodd'%3E%3Cg fill='%23ffffff' fill-opacity='0.05'%3E%3Cpath d='M36 34v-4h-2v4h-4v2h4v4h2v-4h4v-2h-4zm0-30V0h-2v4h-4v2h4v4h2V6h4V4h-4zM6 34v-4H4v4H0v2h4v4h2v-4h4v-2H6zM6 4V0H4v4H0v2h4v4h2V6h4V4H6z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E");
|
|
37157
|
+
opacity: 0.3;
|
|
37158
|
+
}
|
|
37159
|
+
|
|
37160
|
+
.myio-contract-summary-tooltip__icon {
|
|
37161
|
+
width: 40px;
|
|
37162
|
+
height: 40px;
|
|
37163
|
+
background: rgba(255, 255, 255, 0.15);
|
|
37164
|
+
border-radius: 12px;
|
|
37165
|
+
display: flex;
|
|
37166
|
+
align-items: center;
|
|
37167
|
+
justify-content: center;
|
|
37168
|
+
font-size: 20px;
|
|
37169
|
+
backdrop-filter: blur(10px);
|
|
37170
|
+
position: relative;
|
|
37171
|
+
z-index: 1;
|
|
37172
|
+
}
|
|
37173
|
+
|
|
37174
|
+
.myio-contract-summary-tooltip__icon.valid {
|
|
37175
|
+
background: rgba(76, 175, 80, 0.3);
|
|
37176
|
+
}
|
|
37177
|
+
|
|
37178
|
+
.myio-contract-summary-tooltip__icon.invalid {
|
|
37179
|
+
background: rgba(244, 67, 54, 0.3);
|
|
37180
|
+
}
|
|
37181
|
+
|
|
37182
|
+
.myio-contract-summary-tooltip__header-info {
|
|
37183
|
+
flex: 1;
|
|
37184
|
+
position: relative;
|
|
37185
|
+
z-index: 1;
|
|
37186
|
+
}
|
|
37187
|
+
|
|
37188
|
+
.myio-contract-summary-tooltip__title {
|
|
37189
|
+
font-weight: 700;
|
|
37190
|
+
font-size: 15px;
|
|
37191
|
+
color: #ffffff;
|
|
37192
|
+
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
|
|
37193
|
+
margin-bottom: 2px;
|
|
37194
|
+
}
|
|
37195
|
+
|
|
37196
|
+
.myio-contract-summary-tooltip__subtitle {
|
|
37197
|
+
font-size: 11px;
|
|
37198
|
+
color: rgba(255, 255, 255, 0.7);
|
|
37199
|
+
}
|
|
37200
|
+
|
|
37201
|
+
.myio-contract-summary-tooltip__header-actions {
|
|
37202
|
+
display: flex;
|
|
37203
|
+
align-items: center;
|
|
37204
|
+
gap: 4px;
|
|
37205
|
+
position: relative;
|
|
37206
|
+
z-index: 1;
|
|
37207
|
+
}
|
|
37208
|
+
|
|
37209
|
+
.myio-contract-summary-tooltip__header-btn {
|
|
37210
|
+
width: 28px;
|
|
37211
|
+
height: 28px;
|
|
37212
|
+
border: none;
|
|
37213
|
+
background: rgba(255, 255, 255, 0.15);
|
|
37214
|
+
border-radius: 8px;
|
|
37215
|
+
cursor: pointer;
|
|
37216
|
+
display: flex;
|
|
37217
|
+
align-items: center;
|
|
37218
|
+
justify-content: center;
|
|
37219
|
+
transition: all 0.2s ease;
|
|
37220
|
+
color: rgba(255, 255, 255, 0.8);
|
|
37221
|
+
}
|
|
37222
|
+
|
|
37223
|
+
.myio-contract-summary-tooltip__header-btn:hover {
|
|
37224
|
+
background: rgba(255, 255, 255, 0.25);
|
|
37225
|
+
color: #ffffff;
|
|
37226
|
+
transform: scale(1.05);
|
|
37227
|
+
}
|
|
37228
|
+
|
|
37229
|
+
.myio-contract-summary-tooltip__header-btn.pinned {
|
|
37230
|
+
background: rgba(255, 255, 255, 0.9);
|
|
37231
|
+
color: #9684B5;
|
|
37232
|
+
}
|
|
37233
|
+
|
|
37234
|
+
.myio-contract-summary-tooltip__header-btn.pinned:hover {
|
|
37235
|
+
background: #ffffff;
|
|
37236
|
+
color: #2d1458;
|
|
37237
|
+
}
|
|
37238
|
+
|
|
37239
|
+
.myio-contract-summary-tooltip__header-btn svg {
|
|
37240
|
+
width: 14px;
|
|
37241
|
+
height: 14px;
|
|
37242
|
+
}
|
|
37243
|
+
|
|
37244
|
+
/* Body */
|
|
37245
|
+
.myio-contract-summary-tooltip__body {
|
|
37246
|
+
padding: 16px;
|
|
37247
|
+
}
|
|
37248
|
+
|
|
37249
|
+
/* Domain Section */
|
|
37250
|
+
.myio-contract-summary-tooltip__domain {
|
|
37251
|
+
margin-bottom: 14px;
|
|
37252
|
+
background: rgba(255, 255, 255, 0.05);
|
|
37253
|
+
border-radius: 12px;
|
|
37254
|
+
overflow: hidden;
|
|
37255
|
+
border: 1px solid rgba(255, 255, 255, 0.08);
|
|
37256
|
+
}
|
|
37257
|
+
|
|
37258
|
+
.myio-contract-summary-tooltip__domain:last-child {
|
|
37259
|
+
margin-bottom: 0;
|
|
37260
|
+
}
|
|
37261
|
+
|
|
37262
|
+
.myio-contract-summary-tooltip__domain-header {
|
|
37263
|
+
display: flex;
|
|
37264
|
+
align-items: center;
|
|
37265
|
+
justify-content: space-between;
|
|
37266
|
+
padding: 10px 14px;
|
|
37267
|
+
cursor: pointer;
|
|
37268
|
+
transition: background 0.2s ease;
|
|
37269
|
+
}
|
|
37270
|
+
|
|
37271
|
+
.myio-contract-summary-tooltip__domain-header:hover {
|
|
37272
|
+
background: rgba(255, 255, 255, 0.05);
|
|
37273
|
+
}
|
|
37274
|
+
|
|
37275
|
+
.myio-contract-summary-tooltip__domain-info {
|
|
37276
|
+
display: flex;
|
|
37277
|
+
align-items: center;
|
|
37278
|
+
gap: 8px;
|
|
37279
|
+
}
|
|
37280
|
+
|
|
37281
|
+
.myio-contract-summary-tooltip__domain-icon {
|
|
37282
|
+
font-size: 18px;
|
|
37283
|
+
}
|
|
37284
|
+
|
|
37285
|
+
.myio-contract-summary-tooltip__domain-name {
|
|
37286
|
+
font-weight: 600;
|
|
37287
|
+
font-size: 13px;
|
|
37288
|
+
}
|
|
37289
|
+
|
|
37290
|
+
.myio-contract-summary-tooltip__domain-count {
|
|
37291
|
+
font-size: 12px;
|
|
37292
|
+
color: #81c784;
|
|
37293
|
+
font-weight: 600;
|
|
37294
|
+
}
|
|
37295
|
+
|
|
37296
|
+
.myio-contract-summary-tooltip__expand-icon {
|
|
37297
|
+
font-size: 10px;
|
|
37298
|
+
opacity: 0.6;
|
|
37299
|
+
transition: transform 0.3s ease;
|
|
37300
|
+
}
|
|
37301
|
+
|
|
37302
|
+
.myio-contract-summary-tooltip__domain.expanded .myio-contract-summary-tooltip__expand-icon {
|
|
37303
|
+
transform: rotate(180deg);
|
|
37304
|
+
}
|
|
37305
|
+
|
|
37306
|
+
/* Domain Details */
|
|
37307
|
+
.myio-contract-summary-tooltip__domain-details {
|
|
37308
|
+
max-height: 0;
|
|
37309
|
+
overflow: hidden;
|
|
37310
|
+
transition: max-height 0.3s ease;
|
|
37311
|
+
background: rgba(0, 0, 0, 0.15);
|
|
37312
|
+
}
|
|
37313
|
+
|
|
37314
|
+
.myio-contract-summary-tooltip__domain.expanded .myio-contract-summary-tooltip__domain-details {
|
|
37315
|
+
max-height: 150px;
|
|
37316
|
+
}
|
|
37317
|
+
|
|
37318
|
+
.myio-contract-summary-tooltip__detail-row {
|
|
37319
|
+
display: flex;
|
|
37320
|
+
align-items: center;
|
|
37321
|
+
justify-content: space-between;
|
|
37322
|
+
padding: 6px 14px 6px 40px;
|
|
37323
|
+
font-size: 12px;
|
|
37324
|
+
border-top: 1px solid rgba(255, 255, 255, 0.05);
|
|
37325
|
+
}
|
|
37326
|
+
|
|
37327
|
+
.myio-contract-summary-tooltip__detail-row:first-child {
|
|
37328
|
+
border-top: none;
|
|
37329
|
+
}
|
|
37330
|
+
|
|
37331
|
+
.myio-contract-summary-tooltip__detail-label {
|
|
37332
|
+
opacity: 0.7;
|
|
37333
|
+
display: flex;
|
|
37334
|
+
align-items: center;
|
|
37335
|
+
gap: 6px;
|
|
37336
|
+
}
|
|
37337
|
+
|
|
37338
|
+
.myio-contract-summary-tooltip__detail-label::before {
|
|
37339
|
+
content: '';
|
|
37340
|
+
width: 4px;
|
|
37341
|
+
height: 4px;
|
|
37342
|
+
border-radius: 50%;
|
|
37343
|
+
background: currentColor;
|
|
37344
|
+
opacity: 0.5;
|
|
37345
|
+
}
|
|
37346
|
+
|
|
37347
|
+
.myio-contract-summary-tooltip__detail-count {
|
|
37348
|
+
font-weight: 500;
|
|
37349
|
+
color: #81c784;
|
|
37350
|
+
}
|
|
37351
|
+
|
|
37352
|
+
/* Status Banner */
|
|
37353
|
+
.myio-contract-summary-tooltip__status {
|
|
37354
|
+
display: flex;
|
|
37355
|
+
align-items: center;
|
|
37356
|
+
justify-content: center;
|
|
37357
|
+
gap: 8px;
|
|
37358
|
+
padding: 10px 14px;
|
|
37359
|
+
border-radius: 10px;
|
|
37360
|
+
margin-bottom: 14px;
|
|
37361
|
+
font-size: 12px;
|
|
37362
|
+
font-weight: 600;
|
|
37363
|
+
}
|
|
37364
|
+
|
|
37365
|
+
.myio-contract-summary-tooltip__status.valid {
|
|
37366
|
+
background: rgba(76, 175, 80, 0.2);
|
|
37367
|
+
color: #81c784;
|
|
37368
|
+
border: 1px solid rgba(76, 175, 80, 0.3);
|
|
37369
|
+
}
|
|
37370
|
+
|
|
37371
|
+
.myio-contract-summary-tooltip__status.invalid {
|
|
37372
|
+
background: rgba(244, 67, 54, 0.2);
|
|
37373
|
+
color: #ef5350;
|
|
37374
|
+
border: 1px solid rgba(244, 67, 54, 0.3);
|
|
37375
|
+
}
|
|
37376
|
+
|
|
37377
|
+
.myio-contract-summary-tooltip__status-icon {
|
|
37378
|
+
font-size: 14px;
|
|
37379
|
+
}
|
|
37380
|
+
|
|
37381
|
+
/* Discrepancies */
|
|
37382
|
+
.myio-contract-summary-tooltip__discrepancies {
|
|
37383
|
+
background: rgba(244, 67, 54, 0.15);
|
|
37384
|
+
border: 1px solid rgba(244, 67, 54, 0.3);
|
|
37385
|
+
border-radius: 10px;
|
|
37386
|
+
padding: 10px 14px;
|
|
37387
|
+
margin-bottom: 14px;
|
|
37388
|
+
}
|
|
37389
|
+
|
|
37390
|
+
.myio-contract-summary-tooltip__discrepancies-title {
|
|
37391
|
+
font-size: 11px;
|
|
37392
|
+
font-weight: 600;
|
|
37393
|
+
color: #ef5350;
|
|
37394
|
+
margin-bottom: 6px;
|
|
37395
|
+
text-transform: uppercase;
|
|
37396
|
+
letter-spacing: 0.5px;
|
|
37397
|
+
}
|
|
37398
|
+
|
|
37399
|
+
.myio-contract-summary-tooltip__discrepancy-item {
|
|
37400
|
+
font-size: 11px;
|
|
37401
|
+
color: rgba(255, 255, 255, 0.8);
|
|
37402
|
+
padding: 3px 0;
|
|
37403
|
+
}
|
|
37404
|
+
|
|
37405
|
+
/* Footer */
|
|
37406
|
+
.myio-contract-summary-tooltip__footer {
|
|
37407
|
+
display: flex;
|
|
37408
|
+
justify-content: space-between;
|
|
37409
|
+
align-items: center;
|
|
37410
|
+
padding: 12px 16px;
|
|
37411
|
+
background: rgba(0, 0, 0, 0.2);
|
|
37412
|
+
border-top: 1px solid rgba(255, 255, 255, 0.05);
|
|
37413
|
+
border-radius: 0 0 16px 16px;
|
|
37414
|
+
}
|
|
37415
|
+
|
|
37416
|
+
.myio-contract-summary-tooltip__footer-label {
|
|
37417
|
+
font-size: 10px;
|
|
37418
|
+
color: rgba(255, 255, 255, 0.5);
|
|
37419
|
+
}
|
|
37420
|
+
|
|
37421
|
+
.myio-contract-summary-tooltip__footer-value {
|
|
37422
|
+
font-size: 11px;
|
|
37423
|
+
font-weight: 600;
|
|
37424
|
+
color: rgba(255, 255, 255, 0.8);
|
|
37425
|
+
}
|
|
37426
|
+
|
|
37427
|
+
/* Total Devices Badge */
|
|
37428
|
+
.myio-contract-summary-tooltip__total {
|
|
37429
|
+
display: flex;
|
|
37430
|
+
align-items: center;
|
|
37431
|
+
justify-content: center;
|
|
37432
|
+
gap: 8px;
|
|
37433
|
+
padding: 12px;
|
|
37434
|
+
background: rgba(255, 255, 255, 0.08);
|
|
37435
|
+
border-radius: 10px;
|
|
37436
|
+
margin-bottom: 14px;
|
|
37437
|
+
}
|
|
37438
|
+
|
|
37439
|
+
.myio-contract-summary-tooltip__total-label {
|
|
37440
|
+
font-size: 12px;
|
|
37441
|
+
opacity: 0.8;
|
|
37442
|
+
}
|
|
37443
|
+
|
|
37444
|
+
.myio-contract-summary-tooltip__total-value {
|
|
37445
|
+
font-size: 18px;
|
|
37446
|
+
font-weight: 700;
|
|
37447
|
+
color: #81c784;
|
|
37448
|
+
}
|
|
37449
|
+
|
|
37450
|
+
/* Responsive */
|
|
37451
|
+
@media (max-width: 400px) {
|
|
37452
|
+
.myio-contract-summary-tooltip__panel {
|
|
37453
|
+
min-width: 280px;
|
|
37454
|
+
max-width: 95vw;
|
|
37455
|
+
}
|
|
37456
|
+
}
|
|
37457
|
+
`;
|
|
37458
|
+
var cssInjected9 = false;
|
|
37459
|
+
function injectCSS9() {
|
|
37460
|
+
if (cssInjected9) return;
|
|
37461
|
+
if (typeof document === "undefined") return;
|
|
37462
|
+
const styleId = "myio-contract-summary-tooltip-styles";
|
|
37463
|
+
if (document.getElementById(styleId)) {
|
|
37464
|
+
cssInjected9 = true;
|
|
37465
|
+
return;
|
|
37466
|
+
}
|
|
37467
|
+
const style = document.createElement("style");
|
|
37468
|
+
style.id = styleId;
|
|
37469
|
+
style.textContent = CONTRACT_SUMMARY_TOOLTIP_CSS;
|
|
37470
|
+
document.head.appendChild(style);
|
|
37471
|
+
cssInjected9 = true;
|
|
37472
|
+
}
|
|
37473
|
+
var state5 = {
|
|
37474
|
+
hideTimer: null,
|
|
37475
|
+
isMouseOverTooltip: false,
|
|
37476
|
+
isMaximized: false,
|
|
37477
|
+
isDragging: false,
|
|
37478
|
+
dragOffset: { x: 0, y: 0 },
|
|
37479
|
+
savedPosition: null,
|
|
37480
|
+
pinnedCounter: 0,
|
|
37481
|
+
expandedDomains: /* @__PURE__ */ new Set(["energy", "water", "temperature"])
|
|
37482
|
+
};
|
|
37483
|
+
function formatTimestamp5(isoString) {
|
|
37484
|
+
if (!isoString) return "Agora";
|
|
37485
|
+
try {
|
|
37486
|
+
const date = new Date(isoString);
|
|
37487
|
+
return date.toLocaleString("pt-BR", {
|
|
37488
|
+
hour: "2-digit",
|
|
37489
|
+
minute: "2-digit",
|
|
37490
|
+
day: "2-digit",
|
|
37491
|
+
month: "2-digit"
|
|
37492
|
+
});
|
|
37493
|
+
} catch {
|
|
37494
|
+
return "Agora";
|
|
37495
|
+
}
|
|
37496
|
+
}
|
|
37497
|
+
function calculateTotalDevices(data) {
|
|
37498
|
+
return data.energy.total + data.water.total + data.temperature.total;
|
|
37499
|
+
}
|
|
37500
|
+
function generateHeaderHTML5(data) {
|
|
37501
|
+
const iconClass = data.isValid ? "valid" : "invalid";
|
|
37502
|
+
const iconSymbol = data.isValid ? "\u2713" : "!";
|
|
37503
|
+
const totalDevices = calculateTotalDevices(data);
|
|
37504
|
+
return `
|
|
37505
|
+
<div class="myio-contract-summary-tooltip__header" data-drag-handle>
|
|
37506
|
+
<div class="myio-contract-summary-tooltip__icon ${iconClass}">${iconSymbol}</div>
|
|
37507
|
+
<div class="myio-contract-summary-tooltip__header-info">
|
|
37508
|
+
<div class="myio-contract-summary-tooltip__title">Contract Summary</div>
|
|
37509
|
+
<div class="myio-contract-summary-tooltip__subtitle">${totalDevices} devices loaded</div>
|
|
37510
|
+
</div>
|
|
37511
|
+
<div class="myio-contract-summary-tooltip__header-actions">
|
|
37512
|
+
<button class="myio-contract-summary-tooltip__header-btn" data-action="pin" title="Pin to screen">
|
|
37513
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
37514
|
+
<path d="M9 4v6l-2 4v2h10v-2l-2-4V4"/>
|
|
37515
|
+
<line x1="12" y1="16" x2="12" y2="21"/>
|
|
37516
|
+
<line x1="8" y1="4" x2="16" y2="4"/>
|
|
37517
|
+
</svg>
|
|
37518
|
+
</button>
|
|
37519
|
+
<button class="myio-contract-summary-tooltip__header-btn" data-action="maximize" title="Maximize">
|
|
37520
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
37521
|
+
<rect x="3" y="3" width="18" height="18" rx="2"/>
|
|
37522
|
+
</svg>
|
|
37523
|
+
</button>
|
|
37524
|
+
<button class="myio-contract-summary-tooltip__header-btn" data-action="close" title="Close">
|
|
37525
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
37526
|
+
<path d="M18 6L6 18M6 6l12 12"/>
|
|
37527
|
+
</svg>
|
|
37528
|
+
</button>
|
|
37529
|
+
</div>
|
|
37530
|
+
</div>
|
|
37531
|
+
`;
|
|
37532
|
+
}
|
|
37533
|
+
function generateDomainHTML(domain, icon, name, counts, isTemperature = false) {
|
|
37534
|
+
const isExpanded = state5.expandedDomains.has(domain);
|
|
37535
|
+
const expandedClass = isExpanded ? "expanded" : "";
|
|
37536
|
+
let detailsHTML = "";
|
|
37537
|
+
if (isTemperature) {
|
|
37538
|
+
const tempCounts = counts;
|
|
37539
|
+
detailsHTML = `
|
|
37540
|
+
<div class="myio-contract-summary-tooltip__detail-row">
|
|
37541
|
+
<span class="myio-contract-summary-tooltip__detail-label">Internal (Climate)</span>
|
|
37542
|
+
<span class="myio-contract-summary-tooltip__detail-count">${tempCounts.internal}</span>
|
|
37543
|
+
</div>
|
|
37544
|
+
<div class="myio-contract-summary-tooltip__detail-row">
|
|
37545
|
+
<span class="myio-contract-summary-tooltip__detail-label">Stores (Non-Climate)</span>
|
|
37546
|
+
<span class="myio-contract-summary-tooltip__detail-count">${tempCounts.stores}</span>
|
|
37547
|
+
</div>
|
|
37548
|
+
`;
|
|
37549
|
+
} else {
|
|
37550
|
+
const domainCounts = counts;
|
|
37551
|
+
detailsHTML = `
|
|
37552
|
+
<div class="myio-contract-summary-tooltip__detail-row">
|
|
37553
|
+
<span class="myio-contract-summary-tooltip__detail-label">Entries</span>
|
|
37554
|
+
<span class="myio-contract-summary-tooltip__detail-count">${domainCounts.entries}</span>
|
|
37555
|
+
</div>
|
|
37556
|
+
<div class="myio-contract-summary-tooltip__detail-row">
|
|
37557
|
+
<span class="myio-contract-summary-tooltip__detail-label">Common Area</span>
|
|
37558
|
+
<span class="myio-contract-summary-tooltip__detail-count">${domainCounts.commonArea}</span>
|
|
37559
|
+
</div>
|
|
37560
|
+
<div class="myio-contract-summary-tooltip__detail-row">
|
|
37561
|
+
<span class="myio-contract-summary-tooltip__detail-label">Stores</span>
|
|
37562
|
+
<span class="myio-contract-summary-tooltip__detail-count">${domainCounts.stores}</span>
|
|
37563
|
+
</div>
|
|
37564
|
+
`;
|
|
37565
|
+
}
|
|
37566
|
+
return `
|
|
37567
|
+
<div class="myio-contract-summary-tooltip__domain ${expandedClass}" data-domain="${domain}">
|
|
37568
|
+
<div class="myio-contract-summary-tooltip__domain-header" data-toggle-domain="${domain}">
|
|
37569
|
+
<div class="myio-contract-summary-tooltip__domain-info">
|
|
37570
|
+
<span class="myio-contract-summary-tooltip__domain-icon">${icon}</span>
|
|
37571
|
+
<span class="myio-contract-summary-tooltip__domain-name">${name}</span>
|
|
37572
|
+
</div>
|
|
37573
|
+
<div style="display: flex; align-items: center; gap: 8px;">
|
|
37574
|
+
<span class="myio-contract-summary-tooltip__domain-count">${counts.total} devices</span>
|
|
37575
|
+
<span class="myio-contract-summary-tooltip__expand-icon">\u25BC</span>
|
|
37576
|
+
</div>
|
|
37577
|
+
</div>
|
|
37578
|
+
<div class="myio-contract-summary-tooltip__domain-details">
|
|
37579
|
+
${detailsHTML}
|
|
37580
|
+
</div>
|
|
37581
|
+
</div>
|
|
37582
|
+
`;
|
|
37583
|
+
}
|
|
37584
|
+
function generateBodyHTML3(data) {
|
|
37585
|
+
const totalDevices = calculateTotalDevices(data);
|
|
37586
|
+
const timestamp = formatTimestamp5(data.timestamp);
|
|
37587
|
+
const statusClass = data.isValid ? "valid" : "invalid";
|
|
37588
|
+
const statusIcon = data.isValid ? "\u2713" : "\u26A0";
|
|
37589
|
+
const statusText = data.isValid ? "Contract validated successfully" : "Validation issues detected";
|
|
37590
|
+
let discrepanciesHTML = "";
|
|
37591
|
+
if (data.discrepancies && data.discrepancies.length > 0) {
|
|
37592
|
+
const items = data.discrepancies.map((d) => `<div class="myio-contract-summary-tooltip__discrepancy-item">${d.domain}: expected ${d.expected}, found ${d.actual}</div>`).join("");
|
|
37593
|
+
discrepanciesHTML = `
|
|
37594
|
+
<div class="myio-contract-summary-tooltip__discrepancies">
|
|
37595
|
+
<div class="myio-contract-summary-tooltip__discrepancies-title">Discrepancies</div>
|
|
37596
|
+
${items}
|
|
37597
|
+
</div>
|
|
37598
|
+
`;
|
|
37599
|
+
}
|
|
37600
|
+
return `
|
|
37601
|
+
<div class="myio-contract-summary-tooltip__body">
|
|
37602
|
+
<!-- Status Banner -->
|
|
37603
|
+
<div class="myio-contract-summary-tooltip__status ${statusClass}">
|
|
37604
|
+
<span class="myio-contract-summary-tooltip__status-icon">${statusIcon}</span>
|
|
37605
|
+
<span>${statusText}</span>
|
|
37606
|
+
</div>
|
|
37607
|
+
|
|
37608
|
+
${discrepanciesHTML}
|
|
37609
|
+
|
|
37610
|
+
<!-- Total Devices -->
|
|
37611
|
+
<div class="myio-contract-summary-tooltip__total">
|
|
37612
|
+
<span class="myio-contract-summary-tooltip__total-label">Total Devices:</span>
|
|
37613
|
+
<span class="myio-contract-summary-tooltip__total-value">${totalDevices}</span>
|
|
37614
|
+
</div>
|
|
37615
|
+
|
|
37616
|
+
<!-- Energy -->
|
|
37617
|
+
${generateDomainHTML("energy", "\u26A1", "Energy", data.energy)}
|
|
37618
|
+
|
|
37619
|
+
<!-- Water -->
|
|
37620
|
+
${generateDomainHTML("water", "\u{1F4A7}", "Water", data.water)}
|
|
37621
|
+
|
|
37622
|
+
<!-- Temperature -->
|
|
37623
|
+
${generateDomainHTML("temperature", "\u{1F321}\uFE0F", "Temperature", data.temperature, true)}
|
|
37624
|
+
</div>
|
|
37625
|
+
|
|
37626
|
+
<!-- Footer -->
|
|
37627
|
+
<div class="myio-contract-summary-tooltip__footer">
|
|
37628
|
+
<span class="myio-contract-summary-tooltip__footer-label">Loaded at</span>
|
|
37629
|
+
<span class="myio-contract-summary-tooltip__footer-value">${timestamp}</span>
|
|
37630
|
+
</div>
|
|
37631
|
+
`;
|
|
37632
|
+
}
|
|
37633
|
+
function setupHoverListeners5(container) {
|
|
37634
|
+
container.onmouseenter = () => {
|
|
37635
|
+
state5.isMouseOverTooltip = true;
|
|
37636
|
+
if (state5.hideTimer) {
|
|
37637
|
+
clearTimeout(state5.hideTimer);
|
|
37638
|
+
state5.hideTimer = null;
|
|
37639
|
+
}
|
|
37640
|
+
};
|
|
37641
|
+
container.onmouseleave = () => {
|
|
37642
|
+
state5.isMouseOverTooltip = false;
|
|
37643
|
+
startDelayedHide5();
|
|
37644
|
+
};
|
|
37645
|
+
}
|
|
37646
|
+
function setupDomainToggleListeners(container) {
|
|
37647
|
+
const toggles = container.querySelectorAll("[data-toggle-domain]");
|
|
37648
|
+
toggles.forEach((toggle) => {
|
|
37649
|
+
toggle.onclick = (e) => {
|
|
37650
|
+
e.stopPropagation();
|
|
37651
|
+
const domain = toggle.dataset.toggleDomain;
|
|
37652
|
+
if (!domain) return;
|
|
37653
|
+
const domainEl = container.querySelector(`[data-domain="${domain}"]`);
|
|
37654
|
+
if (!domainEl) return;
|
|
37655
|
+
if (state5.expandedDomains.has(domain)) {
|
|
37656
|
+
state5.expandedDomains.delete(domain);
|
|
37657
|
+
domainEl.classList.remove("expanded");
|
|
37658
|
+
} else {
|
|
37659
|
+
state5.expandedDomains.add(domain);
|
|
37660
|
+
domainEl.classList.add("expanded");
|
|
37661
|
+
}
|
|
37662
|
+
};
|
|
37663
|
+
});
|
|
37664
|
+
}
|
|
37665
|
+
function setupButtonListeners5(container) {
|
|
37666
|
+
const buttons = container.querySelectorAll("[data-action]");
|
|
37667
|
+
buttons.forEach((btn) => {
|
|
37668
|
+
btn.onclick = (e) => {
|
|
37669
|
+
e.stopPropagation();
|
|
37670
|
+
const action = btn.dataset.action;
|
|
37671
|
+
switch (action) {
|
|
37672
|
+
case "pin":
|
|
37673
|
+
createPinnedClone5(container);
|
|
37674
|
+
break;
|
|
37675
|
+
case "maximize":
|
|
37676
|
+
toggleMaximize5(container);
|
|
37677
|
+
break;
|
|
37678
|
+
case "close":
|
|
37679
|
+
ContractSummaryTooltip.close();
|
|
37680
|
+
break;
|
|
37681
|
+
}
|
|
37682
|
+
};
|
|
37683
|
+
});
|
|
37684
|
+
}
|
|
37685
|
+
function setupDragListeners5(container) {
|
|
37686
|
+
const header = container.querySelector("[data-drag-handle]");
|
|
37687
|
+
if (!header) return;
|
|
37688
|
+
header.onmousedown = (e) => {
|
|
37689
|
+
if (e.target.closest("[data-action]")) return;
|
|
37690
|
+
if (e.target.closest("[data-toggle-domain]")) return;
|
|
37691
|
+
if (state5.isMaximized) return;
|
|
37692
|
+
state5.isDragging = true;
|
|
37693
|
+
container.classList.add("dragging");
|
|
37694
|
+
const rect = container.getBoundingClientRect();
|
|
37695
|
+
state5.dragOffset = {
|
|
37696
|
+
x: e.clientX - rect.left,
|
|
37697
|
+
y: e.clientY - rect.top
|
|
37698
|
+
};
|
|
37699
|
+
const onMouseMove = (e2) => {
|
|
37700
|
+
if (!state5.isDragging) return;
|
|
37701
|
+
const newLeft = e2.clientX - state5.dragOffset.x;
|
|
37702
|
+
const newTop = e2.clientY - state5.dragOffset.y;
|
|
37703
|
+
const maxLeft = window.innerWidth - container.offsetWidth;
|
|
37704
|
+
const maxTop = window.innerHeight - container.offsetHeight;
|
|
37705
|
+
container.style.left = Math.max(0, Math.min(newLeft, maxLeft)) + "px";
|
|
37706
|
+
container.style.top = Math.max(0, Math.min(newTop, maxTop)) + "px";
|
|
37707
|
+
};
|
|
37708
|
+
const onMouseUp = () => {
|
|
37709
|
+
state5.isDragging = false;
|
|
37710
|
+
container.classList.remove("dragging");
|
|
37711
|
+
document.removeEventListener("mousemove", onMouseMove);
|
|
37712
|
+
document.removeEventListener("mouseup", onMouseUp);
|
|
37713
|
+
};
|
|
37714
|
+
document.addEventListener("mousemove", onMouseMove);
|
|
37715
|
+
document.addEventListener("mouseup", onMouseUp);
|
|
37716
|
+
};
|
|
37717
|
+
}
|
|
37718
|
+
function createPinnedClone5(container) {
|
|
37719
|
+
state5.pinnedCounter++;
|
|
37720
|
+
const pinnedId = `myio-contract-summary-tooltip-pinned-${state5.pinnedCounter}`;
|
|
37721
|
+
const clone = container.cloneNode(true);
|
|
37722
|
+
clone.id = pinnedId;
|
|
37723
|
+
clone.classList.add("pinned");
|
|
37724
|
+
clone.classList.remove("closing");
|
|
37725
|
+
const pinBtn = clone.querySelector('[data-action="pin"]');
|
|
37726
|
+
if (pinBtn) {
|
|
37727
|
+
pinBtn.classList.add("pinned");
|
|
37728
|
+
pinBtn.setAttribute("title", "Unpin");
|
|
37729
|
+
pinBtn.innerHTML = `
|
|
37730
|
+
<svg viewBox="0 0 24 24" fill="currentColor" stroke="currentColor" stroke-width="1">
|
|
37731
|
+
<path d="M9 4v6l-2 4v2h10v-2l-2-4V4"/>
|
|
37732
|
+
<line x1="12" y1="16" x2="12" y2="21"/>
|
|
37733
|
+
<line x1="8" y1="4" x2="16" y2="4"/>
|
|
37734
|
+
</svg>
|
|
37735
|
+
`;
|
|
37736
|
+
}
|
|
37737
|
+
document.body.appendChild(clone);
|
|
37738
|
+
setupPinnedCloneListeners5(clone, pinnedId);
|
|
37739
|
+
ContractSummaryTooltip.hide();
|
|
37740
|
+
}
|
|
37741
|
+
function setupPinnedCloneListeners5(clone, cloneId) {
|
|
37742
|
+
let isMaximized = false;
|
|
37743
|
+
let savedPosition = null;
|
|
37744
|
+
const cloneExpandedDomains = new Set(state5.expandedDomains);
|
|
37745
|
+
const toggles = clone.querySelectorAll("[data-toggle-domain]");
|
|
37746
|
+
toggles.forEach((toggle) => {
|
|
37747
|
+
toggle.onclick = (e) => {
|
|
37748
|
+
e.stopPropagation();
|
|
37749
|
+
const domain = toggle.dataset.toggleDomain;
|
|
37750
|
+
if (!domain) return;
|
|
37751
|
+
const domainEl = clone.querySelector(`[data-domain="${domain}"]`);
|
|
37752
|
+
if (!domainEl) return;
|
|
37753
|
+
if (cloneExpandedDomains.has(domain)) {
|
|
37754
|
+
cloneExpandedDomains.delete(domain);
|
|
37755
|
+
domainEl.classList.remove("expanded");
|
|
37756
|
+
} else {
|
|
37757
|
+
cloneExpandedDomains.add(domain);
|
|
37758
|
+
domainEl.classList.add("expanded");
|
|
37759
|
+
}
|
|
37760
|
+
};
|
|
37761
|
+
});
|
|
37762
|
+
const pinBtn = clone.querySelector('[data-action="pin"]');
|
|
37763
|
+
if (pinBtn) {
|
|
37764
|
+
pinBtn.onclick = (e) => {
|
|
37765
|
+
e.stopPropagation();
|
|
37766
|
+
closePinnedClone5(cloneId);
|
|
37767
|
+
};
|
|
37768
|
+
}
|
|
37769
|
+
const closeBtn = clone.querySelector('[data-action="close"]');
|
|
37770
|
+
if (closeBtn) {
|
|
37771
|
+
closeBtn.onclick = (e) => {
|
|
37772
|
+
e.stopPropagation();
|
|
37773
|
+
closePinnedClone5(cloneId);
|
|
37774
|
+
};
|
|
37775
|
+
}
|
|
37776
|
+
const maxBtn = clone.querySelector('[data-action="maximize"]');
|
|
37777
|
+
if (maxBtn) {
|
|
37778
|
+
maxBtn.onclick = (e) => {
|
|
37779
|
+
e.stopPropagation();
|
|
37780
|
+
isMaximized = !isMaximized;
|
|
37781
|
+
if (isMaximized) {
|
|
37782
|
+
savedPosition = { left: clone.style.left, top: clone.style.top };
|
|
37783
|
+
maxBtn.innerHTML = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="5" y="5" width="14" height="14" rx="2"/><path d="M9 5V3h12v12h-2"/></svg>`;
|
|
37784
|
+
maxBtn.setAttribute("title", "Restore");
|
|
37785
|
+
} else {
|
|
37786
|
+
maxBtn.innerHTML = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="3" width="18" height="18" rx="2"/></svg>`;
|
|
37787
|
+
maxBtn.setAttribute("title", "Maximize");
|
|
37788
|
+
if (savedPosition) {
|
|
37789
|
+
clone.style.left = savedPosition.left;
|
|
37790
|
+
clone.style.top = savedPosition.top;
|
|
37791
|
+
}
|
|
37792
|
+
}
|
|
37793
|
+
clone.classList.toggle("maximized", isMaximized);
|
|
37794
|
+
};
|
|
37795
|
+
}
|
|
37796
|
+
const header = clone.querySelector("[data-drag-handle]");
|
|
37797
|
+
if (header) {
|
|
37798
|
+
let isDragging = false;
|
|
37799
|
+
let dragOffset = { x: 0, y: 0 };
|
|
37800
|
+
header.onmousedown = (e) => {
|
|
37801
|
+
if (e.target.closest("[data-action]")) return;
|
|
37802
|
+
if (e.target.closest("[data-toggle-domain]")) return;
|
|
37803
|
+
if (isMaximized) return;
|
|
37804
|
+
isDragging = true;
|
|
37805
|
+
clone.classList.add("dragging");
|
|
37806
|
+
const rect = clone.getBoundingClientRect();
|
|
37807
|
+
dragOffset = { x: e.clientX - rect.left, y: e.clientY - rect.top };
|
|
37808
|
+
const onMouseMove = (e2) => {
|
|
37809
|
+
if (!isDragging) return;
|
|
37810
|
+
const newLeft = e2.clientX - dragOffset.x;
|
|
37811
|
+
const newTop = e2.clientY - dragOffset.y;
|
|
37812
|
+
const maxLeft = window.innerWidth - clone.offsetWidth;
|
|
37813
|
+
const maxTop = window.innerHeight - clone.offsetHeight;
|
|
37814
|
+
clone.style.left = Math.max(0, Math.min(newLeft, maxLeft)) + "px";
|
|
37815
|
+
clone.style.top = Math.max(0, Math.min(newTop, maxTop)) + "px";
|
|
37816
|
+
};
|
|
37817
|
+
const onMouseUp = () => {
|
|
37818
|
+
isDragging = false;
|
|
37819
|
+
clone.classList.remove("dragging");
|
|
37820
|
+
document.removeEventListener("mousemove", onMouseMove);
|
|
37821
|
+
document.removeEventListener("mouseup", onMouseUp);
|
|
37822
|
+
};
|
|
37823
|
+
document.addEventListener("mousemove", onMouseMove);
|
|
37824
|
+
document.addEventListener("mouseup", onMouseUp);
|
|
37825
|
+
};
|
|
37826
|
+
}
|
|
37827
|
+
}
|
|
37828
|
+
function closePinnedClone5(cloneId) {
|
|
37829
|
+
const clone = document.getElementById(cloneId);
|
|
37830
|
+
if (clone) {
|
|
37831
|
+
clone.classList.add("closing");
|
|
37832
|
+
setTimeout(() => clone.remove(), 400);
|
|
37833
|
+
}
|
|
37834
|
+
}
|
|
37835
|
+
function toggleMaximize5(container) {
|
|
37836
|
+
state5.isMaximized = !state5.isMaximized;
|
|
37837
|
+
if (state5.isMaximized) {
|
|
37838
|
+
state5.savedPosition = {
|
|
37839
|
+
left: container.style.left,
|
|
37840
|
+
top: container.style.top
|
|
37841
|
+
};
|
|
37842
|
+
}
|
|
37843
|
+
container.classList.toggle("maximized", state5.isMaximized);
|
|
37844
|
+
const maxBtn = container.querySelector('[data-action="maximize"]');
|
|
37845
|
+
if (maxBtn) {
|
|
37846
|
+
if (state5.isMaximized) {
|
|
37847
|
+
maxBtn.innerHTML = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="5" y="5" width="14" height="14" rx="2"/><path d="M9 5V3h12v12h-2"/></svg>`;
|
|
37848
|
+
maxBtn.setAttribute("title", "Restore");
|
|
37849
|
+
} else {
|
|
37850
|
+
maxBtn.innerHTML = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="3" width="18" height="18" rx="2"/></svg>`;
|
|
37851
|
+
maxBtn.setAttribute("title", "Maximize");
|
|
37852
|
+
if (state5.savedPosition) {
|
|
37853
|
+
container.style.left = state5.savedPosition.left;
|
|
37854
|
+
container.style.top = state5.savedPosition.top;
|
|
37855
|
+
}
|
|
37856
|
+
}
|
|
37857
|
+
}
|
|
37858
|
+
}
|
|
37859
|
+
function startDelayedHide5() {
|
|
37860
|
+
if (state5.isMouseOverTooltip) return;
|
|
37861
|
+
if (state5.hideTimer) {
|
|
37862
|
+
clearTimeout(state5.hideTimer);
|
|
37863
|
+
}
|
|
37864
|
+
state5.hideTimer = setTimeout(() => {
|
|
37865
|
+
hideWithAnimation5();
|
|
37866
|
+
}, 1500);
|
|
37867
|
+
}
|
|
37868
|
+
function hideWithAnimation5() {
|
|
37869
|
+
const container = document.getElementById("myio-contract-summary-tooltip");
|
|
37870
|
+
if (container && container.classList.contains("visible")) {
|
|
37871
|
+
container.classList.add("closing");
|
|
37872
|
+
setTimeout(() => {
|
|
37873
|
+
container.classList.remove("visible", "closing");
|
|
37874
|
+
}, 400);
|
|
37875
|
+
}
|
|
37876
|
+
}
|
|
37877
|
+
function positionTooltip5(container, triggerElement) {
|
|
37878
|
+
const rect = triggerElement.getBoundingClientRect();
|
|
37879
|
+
let left = rect.left;
|
|
37880
|
+
let top = rect.bottom + 8;
|
|
37881
|
+
const tooltipWidth = 360;
|
|
37882
|
+
if (left + tooltipWidth > window.innerWidth - 20) {
|
|
37883
|
+
left = window.innerWidth - tooltipWidth - 20;
|
|
37884
|
+
}
|
|
37885
|
+
if (left < 10) left = 10;
|
|
37886
|
+
if (top + 500 > window.innerHeight) {
|
|
37887
|
+
top = rect.top - 8 - 500;
|
|
37888
|
+
if (top < 10) top = 10;
|
|
37889
|
+
}
|
|
37890
|
+
container.style.left = left + "px";
|
|
37891
|
+
container.style.top = top + "px";
|
|
37892
|
+
}
|
|
37893
|
+
var ContractSummaryTooltip = {
|
|
37894
|
+
containerId: "myio-contract-summary-tooltip",
|
|
37895
|
+
/**
|
|
37896
|
+
* Get or create container
|
|
37897
|
+
*/
|
|
37898
|
+
getContainer() {
|
|
37899
|
+
injectCSS9();
|
|
37900
|
+
let container = document.getElementById(this.containerId);
|
|
37901
|
+
if (!container) {
|
|
37902
|
+
container = document.createElement("div");
|
|
37903
|
+
container.id = this.containerId;
|
|
37904
|
+
container.className = "myio-contract-summary-tooltip";
|
|
37905
|
+
document.body.appendChild(container);
|
|
37906
|
+
}
|
|
37907
|
+
return container;
|
|
37908
|
+
},
|
|
37909
|
+
/**
|
|
37910
|
+
* Show tooltip
|
|
37911
|
+
*/
|
|
37912
|
+
show(triggerElement, data) {
|
|
37913
|
+
if (state5.hideTimer) {
|
|
37914
|
+
clearTimeout(state5.hideTimer);
|
|
37915
|
+
state5.hideTimer = null;
|
|
37916
|
+
}
|
|
37917
|
+
const container = this.getContainer();
|
|
37918
|
+
container.classList.remove("closing");
|
|
37919
|
+
container.innerHTML = `
|
|
37920
|
+
<div class="myio-contract-summary-tooltip__panel">
|
|
37921
|
+
${generateHeaderHTML5(data)}
|
|
37922
|
+
${generateBodyHTML3(data)}
|
|
37923
|
+
</div>
|
|
37924
|
+
`;
|
|
37925
|
+
positionTooltip5(container, triggerElement);
|
|
37926
|
+
container.classList.add("visible");
|
|
37927
|
+
setupHoverListeners5(container);
|
|
37928
|
+
setupButtonListeners5(container);
|
|
37929
|
+
setupDragListeners5(container);
|
|
37930
|
+
setupDomainToggleListeners(container);
|
|
37931
|
+
},
|
|
37932
|
+
/**
|
|
37933
|
+
* Start delayed hide
|
|
37934
|
+
*/
|
|
37935
|
+
startDelayedHide() {
|
|
37936
|
+
startDelayedHide5();
|
|
37937
|
+
},
|
|
37938
|
+
/**
|
|
37939
|
+
* Hide immediately
|
|
37940
|
+
*/
|
|
37941
|
+
hide() {
|
|
37942
|
+
if (state5.hideTimer) {
|
|
37943
|
+
clearTimeout(state5.hideTimer);
|
|
37944
|
+
state5.hideTimer = null;
|
|
37945
|
+
}
|
|
37946
|
+
state5.isMouseOverTooltip = false;
|
|
37947
|
+
const container = document.getElementById(this.containerId);
|
|
37948
|
+
if (container) {
|
|
37949
|
+
container.classList.remove("visible", "closing");
|
|
37950
|
+
}
|
|
37951
|
+
},
|
|
37952
|
+
/**
|
|
37953
|
+
* Close and reset all states
|
|
37954
|
+
*/
|
|
37955
|
+
close() {
|
|
37956
|
+
state5.isMaximized = false;
|
|
37957
|
+
state5.isDragging = false;
|
|
37958
|
+
state5.savedPosition = null;
|
|
37959
|
+
if (state5.hideTimer) {
|
|
37960
|
+
clearTimeout(state5.hideTimer);
|
|
37961
|
+
state5.hideTimer = null;
|
|
37962
|
+
}
|
|
37963
|
+
state5.isMouseOverTooltip = false;
|
|
37964
|
+
const container = document.getElementById(this.containerId);
|
|
37965
|
+
if (container) {
|
|
37966
|
+
container.classList.remove("visible", "pinned", "maximized", "dragging", "closing");
|
|
37967
|
+
}
|
|
37968
|
+
},
|
|
37969
|
+
/**
|
|
37970
|
+
* Attach tooltip to trigger element with click behavior
|
|
37971
|
+
*/
|
|
37972
|
+
attach(triggerElement, getDataFn) {
|
|
37973
|
+
const self = this;
|
|
37974
|
+
const handleClick = () => {
|
|
37975
|
+
if (state5.hideTimer) {
|
|
37976
|
+
clearTimeout(state5.hideTimer);
|
|
37977
|
+
state5.hideTimer = null;
|
|
37978
|
+
}
|
|
37979
|
+
const data = getDataFn();
|
|
37980
|
+
if (data) {
|
|
37981
|
+
self.show(triggerElement, data);
|
|
37982
|
+
}
|
|
37983
|
+
};
|
|
37984
|
+
triggerElement.addEventListener("click", handleClick);
|
|
37985
|
+
return () => {
|
|
37986
|
+
triggerElement.removeEventListener("click", handleClick);
|
|
37987
|
+
self.hide();
|
|
37988
|
+
};
|
|
37989
|
+
},
|
|
37990
|
+
/**
|
|
37991
|
+
* Attach tooltip with hover behavior
|
|
37992
|
+
*/
|
|
37993
|
+
attachHover(triggerElement, getDataFn) {
|
|
37994
|
+
const self = this;
|
|
37995
|
+
const handleMouseEnter = () => {
|
|
37996
|
+
if (state5.hideTimer) {
|
|
37997
|
+
clearTimeout(state5.hideTimer);
|
|
37998
|
+
state5.hideTimer = null;
|
|
37999
|
+
}
|
|
38000
|
+
const data = getDataFn();
|
|
38001
|
+
if (data) {
|
|
38002
|
+
self.show(triggerElement, data);
|
|
38003
|
+
}
|
|
38004
|
+
};
|
|
38005
|
+
const handleMouseLeave = () => {
|
|
38006
|
+
startDelayedHide5();
|
|
38007
|
+
};
|
|
38008
|
+
triggerElement.addEventListener("mouseenter", handleMouseEnter);
|
|
38009
|
+
triggerElement.addEventListener("mouseleave", handleMouseLeave);
|
|
38010
|
+
return () => {
|
|
38011
|
+
triggerElement.removeEventListener("mouseenter", handleMouseEnter);
|
|
38012
|
+
triggerElement.removeEventListener("mouseleave", handleMouseLeave);
|
|
38013
|
+
self.hide();
|
|
38014
|
+
};
|
|
38015
|
+
},
|
|
38016
|
+
/**
|
|
38017
|
+
* Build contract data from window.CONTRACT_STATE
|
|
38018
|
+
* Helper method to build the data structure from global state
|
|
38019
|
+
*/
|
|
38020
|
+
buildFromGlobalState() {
|
|
38021
|
+
const globalState = window.CONTRACT_STATE;
|
|
38022
|
+
if (!globalState) return null;
|
|
38023
|
+
return {
|
|
38024
|
+
isLoaded: globalState.isLoaded ?? false,
|
|
38025
|
+
isValid: globalState.isValid ?? false,
|
|
38026
|
+
timestamp: globalState.timestamp ?? null,
|
|
38027
|
+
energy: {
|
|
38028
|
+
total: globalState.energy?.total ?? 0,
|
|
38029
|
+
entries: globalState.energy?.entries ?? 0,
|
|
38030
|
+
commonArea: globalState.energy?.commonArea ?? 0,
|
|
38031
|
+
stores: globalState.energy?.stores ?? 0
|
|
38032
|
+
},
|
|
38033
|
+
water: {
|
|
38034
|
+
total: globalState.water?.total ?? 0,
|
|
38035
|
+
entries: globalState.water?.entries ?? 0,
|
|
38036
|
+
commonArea: globalState.water?.commonArea ?? 0,
|
|
38037
|
+
stores: globalState.water?.stores ?? 0
|
|
38038
|
+
},
|
|
38039
|
+
temperature: {
|
|
38040
|
+
total: globalState.temperature?.total ?? 0,
|
|
38041
|
+
internal: globalState.temperature?.internal ?? 0,
|
|
38042
|
+
stores: globalState.temperature?.stores ?? 0
|
|
38043
|
+
},
|
|
38044
|
+
discrepancies: globalState.discrepancies
|
|
38045
|
+
};
|
|
38046
|
+
}
|
|
38047
|
+
};
|
|
38048
|
+
|
|
37042
38049
|
// src/components/ModalHeader/index.ts
|
|
37043
38050
|
var DEFAULT_BG_COLOR = "#3e1a7d";
|
|
37044
38051
|
var DEFAULT_TEXT_COLOR = "white";
|
|
@@ -40797,6 +41804,7 @@
|
|
|
40797
41804
|
exports.CONSUMPTION_CHART_DEFAULTS = DEFAULT_CONFIG;
|
|
40798
41805
|
exports.CONSUMPTION_THEME_COLORS = THEME_COLORS;
|
|
40799
41806
|
exports.ConnectionStatusType = ConnectionStatusType;
|
|
41807
|
+
exports.ContractSummaryTooltip = ContractSummaryTooltip;
|
|
40800
41808
|
exports.DEFAULT_CLAMP_RANGE = DEFAULT_CLAMP_RANGE;
|
|
40801
41809
|
exports.DEFAULT_ENERGY_GROUP_COLORS = DEFAULT_ENERGY_GROUP_COLORS;
|
|
40802
41810
|
exports.DEFAULT_GAS_GROUP_COLORS = DEFAULT_GAS_GROUP_COLORS;
|