新增仪表盘页:流量曲线、流量与内存数字、配置概览、内核状态
流量曲线手画 SVG polyline 而不引图表库:60 个点两条线,一个图表库几百 KB, 决策记录 0006 留的例外用在这里不划算。/traffic 和 /memory 是永不结束的流, api.request() 会把整个响应读完等于挂死,所以新增 api.openStream() 返回响应体, 交给 web/stream.ts 的 readLines 逐行读,离开页面中止 fetch 断流。 导航入口要在 App.vue 里挂,按约定留给集成者统一改。
This commit is contained in:
+23
@@ -126,6 +126,29 @@ export const api = {
|
||||
|
||||
kernel: () => request<{ online: boolean; version?: string }>('GET', '/api/kernel'),
|
||||
|
||||
/** 内核的运行时设置:运行模式、各代理端口、allow-lan 等。 */
|
||||
kernelConfigs: () => request<Record<string, unknown>>('GET', '/api/kernel/configs'),
|
||||
|
||||
/**
|
||||
* 打开一个持续吐数据的流式接口(/traffic、/memory),每秒一行 JSON。
|
||||
*
|
||||
* 不能用上面的 request():它会把整个响应读完,而对永不结束的流来说那等于挂死。
|
||||
* 调用方拿到响应体后用 web/stream.ts 的 readLines() 逐行读;中止 signal 即断流。
|
||||
*/
|
||||
openStream: async (path: string, signal: AbortSignal): Promise<ReadableStream<Uint8Array>> => {
|
||||
const res = await fetch(`/api/kernel${path}`, {
|
||||
headers: { Authorization: `Bearer ${getToken()}` },
|
||||
signal,
|
||||
})
|
||||
if (!res.ok) {
|
||||
const text = await res.text()
|
||||
const payload = text ? (JSON.parse(text) as Record<string, unknown>) : {}
|
||||
throw new ApiError(res.status, payload)
|
||||
}
|
||||
if (!res.body) throw new Error('响应没有内容')
|
||||
return res.body
|
||||
},
|
||||
|
||||
/** 入站类型的字段表,从内核源码提取,用来驱动表单。 */
|
||||
listenerFields: () => request<ListenerFields>('GET', '/api/meta/listener-fields'),
|
||||
|
||||
|
||||
Reference in New Issue
Block a user