181 lines
6.2 KiB
TypeScript
181 lines
6.2 KiB
TypeScript
/*
|
|
* @Author: ZhaoYing
|
|
* @Date: 2026-03-05
|
|
* @Last Modified by: ZhaoYing
|
|
* @Last Modified time: 2026-03-18 20:29:28
|
|
*/
|
|
import { forwardRef, useImperativeHandle, useState } from 'react';
|
|
import { Form, InputNumber, Flex, Switch, Row, Col, Radio } from 'antd';
|
|
import { useTranslation } from 'react-i18next';
|
|
import clsx from 'clsx';
|
|
|
|
import RbModal from '@/components/RbModal';
|
|
import type { FeaturesConfigForm } from '../../types'
|
|
|
|
type FileUpload = Omit<FeaturesConfigForm['file_upload'], 'settings'>
|
|
|
|
interface FileUploadSettingModalRef {
|
|
handleOpen: (values?: FileUpload) => void;
|
|
handleClose: () => void;
|
|
}
|
|
|
|
interface FileUploadSettingModalProps {
|
|
onSave: (values: FileUpload) => void;
|
|
}
|
|
|
|
const fileTypeOptions = [
|
|
{
|
|
type: 'document',
|
|
icon: <div className="rb:size-9 rb:bg-cover rb:bg-[url('@/assets/images/file/txt.svg')]"></div>,
|
|
formats: 'TXT, PDF, DOC, DOCX, XLSX, CSV, JSON',
|
|
},
|
|
{
|
|
type: 'image',
|
|
icon: <div className="rb:size-9 rb:bg-cover rb:bg-[url('@/assets/images/file/image.svg')]"></div>,
|
|
formats: 'JPG, JPEG, PNG, GIF, WEBP',
|
|
},
|
|
{
|
|
type: 'audio',
|
|
icon: <div className="rb:size-9 rb:bg-cover rb:bg-[url('@/assets/images/file/audio.svg')]"></div>,
|
|
formats: 'MP3, M4A, WAV, OGG, FLAC',
|
|
},
|
|
{
|
|
type: 'video',
|
|
icon: <div className="rb:size-9 rb:bg-cover rb:bg-[url('@/assets/images/file/video.svg')]"></div>,
|
|
formats: 'MP4, MOV, AVI, WEBM',
|
|
},
|
|
];
|
|
|
|
const defaultValues: FileUpload = {
|
|
enabled: false,
|
|
image_enabled: false,
|
|
image_max_size_mb: 20,
|
|
image_allowed_extensions: ['png', 'jpg', 'jpeg', 'gif', 'webp'],
|
|
audio_enabled: false,
|
|
audio_max_size_mb: 50,
|
|
audio_allowed_extensions: ['mp3', 'wav', 'm4a', 'ogg', 'flac'],
|
|
document_enabled: false,
|
|
document_max_size_mb: 100,
|
|
document_allowed_extensions: ['pdf', 'docx', 'xlsx', 'txt', 'csv', 'json'],
|
|
video_enabled: false,
|
|
video_max_size_mb: 500,
|
|
video_allowed_extensions: ['mp4', 'mov', 'avi', 'webm'],
|
|
max_file_count: 5,
|
|
allowed_transfer_methods: 'both'
|
|
}
|
|
|
|
const FileUploadSettingModal = forwardRef<FileUploadSettingModalRef, FileUploadSettingModalProps>(({
|
|
onSave,
|
|
}, ref) => {
|
|
const { t } = useTranslation();
|
|
const [visible, setVisible] = useState(false);
|
|
const [form] = Form.useForm<FileUpload>();
|
|
const values = Form.useWatch([], form)
|
|
|
|
const handleClose = () => {
|
|
setVisible(false);
|
|
form.resetFields();
|
|
};
|
|
|
|
const handleOpen = (values?: FileUpload) => {
|
|
setVisible(true);
|
|
if (values) {
|
|
const methods = values.allowed_transfer_methods || ['local_file', 'remote_url']
|
|
const transferMethod = Array.isArray(methods)
|
|
? methods.length === 2 ? 'both' : methods[0]
|
|
: methods
|
|
form.setFieldsValue({ ...values, allowed_transfer_methods: transferMethod as any })
|
|
} else {
|
|
form.setFieldsValue(defaultValues)
|
|
}
|
|
};
|
|
|
|
const handleSave = async () => {
|
|
const vals = await form.validateFields();
|
|
const methodMap: Record<string, string[]> = {
|
|
local_file: ['local_file'],
|
|
remote_url: ['remote_url'],
|
|
both: ['local_file', 'remote_url'],
|
|
}
|
|
onSave({ ...vals, allowed_transfer_methods: methodMap[vals.allowed_transfer_methods as unknown as string] ?? [] });
|
|
handleClose();
|
|
};
|
|
|
|
useImperativeHandle(ref, () => ({
|
|
handleOpen,
|
|
handleClose
|
|
}));
|
|
|
|
return (
|
|
<RbModal
|
|
title={t('application.settings')}
|
|
open={visible}
|
|
onCancel={handleClose}
|
|
onOk={handleSave}
|
|
width={600}
|
|
>
|
|
<Form form={form} layout="vertical" initialValues={defaultValues}>
|
|
<Form.Item
|
|
label={t('application.uploadType')}
|
|
name="allowed_transfer_methods"
|
|
>
|
|
<Radio.Group block buttonStyle="solid">
|
|
<Radio.Button value="local_file">{t('application.local')}</Radio.Button>
|
|
<Radio.Button value="remote_url">URL</Radio.Button>
|
|
<Radio.Button value="both">{t('application.both')}</Radio.Button>
|
|
</Radio.Group>
|
|
</Form.Item>
|
|
|
|
<div className="rb:text-[12px] rb:text-[#5B6167] rb:mb-1">{t('application.maxCount')}</div>
|
|
<Form.Item label={t('application.maxCount')} name="max_file_count">
|
|
<InputNumber min={1} max={100} precision={0} className="rb:w-full!" placeholder={t('common.pleaseEnter')} />
|
|
</Form.Item>
|
|
|
|
<Form.Item label={t('application.supportedTypes')}>
|
|
<Flex vertical gap={12}>
|
|
{fileTypeOptions.map((option) => {
|
|
const enabledKey = `${option.type}_enabled` as keyof FileUpload
|
|
const sizeKey = `${option.type}_max_size_mb` as keyof FileUpload
|
|
const isEnabled = values?.[enabledKey]
|
|
return (
|
|
<div
|
|
key={option.type}
|
|
className={clsx('rb:border rb:border-[#DFE4ED] rb:rounded-lg rb:p-3', {
|
|
'rb:bg-[#f5f7fc]': isEnabled
|
|
})}
|
|
>
|
|
<Row gutter={12}>
|
|
<Col flex="36px" className="rb:self-center">{option.icon}</Col>
|
|
<Col flex="1">
|
|
<Flex align="center" justify="space-between">
|
|
<Flex vertical>
|
|
<div className="rb:font-medium">{t(`application.${option.type}`)}</div>
|
|
<div className="rb:text-[12px] rb:text-[#5B6167]">{option.formats}</div>
|
|
</Flex>
|
|
<Form.Item name={enabledKey} valuePropName="checked" noStyle>
|
|
<Switch />
|
|
</Form.Item>
|
|
</Flex>
|
|
</Col>
|
|
</Row>
|
|
{isEnabled && (
|
|
<Flex align="center" gap={12} className="rb:mt-3! rb:pt-3! rb:border-t rb:border-[#DFE4ED]">
|
|
<div>{t('application.singleMaxSize')}: </div>
|
|
<Form.Item name={sizeKey} noStyle>
|
|
<InputNumber min={1} max={500} suffix="MB" className="rb:flex-1" />
|
|
</Form.Item>
|
|
<Form.Item name={`${option.type}_allowed_extensions`} hidden />
|
|
</Flex>
|
|
)}
|
|
</div>
|
|
)
|
|
})}
|
|
</Flex>
|
|
</Form.Item>
|
|
</Form>
|
|
</RbModal>
|
|
);
|
|
});
|
|
|
|
export default FileUploadSettingModal;
|