diff --git a/web/src/pages/LicensePage.tsx b/web/src/pages/LicensePage.tsx index e08e256..5fbf7d6 100644 --- a/web/src/pages/LicensePage.tsx +++ b/web/src/pages/LicensePage.tsx @@ -1,38 +1,13 @@ 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 ── +import { + LicenseBindPanel, + LicenseHeader, + LicenseInactiveTip, + LicenseStatusPanel, +} from './LicensePageSections' export function LicensePage() { const [status, setStatus] = useState(null) @@ -103,157 +78,22 @@ export function LicensePage() { 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} -

+ + + +
) } diff --git a/web/src/pages/LicensePageSections.tsx b/web/src/pages/LicensePageSections.tsx new file mode 100644 index 0000000..1a369b3 --- /dev/null +++ b/web/src/pages/LicensePageSections.tsx @@ -0,0 +1,219 @@ +import type { FormEvent } from 'react' +import { + CheckCircle2, + KeySquare, + Link2, + Loader2, + RefreshCw, + XCircle, +} from 'lucide-react' + +import type { LicenseStatus } from '../api/license' + +export function LicenseHeader() { + return ( +
+
+ +
+
+

许可证

+

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

+
+
+ ) +} + +export function LicenseBindPanel({ + bindKey, + binding, + onBind, + onBindKeyChange, +}: { + bindKey: string + binding: boolean + onBind: (event: FormEvent) => void + onBindKeyChange: (value: string) => void +}) { + return ( +
+
+ +

绑定许可证

+
+
+ onBindKeyChange(event.target.value)} + disabled={binding} + /> + +
+

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

+
+ ) +} + +export function LicenseStatusPanel({ + status, + loadingStatus, + active, + isExpired, + onRefresh, + onHeartbeat, +}: { + status: LicenseStatus | null + loadingStatus: boolean + active: boolean + isExpired: boolean + onRefresh: () => void + onHeartbeat: () => void +}) { + const activation = status?.activation + + if (loadingStatus) { + return ( +
+ +
+ ) + } + + return ( +
+
+
+ {active && !isExpired ? ( + + ) : ( + + )} +

当前状态

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

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

+
+ )} + + {active && activation && ( +
+ + + + + + + + + +
+ )} + + {isExpired && ( +
+ 此许可证已过期,部分功能可能受限。请获取新的许可证密钥。 +
+ )} +
+ ) +} + +export function LicenseInactiveTip({ active, loadingStatus }: { active: boolean; loadingStatus: boolean }) { + if (active || loadingStatus) return null + return ( +
+

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

+

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

+
+ ) +} + +function StatusBadge({ + label, + value, + mono, + className, +}: { + label: string + value: string + mono?: boolean + className?: string +}) { + return ( +
+

{label}

+

+ {value} +

+
+ ) +} + +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} 人` +}