refactor: 前端全面替换 any 为 unknown 并统一错误处理,后端用量记录补写请求头/体

- 前端 API 层、stores、conversation 解析器、组件全面替换 any 为 unknown/具体类型
- 错误处理统一使用 parseApiError/getErrorStatus 替代 err.response?.data?.detail 模式
- 后端 handler/TaskService/UsageLifecycle/StreamTracker 链路传递 request_headers/request_body
- streaming/pending 状态更新时可补写客户端和提供商的请求头及请求体
- 新增 TaskService 和 UsageService 相关测试
This commit is contained in:
fawney19
2026-02-22 00:43:41 +08:00
parent 98e60e8f74
commit cf2eee222e
121 changed files with 1652 additions and 1179 deletions
@@ -2,24 +2,23 @@
import type { ProxyNode } from '@/api/proxy-nodes'
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip'
import { Cpu } from 'lucide-vue-next'
import { computed, ref } from 'vue'
import { computed } from 'vue'
const props = defineProps<{ node: ProxyNode }>()
const open = ref(false)
const hardwareInfo = computed<Record<string, any> | null>(() => {
const hardwareInfo = computed<Record<string, unknown> | null>(() => {
const info = props.node.hardware_info
if (info == null) return null
if (typeof info === 'string') {
try {
const parsed = JSON.parse(info)
if (parsed && typeof parsed === 'object') return parsed as Record<string, any>
if (parsed && typeof parsed === 'object') return parsed as Record<string, unknown>
} catch {
return {}
}
return {}
}
if (typeof info === 'object') return info as Record<string, any>
if (typeof info === 'object') return info as Record<string, unknown>
return {}
})
@@ -27,16 +26,18 @@ const hardwareRows = computed(() => {
const info = hardwareInfo.value ?? {}
const rows: Array<{ label: string; value: string }> = []
const cpuCores = pickNumber(info.cpu_cores, info.cpu_count, info.cpu?.cores)
const cpuObj = info.cpu as Record<string, unknown> | undefined
const cpuCores = pickNumber(info.cpu_cores, info.cpu_count, cpuObj?.cores)
if (cpuCores != null) {
rows.push({ label: 'CPU', value: `${cpuCores} cores` })
}
const memObj = info.memory as Record<string, unknown> | undefined
const memoryMb = pickNumber(
info.total_memory_mb,
info.memory_total_mb,
info.memory_mb,
info.memory?.total_mb
memObj?.total_mb
)
if (memoryMb != null) {
rows.push({ label: 'RAM', value: formatMemory(memoryMb) })
@@ -62,11 +63,6 @@ const hardwareRows = computed(() => {
return rows
})
const tooltipTitle = computed(() => {
if (hardwareRows.value.length === 0) return '暂无硬件信息上报'
return hardwareRows.value.map(row => `${row.label}: ${row.value}`).join(' | ')
})
const showHardwareInfo = computed(
() =>
!props.node.is_manual
@@ -103,13 +99,7 @@ function pickString(...values: unknown[]): string {
return ''
}
function toggleTooltip() {
open.value = !open.value
}
function handleOpenChange(value: boolean) {
open.value = value
}
</script>
<template>
@@ -117,22 +107,14 @@ function handleOpenChange(value: boolean) {
v-if="showHardwareInfo"
:delay-duration="0"
>
<Tooltip
:open="open"
@update:open="handleOpenChange"
>
<Tooltip>
<TooltipTrigger as-child>
<button
type="button"
<span
aria-label="硬件信息"
:title="tooltipTitle"
class="inline-flex items-center justify-center rounded-sm p-0.5 hover:bg-muted/60 transition-colors cursor-help"
@click.stop="toggleTooltip"
@keydown.enter.prevent.stop="toggleTooltip"
@keydown.space.prevent.stop="toggleTooltip"
>
<Cpu class="h-3.5 w-3.5 text-muted-foreground" />
</button>
</span>
</TooltipTrigger>
<TooltipContent
side="right"