myio-js-library 0.1.551 → 0.1.553
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 +524 -140
- package/dist/index.d.cts +21 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.js +524 -140
- package/dist/myio-js-library.umd.js +524 -141
- package/dist/myio-js-library.umd.min.js +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -899,7 +899,7 @@ module.exports = __toCommonJS(src_exports);
|
|
|
899
899
|
// package.json
|
|
900
900
|
var package_default = {
|
|
901
901
|
name: "myio-js-library",
|
|
902
|
-
version: "0.1.
|
|
902
|
+
version: "0.1.553",
|
|
903
903
|
description: "A clean, standalone JS SDK for MYIO projects",
|
|
904
904
|
license: "MIT",
|
|
905
905
|
repository: "github:gh-myio/myio-js-library",
|
|
@@ -5568,12 +5568,14 @@ var ModalHeader = {
|
|
|
5568
5568
|
showClose = true,
|
|
5569
5569
|
primaryColor = "#3e1a7d",
|
|
5570
5570
|
borderRadius = "10px 10px 0 0",
|
|
5571
|
-
draggable = true
|
|
5571
|
+
draggable = true,
|
|
5572
|
+
solid = false
|
|
5572
5573
|
} = options;
|
|
5573
5574
|
const isDark = theme === "dark";
|
|
5574
|
-
const
|
|
5575
|
-
const
|
|
5576
|
-
const
|
|
5575
|
+
const solidStyle = isDark || solid;
|
|
5576
|
+
const bgColor = solidStyle ? primaryColor : "linear-gradient(90deg, #f1f5f9 0%, #e2e8f0 100%)";
|
|
5577
|
+
const textColor = solidStyle ? "white" : "#475569";
|
|
5578
|
+
const btnColor = solidStyle ? "rgba(255,255,255,0.8)" : "rgba(71,85,105,0.8)";
|
|
5577
5579
|
const headerStyle = `
|
|
5578
5580
|
padding: 8px 12px;
|
|
5579
5581
|
display: flex;
|
|
@@ -33572,31 +33574,52 @@ var fmtPt = (n) => new Intl.NumberFormat("pt-BR", { minimumFractionDigits: 2, ma
|
|
|
33572
33574
|
|
|
33573
33575
|
// src/components/telemetry-grid-shopping/export.ts
|
|
33574
33576
|
var import_jspdf = require("jspdf");
|
|
33577
|
+
function extras(d) {
|
|
33578
|
+
return d;
|
|
33579
|
+
}
|
|
33575
33580
|
function makeCols(unit, colOpts) {
|
|
33576
33581
|
const cols = [
|
|
33577
33582
|
{ key: "idx", label: "#", pdfW: 10 },
|
|
33578
33583
|
{ key: "nome", label: colOpts?.nameLabel || "Nome", pdfW: 100 },
|
|
33579
33584
|
{ key: "identificador", label: "Identificador", pdfW: 60 },
|
|
33580
33585
|
{ key: "consumo", label: colOpts?.valueLabel || (unit ? `Consumo (${unit})` : "Consumo"), pdfW: 50 },
|
|
33586
|
+
...(colOpts?.extraColumns || []).map((c, i) => ({ key: `x${i}`, label: c.label, pdfW: c.pdfW ?? 40 })),
|
|
33581
33587
|
{ key: "perc", label: "%", pdfW: 20 }
|
|
33582
33588
|
];
|
|
33583
33589
|
return cols.filter(
|
|
33584
33590
|
(c) => !(colOpts?.hideIdentifier && c.key === "identificador") && !(colOpts?.hidePerc && c.key === "perc")
|
|
33585
33591
|
);
|
|
33586
33592
|
}
|
|
33587
|
-
function buildRow(d, idx) {
|
|
33593
|
+
function buildRow(d, idx, colOpts) {
|
|
33594
|
+
const x = extras(d);
|
|
33588
33595
|
const fmtVal = () => {
|
|
33589
|
-
if (d.val === null || d.val === void 0) return "\u2014";
|
|
33596
|
+
if (d.val === null || d.val === void 0) return colOpts?.emptyValueText || "\u2014";
|
|
33590
33597
|
return Number(d.val).toLocaleString("pt-BR", { maximumFractionDigits: 3, useGrouping: false });
|
|
33591
33598
|
};
|
|
33592
33599
|
const pd = resolvePercentDecimals();
|
|
33593
|
-
|
|
33600
|
+
const name = d.labelOrName || d.name || "\u2014";
|
|
33601
|
+
const row = {
|
|
33594
33602
|
idx: String(idx + 1),
|
|
33595
|
-
nome:
|
|
33603
|
+
nome: x.nameNote ? `${name} (${x.nameNote})` : name,
|
|
33596
33604
|
identificador: d.deviceIdentifier || "\u2014",
|
|
33597
33605
|
consumo: fmtVal(),
|
|
33598
33606
|
perc: d.perc !== void 0 ? `${d.perc.toFixed(pd).replace(".", ",")}%` : "\u2014"
|
|
33599
33607
|
};
|
|
33608
|
+
(colOpts?.extraColumns || []).forEach((_, i) => {
|
|
33609
|
+
row[`x${i}`] = x.extraCells?.[i] ?? "\u2014";
|
|
33610
|
+
});
|
|
33611
|
+
return row;
|
|
33612
|
+
}
|
|
33613
|
+
function forEachRow(devices, onGroup, onRow) {
|
|
33614
|
+
let n = 0;
|
|
33615
|
+
devices.forEach((d) => {
|
|
33616
|
+
const g = extras(d).groupHeader;
|
|
33617
|
+
if (g) onGroup(g);
|
|
33618
|
+
else onRow(d, n++);
|
|
33619
|
+
});
|
|
33620
|
+
}
|
|
33621
|
+
function countDataRows(devices) {
|
|
33622
|
+
return devices.filter((d) => !extras(d).groupHeader).length;
|
|
33600
33623
|
}
|
|
33601
33624
|
function fmtPeriod(period) {
|
|
33602
33625
|
if (!period?.startISO) return "";
|
|
@@ -33644,10 +33667,15 @@ function exportGridCsv(devices, label, unit, period, customerName) {
|
|
|
33644
33667
|
].filter((v) => v !== null);
|
|
33645
33668
|
const cols = makeCols(unit);
|
|
33646
33669
|
const header = cols.map((c) => `"${c.label}"`).join(";");
|
|
33647
|
-
const rows =
|
|
33648
|
-
|
|
33649
|
-
|
|
33650
|
-
|
|
33670
|
+
const rows = [];
|
|
33671
|
+
forEachRow(
|
|
33672
|
+
devices,
|
|
33673
|
+
(g) => rows.push(`"${g.replace(/"/g, '""')}"`),
|
|
33674
|
+
(d, i) => {
|
|
33675
|
+
const r = buildRow(d, i);
|
|
33676
|
+
rows.push(cols.map((c) => `"${String(r[c.key]).replace(/"/g, '""')}"`).join(";"));
|
|
33677
|
+
}
|
|
33678
|
+
);
|
|
33651
33679
|
const csv = "\uFEFF" + [...metaRows, header, ...rows].join("\r\n");
|
|
33652
33680
|
triggerDownload(
|
|
33653
33681
|
new Blob([csv], { type: "text/csv;charset=utf-8;" }),
|
|
@@ -33663,14 +33691,23 @@ function exportGridXls(devices, label, unit, period, customerName, options) {
|
|
|
33663
33691
|
const headerCells = cols.map(
|
|
33664
33692
|
(c) => `<Cell ss:StyleID="h"><Data ss:Type="String">${escXml(c.label)}</Data></Cell>`
|
|
33665
33693
|
).join("");
|
|
33666
|
-
const
|
|
33667
|
-
|
|
33668
|
-
|
|
33669
|
-
|
|
33670
|
-
|
|
33671
|
-
|
|
33672
|
-
|
|
33673
|
-
|
|
33694
|
+
const dataRowsArr = [];
|
|
33695
|
+
forEachRow(
|
|
33696
|
+
devices,
|
|
33697
|
+
(g) => dataRowsArr.push(
|
|
33698
|
+
`<Row><Cell ss:StyleID="g" ss:MergeAcross="${cols.length - 1}"><Data ss:Type="String">${escXml(g)}</Data></Cell></Row>`
|
|
33699
|
+
),
|
|
33700
|
+
(d, i) => {
|
|
33701
|
+
const r = buildRow(d, i, options?.columns);
|
|
33702
|
+
const cells = cols.map((c) => {
|
|
33703
|
+
const v = escXml(String(r[c.key]));
|
|
33704
|
+
return `<Cell><Data ss:Type="String">${v}</Data></Cell>`;
|
|
33705
|
+
}).join("");
|
|
33706
|
+
dataRowsArr.push(`<Row>${cells}</Row>`);
|
|
33707
|
+
}
|
|
33708
|
+
);
|
|
33709
|
+
const dataRows = dataRowsArr.join("\n");
|
|
33710
|
+
const kpiRows = (options?.kpis || []).map((k) => metaRow(k.label, k.sub ? `${k.value} (${k.sub})` : k.value)).join("\n");
|
|
33674
33711
|
const xml = `<?xml version="1.0" encoding="UTF-8"?>
|
|
33675
33712
|
<Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet"
|
|
33676
33713
|
xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet">
|
|
@@ -33683,6 +33720,10 @@ function exportGridXls(devices, label, unit, period, customerName, options) {
|
|
|
33683
33720
|
<Font ss:Bold="1"/>
|
|
33684
33721
|
<Interior ss:Color="#F0EDF9" ss:Pattern="Solid"/>
|
|
33685
33722
|
</Style>
|
|
33723
|
+
<Style ss:ID="g">
|
|
33724
|
+
<Font ss:Bold="1" ss:Color="#555555"/>
|
|
33725
|
+
<Interior ss:Color="#EEEEEE" ss:Pattern="Solid"/>
|
|
33726
|
+
</Style>
|
|
33686
33727
|
</Styles>
|
|
33687
33728
|
<Worksheet ss:Name="${escXml(label.slice(0, 31))}">
|
|
33688
33729
|
<Table>
|
|
@@ -33690,6 +33731,8 @@ function exportGridXls(devices, label, unit, period, customerName, options) {
|
|
|
33690
33731
|
${customerName ? metaRow("Cliente", customerName) : ""}
|
|
33691
33732
|
${periodLabel2 ? metaRow("Per\xEDodo", periodLabel2) : ""}
|
|
33692
33733
|
${metaRow("Gerado em", (/* @__PURE__ */ new Date()).toLocaleString("pt-BR"))}
|
|
33734
|
+
${kpiRows ? `<Row/>
|
|
33735
|
+
${kpiRows}` : ""}
|
|
33693
33736
|
<Row/>
|
|
33694
33737
|
<Row>${headerCells}</Row>
|
|
33695
33738
|
${dataRows}
|
|
@@ -33744,7 +33787,8 @@ function exportGridPdf(devices, label, unit, period, customerName, options) {
|
|
|
33744
33787
|
doc.setFontSize(8);
|
|
33745
33788
|
const periodLabel2 = fmtPeriod(period);
|
|
33746
33789
|
const periodPart = periodLabel2 ? `Per\xEDodo: ${periodLabel2} \u2022 ` : "";
|
|
33747
|
-
const
|
|
33790
|
+
const countLabel = options?.columns?.countLabel || "dispositivo(s)";
|
|
33791
|
+
const info = `${periodPart}Gerado em: ${generatedAt} \u2022 ${countDataRows(devices)} ${countLabel} \u2022 Unidade: ${unit} \u2022 P\xE1g. ${pageNo2}`;
|
|
33748
33792
|
doc.text(info, PW - MARGIN, HDR_H / 2 + 1.5, { align: "right" });
|
|
33749
33793
|
}
|
|
33750
33794
|
function drawColumnHeaders(y) {
|
|
@@ -33779,6 +33823,14 @@ function exportGridPdf(devices, label, unit, period, customerName, options) {
|
|
|
33779
33823
|
doc.setLineWidth(0.1);
|
|
33780
33824
|
doc.line(MARGIN, y + ROW_H, MARGIN + TABLE_W, y + ROW_H);
|
|
33781
33825
|
}
|
|
33826
|
+
function drawGroupRow(text2, y) {
|
|
33827
|
+
doc.setFillColor(...ACCENT_SOFT);
|
|
33828
|
+
doc.rect(MARGIN, y, TABLE_W, ROW_H, "F");
|
|
33829
|
+
doc.setTextColor(...ACCENT2);
|
|
33830
|
+
doc.setFont("helvetica", "bold");
|
|
33831
|
+
doc.setFontSize(6.5);
|
|
33832
|
+
doc.text(truncate(text2, 160), MARGIN + 1.5, y + ROW_H / 2 + 2.2);
|
|
33833
|
+
}
|
|
33782
33834
|
function drawFooter2() {
|
|
33783
33835
|
doc.setFillColor(250, 249, 255);
|
|
33784
33836
|
doc.rect(0, PH - FTR_H, PW, FTR_H, "F");
|
|
@@ -33825,7 +33877,7 @@ function exportGridPdf(devices, label, unit, period, customerName, options) {
|
|
|
33825
33877
|
}
|
|
33826
33878
|
drawColumnHeaders(currentY);
|
|
33827
33879
|
currentY += HEAD_H;
|
|
33828
|
-
|
|
33880
|
+
const ensureSpace = () => {
|
|
33829
33881
|
if (currentY + ROW_H > MAX_Y) {
|
|
33830
33882
|
drawFooter2();
|
|
33831
33883
|
doc.addPage();
|
|
@@ -33835,9 +33887,20 @@ function exportGridPdf(devices, label, unit, period, customerName, options) {
|
|
|
33835
33887
|
drawColumnHeaders(currentY);
|
|
33836
33888
|
currentY += HEAD_H;
|
|
33837
33889
|
}
|
|
33838
|
-
|
|
33839
|
-
|
|
33840
|
-
|
|
33890
|
+
};
|
|
33891
|
+
forEachRow(
|
|
33892
|
+
devices,
|
|
33893
|
+
(g) => {
|
|
33894
|
+
ensureSpace();
|
|
33895
|
+
drawGroupRow(g, currentY);
|
|
33896
|
+
currentY += ROW_H;
|
|
33897
|
+
},
|
|
33898
|
+
(d, i) => {
|
|
33899
|
+
ensureSpace();
|
|
33900
|
+
drawDataRow(buildRow(d, i, options?.columns), currentY, i % 2 === 0);
|
|
33901
|
+
currentY += ROW_H;
|
|
33902
|
+
}
|
|
33903
|
+
);
|
|
33841
33904
|
drawFooter2();
|
|
33842
33905
|
const chart = options?.chartImage;
|
|
33843
33906
|
if (chart?.dataUrl) {
|
|
@@ -35088,6 +35151,81 @@ function createModalFooter(params = {}) {
|
|
|
35088
35151
|
};
|
|
35089
35152
|
}
|
|
35090
35153
|
|
|
35154
|
+
// src/components/premium-modals/internal/temperatureBarsPng.ts
|
|
35155
|
+
function renderTemperatureBarsPng(opts) {
|
|
35156
|
+
if (typeof document === "undefined" || !opts.items.length) return null;
|
|
35157
|
+
const W = 1400;
|
|
35158
|
+
const ROW = 34;
|
|
35159
|
+
const TOP = 56;
|
|
35160
|
+
const H = TOP + opts.items.length * ROW + 20;
|
|
35161
|
+
const canvas = document.createElement("canvas");
|
|
35162
|
+
canvas.width = W;
|
|
35163
|
+
canvas.height = H;
|
|
35164
|
+
let ctx = null;
|
|
35165
|
+
try {
|
|
35166
|
+
ctx = canvas.getContext("2d");
|
|
35167
|
+
} catch {
|
|
35168
|
+
ctx = null;
|
|
35169
|
+
}
|
|
35170
|
+
if (!ctx) return null;
|
|
35171
|
+
const fmt2 = (v) => v.toLocaleString("pt-BR", { minimumFractionDigits: 2, maximumFractionDigits: 2 });
|
|
35172
|
+
const ideal = opts.ideal && Number.isFinite(opts.ideal.min) && Number.isFinite(opts.ideal.max) ? opts.ideal : null;
|
|
35173
|
+
const values = opts.items.map((i) => i.value).filter((v) => v !== null && Number.isFinite(v));
|
|
35174
|
+
const base = values.length ? values : [20, 30];
|
|
35175
|
+
const lo = Math.floor(Math.min(...base, ideal ? ideal.min : Infinity) - 1);
|
|
35176
|
+
const hi = Math.ceil(Math.max(...base, ideal ? ideal.max : -Infinity) + 1);
|
|
35177
|
+
const span = Math.max(1, hi - lo);
|
|
35178
|
+
const LABEL_W = 460;
|
|
35179
|
+
const VALUE_W = 120;
|
|
35180
|
+
const trackX = LABEL_W + 20;
|
|
35181
|
+
const trackW = W - trackX - VALUE_W - 20;
|
|
35182
|
+
const xOf = (v) => trackX + (v - lo) / span * trackW;
|
|
35183
|
+
ctx.fillStyle = "#ffffff";
|
|
35184
|
+
ctx.fillRect(0, 0, W, H);
|
|
35185
|
+
ctx.fillStyle = "#6b7280";
|
|
35186
|
+
ctx.font = "20px Helvetica, Arial, sans-serif";
|
|
35187
|
+
ctx.textBaseline = "middle";
|
|
35188
|
+
const scale = `Escala ${fmt2(lo)}\u2013${fmt2(hi)} \xB0C`;
|
|
35189
|
+
ctx.fillText(ideal ? `${scale} \xB7 faixa ideal ${fmt2(ideal.min)}\u2013${fmt2(ideal.max)} \xB0C` : scale, 16, 26);
|
|
35190
|
+
opts.items.forEach((item, i) => {
|
|
35191
|
+
const y = TOP + i * ROW;
|
|
35192
|
+
const cy = y + ROW / 2;
|
|
35193
|
+
ctx.fillStyle = "#1f2937";
|
|
35194
|
+
ctx.font = "20px Helvetica, Arial, sans-serif";
|
|
35195
|
+
ctx.textAlign = "left";
|
|
35196
|
+
let label = item.label;
|
|
35197
|
+
while (ctx.measureText(label).width > LABEL_W - 10 && label.length > 4) label = label.slice(0, -2);
|
|
35198
|
+
if (label !== item.label) label = label.slice(0, -1) + "\u2026";
|
|
35199
|
+
ctx.fillText(label, 16, cy);
|
|
35200
|
+
if (item.value === null || !Number.isFinite(item.value)) {
|
|
35201
|
+
ctx.fillStyle = "#9ca3af";
|
|
35202
|
+
ctx.font = "italic 18px Helvetica, Arial, sans-serif";
|
|
35203
|
+
ctx.fillText("Sem leitura", trackX, cy);
|
|
35204
|
+
ctx.textAlign = "right";
|
|
35205
|
+
ctx.fillText("\u2014", W - 16, cy);
|
|
35206
|
+
return;
|
|
35207
|
+
}
|
|
35208
|
+
ctx.fillStyle = "#e5e7eb";
|
|
35209
|
+
ctx.fillRect(trackX, cy - 9, trackW, 18);
|
|
35210
|
+
if (ideal) {
|
|
35211
|
+
ctx.fillStyle = "rgba(34,197,94,0.18)";
|
|
35212
|
+
ctx.fillRect(xOf(ideal.min), cy - 9, xOf(ideal.max) - xOf(ideal.min), 18);
|
|
35213
|
+
}
|
|
35214
|
+
const v = item.value;
|
|
35215
|
+
ctx.fillStyle = ideal && v > ideal.max ? "#ef4444" : ideal && v < ideal.min ? "#3b82f6" : opts.accent || "#3e1a7d";
|
|
35216
|
+
ctx.fillRect(trackX, cy - 6, Math.max(2, xOf(v) - trackX), 12);
|
|
35217
|
+
ctx.fillStyle = "#111827";
|
|
35218
|
+
ctx.font = "bold 20px Helvetica, Arial, sans-serif";
|
|
35219
|
+
ctx.textAlign = "right";
|
|
35220
|
+
ctx.fillText(fmt2(v), W - 16, cy);
|
|
35221
|
+
});
|
|
35222
|
+
try {
|
|
35223
|
+
return { dataUrl: canvas.toDataURL("image/png"), width: W, height: H };
|
|
35224
|
+
} catch {
|
|
35225
|
+
return null;
|
|
35226
|
+
}
|
|
35227
|
+
}
|
|
35228
|
+
|
|
35091
35229
|
// src/components/premium-modals/report-device/DeviceReportModal.ts
|
|
35092
35230
|
var DOMAIN_CONFIG = {
|
|
35093
35231
|
energy: {
|
|
@@ -35659,11 +35797,26 @@ var DeviceReportModal = class {
|
|
|
35659
35797
|
);
|
|
35660
35798
|
const zeroCount = this.data.filter((r) => r.consumption <= 0).length;
|
|
35661
35799
|
const rowLabel = isHourly ? "Hora" : "Dia";
|
|
35800
|
+
let perDay;
|
|
35801
|
+
if (isTemperature) {
|
|
35802
|
+
const byDay = /* @__PURE__ */ new Map();
|
|
35803
|
+
for (const r of rows) {
|
|
35804
|
+
const k = r.date.slice(0, 10);
|
|
35805
|
+
const acc = byDay.get(k) || { sum: 0, n: 0 };
|
|
35806
|
+
acc.sum += r.consumption;
|
|
35807
|
+
acc.n += 1;
|
|
35808
|
+
byDay.set(k, acc);
|
|
35809
|
+
}
|
|
35810
|
+
const dayAvgs = [...byDay.values()].map((d) => d.sum / d.n);
|
|
35811
|
+
perDay = dayAvgs.length ? dayAvgs.reduce((x, y) => x + y, 0) / dayAvgs.length : 0;
|
|
35812
|
+
} else {
|
|
35813
|
+
perDay = total / dayCount;
|
|
35814
|
+
}
|
|
35662
35815
|
const kpis = [
|
|
35663
35816
|
{ value: `${fmt2(summaryValue)} ${unit}`, label: `${this.domainConfig.summaryLabel} (${unit})` },
|
|
35664
|
-
{ value: fmt2(
|
|
35817
|
+
{ value: fmt2(perDay), label: `M\xE9dia por Dia (${unit})` }
|
|
35665
35818
|
];
|
|
35666
|
-
if (isHourly) {
|
|
35819
|
+
if (isHourly && !isTemperature) {
|
|
35667
35820
|
kpis.push({ value: fmt2(rows.length ? total / rows.length : 0), label: `M\xE9dia por Hora (${unit})` });
|
|
35668
35821
|
}
|
|
35669
35822
|
kpis.push(
|
|
@@ -35866,10 +36019,22 @@ var DeviceReportModal = class {
|
|
|
35866
36019
|
const summaryValue = this.domainConfig.summaryType === "average" ? valid > 0 ? total / valid : 0 : total;
|
|
35867
36020
|
const now = /* @__PURE__ */ new Date();
|
|
35868
36021
|
const timestamp = now.toLocaleDateString("pt-BR") + " - " + now.toLocaleTimeString("pt-BR", { hour: "2-digit", minute: "2-digit" });
|
|
36022
|
+
const p = this.exportPeriod;
|
|
36023
|
+
const fmtD = (iso) => iso ? new Date(iso).toLocaleDateString("pt-BR") : "";
|
|
36024
|
+
const off = Number(this.params.temperatureOffset) || 0;
|
|
36025
|
+
const isTemp = this.domainConfig.summaryType === "average";
|
|
36026
|
+
void summaryValue;
|
|
35869
36027
|
const csvData = [
|
|
35870
36028
|
["Dispositivo/Loja", this.params.identifier || "N/A", this.params.label || ""],
|
|
36029
|
+
...this.params.deviceName ? [["Dispositivo (TB)", this.params.deviceName, ""]] : [],
|
|
36030
|
+
...isTemp && off !== 0 ? [["Offset aplicado (\xB0C)", this.domainConfig.formatter(off), ""]] : [],
|
|
36031
|
+
...this.resolveCustomerName() ? [["Cliente", this.resolveCustomerName(), ""]] : [],
|
|
36032
|
+
...p?.startISO ? [["Per\xEDodo", `${fmtD(p.startISO)} \u2014 ${fmtD(p.endISO)}`, ""]] : [],
|
|
36033
|
+
["Granularidade", this.granularity === "1h" ? "Hora" : "Dia", ""],
|
|
35871
36034
|
["DATA EMISS\xC3O", timestamp, ""],
|
|
35872
|
-
[
|
|
36035
|
+
[],
|
|
36036
|
+
...this.computeKpis().map((k) => [k.label, k.value, k.sub || ""]),
|
|
36037
|
+
[],
|
|
35873
36038
|
[this.granularity === "1h" ? "Data/Hora" : "Data", this.domainConfig.label, ""],
|
|
35874
36039
|
...this.data.map((row) => [this.formatDate(row.date), row.noData ? "Sem leitura" : this.domainConfig.formatter(row.consumption)])
|
|
35875
36040
|
];
|
|
@@ -35890,7 +36055,11 @@ var DeviceReportModal = class {
|
|
|
35890
36055
|
}
|
|
35891
36056
|
// Título dos exports — mesmo da modal (identificador + etiqueta do device).
|
|
35892
36057
|
resolveExportTitle() {
|
|
35893
|
-
|
|
36058
|
+
const base = `Relat\xF3rio - ${this.params.identifier || "SEM IDENTIFICADOR"} - ${this.params.label || "SEM ETIQUETA"}`;
|
|
36059
|
+
const dev = this.params.deviceName ? ` (${this.params.deviceName})` : "";
|
|
36060
|
+
const off = Number(this.params.temperatureOffset) || 0;
|
|
36061
|
+
const offTxt = this.domainConfig.summaryType === "average" && off !== 0 ? ` \xB7 offset ${off > 0 ? "+" : "\u2212"}${Math.abs(off).toLocaleString("pt-BR", { maximumFractionDigits: 2 })} \xB0C` : "";
|
|
36062
|
+
return `${base}${dev}${offTxt}`;
|
|
35894
36063
|
}
|
|
35895
36064
|
// Mapeia as linhas do relatório (dia/hora × consumo) para o shape TelemetryDevice
|
|
35896
36065
|
// dos exporters compartilhados do grid: labelOrName = data formatada, val = consumo,
|
|
@@ -35909,16 +36078,41 @@ var DeviceReportModal = class {
|
|
|
35909
36078
|
// Opções de coluna dos exporters: relatório single-device → Data | Consumo | %
|
|
35910
36079
|
// (Identificador redundante — o device já está no título/filename).
|
|
35911
36080
|
exportColumnOptions() {
|
|
36081
|
+
const isTemp = this.domainConfig.summaryType === "average";
|
|
35912
36082
|
return {
|
|
35913
36083
|
nameLabel: this.granularity === "1h" ? "Data/Hora" : "Data",
|
|
35914
|
-
hideIdentifier: true
|
|
36084
|
+
hideIdentifier: true,
|
|
36085
|
+
// Mesmo rótulo da coluna da tela (antes saía "Consumo (°C)" em temperatura)
|
|
36086
|
+
valueLabel: this.domainConfig.label,
|
|
36087
|
+
countLabel: this.granularity === "1h" ? "hora(s)" : "dia(s)",
|
|
36088
|
+
...isTemp ? { hidePerc: true, emptyValueText: "Sem leitura" } : {}
|
|
35915
36089
|
};
|
|
35916
36090
|
}
|
|
36091
|
+
// Gráfico da página final do PDF = painel da direita da tela
|
|
36092
|
+
async buildExportChart() {
|
|
36093
|
+
if (this.domainConfig.summaryType === "average") {
|
|
36094
|
+
const isHourly = this.granularity === "1h";
|
|
36095
|
+
const ranked = [...this.validRows].sort((a, b) => b.consumption - a.consumption);
|
|
36096
|
+
const shown = isHourly ? ranked.slice(0, 24) : ranked;
|
|
36097
|
+
const noData = isHourly ? [] : this.data.filter((r) => r.noData);
|
|
36098
|
+
const png = renderTemperatureBarsPng({
|
|
36099
|
+
items: [
|
|
36100
|
+
...shown.map((r) => ({ label: this.formatDate(r.date), value: r.consumption })),
|
|
36101
|
+
...noData.map((r) => ({ label: this.formatDate(r.date), value: null }))
|
|
36102
|
+
],
|
|
36103
|
+
ideal: this.params.temperatureIdealRange ?? null,
|
|
36104
|
+
accent: this.resolveAccentHex()
|
|
36105
|
+
});
|
|
36106
|
+
const title = isHourly ? `Horas mais quentes${ranked.length > 24 ? " (top 24)" : ""}` : "Dias mais quentes (m\xE9dia do dia)";
|
|
36107
|
+
return png ? { ...png, title } : null;
|
|
36108
|
+
}
|
|
36109
|
+
const chartPng = await this.participationChart?.toPngDataUrl?.().catch(() => null);
|
|
36110
|
+
return chartPng ? { ...chartPng, title: "Participa\xE7\xE3o por Dia" } : null;
|
|
36111
|
+
}
|
|
35917
36112
|
// PDF export — layout premium do grid + paleta do dashboard + faixa de KPIs +
|
|
35918
36113
|
// página dedicada com o gráfico "Participação por Dia" da modal.
|
|
35919
36114
|
async exportPDF() {
|
|
35920
36115
|
if (!this.data.length) return;
|
|
35921
|
-
const chartPng = await this.participationChart?.toPngDataUrl?.().catch(() => null);
|
|
35922
36116
|
exportGridPdf(
|
|
35923
36117
|
this.buildExportDevices(),
|
|
35924
36118
|
this.resolveExportTitle(),
|
|
@@ -35928,7 +36122,7 @@ var DeviceReportModal = class {
|
|
|
35928
36122
|
{
|
|
35929
36123
|
accentColor: this.resolveAccentHex(),
|
|
35930
36124
|
kpis: this.computeKpis(),
|
|
35931
|
-
chartImage:
|
|
36125
|
+
chartImage: await this.buildExportChart(),
|
|
35932
36126
|
columns: this.exportColumnOptions()
|
|
35933
36127
|
}
|
|
35934
36128
|
);
|
|
@@ -35944,7 +36138,8 @@ var DeviceReportModal = class {
|
|
|
35944
36138
|
this.resolveCustomerName() || null,
|
|
35945
36139
|
{
|
|
35946
36140
|
accentColor: this.resolveAccentHex(),
|
|
35947
|
-
columns: this.exportColumnOptions()
|
|
36141
|
+
columns: this.exportColumnOptions(),
|
|
36142
|
+
kpis: this.computeKpis()
|
|
35948
36143
|
}
|
|
35949
36144
|
);
|
|
35950
36145
|
}
|
|
@@ -38935,21 +39130,36 @@ var AllReportModal = class {
|
|
|
38935
39130
|
}
|
|
38936
39131
|
// Temperatura: valores já com offset e sem leituras inválidas (mesma base da tabela).
|
|
38937
39132
|
// 1d → uma linha por sensor por DIA; 1h → uma linha por sensor por HORA.
|
|
38938
|
-
exportTemperatureCSV(
|
|
39133
|
+
exportTemperatureCSV(_rows) {
|
|
39134
|
+
const rows = this.getFilteredData();
|
|
38939
39135
|
const showId = this.showIdentifierColumn(rows);
|
|
38940
39136
|
const idCol = (r) => showId ? [r.identifier] : [];
|
|
38941
39137
|
const idHead = showId ? ["Identificador"] : [];
|
|
38942
39138
|
const n2 = (v) => v === null || v === void 0 || !Number.isFinite(v) ? "" : v.toFixed(2);
|
|
38943
39139
|
const date = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
39140
|
+
const gran = this.granularity;
|
|
38944
39141
|
const fmtStamp = (ts) => {
|
|
38945
39142
|
const { date: d, time } = this.formatSpDateTime(ts);
|
|
38946
39143
|
return `${d} ${time}`;
|
|
38947
39144
|
};
|
|
39145
|
+
const p = this.exportPeriod;
|
|
39146
|
+
const fmtD = (iso) => iso ? new Date(iso).toLocaleDateString("pt-BR") : "";
|
|
39147
|
+
const meta = [
|
|
39148
|
+
["Relat\xF3rio", this.resolveTitle()],
|
|
39149
|
+
...this.params.customerName ? [["Cliente", this.params.customerName]] : [],
|
|
39150
|
+
...p?.startISO ? [["Per\xEDodo", `${fmtD(p.startISO)} \u2014 ${fmtD(p.endISO)}`]] : [],
|
|
39151
|
+
["Granularidade", gran === "1h" ? "Hora" : "Dia"],
|
|
39152
|
+
["Gerado em", (/* @__PURE__ */ new Date()).toLocaleString("pt-BR")],
|
|
39153
|
+
[],
|
|
39154
|
+
...this.computeKpis().map((k) => [k.label, k.value, k.sub || ""]),
|
|
39155
|
+
[]
|
|
39156
|
+
];
|
|
38948
39157
|
const summary = [
|
|
38949
|
-
[...idHead, "Sensor", "M\xE9dia (\xB0C)", "M\xEDn (\xB0C)", "Data/Hora M\xEDn", "M\xE1x (\xB0C)", "Data/Hora M\xE1x", "Leituras", "Leituras descartadas"],
|
|
39158
|
+
[...idHead, "Sensor", "Offset (\xB0C)", "M\xE9dia (\xB0C)", "M\xEDn (\xB0C)", "Data/Hora M\xEDn", "M\xE1x (\xB0C)", "Data/Hora M\xE1x", "Leituras", "Leituras descartadas"],
|
|
38950
39159
|
...rows.map((r) => [
|
|
38951
39160
|
...idCol(r),
|
|
38952
39161
|
r.name,
|
|
39162
|
+
r.id ? n2(this.temperatureOffsetFor(r.id)) : "",
|
|
38953
39163
|
r.noData ? "Sem leitura" : n2(r.consumption),
|
|
38954
39164
|
r.noData ? "" : n2(r.min),
|
|
38955
39165
|
r.noData || !r.minTs ? "" : fmtStamp(r.minTs),
|
|
@@ -38959,7 +39169,6 @@ var AllReportModal = class {
|
|
|
38959
39169
|
String(r.discarded ?? "")
|
|
38960
39170
|
])
|
|
38961
39171
|
];
|
|
38962
|
-
const gran = this.granularity;
|
|
38963
39172
|
const series = [[...idHead, "Sensor", gran === "1h" ? "Data/Hora" : "Dia", "Temperatura (\xB0C)"]];
|
|
38964
39173
|
const fmtTs = (ts) => gran === "1h" ? new Date(ts).toLocaleString("pt-BR", {
|
|
38965
39174
|
day: "2-digit",
|
|
@@ -38972,9 +39181,9 @@ var AllReportModal = class {
|
|
|
38972
39181
|
for (const r of rows) {
|
|
38973
39182
|
const raw = r.id && this.temperatureStats.get(r.id)?.series || [];
|
|
38974
39183
|
const pts = gran === "1h" ? this.aggregateHourly(raw, "avg") : this.aggregateDaily(raw, "avg");
|
|
38975
|
-
for (const
|
|
39184
|
+
for (const p2 of pts) series.push([...idCol(r), r.name, fmtTs(p2.timestamp), p2.value.toFixed(2)]);
|
|
38976
39185
|
}
|
|
38977
|
-
const csvContent = toCsv([...summary, [], ...series]);
|
|
39186
|
+
const csvContent = toCsv([...meta, ...summary, [], ...series]);
|
|
38978
39187
|
this.downloadCSV(csvContent, `relatorio-temperatura-${gran}-${date}.csv`);
|
|
38979
39188
|
}
|
|
38980
39189
|
// 1h CSV: one row per device × hour. The series comes from per-device requests
|
|
@@ -39063,28 +39272,73 @@ var AllReportModal = class {
|
|
|
39063
39272
|
}
|
|
39064
39273
|
// Maps the report rows to the TelemetryDevice shape consumed by the shared
|
|
39065
39274
|
// TELEMETRY grid exporters (only labelOrName/name/deviceIdentifier/val/perc are read).
|
|
39275
|
+
// Linhas dos exports = a TABELA DA TELA: mesma ordem/filtros (getFilteredData), cabeçalhos
|
|
39276
|
+
// de grupo com o mesmo resumo, e — em temperatura — Mín/Máx, offset e "Sem leitura".
|
|
39066
39277
|
buildExportDevices() {
|
|
39067
|
-
const
|
|
39068
|
-
|
|
39069
|
-
)
|
|
39070
|
-
|
|
39071
|
-
|
|
39072
|
-
|
|
39073
|
-
|
|
39074
|
-
|
|
39075
|
-
|
|
39076
|
-
|
|
39077
|
-
|
|
39078
|
-
|
|
39278
|
+
const rows = this.getFilteredData();
|
|
39279
|
+
const grandTotal = this.calculateTotalConsumption();
|
|
39280
|
+
const toDevice = (r) => {
|
|
39281
|
+
const base = {
|
|
39282
|
+
labelOrName: r.name,
|
|
39283
|
+
name: r.name,
|
|
39284
|
+
deviceIdentifier: r.identifier,
|
|
39285
|
+
val: this.isTemperature && r.noData ? null : r.consumption,
|
|
39286
|
+
perc: this.isTemperature ? void 0 : grandTotal > 0 ? r.consumption / grandTotal * 100 : 0
|
|
39287
|
+
};
|
|
39288
|
+
if (!this.isTemperature) return base;
|
|
39289
|
+
const off = r.id && !r.noData ? this.temperatureOffsetFor(r.id) : 0;
|
|
39290
|
+
return {
|
|
39291
|
+
...base,
|
|
39292
|
+
extraCells: [this.fmtTemp(r.noData ? null : r.min), this.fmtTemp(r.noData ? null : r.max)],
|
|
39293
|
+
...off ? { nameNote: `offset ${off > 0 ? "+" : "\u2212"}${fmtPt(Math.abs(off))} \xB0C` } : {}
|
|
39294
|
+
};
|
|
39295
|
+
};
|
|
39296
|
+
const out = [];
|
|
39297
|
+
if (rows.some((r) => r.groupLabel)) {
|
|
39298
|
+
const order = [];
|
|
39299
|
+
const byGroup = /* @__PURE__ */ new Map();
|
|
39300
|
+
for (const r of rows) {
|
|
39301
|
+
const g = r.groupLabel || "\u2014";
|
|
39302
|
+
if (!byGroup.has(g)) {
|
|
39303
|
+
byGroup.set(g, []);
|
|
39304
|
+
order.push(g);
|
|
39305
|
+
}
|
|
39306
|
+
byGroup.get(g).push(r);
|
|
39307
|
+
}
|
|
39308
|
+
for (const g of order) {
|
|
39309
|
+
const items = byGroup.get(g);
|
|
39310
|
+
out.push({ groupHeader: `${g.toUpperCase()} \xB7 ${this.groupSummaryText(items)}` });
|
|
39311
|
+
items.forEach((r) => out.push(toDevice(r)));
|
|
39312
|
+
}
|
|
39313
|
+
} else {
|
|
39314
|
+
rows.forEach((r) => out.push(toDevice(r)));
|
|
39315
|
+
}
|
|
39316
|
+
return out;
|
|
39079
39317
|
}
|
|
39080
|
-
//
|
|
39318
|
+
// Mesmo texto do cabeçalho de grupo da tabela
|
|
39319
|
+
groupSummaryText(items) {
|
|
39320
|
+
if (this.isTemperature) {
|
|
39321
|
+
const withData = items.filter((r) => !r.noData);
|
|
39322
|
+
const avg = withData.length ? withData.reduce((s, r) => s + r.consumption, 0) / withData.length : null;
|
|
39323
|
+
return `${items.length} sensores \xB7 m\xE9dia ${this.fmtTemp(avg)} \xB0C`;
|
|
39324
|
+
}
|
|
39325
|
+
const total = items.reduce((s, r) => s + r.consumption, 0);
|
|
39326
|
+
return `${items.length} dispositivos \xB7 ${fmtPt(total)} ${this.domainConfig.unit}`;
|
|
39327
|
+
}
|
|
39328
|
+
// Colunas do PDF/XLS = colunas da tela. Temperatura: Sensor | Média | Mín | Máx (sem %).
|
|
39081
39329
|
exportColumns() {
|
|
39082
39330
|
if (!this.isTemperature) return null;
|
|
39083
39331
|
return {
|
|
39084
39332
|
nameLabel: "Sensor",
|
|
39085
|
-
valueLabel: "
|
|
39333
|
+
valueLabel: "M\xE9dia (\xB0C)",
|
|
39086
39334
|
hidePerc: true,
|
|
39087
|
-
hideIdentifier: !this.showIdentifierColumn()
|
|
39335
|
+
hideIdentifier: !this.showIdentifierColumn(),
|
|
39336
|
+
extraColumns: [
|
|
39337
|
+
{ label: "M\xEDn (\xB0C)", pdfW: 35 },
|
|
39338
|
+
{ label: "M\xE1x (\xB0C)", pdfW: 35 }
|
|
39339
|
+
],
|
|
39340
|
+
emptyValueText: "Sem leitura",
|
|
39341
|
+
countLabel: "sensor(es)"
|
|
39088
39342
|
};
|
|
39089
39343
|
}
|
|
39090
39344
|
// Accent hex da paleta do dashboard (tema efetivo) para o PDF/XLS — cai no
|
|
@@ -39098,26 +39352,38 @@ var AllReportModal = class {
|
|
|
39098
39352
|
const vars = typeof theme.cssVars === "function" ? theme.cssVars() : theme;
|
|
39099
39353
|
return vars?.["--myio-brand-700"];
|
|
39100
39354
|
}
|
|
39355
|
+
// Gráfico da página final do PDF = o painel da direita da tela
|
|
39356
|
+
async buildExportChart() {
|
|
39357
|
+
if (this.isTemperature) {
|
|
39358
|
+
const png = renderTemperatureBarsPng({
|
|
39359
|
+
items: this.getFilteredData().map((r) => ({ label: r.name, value: r.noData ? null : r.consumption })),
|
|
39360
|
+
ideal: this.temperatureIdealRange,
|
|
39361
|
+
accent: this.resolveAccentHex()
|
|
39362
|
+
});
|
|
39363
|
+
return png ? { ...png, title: "Temperatura m\xE9dia por sensor" } : null;
|
|
39364
|
+
}
|
|
39365
|
+
const chartPng = await this.participationChart?.toPngDataUrl?.().catch(() => null);
|
|
39366
|
+
return chartPng ? { ...chartPng, title: "Participa\xE7\xE3o por Dispositivo" } : null;
|
|
39367
|
+
}
|
|
39101
39368
|
// PDF export — layout premium do grid + paleta do dashboard + faixa de KPIs +
|
|
39102
|
-
// página dedicada com o gráfico
|
|
39369
|
+
// página dedicada com o mesmo gráfico do painel da modal.
|
|
39103
39370
|
async exportPDF() {
|
|
39104
39371
|
if (!this.data.length) return;
|
|
39105
|
-
const chartPng = await this.participationChart?.toPngDataUrl?.().catch(() => null);
|
|
39106
39372
|
exportGridPdf(
|
|
39107
39373
|
this.buildExportDevices(),
|
|
39108
39374
|
this.resolveTitle(),
|
|
39109
39375
|
this.domainConfig.unit,
|
|
39110
39376
|
this.exportPeriod,
|
|
39111
|
-
null,
|
|
39377
|
+
this.params.customerName || null,
|
|
39112
39378
|
{
|
|
39113
39379
|
accentColor: this.resolveAccentHex(),
|
|
39114
39380
|
kpis: this.computeKpis(),
|
|
39115
39381
|
columns: this.exportColumns(),
|
|
39116
|
-
chartImage:
|
|
39382
|
+
chartImage: await this.buildExportChart()
|
|
39117
39383
|
}
|
|
39118
39384
|
);
|
|
39119
39385
|
}
|
|
39120
|
-
// XLS export (XML Spreadsheet) —
|
|
39386
|
+
// XLS export (XML Spreadsheet) — mesma tabela + KPIs da tela.
|
|
39121
39387
|
exportXLS() {
|
|
39122
39388
|
if (!this.data.length) return;
|
|
39123
39389
|
exportGridXls(
|
|
@@ -39125,8 +39391,8 @@ var AllReportModal = class {
|
|
|
39125
39391
|
this.resolveTitle(),
|
|
39126
39392
|
this.domainConfig.unit,
|
|
39127
39393
|
this.exportPeriod,
|
|
39128
|
-
null,
|
|
39129
|
-
{ accentColor: this.resolveAccentHex(), columns: this.exportColumns() }
|
|
39394
|
+
this.params.customerName || null,
|
|
39395
|
+
{ accentColor: this.resolveAccentHex(), columns: this.exportColumns(), kpis: this.computeKpis() }
|
|
39130
39396
|
);
|
|
39131
39397
|
}
|
|
39132
39398
|
async fetchCustomerTotals(startISO, endISO) {
|
|
@@ -79599,7 +79865,10 @@ async function openTemperatureModal(params) {
|
|
|
79599
79865
|
document.body.appendChild(modalContainer);
|
|
79600
79866
|
renderModal3(modalContainer, state6, modalId);
|
|
79601
79867
|
try {
|
|
79602
|
-
state6.data =
|
|
79868
|
+
state6.data = discardInvalid(
|
|
79869
|
+
await (state6.dataFetcher ? state6.dataFetcher(state6.startTs, state6.endTs) : fetchTemperatureData(state6.token, state6.deviceId, state6.startTs, state6.endTs)),
|
|
79870
|
+
state6
|
|
79871
|
+
);
|
|
79603
79872
|
state6.stats = calculateStats(state6.data, state6.clampRange, state6.temperatureOffset);
|
|
79604
79873
|
state6.isLoading = false;
|
|
79605
79874
|
renderModal3(modalContainer, state6, modalId);
|
|
@@ -79624,7 +79893,10 @@ async function openTemperatureModal(params) {
|
|
|
79624
79893
|
state6.isLoading = true;
|
|
79625
79894
|
renderModal3(modalContainer, state6, modalId);
|
|
79626
79895
|
try {
|
|
79627
|
-
state6.data =
|
|
79896
|
+
state6.data = discardInvalid(
|
|
79897
|
+
await (state6.dataFetcher ? state6.dataFetcher(state6.startTs, state6.endTs) : fetchTemperatureData(state6.token, state6.deviceId, state6.startTs, state6.endTs)),
|
|
79898
|
+
state6
|
|
79899
|
+
);
|
|
79628
79900
|
state6.stats = calculateStats(state6.data, state6.clampRange, state6.temperatureOffset);
|
|
79629
79901
|
state6.isLoading = false;
|
|
79630
79902
|
renderModal3(modalContainer, state6, modalId);
|
|
@@ -79676,6 +79948,8 @@ function renderModal3(container, state6, modalId, error) {
|
|
|
79676
79948
|
showMaximize: true,
|
|
79677
79949
|
showClose: true,
|
|
79678
79950
|
primaryColor: state6.accent,
|
|
79951
|
+
solid: true,
|
|
79952
|
+
// padrão dos relatórios: cor do dashboard também no tema light
|
|
79679
79953
|
borderRadius: "10px 10px 0 0",
|
|
79680
79954
|
draggable: false
|
|
79681
79955
|
})}
|
|
@@ -80014,12 +80288,19 @@ function drawChart2(modalId, state6) {
|
|
|
80014
80288
|
ctx.textAlign = "center";
|
|
80015
80289
|
const numLabels = Math.min(8, chartData.length);
|
|
80016
80290
|
const labelInterval = Math.max(1, Math.floor(chartData.length / numLabels));
|
|
80291
|
+
const xSpan = chartData.length > 1 ? chartData[chartData.length - 1].x - chartData[0].x : 0;
|
|
80292
|
+
const multiDay = state6.granularity === "hour" && xSpan > 24 * 60 * 60 * 1e3;
|
|
80017
80293
|
for (let i = 0; i < chartData.length; i += labelInterval) {
|
|
80018
80294
|
const point = chartData[i];
|
|
80019
80295
|
const date = new Date(point.x);
|
|
80020
80296
|
let label;
|
|
80297
|
+
let subLabel = "";
|
|
80021
80298
|
if (state6.granularity === "hour") {
|
|
80022
80299
|
label = date.toLocaleTimeString(state6.locale, { hour: "2-digit", minute: "2-digit" });
|
|
80300
|
+
if (multiDay) {
|
|
80301
|
+
subLabel = label;
|
|
80302
|
+
label = date.toLocaleDateString(state6.locale, { day: "2-digit", month: "2-digit" });
|
|
80303
|
+
}
|
|
80023
80304
|
} else {
|
|
80024
80305
|
label = date.toLocaleDateString(state6.locale, { day: "2-digit", month: "2-digit" });
|
|
80025
80306
|
}
|
|
@@ -80031,6 +80312,7 @@ function drawChart2(modalId, state6) {
|
|
|
80031
80312
|
ctx.stroke();
|
|
80032
80313
|
ctx.fillStyle = colors2.textMuted;
|
|
80033
80314
|
ctx.fillText(label, point.screenX, height - paddingBottom + 18);
|
|
80315
|
+
if (subLabel) ctx.fillText(subLabel, point.screenX, height - paddingBottom + 31);
|
|
80034
80316
|
}
|
|
80035
80317
|
ctx.strokeStyle = colors2.border;
|
|
80036
80318
|
ctx.lineWidth = 1;
|
|
@@ -80242,7 +80524,10 @@ async function setupEventListeners3(container, state6, modalId, onClose) {
|
|
|
80242
80524
|
state6.dateRangePicker = null;
|
|
80243
80525
|
renderModal3(container, state6, modalId);
|
|
80244
80526
|
try {
|
|
80245
|
-
state6.data =
|
|
80527
|
+
state6.data = discardInvalid(
|
|
80528
|
+
await (state6.dataFetcher ? state6.dataFetcher(state6.startTs, state6.endTs) : fetchTemperatureData(state6.token, state6.deviceId, state6.startTs, state6.endTs)),
|
|
80529
|
+
state6
|
|
80530
|
+
);
|
|
80246
80531
|
state6.stats = calculateStats(state6.data, state6.clampRange, state6.temperatureOffset);
|
|
80247
80532
|
state6.isLoading = false;
|
|
80248
80533
|
renderModal3(container, state6, modalId);
|
|
@@ -80256,19 +80541,64 @@ async function setupEventListeners3(container, state6, modalId, onClose) {
|
|
|
80256
80541
|
}
|
|
80257
80542
|
});
|
|
80258
80543
|
}
|
|
80544
|
+
function discardInvalid(data, state6) {
|
|
80545
|
+
const off = Number(state6.temperatureOffset) || 0;
|
|
80546
|
+
return data.filter((p) => {
|
|
80547
|
+
const v = Number(p.value) + off;
|
|
80548
|
+
return Number.isFinite(v) && v >= state6.clampRange.min && v <= state6.clampRange.max;
|
|
80549
|
+
});
|
|
80550
|
+
}
|
|
80259
80551
|
function exportCsv(state6) {
|
|
80260
80552
|
if (state6.data.length === 0) return;
|
|
80261
|
-
const
|
|
80262
|
-
const
|
|
80263
|
-
|
|
80264
|
-
|
|
80265
|
-
|
|
80266
|
-
|
|
80267
|
-
|
|
80268
|
-
|
|
80269
|
-
|
|
80270
|
-
state6.
|
|
80271
|
-
);
|
|
80553
|
+
const off = Number(state6.temperatureOffset) || 0;
|
|
80554
|
+
const n2 = (v) => v.toFixed(2).replace(".", ",");
|
|
80555
|
+
const q = (v) => `"${String(v).replace(/"/g, '""')}"`;
|
|
80556
|
+
const dt = (ts) => new Date(ts).toLocaleString("pt-BR", {
|
|
80557
|
+
day: "2-digit",
|
|
80558
|
+
month: "2-digit",
|
|
80559
|
+
year: "numeric",
|
|
80560
|
+
hour: "2-digit",
|
|
80561
|
+
minute: "2-digit",
|
|
80562
|
+
timeZone: state6.timezone || "America/Sao_Paulo"
|
|
80563
|
+
});
|
|
80564
|
+
const fmtD = (ts) => new Date(ts).toLocaleDateString("pt-BR", { timeZone: state6.timezone || "America/Sao_Paulo" });
|
|
80565
|
+
const filtered = filterByDayPeriods(state6.data, state6.selectedPeriods);
|
|
80566
|
+
const lines = [
|
|
80567
|
+
["Relat\xF3rio", `${state6.label} - Hist\xF3rico de Temperatura`],
|
|
80568
|
+
...state6.deviceName ? [["Dispositivo (TB)", state6.deviceName]] : [],
|
|
80569
|
+
...state6.customerName ? [["Cliente", state6.customerName]] : [],
|
|
80570
|
+
["Per\xEDodo", `${fmtD(state6.startTs)} \u2014 ${fmtD(state6.endTs)}`],
|
|
80571
|
+
["Granularidade", state6.granularity === "hour" ? "Hora (m\xE9dia da hora fechada)" : "Dia (m\xE9dia do dia)"],
|
|
80572
|
+
["Per\xEDodos do dia", getSelectedPeriodsLabel(state6.selectedPeriods)],
|
|
80573
|
+
...off !== 0 ? [["Offset aplicado (\xB0C)", n2(off)]] : [],
|
|
80574
|
+
["Gerado em", (/* @__PURE__ */ new Date()).toLocaleString("pt-BR")],
|
|
80575
|
+
[],
|
|
80576
|
+
["Temperatura atual (\xB0C)", state6.currentTemperature !== null ? n2(state6.currentTemperature) : "N/A"],
|
|
80577
|
+
["M\xE9dia do per\xEDodo (\xB0C)", state6.stats.count > 0 ? n2(state6.stats.avg) : "N/A"],
|
|
80578
|
+
["M\xEDnima (\xB0C)", state6.stats.count > 0 ? n2(state6.stats.min) : "N/A"],
|
|
80579
|
+
["M\xE1xima (\xB0C)", state6.stats.count > 0 ? n2(state6.stats.max) : "N/A"],
|
|
80580
|
+
["Leituras", String(state6.stats.count)],
|
|
80581
|
+
[]
|
|
80582
|
+
];
|
|
80583
|
+
if (state6.granularity === "hour") {
|
|
80584
|
+
lines.push(["Data/Hora", "Temperatura (\xB0C)"]);
|
|
80585
|
+
aggregateByHour(filtered, state6.clampRange, off).forEach((p) => lines.push([dt(p.ts), n2(Number(p.value))]));
|
|
80586
|
+
} else {
|
|
80587
|
+
lines.push(["Dia", "M\xE9dia (\xB0C)", "M\xEDn (\xB0C)", "M\xE1x (\xB0C)", "Leituras"]);
|
|
80588
|
+
aggregateByDay(filtered, state6.clampRange, off).forEach(
|
|
80589
|
+
(d) => lines.push([fmtD(d.dateTs), n2(d.avg), n2(d.min), n2(d.max), String(d.count)])
|
|
80590
|
+
);
|
|
80591
|
+
}
|
|
80592
|
+
const csv = "\uFEFF" + lines.map((r) => r.map(q).join(";")).join("\r\n");
|
|
80593
|
+
const blob = new Blob([csv], { type: "text/csv;charset=utf-8;" });
|
|
80594
|
+
const url = URL.createObjectURL(blob);
|
|
80595
|
+
const a = document.createElement("a");
|
|
80596
|
+
a.href = url;
|
|
80597
|
+
a.download = `temperatura_${state6.label.replace(/\s+/g, "_")}_${state6.granularity === "hour" ? "1h" : "1d"}_${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}.csv`;
|
|
80598
|
+
document.body.appendChild(a);
|
|
80599
|
+
a.click();
|
|
80600
|
+
document.body.removeChild(a);
|
|
80601
|
+
setTimeout(() => URL.revokeObjectURL(url), 1e3);
|
|
80272
80602
|
}
|
|
80273
80603
|
function buildHeaderTitle(state6) {
|
|
80274
80604
|
const base = `${escHtml3(state6.label)} - Hist\xF3rico de Temperatura`;
|
|
@@ -80321,6 +80651,21 @@ function mountChrome(container, state6, modalId) {
|
|
|
80321
80651
|
}
|
|
80322
80652
|
|
|
80323
80653
|
// src/components/temperature/TemperatureComparisonModal.ts
|
|
80654
|
+
var _cmpFooters = /* @__PURE__ */ new Map();
|
|
80655
|
+
function resolveAccent2(palette) {
|
|
80656
|
+
const fallback = "#3e1a7d";
|
|
80657
|
+
const src = palette ?? (typeof window !== "undefined" ? window.MyIOUtils?.theme : void 0);
|
|
80658
|
+
if (!src) return fallback;
|
|
80659
|
+
const vars = typeof src.cssVars === "function" ? src.cssVars() : src;
|
|
80660
|
+
const accent = src.accent || vars?.["--myio-brand-700"];
|
|
80661
|
+
return typeof accent === "string" && accent ? accent : fallback;
|
|
80662
|
+
}
|
|
80663
|
+
function resolveCustomerName2(explicit) {
|
|
80664
|
+
if (explicit) return explicit;
|
|
80665
|
+
if (typeof window === "undefined") return "";
|
|
80666
|
+
const w = window;
|
|
80667
|
+
return w.MyIOOrchestrator?.customerName || w.MyIOUtils?.customerName || "";
|
|
80668
|
+
}
|
|
80324
80669
|
async function openTemperatureComparisonModal(params) {
|
|
80325
80670
|
const modalId = `myio-temp-comparison-modal-${Date.now()}`;
|
|
80326
80671
|
const defaultDateRange = getTodaySoFar();
|
|
@@ -80342,7 +80687,9 @@ async function openTemperatureComparisonModal(params) {
|
|
|
80342
80687
|
// All periods selected by default
|
|
80343
80688
|
temperatureMin: params.temperatureMin ?? null,
|
|
80344
80689
|
temperatureMax: params.temperatureMax ?? null,
|
|
80345
|
-
dataFetcher: params.dataFetcher ?? null
|
|
80690
|
+
dataFetcher: params.dataFetcher ?? null,
|
|
80691
|
+
customerName: resolveCustomerName2(params.customerName),
|
|
80692
|
+
accent: resolveAccent2(params.palette)
|
|
80346
80693
|
};
|
|
80347
80694
|
const savedGranularity = localStorage.getItem("myio-temp-comparison-granularity");
|
|
80348
80695
|
const savedTheme = localStorage.getItem("myio-temp-comparison-theme");
|
|
@@ -80358,6 +80705,8 @@ async function openTemperatureComparisonModal(params) {
|
|
|
80358
80705
|
await setupEventListeners4(modalContainer, state6, modalId, params.onClose);
|
|
80359
80706
|
return {
|
|
80360
80707
|
destroy: () => {
|
|
80708
|
+
_cmpFooters.get(modalId)?.destroy();
|
|
80709
|
+
_cmpFooters.delete(modalId);
|
|
80361
80710
|
modalContainer.remove();
|
|
80362
80711
|
params.onClose?.();
|
|
80363
80712
|
},
|
|
@@ -80384,7 +80733,9 @@ async function fetchAllDevicesData(state6) {
|
|
|
80384
80733
|
try {
|
|
80385
80734
|
const raw = state6.dataFetcher ? await state6.dataFetcher(device, state6.startTs, state6.endTs) : await fetchTemperatureData(state6.token, deviceId, state6.startTs, state6.endTs);
|
|
80386
80735
|
const offset = Number(device.temperatureOffset) || 0;
|
|
80387
|
-
const data =
|
|
80736
|
+
const data = raw.map((p) => ({ ...p, value: Number(p.value) + offset })).filter(
|
|
80737
|
+
(p) => Number.isFinite(p.value) && p.value >= state6.clampRange.min && p.value <= state6.clampRange.max
|
|
80738
|
+
);
|
|
80388
80739
|
const stats = calculateStats(data, state6.clampRange);
|
|
80389
80740
|
return {
|
|
80390
80741
|
device,
|
|
@@ -80481,7 +80832,7 @@ function renderModal4(container, state6, modalId) {
|
|
|
80481
80832
|
<!-- Header - MyIO Premium Style -->
|
|
80482
80833
|
<div style="
|
|
80483
80834
|
padding: 4px 8px; display: flex; align-items: center; justify-content: space-between;
|
|
80484
|
-
background:
|
|
80835
|
+
background: ${state6.accent}; color: white; border-radius: ${isMaximized ? "0" : "10px 10px 0 0"};
|
|
80485
80836
|
min-height: 20px;
|
|
80486
80837
|
">
|
|
80487
80838
|
<h2 style="margin: 6px; font-size: 18px; font-weight: 600; color: white; line-height: 2;">
|
|
@@ -80563,7 +80914,7 @@ function renderModal4(container, state6, modalId) {
|
|
|
80563
80914
|
name="${modalId}-period"
|
|
80564
80915
|
value="${period.id}"
|
|
80565
80916
|
${state6.selectedPeriods.includes(period.id) ? "checked" : ""}
|
|
80566
|
-
style="width: 16px; height: 16px; cursor: pointer; accent-color:
|
|
80917
|
+
style="width: 16px; height: 16px; cursor: pointer; accent-color: ${state6.accent};">
|
|
80567
80918
|
${period.label}
|
|
80568
80919
|
</label>
|
|
80569
80920
|
`).join("")}
|
|
@@ -80596,7 +80947,7 @@ function renderModal4(container, state6, modalId) {
|
|
|
80596
80947
|
</div>
|
|
80597
80948
|
<!-- Query Button -->
|
|
80598
80949
|
<button id="${modalId}-query" style="
|
|
80599
|
-
background:
|
|
80950
|
+
background: ${state6.accent}; color: white; border: none;
|
|
80600
80951
|
padding: 8px 16px; border-radius: 6px; cursor: pointer;
|
|
80601
80952
|
font-size: 14px; font-weight: 500; height: 38px;
|
|
80602
80953
|
display: flex; align-items: center; gap: 8px;
|
|
@@ -80640,33 +80991,15 @@ function renderModal4(container, state6, modalId) {
|
|
|
80640
80991
|
${statsHTML}
|
|
80641
80992
|
</div>
|
|
80642
80993
|
|
|
80643
|
-
<!-- Actions -->
|
|
80644
|
-
<div style="display: flex; justify-content: flex-end; gap: 12px;">
|
|
80645
|
-
<button id="${modalId}-export" style="
|
|
80646
|
-
background: ${state6.theme === "dark" ? "rgba(255,255,255,0.1)" : "#f7f7f7"};
|
|
80647
|
-
color: ${colors2.text}; border: 1px solid ${colors2.border};
|
|
80648
|
-
padding: 8px 16px; border-radius: 6px; cursor: pointer;
|
|
80649
|
-
font-size: 14px; display: flex; align-items: center; gap: 8px;
|
|
80650
|
-
font-family: 'Nunito', system-ui, sans-serif;
|
|
80651
|
-
" ${state6.deviceData.every((dd) => dd.data.length === 0) ? "disabled" : ""}>
|
|
80652
|
-
\u{1F4E5} Exportar CSV
|
|
80653
|
-
</button>
|
|
80654
|
-
<button id="${modalId}-close-btn" style="
|
|
80655
|
-
background: #3e1a7d; color: white; border: none;
|
|
80656
|
-
padding: 8px 16px; border-radius: 6px; cursor: pointer;
|
|
80657
|
-
font-size: 14px; font-weight: 500;
|
|
80658
|
-
font-family: 'Nunito', system-ui, sans-serif;
|
|
80659
|
-
">
|
|
80660
|
-
Fechar
|
|
80661
|
-
</button>
|
|
80662
|
-
</div>
|
|
80663
80994
|
</div><!-- End Body -->
|
|
80995
|
+
<!-- Footer premium (customer \xB7 rel\xF3gio \xB7 vers\xE3o | Powered by MYIO | CSV) \u2014 padr\xE3o dos relat\xF3rios -->
|
|
80996
|
+
<div id="${modalId}-footer-slot"></div>
|
|
80664
80997
|
</div>
|
|
80665
80998
|
</div>
|
|
80666
80999
|
<style>
|
|
80667
81000
|
@keyframes spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
|
|
80668
81001
|
#${modalId} select:focus, #${modalId} input:focus {
|
|
80669
|
-
outline: 2px solid
|
|
81002
|
+
outline: 2px solid ${state6.accent};
|
|
80670
81003
|
outline-offset: 2px;
|
|
80671
81004
|
}
|
|
80672
81005
|
#${modalId} button:hover:not(:disabled) {
|
|
@@ -80682,6 +81015,7 @@ function renderModal4(container, state6, modalId) {
|
|
|
80682
81015
|
}
|
|
80683
81016
|
</style>
|
|
80684
81017
|
`;
|
|
81018
|
+
mountCmpFooter(container, state6, modalId);
|
|
80685
81019
|
}
|
|
80686
81020
|
function drawComparisonChart2(modalId, state6) {
|
|
80687
81021
|
const chartContainer = document.getElementById(`${modalId}-chart`);
|
|
@@ -80888,12 +81222,19 @@ function drawComparisonChart2(modalId, state6) {
|
|
|
80888
81222
|
const xAxisPoints = processedData[0]?.points || [];
|
|
80889
81223
|
const numLabels = Math.min(8, xAxisPoints.length);
|
|
80890
81224
|
const labelInterval = Math.max(1, Math.floor(xAxisPoints.length / numLabels));
|
|
81225
|
+
const xSpan = xAxisPoints.length > 1 ? xAxisPoints[xAxisPoints.length - 1].x - xAxisPoints[0].x : 0;
|
|
81226
|
+
const multiDay = state6.granularity === "hour" && xSpan > 24 * 60 * 60 * 1e3;
|
|
80891
81227
|
for (let i = 0; i < xAxisPoints.length; i += labelInterval) {
|
|
80892
81228
|
const point = xAxisPoints[i];
|
|
80893
81229
|
const date = new Date(point.x);
|
|
80894
81230
|
let label;
|
|
81231
|
+
let subLabel = "";
|
|
80895
81232
|
if (state6.granularity === "hour") {
|
|
80896
81233
|
label = date.toLocaleTimeString(state6.locale, { hour: "2-digit", minute: "2-digit" });
|
|
81234
|
+
if (multiDay) {
|
|
81235
|
+
subLabel = label;
|
|
81236
|
+
label = date.toLocaleDateString(state6.locale, { day: "2-digit", month: "2-digit" });
|
|
81237
|
+
}
|
|
80897
81238
|
} else {
|
|
80898
81239
|
label = date.toLocaleDateString(state6.locale, { day: "2-digit", month: "2-digit" });
|
|
80899
81240
|
}
|
|
@@ -80905,6 +81246,7 @@ function drawComparisonChart2(modalId, state6) {
|
|
|
80905
81246
|
ctx.stroke();
|
|
80906
81247
|
ctx.fillStyle = colors2.textMuted;
|
|
80907
81248
|
ctx.fillText(label, point.screenX, height - paddingBottom + 18);
|
|
81249
|
+
if (subLabel) ctx.fillText(subLabel, point.screenX, height - paddingBottom + 31);
|
|
80908
81250
|
}
|
|
80909
81251
|
ctx.strokeStyle = colors2.border;
|
|
80910
81252
|
ctx.lineWidth = 1;
|
|
@@ -81014,6 +81356,8 @@ function setupComparisonChartTooltip2(canvas, container, chartData, state6, colo
|
|
|
81014
81356
|
}
|
|
81015
81357
|
async function setupEventListeners4(container, state6, modalId, onClose) {
|
|
81016
81358
|
const closeModal2 = () => {
|
|
81359
|
+
_cmpFooters.get(modalId)?.destroy();
|
|
81360
|
+
_cmpFooters.delete(modalId);
|
|
81017
81361
|
container.remove();
|
|
81018
81362
|
onClose?.();
|
|
81019
81363
|
};
|
|
@@ -81135,49 +81479,89 @@ async function setupEventListeners4(container, state6, modalId, onClose) {
|
|
|
81135
81479
|
drawComparisonChart2(modalId, state6);
|
|
81136
81480
|
await setupEventListeners4(container, state6, modalId, onClose);
|
|
81137
81481
|
});
|
|
81138
|
-
|
|
81139
|
-
|
|
81140
|
-
|
|
81482
|
+
}
|
|
81483
|
+
function mountCmpFooter(container, state6, modalId) {
|
|
81484
|
+
_cmpFooters.get(modalId)?.destroy();
|
|
81485
|
+
_cmpFooters.delete(modalId);
|
|
81486
|
+
const slot = container.querySelector(`#${modalId}-footer-slot`);
|
|
81487
|
+
if (!slot) return;
|
|
81488
|
+
const lib = typeof window !== "undefined" ? window.MyIOLibrary : void 0;
|
|
81489
|
+
const footer = createModalFooter({
|
|
81490
|
+
customerName: state6.customerName,
|
|
81491
|
+
libVersion: lib?.version ? { current: lib.version } : false,
|
|
81492
|
+
themeMode: state6.theme === "dark" ? "dark" : "light",
|
|
81493
|
+
exports: {
|
|
81494
|
+
csv: {
|
|
81495
|
+
onClick: () => {
|
|
81496
|
+
if (state6.deviceData.every((dd) => dd.data.length === 0)) return;
|
|
81497
|
+
exportComparisonCSV2(state6);
|
|
81498
|
+
},
|
|
81499
|
+
disabled: state6.deviceData.every((dd) => dd.data.length === 0),
|
|
81500
|
+
tooltipText: "Exporta em CSV as leituras de cada sensor (offset aplicado)"
|
|
81501
|
+
}
|
|
81502
|
+
}
|
|
81141
81503
|
});
|
|
81504
|
+
slot.appendChild(footer.element);
|
|
81505
|
+
_cmpFooters.set(modalId, footer);
|
|
81142
81506
|
}
|
|
81143
81507
|
function exportComparisonCSV2(state6) {
|
|
81144
|
-
const
|
|
81145
|
-
const
|
|
81146
|
-
const
|
|
81147
|
-
|
|
81148
|
-
|
|
81149
|
-
|
|
81150
|
-
|
|
81151
|
-
|
|
81152
|
-
|
|
81153
|
-
|
|
81154
|
-
csvContent += "\n";
|
|
81155
|
-
csvContent += "Estat\xEDsticas por Sensor:\n";
|
|
81156
|
-
csvContent += "Sensor,M\xE9dia (\xB0C),Min (\xB0C),Max (\xB0C),Leituras\n";
|
|
81157
|
-
state6.deviceData.forEach((dd) => {
|
|
81158
|
-
csvContent += `"${dd.device.label}",${dd.stats.avg.toFixed(2)},${dd.stats.min.toFixed(2)},${dd.stats.max.toFixed(2)},${dd.stats.count}
|
|
81159
|
-
`;
|
|
81508
|
+
const n2 = (v) => v.toFixed(2).replace(".", ",");
|
|
81509
|
+
const q = (v) => `"${String(v).replace(/"/g, '""')}"`;
|
|
81510
|
+
const fmtD = (ts) => new Date(ts).toLocaleDateString("pt-BR", { timeZone: "America/Sao_Paulo" });
|
|
81511
|
+
const dt = (ts) => new Date(ts).toLocaleString("pt-BR", {
|
|
81512
|
+
day: "2-digit",
|
|
81513
|
+
month: "2-digit",
|
|
81514
|
+
year: "numeric",
|
|
81515
|
+
hour: "2-digit",
|
|
81516
|
+
minute: "2-digit",
|
|
81517
|
+
timeZone: "America/Sao_Paulo"
|
|
81160
81518
|
});
|
|
81161
|
-
|
|
81162
|
-
|
|
81163
|
-
|
|
81164
|
-
|
|
81165
|
-
|
|
81166
|
-
|
|
81167
|
-
|
|
81168
|
-
|
|
81169
|
-
|
|
81170
|
-
|
|
81519
|
+
const offTxt = (d) => {
|
|
81520
|
+
const o = Number(d.temperatureOffset) || 0;
|
|
81521
|
+
return o !== 0 ? n2(o) : "";
|
|
81522
|
+
};
|
|
81523
|
+
const lines = [
|
|
81524
|
+
["Relat\xF3rio", `Compara\xE7\xE3o de Temperatura - ${state6.devices.length} sensores`],
|
|
81525
|
+
...state6.customerName ? [["Cliente", state6.customerName]] : [],
|
|
81526
|
+
["Per\xEDodo", `${fmtD(state6.startTs)} \u2014 ${fmtD(state6.endTs)}`],
|
|
81527
|
+
["Granularidade", state6.granularity === "hour" ? "Hora (m\xE9dia da hora fechada)" : "Dia (m\xE9dia do dia)"],
|
|
81528
|
+
["Per\xEDodos do dia", getSelectedPeriodsLabel(state6.selectedPeriods)],
|
|
81529
|
+
["Gerado em", (/* @__PURE__ */ new Date()).toLocaleString("pt-BR")],
|
|
81530
|
+
[],
|
|
81531
|
+
["Sensor", "Offset (\xB0C)", "M\xE9dia (\xB0C)", "M\xEDn (\xB0C)", "M\xE1x (\xB0C)", "Leituras"],
|
|
81532
|
+
...state6.deviceData.map((dd) => [
|
|
81533
|
+
dd.device.label,
|
|
81534
|
+
offTxt(dd.device),
|
|
81535
|
+
dd.stats.count > 0 ? n2(dd.stats.avg) : "N/A",
|
|
81536
|
+
dd.stats.count > 0 ? n2(dd.stats.min) : "N/A",
|
|
81537
|
+
dd.stats.count > 0 ? n2(dd.stats.max) : "N/A",
|
|
81538
|
+
String(dd.stats.count)
|
|
81539
|
+
]),
|
|
81540
|
+
[]
|
|
81541
|
+
];
|
|
81542
|
+
const perDevice = state6.deviceData.map((dd) => {
|
|
81543
|
+
const filtered = filterByDayPeriods(dd.data, state6.selectedPeriods);
|
|
81544
|
+
const pts = state6.granularity === "hour" ? aggregateByHour(filtered, state6.clampRange).map((p) => [p.ts, Number(p.value)]) : aggregateByDay(filtered, state6.clampRange).map((d) => [d.dateTs, d.avg]);
|
|
81545
|
+
return new Map(pts);
|
|
81171
81546
|
});
|
|
81172
|
-
const
|
|
81547
|
+
const allTs = [...new Set(perDevice.flatMap((m) => [...m.keys()]))].sort((a, b) => a - b);
|
|
81548
|
+
lines.push([state6.granularity === "hour" ? "Data/Hora" : "Dia", ...state6.deviceData.map((dd) => `${dd.device.label} (\xB0C)`)]);
|
|
81549
|
+
allTs.forEach(
|
|
81550
|
+
(ts) => lines.push([
|
|
81551
|
+
state6.granularity === "hour" ? dt(ts) : fmtD(ts),
|
|
81552
|
+
...perDevice.map((m) => m.has(ts) ? n2(m.get(ts)) : "")
|
|
81553
|
+
])
|
|
81554
|
+
);
|
|
81555
|
+
const csv = "\uFEFF" + lines.map((r) => r.map(q).join(";")).join("\r\n");
|
|
81556
|
+
const blob = new Blob([csv], { type: "text/csv;charset=utf-8;" });
|
|
81173
81557
|
const url = URL.createObjectURL(blob);
|
|
81174
81558
|
const link = document.createElement("a");
|
|
81175
81559
|
link.href = url;
|
|
81176
|
-
link.download = `comparacao_temperatura_${
|
|
81560
|
+
link.download = `comparacao_temperatura_${state6.granularity === "hour" ? "1h" : "1d"}_${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}.csv`;
|
|
81177
81561
|
document.body.appendChild(link);
|
|
81178
81562
|
link.click();
|
|
81179
81563
|
document.body.removeChild(link);
|
|
81180
|
-
URL.revokeObjectURL(url);
|
|
81564
|
+
setTimeout(() => URL.revokeObjectURL(url), 1e3);
|
|
81181
81565
|
}
|
|
81182
81566
|
|
|
81183
81567
|
// src/components/temperature/TemperatureSettingsModal.ts
|
|
@@ -93944,7 +94328,7 @@ function fmtPct3(pct) {
|
|
|
93944
94328
|
if (pct == null || !isFinite(pct)) return "";
|
|
93945
94329
|
return `${pct.toLocaleString("pt-BR", { minimumFractionDigits: 1, maximumFractionDigits: 1 })}%`;
|
|
93946
94330
|
}
|
|
93947
|
-
function
|
|
94331
|
+
function resolveAccent3(explicit, doc) {
|
|
93948
94332
|
if (explicit) return explicit;
|
|
93949
94333
|
try {
|
|
93950
94334
|
const v = getComputedStyle(doc.documentElement).getPropertyValue("--myio-brand-700").trim();
|
|
@@ -93990,7 +94374,7 @@ function createGoalsBarTooltip(opts) {
|
|
|
93990
94374
|
injectStyles12(doc);
|
|
93991
94375
|
const el2 = doc.createElement("div");
|
|
93992
94376
|
el2.className = "myio-gbt";
|
|
93993
|
-
el2.style.setProperty("--myio-gbt-accent",
|
|
94377
|
+
el2.style.setProperty("--myio-gbt-accent", resolveAccent3(opts?.accentColor, doc));
|
|
93994
94378
|
doc.body.appendChild(el2);
|
|
93995
94379
|
let pinned = false;
|
|
93996
94380
|
let hideTimer = null;
|
|
@@ -94048,7 +94432,7 @@ function createGoalsBarTooltip(opts) {
|
|
|
94048
94432
|
});
|
|
94049
94433
|
}
|
|
94050
94434
|
function render3(data) {
|
|
94051
|
-
const accent =
|
|
94435
|
+
const accent = resolveAccent3(data.accentColor ?? opts?.accentColor, doc);
|
|
94052
94436
|
el2.style.setProperty("--myio-gbt-accent", accent);
|
|
94053
94437
|
const rowsHtml = data.rows && data.rows.length > 0 ? data.rows.map((r) => renderRow(r, 0)).join("") : `<div class="myio-gbt__empty">Sem dados para este per\xEDodo</div>`;
|
|
94054
94438
|
el2.innerHTML = `
|
|
@@ -132804,19 +133188,19 @@ var TelemetryGridShoppingView = class {
|
|
|
132804
133188
|
this.maximizeBtnEl?.addEventListener("click", this.toggleMaximize.bind(this));
|
|
132805
133189
|
const label = this.params.labelWidget || CONTEXT_CONFIG2[this.params.context]?.headerLabel || "Dispositivos";
|
|
132806
133190
|
const unit = DOMAIN_CONFIG8[this.params.domain]?.unit || "";
|
|
132807
|
-
const
|
|
133191
|
+
const resolveCustomerName3 = () => {
|
|
132808
133192
|
const devs = this.controller.getFilteredDevices();
|
|
132809
133193
|
const name = devs.find((d) => d.customerName)?.customerName;
|
|
132810
133194
|
return name ? String(name).trim() : null;
|
|
132811
133195
|
};
|
|
132812
133196
|
this.root.querySelector("#btnExportPdf")?.addEventListener("click", () => {
|
|
132813
|
-
exportGridPdf(this.controller.getFilteredDevices(), label, unit, null,
|
|
133197
|
+
exportGridPdf(this.controller.getFilteredDevices(), label, unit, null, resolveCustomerName3());
|
|
132814
133198
|
});
|
|
132815
133199
|
this.root.querySelector("#btnExportXls")?.addEventListener("click", () => {
|
|
132816
|
-
exportGridXls(this.controller.getFilteredDevices(), label, unit, null,
|
|
133200
|
+
exportGridXls(this.controller.getFilteredDevices(), label, unit, null, resolveCustomerName3());
|
|
132817
133201
|
});
|
|
132818
133202
|
this.root.querySelector("#btnExportCsv")?.addEventListener("click", () => {
|
|
132819
|
-
exportGridCsv(this.controller.getFilteredDevices(), label, unit, null,
|
|
133203
|
+
exportGridCsv(this.controller.getFilteredDevices(), label, unit, null, resolveCustomerName3());
|
|
132820
133204
|
});
|
|
132821
133205
|
this.bindFilterModalEvents();
|
|
132822
133206
|
}
|