Fix notification event toggles and license heartbeat

This commit is contained in:
ShukeBta
2026-06-17 20:35:11 +08:00
parent b128b4d11e
commit a0aeb07f03
12 changed files with 164 additions and 42 deletions
+2 -2
View File
@@ -5,8 +5,8 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="theme-color" content="#faf8f5" />
<meta name="description" content="MediaStationGo — 个人家庭媒体中心" />
<link rel="icon" type="image/png" href="/brand/mgo-emby-icon.png" />
<link rel="apple-touch-icon" href="/brand/mgo-emby-icon.png" />
<link rel="icon" type="image/svg+xml" href="/brand/mgo-emby-icon.svg" />
<link rel="apple-touch-icon" href="/brand/mgo-emby-icon.svg" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
+1 -1
View File
@@ -1,4 +1,4 @@
<svg width="64" height="64" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="32" height="32" rx="8" fill="url(#mgoPurpleGrad)" />
<path d="M11 10 L21 16 L11 22" stroke="white" stroke-width="2.5" stroke-linecap="square" stroke-linejoin="miter" fill="none" />
<path d="M11 18 L11 24 L16 21" stroke="white" stroke-width="2.5" stroke-linecap="square" stroke-linejoin="miter" fill="none" />

Before

Width:  |  Height:  |  Size: 705 B

After

Width:  |  Height:  |  Size: 705 B

+11 -2
View File
@@ -1,3 +1,12 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" role="img" aria-label="MediaStationGo">
<image href="/brand/mgo-emby-icon.png" width="64" height="64" preserveAspectRatio="xMidYMid meet"/>
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="MediaStationGo">
<rect width="32" height="32" rx="8" fill="url(#mgoPurpleGrad)" />
<path d="M11 10 L21 16 L11 22" stroke="white" stroke-width="2.5" stroke-linecap="square" stroke-linejoin="miter" fill="none" />
<path d="M11 18 L11 24 L16 21" stroke="white" stroke-width="2.5" stroke-linecap="square" stroke-linejoin="miter" fill="none" />
<circle cx="23" cy="9" r="2" fill="#06B6D4" />
<defs>
<linearGradient id="mgoPurpleGrad" x1="0" y1="0" x2="32" y2="32" gradientUnits="userSpaceOnUse">
<stop stop-color="#7C3AED" />
<stop offset="1" stop-color="#5B21B6" />
</linearGradient>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 209 B

After

Width:  |  Height:  |  Size: 744 B

+1 -1
View File
@@ -192,7 +192,7 @@ export function Layout() {
<div className="flex h-20 items-center justify-between px-6 border-b border-gray-100">
<Link to="/" className="flex items-center gap-3">
<img
src="/brand/mgo-emby-icon.png"
src="/brand/mgo-emby-icon.svg"
alt="MediaStationGo"
className="h-10 w-10 shrink-0 rounded-xl object-contain shadow-sm"
/>
+1 -1
View File
@@ -54,7 +54,7 @@ export function LoginPage() {
initial={{ scale: 0.8, opacity: 0 }}
animate={{ scale: 1, opacity: 1 }}
transition={{ delay: 0.15, type: 'spring', stiffness: 200 }}
src="/brand/mgo-emby-icon.png"
src="/brand/mgo-emby-icon.svg"
alt="MediaStationGo"
className="mb-4 h-14 w-14 rounded-2xl object-contain shadow-sm"
/>
+47 -5
View File
@@ -197,6 +197,16 @@ const EVENT_OPTIONS = [
{ value: 'system_alert', label: '系统异常通知' },
]
const EVENT_ALL = '__all__'
const EVENT_NONE = '__none__'
type EventMode = 'all' | 'custom' | 'none'
function initialEventMode(events: string[] | undefined): EventMode {
if (events?.includes(EVENT_NONE)) return 'none'
if (events?.includes(EVENT_ALL) || !events || events.length === 0) return 'all'
return 'custom'
}
function ChannelCard({
channel,
onTest,
@@ -252,6 +262,8 @@ function ChannelCard({
}
function eventSummary(events: string[] | undefined): string {
if (events?.includes(EVENT_NONE)) return '事件:不推送'
if (events?.includes(EVENT_ALL)) return '事件:全部'
if (!events || events.length === 0) return '事件:全部'
const labels = events.map((event) => EVENT_OPTIONS.find((item) => item.value === event)?.label ?? event)
return `事件:${labels.join('、')}`
@@ -324,6 +336,7 @@ function ChannelFormModal({
normalizeInitialConfig(editing?.type ?? 'telegram', editing?.config ?? {}),
)
const [events, setEvents] = useState<string[]>(editing?.events ?? [])
const [eventMode, setEventMode] = useState<EventMode>(initialEventMode(editing?.events))
const [enabled, setEnabled] = useState(editing?.enabled ?? true)
const [saving, setSaving] = useState(false)
@@ -344,6 +357,11 @@ function ChannelFormModal({
return
}
}
const selectedEvents = events.filter((event) => EVENT_OPTIONS.some((item) => item.value === event))
if (eventMode === 'custom' && selectedEvents.length === 0) {
toast.error('请至少选择一个推送事件,或选择关闭全部推送事件')
return
}
setSaving(true)
try {
const cleanedConfig = Object.fromEntries(
@@ -354,7 +372,7 @@ function ChannelFormModal({
name: name.trim(),
type: type,
config: cleanedConfig,
events,
events: eventMode === 'all' ? [EVENT_ALL] : eventMode === 'none' ? [EVENT_NONE] : selectedEvents,
enabled,
}
if (editing) {
@@ -378,7 +396,9 @@ function ChannelFormModal({
const toggleEvent = (event: string) => {
setEvents((current) =>
current.includes(event) ? current.filter((item) => item !== event) : [...current, event],
current.includes(event)
? current.filter((item) => item !== event)
: [...current.filter((item) => item !== EVENT_ALL && item !== EVENT_NONE), event],
)
}
@@ -622,19 +642,41 @@ function ChannelFormModal({
<div className="space-y-2 rounded-lg border border-gray-200 bg-gray-50/60 p-3">
<label className="flex cursor-pointer items-center gap-2 text-sm text-ink-100">
<input
type="checkbox"
type="radio"
name="notify-event-mode"
className="h-4 w-4 accent-primary-400"
checked={events.length === 0}
onChange={() => setEvents([])}
checked={eventMode === 'all'}
onChange={() => setEventMode('all')}
/>
全部事件
</label>
<label className="flex cursor-pointer items-center gap-2 text-sm text-ink-100">
<input
type="radio"
name="notify-event-mode"
className="h-4 w-4 accent-primary-400"
checked={eventMode === 'none'}
onChange={() => setEventMode('none')}
/>
关闭全部推送事件
</label>
<label className="flex cursor-pointer items-center gap-2 text-sm text-ink-100">
<input
type="radio"
name="notify-event-mode"
className="h-4 w-4 accent-primary-400"
checked={eventMode === 'custom'}
onChange={() => setEventMode('custom')}
/>
仅推送勾选事件
</label>
<div className="grid gap-2 sm:grid-cols-2">
{EVENT_OPTIONS.map((event) => (
<label key={event.value} className="flex cursor-pointer items-center gap-2 text-sm text-ink-100">
<input
type="checkbox"
className="h-4 w-4 accent-primary-400"
disabled={eventMode !== 'custom'}
checked={events.includes(event.value)}
onChange={() => toggleEvent(event.value)}
/>