"use client"; import { useEffect, useRef, useState, type ReactNode } from "react"; import { Activity, ClipboardList, FileSearch, Loader2, Mail, Trash2, } from "lucide-react"; import { AdminSegmented, AdminSettingsActions, AdminSettingsGroup, AdminSettingsRow, AdminSwitch, } from "@/components/admin"; import { apiOperations } from "@/lib/api"; import ConfirmDialog from "@/components/ConfirmDialog"; import FilterRules, { type Rule } from "./FilterRules"; export type ModuleName = "security" | "mail" | "storage" | "filter" | "maintenance"; type Data = Record; type Snapshot = { data: Data; version: number; state: string; site_url: string; local_directory: string; encryption_ready: boolean; recovery_override: boolean; template_preview?: string; }; type Field = { key: string; label: string; type?: "number" | "switch" | "secret" | "select" | "list" | "textarea" | "datetime"; hint?: string; /** 控件下方较长说明(如模板变量释义) */ hintBelow?: ReactNode; min?: number; max?: number; rows?: number; wide?: boolean; options?: [string, string][]; advanced?: boolean; s3?: boolean; }; type Group = { title: string; description?: string; fields: Field[] }; const NUM = (key: string, label: string, min: number, max: number, unit: string): Field => ({ key, label, type: "number", min, max, hint: `${min}–${max} ${unit}`.trim(), }); /** 邮件模板占位符释义(注册验证与找回密码共用) */ const MAIL_TEMPLATE_VARS = (
{"{{site_name}}"}
站点名称(取自基本信息)
{"{{purpose}}"}
用途文案:账号验证 / 密码找回
{"{{code}}"}
验证码(正文必须包含)
{"{{link}}"}
引导用户回站完成验证/重置的链接
{"{{site_url}}"}
站点正式地址(SITE_URL)
{"{{logo}}"}
浅色 Logo 的完整 img 标签(勿写入 src)
{"{{logo_url}}"}
浅色 Logo 的绝对图片 URL
); const schemas: Record = { security: [ { title: "注册准入", fields: [ { key: "allow_register", label: "开放注册", type: "switch", hint: "关闭后仍保留注册入口,用户可看到关闭提示" }, { key: "register_notice", label: "关闭注册提示", hint: "关闭注册时在注册页展示" }, { key: "verify_email", label: "注册邮箱验证", type: "switch" }, { key: "password_reset", label: "邮件找回密码", type: "switch" }, ], }, { title: "登录保护与频率", fields: [ NUM("login_window", "失败观察窗口", 60, 3600, "秒"), NUM("login_failures", "账号失败阈值", 3, 50, "次"), NUM("post_interval", "发帖最小间隔", 0, 3600, "秒"), NUM("comment_interval", "评论最小间隔", 0, 3600, "秒"), NUM("search_minute", "搜索频率", 1, 120, "次/分"), ], }, { title: "账号邮件保护", fields: [ NUM("resend_interval", "验证码重发间隔", 30, 3600, "秒"), NUM("email_hourly", "邮箱发送上限", 1, 20, "次/时"), ], }, ], mail: [ { title: "SMTP 服务", fields: [ { key: "enabled", label: "启用邮件", type: "switch" }, { key: "host", label: "SMTP 主机" }, { key: "tls", label: "加密方式", type: "select", options: [ ["tls", "隐式 TLS(465)"], ["starttls", "STARTTLS(587)"], ], }, NUM("port", "SMTP 端口", 1, 65535, ""), { key: "username", label: "登录用户名" }, { key: "password", label: "密码 / 授权码", type: "secret" }, ], }, { title: "发件身份", fields: [ { key: "from_name", label: "发件人名称" }, { key: "from", label: "发件人邮箱" }, { key: "reply_to", label: "回复邮箱" }, { ...NUM("timeout", "连接超时", 2, 30, "秒"), advanced: true }, { ...NUM("retention", "发送记录保留", 1, 365, "天"), advanced: true }, ], }, { title: "邮件模板", description: "注册验证与找回密码共用;主题或正文留空则恢复内置模板。发送与预览会把 ${cleaned}