feat(web): 插件管理弹窗(启停 / 重载)

- 顶栏新增「插件管理」图标按钮,打开 PluginsDialog
- 弹窗列出 pugins/ 下的插件:标题 / 目录名 / 是否启用与已加载 / 平台 label / 能力清单
- 每个插件可启用、停用、重载,底部有「全部重载」
- 启停成功后重新拉 /api/platforms,「添加账号」的平台下拉同步刷新
- types.ts 新增 PluginInfo;App.tsx 把平台列表加载提成 loadPlatforms 复用
- static/ 重新构建(pnpm typecheck + pnpm build 均通过)
- 顺带把 .vscode/ 纳入跟踪
This commit is contained in:
study-tool
2026-10-31 16:01:44 +08:00
parent f8458cff51
commit cfa960221e
12 changed files with 471 additions and 244 deletions
+24 -11
View File
@@ -3,6 +3,7 @@ import { Plus, RefreshCw, Users, WifiOff } from 'lucide-react'
import { AccountCard } from './components/AccountCard'
import { AddAccountDialog, type NewAccount } from './components/AddAccountDialog'
import { PluginsDialog } from './components/PluginsDialog'
import { QuizDialog } from './components/QuizDialog'
import { SettingsDialog } from './components/SettingsDialog'
import { StatBar } from './components/StatBar'
@@ -48,6 +49,7 @@ interface InlineLog {
type DialogState =
| { type: 'add' }
| { type: 'settings' }
| { type: 'plugins' }
| { type: 'system' }
| { type: 'quiz'; accountId: string; course: Course }
| null
@@ -194,19 +196,23 @@ export default function App() {
return () => window.clearInterval(timer)
}, [load])
useEffect(() => {
api<{ platforms: PlatformInfo[] }>('/api/platforms')
.then((response) => {
const list = response.platforms || []
if (!list.length) return
setPlatformList(list)
const map: Record<string, string> = {}
for (const platform of list) map[platform.id] = platform.label
setPlatforms(map)
})
.catch(() => {})
const loadPlatforms = useCallback(async () => {
try {
const response = await api<{ platforms: PlatformInfo[] }>('/api/platforms')
const list = response.platforms || []
setPlatformList(list)
const map: Record<string, string> = {}
for (const platform of list) map[platform.id] = platform.label
setPlatforms(map)
} catch {
// 后端未连接时保留上一次的平台列表
}
}, [])
useEffect(() => {
void loadPlatforms()
}, [loadPlatforms])
const pullLog = useCallback(
async (id: string) => {
const current = logsRef.current[id] || {
@@ -656,6 +662,7 @@ export default function App() {
onRefresh={() => void refreshNow()}
onSettings={() => setDialog({ type: 'settings' })}
onSystemLog={() => setDialog({ type: 'system' })}
onPlugins={() => setDialog({ type: 'plugins' })}
onAdd={() => setDialog({ type: 'add' })}
/>
@@ -773,6 +780,12 @@ export default function App() {
notify={notify}
/>
<SystemLogDialog open={dialog?.type === 'system'} onClose={() => setDialog(null)} />
<PluginsDialog
open={dialog?.type === 'plugins'}
onClose={() => setDialog(null)}
notify={notify}
onChanged={() => void loadPlatforms()}
/>
<QuizDialog
open={dialog?.type === 'quiz' && !!quizAccount}
account={quizAccount}