import { FormEvent, useEffect, useState } from 'react' import toast from 'react-hot-toast' import { Trash2 } from 'lucide-react' import { adminAPI } from '../api/admin' import { libraryAPI } from '../api/library' import { schedulerAPI, type JobStatus } from '../api/scheduler' import type { Library, User } from '../types' import { DownloadClientCard } from '../components/DownloadClientCard' import { NotifyChannelCard } from '../components/NotifyChannelCard' import { APIConfigsPanel } from '../components/APIConfigsPanel' import { SitesPage } from './SitesPage' export function AdminPage() { const [tab, setTab] = useState< 'sites' | 'library' | 'users' | 'settings' | 'api' | 'downloads' | 'notify' | 'scheduler' >('sites') const tabs = [ { key: 'sites' as const, label: '站点管理' }, { key: 'library' as const, label: '媒体库' }, { key: 'users' as const, label: '用户' }, { key: 'api' as const, label: '外部API' }, { key: 'settings' as const, label: '系统设置' }, { key: 'downloads' as const, label: '下载客户端' }, { key: 'notify' as const, label: '通知渠道' }, { key: 'scheduler' as const, label: '定时任务' }, ] return (

管理后台

{tabs.map((k) => ( ))}
{tab === 'sites' && } {tab === 'library' && } {tab === 'users' && } {tab === 'api' && } {tab === 'settings' && } {tab === 'downloads' && } {tab === 'notify' && } {tab === 'scheduler' && }
) } function LibraryPanel() { const [libs, setLibs] = useState([]) const [name, setName] = useState('') const [path, setPath] = useState('') const [type, setType] = useState('movie') const refresh = () => libraryAPI.list().then(setLibs) useEffect(() => { refresh().catch(() => undefined) }, []) const handleCreate = async (e: FormEvent) => { e.preventDefault() try { await libraryAPI.create(name, path, type) toast.success('媒体库已创建') setName('') setPath('') await refresh() } catch (err: unknown) { const msg = (err as { response?: { data?: { error?: string } } })?.response?.data?.error ?? '创建失败' toast.error(msg) } } return (
setName(e.target.value)} /> setPath(e.target.value)} />
{libs.map((l) => ( ))}
名称 路径 类型 操作
{l.name} {l.path} {l.type}
) } function UsersPanel() { const [users, setUsers] = useState([]) const refresh = () => adminAPI.listUsers().then(setUsers) useEffect(() => { refresh().catch(() => undefined) }, []) return (
{users.map((u) => ( ))}
用户名 角色 最近登录 操作
{u.username} {u.role} {u.last_login_at ? new Date(u.last_login_at).toLocaleString() : '从未登录'}
) } function SettingsPanel() { const [items, setItems] = useState<{ key: string; value: string }[]>([]) const [k, setK] = useState('') const [v, setV] = useState('') const refresh = () => adminAPI.listSettings().then(setItems) useEffect(() => { refresh().catch(() => undefined) }, []) const onSave = async (e: FormEvent) => { e.preventDefault() await adminAPI.updateSetting(k, v) toast.success('已保存') setK('') setV('') await refresh() } return (
setK(e.target.value)} /> setV(e.target.value)} />
{items.map((it) => ( ))}
键 值
{it.key} {it.value}
) } function SchedulerPanel() { const [tasks, setTasks] = useState([]) const [loading, setLoading] = useState(false) const refresh = () => { setLoading(true) schedulerAPI.status().then(setTasks).finally(() => setLoading(false)) } useEffect(() => { refresh() }, []) return (
{loading &&

加载中...

} {!loading && tasks.length === 0 && (

暂无定时任务

)} {!loading && tasks.length > 0 && ( {tasks.map((t) => ( ))}
名称 间隔 上次运行 操作
{t.name} {t.interval} {t.last_run ? new Date(t.last_run).toLocaleString() : '-'}
)}
) }