feat: 前端集成 Prettier 代码格式化
This commit is contained in:
@@ -1,81 +1,77 @@
|
||||
import { ApiError } from '@/types';
|
||||
import { ApiError } from '@/types'
|
||||
|
||||
const API_BASE = import.meta.env.VITE_API_BASE || '';
|
||||
const API_BASE = import.meta.env.VITE_API_BASE || ''
|
||||
|
||||
function toCamelCase(str: string): string {
|
||||
return str.replace(/_([a-z])/g, (_, letter: string) => letter.toUpperCase());
|
||||
return str.replace(/_([a-z])/g, (_, letter: string) => letter.toUpperCase())
|
||||
}
|
||||
|
||||
function toSnakeCase(str: string): string {
|
||||
return str.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);
|
||||
return str.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`)
|
||||
}
|
||||
|
||||
function transformKeys<T>(obj: unknown, transformer: (key: string) => string): T {
|
||||
if (Array.isArray(obj)) {
|
||||
return obj.map((item) => transformKeys(item, transformer)) as T;
|
||||
return obj.map((item) => transformKeys(item, transformer)) as T
|
||||
}
|
||||
if (obj !== null && typeof obj === 'object') {
|
||||
const result: Record<string, unknown> = {};
|
||||
const result: Record<string, unknown> = {}
|
||||
for (const [key, value] of Object.entries(obj as Record<string, unknown>)) {
|
||||
result[transformer(key)] = transformKeys(value, transformer);
|
||||
result[transformer(key)] = transformKeys(value, transformer)
|
||||
}
|
||||
return result as T;
|
||||
return result as T
|
||||
}
|
||||
return obj as T;
|
||||
return obj as T
|
||||
}
|
||||
|
||||
export function fromApi<T>(data: unknown): T {
|
||||
return transformKeys<T>(data, toCamelCase);
|
||||
return transformKeys<T>(data, toCamelCase)
|
||||
}
|
||||
|
||||
export function toApi<T>(data: unknown): T {
|
||||
return transformKeys<T>(data, toSnakeCase);
|
||||
return transformKeys<T>(data, toSnakeCase)
|
||||
}
|
||||
|
||||
export async function request<T>(
|
||||
method: string,
|
||||
path: string,
|
||||
body?: unknown,
|
||||
): Promise<T> {
|
||||
const url = `${API_BASE}${path}`;
|
||||
export async function request<T>(method: string, path: string, body?: unknown): Promise<T> {
|
||||
const url = `${API_BASE}${path}`
|
||||
const options: RequestInit = {
|
||||
method,
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
};
|
||||
|
||||
if (body !== undefined) {
|
||||
options.body = JSON.stringify(toApi(body));
|
||||
}
|
||||
|
||||
const response = await fetch(url, options);
|
||||
if (body !== undefined) {
|
||||
options.body = JSON.stringify(toApi(body))
|
||||
}
|
||||
|
||||
const response = await fetch(url, options)
|
||||
|
||||
if (!response.ok) {
|
||||
let message = `请求失败 (${response.status})`;
|
||||
let code: string | undefined;
|
||||
let message = `请求失败 (${response.status})`
|
||||
let code: string | undefined
|
||||
try {
|
||||
const errorData = await response.json();
|
||||
const errorData = await response.json()
|
||||
if (typeof errorData === 'object' && errorData !== null) {
|
||||
// 提取结构化错误响应
|
||||
if ('error' in errorData && typeof errorData.error === 'string') {
|
||||
message = errorData.error;
|
||||
message = errorData.error
|
||||
} else if ('message' in errorData && typeof errorData.message === 'string') {
|
||||
message = errorData.message;
|
||||
message = errorData.message
|
||||
}
|
||||
// 提取错误码
|
||||
if ('code' in errorData && typeof errorData.code === 'string') {
|
||||
code = errorData.code;
|
||||
code = errorData.code
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
// ignore JSON parse error
|
||||
}
|
||||
throw new ApiError(response.status, message, code);
|
||||
throw new ApiError(response.status, message, code)
|
||||
}
|
||||
|
||||
if (response.status === 204) {
|
||||
return undefined as T;
|
||||
return undefined as T
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
return fromApi<T>(data);
|
||||
const data = await response.json()
|
||||
return fromApi<T>(data)
|
||||
}
|
||||
|
||||
@@ -1,24 +1,19 @@
|
||||
import type { Model, CreateModelInput, UpdateModelInput } from '@/types';
|
||||
import { request } from './client';
|
||||
import type { Model, CreateModelInput, UpdateModelInput } from '@/types'
|
||||
import { request } from './client'
|
||||
|
||||
export async function listModels(providerId?: string): Promise<Model[]> {
|
||||
const path = providerId
|
||||
? `/api/models?provider_id=${encodeURIComponent(providerId)}`
|
||||
: '/api/models';
|
||||
return request<Model[]>('GET', path);
|
||||
const path = providerId ? `/api/models?provider_id=${encodeURIComponent(providerId)}` : '/api/models'
|
||||
return request<Model[]>('GET', path)
|
||||
}
|
||||
|
||||
export async function createModel(input: CreateModelInput): Promise<Model> {
|
||||
return request<Model>('POST', '/api/models', input);
|
||||
return request<Model>('POST', '/api/models', input)
|
||||
}
|
||||
|
||||
export async function updateModel(
|
||||
id: string,
|
||||
input: UpdateModelInput,
|
||||
): Promise<Model> {
|
||||
return request<Model>('PUT', `/api/models/${id}`, input);
|
||||
export async function updateModel(id: string, input: UpdateModelInput): Promise<Model> {
|
||||
return request<Model>('PUT', `/api/models/${id}`, input)
|
||||
}
|
||||
|
||||
export async function deleteModel(id: string): Promise<void> {
|
||||
return request<void>('DELETE', `/api/models/${id}`);
|
||||
return request<void>('DELETE', `/api/models/${id}`)
|
||||
}
|
||||
|
||||
@@ -1,21 +1,18 @@
|
||||
import type { Provider, CreateProviderInput, UpdateProviderInput } from '@/types';
|
||||
import { request } from './client';
|
||||
import type { Provider, CreateProviderInput, UpdateProviderInput } from '@/types'
|
||||
import { request } from './client'
|
||||
|
||||
export async function listProviders(): Promise<Provider[]> {
|
||||
return request<Provider[]>('GET', '/api/providers');
|
||||
return request<Provider[]>('GET', '/api/providers')
|
||||
}
|
||||
|
||||
export async function createProvider(input: CreateProviderInput): Promise<Provider> {
|
||||
return request<Provider>('POST', '/api/providers', input);
|
||||
return request<Provider>('POST', '/api/providers', input)
|
||||
}
|
||||
|
||||
export async function updateProvider(
|
||||
id: string,
|
||||
input: UpdateProviderInput,
|
||||
): Promise<Provider> {
|
||||
return request<Provider>('PUT', `/api/providers/${id}`, input);
|
||||
export async function updateProvider(id: string, input: UpdateProviderInput): Promise<Provider> {
|
||||
return request<Provider>('PUT', `/api/providers/${id}`, input)
|
||||
}
|
||||
|
||||
export async function deleteProvider(id: string): Promise<void> {
|
||||
return request<void>('DELETE', `/api/providers/${id}`);
|
||||
return request<void>('DELETE', `/api/providers/${id}`)
|
||||
}
|
||||
|
||||
@@ -1,26 +1,26 @@
|
||||
import type { UsageStats, StatsQueryParams } from '@/types';
|
||||
import { request } from './client';
|
||||
import type { UsageStats, StatsQueryParams } from '@/types'
|
||||
import { request } from './client'
|
||||
|
||||
export async function getStats(params?: StatsQueryParams): Promise<UsageStats[]> {
|
||||
if (!params) {
|
||||
return request<UsageStats[]>('GET', '/api/stats');
|
||||
return request<UsageStats[]>('GET', '/api/stats')
|
||||
}
|
||||
|
||||
const query = new URLSearchParams();
|
||||
const query = new URLSearchParams()
|
||||
const snakeParams: Record<string, string | undefined> = {
|
||||
provider_id: params.providerId,
|
||||
model_name: params.modelName,
|
||||
start_date: params.startDate,
|
||||
end_date: params.endDate,
|
||||
};
|
||||
}
|
||||
|
||||
for (const [key, value] of Object.entries(snakeParams)) {
|
||||
if (value) {
|
||||
query.set(key, value);
|
||||
query.set(key, value)
|
||||
}
|
||||
}
|
||||
|
||||
const queryString = query.toString();
|
||||
const path = queryString ? `/api/stats?${queryString}` : '/api/stats';
|
||||
return request<UsageStats[]>('GET', path);
|
||||
const queryString = query.toString()
|
||||
const path = queryString ? `/api/stats?${queryString}` : '/api/stats'
|
||||
return request<UsageStats[]>('GET', path)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user