From 99d9cd1e1d16ef1f74c5f4584ed38be98a11d979 Mon Sep 17 00:00:00 2001 From: imbytecat Date: Mon, 11 May 2026 23:38:37 +0800 Subject: [PATCH] =?UTF-8?q?refactor(api):=20=E5=A4=8D=E7=94=A8=E7=94=B5?= =?UTF-8?q?=E6=B1=A0=E4=B8=9A=E5=8A=A1=E5=B8=B8=E9=87=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scripts/seed.ts | 48 +++++++++++++----- src/routes/batteries.tsx | 51 +++++++++----------- src/server/api/contracts/battery.contract.ts | 14 ++++-- src/server/battery/mysql.ts | 51 ++++++++++++-------- src/server/prediction/client.ts | 20 ++++---- 5 files changed, 113 insertions(+), 71 deletions(-) diff --git a/scripts/seed.ts b/scripts/seed.ts index 8a5b935..e815616 100644 --- a/scripts/seed.ts +++ b/scripts/seed.ts @@ -2,14 +2,15 @@ import { datetime, index, int, mysqlTable, tinyint, varchar } from 'drizzle-orm/ import { drizzle } from 'drizzle-orm/mysql2' import { reset } from 'drizzle-seed' import mysql from 'mysql2/promise' +import { type MYSQL_BOOLEAN, POWER_STATUS, type PowerStatus, toMysqlBoolean } from '@/domain/battery' type SeedRow = { userId: number mac: string devModel: string devName: string - isLowPower: 'true' | 'false' - powerStatus: 0 | 1 | 2 + isLowPower: (typeof MYSQL_BOOLEAN)[keyof typeof MYSQL_BOOLEAN] + powerStatus: PowerStatus power: number createTime: Date remark: string | null @@ -48,20 +49,41 @@ if (!safeSeedHosts.has(parsedUrl.hostname) && process.env.SEED_ALLOW_REMOTE !== } const devices = [ - { mac: 'RING-A03', model: 'SR-01', name: '样机-A03', basePower: 96, status: 2, remark: 'v3.8.2' }, - { mac: 'RING-B11', model: 'SR-01', name: '样机-B11', basePower: 91, status: 1, remark: 'v3.8.2' }, - { mac: 'RING-C07', model: 'SR-02', name: '样机-C07', basePower: 88, status: 0, remark: 'v3.8.1' }, - { mac: 'RING-D19', model: 'SR-02', name: '样机-D19', basePower: 84, status: 0, remark: 'v3.7.9' }, - { mac: 'RING-E21', model: 'SR-03', name: '样机-E21', basePower: 79, status: 1, remark: 'v3.7.9' }, - { mac: 'RING-F02', model: 'SR-03', name: '样机-F02', basePower: 73, status: 0, remark: null }, - { mac: 'RING-G15', model: 'SR-04', name: '样机-G15', basePower: 93, status: 2, remark: 'v3.9.0' }, - { mac: 'RING-H09', model: 'SR-04', name: '样机-H09', basePower: 86, status: 0, remark: 'v3.8.1' }, + { mac: 'RING-A03', model: 'SR-01', name: '样机-A03', basePower: 96, status: POWER_STATUS.FULL, remark: 'v3.8.2' }, + { mac: 'RING-B11', model: 'SR-01', name: '样机-B11', basePower: 91, status: POWER_STATUS.CHARGING, remark: 'v3.8.2' }, + { + mac: 'RING-C07', + model: 'SR-02', + name: '样机-C07', + basePower: 88, + status: POWER_STATUS.NOT_CHARGING, + remark: 'v3.8.1', + }, + { + mac: 'RING-D19', + model: 'SR-02', + name: '样机-D19', + basePower: 84, + status: POWER_STATUS.NOT_CHARGING, + remark: 'v3.7.9', + }, + { mac: 'RING-E21', model: 'SR-03', name: '样机-E21', basePower: 79, status: POWER_STATUS.CHARGING, remark: 'v3.7.9' }, + { mac: 'RING-F02', model: 'SR-03', name: '样机-F02', basePower: 73, status: POWER_STATUS.NOT_CHARGING, remark: null }, + { mac: 'RING-G15', model: 'SR-04', name: '样机-G15', basePower: 93, status: POWER_STATUS.FULL, remark: 'v3.9.0' }, + { + mac: 'RING-H09', + model: 'SR-04', + name: '样机-H09', + basePower: 86, + status: POWER_STATUS.NOT_CHARGING, + remark: 'v3.8.1', + }, ] satisfies Array<{ mac: string model: string name: string basePower: number - status: 0 | 1 | 2 + status: PowerStatus remark: string | null }> @@ -76,8 +98,8 @@ function createSeedRows(now = new Date()): SeedRow[] { mac: device.mac, devModel: device.model, devName: device.name, - isLowPower: power <= 20 || device.basePower <= 80 ? 'true' : 'false', - powerStatus: historyIndex === 0 ? device.status : 0, + isLowPower: toMysqlBoolean(power <= 20 || device.basePower <= 80), + powerStatus: historyIndex === 0 ? device.status : POWER_STATUS.NOT_CHARGING, power, createTime: createdAt, remark: device.remark, diff --git a/src/routes/batteries.tsx b/src/routes/batteries.tsx index d4f791b..60f427e 100644 --- a/src/routes/batteries.tsx +++ b/src/routes/batteries.tsx @@ -4,13 +4,8 @@ import { createColumnHelper, flexRender, getCoreRowModel, useReactTable } from ' import { useEffect, useMemo, useState } from 'react' import { z } from 'zod' import { orpc } from '@/client/orpc' -import type { BatteryInfo } from '@/domain/battery' - -const sortOptions = ['createdAtDesc', 'createdAtAsc', 'powerDesc', 'powerAsc'] as const -type BatteryListSort = (typeof sortOptions)[number] - -const powerStatusOptions = [0, 1, 2] as const -type PowerStatusFilter = (typeof powerStatusOptions)[number] +import type { BatteryInfo, BatteryListSort, PowerStatus } from '@/domain/battery' +import { BATTERY_LIST_SORT, BATTERY_LIST_SORT_VALUES, POWER_STATUS, POWER_STATUS_VALUES } from '@/domain/battery' const pageSizeOptions = [20, 50, 100] as const type PageSizeOption = (typeof pageSizeOptions)[number] @@ -29,8 +24,10 @@ const cursorSchema = z.preprocess( const searchSchema = z.object({ search: searchFilterSchema, lowPower: z.boolean().optional(), - powerStatus: z.union([z.literal(0), z.literal(1), z.literal(2)]).optional(), - sort: z.enum(sortOptions).optional().default('createdAtDesc'), + powerStatus: z + .union([z.literal(POWER_STATUS.NOT_CHARGING), z.literal(POWER_STATUS.CHARGING), z.literal(POWER_STATUS.FULL)]) + .optional(), + sort: z.enum(BATTERY_LIST_SORT_VALUES).optional().default(BATTERY_LIST_SORT.CREATED_AT_DESC), pageSize: z.coerce .number() .pipe(z.union([z.literal(20), z.literal(50), z.literal(100)])) @@ -53,16 +50,16 @@ export const Route = createFileRoute('/batteries')({ ), }) -const powerStatusLabel: Record<0 | 1 | 2, string> = { - 0: '未充电', - 1: '充电中', - 2: '已充满', +const powerStatusLabel: Record = { + [POWER_STATUS.NOT_CHARGING]: '未充电', + [POWER_STATUS.CHARGING]: '充电中', + [POWER_STATUS.FULL]: '已充满', } -const powerStatusColor: Record<0 | 1 | 2, string> = { - 0: 'text-zinc-400', - 1: 'text-teal-400', - 2: 'text-emerald-400', +const powerStatusColor: Record = { + [POWER_STATUS.NOT_CHARGING]: 'text-zinc-400', + [POWER_STATUS.CHARGING]: 'text-teal-400', + [POWER_STATUS.FULL]: 'text-emerald-400', } function powerBarColor(power: number, isLowPower: boolean): string { @@ -74,13 +71,13 @@ function powerBarColor(power: number, isLowPower: boolean): string { const columnHelper = createColumnHelper() function parseSort(value: string): BatteryListSort { - return sortOptions.find((option) => option === value) ?? 'createdAtDesc' + return BATTERY_LIST_SORT_VALUES.find((option) => option === value) ?? BATTERY_LIST_SORT.CREATED_AT_DESC } -function parsePowerStatus(value: string): PowerStatusFilter | undefined { +function parsePowerStatus(value: string): PowerStatus | undefined { const parsed = Number(value) - return powerStatusOptions.find((option) => option === parsed) + return POWER_STATUS_VALUES.find((option) => option === parsed) } function parsePageSize(value: string): PageSizeOption { @@ -284,9 +281,9 @@ function BatteriesPage() { }} > - - - + + +