myio-js-library 0.1.321 → 0.1.324
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 +1661 -46
- package/dist/index.d.cts +290 -79
- package/dist/index.js +1659 -46
- package/dist/myio-js-library.umd.js +1659 -46
- package/dist/myio-js-library.umd.min.js +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -680,6 +680,7 @@ __export(index_exports, {
|
|
|
680
680
|
createDeviceItem: () => createDeviceItem,
|
|
681
681
|
createDeviceItemsFromMap: () => createDeviceItemsFromMap,
|
|
682
682
|
createDistributionChartWidget: () => createDistributionChartWidget,
|
|
683
|
+
createEnergyPanelComponent: () => createEnergyPanelComponent,
|
|
683
684
|
createFilterModalComponent: () => createFilterModalComponent,
|
|
684
685
|
createFooterComponent: () => createFooterComponent,
|
|
685
686
|
createHeaderComponent: () => createHeaderComponent,
|
|
@@ -689,6 +690,7 @@ __export(index_exports, {
|
|
|
689
690
|
createMenuComponent: () => createMenuComponent,
|
|
690
691
|
createModalHeader: () => createModalHeader,
|
|
691
692
|
createTelemetryGridComponent: () => createTelemetryGridComponent,
|
|
693
|
+
createWaterPanelComponent: () => createWaterPanelComponent,
|
|
692
694
|
decodePayload: () => decodePayload,
|
|
693
695
|
decodePayloadBase64Xor: () => decodePayloadBase64Xor,
|
|
694
696
|
detectContext: () => detectContext,
|
|
@@ -1775,8 +1777,8 @@ function normalizeConnectionStatus(rawStatus) {
|
|
|
1775
1777
|
}
|
|
1776
1778
|
return "offline";
|
|
1777
1779
|
}
|
|
1778
|
-
function isTelemetryStale(telemetryTimestamp,
|
|
1779
|
-
const timestamp = telemetryTimestamp && telemetryTimestamp > 0 ? telemetryTimestamp :
|
|
1780
|
+
function isTelemetryStale(telemetryTimestamp, delayMins) {
|
|
1781
|
+
const timestamp = telemetryTimestamp && telemetryTimestamp > 0 ? telemetryTimestamp : null;
|
|
1780
1782
|
if (!timestamp) {
|
|
1781
1783
|
return false;
|
|
1782
1784
|
}
|
|
@@ -1786,12 +1788,8 @@ function isTelemetryStale(telemetryTimestamp, lastActivityTime = null, delayMins
|
|
|
1786
1788
|
const timeSinceUpdate = now.getTime() - lastUpdate.getTime();
|
|
1787
1789
|
return timeSinceUpdate > delayMs;
|
|
1788
1790
|
}
|
|
1789
|
-
function isConnectionStale({
|
|
1790
|
-
connectionStatusTs
|
|
1791
|
-
lastActivityTime = null,
|
|
1792
|
-
delayTimeConnectionInMins = 1440
|
|
1793
|
-
} = {}) {
|
|
1794
|
-
return isTelemetryStale(connectionStatusTs, lastActivityTime, delayTimeConnectionInMins);
|
|
1791
|
+
function isConnectionStale({ connectionStatusTs = null, delayTimeConnectionInMins } = {}) {
|
|
1792
|
+
return isTelemetryStale(connectionStatusTs, delayTimeConnectionInMins);
|
|
1795
1793
|
}
|
|
1796
1794
|
function mapDeviceStatusToCardStatus(deviceStatus) {
|
|
1797
1795
|
const statusMap = {
|
|
@@ -1857,41 +1855,33 @@ function calculateDeviceStatus({
|
|
|
1857
1855
|
domain = "energy",
|
|
1858
1856
|
telemetryValue = null,
|
|
1859
1857
|
telemetryTimestamp = null,
|
|
1860
|
-
//
|
|
1861
|
-
lastActivityTime = null,
|
|
1862
|
-
// v3: NOT USED as fallback anymore
|
|
1858
|
+
// MUST be domain-specific (consumptionTs, pulsesTs, etc.)
|
|
1863
1859
|
ranges = null,
|
|
1864
1860
|
// RFC-0110 v2: Dual threshold configuration
|
|
1865
|
-
delayTimeConnectionInMins
|
|
1866
|
-
// For 'online' status
|
|
1867
|
-
shortDelayMins
|
|
1868
|
-
// For 'offline'/'bad' status
|
|
1861
|
+
delayTimeConnectionInMins,
|
|
1862
|
+
// For 'online' status
|
|
1863
|
+
shortDelayMins,
|
|
1864
|
+
// For 'offline'/'bad' status
|
|
1869
1865
|
// Legacy parameters (backward compatibility)
|
|
1870
1866
|
lastConsumptionValue = null,
|
|
1871
1867
|
limitOfPowerOnStandByWatts = null,
|
|
1872
1868
|
limitOfPowerOnAlertWatts = null,
|
|
1873
|
-
limitOfPowerOnFailureWatts = null
|
|
1874
|
-
// @deprecated - kept for backward compatibility
|
|
1875
|
-
lastConnectTime = null,
|
|
1876
|
-
lastDisconnectTime = null
|
|
1869
|
+
limitOfPowerOnFailureWatts = null
|
|
1877
1870
|
}) {
|
|
1878
1871
|
const normalizedStatus = normalizeConnectionStatus(connectionStatus);
|
|
1879
1872
|
if (normalizedStatus === "waiting") {
|
|
1880
1873
|
return DeviceStatusType.NOT_INSTALLED;
|
|
1881
1874
|
}
|
|
1882
1875
|
const hasTelemetryTs = telemetryTimestamp !== null && telemetryTimestamp !== void 0 && telemetryTimestamp > 0;
|
|
1883
|
-
const hasLastActivityTime = lastActivityTime !== null && lastActivityTime !== void 0 && lastActivityTime > 0;
|
|
1884
|
-
const effectiveTimestampForRecovery = hasTelemetryTs ? telemetryTimestamp : hasLastActivityTime ? lastActivityTime : null;
|
|
1885
|
-
const hasEffectiveTimestampForRecovery = effectiveTimestampForRecovery !== null;
|
|
1886
1876
|
if (normalizedStatus === "bad") {
|
|
1887
|
-
const hasRecentTelemetry =
|
|
1877
|
+
const hasRecentTelemetry = hasTelemetryTs && !isTelemetryStale(telemetryTimestamp, shortDelayMins);
|
|
1888
1878
|
if (hasRecentTelemetry) {
|
|
1889
1879
|
} else {
|
|
1890
1880
|
return DeviceStatusType.WEAK_CONNECTION;
|
|
1891
1881
|
}
|
|
1892
1882
|
}
|
|
1893
1883
|
if (normalizedStatus === "offline") {
|
|
1894
|
-
const hasRecentTelemetry =
|
|
1884
|
+
const hasRecentTelemetry = hasTelemetryTs && !isTelemetryStale(telemetryTimestamp, shortDelayMins);
|
|
1895
1885
|
if (!hasRecentTelemetry) {
|
|
1896
1886
|
return DeviceStatusType.OFFLINE;
|
|
1897
1887
|
}
|
|
@@ -1900,7 +1890,7 @@ function calculateDeviceStatus({
|
|
|
1900
1890
|
if (!hasTelemetryTs) {
|
|
1901
1891
|
return DeviceStatusType.OFFLINE;
|
|
1902
1892
|
}
|
|
1903
|
-
const telemetryStale = isTelemetryStale(telemetryTimestamp,
|
|
1893
|
+
const telemetryStale = isTelemetryStale(telemetryTimestamp, delayTimeConnectionInMins);
|
|
1904
1894
|
if (telemetryStale) {
|
|
1905
1895
|
return DeviceStatusType.OFFLINE;
|
|
1906
1896
|
}
|
|
@@ -1953,31 +1943,19 @@ function calculateDeviceStatusWithRanges({
|
|
|
1953
1943
|
ranges,
|
|
1954
1944
|
// RFC-0110: New parameters
|
|
1955
1945
|
telemetryTimestamp = null,
|
|
1956
|
-
|
|
1957
|
-
delayTimeConnectionInMins = 1440,
|
|
1958
|
-
// @deprecated - kept for backward compatibility
|
|
1959
|
-
lastConnectTime = null,
|
|
1960
|
-
lastDisconnectTime = null
|
|
1946
|
+
delayTimeConnectionInMins
|
|
1961
1947
|
}) {
|
|
1962
1948
|
return calculateDeviceStatus({
|
|
1963
1949
|
connectionStatus,
|
|
1964
1950
|
domain: "energy",
|
|
1965
1951
|
telemetryValue: lastConsumptionValue,
|
|
1966
|
-
telemetryTimestamp
|
|
1967
|
-
lastActivityTime,
|
|
1952
|
+
telemetryTimestamp,
|
|
1968
1953
|
ranges,
|
|
1969
1954
|
delayTimeConnectionInMins
|
|
1970
1955
|
});
|
|
1971
1956
|
}
|
|
1972
1957
|
function calculateDeviceStatusMasterRules(options = {}) {
|
|
1973
|
-
const {
|
|
1974
|
-
connectionStatus = "",
|
|
1975
|
-
telemetryTimestamp = null,
|
|
1976
|
-
delayMins = 1440,
|
|
1977
|
-
// 24h for online status
|
|
1978
|
-
domain = "energy"
|
|
1979
|
-
} = options;
|
|
1980
|
-
const SHORT_DELAY_MINS = 60;
|
|
1958
|
+
const { connectionStatus, telemetryTimestamp = null, delayMins, domain, SHORT_DELAY_MINS } = options;
|
|
1981
1959
|
const now = Date.now();
|
|
1982
1960
|
const normalizedStatus = (connectionStatus || "").toLowerCase().trim();
|
|
1983
1961
|
if (normalizedStatus === "waiting" || normalizedStatus === "connecting" || normalizedStatus === "pending") {
|
|
@@ -2132,9 +2110,6 @@ function createDeviceItem(entityId, meta, options = {}) {
|
|
|
2132
2110
|
domain: "energy",
|
|
2133
2111
|
telemetryValue: consumptionValue,
|
|
2134
2112
|
telemetryTimestamp: telemetryTs,
|
|
2135
|
-
// v3: MUST be consumptionTs, NOT lastActivityTime
|
|
2136
|
-
lastActivityTime: null,
|
|
2137
|
-
// v3: NOT used as fallback
|
|
2138
2113
|
ranges,
|
|
2139
2114
|
delayTimeConnectionInMins
|
|
2140
2115
|
});
|
|
@@ -2145,8 +2120,8 @@ function createDeviceItem(entityId, meta, options = {}) {
|
|
|
2145
2120
|
deviceStatus = DeviceStatusType.OFFLINE;
|
|
2146
2121
|
} else {
|
|
2147
2122
|
const SHORT_DELAY_MINS = 60;
|
|
2148
|
-
const hasRecentTelemetry = !isTelemetryStale(telemetryTs,
|
|
2149
|
-
const staleTelemetryLong = isTelemetryStale(telemetryTs,
|
|
2123
|
+
const hasRecentTelemetry = !isTelemetryStale(telemetryTs, SHORT_DELAY_MINS);
|
|
2124
|
+
const staleTelemetryLong = isTelemetryStale(telemetryTs, delayTimeConnectionInMins);
|
|
2150
2125
|
if (connectionStatus === "bad") {
|
|
2151
2126
|
deviceStatus = hasRecentTelemetry ? DeviceStatusType.POWER_ON : DeviceStatusType.WEAK_CONNECTION;
|
|
2152
2127
|
} else if (connectionStatus === "offline") {
|
|
@@ -50833,7 +50808,22 @@ function createConsumption7DaysChart(config) {
|
|
|
50833
50808
|
"#65a30d",
|
|
50834
50809
|
"#d97706",
|
|
50835
50810
|
"#be185d",
|
|
50836
|
-
"#0d9488"
|
|
50811
|
+
"#0d9488",
|
|
50812
|
+
"#7c3aed",
|
|
50813
|
+
"#059669",
|
|
50814
|
+
"#db2777",
|
|
50815
|
+
"#9333ea",
|
|
50816
|
+
"#0284c7",
|
|
50817
|
+
"#ca8a04",
|
|
50818
|
+
"#4f46e5",
|
|
50819
|
+
"#c026d3",
|
|
50820
|
+
"#14b8a6",
|
|
50821
|
+
"#f97316",
|
|
50822
|
+
"#6366f1",
|
|
50823
|
+
"#84cc16",
|
|
50824
|
+
"#ec4899",
|
|
50825
|
+
"#06b6d4",
|
|
50826
|
+
"#a855f7"
|
|
50837
50827
|
];
|
|
50838
50828
|
datasets = Object.entries(data.shoppingData).map(([shoppingId, values], index) => ({
|
|
50839
50829
|
label: data.shoppingNames?.[shoppingId] || shoppingId,
|
|
@@ -66578,6 +66568,1629 @@ var CustomerCardV1 = class {
|
|
|
66578
66568
|
function createCustomerCardV1(params) {
|
|
66579
66569
|
return new CustomerCardV1(params);
|
|
66580
66570
|
}
|
|
66571
|
+
|
|
66572
|
+
// src/components/energy-panel/EnergyPanelController.ts
|
|
66573
|
+
var EnergyPanelController = class {
|
|
66574
|
+
state;
|
|
66575
|
+
params;
|
|
66576
|
+
onStateChange = null;
|
|
66577
|
+
constructor(params) {
|
|
66578
|
+
this.params = params;
|
|
66579
|
+
this.state = {
|
|
66580
|
+
theme: params.theme || "light",
|
|
66581
|
+
period: params.period || 7,
|
|
66582
|
+
vizMode: params.vizMode || "total",
|
|
66583
|
+
chartType: params.chartType || "line",
|
|
66584
|
+
selectedShoppingIds: params.selectedShoppingIds || [],
|
|
66585
|
+
summary: params.initialSummary || null,
|
|
66586
|
+
isLoading: false,
|
|
66587
|
+
error: null
|
|
66588
|
+
};
|
|
66589
|
+
}
|
|
66590
|
+
setOnStateChange(callback) {
|
|
66591
|
+
this.onStateChange = callback;
|
|
66592
|
+
}
|
|
66593
|
+
notifyStateChange() {
|
|
66594
|
+
if (this.onStateChange) {
|
|
66595
|
+
this.onStateChange({ ...this.state });
|
|
66596
|
+
}
|
|
66597
|
+
}
|
|
66598
|
+
getState() {
|
|
66599
|
+
return { ...this.state };
|
|
66600
|
+
}
|
|
66601
|
+
getSummary() {
|
|
66602
|
+
return this.state.summary ? { ...this.state.summary } : null;
|
|
66603
|
+
}
|
|
66604
|
+
updateSummary(data) {
|
|
66605
|
+
this.state.summary = { ...data };
|
|
66606
|
+
this.notifyStateChange();
|
|
66607
|
+
}
|
|
66608
|
+
setTheme(mode) {
|
|
66609
|
+
if (this.state.theme !== mode) {
|
|
66610
|
+
this.state.theme = mode;
|
|
66611
|
+
this.notifyStateChange();
|
|
66612
|
+
}
|
|
66613
|
+
}
|
|
66614
|
+
setPeriod(days) {
|
|
66615
|
+
if (this.state.period !== days) {
|
|
66616
|
+
this.state.period = days;
|
|
66617
|
+
this.params.onPeriodChange?.(days);
|
|
66618
|
+
this.notifyStateChange();
|
|
66619
|
+
}
|
|
66620
|
+
}
|
|
66621
|
+
setVizMode(mode) {
|
|
66622
|
+
if (this.state.vizMode !== mode) {
|
|
66623
|
+
this.state.vizMode = mode;
|
|
66624
|
+
this.params.onVizModeChange?.(mode);
|
|
66625
|
+
this.notifyStateChange();
|
|
66626
|
+
}
|
|
66627
|
+
}
|
|
66628
|
+
setChartType(type) {
|
|
66629
|
+
if (this.state.chartType !== type) {
|
|
66630
|
+
this.state.chartType = type;
|
|
66631
|
+
this.notifyStateChange();
|
|
66632
|
+
}
|
|
66633
|
+
}
|
|
66634
|
+
applyShoppingFilter(ids) {
|
|
66635
|
+
this.state.selectedShoppingIds = [...ids];
|
|
66636
|
+
this.params.onFilterChange?.(ids);
|
|
66637
|
+
this.notifyStateChange();
|
|
66638
|
+
}
|
|
66639
|
+
clearFilters() {
|
|
66640
|
+
this.state.selectedShoppingIds = [];
|
|
66641
|
+
this.params.onFilterChange?.([]);
|
|
66642
|
+
this.notifyStateChange();
|
|
66643
|
+
}
|
|
66644
|
+
setLoading(loading) {
|
|
66645
|
+
this.state.isLoading = loading;
|
|
66646
|
+
this.notifyStateChange();
|
|
66647
|
+
}
|
|
66648
|
+
setError(error) {
|
|
66649
|
+
this.state.error = error;
|
|
66650
|
+
this.notifyStateChange();
|
|
66651
|
+
}
|
|
66652
|
+
};
|
|
66653
|
+
|
|
66654
|
+
// src/components/energy-panel/styles.ts
|
|
66655
|
+
var ENERGY_PANEL_STYLES = `
|
|
66656
|
+
.energy-panel-wrap {
|
|
66657
|
+
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
66658
|
+
color: #1e293b;
|
|
66659
|
+
background-color: #f8fafc;
|
|
66660
|
+
padding: 16px;
|
|
66661
|
+
border-radius: 12px;
|
|
66662
|
+
}
|
|
66663
|
+
|
|
66664
|
+
.energy-panel-wrap[data-theme="dark"] {
|
|
66665
|
+
color: #e2e8f0;
|
|
66666
|
+
background-color: #1e293b;
|
|
66667
|
+
}
|
|
66668
|
+
|
|
66669
|
+
.energy-panel__cards {
|
|
66670
|
+
display: grid;
|
|
66671
|
+
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
|
|
66672
|
+
gap: 16px;
|
|
66673
|
+
margin-bottom: 20px;
|
|
66674
|
+
}
|
|
66675
|
+
|
|
66676
|
+
.energy-panel__card {
|
|
66677
|
+
background-color: #ffffff;
|
|
66678
|
+
padding: 16px;
|
|
66679
|
+
border-radius: 12px;
|
|
66680
|
+
display: flex;
|
|
66681
|
+
align-items: center;
|
|
66682
|
+
border: 1px solid #e2e8f0;
|
|
66683
|
+
transition: box-shadow 0.2s ease;
|
|
66684
|
+
}
|
|
66685
|
+
|
|
66686
|
+
.energy-panel__card:hover {
|
|
66687
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
|
|
66688
|
+
}
|
|
66689
|
+
|
|
66690
|
+
.energy-panel-wrap[data-theme="dark"] .energy-panel__card {
|
|
66691
|
+
background-color: #334155;
|
|
66692
|
+
border-color: #475569;
|
|
66693
|
+
}
|
|
66694
|
+
|
|
66695
|
+
.energy-panel__card-icon {
|
|
66696
|
+
font-size: 2.5em;
|
|
66697
|
+
margin-right: 16px;
|
|
66698
|
+
}
|
|
66699
|
+
|
|
66700
|
+
.energy-panel__card-label {
|
|
66701
|
+
font-size: 13px;
|
|
66702
|
+
color: #64748b;
|
|
66703
|
+
font-weight: 500;
|
|
66704
|
+
}
|
|
66705
|
+
|
|
66706
|
+
.energy-panel-wrap[data-theme="dark"] .energy-panel__card-label {
|
|
66707
|
+
color: #94a3b8;
|
|
66708
|
+
}
|
|
66709
|
+
|
|
66710
|
+
.energy-panel__card-value {
|
|
66711
|
+
font-size: 1.6em;
|
|
66712
|
+
font-weight: 700;
|
|
66713
|
+
color: #2563eb;
|
|
66714
|
+
}
|
|
66715
|
+
|
|
66716
|
+
.energy-panel-wrap[data-theme="dark"] .energy-panel__card-value {
|
|
66717
|
+
color: #60a5fa;
|
|
66718
|
+
}
|
|
66719
|
+
|
|
66720
|
+
.energy-panel__card-count {
|
|
66721
|
+
font-size: 12px;
|
|
66722
|
+
color: #94a3b8;
|
|
66723
|
+
}
|
|
66724
|
+
|
|
66725
|
+
.energy-panel-wrap[data-theme="dark"] .energy-panel__card-count {
|
|
66726
|
+
color: #64748b;
|
|
66727
|
+
}
|
|
66728
|
+
|
|
66729
|
+
.energy-panel__chart-section {
|
|
66730
|
+
background-color: #ffffff;
|
|
66731
|
+
padding: 16px;
|
|
66732
|
+
border-radius: 12px;
|
|
66733
|
+
border: 1px solid #e2e8f0;
|
|
66734
|
+
margin-bottom: 20px;
|
|
66735
|
+
}
|
|
66736
|
+
|
|
66737
|
+
.energy-panel-wrap[data-theme="dark"] .energy-panel__chart-section {
|
|
66738
|
+
background-color: #334155;
|
|
66739
|
+
border-color: #475569;
|
|
66740
|
+
}
|
|
66741
|
+
|
|
66742
|
+
.energy-panel__chart-header {
|
|
66743
|
+
display: flex;
|
|
66744
|
+
justify-content: space-between;
|
|
66745
|
+
align-items: center;
|
|
66746
|
+
flex-wrap: wrap;
|
|
66747
|
+
gap: 12px;
|
|
66748
|
+
margin-bottom: 16px;
|
|
66749
|
+
padding-bottom: 12px;
|
|
66750
|
+
border-bottom: 1px solid #e2e8f0;
|
|
66751
|
+
}
|
|
66752
|
+
|
|
66753
|
+
.energy-panel-wrap[data-theme="dark"] .energy-panel__chart-header {
|
|
66754
|
+
border-bottom-color: #475569;
|
|
66755
|
+
}
|
|
66756
|
+
|
|
66757
|
+
.energy-panel__chart-title-group {
|
|
66758
|
+
display: flex;
|
|
66759
|
+
align-items: center;
|
|
66760
|
+
gap: 12px;
|
|
66761
|
+
flex-wrap: wrap;
|
|
66762
|
+
}
|
|
66763
|
+
|
|
66764
|
+
.energy-panel__chart-header h3 {
|
|
66765
|
+
margin: 0;
|
|
66766
|
+
font-size: 15px;
|
|
66767
|
+
font-weight: 600;
|
|
66768
|
+
color: #1e293b;
|
|
66769
|
+
}
|
|
66770
|
+
|
|
66771
|
+
.energy-panel-wrap[data-theme="dark"] .energy-panel__chart-header h3 {
|
|
66772
|
+
color: #f1f5f9;
|
|
66773
|
+
}
|
|
66774
|
+
|
|
66775
|
+
/* Tab styles */
|
|
66776
|
+
.energy-panel__chart-tabs {
|
|
66777
|
+
display: flex;
|
|
66778
|
+
gap: 2px;
|
|
66779
|
+
background: #f1f5f9;
|
|
66780
|
+
padding: 3px;
|
|
66781
|
+
border-radius: 8px;
|
|
66782
|
+
}
|
|
66783
|
+
|
|
66784
|
+
.energy-panel-wrap[data-theme="dark"] .energy-panel__chart-tabs {
|
|
66785
|
+
background: #1e293b;
|
|
66786
|
+
}
|
|
66787
|
+
|
|
66788
|
+
.energy-panel__tab {
|
|
66789
|
+
display: flex;
|
|
66790
|
+
align-items: center;
|
|
66791
|
+
justify-content: center;
|
|
66792
|
+
padding: 6px 10px;
|
|
66793
|
+
border: none;
|
|
66794
|
+
background: transparent;
|
|
66795
|
+
color: #64748b;
|
|
66796
|
+
cursor: pointer;
|
|
66797
|
+
border-radius: 6px;
|
|
66798
|
+
transition: all 0.2s ease;
|
|
66799
|
+
font-size: 12px;
|
|
66800
|
+
font-weight: 500;
|
|
66801
|
+
}
|
|
66802
|
+
|
|
66803
|
+
.energy-panel__tab:hover {
|
|
66804
|
+
color: #1e293b;
|
|
66805
|
+
background: rgba(0, 0, 0, 0.05);
|
|
66806
|
+
}
|
|
66807
|
+
|
|
66808
|
+
.energy-panel-wrap[data-theme="dark"] .energy-panel__tab:hover {
|
|
66809
|
+
color: #e2e8f0;
|
|
66810
|
+
background: rgba(255, 255, 255, 0.1);
|
|
66811
|
+
}
|
|
66812
|
+
|
|
66813
|
+
.energy-panel__tab.active {
|
|
66814
|
+
background: #2563eb;
|
|
66815
|
+
color: white;
|
|
66816
|
+
box-shadow: 0 1px 3px rgba(37, 99, 235, 0.3);
|
|
66817
|
+
}
|
|
66818
|
+
|
|
66819
|
+
.energy-panel__tab svg {
|
|
66820
|
+
width: 14px;
|
|
66821
|
+
height: 14px;
|
|
66822
|
+
}
|
|
66823
|
+
|
|
66824
|
+
/* Controls */
|
|
66825
|
+
.energy-panel__chart-controls {
|
|
66826
|
+
display: flex;
|
|
66827
|
+
align-items: center;
|
|
66828
|
+
gap: 8px;
|
|
66829
|
+
}
|
|
66830
|
+
|
|
66831
|
+
.energy-panel__chart-controls select {
|
|
66832
|
+
padding: 6px 12px;
|
|
66833
|
+
border-radius: 6px;
|
|
66834
|
+
border: 1px solid #e2e8f0;
|
|
66835
|
+
background-color: #ffffff;
|
|
66836
|
+
color: #1e293b;
|
|
66837
|
+
font-size: 12px;
|
|
66838
|
+
font-weight: 500;
|
|
66839
|
+
cursor: pointer;
|
|
66840
|
+
min-width: 180px;
|
|
66841
|
+
}
|
|
66842
|
+
|
|
66843
|
+
.energy-panel__chart-controls select:focus {
|
|
66844
|
+
outline: none;
|
|
66845
|
+
border-color: #2563eb;
|
|
66846
|
+
}
|
|
66847
|
+
|
|
66848
|
+
.energy-panel-wrap[data-theme="dark"] .energy-panel__chart-controls select {
|
|
66849
|
+
background-color: #1e293b;
|
|
66850
|
+
border-color: #475569;
|
|
66851
|
+
color: #e2e8f0;
|
|
66852
|
+
}
|
|
66853
|
+
|
|
66854
|
+
.energy-panel__period-select {
|
|
66855
|
+
min-width: 100px !important;
|
|
66856
|
+
}
|
|
66857
|
+
|
|
66858
|
+
.energy-panel__distribution-mode {
|
|
66859
|
+
min-width: 220px !important;
|
|
66860
|
+
}
|
|
66861
|
+
|
|
66862
|
+
.energy-panel__maximize-btn {
|
|
66863
|
+
display: flex;
|
|
66864
|
+
align-items: center;
|
|
66865
|
+
justify-content: center;
|
|
66866
|
+
width: 32px;
|
|
66867
|
+
height: 32px;
|
|
66868
|
+
padding: 0;
|
|
66869
|
+
border: 1px solid #e2e8f0;
|
|
66870
|
+
border-radius: 6px;
|
|
66871
|
+
background: transparent;
|
|
66872
|
+
color: #64748b;
|
|
66873
|
+
cursor: pointer;
|
|
66874
|
+
font-size: 16px;
|
|
66875
|
+
transition: all 0.2s ease;
|
|
66876
|
+
}
|
|
66877
|
+
|
|
66878
|
+
.energy-panel__maximize-btn:hover {
|
|
66879
|
+
background: #2563eb;
|
|
66880
|
+
border-color: #2563eb;
|
|
66881
|
+
color: white;
|
|
66882
|
+
}
|
|
66883
|
+
|
|
66884
|
+
.energy-panel-wrap[data-theme="dark"] .energy-panel__maximize-btn {
|
|
66885
|
+
border-color: #475569;
|
|
66886
|
+
color: #94a3b8;
|
|
66887
|
+
}
|
|
66888
|
+
|
|
66889
|
+
.energy-panel-wrap[data-theme="dark"] .energy-panel__maximize-btn:hover {
|
|
66890
|
+
background: #2563eb;
|
|
66891
|
+
border-color: #2563eb;
|
|
66892
|
+
color: white;
|
|
66893
|
+
}
|
|
66894
|
+
|
|
66895
|
+
/* Chart containers */
|
|
66896
|
+
.energy-panel__consumption-chart,
|
|
66897
|
+
.energy-panel__distribution-chart {
|
|
66898
|
+
min-height: 220px;
|
|
66899
|
+
position: relative;
|
|
66900
|
+
}
|
|
66901
|
+
|
|
66902
|
+
.energy-panel__consumption-chart canvas,
|
|
66903
|
+
.energy-panel__distribution-chart canvas {
|
|
66904
|
+
width: 100% !important;
|
|
66905
|
+
}
|
|
66906
|
+
|
|
66907
|
+
/* Responsive */
|
|
66908
|
+
@media (max-width: 768px) {
|
|
66909
|
+
.energy-panel__chart-header {
|
|
66910
|
+
flex-direction: column;
|
|
66911
|
+
align-items: flex-start;
|
|
66912
|
+
}
|
|
66913
|
+
|
|
66914
|
+
.energy-panel__chart-title-group {
|
|
66915
|
+
width: 100%;
|
|
66916
|
+
flex-wrap: wrap;
|
|
66917
|
+
}
|
|
66918
|
+
|
|
66919
|
+
.energy-panel__chart-controls {
|
|
66920
|
+
width: 100%;
|
|
66921
|
+
justify-content: flex-start;
|
|
66922
|
+
}
|
|
66923
|
+
|
|
66924
|
+
.energy-panel__distribution-mode {
|
|
66925
|
+
flex: 1;
|
|
66926
|
+
}
|
|
66927
|
+
}
|
|
66928
|
+
`;
|
|
66929
|
+
function injectEnergyPanelStyles() {
|
|
66930
|
+
if (!document.getElementById("energy-panel-styles")) {
|
|
66931
|
+
const styleTag = document.createElement("style");
|
|
66932
|
+
styleTag.id = "energy-panel-styles";
|
|
66933
|
+
styleTag.textContent = ENERGY_PANEL_STYLES;
|
|
66934
|
+
document.head.appendChild(styleTag);
|
|
66935
|
+
}
|
|
66936
|
+
}
|
|
66937
|
+
|
|
66938
|
+
// src/components/energy-panel/EnergyPanelView.ts
|
|
66939
|
+
var EnergyPanelView = class {
|
|
66940
|
+
params;
|
|
66941
|
+
controller;
|
|
66942
|
+
root = null;
|
|
66943
|
+
// Chart widget instances (using existing reusable components)
|
|
66944
|
+
consumptionWidget = null;
|
|
66945
|
+
distributionWidget = null;
|
|
66946
|
+
// Unique IDs for this panel instance
|
|
66947
|
+
panelId;
|
|
66948
|
+
constructor(params, controller) {
|
|
66949
|
+
this.params = params;
|
|
66950
|
+
this.controller = controller;
|
|
66951
|
+
this.panelId = `energy-panel-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
66952
|
+
this.controller.setOnStateChange((state6) => this.onStateChange(state6));
|
|
66953
|
+
}
|
|
66954
|
+
render() {
|
|
66955
|
+
injectEnergyPanelStyles();
|
|
66956
|
+
const state6 = this.controller.getState();
|
|
66957
|
+
this.root = document.createElement("div");
|
|
66958
|
+
this.root.className = "energy-panel-wrap";
|
|
66959
|
+
this.root.setAttribute("data-theme", state6.theme);
|
|
66960
|
+
this.root.setAttribute("data-domain", "energy");
|
|
66961
|
+
this.root.innerHTML = this.buildHTML(state6);
|
|
66962
|
+
this.bindEvents();
|
|
66963
|
+
setTimeout(() => this.initializeCharts(), 0);
|
|
66964
|
+
return this.root;
|
|
66965
|
+
}
|
|
66966
|
+
buildHTML(state6) {
|
|
66967
|
+
const { showCards = true, showConsumptionChart = true, showDistributionChart = true } = this.params;
|
|
66968
|
+
return `
|
|
66969
|
+
<div class="energy-panel">
|
|
66970
|
+
${showCards ? this.buildCardsHTML(state6) : ""}
|
|
66971
|
+
${showConsumptionChart ? this.buildConsumptionChartContainerHTML() : ""}
|
|
66972
|
+
${showDistributionChart ? this.buildDistributionChartContainerHTML() : ""}
|
|
66973
|
+
</div>
|
|
66974
|
+
`;
|
|
66975
|
+
}
|
|
66976
|
+
buildCardsHTML(state6) {
|
|
66977
|
+
const summary = state6.summary;
|
|
66978
|
+
const storesValue = summary?.storesTotal ?? 0;
|
|
66979
|
+
const equipmentsValue = summary?.equipmentsTotal ?? 0;
|
|
66980
|
+
return `
|
|
66981
|
+
<div class="energy-panel__cards">
|
|
66982
|
+
<div class="energy-panel__card" data-type="stores">
|
|
66983
|
+
<div class="energy-panel__card-icon">🏠</div>
|
|
66984
|
+
<div class="energy-panel__card-content">
|
|
66985
|
+
<div class="energy-panel__card-label">Consumo Lojas</div>
|
|
66986
|
+
<div class="energy-panel__card-value">${this.formatEnergy(storesValue)}</div>
|
|
66987
|
+
<div class="energy-panel__card-count">${summary?.byCategory?.lojas?.count || 0} medidores</div>
|
|
66988
|
+
</div>
|
|
66989
|
+
</div>
|
|
66990
|
+
<div class="energy-panel__card" data-type="equipments">
|
|
66991
|
+
<div class="energy-panel__card-icon">⚙️</div>
|
|
66992
|
+
<div class="energy-panel__card-content">
|
|
66993
|
+
<div class="energy-panel__card-label">Consumo Equipamentos</div>
|
|
66994
|
+
<div class="energy-panel__card-value">${this.formatEnergy(equipmentsValue)}</div>
|
|
66995
|
+
<div class="energy-panel__card-count">${this.getEquipmentCount(summary)} equipamentos</div>
|
|
66996
|
+
</div>
|
|
66997
|
+
</div>
|
|
66998
|
+
</div>
|
|
66999
|
+
`;
|
|
67000
|
+
}
|
|
67001
|
+
/**
|
|
67002
|
+
* Container for consumption chart widget (RFC-0098)
|
|
67003
|
+
* The createConsumptionChartWidget will inject its own HTML structure
|
|
67004
|
+
*/
|
|
67005
|
+
buildConsumptionChartContainerHTML() {
|
|
67006
|
+
return `
|
|
67007
|
+
<div class="energy-panel__chart-section">
|
|
67008
|
+
<div id="${this.panelId}-consumption-chart" class="energy-panel__consumption-chart"></div>
|
|
67009
|
+
</div>
|
|
67010
|
+
`;
|
|
67011
|
+
}
|
|
67012
|
+
/**
|
|
67013
|
+
* Container for distribution chart widget (RFC-0102)
|
|
67014
|
+
* The createDistributionChartWidget will inject its own HTML structure
|
|
67015
|
+
*/
|
|
67016
|
+
buildDistributionChartContainerHTML() {
|
|
67017
|
+
return `
|
|
67018
|
+
<div class="energy-panel__chart-section">
|
|
67019
|
+
<div id="${this.panelId}-distribution-chart" class="energy-panel__distribution-chart"></div>
|
|
67020
|
+
</div>
|
|
67021
|
+
`;
|
|
67022
|
+
}
|
|
67023
|
+
formatEnergy(value) {
|
|
67024
|
+
if (value >= 1e3) {
|
|
67025
|
+
return `${(value / 1e3).toFixed(2)} MWh`;
|
|
67026
|
+
}
|
|
67027
|
+
return `${value.toFixed(1)} kWh`;
|
|
67028
|
+
}
|
|
67029
|
+
getEquipmentCount(summary) {
|
|
67030
|
+
if (!summary?.byCategory) return 0;
|
|
67031
|
+
const { climatizacao, elevadores, escadas, outros } = summary.byCategory;
|
|
67032
|
+
return (climatizacao?.count || 0) + (elevadores?.count || 0) + (escadas?.count || 0) + (outros?.count || 0);
|
|
67033
|
+
}
|
|
67034
|
+
bindEvents() {
|
|
67035
|
+
}
|
|
67036
|
+
/**
|
|
67037
|
+
* Initialize chart widgets using the existing reusable components
|
|
67038
|
+
*/
|
|
67039
|
+
async initializeCharts() {
|
|
67040
|
+
if (!this.root) return;
|
|
67041
|
+
const state6 = this.controller.getState();
|
|
67042
|
+
const { showConsumptionChart = true, showDistributionChart = true } = this.params;
|
|
67043
|
+
if (showConsumptionChart) {
|
|
67044
|
+
await this.initializeConsumptionWidget(state6);
|
|
67045
|
+
}
|
|
67046
|
+
if (showDistributionChart) {
|
|
67047
|
+
await this.initializeDistributionWidget(state6);
|
|
67048
|
+
}
|
|
67049
|
+
}
|
|
67050
|
+
/**
|
|
67051
|
+
* Initialize the consumption chart using createConsumptionChartWidget
|
|
67052
|
+
* This provides: settings modal, ideal range, viz modes, chart types
|
|
67053
|
+
*/
|
|
67054
|
+
async initializeConsumptionWidget(state6) {
|
|
67055
|
+
const containerId = `${this.panelId}-consumption-chart`;
|
|
67056
|
+
const container = this.root?.querySelector(`#${containerId}`);
|
|
67057
|
+
if (!container) {
|
|
67058
|
+
console.warn("[EnergyPanel] Consumption chart container not found");
|
|
67059
|
+
return;
|
|
67060
|
+
}
|
|
67061
|
+
try {
|
|
67062
|
+
this.consumptionWidget = createConsumptionChartWidget({
|
|
67063
|
+
domain: "energy",
|
|
67064
|
+
containerId,
|
|
67065
|
+
title: "Consumo de Energia",
|
|
67066
|
+
unit: "kWh",
|
|
67067
|
+
unitLarge: "MWh",
|
|
67068
|
+
thresholdForLargeUnit: 1e3,
|
|
67069
|
+
theme: state6.theme,
|
|
67070
|
+
defaultPeriod: state6.period,
|
|
67071
|
+
defaultChartType: "line",
|
|
67072
|
+
defaultVizMode: "total",
|
|
67073
|
+
// Settings modal options
|
|
67074
|
+
showSettingsButton: true,
|
|
67075
|
+
showMaximizeButton: true,
|
|
67076
|
+
showVizModeTabs: true,
|
|
67077
|
+
showChartTypeTabs: true,
|
|
67078
|
+
chartHeight: 280,
|
|
67079
|
+
// Data fetching - use params callback or mock data
|
|
67080
|
+
fetchData: this.params.fetchConsumptionData || this.createMockFetchData(),
|
|
67081
|
+
// Callbacks
|
|
67082
|
+
onMaximizeClick: () => {
|
|
67083
|
+
this.params.onMaximizeClick?.();
|
|
67084
|
+
},
|
|
67085
|
+
onSettingsClick: () => {
|
|
67086
|
+
console.log("[EnergyPanel] Settings clicked");
|
|
67087
|
+
},
|
|
67088
|
+
onDataLoaded: (data) => {
|
|
67089
|
+
console.log("[EnergyPanel] Consumption data loaded:", data.labels?.length, "days");
|
|
67090
|
+
},
|
|
67091
|
+
onError: (error) => {
|
|
67092
|
+
console.error("[EnergyPanel] Consumption chart error:", error);
|
|
67093
|
+
},
|
|
67094
|
+
// Ideal range (from customer settings or orchestrator)
|
|
67095
|
+
idealRange: this.params.idealRange || void 0,
|
|
67096
|
+
// ThingsBoard container reference
|
|
67097
|
+
$container: this.params.$container
|
|
67098
|
+
});
|
|
67099
|
+
await this.consumptionWidget.render();
|
|
67100
|
+
console.log("[EnergyPanel] Consumption widget initialized");
|
|
67101
|
+
} catch (error) {
|
|
67102
|
+
console.error("[EnergyPanel] Failed to initialize consumption widget:", error);
|
|
67103
|
+
}
|
|
67104
|
+
}
|
|
67105
|
+
/**
|
|
67106
|
+
* Initialize the distribution chart using createDistributionChartWidget
|
|
67107
|
+
* This provides: mode selector, horizontal bars, shopping colors
|
|
67108
|
+
*/
|
|
67109
|
+
async initializeDistributionWidget(state6) {
|
|
67110
|
+
const containerId = `${this.panelId}-distribution-chart`;
|
|
67111
|
+
const container = this.root?.querySelector(`#${containerId}`);
|
|
67112
|
+
if (!container) {
|
|
67113
|
+
console.warn("[EnergyPanel] Distribution chart container not found");
|
|
67114
|
+
return;
|
|
67115
|
+
}
|
|
67116
|
+
try {
|
|
67117
|
+
this.distributionWidget = createDistributionChartWidget({
|
|
67118
|
+
domain: "energy",
|
|
67119
|
+
containerId,
|
|
67120
|
+
title: "Distribuicao de Consumo",
|
|
67121
|
+
unit: "kWh",
|
|
67122
|
+
unitLarge: "MWh",
|
|
67123
|
+
thresholdForLargeUnit: 1e3,
|
|
67124
|
+
theme: state6.theme,
|
|
67125
|
+
chartHeight: 300,
|
|
67126
|
+
showHeader: true,
|
|
67127
|
+
showModeSelector: true,
|
|
67128
|
+
showSettingsButton: false,
|
|
67129
|
+
showMaximizeButton: false,
|
|
67130
|
+
defaultMode: "groups",
|
|
67131
|
+
// Energy-specific modes
|
|
67132
|
+
modes: [
|
|
67133
|
+
{ value: "groups", label: "Por Grupos de Equipamentos" },
|
|
67134
|
+
{ value: "elevators", label: "Elevadores por Shopping" },
|
|
67135
|
+
{ value: "escalators", label: "Escadas Rolantes por Shopping" },
|
|
67136
|
+
{ value: "hvac", label: "Climatizacao por Shopping" },
|
|
67137
|
+
{ value: "others", label: "Outros Equipamentos por Shopping" },
|
|
67138
|
+
{ value: "stores", label: "Lojas por Shopping" }
|
|
67139
|
+
],
|
|
67140
|
+
// Data fetching
|
|
67141
|
+
fetchDistribution: this.params.fetchDistributionData || this.createMockFetchDistribution(),
|
|
67142
|
+
// Callbacks
|
|
67143
|
+
onModeChange: (mode) => {
|
|
67144
|
+
console.log("[EnergyPanel] Distribution mode changed:", mode);
|
|
67145
|
+
},
|
|
67146
|
+
onDataLoaded: (data) => {
|
|
67147
|
+
console.log("[EnergyPanel] Distribution data loaded:", Object.keys(data).length, "categories");
|
|
67148
|
+
},
|
|
67149
|
+
onError: (error) => {
|
|
67150
|
+
console.error("[EnergyPanel] Distribution chart error:", error);
|
|
67151
|
+
},
|
|
67152
|
+
// Get shopping colors from orchestrator
|
|
67153
|
+
getShoppingColors: () => {
|
|
67154
|
+
return window.MyIOOrchestrator?.getShoppingColors?.() || null;
|
|
67155
|
+
}
|
|
67156
|
+
});
|
|
67157
|
+
await this.distributionWidget.render();
|
|
67158
|
+
console.log("[EnergyPanel] Distribution widget initialized");
|
|
67159
|
+
} catch (error) {
|
|
67160
|
+
console.error("[EnergyPanel] Failed to initialize distribution widget:", error);
|
|
67161
|
+
}
|
|
67162
|
+
}
|
|
67163
|
+
/**
|
|
67164
|
+
* Create mock data fetcher for showcase/demo purposes
|
|
67165
|
+
*/
|
|
67166
|
+
createMockFetchData() {
|
|
67167
|
+
return async (period) => {
|
|
67168
|
+
const labels = [];
|
|
67169
|
+
const dailyTotals = [];
|
|
67170
|
+
const today = /* @__PURE__ */ new Date();
|
|
67171
|
+
for (let i = period - 1; i >= 0; i--) {
|
|
67172
|
+
const date = new Date(today);
|
|
67173
|
+
date.setDate(date.getDate() - i);
|
|
67174
|
+
labels.push(date.toLocaleDateString("pt-BR", { day: "2-digit", month: "2-digit" }));
|
|
67175
|
+
const baseValue = 500 + Math.random() * 500;
|
|
67176
|
+
const variation = (Math.random() - 0.5) * 200;
|
|
67177
|
+
dailyTotals.push(Math.max(100, baseValue + variation));
|
|
67178
|
+
}
|
|
67179
|
+
const shoppingData = {
|
|
67180
|
+
"shopping-1": dailyTotals.map((v) => v * 0.35),
|
|
67181
|
+
"shopping-2": dailyTotals.map((v) => v * 0.25),
|
|
67182
|
+
"shopping-3": dailyTotals.map((v) => v * 0.25),
|
|
67183
|
+
"shopping-4": dailyTotals.map((v) => v * 0.15)
|
|
67184
|
+
};
|
|
67185
|
+
const shoppingNames = {
|
|
67186
|
+
"shopping-1": "Shopping Aricanduva",
|
|
67187
|
+
"shopping-2": "Shopping Interlagos",
|
|
67188
|
+
"shopping-3": "Shopping Tucuruvi",
|
|
67189
|
+
"shopping-4": "Shopping Penha"
|
|
67190
|
+
};
|
|
67191
|
+
return {
|
|
67192
|
+
labels,
|
|
67193
|
+
dailyTotals,
|
|
67194
|
+
shoppingData,
|
|
67195
|
+
shoppingNames,
|
|
67196
|
+
fetchTimestamp: Date.now()
|
|
67197
|
+
};
|
|
67198
|
+
};
|
|
67199
|
+
}
|
|
67200
|
+
/**
|
|
67201
|
+
* Create mock distribution data fetcher for showcase/demo purposes
|
|
67202
|
+
*/
|
|
67203
|
+
createMockFetchDistribution() {
|
|
67204
|
+
const state6 = this.controller.getState();
|
|
67205
|
+
const summary = state6.summary;
|
|
67206
|
+
return async (mode) => {
|
|
67207
|
+
if (mode === "groups") {
|
|
67208
|
+
if (summary?.byCategory) {
|
|
67209
|
+
return {
|
|
67210
|
+
"Lojas": summary.byCategory.lojas?.total || 0,
|
|
67211
|
+
"Climatizacao": summary.byCategory.climatizacao?.total || 0,
|
|
67212
|
+
"Elevadores": summary.byCategory.elevadores?.total || 0,
|
|
67213
|
+
"Escadas Rolantes": summary.byCategory.escadas?.total || 0,
|
|
67214
|
+
"Outros": summary.byCategory.outros?.total || 0
|
|
67215
|
+
};
|
|
67216
|
+
}
|
|
67217
|
+
return {
|
|
67218
|
+
"Lojas": 12500,
|
|
67219
|
+
"Climatizacao": 8500,
|
|
67220
|
+
"Elevadores": 3200,
|
|
67221
|
+
"Escadas Rolantes": 2100,
|
|
67222
|
+
"Outros": 1800
|
|
67223
|
+
};
|
|
67224
|
+
}
|
|
67225
|
+
if (mode === "elevators") {
|
|
67226
|
+
return {
|
|
67227
|
+
"Shopping Aricanduva": 2400,
|
|
67228
|
+
"Shopping Interlagos": 1800,
|
|
67229
|
+
"Shopping Tucuruvi": 1500,
|
|
67230
|
+
"Shopping Penha": 1200,
|
|
67231
|
+
"Shopping Tatuape": 900
|
|
67232
|
+
};
|
|
67233
|
+
}
|
|
67234
|
+
if (mode === "escalators") {
|
|
67235
|
+
return {
|
|
67236
|
+
"Shopping Aricanduva": 1800,
|
|
67237
|
+
"Shopping Interlagos": 1400,
|
|
67238
|
+
"Shopping Tucuruvi": 1100,
|
|
67239
|
+
"Shopping Penha": 800
|
|
67240
|
+
};
|
|
67241
|
+
}
|
|
67242
|
+
if (mode === "hvac") {
|
|
67243
|
+
return {
|
|
67244
|
+
"Shopping Aricanduva": 5200,
|
|
67245
|
+
"Shopping Interlagos": 4100,
|
|
67246
|
+
"Shopping Tucuruvi": 3800,
|
|
67247
|
+
"Shopping Penha": 3200,
|
|
67248
|
+
"Shopping Tatuape": 2800,
|
|
67249
|
+
"Shopping Santana": 2400
|
|
67250
|
+
};
|
|
67251
|
+
}
|
|
67252
|
+
if (mode === "others") {
|
|
67253
|
+
return {
|
|
67254
|
+
"Shopping Aricanduva": 1200,
|
|
67255
|
+
"Shopping Interlagos": 900,
|
|
67256
|
+
"Shopping Tucuruvi": 700
|
|
67257
|
+
};
|
|
67258
|
+
}
|
|
67259
|
+
if (mode === "stores") {
|
|
67260
|
+
return {
|
|
67261
|
+
"Shopping Aricanduva": 8500,
|
|
67262
|
+
"Shopping Interlagos": 7200,
|
|
67263
|
+
"Shopping Tucuruvi": 6800,
|
|
67264
|
+
"Shopping Penha": 5500,
|
|
67265
|
+
"Shopping Tatuape": 5100,
|
|
67266
|
+
"Shopping Santana": 4800,
|
|
67267
|
+
"Shopping Campo Limpo": 4200
|
|
67268
|
+
};
|
|
67269
|
+
}
|
|
67270
|
+
return null;
|
|
67271
|
+
};
|
|
67272
|
+
}
|
|
67273
|
+
onStateChange(state6) {
|
|
67274
|
+
if (!this.root) return;
|
|
67275
|
+
this.root.setAttribute("data-theme", state6.theme);
|
|
67276
|
+
if (this.consumptionWidget) {
|
|
67277
|
+
this.consumptionWidget.setTheme(state6.theme);
|
|
67278
|
+
}
|
|
67279
|
+
if (this.distributionWidget) {
|
|
67280
|
+
this.distributionWidget.setTheme(state6.theme);
|
|
67281
|
+
}
|
|
67282
|
+
this.updateCards(state6);
|
|
67283
|
+
}
|
|
67284
|
+
updateCards(state6) {
|
|
67285
|
+
const summary = state6.summary;
|
|
67286
|
+
if (!summary || !this.root) return;
|
|
67287
|
+
const storesCard = this.root.querySelector('[data-type="stores"] .energy-panel__card-value');
|
|
67288
|
+
const equipmentsCard = this.root.querySelector('[data-type="equipments"] .energy-panel__card-value');
|
|
67289
|
+
if (storesCard) {
|
|
67290
|
+
storesCard.textContent = this.formatEnergy(summary.storesTotal);
|
|
67291
|
+
}
|
|
67292
|
+
if (equipmentsCard) {
|
|
67293
|
+
equipmentsCard.textContent = this.formatEnergy(summary.equipmentsTotal);
|
|
67294
|
+
}
|
|
67295
|
+
}
|
|
67296
|
+
/**
|
|
67297
|
+
* Public method to refresh consumption chart data
|
|
67298
|
+
*/
|
|
67299
|
+
async refreshConsumptionChart() {
|
|
67300
|
+
if (this.consumptionWidget) {
|
|
67301
|
+
await this.consumptionWidget.refresh(true);
|
|
67302
|
+
}
|
|
67303
|
+
}
|
|
67304
|
+
/**
|
|
67305
|
+
* Public method to refresh distribution chart data
|
|
67306
|
+
*/
|
|
67307
|
+
async refreshDistributionChart() {
|
|
67308
|
+
if (this.distributionWidget) {
|
|
67309
|
+
await this.distributionWidget.refresh();
|
|
67310
|
+
}
|
|
67311
|
+
}
|
|
67312
|
+
/**
|
|
67313
|
+
* Public method to set ideal range on consumption chart
|
|
67314
|
+
*/
|
|
67315
|
+
setIdealRange(range) {
|
|
67316
|
+
if (this.consumptionWidget) {
|
|
67317
|
+
this.consumptionWidget.setIdealRange(range ? {
|
|
67318
|
+
min: range.min,
|
|
67319
|
+
max: range.max,
|
|
67320
|
+
label: range.label,
|
|
67321
|
+
enabled: true
|
|
67322
|
+
} : null);
|
|
67323
|
+
}
|
|
67324
|
+
}
|
|
67325
|
+
destroy() {
|
|
67326
|
+
if (this.consumptionWidget) {
|
|
67327
|
+
this.consumptionWidget.destroy();
|
|
67328
|
+
this.consumptionWidget = null;
|
|
67329
|
+
}
|
|
67330
|
+
if (this.distributionWidget) {
|
|
67331
|
+
this.distributionWidget.destroy();
|
|
67332
|
+
this.distributionWidget = null;
|
|
67333
|
+
}
|
|
67334
|
+
this.root?.remove();
|
|
67335
|
+
this.root = null;
|
|
67336
|
+
}
|
|
67337
|
+
};
|
|
67338
|
+
|
|
67339
|
+
// src/components/energy-panel/createEnergyPanelComponent.ts
|
|
67340
|
+
function createEnergyPanelComponent(params) {
|
|
67341
|
+
if (!params.container) {
|
|
67342
|
+
throw new Error("[EnergyPanel] container is required");
|
|
67343
|
+
}
|
|
67344
|
+
const controller = new EnergyPanelController(params);
|
|
67345
|
+
const view = new EnergyPanelView(params, controller);
|
|
67346
|
+
const element = view.render();
|
|
67347
|
+
params.container.appendChild(element);
|
|
67348
|
+
return {
|
|
67349
|
+
element,
|
|
67350
|
+
updateSummary: (data) => controller.updateSummary(data),
|
|
67351
|
+
getSummary: () => controller.getSummary(),
|
|
67352
|
+
setTheme: (mode) => controller.setTheme(mode),
|
|
67353
|
+
getTheme: () => controller.getState().theme,
|
|
67354
|
+
setPeriod: (days) => controller.setPeriod(days),
|
|
67355
|
+
getPeriod: () => controller.getState().period,
|
|
67356
|
+
setVizMode: (mode) => controller.setVizMode(mode),
|
|
67357
|
+
getVizMode: () => controller.getState().vizMode,
|
|
67358
|
+
setChartType: (type) => controller.setChartType(type),
|
|
67359
|
+
getChartType: () => controller.getState().chartType,
|
|
67360
|
+
applyShoppingFilter: (ids) => controller.applyShoppingFilter(ids),
|
|
67361
|
+
getSelectedShoppingIds: () => [...controller.getState().selectedShoppingIds],
|
|
67362
|
+
clearFilters: () => controller.clearFilters(),
|
|
67363
|
+
refresh: () => {
|
|
67364
|
+
params.onRefresh?.();
|
|
67365
|
+
},
|
|
67366
|
+
openFullscreen: () => {
|
|
67367
|
+
params.onMaximizeClick?.();
|
|
67368
|
+
},
|
|
67369
|
+
destroy: () => view.destroy()
|
|
67370
|
+
};
|
|
67371
|
+
}
|
|
67372
|
+
|
|
67373
|
+
// src/components/water-panel/WaterPanelController.ts
|
|
67374
|
+
var WaterPanelController = class {
|
|
67375
|
+
state;
|
|
67376
|
+
params;
|
|
67377
|
+
onStateChange = null;
|
|
67378
|
+
constructor(params) {
|
|
67379
|
+
this.params = params;
|
|
67380
|
+
this.state = {
|
|
67381
|
+
theme: params.theme || "light",
|
|
67382
|
+
period: params.period || 7,
|
|
67383
|
+
vizMode: params.vizMode || "total",
|
|
67384
|
+
chartType: params.chartType || "line",
|
|
67385
|
+
selectedShoppingIds: params.selectedShoppingIds || [],
|
|
67386
|
+
summary: params.initialSummary || null,
|
|
67387
|
+
isLoading: false,
|
|
67388
|
+
error: null
|
|
67389
|
+
};
|
|
67390
|
+
}
|
|
67391
|
+
// Observer pattern
|
|
67392
|
+
setOnStateChange(callback) {
|
|
67393
|
+
this.onStateChange = callback;
|
|
67394
|
+
}
|
|
67395
|
+
notifyStateChange() {
|
|
67396
|
+
if (this.onStateChange) {
|
|
67397
|
+
this.onStateChange({ ...this.state });
|
|
67398
|
+
}
|
|
67399
|
+
}
|
|
67400
|
+
// Getters
|
|
67401
|
+
getState() {
|
|
67402
|
+
return { ...this.state };
|
|
67403
|
+
}
|
|
67404
|
+
getSummary() {
|
|
67405
|
+
return this.state.summary ? { ...this.state.summary } : null;
|
|
67406
|
+
}
|
|
67407
|
+
// Data updates
|
|
67408
|
+
updateSummary(data) {
|
|
67409
|
+
const total = data.total || data.storesTotal + data.commonAreaTotal;
|
|
67410
|
+
const storesPercentage = total > 0 ? data.storesTotal / total * 100 : 0;
|
|
67411
|
+
const commonAreaPercentage = total > 0 ? data.commonAreaTotal / total * 100 : 0;
|
|
67412
|
+
this.state.summary = {
|
|
67413
|
+
...data,
|
|
67414
|
+
total,
|
|
67415
|
+
storesPercentage: data.storesPercentage ?? storesPercentage,
|
|
67416
|
+
commonAreaPercentage: data.commonAreaPercentage ?? commonAreaPercentage
|
|
67417
|
+
};
|
|
67418
|
+
this.notifyStateChange();
|
|
67419
|
+
}
|
|
67420
|
+
// Config updates
|
|
67421
|
+
setTheme(mode) {
|
|
67422
|
+
if (this.state.theme !== mode) {
|
|
67423
|
+
this.state.theme = mode;
|
|
67424
|
+
this.notifyStateChange();
|
|
67425
|
+
}
|
|
67426
|
+
}
|
|
67427
|
+
setPeriod(days) {
|
|
67428
|
+
if (this.state.period !== days) {
|
|
67429
|
+
this.state.period = days;
|
|
67430
|
+
this.params.onPeriodChange?.(days);
|
|
67431
|
+
this.notifyStateChange();
|
|
67432
|
+
}
|
|
67433
|
+
}
|
|
67434
|
+
setVizMode(mode) {
|
|
67435
|
+
if (this.state.vizMode !== mode) {
|
|
67436
|
+
this.state.vizMode = mode;
|
|
67437
|
+
this.params.onVizModeChange?.(mode);
|
|
67438
|
+
this.notifyStateChange();
|
|
67439
|
+
}
|
|
67440
|
+
}
|
|
67441
|
+
setChartType(type) {
|
|
67442
|
+
if (this.state.chartType !== type) {
|
|
67443
|
+
this.state.chartType = type;
|
|
67444
|
+
this.notifyStateChange();
|
|
67445
|
+
}
|
|
67446
|
+
}
|
|
67447
|
+
// Filter updates
|
|
67448
|
+
applyShoppingFilter(ids) {
|
|
67449
|
+
this.state.selectedShoppingIds = [...ids];
|
|
67450
|
+
this.params.onFilterChange?.(ids);
|
|
67451
|
+
this.notifyStateChange();
|
|
67452
|
+
}
|
|
67453
|
+
clearFilters() {
|
|
67454
|
+
this.state.selectedShoppingIds = [];
|
|
67455
|
+
this.params.onFilterChange?.([]);
|
|
67456
|
+
this.notifyStateChange();
|
|
67457
|
+
}
|
|
67458
|
+
// Loading state
|
|
67459
|
+
setLoading(loading) {
|
|
67460
|
+
this.state.isLoading = loading;
|
|
67461
|
+
this.notifyStateChange();
|
|
67462
|
+
}
|
|
67463
|
+
setError(error) {
|
|
67464
|
+
this.state.error = error;
|
|
67465
|
+
this.notifyStateChange();
|
|
67466
|
+
}
|
|
67467
|
+
};
|
|
67468
|
+
|
|
67469
|
+
// src/components/water-panel/styles.ts
|
|
67470
|
+
var WATER_PANEL_STYLES = `
|
|
67471
|
+
.water-panel-wrap {
|
|
67472
|
+
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
67473
|
+
color: #1e293b;
|
|
67474
|
+
background-color: #f8fafc;
|
|
67475
|
+
padding: 16px;
|
|
67476
|
+
border-radius: 12px;
|
|
67477
|
+
}
|
|
67478
|
+
|
|
67479
|
+
.water-panel-wrap[data-theme="dark"] {
|
|
67480
|
+
color: #e2e8f0;
|
|
67481
|
+
background-color: #1e293b;
|
|
67482
|
+
}
|
|
67483
|
+
|
|
67484
|
+
.water-panel__cards {
|
|
67485
|
+
display: grid;
|
|
67486
|
+
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
|
|
67487
|
+
gap: 16px;
|
|
67488
|
+
margin-bottom: 20px;
|
|
67489
|
+
}
|
|
67490
|
+
|
|
67491
|
+
.water-panel__card {
|
|
67492
|
+
background-color: #ffffff;
|
|
67493
|
+
padding: 16px;
|
|
67494
|
+
border-radius: 12px;
|
|
67495
|
+
display: flex;
|
|
67496
|
+
align-items: center;
|
|
67497
|
+
border: 1px solid #e2e8f0;
|
|
67498
|
+
transition: box-shadow 0.2s ease;
|
|
67499
|
+
}
|
|
67500
|
+
|
|
67501
|
+
.water-panel__card:hover {
|
|
67502
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
|
|
67503
|
+
}
|
|
67504
|
+
|
|
67505
|
+
.water-panel-wrap[data-theme="dark"] .water-panel__card {
|
|
67506
|
+
background-color: #334155;
|
|
67507
|
+
border-color: #475569;
|
|
67508
|
+
}
|
|
67509
|
+
|
|
67510
|
+
.water-panel__card--total {
|
|
67511
|
+
border-left: 4px solid #0288d1;
|
|
67512
|
+
}
|
|
67513
|
+
|
|
67514
|
+
.water-panel__card-icon {
|
|
67515
|
+
font-size: 2.5em;
|
|
67516
|
+
margin-right: 16px;
|
|
67517
|
+
}
|
|
67518
|
+
|
|
67519
|
+
.water-panel__card-content {
|
|
67520
|
+
flex: 1;
|
|
67521
|
+
}
|
|
67522
|
+
|
|
67523
|
+
.water-panel__card-label {
|
|
67524
|
+
font-size: 13px;
|
|
67525
|
+
color: #64748b;
|
|
67526
|
+
font-weight: 500;
|
|
67527
|
+
}
|
|
67528
|
+
|
|
67529
|
+
.water-panel-wrap[data-theme="dark"] .water-panel__card-label {
|
|
67530
|
+
color: #94a3b8;
|
|
67531
|
+
}
|
|
67532
|
+
|
|
67533
|
+
.water-panel__card-value {
|
|
67534
|
+
font-size: 1.6em;
|
|
67535
|
+
font-weight: 700;
|
|
67536
|
+
color: #0288d1;
|
|
67537
|
+
}
|
|
67538
|
+
|
|
67539
|
+
.water-panel-wrap[data-theme="dark"] .water-panel__card-value {
|
|
67540
|
+
color: #38bdf8;
|
|
67541
|
+
}
|
|
67542
|
+
|
|
67543
|
+
.water-panel__card-trend {
|
|
67544
|
+
font-size: 12px;
|
|
67545
|
+
color: #64748b;
|
|
67546
|
+
margin-top: 2px;
|
|
67547
|
+
}
|
|
67548
|
+
|
|
67549
|
+
.water-panel-wrap[data-theme="dark"] .water-panel__card-trend {
|
|
67550
|
+
color: #94a3b8;
|
|
67551
|
+
}
|
|
67552
|
+
|
|
67553
|
+
.water-panel__card-count {
|
|
67554
|
+
font-size: 12px;
|
|
67555
|
+
color: #94a3b8;
|
|
67556
|
+
margin-top: 4px;
|
|
67557
|
+
}
|
|
67558
|
+
|
|
67559
|
+
.water-panel-wrap[data-theme="dark"] .water-panel__card-count {
|
|
67560
|
+
color: #64748b;
|
|
67561
|
+
}
|
|
67562
|
+
|
|
67563
|
+
.water-panel__chart-section {
|
|
67564
|
+
background-color: #ffffff;
|
|
67565
|
+
padding: 16px;
|
|
67566
|
+
border-radius: 12px;
|
|
67567
|
+
border: 1px solid #e2e8f0;
|
|
67568
|
+
margin-bottom: 20px;
|
|
67569
|
+
}
|
|
67570
|
+
|
|
67571
|
+
.water-panel-wrap[data-theme="dark"] .water-panel__chart-section {
|
|
67572
|
+
background-color: #334155;
|
|
67573
|
+
border-color: #475569;
|
|
67574
|
+
}
|
|
67575
|
+
|
|
67576
|
+
.water-panel__chart-header {
|
|
67577
|
+
display: flex;
|
|
67578
|
+
justify-content: space-between;
|
|
67579
|
+
align-items: center;
|
|
67580
|
+
flex-wrap: wrap;
|
|
67581
|
+
gap: 12px;
|
|
67582
|
+
margin-bottom: 16px;
|
|
67583
|
+
padding-bottom: 12px;
|
|
67584
|
+
border-bottom: 1px solid #e2e8f0;
|
|
67585
|
+
}
|
|
67586
|
+
|
|
67587
|
+
.water-panel-wrap[data-theme="dark"] .water-panel__chart-header {
|
|
67588
|
+
border-bottom-color: #475569;
|
|
67589
|
+
}
|
|
67590
|
+
|
|
67591
|
+
.water-panel__chart-title-group {
|
|
67592
|
+
display: flex;
|
|
67593
|
+
align-items: center;
|
|
67594
|
+
gap: 12px;
|
|
67595
|
+
flex-wrap: wrap;
|
|
67596
|
+
}
|
|
67597
|
+
|
|
67598
|
+
.water-panel__chart-header h3 {
|
|
67599
|
+
margin: 0;
|
|
67600
|
+
font-size: 15px;
|
|
67601
|
+
font-weight: 600;
|
|
67602
|
+
color: #1e293b;
|
|
67603
|
+
}
|
|
67604
|
+
|
|
67605
|
+
.water-panel-wrap[data-theme="dark"] .water-panel__chart-header h3 {
|
|
67606
|
+
color: #f1f5f9;
|
|
67607
|
+
}
|
|
67608
|
+
|
|
67609
|
+
/* Tab styles */
|
|
67610
|
+
.water-panel__chart-tabs {
|
|
67611
|
+
display: flex;
|
|
67612
|
+
gap: 2px;
|
|
67613
|
+
background: #f1f5f9;
|
|
67614
|
+
padding: 3px;
|
|
67615
|
+
border-radius: 8px;
|
|
67616
|
+
}
|
|
67617
|
+
|
|
67618
|
+
.water-panel-wrap[data-theme="dark"] .water-panel__chart-tabs {
|
|
67619
|
+
background: #1e293b;
|
|
67620
|
+
}
|
|
67621
|
+
|
|
67622
|
+
.water-panel__tab {
|
|
67623
|
+
display: flex;
|
|
67624
|
+
align-items: center;
|
|
67625
|
+
justify-content: center;
|
|
67626
|
+
padding: 6px 10px;
|
|
67627
|
+
border: none;
|
|
67628
|
+
background: transparent;
|
|
67629
|
+
color: #64748b;
|
|
67630
|
+
cursor: pointer;
|
|
67631
|
+
border-radius: 6px;
|
|
67632
|
+
transition: all 0.2s ease;
|
|
67633
|
+
font-size: 12px;
|
|
67634
|
+
font-weight: 500;
|
|
67635
|
+
}
|
|
67636
|
+
|
|
67637
|
+
.water-panel__tab:hover {
|
|
67638
|
+
color: #1e293b;
|
|
67639
|
+
background: rgba(0, 0, 0, 0.05);
|
|
67640
|
+
}
|
|
67641
|
+
|
|
67642
|
+
.water-panel-wrap[data-theme="dark"] .water-panel__tab:hover {
|
|
67643
|
+
color: #e2e8f0;
|
|
67644
|
+
background: rgba(255, 255, 255, 0.1);
|
|
67645
|
+
}
|
|
67646
|
+
|
|
67647
|
+
.water-panel__tab.active {
|
|
67648
|
+
background: #0288d1;
|
|
67649
|
+
color: white;
|
|
67650
|
+
box-shadow: 0 1px 3px rgba(2, 136, 209, 0.3);
|
|
67651
|
+
}
|
|
67652
|
+
|
|
67653
|
+
.water-panel__tab svg {
|
|
67654
|
+
width: 14px;
|
|
67655
|
+
height: 14px;
|
|
67656
|
+
}
|
|
67657
|
+
|
|
67658
|
+
/* Controls */
|
|
67659
|
+
.water-panel__chart-controls {
|
|
67660
|
+
display: flex;
|
|
67661
|
+
align-items: center;
|
|
67662
|
+
gap: 8px;
|
|
67663
|
+
}
|
|
67664
|
+
|
|
67665
|
+
.water-panel__chart-controls select {
|
|
67666
|
+
padding: 6px 12px;
|
|
67667
|
+
border-radius: 6px;
|
|
67668
|
+
border: 1px solid #e2e8f0;
|
|
67669
|
+
background-color: #ffffff;
|
|
67670
|
+
color: #1e293b;
|
|
67671
|
+
font-size: 12px;
|
|
67672
|
+
font-weight: 500;
|
|
67673
|
+
cursor: pointer;
|
|
67674
|
+
min-width: 180px;
|
|
67675
|
+
}
|
|
67676
|
+
|
|
67677
|
+
.water-panel__chart-controls select:focus {
|
|
67678
|
+
outline: none;
|
|
67679
|
+
border-color: #0288d1;
|
|
67680
|
+
}
|
|
67681
|
+
|
|
67682
|
+
.water-panel-wrap[data-theme="dark"] .water-panel__chart-controls select {
|
|
67683
|
+
background-color: #1e293b;
|
|
67684
|
+
border-color: #475569;
|
|
67685
|
+
color: #e2e8f0;
|
|
67686
|
+
}
|
|
67687
|
+
|
|
67688
|
+
.water-panel__period-select {
|
|
67689
|
+
min-width: 100px !important;
|
|
67690
|
+
}
|
|
67691
|
+
|
|
67692
|
+
.water-panel__distribution-mode {
|
|
67693
|
+
min-width: 200px !important;
|
|
67694
|
+
}
|
|
67695
|
+
|
|
67696
|
+
.water-panel__maximize-btn {
|
|
67697
|
+
display: flex;
|
|
67698
|
+
align-items: center;
|
|
67699
|
+
justify-content: center;
|
|
67700
|
+
width: 32px;
|
|
67701
|
+
height: 32px;
|
|
67702
|
+
padding: 0;
|
|
67703
|
+
border: 1px solid #e2e8f0;
|
|
67704
|
+
border-radius: 6px;
|
|
67705
|
+
background: transparent;
|
|
67706
|
+
color: #64748b;
|
|
67707
|
+
cursor: pointer;
|
|
67708
|
+
font-size: 16px;
|
|
67709
|
+
transition: all 0.2s ease;
|
|
67710
|
+
}
|
|
67711
|
+
|
|
67712
|
+
.water-panel__maximize-btn:hover {
|
|
67713
|
+
background: #0288d1;
|
|
67714
|
+
border-color: #0288d1;
|
|
67715
|
+
color: white;
|
|
67716
|
+
}
|
|
67717
|
+
|
|
67718
|
+
.water-panel-wrap[data-theme="dark"] .water-panel__maximize-btn {
|
|
67719
|
+
border-color: #475569;
|
|
67720
|
+
color: #94a3b8;
|
|
67721
|
+
}
|
|
67722
|
+
|
|
67723
|
+
.water-panel-wrap[data-theme="dark"] .water-panel__maximize-btn:hover {
|
|
67724
|
+
background: #0288d1;
|
|
67725
|
+
border-color: #0288d1;
|
|
67726
|
+
color: white;
|
|
67727
|
+
}
|
|
67728
|
+
|
|
67729
|
+
/* Chart containers */
|
|
67730
|
+
.water-panel__consumption-chart,
|
|
67731
|
+
.water-panel__distribution-chart {
|
|
67732
|
+
min-height: 220px;
|
|
67733
|
+
position: relative;
|
|
67734
|
+
}
|
|
67735
|
+
|
|
67736
|
+
.water-panel__consumption-chart canvas,
|
|
67737
|
+
.water-panel__distribution-chart canvas {
|
|
67738
|
+
width: 100% !important;
|
|
67739
|
+
}
|
|
67740
|
+
|
|
67741
|
+
/* Responsive */
|
|
67742
|
+
@media (max-width: 768px) {
|
|
67743
|
+
.water-panel__chart-header {
|
|
67744
|
+
flex-direction: column;
|
|
67745
|
+
align-items: flex-start;
|
|
67746
|
+
}
|
|
67747
|
+
|
|
67748
|
+
.water-panel__chart-title-group {
|
|
67749
|
+
width: 100%;
|
|
67750
|
+
flex-wrap: wrap;
|
|
67751
|
+
}
|
|
67752
|
+
|
|
67753
|
+
.water-panel__chart-controls {
|
|
67754
|
+
width: 100%;
|
|
67755
|
+
justify-content: flex-start;
|
|
67756
|
+
}
|
|
67757
|
+
|
|
67758
|
+
.water-panel__distribution-mode {
|
|
67759
|
+
flex: 1;
|
|
67760
|
+
}
|
|
67761
|
+
}
|
|
67762
|
+
`;
|
|
67763
|
+
function injectWaterPanelStyles() {
|
|
67764
|
+
if (typeof document === "undefined") return;
|
|
67765
|
+
const id = "myio-water-panel-styles";
|
|
67766
|
+
if (document.getElementById(id)) return;
|
|
67767
|
+
const style = document.createElement("style");
|
|
67768
|
+
style.id = id;
|
|
67769
|
+
style.textContent = WATER_PANEL_STYLES;
|
|
67770
|
+
document.head.appendChild(style);
|
|
67771
|
+
}
|
|
67772
|
+
|
|
67773
|
+
// src/components/water-panel/WaterPanelView.ts
|
|
67774
|
+
var WaterPanelView = class {
|
|
67775
|
+
params;
|
|
67776
|
+
controller;
|
|
67777
|
+
root = null;
|
|
67778
|
+
// Chart widget instances (using existing reusable components)
|
|
67779
|
+
consumptionWidget = null;
|
|
67780
|
+
distributionWidget = null;
|
|
67781
|
+
// Unique IDs for this panel instance
|
|
67782
|
+
panelId;
|
|
67783
|
+
constructor(params, controller) {
|
|
67784
|
+
this.params = params;
|
|
67785
|
+
this.controller = controller;
|
|
67786
|
+
this.panelId = `water-panel-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
67787
|
+
this.controller.setOnStateChange((state6) => this.onStateChange(state6));
|
|
67788
|
+
}
|
|
67789
|
+
render() {
|
|
67790
|
+
injectWaterPanelStyles();
|
|
67791
|
+
const state6 = this.controller.getState();
|
|
67792
|
+
this.root = document.createElement("div");
|
|
67793
|
+
this.root.className = "water-panel-wrap";
|
|
67794
|
+
this.root.setAttribute("data-theme", state6.theme);
|
|
67795
|
+
this.root.setAttribute("data-domain", "water");
|
|
67796
|
+
this.root.innerHTML = this.buildHTML(state6);
|
|
67797
|
+
this.bindEvents();
|
|
67798
|
+
setTimeout(() => this.initializeCharts(), 0);
|
|
67799
|
+
return this.root;
|
|
67800
|
+
}
|
|
67801
|
+
buildHTML(state6) {
|
|
67802
|
+
const { showCards = true, showConsumptionChart = true, showDistributionChart = true } = this.params;
|
|
67803
|
+
return `
|
|
67804
|
+
<div class="water-panel">
|
|
67805
|
+
${showCards ? this.buildCardsHTML(state6) : ""}
|
|
67806
|
+
${showConsumptionChart ? this.buildConsumptionChartContainerHTML() : ""}
|
|
67807
|
+
${showDistributionChart ? this.buildDistributionChartContainerHTML() : ""}
|
|
67808
|
+
</div>
|
|
67809
|
+
`;
|
|
67810
|
+
}
|
|
67811
|
+
buildCardsHTML(state6) {
|
|
67812
|
+
const summary = state6.summary;
|
|
67813
|
+
const storesValue = summary?.storesTotal ?? 0;
|
|
67814
|
+
const commonAreaValue = summary?.commonAreaTotal ?? 0;
|
|
67815
|
+
const totalValue = summary?.total ?? 0;
|
|
67816
|
+
const storesPercent = summary?.storesPercentage ?? 0;
|
|
67817
|
+
const commonAreaPercent = summary?.commonAreaPercentage ?? 0;
|
|
67818
|
+
return `
|
|
67819
|
+
<div class="water-panel__cards">
|
|
67820
|
+
<div class="water-panel__card" data-type="stores">
|
|
67821
|
+
<div class="water-panel__card-icon">💧</div>
|
|
67822
|
+
<div class="water-panel__card-content">
|
|
67823
|
+
<div class="water-panel__card-label">Consumo Lojas</div>
|
|
67824
|
+
<div class="water-panel__card-value">${this.formatWater(storesValue)}</div>
|
|
67825
|
+
<div class="water-panel__card-trend">${storesPercent.toFixed(1)}% do total</div>
|
|
67826
|
+
<div class="water-panel__card-count">${summary?.deviceCount || 0} hidrometros</div>
|
|
67827
|
+
</div>
|
|
67828
|
+
</div>
|
|
67829
|
+
<div class="water-panel__card" data-type="common-area">
|
|
67830
|
+
<div class="water-panel__card-icon">🚿</div>
|
|
67831
|
+
<div class="water-panel__card-content">
|
|
67832
|
+
<div class="water-panel__card-label">Consumo Area Comum</div>
|
|
67833
|
+
<div class="water-panel__card-value">${this.formatWater(commonAreaValue)}</div>
|
|
67834
|
+
<div class="water-panel__card-trend">${commonAreaPercent.toFixed(1)}% do total</div>
|
|
67835
|
+
<div class="water-panel__card-count">Banheiros, limpeza, etc.</div>
|
|
67836
|
+
</div>
|
|
67837
|
+
</div>
|
|
67838
|
+
<div class="water-panel__card water-panel__card--total" data-type="total">
|
|
67839
|
+
<div class="water-panel__card-icon">📊</div>
|
|
67840
|
+
<div class="water-panel__card-content">
|
|
67841
|
+
<div class="water-panel__card-label">Consumo Total</div>
|
|
67842
|
+
<div class="water-panel__card-value">${this.formatWater(totalValue)}</div>
|
|
67843
|
+
<div class="water-panel__card-trend">Lojas + Area Comum</div>
|
|
67844
|
+
<div class="water-panel__card-count">${summary?.deviceCount || 0} dispositivos</div>
|
|
67845
|
+
</div>
|
|
67846
|
+
</div>
|
|
67847
|
+
</div>
|
|
67848
|
+
`;
|
|
67849
|
+
}
|
|
67850
|
+
/**
|
|
67851
|
+
* Container for consumption chart widget (RFC-0098)
|
|
67852
|
+
* The createConsumptionChartWidget will inject its own HTML structure
|
|
67853
|
+
*/
|
|
67854
|
+
buildConsumptionChartContainerHTML() {
|
|
67855
|
+
return `
|
|
67856
|
+
<div class="water-panel__chart-section">
|
|
67857
|
+
<div id="${this.panelId}-consumption-chart" class="water-panel__consumption-chart"></div>
|
|
67858
|
+
</div>
|
|
67859
|
+
`;
|
|
67860
|
+
}
|
|
67861
|
+
/**
|
|
67862
|
+
* Container for distribution chart widget (RFC-0102)
|
|
67863
|
+
* The createDistributionChartWidget will inject its own HTML structure
|
|
67864
|
+
*/
|
|
67865
|
+
buildDistributionChartContainerHTML() {
|
|
67866
|
+
return `
|
|
67867
|
+
<div class="water-panel__chart-section">
|
|
67868
|
+
<div id="${this.panelId}-distribution-chart" class="water-panel__distribution-chart"></div>
|
|
67869
|
+
</div>
|
|
67870
|
+
`;
|
|
67871
|
+
}
|
|
67872
|
+
formatWater(value) {
|
|
67873
|
+
if (value >= 1e3) {
|
|
67874
|
+
return `${(value / 1e3).toFixed(2)} k m3`;
|
|
67875
|
+
}
|
|
67876
|
+
return `${value.toFixed(1)} m3`;
|
|
67877
|
+
}
|
|
67878
|
+
bindEvents() {
|
|
67879
|
+
}
|
|
67880
|
+
/**
|
|
67881
|
+
* Initialize chart widgets using the existing reusable components
|
|
67882
|
+
*/
|
|
67883
|
+
async initializeCharts() {
|
|
67884
|
+
if (!this.root) return;
|
|
67885
|
+
const state6 = this.controller.getState();
|
|
67886
|
+
const { showConsumptionChart = true, showDistributionChart = true } = this.params;
|
|
67887
|
+
if (showConsumptionChart) {
|
|
67888
|
+
await this.initializeConsumptionWidget(state6);
|
|
67889
|
+
}
|
|
67890
|
+
if (showDistributionChart) {
|
|
67891
|
+
await this.initializeDistributionWidget(state6);
|
|
67892
|
+
}
|
|
67893
|
+
}
|
|
67894
|
+
/**
|
|
67895
|
+
* Initialize the consumption chart using createConsumptionChartWidget
|
|
67896
|
+
* This provides: settings modal, ideal range, viz modes, chart types
|
|
67897
|
+
*/
|
|
67898
|
+
async initializeConsumptionWidget(state6) {
|
|
67899
|
+
const containerId = `${this.panelId}-consumption-chart`;
|
|
67900
|
+
const container = this.root?.querySelector(`#${containerId}`);
|
|
67901
|
+
if (!container) {
|
|
67902
|
+
console.warn("[WaterPanel] Consumption chart container not found");
|
|
67903
|
+
return;
|
|
67904
|
+
}
|
|
67905
|
+
try {
|
|
67906
|
+
this.consumptionWidget = createConsumptionChartWidget({
|
|
67907
|
+
domain: "water",
|
|
67908
|
+
containerId,
|
|
67909
|
+
title: "Consumo de Agua",
|
|
67910
|
+
unit: "m3",
|
|
67911
|
+
unitLarge: "k m3",
|
|
67912
|
+
thresholdForLargeUnit: 1e3,
|
|
67913
|
+
theme: state6.theme,
|
|
67914
|
+
defaultPeriod: state6.period,
|
|
67915
|
+
defaultChartType: "line",
|
|
67916
|
+
defaultVizMode: "total",
|
|
67917
|
+
// Settings modal options
|
|
67918
|
+
showSettingsButton: true,
|
|
67919
|
+
showMaximizeButton: true,
|
|
67920
|
+
showVizModeTabs: true,
|
|
67921
|
+
showChartTypeTabs: true,
|
|
67922
|
+
chartHeight: 280,
|
|
67923
|
+
// Data fetching - use params callback or mock data
|
|
67924
|
+
fetchData: this.params.fetchConsumptionData || this.createMockFetchData(),
|
|
67925
|
+
// Callbacks
|
|
67926
|
+
onMaximizeClick: () => {
|
|
67927
|
+
this.params.onMaximizeClick?.();
|
|
67928
|
+
},
|
|
67929
|
+
onSettingsClick: () => {
|
|
67930
|
+
console.log("[WaterPanel] Settings clicked");
|
|
67931
|
+
},
|
|
67932
|
+
onDataLoaded: (data) => {
|
|
67933
|
+
console.log("[WaterPanel] Consumption data loaded:", data.labels?.length, "days");
|
|
67934
|
+
},
|
|
67935
|
+
onError: (error) => {
|
|
67936
|
+
console.error("[WaterPanel] Consumption chart error:", error);
|
|
67937
|
+
},
|
|
67938
|
+
// Ideal range (from customer settings or orchestrator)
|
|
67939
|
+
idealRange: this.params.idealRange || void 0,
|
|
67940
|
+
// ThingsBoard container reference
|
|
67941
|
+
$container: this.params.$container
|
|
67942
|
+
});
|
|
67943
|
+
await this.consumptionWidget.render();
|
|
67944
|
+
console.log("[WaterPanel] Consumption widget initialized");
|
|
67945
|
+
} catch (error) {
|
|
67946
|
+
console.error("[WaterPanel] Failed to initialize consumption widget:", error);
|
|
67947
|
+
}
|
|
67948
|
+
}
|
|
67949
|
+
/**
|
|
67950
|
+
* Initialize the distribution chart using createDistributionChartWidget
|
|
67951
|
+
* This provides: mode selector, horizontal bars, shopping colors
|
|
67952
|
+
*/
|
|
67953
|
+
async initializeDistributionWidget(state6) {
|
|
67954
|
+
const containerId = `${this.panelId}-distribution-chart`;
|
|
67955
|
+
const container = this.root?.querySelector(`#${containerId}`);
|
|
67956
|
+
if (!container) {
|
|
67957
|
+
console.warn("[WaterPanel] Distribution chart container not found");
|
|
67958
|
+
return;
|
|
67959
|
+
}
|
|
67960
|
+
try {
|
|
67961
|
+
this.distributionWidget = createDistributionChartWidget({
|
|
67962
|
+
domain: "water",
|
|
67963
|
+
containerId,
|
|
67964
|
+
title: "Distribuicao de Consumo",
|
|
67965
|
+
unit: "m3",
|
|
67966
|
+
unitLarge: "k m3",
|
|
67967
|
+
thresholdForLargeUnit: 1e3,
|
|
67968
|
+
theme: state6.theme,
|
|
67969
|
+
chartHeight: 300,
|
|
67970
|
+
showHeader: true,
|
|
67971
|
+
showModeSelector: true,
|
|
67972
|
+
showSettingsButton: false,
|
|
67973
|
+
showMaximizeButton: false,
|
|
67974
|
+
defaultMode: "groups",
|
|
67975
|
+
// Water-specific modes
|
|
67976
|
+
modes: [
|
|
67977
|
+
{ value: "groups", label: "Lojas vs Area Comum" },
|
|
67978
|
+
{ value: "stores", label: "Lojas por Shopping" },
|
|
67979
|
+
{ value: "common", label: "Area Comum por Shopping" }
|
|
67980
|
+
],
|
|
67981
|
+
// Data fetching
|
|
67982
|
+
fetchDistribution: this.params.fetchDistributionData || this.createMockFetchDistribution(),
|
|
67983
|
+
// Callbacks
|
|
67984
|
+
onModeChange: (mode) => {
|
|
67985
|
+
console.log("[WaterPanel] Distribution mode changed:", mode);
|
|
67986
|
+
},
|
|
67987
|
+
onDataLoaded: (data) => {
|
|
67988
|
+
console.log("[WaterPanel] Distribution data loaded:", Object.keys(data).length, "categories");
|
|
67989
|
+
},
|
|
67990
|
+
onError: (error) => {
|
|
67991
|
+
console.error("[WaterPanel] Distribution chart error:", error);
|
|
67992
|
+
},
|
|
67993
|
+
// Get shopping colors from orchestrator
|
|
67994
|
+
getShoppingColors: () => {
|
|
67995
|
+
return window.MyIOOrchestrator?.getShoppingColors?.() || null;
|
|
67996
|
+
}
|
|
67997
|
+
});
|
|
67998
|
+
await this.distributionWidget.render();
|
|
67999
|
+
console.log("[WaterPanel] Distribution widget initialized");
|
|
68000
|
+
} catch (error) {
|
|
68001
|
+
console.error("[WaterPanel] Failed to initialize distribution widget:", error);
|
|
68002
|
+
}
|
|
68003
|
+
}
|
|
68004
|
+
/**
|
|
68005
|
+
* Create mock data fetcher for showcase/demo purposes
|
|
68006
|
+
*/
|
|
68007
|
+
createMockFetchData() {
|
|
68008
|
+
return async (period) => {
|
|
68009
|
+
const labels = [];
|
|
68010
|
+
const dailyTotals = [];
|
|
68011
|
+
const today = /* @__PURE__ */ new Date();
|
|
68012
|
+
for (let i = period - 1; i >= 0; i--) {
|
|
68013
|
+
const date = new Date(today);
|
|
68014
|
+
date.setDate(date.getDate() - i);
|
|
68015
|
+
labels.push(date.toLocaleDateString("pt-BR", { day: "2-digit", month: "2-digit" }));
|
|
68016
|
+
const baseValue = 50 + Math.random() * 50;
|
|
68017
|
+
const variation = (Math.random() - 0.5) * 20;
|
|
68018
|
+
dailyTotals.push(Math.max(10, baseValue + variation));
|
|
68019
|
+
}
|
|
68020
|
+
const shoppingData = {
|
|
68021
|
+
"shopping-1": dailyTotals.map((v) => v * 0.35),
|
|
68022
|
+
"shopping-2": dailyTotals.map((v) => v * 0.25),
|
|
68023
|
+
"shopping-3": dailyTotals.map((v) => v * 0.25),
|
|
68024
|
+
"shopping-4": dailyTotals.map((v) => v * 0.15)
|
|
68025
|
+
};
|
|
68026
|
+
const shoppingNames = {
|
|
68027
|
+
"shopping-1": "Shopping Aricanduva",
|
|
68028
|
+
"shopping-2": "Shopping Interlagos",
|
|
68029
|
+
"shopping-3": "Shopping Tucuruvi",
|
|
68030
|
+
"shopping-4": "Shopping Penha"
|
|
68031
|
+
};
|
|
68032
|
+
return {
|
|
68033
|
+
labels,
|
|
68034
|
+
dailyTotals,
|
|
68035
|
+
shoppingData,
|
|
68036
|
+
shoppingNames,
|
|
68037
|
+
fetchTimestamp: Date.now()
|
|
68038
|
+
};
|
|
68039
|
+
};
|
|
68040
|
+
}
|
|
68041
|
+
/**
|
|
68042
|
+
* Create mock distribution data fetcher for showcase/demo purposes
|
|
68043
|
+
*/
|
|
68044
|
+
createMockFetchDistribution() {
|
|
68045
|
+
const state6 = this.controller.getState();
|
|
68046
|
+
const summary = state6.summary;
|
|
68047
|
+
return async (mode) => {
|
|
68048
|
+
if (mode === "groups") {
|
|
68049
|
+
const storesTotal = summary?.storesTotal || 850;
|
|
68050
|
+
const commonAreaTotal = summary?.commonAreaTotal || 650;
|
|
68051
|
+
return {
|
|
68052
|
+
"Lojas": storesTotal,
|
|
68053
|
+
"Area Comum": commonAreaTotal
|
|
68054
|
+
};
|
|
68055
|
+
}
|
|
68056
|
+
if (mode === "stores") {
|
|
68057
|
+
return {
|
|
68058
|
+
"Shopping Aricanduva": 180,
|
|
68059
|
+
"Shopping Interlagos": 150,
|
|
68060
|
+
"Shopping Tucuruvi": 140,
|
|
68061
|
+
"Shopping Penha": 120,
|
|
68062
|
+
"Shopping Tatuape": 110,
|
|
68063
|
+
"Shopping Santana": 100
|
|
68064
|
+
};
|
|
68065
|
+
}
|
|
68066
|
+
if (mode === "common") {
|
|
68067
|
+
return {
|
|
68068
|
+
"Shopping Aricanduva": 150,
|
|
68069
|
+
"Shopping Interlagos": 130,
|
|
68070
|
+
"Shopping Tucuruvi": 120,
|
|
68071
|
+
"Shopping Penha": 100,
|
|
68072
|
+
"Shopping Tatuape": 90
|
|
68073
|
+
};
|
|
68074
|
+
}
|
|
68075
|
+
return null;
|
|
68076
|
+
};
|
|
68077
|
+
}
|
|
68078
|
+
onStateChange(state6) {
|
|
68079
|
+
if (!this.root) return;
|
|
68080
|
+
this.root.setAttribute("data-theme", state6.theme);
|
|
68081
|
+
if (this.consumptionWidget) {
|
|
68082
|
+
this.consumptionWidget.setTheme(state6.theme);
|
|
68083
|
+
}
|
|
68084
|
+
if (this.distributionWidget) {
|
|
68085
|
+
this.distributionWidget.setTheme(state6.theme);
|
|
68086
|
+
}
|
|
68087
|
+
this.updateCards(state6);
|
|
68088
|
+
}
|
|
68089
|
+
updateCards(state6) {
|
|
68090
|
+
const summary = state6.summary;
|
|
68091
|
+
if (!summary || !this.root) return;
|
|
68092
|
+
const storesCard = this.root.querySelector('[data-type="stores"] .water-panel__card-value');
|
|
68093
|
+
const storesTrend = this.root.querySelector('[data-type="stores"] .water-panel__card-trend');
|
|
68094
|
+
if (storesCard) {
|
|
68095
|
+
storesCard.textContent = this.formatWater(summary.storesTotal);
|
|
68096
|
+
}
|
|
68097
|
+
if (storesTrend) {
|
|
68098
|
+
storesTrend.textContent = `${summary.storesPercentage.toFixed(1)}% do total`;
|
|
68099
|
+
}
|
|
68100
|
+
const commonAreaCard = this.root.querySelector('[data-type="common-area"] .water-panel__card-value');
|
|
68101
|
+
const commonAreaTrend = this.root.querySelector('[data-type="common-area"] .water-panel__card-trend');
|
|
68102
|
+
if (commonAreaCard) {
|
|
68103
|
+
commonAreaCard.textContent = this.formatWater(summary.commonAreaTotal);
|
|
68104
|
+
}
|
|
68105
|
+
if (commonAreaTrend) {
|
|
68106
|
+
commonAreaTrend.textContent = `${summary.commonAreaPercentage.toFixed(1)}% do total`;
|
|
68107
|
+
}
|
|
68108
|
+
const totalCard = this.root.querySelector('[data-type="total"] .water-panel__card-value');
|
|
68109
|
+
if (totalCard) {
|
|
68110
|
+
totalCard.textContent = this.formatWater(summary.total);
|
|
68111
|
+
}
|
|
68112
|
+
}
|
|
68113
|
+
/**
|
|
68114
|
+
* Public method to refresh consumption chart data
|
|
68115
|
+
*/
|
|
68116
|
+
async refreshConsumptionChart() {
|
|
68117
|
+
if (this.consumptionWidget) {
|
|
68118
|
+
await this.consumptionWidget.refresh(true);
|
|
68119
|
+
}
|
|
68120
|
+
}
|
|
68121
|
+
/**
|
|
68122
|
+
* Public method to refresh distribution chart data
|
|
68123
|
+
*/
|
|
68124
|
+
async refreshDistributionChart() {
|
|
68125
|
+
if (this.distributionWidget) {
|
|
68126
|
+
await this.distributionWidget.refresh();
|
|
68127
|
+
}
|
|
68128
|
+
}
|
|
68129
|
+
/**
|
|
68130
|
+
* Public method to set ideal range on consumption chart
|
|
68131
|
+
*/
|
|
68132
|
+
setIdealRange(range) {
|
|
68133
|
+
if (this.consumptionWidget) {
|
|
68134
|
+
this.consumptionWidget.setIdealRange(range ? {
|
|
68135
|
+
min: range.min,
|
|
68136
|
+
max: range.max,
|
|
68137
|
+
label: range.label,
|
|
68138
|
+
enabled: true
|
|
68139
|
+
} : null);
|
|
68140
|
+
}
|
|
68141
|
+
}
|
|
68142
|
+
destroy() {
|
|
68143
|
+
if (this.consumptionWidget) {
|
|
68144
|
+
this.consumptionWidget.destroy();
|
|
68145
|
+
this.consumptionWidget = null;
|
|
68146
|
+
}
|
|
68147
|
+
if (this.distributionWidget) {
|
|
68148
|
+
this.distributionWidget.destroy();
|
|
68149
|
+
this.distributionWidget = null;
|
|
68150
|
+
}
|
|
68151
|
+
this.root?.remove();
|
|
68152
|
+
this.root = null;
|
|
68153
|
+
}
|
|
68154
|
+
};
|
|
68155
|
+
|
|
68156
|
+
// src/components/water-panel/createWaterPanelComponent.ts
|
|
68157
|
+
function createWaterPanelComponent(params) {
|
|
68158
|
+
if (!params.container) {
|
|
68159
|
+
throw new Error("[WaterPanel] container is required");
|
|
68160
|
+
}
|
|
68161
|
+
const controller = new WaterPanelController(params);
|
|
68162
|
+
const view = new WaterPanelView(params, controller);
|
|
68163
|
+
const element = view.render();
|
|
68164
|
+
params.container.appendChild(element);
|
|
68165
|
+
return {
|
|
68166
|
+
element,
|
|
68167
|
+
// Data methods
|
|
68168
|
+
updateSummary: (data) => controller.updateSummary(data),
|
|
68169
|
+
getSummary: () => controller.getSummary(),
|
|
68170
|
+
// Config methods
|
|
68171
|
+
setTheme: (mode) => controller.setTheme(mode),
|
|
68172
|
+
getTheme: () => controller.getState().theme,
|
|
68173
|
+
setPeriod: (days) => controller.setPeriod(days),
|
|
68174
|
+
getPeriod: () => controller.getState().period,
|
|
68175
|
+
setVizMode: (mode) => controller.setVizMode(mode),
|
|
68176
|
+
getVizMode: () => controller.getState().vizMode,
|
|
68177
|
+
setChartType: (type) => controller.setChartType(type),
|
|
68178
|
+
getChartType: () => controller.getState().chartType,
|
|
68179
|
+
// Filter methods
|
|
68180
|
+
applyShoppingFilter: (ids) => controller.applyShoppingFilter(ids),
|
|
68181
|
+
getSelectedShoppingIds: () => [...controller.getState().selectedShoppingIds],
|
|
68182
|
+
clearFilters: () => controller.clearFilters(),
|
|
68183
|
+
// Actions
|
|
68184
|
+
refresh: () => {
|
|
68185
|
+
params.onRefresh?.();
|
|
68186
|
+
},
|
|
68187
|
+
openFullscreen: () => {
|
|
68188
|
+
params.onMaximizeClick?.();
|
|
68189
|
+
},
|
|
68190
|
+
// Lifecycle
|
|
68191
|
+
destroy: () => view.destroy()
|
|
68192
|
+
};
|
|
68193
|
+
}
|
|
66581
68194
|
// Annotate the CommonJS export names for ESM import in node:
|
|
66582
68195
|
0 && (module.exports = {
|
|
66583
68196
|
ANNOTATION_TYPE_COLORS,
|
|
@@ -66714,6 +68327,7 @@ function createCustomerCardV1(params) {
|
|
|
66714
68327
|
createDeviceItem,
|
|
66715
68328
|
createDeviceItemsFromMap,
|
|
66716
68329
|
createDistributionChartWidget,
|
|
68330
|
+
createEnergyPanelComponent,
|
|
66717
68331
|
createFilterModalComponent,
|
|
66718
68332
|
createFooterComponent,
|
|
66719
68333
|
createHeaderComponent,
|
|
@@ -66723,6 +68337,7 @@ function createCustomerCardV1(params) {
|
|
|
66723
68337
|
createMenuComponent,
|
|
66724
68338
|
createModalHeader,
|
|
66725
68339
|
createTelemetryGridComponent,
|
|
68340
|
+
createWaterPanelComponent,
|
|
66726
68341
|
decodePayload,
|
|
66727
68342
|
decodePayloadBase64Xor,
|
|
66728
68343
|
detectContext,
|