Files
BiliNote/BillNote_frontend/src/components/Form/DownloaderForm/ProxyConfig.tsx
huangjianwu 37f7ee6e15 feat(desktop): 后端健康监控韧性 + onboarding 修复 + 全局代理 UI
- useCheckBackend 重写:60s 总超时取代 while(true) 死轮询,订阅 Tauri
  backend-ready/terminated/startup-timeout 事件,裸 fetch 探测避免
  启动期 toast 叠堆
- Tauri lib.rs:spawn 后 HTTP 探针轮询 /api/sys_check 拿 200 才算就绪
  (之前 TCP connect 会被孤儿进程误判);RunEvent::Exit 钩子退出前
  kill sidecar,修孤儿进程占端口;restart 前发 backend-restarting
  让前端忽略主动 kill 引发的 terminated
- BackendInitDialog:失败态展示原因 + 最近 stderr + 重启/复制日志按钮
- StartupBanner:收到 restarted/ready 自动清「已退出」横幅
- BackendHealthIndicator:修 /api/api/sys_health 双前缀 404
- Onboarding:step1 后端连通改自动重试 + 事件触发 + 手动按钮;step2
  撞预置供应商名时改为更新已存在供应商;errText 统一错误文案
- 全局代理 UI:下载配置页新增代理卡片(services/proxy.ts + ProxyConfig)
- request.ts 加 suppressToast 配置位,预期失败不弹全局红 toast
- NoteForm/taskStore:捕获就绪门禁错误,引导去音频转写配置页下载
- providerCard:整行可点切换(之前只有 icon 区域响应)
- Monitor 页 Whisper 卡显示模型本地下载状态
- tauri/api 升级对齐 2.11,修 vite build 版本不匹配

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 19:01:37 +08:00

90 lines
2.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { useEffect, useState } from 'react'
import toast from 'react-hot-toast'
import { Switch } from '@/components/ui/switch'
import { Input } from '@/components/ui/input'
import { Button } from '@/components/ui/button'
import { getProxyConfig, updateProxyConfig } from '@/services/proxy'
// 全局代理配置:作用于 LLM API + 转写 APIGroq 等)+ yt-dlp 视频下载。
// 国内访问 OpenAI / Groq / YouTube 基本都要靠它。
const ProxyConfig = () => {
const [enabled, setEnabled] = useState(false)
const [url, setUrl] = useState('')
const [effective, setEffective] = useState('')
const [loading, setLoading] = useState(true)
const [saving, setSaving] = useState(false)
useEffect(() => {
;(async () => {
try {
const cfg = await getProxyConfig()
setEnabled(cfg.enabled)
setUrl(cfg.url)
setEffective(cfg.effective)
} catch {
/* 拦截器已 toast */
} finally {
setLoading(false)
}
})()
}, [])
const handleSave = async () => {
if (enabled && !url.trim()) {
toast.error('请填写代理地址,或关闭代理开关')
return
}
setSaving(true)
try {
const cfg = await updateProxyConfig({ enabled, url: url.trim() })
setEnabled(cfg.enabled)
setUrl(cfg.url)
setEffective(cfg.effective)
toast.success('代理配置已保存')
} catch {
/* 拦截器已 toast */
} finally {
setSaving(false)
}
}
if (loading) {
return <div className="text-xs text-gray-400"></div>
}
// env 兜底:配置没开但 effective 有值,说明来自 HTTP_PROXY 环境变量
const fromEnv = !enabled && !!effective
return (
<div className="flex flex-col gap-2 rounded border border-neutral-200 p-3">
<div className="flex items-center justify-between">
<span className="text-sm font-medium"></span>
<Switch checked={enabled} onCheckedChange={setEnabled} />
</div>
<p className="text-xs text-gray-400">
AI Groq YouTube
</p>
<Input
placeholder="http://127.0.0.1:7890"
value={url}
disabled={!enabled}
onChange={e => setUrl(e.target.value)}
className="text-sm"
/>
{fromEnv && (
<p className="text-xs text-amber-600">
{effective}
</p>
)}
{enabled && effective && (
<p className="text-xs text-green-600">{effective}</p>
)}
<Button size="sm" onClick={handleSave} disabled={saving}>
{saving ? '保存中…' : '保存代理配置'}
</Button>
</div>
)
}
export default ProxyConfig