Files
Frontend/src/libs/api/services/soilService.ts
T
2026-04-29 22:26:53 +03:30

145 lines
4.3 KiB
TypeScript

import { apiClient } from '../client'
const PREFIX = '/api/soil'
export interface SoilSummary {
summaryKpis?: Record<string, unknown>
avg_soil_moisture?: Record<string, unknown>
anomalyDetectionCard?: Record<string, unknown>
soilMoistureHeatmap?: Record<string, unknown>
}
interface ApiResponse<T> {
code: number
msg: string
data: T
}
interface StatusResponse<T> {
status: string
data: T
}
type HeatmapPoint = {
x: string
y: number
}
type HeatmapSeries = {
name: string
data: HeatmapPoint[]
}
function extract<T>(res: ApiResponse<T> | StatusResponse<T> | T): T {
return res && typeof res === 'object' && 'data' in res ? (res as ApiResponse<T>).data : (res as T)
}
function getNumericValue(value: unknown): number {
if (typeof value === 'number' && Number.isFinite(value)) return value
const parsed = Number(value)
return Number.isFinite(parsed) ? parsed : 0
}
function normalizeHeatmapSeries(data: Record<string, unknown>): HeatmapSeries[] {
const legacySeries = Array.isArray(data.series) ? (data.series as HeatmapSeries[]) : []
if (legacySeries.length > 0) return legacySeries
const gridCells = Array.isArray(data.grid_cells) ? (data.grid_cells as Array<Record<string, unknown>>) : []
if (gridCells.length === 0) return []
const grouped = new Map<string, HeatmapPoint[]>()
gridCells.forEach((cell, index) => {
const rowLabel = String(
cell.zone_name ?? cell.zone ?? cell.row_label ?? cell.row ?? cell.y_label ?? `ردیف ${index + 1}`
)
const columnLabel = String(
cell.time_label ?? cell.col_label ?? cell.column_label ?? cell.x_label ?? cell.col ?? cell.x ?? `${index + 1}`
)
const rawValue = cell.value ?? cell.moisture ?? cell.moisture_percent ?? cell.intensity ?? cell.y
const value = getNumericValue(rawValue)
const current = grouped.get(rowLabel) ?? []
current.push({ x: columnLabel, y: value })
grouped.set(rowLabel, current)
})
return Array.from(grouped.entries()).map(([name, points]) => ({
name,
data: points
}))
}
function buildHealthScoreKpi(summary: Record<string, unknown>): Record<string, unknown> {
const healthScore = getNumericValue(summary.healthScore)
const profileSource = String(summary.profileSource ?? 'مرجع خاک')
const healthLanguage =
summary.healthLanguage && typeof summary.healthLanguage === 'object'
? (summary.healthLanguage as Record<string, unknown>)
: {}
const chipText = String(healthLanguage.short_chip_text ?? summary.avgSoilMoistureStatus ?? '-')
let chipColor: 'success' | 'warning' | 'error' = 'success'
if (healthScore < 45) chipColor = 'error'
else if (healthScore < 70) chipColor = 'warning'
return {
id: 'soil_health_score',
title: 'سلامت خاک',
subtitle: profileSource,
stats: `${Math.round(healthScore)} / 100`,
avatarColor: chipColor === 'error' ? 'error' : chipColor === 'warning' ? 'warning' : 'success',
avatarIcon: 'tabler-activity-heartbeat',
chipText,
chipColor
}
}
export const soilService = {
async getSummary(farmUuid: string): Promise<SoilSummary> {
const res = await apiClient.get<ApiResponse<Record<string, unknown>> | Record<string, unknown>>(
`${PREFIX}/summary/?farm_uuid=${encodeURIComponent(farmUuid)}`
)
const data = extract(res)
return {
summaryKpis: { kpis: [buildHealthScoreKpi(data)] }
}
},
async getAvgMoisture(farmUuid: string): Promise<Record<string, unknown>> {
const res = await apiClient.get<StatusResponse<Record<string, unknown>> | Record<string, unknown>>(
`${PREFIX}/avg-moisture/?farm_uuid=${encodeURIComponent(farmUuid)}`
)
const data = extract(res)
return {
kpis: [data]
}
},
async getAnomalies(farmUuid: string): Promise<Record<string, unknown>> {
const res = await apiClient.get<ApiResponse<Record<string, unknown>> | Record<string, unknown>>(
`${PREFIX}/anomalies/?farm_uuid=${encodeURIComponent(farmUuid)}`
)
return extract(res)
},
async getMoistureHeatmap(farmUuid: string): Promise<Record<string, unknown>> {
const res = await apiClient.get<ApiResponse<Record<string, unknown>> | Record<string, unknown>>(
`${PREFIX}/moisture-heatmap/?farm_uuid=${encodeURIComponent(farmUuid)}`
)
const data = extract(res)
return {
...data,
series: normalizeHeatmapSeries(data)
}
},
}