mirror of
https://gitee.com/ccnetcore/Yi
synced 2026-03-20 08:26:37 +08:00
feat: 消息ui优化
This commit is contained in:
144
Yi.Ai.Vue3/src/composables/chat/useFilePaste.ts
Normal file
144
Yi.Ai.Vue3/src/composables/chat/useFilePaste.ts
Normal file
@@ -0,0 +1,144 @@
|
||||
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,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user