feat(web): 插件管理弹窗(启停 / 重载)
- 顶栏新增「插件管理」图标按钮,打开 PluginsDialog - 弹窗列出 pugins/ 下的插件:标题 / 目录名 / 是否启用与已加载 / 平台 label / 能力清单 - 每个插件可启用、停用、重载,底部有「全部重载」 - 启停成功后重新拉 /api/platforms,「添加账号」的平台下拉同步刷新 - types.ts 新增 PluginInfo;App.tsx 把平台列表加载提成 loadPlatforms 复用 - static/ 重新构建(pnpm typecheck + pnpm build 均通过) - 顺带把 .vscode/ 纳入跟踪
This commit is contained in:
+24
-11
@@ -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}
|
||||
|
||||
Reference in New Issue
Block a user