Files
tashow-manager/src/components/Upload/UploadCard/index.tsx
2025-10-13 16:50:21 +08:00

168 lines
4.5 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 } 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('files', file);
const response = await createSample(formData);
message.success('上传成功!');
return response;
};
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);
console.log(result, 'res');
onProgress?.({ percent: 100 });
if (result) {
// 构造返回数据
const responseData = {
url: result[0].fileUrl,
name: result[0].fileName || (file as File).name,
uid: (file as any).uid,
status: 'done' as const,
response: result,
};
onSuccess?.(responseData);
} 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;