import { App, Button, Form, Input, Segmented, Space } from "antd"; import { Cloud, Globe, HardDrive, LocateFixed } from "lucide-react"; import { useEffect, useMemo, useState } from "react"; import { getAdminOSSSetting, updateAdminOSSSetting, type AdminOSSSetting } from "@/services/api/auth"; import { useAdminContext } from "../admin-context"; import { AdminPageFrame } from "../components/admin-shell"; import { AdminStatusBadge, configuredSecretText, SettingsSectionCard } from "../components/admin-ui"; type StorageMode = "local" | "aliyun" | "tencent" | "qiniu"; type OSSFormValues = { mode: StorageMode; publicBaseUrl?: string; region?: string; endpoint?: string; cdnBaseUrl?: string; bucket?: string; accessKeyId?: string; accessKeySecret?: string; pathPrefix?: string; }; export default function StorageSettingsPage() { const { message } = App.useApp(); const { references } = useAdminContext(); const [setting, setSetting] = useState(null); const [loading, setLoading] = useState(true); const [saving, setSaving] = useState(false); const [form] = Form.useForm(); const mode = Form.useWatch("mode", form) || "local"; const isObjectStorage = mode !== "local"; const isTencentCOS = mode === "tencent"; const isQiniuKodo = mode === "qiniu"; const accessKeyIdLabel = isTencentCOS ? "SecretId" : isQiniuKodo ? "AccessKey" : "AccessKey ID"; const accessKeySecretLabel = isTencentCOS ? "SecretKey" : isQiniuKodo ? "SecretKey" : "AccessKey Secret"; const hasCurrentProviderSecret = Boolean(setting && setting.provider === mode && setting.hasAccessKeySecret); const userNameById = useMemo(() => new Map(references.users.map((user) => [user.id, user.displayName || user.username])), [references.users]); useEffect(() => { void getAdminOSSSetting() .then(({ setting: value }) => { setSetting(value); form.setFieldsValue(formValues(value)); }) .catch((error) => message.error(error instanceof Error ? error.message : "读取对象存储配置失败")) .finally(() => setLoading(false)); }, [form, message]); const save = async () => { await form.validateFields(); const values = form.getFieldsValue(true); if (values.mode === "local" && !values.publicBaseUrl?.trim()) return message.error("请填写服务器访问地址"); if (values.mode !== "local" && !values.accessKeySecret?.trim() && !hasCurrentProviderSecret) return message.error(`请填写 ${accessKeySecretLabel}`); if (values.mode !== "local" && !values.bucket?.trim()) return message.error("请填写对象存储 Bucket"); if (values.mode !== "local" && !values.accessKeyId?.trim()) return message.error(`请填写 ${accessKeyIdLabel}`); if (values.mode === "aliyun" && !values.endpoint?.trim()) return message.error("请填写阿里云 OSS Endpoint"); if (values.mode === "tencent" && !values.endpoint?.trim() && !values.region?.trim()) return message.error("请填写腾讯云 COS Region 或 Endpoint"); if (values.mode === "qiniu" && !values.endpoint?.trim()) return message.error("请填写七牛云 Kodo 上传 Endpoint"); setSaving(true); try { const result = await updateAdminOSSSetting({ enabled: values.mode !== "local", provider: values.mode === "local" ? setting?.provider || "aliyun" : values.mode, region: values.region?.trim() || "", endpoint: values.endpoint?.trim() || "", cdnBaseUrl: values.cdnBaseUrl?.trim() || "", bucket: values.bucket?.trim() || "", accessKeyId: values.accessKeyId?.trim() || "", accessKeySecret: values.accessKeySecret?.trim() || "", publicBaseUrl: values.publicBaseUrl?.trim() || "", pathPrefix: values.pathPrefix?.trim() || "", }); setSetting(result.setting); form.setFieldsValue(formValues(result.setting)); message.success("存储配置已保存"); } catch (error) { message.error(error instanceof Error ? error.message : "保存存储配置失败"); } finally { setSaving(false); } }; return (
} title="平台存储" status={ {setting?.enabled ? : null} } footer={ <>
{setting?.updatedAt ? `上次更新:${formatTime(setting.updatedAt)}${setting.updatedBy ? ` · ${userNameById.get(setting.updatedBy) || setting.updatedBy}` : ""}` : "尚未保存平台存储配置"}
} >
block options={[ { label: 服务器本地, value: "local" }, { label: 阿里云 OSS, value: "aliyun" }, { label: 腾讯云 COS, value: "tencent" }, { label: 七牛云 Kodo, value: "qiniu" }, ]} onChange={(value) => { const nextMode = value as StorageMode; const switchingProvider = nextMode !== "local" && ((mode !== "local" && mode !== nextMode) || (mode === "local" && setting?.provider !== nextMode)); if (switchingProvider) form.setFieldsValue({ region: "", endpoint: "", cdnBaseUrl: "", bucket: "", accessKeyId: "", accessKeySecret: "" }); }} /> {isObjectStorage ? (
) : ( } /> )}
); } function formValues(setting?: AdminOSSSetting | null): OSSFormValues { return { mode: setting?.enabled ? setting.provider : "local", publicBaseUrl: setting?.publicBaseUrl || "", region: setting?.region || "", endpoint: setting?.endpoint || "", cdnBaseUrl: setting?.cdnBaseUrl || "", bucket: setting?.bucket || "", accessKeyId: setting?.accessKeyId || "", accessKeySecret: "", pathPrefix: setting?.pathPrefix || "", }; } function storageProviderLabel(provider?: AdminOSSSetting["provider"] | StorageMode) { return provider === "tencent" ? "腾讯云 COS" : provider === "qiniu" ? "七牛云 Kodo" : provider === "aliyun" ? "阿里云 OSS" : "服务器本地"; } function formatTime(value?: string) { return value ? new Date(value).toLocaleString("zh-CN", { hour12: false }) : "--"; }