"use client"; import { ExternalLink, LogIn, MessageSquare, MessagesSquare, ShieldCheck, ShieldOff, Timer } from "lucide-react"; import { useState } from "react"; import { AdminSettingsGroup, AdminSettingsRow, AdminStepper, AdminSwitch, } from "@/components/admin"; import ConfirmDialog from "@/components/ConfirmDialog"; import useUnsavedGuard from "@/hooks/useUnsavedGuard"; import { apiUpdateSiteSettings, type PublicSettings } from "@/lib/api"; import { toast } from "@/lib/toast"; import OperationsPanel from "./OperationsPanel"; function InstantNote({ saving }: { saving?: boolean }) { return {saving ? "正在保存…" : "修改后立即生效"}; } /** 内容互动开关 + 访问安全模块 */ export default function AccessSettings({ initial }: { initial: PublicSettings }) { const [allowComments, setAllowComments] = useState(initial.allow_comments !== false); const [commentsRequireLogin, setCommentsRequireLogin] = useState( initial.comments_require_login === true, ); const [allowMessages, setAllowMessages] = useState(initial.allow_messages !== false); const [postLinkNewTab, setPostLinkNewTab] = useState(initial.post_link_new_tab !== false); const [trustOn, setTrustOn] = useState(initial.trust_reviewed_publish !== false); const [withoutReviewOn, setWithoutReviewOn] = useState(initial.publish_without_review === true); const [cooldown, setCooldown] = useState(initial.post_cooldown_hours); const [savedCooldown, setSavedCooldown] = useState(initial.post_cooldown_hours); const [togglingComments, setTogglingComments] = useState(false); const [togglingCommentsLogin, setTogglingCommentsLogin] = useState(false); const [togglingMessages, setTogglingMessages] = useState(false); const [togglingLink, setTogglingLink] = useState(false); const [togglingTrust, setTogglingTrust] = useState(false); const [togglingWithoutReview, setTogglingWithoutReview] = useState(false); const [savingCooldown, setSavingCooldown] = useState(false); const [moduleDirty, setModuleDirty] = useState(false); const leave = useUnsavedGuard(moduleDirty); const toggleComments = async () => { if (togglingComments) return; const next = !allowComments; setTogglingComments(true); try { const res = await apiUpdateSiteSettings({ allow_comments: next }); setAllowComments(res.allow_comments); toast(res.allow_comments ? "已开放评论" : "已关闭评论", "ok"); } catch (e) { toast(e instanceof Error ? e.message : "保存失败"); } finally { setTogglingComments(false); } }; const toggleCommentsRequireLogin = async () => { if (togglingCommentsLogin || !allowComments) return; const next = !commentsRequireLogin; setTogglingCommentsLogin(true); try { const res = await apiUpdateSiteSettings({ comments_require_login: next }); setCommentsRequireLogin(res.comments_require_login === true); toast(res.comments_require_login ? "评论仅登录用户可见" : "游客也可查看评论", "ok"); } catch (e) { toast(e instanceof Error ? e.message : "保存失败"); } finally { setTogglingCommentsLogin(false); } }; const toggleMessages = async () => { if (togglingMessages) return; const next = !allowMessages; setTogglingMessages(true); try { const res = await apiUpdateSiteSettings({ allow_messages: next }); setAllowMessages(res.allow_messages); toast(res.allow_messages ? "已开放消息" : "已关闭消息", "ok"); } catch (e) { toast(e instanceof Error ? e.message : "保存失败"); } finally { setTogglingMessages(false); } }; const togglePostLinkNewTab = async () => { if (togglingLink) return; const next = !postLinkNewTab; setTogglingLink(true); try { const res = await apiUpdateSiteSettings({ post_link_new_tab: next }); setPostLinkNewTab(res.post_link_new_tab !== false); toast( res.post_link_new_tab !== false ? "帖子与评论外链将在新标签打开" : "帖子与评论外链将在当前页打开", "ok", ); } catch (e) { toast(e instanceof Error ? e.message : "保存失败"); } finally { setTogglingLink(false); } }; const toggleWithoutReview = async () => { if (togglingWithoutReview) return; setTogglingWithoutReview(true); try { const res = await apiUpdateSiteSettings({ publish_without_review: !withoutReviewOn }); setWithoutReviewOn(res.publish_without_review === true); toast( res.publish_without_review ? "已开启全站免审(发帖与评论直接公开,无需过审记录)" : "已关闭全站免审(将按过审免审规则决定是否待审)", "ok", ); } catch (e) { toast(e instanceof Error ? e.message : "保存失败"); } finally { setTogglingWithoutReview(false); } }; const toggleTrust = async () => { if (togglingTrust) return; setTogglingTrust(true); try { const res = await apiUpdateSiteSettings({ trust_reviewed_publish: !trustOn }); setTrustOn(res.trust_reviewed_publish); toast( res.trust_reviewed_publish ? "已开启过审免审(帖子与评论)" : "已关闭过审免审(帖子与评论将按规则待审)", "ok", ); } catch (e) { toast(e instanceof Error ? e.message : "保存失败"); } finally { setTogglingTrust(false); } }; const saveCooldown = async () => { if (savingCooldown) return; const n = Math.max(0, Math.min(168, Math.round(Number(cooldown)) || 0)); setSavingCooldown(true); try { const res = await apiUpdateSiteSettings({ post_cooldown_hours: n }); setCooldown(res.post_cooldown_hours); setSavedCooldown(res.post_cooldown_hours); toast( res.post_cooldown_hours === 0 ? "已关闭新用户发帖冷静期" : `新用户发帖冷静期已设为 ${res.post_cooldown_hours} 小时(评论与聊天不受限)`, "ok", ); } catch (e) { toast(e instanceof Error ? e.message : "保存失败"); } finally { setSavingCooldown(false); } }; return (
开放评论 } hintBelow="关闭后全站不提供评论功能。" >
void toggleComments()} label="开放评论" />
登录可见评论 } hintBelow="开启后游客无法查看评论内容,需登录后阅读与参与。" >
void toggleCommentsRequireLogin()} label="登录可见评论" />
开放消息 } hintBelow="关闭后前台隐藏私聊与群聊入口。" >
void toggleMessages()} label="开放消息" />
外链新标签打开 } hintBelow="帖子与评论中的外链是否在新标签打开。" >
void togglePostLinkNewTab()} label="外链新标签打开" />
全站免审 } hintBelow="所有人发帖与评论直接公开,无需有过审记录;开启后优先生效。" >
void toggleWithoutReview()} label="全站免审" />
过审免审 } hintBelow={ withoutReviewOn ? "全站免审已开启,所有内容直接公开,本开关暂不参与判定。" : "用户曾有过审内容后,后续发帖与评论直接公开。" } >
void toggleTrust()} label="过审免审" />
新用户发帖冷静期 } hintBelow="仅限制新注册用户发帖(0=关闭,上限 168 小时)。评论与聊天不受限。" >
); }