import { FormEvent, useCallback, useEffect, useState } from 'react' import { CheckCircle2, KeySquare, Link2, Loader2, RefreshCw, XCircle, } from 'lucide-react' import toast from 'react-hot-toast' import { licenseAPI, type LicenseStatus } from '../api/license' // ── Helpers ── function fmtDate(iso: string | null | undefined): string { if (!iso) return '永久' return new Date(iso).toLocaleDateString('zh-CN', { year: 'numeric', month: '2-digit', day: '2-digit', }) } function fmtDateTime(iso: string | null | undefined): string { if (!iso) return '—' return new Date(iso).toLocaleString('zh-CN') } function fmtUserLimit(maxUsers: number | null | undefined, unlimited?: boolean): string { if (unlimited || maxUsers == null) return '不限制' return `${maxUsers} 人` } // ── Page ── export function LicensePage() { const [status, setStatus] = useState(null) const [loadingStatus, setLoadingStatus] = useState(true) const [bindKey, setBindKey] = useState('') const [binding, setBinding] = useState(false) const refreshStatus = useCallback(async () => { setLoadingStatus(true) try { const s = await licenseAPI.status() setStatus(s) } catch { setStatus({ active: false }) } finally { setLoadingStatus(false) } }, []) useEffect(() => { refreshStatus() }, [refreshStatus]) const onBind = async (e: FormEvent) => { e.preventDefault() const key = bindKey.trim() if (!key) { toast.error('请输入许可证密钥') return } setBinding(true) try { const activation = await licenseAPI.bind(key) toast.success('许可证绑定成功!') setBindKey('') // Optimistically update status setStatus({ active: true, activation, message: '已激活', }) } catch (err: unknown) { const msg = (err as { response?: { data?: { error?: string } } })?.response?.data?.error ?? '绑定失败,请检查密钥是否正确' toast.error(msg) } finally { setBinding(false) } } const onHeartbeat = async () => { try { await licenseAPI.heartbeat() toast.success('心跳上报成功') } catch { toast.error('心跳上报失败') } } // ── Derive display values ── const active = status?.active === true const activation = status?.activation const isExpired = activation?.expires_at != null && new Date(activation.expires_at).getTime() < Date.now() return (
{/* ── Header ── */}

许可证

绑定授权密钥以解锁全部功能

{/* ── Bind Form ── */}

绑定许可证

setBindKey(e.target.value)} disabled={binding} />

输入从授权服务器获取的许可证密钥,激活后即可使用所有高级功能。

{/* ── License Status ── */} {loadingStatus ? (
) : (
{active && !isExpired ? ( ) : ( )}

当前状态

{active && ( )}
{!active && (

尚未绑定许可证。请在上方输入密钥完成激活。

)} {active && activation && (
)} {isExpired && (
此许可证已过期,部分功能可能受限。请获取新的许可证密钥。
)}
)} {/* ── Pro tip ── */} {!active && !loadingStatus && (

需要获取许可证?请联系管理员获取 MediaStationGo 授权密钥。

授权服务器地址可在系统设置中配置

)}
) } // ── Reusable status row ── function StatusBadge({ label, value, mono, className, }: { label: string value: string mono?: boolean className?: string }) { return (

{label}

{value}

) }