feat: 基础框架搭建完毕
Checks / verify (push) Failing after 2m37s

This commit is contained in:
2026-10-07 09:27:47 +08:00
parent ba6dfffab7
commit bffdb3858b
64 changed files with 326 additions and 332 deletions
+16
View File
@@ -0,0 +1,16 @@
export type ComponentStatus = "ready" | "unavailable" | "not_configured"
export type Health = {
status: "ready" | "not_ready"
checked_at: string
components: { postgresql: { status: ComponentStatus }; redis: { status: ComponentStatus } }
}
export async function getHealth(signal?: AbortSignal): Promise<Health> {
const response = await fetch("/api/v1/system/health", { signal, headers: { Accept: "application/json" } })
if (!response.ok && response.status !== 503) throw new Error(`服务请求失败(${response.status})`)
const data: unknown = await response.json()
if (!data || typeof data !== "object" || !("status" in data) || !("components" in data) || !("checked_at" in data)) throw new Error("服务返回了无效的状态数据")
const health = data as Health
const statuses = ["ready", "unavailable", "not_configured"]
if (!["ready", "not_ready"].includes(health.status) || typeof health.checked_at !== "string" || !statuses.includes(health.components?.postgresql?.status) || !statuses.includes(health.components?.redis?.status)) throw new Error("服务返回了无效的状态数据")
return health
}
+16
View File
@@ -0,0 +1,16 @@
export type User = {id:string;display_name:string;status:"ACTIVE" | "DISABLED";created_at:string;updated_at:string}
type Envelope<T> = {data:T;meta:{request_id:string;server_time?:string}}
export class ApiError extends Error {
constructor(public status:number,public code:string,message:string) {super(message);this.name="ApiError"}
}
async function request<T>(path:string,init?:RequestInit):Promise<T> {
const response=await fetch(path,{...init,credentials:"same-origin",headers:{Accept:"application/json",...(init?.body ? {"Content-Type":"application/json"} : {}),...init?.headers}})
const data=await response.json()
if (!response.ok) throw new ApiError(response.status,data.error?.code ?? "REQUEST_FAILED",data.error?.message ?? "请求失败,请稍后重试。")
if (!data || typeof data !== "object" || !("data" in data)) throw new Error("服务返回了无效数据。")
return (data as Envelope<T>).data
}
export function getMe(signal?:AbortSignal) {return request<User>("/api/admin/v1/me",{signal})}
export function login(login_name:string,password:string) {return request<{user:User;expires_at:string}>("/api/admin/v1/auth/login",{method:"POST",body:JSON.stringify({login_name,password})})}
export function logout() {return request<{revoked:boolean}>("/api/admin/v1/auth/logout",{method:"POST"})}
export function getUsers(signal?:AbortSignal) {return request<User[]>("/api/admin/v1/users",{signal})}
+3
View File
@@ -0,0 +1,3 @@
import { clsx, type ClassValue } from "clsx"
import { twMerge } from "tailwind-merge"
export function cn(...inputs: ClassValue[]) { return twMerge(clsx(inputs)) }