web/frpc: refactor dashboard with improved structure and API layer (#5117)

This commit is contained in:
fatedier
2026-01-09 00:40:51 +08:00
committed by GitHub
parent a4175a2595
commit 479e9f50c2
30 changed files with 2309 additions and 1694 deletions

18
web/frpc/src/api/frpc.ts Normal file
View File

@@ -0,0 +1,18 @@
import { http } from './http'
import type { StatusResponse } from '../types/proxy'
export const getStatus = () => {
return http.get<StatusResponse>('/api/status')
}
export const getConfig = () => {
return http.get<string>('/api/config')
}
export const putConfig = (content: string) => {
return http.put<void>('/api/config', content)
}
export const reloadConfig = () => {
return http.get<void>('/api/reload')
}

76
web/frpc/src/api/http.ts Normal file
View File

@@ -0,0 +1,76 @@
// http.ts - Base HTTP client
class HTTPError extends Error {
status: number
statusText: string
constructor(status: number, statusText: string, message?: string) {
super(message || statusText)
this.status = status
this.statusText = statusText
}
}
async function request<T>(url: string, options: RequestInit = {}): Promise<T> {
const defaultOptions: RequestInit = {
credentials: 'include',
}
const response = await fetch(url, { ...defaultOptions, ...options })
if (!response.ok) {
throw new HTTPError(response.status, response.statusText, `HTTP ${response.status}`)
}
// Handle empty response (e.g. 204 No Content)
if (response.status === 204) {
return {} as T
}
const contentType = response.headers.get('content-type')
if (contentType && contentType.includes('application/json')) {
return response.json()
}
return response.text() as unknown as T
}
export const http = {
get: <T>(url: string, options?: RequestInit) => request<T>(url, { ...options, method: 'GET' }),
post: <T>(url: string, body?: any, options?: RequestInit) => {
const headers: HeadersInit = { ...options?.headers }
let requestBody = body
if (body && typeof body === 'object' && !(body instanceof FormData) && !(body instanceof Blob)) {
if (!('Content-Type' in headers)) {
(headers as any)['Content-Type'] = 'application/json'
}
requestBody = JSON.stringify(body)
}
return request<T>(url, {
...options,
method: 'POST',
headers,
body: requestBody
})
},
put: <T>(url: string, body?: any, options?: RequestInit) => {
const headers: HeadersInit = { ...options?.headers }
let requestBody = body
if (body && typeof body === 'object' && !(body instanceof FormData) && !(body instanceof Blob)) {
if (!('Content-Type' in headers)) {
(headers as any)['Content-Type'] = 'application/json'
}
requestBody = JSON.stringify(body)
}
return request<T>(url, {
...options,
method: 'PUT',
headers,
body: requestBody
})
},
delete: <T>(url: string, options?: RequestInit) => request<T>(url, { ...options, method: 'DELETE' }),
}