Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 11cf298332 | |||
| 25d7f1c315 |
@@ -56,6 +56,20 @@ describe('battery domain', () => {
|
|||||||
expect(response.items[0]?.createTime).toBe('2026-05-10T23:00:00.000Z')
|
expect(response.items[0]?.createTime).toBe('2026-05-10T23:00:00.000Z')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('keeps explicit window summaries for limited history slices', () => {
|
||||||
|
const now = new Date('2026-05-11T00:00:00.000Z')
|
||||||
|
const items = rows.map(toBatteryInfo)
|
||||||
|
const response = createBatteriesResponse(items, now, {
|
||||||
|
total: items.length,
|
||||||
|
lowPower: 1,
|
||||||
|
charging: 1,
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(response.total).toBe(2)
|
||||||
|
expect(response.lowPower).toBe(1)
|
||||||
|
expect(response.charging).toBe(1)
|
||||||
|
})
|
||||||
|
|
||||||
test('creates dashboard aggregate shape without using power as fake SOH', () => {
|
test('creates dashboard aggregate shape without using power as fake SOH', () => {
|
||||||
const now = new Date('2026-05-11T00:00:00.000Z')
|
const now = new Date('2026-05-11T00:00:00.000Z')
|
||||||
const snapshot = createDashboardSnapshot(rows.map(toBatteryInfo), now)
|
const snapshot = createDashboardSnapshot(rows.map(toBatteryInfo), now)
|
||||||
|
|||||||
@@ -205,7 +205,7 @@ function BatteriesPage() {
|
|||||||
search: (prev) => ({
|
search: (prev) => ({
|
||||||
...prev,
|
...prev,
|
||||||
cursor: nextCursor,
|
cursor: nextCursor,
|
||||||
cursors: [...(prev.cursors || []), prev.cursor || firstPageCursor],
|
cursors: [...(prev.cursors || []), prev.cursor || firstPageCursor].slice(-100),
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { createBatteriesResponse, createDashboardSnapshot } from '@/domain/battery'
|
import { createBatteriesResponse, createDashboardSnapshot, POWER_STATUS } from '@/domain/battery'
|
||||||
import { os } from '@/server/api/server'
|
import { os } from '@/server/api/server'
|
||||||
import {
|
import {
|
||||||
getBatteryHistory,
|
getBatteryHistory,
|
||||||
@@ -63,5 +63,10 @@ export const batteries = os.battery.batteries.handler(async ({ input }) => {
|
|||||||
export const history = os.battery.history.handler(async ({ input }) => {
|
export const history = os.battery.history.handler(async ({ input }) => {
|
||||||
const items = await getBatteryHistory(input.mac)
|
const items = await getBatteryHistory(input.mac)
|
||||||
|
|
||||||
return createBatteriesResponse(items)
|
// History returns a limited window, so the counters must describe only this returned slice.
|
||||||
|
return createBatteriesResponse(items, new Date(), {
|
||||||
|
total: items.length,
|
||||||
|
lowPower: items.filter((item) => item.isLowPower).length,
|
||||||
|
charging: items.filter((item) => item.powerStatus === POWER_STATUS.CHARGING).length,
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -15,8 +15,6 @@ import { env } from '@/env'
|
|||||||
|
|
||||||
const historyLimit = 500
|
const historyLimit = 500
|
||||||
const predictionHistoryLimit = 10
|
const predictionHistoryLimit = 10
|
||||||
const dashboardLatestLimit = 100
|
|
||||||
|
|
||||||
type BatteryInfoMysqlRow = RowDataPacket & BatteryInfoSourceRow
|
type BatteryInfoMysqlRow = RowDataPacket & BatteryInfoSourceRow
|
||||||
type CountMysqlRow = RowDataPacket & {
|
type CountMysqlRow = RowDataPacket & {
|
||||||
total: number
|
total: number
|
||||||
@@ -314,16 +312,19 @@ export async function getLatestBatteryPage(input: LatestBatteryPageInput): Promi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getLatestBatteryPerDevice(limit = dashboardLatestLimit): Promise<BatteryInfo[]> {
|
export async function getLatestBatteryPerDevice(limit?: number): Promise<BatteryInfo[]> {
|
||||||
|
const appliedLimit = typeof limit === 'number' && limit > 0 ? limit : undefined
|
||||||
|
const limitSql = appliedLimit ? '\n LIMIT :limit' : ''
|
||||||
|
const queryParams = appliedLimit ? { limit: appliedLimit } : {}
|
||||||
|
|
||||||
const [rows] = await getBatteryPool().query<BatteryInfoMysqlRow[]>(
|
const [rows] = await getBatteryPool().query<BatteryInfoMysqlRow[]>(
|
||||||
`
|
`
|
||||||
SELECT ${sourceColumns}
|
SELECT ${sourceColumns}
|
||||||
FROM ls_battery_info AS current_record
|
FROM ls_battery_info AS current_record
|
||||||
WHERE ${latestRecordPredicate}
|
WHERE ${latestRecordPredicate}
|
||||||
ORDER BY current_record.create_time DESC, current_record.id DESC
|
ORDER BY current_record.create_time DESC, current_record.id DESC${limitSql}
|
||||||
LIMIT :limit
|
|
||||||
`,
|
`,
|
||||||
{ limit: Math.min(Math.max(limit, 1), dashboardLatestLimit) },
|
queryParams,
|
||||||
)
|
)
|
||||||
|
|
||||||
return rows.map(toBatteryInfo)
|
return rows.map(toBatteryInfo)
|
||||||
|
|||||||
Reference in New Issue
Block a user