mirror of
https://gitee.com/ccnetcore/Yi
synced 2026-03-12 04:29:28 +08:00
145 lines
3.6 KiB
TypeScript
145 lines
3.6 KiB
TypeScript
import { ElMessage } from 'element-plus';
|
|
import { useImageCompression, type CompressionLevel } from './useImageCompression';
|
|
import type { FileItem } from '@/stores/modules/files';
|
|
|
|
export interface UseFilePasteOptions {
|
|
/** 最大文件大小 (字节) */
|
|
maxFileSize?: number;
|
|
/** 最大总内容长度 */
|
|
maxTotalContentLength?: number;
|
|
/** 压缩级别配置 */
|
|
compressionLevels?: CompressionLevel[];
|
|
/** 获取当前文件列表总长度 */
|
|
getCurrentTotalLength: () => number;
|
|
/** 添加文件到列表 */
|
|
addFiles: (files: FileItem[]) => void;
|
|
/** 是否只接受图片 (默认true) */
|
|
imagesOnly?: boolean;
|
|
}
|
|
|
|
/**
|
|
* 从剪贴板数据项中提取文件
|
|
*/
|
|
function extractFilesFromItems(items: DataTransferItemList): File[] {
|
|
const files: File[] = [];
|
|
for (let i = 0; i < items.length; i++) {
|
|
const item = items[i];
|
|
if (item.kind === 'file') {
|
|
const file = item.getAsFile();
|
|
if (file) {
|
|
files.push(file);
|
|
}
|
|
}
|
|
}
|
|
return files;
|
|
}
|
|
|
|
/**
|
|
* Composable: 处理粘贴事件中的文件
|
|
*/
|
|
export function useFilePaste(options: UseFilePasteOptions) {
|
|
const {
|
|
maxFileSize = 3 * 1024 * 1024,
|
|
maxTotalContentLength = 150000,
|
|
compressionLevels,
|
|
getCurrentTotalLength,
|
|
addFiles,
|
|
imagesOnly = true,
|
|
} = options;
|
|
|
|
const { tryCompressToLimit } = useImageCompression();
|
|
|
|
/**
|
|
* 处理单个粘贴的文件
|
|
*/
|
|
async function processPastedFile(
|
|
file: File,
|
|
currentTotalLength: number,
|
|
): Promise<FileItem | null> {
|
|
// 验证文件大小
|
|
if (file.size > maxFileSize) {
|
|
ElMessage.error(`文件 ${file.name} 超过 3MB 限制,已跳过`);
|
|
return null;
|
|
}
|
|
|
|
const isImage = file.type.startsWith('image/');
|
|
|
|
if (isImage) {
|
|
try {
|
|
const result = await tryCompressToLimit(
|
|
file,
|
|
currentTotalLength,
|
|
maxTotalContentLength,
|
|
compressionLevels,
|
|
);
|
|
|
|
if (!result) {
|
|
ElMessage.error(`${file.name} 图片内容过大,请压缩后上传`);
|
|
return null;
|
|
}
|
|
|
|
return {
|
|
uid: crypto.randomUUID(),
|
|
name: file.name,
|
|
fileSize: file.size,
|
|
file,
|
|
maxWidth: '200px',
|
|
showDelIcon: true,
|
|
imgPreview: true,
|
|
imgVariant: 'square',
|
|
url: result.base64,
|
|
isUploaded: true,
|
|
base64: result.base64,
|
|
fileType: 'image',
|
|
};
|
|
}
|
|
catch (error) {
|
|
console.error('处理图片失败:', error);
|
|
ElMessage.error(`${file.name} 处理失败`);
|
|
return null;
|
|
}
|
|
}
|
|
else if (!imagesOnly) {
|
|
// 如果不是仅图片模式,可以在这里处理其他类型文件
|
|
ElMessage.warning(`${file.name} 不支持粘贴,请使用上传按钮`);
|
|
return null;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* 处理粘贴事件
|
|
*/
|
|
async function handlePaste(event: ClipboardEvent) {
|
|
const items = event.clipboardData?.items;
|
|
if (!items) return;
|
|
|
|
const files = extractFilesFromItems(items);
|
|
if (files.length === 0) return;
|
|
|
|
event.preventDefault();
|
|
|
|
let totalContentLength = getCurrentTotalLength();
|
|
const newFiles: FileItem[] = [];
|
|
|
|
for (const file of files) {
|
|
const processedFile = await processPastedFile(file, totalContentLength);
|
|
if (processedFile) {
|
|
newFiles.push(processedFile);
|
|
totalContentLength += Math.floor((processedFile.base64?.length || 0) * 0.5);
|
|
}
|
|
}
|
|
|
|
if (newFiles.length > 0) {
|
|
addFiles(newFiles);
|
|
ElMessage.success(`已添加 ${newFiles.length} 个文件`);
|
|
}
|
|
}
|
|
|
|
return {
|
|
handlePaste,
|
|
processPastedFile,
|
|
};
|
|
}
|