fix prices reloading
This commit is contained in:
8
db/migration/V066__site_market_config_validity_index.sql
Normal file
8
db/migration/V066__site_market_config_validity_index.sql
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
-- ============================================================
|
||||||
|
-- Site market config: urychlení lookupu platné konfigurace
|
||||||
|
-- (vw_site_effective_price, fn_effective_*_price)
|
||||||
|
-- ============================================================
|
||||||
|
|
||||||
|
create index if not exists idx_site_market_config_site_valid_from
|
||||||
|
on ems.site_market_config (site_id, valid_from desc);
|
||||||
|
|
||||||
@@ -6,6 +6,11 @@ returns jsonb
|
|||||||
language sql
|
language sql
|
||||||
stable
|
stable
|
||||||
as $fn$
|
as $fn$
|
||||||
|
with bounds as (
|
||||||
|
select
|
||||||
|
((p_day::timestamp) at time zone 'Europe/Prague') as day_start_utc,
|
||||||
|
(((p_day + 1)::timestamp) at time zone 'Europe/Prague') as day_end_utc
|
||||||
|
)
|
||||||
select coalesce(
|
select coalesce(
|
||||||
jsonb_agg(u.j order by u.interval_start),
|
jsonb_agg(u.j order by u.interval_start),
|
||||||
'[]'::jsonb
|
'[]'::jsonb
|
||||||
@@ -17,8 +22,10 @@ as $fn$
|
|||||||
from (
|
from (
|
||||||
select v.*
|
select v.*
|
||||||
from ems.vw_site_effective_price v
|
from ems.vw_site_effective_price v
|
||||||
|
cross join bounds b
|
||||||
where v.site_id = p_site_id
|
where v.site_id = p_site_id
|
||||||
and (v.interval_start at time zone 'Europe/Prague')::date = p_day
|
and v.interval_start >= b.day_start_utc
|
||||||
|
and v.interval_start < b.day_end_utc
|
||||||
order by v.interval_start
|
order by v.interval_start
|
||||||
) t
|
) t
|
||||||
) u;
|
) u;
|
||||||
|
|||||||
@@ -3,9 +3,7 @@ import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
getCurrentPlan,
|
getCurrentPlan,
|
||||||
getSitePrices,
|
|
||||||
getForecastPvSlotsRangeCorrected,
|
getForecastPvSlotsRangeCorrected,
|
||||||
type SiteEffectivePriceRowDto,
|
|
||||||
} from '../api/backend'
|
} from '../api/backend'
|
||||||
import { getJson } from '../api/postgrest'
|
import { getJson } from '../api/postgrest'
|
||||||
import {
|
import {
|
||||||
@@ -22,6 +20,7 @@ import type {
|
|||||||
HeatPumpLatestRow,
|
HeatPumpLatestRow,
|
||||||
ModeLogRecentRow,
|
ModeLogRecentRow,
|
||||||
SiteStatusRow,
|
SiteStatusRow,
|
||||||
|
SiteEffectivePriceRow,
|
||||||
Telemetry15m7dRow,
|
Telemetry15m7dRow,
|
||||||
} from '../types/ems'
|
} from '../types/ems'
|
||||||
import type { PlanningIntervalDto } from '../types/plan'
|
import type { PlanningIntervalDto } from '../types/plan'
|
||||||
@@ -197,7 +196,7 @@ export function useDashboardData(siteId: number | null) {
|
|||||||
auditHourly,
|
auditHourly,
|
||||||
modeLog,
|
modeLog,
|
||||||
hpArr,
|
hpArr,
|
||||||
...priceLists
|
priceRows,
|
||||||
] = await Promise.all([
|
] = await Promise.all([
|
||||||
getCurrentPlan(siteId).catch((e: unknown) => {
|
getCurrentPlan(siteId).catch((e: unknown) => {
|
||||||
if (axios.isAxiosError(e) && e.response?.status === 404) {
|
if (axios.isAxiosError(e) && e.response?.status === 404) {
|
||||||
@@ -221,7 +220,15 @@ export function useDashboardData(siteId: number | null) {
|
|||||||
limit: '200',
|
limit: '200',
|
||||||
}),
|
}),
|
||||||
getJson<HeatPumpLatestRow[]>('/vw_latest_heat_pump', { site_id: `eq.${siteId}` }),
|
getJson<HeatPumpLatestRow[]>('/vw_latest_heat_pump', { site_id: `eq.${siteId}` }),
|
||||||
...[...dates].map((d) => getSitePrices(siteId, d)),
|
// Ceny bereme v jednom range dotazu přes PostgREST view (místo N× /api/v1/sites/{id}/prices?date=...).
|
||||||
|
// Okno: [windowStart, windowStart + TOTAL_SLOTS) pro mapování na sloty.
|
||||||
|
getJson<SiteEffectivePriceRow[]>('/vw_site_effective_price', {
|
||||||
|
site_id: `eq.${siteId}`,
|
||||||
|
interval_start: `gte.${new Date(windowStart).toISOString()}`,
|
||||||
|
interval_end: `lt.${new Date(windowStart + TOTAL_SLOTS * SLOT_MS).toISOString()}`,
|
||||||
|
order: 'interval_start.asc',
|
||||||
|
limit: String(TOTAL_SLOTS + 32),
|
||||||
|
}),
|
||||||
])
|
])
|
||||||
|
|
||||||
const status = Array.isArray(statusArr) && statusArr[0] ? statusArr[0]! : null
|
const status = Array.isArray(statusArr) && statusArr[0] ? statusArr[0]! : null
|
||||||
@@ -235,7 +242,7 @@ export function useDashboardData(siteId: number | null) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const priceBySlot = new Map<string, { buy: number | null; sell: number | null }>()
|
const priceBySlot = new Map<string, { buy: number | null; sell: number | null }>()
|
||||||
const flatPrices: SiteEffectivePriceRowDto[] = priceLists.flat() as SiteEffectivePriceRowDto[]
|
const flatPrices: SiteEffectivePriceRow[] = Array.isArray(priceRows) ? priceRows : []
|
||||||
for (const r of flatPrices) {
|
for (const r of flatPrices) {
|
||||||
const k = slotTimeKey(new Date(r.interval_start).getTime())
|
const k = slotTimeKey(new Date(r.interval_start).getTime())
|
||||||
priceBySlot.set(k, {
|
priceBySlot.set(k, {
|
||||||
|
|||||||
Reference in New Issue
Block a user