"use client"; import { ArrowDown, ArrowUp, Loader2, Plus, Save, Trash2 } from "lucide-react"; import { useState } from "react"; import { AdminField, AdminSection } from "@/components/admin"; import { apiUpdateSiteSettings, type PublicSettings } from "@/lib/api"; import { BRAND_LIMITS, footerURLAllowed, isExternalFooterURL, type FooterLink, } from "@/lib/brand"; import { toast } from "@/lib/toast"; function clone(links: FooterLink[]): FooterLink[] { return links.map((l) => ({ ...l })); } export default function FooterLinksPanel({ initial, onSaved, }: { initial: PublicSettings; onSaved?: (next: PublicSettings) => void; }) { const [links, setLinks] = useState(() => clone(initial.footer_links)); const [saved, setSaved] = useState(() => clone(initial.footer_links)); const [saving, setSaving] = useState(false); const dirty = JSON.stringify(links) !== JSON.stringify(saved); const update = (i: number, patch: Partial) => { setLinks((prev) => prev.map((item, idx) => (idx === i ? { ...item, ...patch } : item))); }; const save = async () => { if (saving || !dirty) return; for (const item of links) { if (!item.label.trim()) { toast("链接文案不能为空"); return; } if (!footerURLAllowed(item.url)) { toast(`地址无效:${item.url || "(空)"}`); return; } } setSaving(true); try { const payload = links.map((item) => ({ label: item.label.trim(), url: item.url.trim(), new_tab: item.new_tab, })); const res = await apiUpdateSiteSettings({ footer_links: payload }); setLinks(clone(res.footer_links)); setSaved(clone(res.footer_links)); onSaved?.(res); toast("页脚链接已保存", "ok"); } catch (e) { toast(e instanceof Error ? e.message : "保存失败"); } finally { setSaving(false); } }; const move = (i: number, dir: -1 | 1) => { setLinks((prev) => { const j = i + dir; if (j < 0 || j >= prev.length) return prev; const next = [...prev]; const [row] = next.splice(i, 1); next.splice(j, 0, row); return next; }); }; return (
void save()}> {saving ? : } 保存 } >
{links.map((item, i) => (
第 {i + 1} 条
update(i, { label: v })} placeholder="京 ICP 备xxxxxxxx号" /> { const wasExt = isExternalFooterURL(item.url); const nowExt = isExternalFooterURL(v); update(i, { url: v, new_tab: !wasExt && nowExt ? true : item.new_tab }); }} placeholder="https://beian.miit.gov.cn/ 或 /about" />
))}
© {new Date().getFullYear()} {initial.site_name} {links.filter((l) => l.label.trim() && l.url.trim()).map((item) => ( {item.label.trim()} {item.new_tab ? " ↗" : ""} ))} 性能指标

外链保存后带 target=_blank 与 rel=noopener。站内路径留在本页。

); }