feat(api): 支持电池分页和安全预测

This commit is contained in:
2026-05-11 22:39:05 +08:00
parent 29e70fea9a
commit cf6f91651d
4 changed files with 322 additions and 33 deletions
+45 -9
View File
@@ -1,19 +1,44 @@
import { createBatteriesResponse, createDashboardSnapshot } from '@/domain/battery'
import { os } from '@/server/api/server'
import { getBatteryHistory, getBatteryPredictionHistory, getLatestBatteryPerDevice } from '@/server/battery/mysql'
import {
getBatteryHistory,
getBatteryPredictionHistories,
getLatestBatteryPage,
getLatestBatteryPerDevice,
} from '@/server/battery/mysql'
import { isPredictionEnabled, predictSoh } from '@/server/prediction/client'
const dashboardPredictionConcurrency = 5
async function mapWithConcurrency<T, R>(items: T[], concurrency: number, handler: (item: T) => Promise<R>): Promise<R[]> {
const results: R[] = []
let nextIndex = 0
async function worker() {
while (nextIndex < items.length) {
const index = nextIndex
nextIndex += 1
const item = items[index]
if (item !== undefined) results[index] = await handler(item)
}
}
await Promise.all(Array.from({ length: Math.min(concurrency, items.length) }, worker))
return results
}
export const dashboard = os.battery.dashboard.handler(async () => {
const items = await getLatestBatteryPerDevice()
const predictionHistories = isPredictionEnabled()
? await getBatteryPredictionHistories(items.map((item) => item.mac))
: new Map()
const predictionEntries = isPredictionEnabled()
? await Promise.all(
items.map(async (item) => {
const history = await getBatteryPredictionHistory(item.mac)
const prediction = await predictSoh(item, history)
? await mapWithConcurrency(items, dashboardPredictionConcurrency, async (item) => {
const prediction = await predictSoh(item, predictionHistories.get(item.mac) ?? [])
return prediction ? ([item.mac, prediction] as const) : null
}),
)
return prediction ? ([item.mac, prediction] as const) : null
})
: []
const predictions = new Map(predictionEntries.filter((entry) => entry !== null))
@@ -21,7 +46,18 @@ export const dashboard = os.battery.dashboard.handler(async () => {
})
export const batteries = os.battery.batteries.handler(async ({ input }) => {
const items = input.mac ? await getBatteryHistory(input.mac) : await getLatestBatteryPerDevice()
const page = await getLatestBatteryPage(input)
return createBatteriesResponse(
page.items,
new Date(),
{ total: page.total, lowPower: page.lowPower, charging: page.charging },
page.nextCursor,
)
})
export const history = os.battery.history.handler(async ({ input }) => {
const items = await getBatteryHistory(input.mac)
return createBatteriesResponse(items)
})