Files
tashow-manager/src/components/Upload/UploadCard/index.tsx
wuxichen 4e9ebc76f7
Some checks failed
coverage CI / build (push) Has been cancelled
feat: upload
2025-09-25 13:51:24 +08:00

177 lines
4.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import {
DeleteOutlined,
FileTextOutlined,
PlayCircleOutlined,
} from '@ant-design/icons';
import { message, Upload } from 'antd';
import type { RcFile, UploadFile, UploadProps } from 'antd/lib/upload';
import React, { useState } from 'react';
import { createSample, getSample } from '@/services/ai/sample';
import styles from './index.module.less';
const { Dragger } = Upload;
interface AudioUploaderProps {
value?: UploadFile[] | UploadFile | null;
onChange?: (file: UploadFile[] | UploadFile | null) => void;
maxSize?: number;
accept?: string;
disabled?: boolean;
maxCount?: number;
placeholder?: string;
}
const AudioUploader: React.FC<AudioUploaderProps> = ({
value,
onChange,
maxSize = 10,
accept = '.mp3,.wav,.flac,.aac,.ogg',
disabled = false,
maxCount = 10,
placeholder = '点击或拖拽音频文件到此区域上传',
}) => {
const [fileList, setFileList] = useState<UploadFile[]>(() => {
if (Array.isArray(value)) {
return value;
} else if (value) {
return [value];
}
return [];
});
const [uploading, setUploading] = useState<boolean>(false);
const beforeUpload = (file: RcFile): boolean => {
const isAudio = file.type.startsWith('audio/');
if (!isAudio) {
message.error('只能上传音频文件!');
return false;
}
// 检查文件大小
const isLtMaxSize = file.size / 1024 / 1024 < maxSize;
if (!isLtMaxSize) {
message.error(`音频文件大小不能超过 ${maxSize}MB`);
return false;
}
// 检查文件数量限制
if (fileList.length >= maxCount) {
message.error(`最多只能上传 ${maxCount} 个文件!`);
return false;
}
return true;
};
// 实际的后端接口上传
const uploadToServer = async (file: File) => {
const formData = new FormData();
formData.append('file', file);
// formData.append("type", "audio"); // 可以添加额外参数
const response = await createSample(formData);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return response.json();
};
const customRequest: UploadProps['customRequest'] = async (options) => {
const { file, onSuccess, onError, onProgress } = options;
try {
setUploading(true);
// 模拟进度更新
onProgress?.({ percent: 10 });
// 调用后端接口
const result = await uploadToServer(file as File);
onProgress?.({ percent: 100 });
if (result.success && result.data) {
// 构造返回数据
const responseData = {
url: result.data.url,
name: result.data.filename || (file as File).name,
uid: (file as any).uid,
status: 'done' as const,
response: result.data,
};
onSuccess?.(responseData);
message.success('音频上传成功!');
} else {
throw new Error(result.message || '上传失败');
}
} catch (error) {
console.error('Upload error:', error);
onError?.(error as Error);
message.error(`上传失败: ${(error as Error).message}`);
} finally {
setUploading(false);
}
};
const handleChange: UploadProps['onChange'] = ({
fileList: newFileList,
file,
}) => {
setFileList(newFileList);
onChange?.(newFileList);
};
const handleRemove = (file: UploadFile): boolean => {
const newFileList = fileList.filter((item) => item.uid !== file.uid);
setFileList(newFileList);
onChange?.(newFileList);
return true;
};
const handlePreview = (file: UploadFile): void => {
const audioUrl = file.url || (file.response as any)?.url;
if (audioUrl) {
const audio = new Audio(audioUrl);
audio.play().catch(() => {
message.error('音频播放失败');
});
}
};
const uploadProps: UploadProps = {
name: 'file',
multiple: true,
fileList,
accept,
disabled: disabled || uploading,
beforeUpload,
customRequest,
// onChange: handleChange,
onRemove: handleRemove,
onPreview: handlePreview,
showUploadList: {
showPreviewIcon: true,
showRemoveIcon: true,
previewIcon: <PlayCircleOutlined />,
removeIcon: <DeleteOutlined />,
},
};
return (
<div className={styles['uploader-card']}>
<Dragger {...uploadProps}>
<p className="">
<FileTextOutlined style={{ fontSize: 36 }} />
</p>
<p className="ant-upload-text">{placeholder}</p>
<p className="ant-upload-hint">
{accept} {maxCount}
</p>
</Dragger>
</div>
);
};
export default AudioUploader;