adjust ai insight and seed data

This commit is contained in:
Alberto-Audrix committed 2026-09-18 11:34:07 +07:00
1 parent 68e0d1a0bb
commit a2b5b10977
18 files changed
+1835 -140

No files matched your search

+55 -3
View File
@@ -6,6 +6,7 @@ import type {
Karung,
KPI,
ManualInput,
PanelIoT,
} from '../types/api.ts';
import type { View } from '../types/common.ts';
import { useFarm } from '../context/FarmContext.tsx';
@@ -23,7 +24,10 @@ import { getCountingAccuracyWarning } from '../utils/countingAccuracyWarning.ts'
import {
buildDashboardInsightContext,
buildDashboardInsightMetrics,
buildIotDayAggregates,
type EndCycleIotDayAggregate,
} from '../utils/insightContextBuilders.ts';
import { getTempStandardByDay } from '../utils/cp707EnvStandards.ts';
import DashboardReportCtas from './dashboard/DashboardReportCtas.tsx';
import DashboardCloseCycleControls from './dashboard/DashboardCloseCycleControls.tsx';
import DashboardManualInputForm from './dashboard/DashboardManualInputForm.tsx';
@@ -47,6 +51,7 @@ const Dashboard: React.FC<Props> = ({ setView }) => {
const [manualInputs, setManualInputs] = useState<ManualInput[]>([]);
const [weights, setWeights] = useState<ChickenWeight[]>([]);
const [karung, setKarung] = useState<Karung | null>(null);
const [iotDayAggregates, setIotDayAggregates] = useState<EndCycleIotDayAggregate[]>([]);
const [reportOpen, setReportOpen] = useState(false);
const [reportType, setReportType] = useState<DashboardReportType>('daily');
@@ -57,6 +62,7 @@ const Dashboard: React.FC<Props> = ({ setView }) => {
setManualInputs([]);
setWeights([]);
setKarung(null);
setIotDayAggregates([]);
return;
}
const cycleId = selectedCycle.id;
@@ -83,6 +89,44 @@ const Dashboard: React.FC<Props> = ({ setView }) => {
setManualInputs(manualRows);
setWeights(weightRows);
setKarung(latestKarung);
// Best-effort IoT aggregates for end-cycle root cause (non-blocking on failure).
try {
const flockId =
kpiRows.find((row) => row.flock_id != null)?.flock_id ??
(selectedKandang
? (await api.flocks.list({ kandang_id: selectedKandang.id }))[0]?.id
: null);
if (flockId == null) {
setIotDayAggregates([]);
} else {
let iotRows: PanelIoT[] = [];
try {
iotRows = await api.panelIot.list({ cycle_id: cycleId, flock_id: flockId });
} catch {
// Some deployments require a date — fall back to sampling recent dates.
const dates = await api.panelIot.dates({ cycle_id: cycleId, flock_id: flockId });
const sample = [...dates].sort().slice(-14);
const batches = await Promise.all(
sample.map((date) =>
api.panelIot.list({ cycle_id: cycleId, flock_id: flockId, date }).catch(() => [])
)
);
iotRows = batches.flat();
}
if (!cancelled) {
setIotDayAggregates(
buildIotDayAggregates({
rows: iotRows,
cycleStartDate: selectedCycle.start_date,
getTempTarget: getTempStandardByDay,
})
);
}
}
} catch {
if (!cancelled) setIotDayAggregates([]);
}
} catch (err) {
if (!cancelled) setError(errorMessage(err));
} finally {
@@ -92,7 +136,7 @@ const Dashboard: React.FC<Props> = ({ setView }) => {
return () => {
cancelled = true;
};
}, [selectedCycle]);
}, [selectedCycle, selectedKandang]);
const cards: KpiCardModel[] = useMemo(() => {
// All cards share the latest complete KPI day (not calendar current_day / live IoT).
@@ -246,12 +290,19 @@ const Dashboard: React.FC<Props> = ({ setView }) => {
karung_dituang_hari_ini:
latest != null ? latest.feed : (karung?.feed_use_today ?? karung?.out_today ?? null),
pakan_kumulatif_karung: karung?.feed_use_total ?? latest?.feed_total ?? null,
ayam_hidup_ekor: latest?.chicken_life ?? null,
ayam_hidup_ekor:
latest != null
? Math.max(0, latest.chicken_life - (latest.harvest_total ?? 0))
: null,
persen_hidup: latest?.chicken_life_percentage ?? null,
doc_in_ekor: selectedCycle?.doc_in_count ?? null,
kematian_kumulatif_ekor: latest?.mortality_total ?? null,
panen_kumulatif_ekor: latest?.harvest_total ?? null,
tonase_panen_kg: latest?.harvest_weight_total ?? null,
// KPI harvest_weight_total is grams; insight context expects kg.
tonase_panen_kg:
latest?.harvest_weight_total != null
? latest.harvest_weight_total / 1000
: null,
uniformity_persen: weightOnAnchor?.uniformity ?? null,
});
}, [
@@ -420,6 +471,7 @@ const Dashboard: React.FC<Props> = ({ setView }) => {
kandangId={selectedKandangId}
context={insightContext ?? undefined}
dashboardMetrics={insightMetrics}
iotDayAggregates={iotDayAggregates}
page="dashboard"
/>
) : (