This commit is contained in:
2026-04-24 20:08:23 +08:00
parent b7ba9a26b0
commit 86b9456ecd
18 changed files with 661 additions and 61 deletions
+5 -1
View File
@@ -2,4 +2,8 @@ import request from '@/utils/request';
export const getServiceFeeConfig = () => request.get('/admin/config/service-fee');
export const updateServiceFeeConfig = (rate: number) => request.put('/admin/config/service-fee', { rate });
export const updateServiceFeeConfig = (rate: number) => request.put('/admin/config/service-fee', { rate });
export const getStorageConfig = () => request.get('/admin/config/storage');
export const updateStorageConfig = (data: Record<string, string>) => request.put('/admin/config/storage', data);
@@ -0,0 +1,134 @@
import React, { useEffect, useState } from 'react';
import { Card, Form, Select, Input, Button, message, Spin, Divider } from 'antd';
import { getStorageConfig, updateStorageConfig } from '@/api/config';
const providerOptions = [
{ value: 'local', label: '本地存储' },
{ value: 'tencent_cos', label: '腾讯云 COS' },
{ value: 'aliyun_oss', label: '阿里云 OSS' },
];
const StorageSettings: React.FC = () => {
const [loading, setLoading] = useState(false);
const [saving, setSaving] = useState(false);
const [provider, setProvider] = useState<string>('local');
const [form] = Form.useForm();
const fetchConfig = async () => {
setLoading(true);
try {
const res: any = await getStorageConfig();
const data = res.data || {};
setProvider(data.storage_provider || 'local');
form.setFieldsValue({
storage_provider: data.storage_provider || 'local',
storage_local_path: data.storage_local_path || './uploads',
storage_cos_bucket: data.storage_cos_bucket || '',
storage_cos_region: data.storage_cos_region || '',
storage_cos_secret_id: data.storage_cos_secret_id || '',
storage_cos_secret_key: data.storage_cos_secret_key || '',
storage_oss_bucket: data.storage_oss_bucket || '',
storage_oss_region: data.storage_oss_region || '',
storage_oss_access_key_id: data.storage_oss_access_key_id || '',
storage_oss_access_key_secret: data.storage_oss_access_key_secret || '',
});
} catch {
form.setFieldsValue({ storage_provider: 'local', storage_local_path: './uploads' });
} finally {
setLoading(false);
}
};
useEffect(() => { fetchConfig(); }, []);
const handleSave = async () => {
try {
const values = await form.validateFields();
setSaving(true);
const data: Record<string, string> = {};
for (const [key, value] of Object.entries(values)) {
if (value !== undefined && value !== null && value !== '') {
data[key] = String(value);
}
}
data.storage_provider = provider;
await updateStorageConfig(data);
message.success('存储配置已保存');
} catch (e: any) {
if (e?.message) message.error(e.message);
} finally {
setSaving(false);
}
};
if (loading) return <Spin size="large" style={{ display: 'block', marginTop: 100 }} />;
return (
<Card title="存储配置" style={{ maxWidth: 700 }}>
<Form form={form} layout="vertical">
<Form.Item label="存储方式" name="storage_provider" rules={[{ required: true, message: '请选择存储方式' }]}>
<Select options={providerOptions} onChange={(v) => setProvider(v)} />
</Form.Item>
{provider === 'local' && (
<>
<Form.Item label="存储路径" name="storage_local_path" extra="相对于服务启动目录">
<Input placeholder="./uploads" />
</Form.Item>
<div style={{ color: '#888', fontSize: 13, marginBottom: 16 }}>
/uploads/ 访
</div>
</>
)}
{provider === 'tencent_cos' && (
<>
<Divider orientation="left" plain> COS </Divider>
<Form.Item label="Bucket" name="storage_cos_bucket" rules={[{ required: true, message: '请输入 Bucket' }]}>
<Input placeholder="example-1250000000" />
</Form.Item>
<Form.Item label="Region" name="storage_cos_region" rules={[{ required: true, message: '请输入 Region' }]}>
<Input placeholder="ap-guangzhou" />
</Form.Item>
<Form.Item label="SecretId" name="storage_cos_secret_id" rules={[{ required: true, message: '请输入 SecretId' }]}>
<Input.Password placeholder="请输入 SecretId" />
</Form.Item>
<Form.Item label="SecretKey" name="storage_cos_secret_key" rules={[{ required: true, message: '请输入 SecretKey' }]}>
<Input.Password placeholder="请输入 SecretKey" />
</Form.Item>
<div style={{ color: '#888', fontSize: 13, marginBottom: 16 }}>
SDK: pnpm add cos-nodejs-sdk-v5
</div>
</>
)}
{provider === 'aliyun_oss' && (
<>
<Divider orientation="left" plain> OSS </Divider>
<Form.Item label="Bucket" name="storage_oss_bucket" rules={[{ required: true, message: '请输入 Bucket' }]}>
<Input placeholder="my-bucket" />
</Form.Item>
<Form.Item label="Region" name="storage_oss_region" rules={[{ required: true, message: '请输入 Region' }]}>
<Input placeholder="oss-cn-hangzhou" />
</Form.Item>
<Form.Item label="AccessKeyId" name="storage_oss_access_key_id" rules={[{ required: true, message: '请输入 AccessKeyId' }]}>
<Input.Password placeholder="请输入 AccessKeyId" />
</Form.Item>
<Form.Item label="AccessKeySecret" name="storage_oss_access_key_secret" rules={[{ required: true, message: '请输入 AccessKeySecret' }]}>
<Input.Password placeholder="请输入 AccessKeySecret" />
</Form.Item>
<div style={{ color: '#888', fontSize: 13, marginBottom: 16 }}>
SDK: pnpm add ali-oss
</div>
</>
)}
<Form.Item>
<Button type="primary" loading={saving} onClick={handleSave}></Button>
</Form.Item>
</Form>
</Card>
);
};
export default StorageSettings;
@@ -1,6 +1,7 @@
import React, { useEffect, useState } from 'react';
import { Card, Form, InputNumber, Button, message, Spin, Divider } from 'antd';
import { getServiceFeeConfig, updateServiceFeeConfig } from '@/api/config';
import StorageSettings from './StorageSettings';
const SystemSettings: React.FC = () => {
const [loading, setLoading] = useState(false);
@@ -41,7 +42,7 @@ const SystemSettings: React.FC = () => {
<div>
<h2 style={{ marginBottom: 24 }}></h2>
<Card title="服务费配置" style={{ maxWidth: 600 }}>
<Card title="服务费配置" style={{ maxWidth: 600, marginBottom: 24 }}>
<Form form={form} layout="vertical">
<Form.Item
label="软件服务费比例"
@@ -81,6 +82,8 @@ const SystemSettings: React.FC = () => {
<p> = ¥5.00 = ¥95.00</p>
</div>
</Card>
<StorageSettings />
</div>
);
};