Files
vf_react/src/views/AgentChat/hooks/useFileUpload.ts

132 lines
3.2 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.

// src/views/AgentChat/hooks/useFileUpload.ts
// 文件上传 Hook - 处理文件选择、预览、删除
import { useState, useRef } from 'react';
import type { ChangeEvent, RefObject } from 'react';
/**
* 上传文件数据结构
*/
export interface UploadedFile {
/** 文件名 */
name: string;
/** 文件大小(字节) */
size: number;
/** 文件 MIME 类型 */
type: string;
/** 文件预览 URL使用 URL.createObjectURL 创建) */
url: string;
}
/**
* useFileUpload Hook 返回值
*/
export interface UseFileUploadReturn {
/** 已上传文件列表 */
uploadedFiles: UploadedFile[];
/** 文件输入框引用(用于触发文件选择) */
fileInputRef: RefObject<HTMLInputElement>;
/** 处理文件选择事件 */
handleFileSelect: (event: ChangeEvent<HTMLInputElement>) => void;
/** 删除指定文件 */
removeFile: (index: number) => void;
/** 清空所有文件 */
clearFiles: () => void;
}
/**
* useFileUpload Hook
*
* 处理文件上传相关逻辑(选择、预览、删除)
*
* @returns UseFileUploadReturn
*
* @example
* ```tsx
* const { uploadedFiles, fileInputRef, handleFileSelect, removeFile } = useFileUpload();
*
* return (
* <>
* <input
* ref={fileInputRef}
* type="file"
* multiple
* accept="image/*,.pdf,.doc,.docx,.txt"
* onChange={handleFileSelect}
* style={{ display: 'none' }}
* />
* <Button onClick={() => fileInputRef.current?.click()}>上传文件</Button>
* {uploadedFiles.map((file, idx) => (
* <Tag key={idx}>
* {file.name}
* <TagCloseButton onClick={() => removeFile(idx)} />
* </Tag>
* ))}
* </>
* );
* ```
*/
export const useFileUpload = (): UseFileUploadReturn => {
const [uploadedFiles, setUploadedFiles] = useState<UploadedFile[]>([]);
const fileInputRef = useRef<HTMLInputElement>(null);
/**
* 处理文件选择事件
*/
const handleFileSelect = (event: ChangeEvent<HTMLInputElement>) => {
const files = Array.from(event.target.files || []);
const fileData: UploadedFile[] = files.map((file) => ({
name: file.name,
size: file.size,
type: file.type,
// 创建本地预览 URL实际上传时需要转换为 base64 或上传到服务器)
url: URL.createObjectURL(file),
}));
setUploadedFiles((prev) => [...prev, ...fileData]);
// 清空 input value允许重复选择同一文件
if (event.target) {
event.target.value = '';
}
};
/**
* 删除指定索引的文件
*/
const removeFile = (index: number) => {
setUploadedFiles((prev) => {
// 释放 URL.createObjectURL 创建的内存
const file = prev[index];
if (file?.url) {
URL.revokeObjectURL(file.url);
}
return prev.filter((_, i) => i !== index);
});
};
/**
* 清空所有文件
*/
const clearFiles = () => {
// 释放所有 URL 内存
uploadedFiles.forEach((file) => {
if (file.url) {
URL.revokeObjectURL(file.url);
}
});
setUploadedFiles([]);
};
return {
uploadedFiles,
fileInputRef,
handleFileSelect,
removeFile,
clearFiles,
};
};