ChenYu пре 7 месеци
родитељ
комит
78b2a4e796
3 измењених фајлова са 73 додато и 5 уклоњено
  1. 4 0
      src/i18n/locales/en.json
  2. 4 0
      src/i18n/locales/zh.json
  3. 65 5
      src/pages/config/ConfigPage.tsx

+ 4 - 0
src/i18n/locales/en.json

@@ -621,6 +621,10 @@
     "fieldKey": "Config Key",
     "fieldValue": "Config Value",
     "fieldRemark": "Remark",
+    "advanced": "Advanced",
+    "appendUploadBtn": "Upload And Append",
+    "appendUploadTip": "After each successful upload, the returned value will be appended to the config value field and can still be edited manually",
+    "uploadAppendSuccess": "File uploaded and appended to the config value",
     "keyPlaceholder": "Enter a unique config key, e.g. site_name",
     "valuePlaceholder": "Enter config value",
     "remarkPlaceholder": "Enter remark"

+ 4 - 0
src/i18n/locales/zh.json

@@ -621,6 +621,10 @@
     "fieldKey": "配置 Key",
     "fieldValue": "配置值",
     "fieldRemark": "说明",
+    "advanced": "高级",
+    "appendUploadBtn": "上传文件并追加",
+    "appendUploadTip": "每次上传成功后,返回值会自动追加到配置值输入框中,仍可手动修改",
+    "uploadAppendSuccess": "文件上传成功,已追加到配置值",
     "keyPlaceholder": "请输入唯一的配置 Key,如 site_name",
     "valuePlaceholder": "请输入配置值",
     "remarkPlaceholder": "请输入配置说明"

+ 65 - 5
src/pages/config/ConfigPage.tsx

@@ -11,6 +11,8 @@ import {
   Form,
   Input,
   Space,
+  Switch,
+  Upload,
 } from "antd";
 import type { TableProps } from "antd";
 import {
@@ -19,7 +21,10 @@ import {
   DeleteOutlined,
   ReloadOutlined,
   SearchOutlined,
+  UploadOutlined,
+  LoadingOutlined,
 } from "@ant-design/icons";
+import type { RcFile } from "antd/es/upload";
 import type { ConfigForm, ConfigItem } from "@/api/config";
 import {
   addConfig,
@@ -28,6 +33,7 @@ import {
   getConfigPage,
   updateConfig,
 } from "@/api/config";
+import { uploadImage } from "@/api/storage";
 
 const { Title, Text } = Typography;
 const { TextArea } = Input;
@@ -39,6 +45,8 @@ export function ConfigPage() {
   const [submitting, setSubmitting] = useState(false);
   const [modalOpen, setModalOpen] = useState(false);
   const [editingKey, setEditingKey] = useState<string | null>(null);
+  const [advancedValue, setAdvancedValue] = useState(false);
+  const [uploading, setUploading] = useState(false);
   const [total, setTotal] = useState(0);
   const [keyword, setKeyword] = useState("");
   const [query, setQuery] = useState({ page: 1, size: 10, keyword: undefined as string | undefined });
@@ -76,12 +84,14 @@ export function ConfigPage() {
 
   function openAdd() {
     setEditingKey(null);
+    setAdvancedValue(false);
     form.resetFields();
     setModalOpen(true);
   }
 
   async function openEdit(record: ConfigItem) {
     setEditingKey(record.configKey);
+    setAdvancedValue(false);
     setModalOpen(true);
     try {
       const detail = await getConfig(record.configKey);
@@ -97,6 +107,22 @@ export function ConfigPage() {
     }
   }
 
+  async function handleValueUpload(file: RcFile) {
+    setUploading(true);
+    try {
+      const url = await uploadImage(file, "config/value/");
+      const currentValue = form.getFieldValue("configValue") || "";
+      const nextValue = currentValue ? `${currentValue}\n${url}` : url;
+      form.setFieldValue("configValue", nextValue);
+      message.success(t("config.uploadAppendSuccess"));
+    } catch {
+      message.error(t("upload.failed"));
+    } finally {
+      setUploading(false);
+    }
+    return false;
+  }
+
   async function handleSubmit() {
     try {
       const values = await form.validateFields();
@@ -110,6 +136,7 @@ export function ConfigPage() {
       }
       setModalOpen(false);
       setEditingKey(null);
+      setAdvancedValue(false);
       form.resetFields();
       fetchData();
     } catch {
@@ -268,6 +295,7 @@ export function ConfigPage() {
         onCancel={() => {
           setModalOpen(false);
           setEditingKey(null);
+          setAdvancedValue(false);
           form.resetFields();
         }}
         onOk={handleSubmit}
@@ -285,11 +313,43 @@ export function ConfigPage() {
               disabled={!!editingKey}
             />
           </Form.Item>
-          <Form.Item name="configValue" label={t("config.fieldValue")}>
-            <TextArea
-              rows={4}
-              placeholder={t("config.valuePlaceholder")}
-            />
+          <Form.Item
+            label={(
+              <div className="flex items-center gap-3">
+                <span>{t("config.fieldValue")}</span>
+                <div className="flex items-center gap-2">
+                  <span className="text-xs text-gray-500">{t("config.advanced")}</span>
+                  <Switch size="small" checked={advancedValue} onChange={setAdvancedValue} />
+                </div>
+              </div>
+            )}
+          >
+            <div>
+              <Form.Item name="configValue" noStyle>
+                <TextArea
+                  rows={4}
+                  placeholder={t("config.valuePlaceholder")}
+                />
+              </Form.Item>
+              {advancedValue && (
+                <div className="mt-3 flex items-center gap-3 flex-wrap">
+                  <Upload
+                    showUploadList={false}
+                    beforeUpload={handleValueUpload}
+                  >
+                    <Button
+                      icon={uploading ? <LoadingOutlined /> : <UploadOutlined />}
+                      loading={uploading}
+                    >
+                      {t("config.appendUploadBtn")}
+                    </Button>
+                  </Upload>
+                  <Text type="secondary" style={{ fontSize: 12 }}>
+                    {t("config.appendUploadTip")}
+                  </Text>
+                </div>
+              )}
+            </div>
           </Form.Item>
           <Form.Item name="remark" label={t("config.fieldRemark")}>
             <TextArea