import {RefreshCcw, Save} from 'lucide-react'; import {FormEvent, useEffect, useState} from 'react'; import { getAdminCreationEntryConfig, upsertAdminCreationEntryConfig, } from '../api/adminApiClient'; import type {AdminCreationEntryTypeConfigPayload} from '../api/adminApiTypes'; import {useAdminWriteConfirm} from '../components/useAdminWriteConfirm'; import {handlePageError} from './pageUtils'; interface AdminCreationEntrySwitchPageProps { token: string; onUnauthorized: (message?: string) => void; } export function AdminCreationEntrySwitchPage({ token, onUnauthorized, }: AdminCreationEntrySwitchPageProps) { const [entries, setEntries] = useState([]); const [selectedId, setSelectedId] = useState('puzzle'); const [title, setTitle] = useState(''); const [subtitle, setSubtitle] = useState(''); const [badge, setBadge] = useState(''); const [imageSrc, setImageSrc] = useState(''); const [visible, setVisible] = useState(true); const [open, setOpen] = useState(true); const [sortOrder, setSortOrder] = useState('30'); const [isLoading, setIsLoading] = useState(false); const [isSaving, setIsSaving] = useState(false); const [listErrorMessage, setListErrorMessage] = useState(''); const [errorMessage, setErrorMessage] = useState(''); const {confirmWrite, confirmDialog} = useAdminWriteConfirm(); useEffect(() => { void refreshEntries(); // eslint-disable-next-line react-hooks/exhaustive-deps }, [token]); async function refreshEntries() { setIsLoading(true); setListErrorMessage(''); try { const response = await getAdminCreationEntryConfig(token); const nextEntries = sortEntries(response.entries); setEntries(nextEntries); fillForm( nextEntries.find((entry) => entry.id === selectedId) ?? nextEntries[0] ?? null, ); } catch (error: unknown) { handlePageError(error, onUnauthorized, setListErrorMessage); } finally { setIsLoading(false); } } async function handleSave(event: FormEvent) { event.preventDefault(); if (isSaving) { return; } const targetId = selectedId.trim(); setErrorMessage(''); const confirmed = await confirmWrite({ action: '保存创作入口开关', target: targetId, }); if (!confirmed) { return; } setIsSaving(true); try { const response = await upsertAdminCreationEntryConfig(token, { id: targetId, title: title.trim(), subtitle: subtitle.trim(), badge: badge.trim(), imageSrc: imageSrc.trim(), visible, open, sortOrder: parseInteger(sortOrder), }); const nextEntries = sortEntries(response.entries); setEntries(nextEntries); fillForm(nextEntries.find((entry) => entry.id === targetId) ?? null); } catch (error: unknown) { handlePageError(error, onUnauthorized, setErrorMessage); } finally { setIsSaving(false); } } function fillForm(entry: AdminCreationEntryTypeConfigPayload | null) { if (!entry) { return; } setSelectedId(entry.id); setTitle(entry.title); setSubtitle(entry.subtitle); setBadge(entry.badge); setImageSrc(entry.imageSrc); setVisible(entry.visible); setOpen(entry.open); setSortOrder(String(entry.sortOrder)); } return (

创作入口开关

控制创作中心入口展示与运行态路由可用性

{listErrorMessage ? (
{listErrorMessage}
) : null}
{errorMessage ? (
{errorMessage}
) : null}
{entries.map((entry) => ( ))}
入口 展示 开放 排序
{entry.visible ? '是' : '否'} {entry.open ? '是' : '否'} {entry.sortOrder}
{confirmDialog}
); } function sortEntries(entries: AdminCreationEntryTypeConfigPayload[]) { return [...entries].sort((left, right) => { if (left.sortOrder !== right.sortOrder) { return left.sortOrder - right.sortOrder; } return left.id.localeCompare(right.id); }); } function parseInteger(value: string) { const parsed = Number.parseInt(value, 10); if (!Number.isFinite(parsed)) { return 0; } return parsed; }