yearning
11 小时以前 3f96c9c6502243b06efd4bb34a189e72e3a5557c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
import { useEffect, useState } from "react";
import { Button, Card, Form, Input, Upload, message, Image, Space } from "antd";
import { UploadOutlined } from "@ant-design/icons";
import { api } from "../api";
import { logoSrc, useSystemSettings } from "../systemSettings";
 
export default function AdminSystemSettingsPage() {
  const { settings, refresh, logoCacheKey } = useSystemSettings();
  const [form] = Form.useForm<{ system_name: string }>();
  const [saving, setSaving] = useState(false);
 
  useEffect(() => {
    form.setFieldsValue({ system_name: settings.system_name });
  }, [settings.system_name, form]);
 
  const logo = logoSrc(settings.logo_url, logoCacheKey);
 
  return (
    <Card title="系统设置">
      <Form
        form={form}
        layout="vertical"
        style={{ maxWidth: 480 }}
        onFinish={async (v) => {
          setSaving(true);
          try {
            await api.put("/api/admin/settings", { system_name: v.system_name });
            message.success("已保存");
            await refresh();
          } catch (e: unknown) {
            const msg =
              (e as { response?: { data?: { detail?: string } } })?.response?.data?.detail || "保存失败";
            message.error(msg);
          } finally {
            setSaving(false);
          }
        }}
      >
        <Form.Item name="system_name" label="系统名称" rules={[{ required: true, max: 128 }]}>
          <Input placeholder="显示在顶栏、登录页与浏览器标题" />
        </Form.Item>
        <Button type="primary" htmlType="submit" loading={saving}>保存名称</Button>
      </Form>
 
      <Card type="inner" title="系统 Logo" style={{ marginTop: 24, maxWidth: 480 }}>
        {logo && (
          <div style={{ marginBottom: 16 }}>
            <Image src={logo} alt="Logo" style={{ maxHeight: 64, maxWidth: 200, objectFit: "contain" }} />
          </div>
        )}
        <Space wrap>
          <Upload
            accept=".png,.jpg,.jpeg,.webp,.svg,.gif"
            showUploadList={false}
            beforeUpload={async (file) => {
              const fd = new FormData();
              fd.append("file", file);
              try {
                await api.post("/api/admin/settings/logo", fd);
                message.success("Logo 已更新");
                await refresh();
              } catch (e: unknown) {
                const msg =
                  (e as { response?: { data?: { detail?: string } } })?.response?.data?.detail || "上传失败";
                message.error(msg);
              }
              return false;
            }}
          >
            <Button icon={<UploadOutlined />}>上传 Logo</Button>
          </Upload>
          {logo && (
            <Button
              danger
              onClick={async () => {
                await api.delete("/api/admin/settings/logo");
                message.success("已移除 Logo");
                await refresh();
              }}
            >
              移除 Logo
            </Button>
          )}
        </Space>
        <p style={{ color: "#8c8c8c", fontSize: 12, marginTop: 12 }}>
          建议透明底 PNG/WebP,高度约 32–48px,最大 2MB。
        </p>
      </Card>
    </Card>
  );
}