fix: 网页版增加对话图片支持
This commit is contained in:
@@ -1,18 +1,17 @@
|
||||
<!-- 文件上传 -->
|
||||
<script setup lang="ts">
|
||||
import type { FilesCardProps } from 'vue-element-plus-x/types/FilesCard';
|
||||
import type { FileItem } from '@/stores/modules/files';
|
||||
import { useFileDialog } from '@vueuse/core';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import Popover from '@/components/Popover/index.vue';
|
||||
import SvgIcon from '@/components/SvgIcon/index.vue';
|
||||
import { useFilesStore } from '@/stores/modules/files';
|
||||
|
||||
type FilesList = FilesCardProps & {
|
||||
file: File;
|
||||
};
|
||||
|
||||
const filesStore = useFilesStore();
|
||||
|
||||
// 文件大小限制 3MB
|
||||
const MAX_FILE_SIZE = 3 * 1024 * 1024;
|
||||
|
||||
/* 弹出面板 开始 */
|
||||
const popoverStyle = ref({
|
||||
padding: '4px',
|
||||
@@ -26,31 +25,129 @@ const popoverRef = ref();
|
||||
/* 弹出面板 结束 */
|
||||
|
||||
const { reset, open, onChange } = useFileDialog({
|
||||
// 允许所有图片文件,文档文件,音视频文件
|
||||
accept: 'image/*,video/*,audio/*,application/*',
|
||||
// 允许图片和文件
|
||||
accept: 'image/*,application/pdf,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
||||
directory: false, // 是否允许选择文件夹
|
||||
multiple: true, // 是否允许多选
|
||||
});
|
||||
|
||||
onChange((files) => {
|
||||
// 压缩图片
|
||||
function compressImage(file: File, maxWidth = 1024, maxHeight = 1024, quality = 0.8): Promise<Blob> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const reader = new FileReader();
|
||||
reader.onload = (e) => {
|
||||
const img = new Image();
|
||||
img.onload = () => {
|
||||
const canvas = document.createElement('canvas');
|
||||
let width = img.width;
|
||||
let height = img.height;
|
||||
|
||||
// 计算缩放比例
|
||||
if (width > maxWidth || height > maxHeight) {
|
||||
const ratio = Math.min(maxWidth / width, maxHeight / height);
|
||||
width = width * ratio;
|
||||
height = height * ratio;
|
||||
}
|
||||
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
|
||||
const ctx = canvas.getContext('2d')!;
|
||||
ctx.drawImage(img, 0, 0, width, height);
|
||||
|
||||
// 转换为 Blob
|
||||
canvas.toBlob(
|
||||
(blob) => {
|
||||
if (blob) {
|
||||
resolve(blob);
|
||||
} else {
|
||||
reject(new Error('压缩失败'));
|
||||
}
|
||||
},
|
||||
file.type,
|
||||
quality
|
||||
);
|
||||
};
|
||||
img.onerror = reject;
|
||||
img.src = e.target?.result as string;
|
||||
};
|
||||
reader.onerror = reject;
|
||||
reader.readAsDataURL(file);
|
||||
});
|
||||
}
|
||||
|
||||
// 将 Blob 转换为 base64
|
||||
function blobToBase64(blob: Blob): Promise<string> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const reader = new FileReader();
|
||||
reader.onload = () => {
|
||||
resolve(reader.result as string);
|
||||
};
|
||||
reader.onerror = reject;
|
||||
reader.readAsDataURL(blob);
|
||||
});
|
||||
}
|
||||
|
||||
onChange(async (files) => {
|
||||
if (!files)
|
||||
return;
|
||||
const arr = [] as FilesList[];
|
||||
|
||||
const arr = [] as FileItem[];
|
||||
|
||||
for (let i = 0; i < files!.length; i++) {
|
||||
const file = files![i];
|
||||
|
||||
// 验证文件大小
|
||||
if (file.size > MAX_FILE_SIZE) {
|
||||
ElMessage.error(`文件 ${file.name} 超过 3MB 限制,已跳过`);
|
||||
continue;
|
||||
}
|
||||
|
||||
const isImage = file.type.startsWith('image/');
|
||||
|
||||
// 压缩并转换为base64
|
||||
let base64 = '';
|
||||
let previewUrl = '';
|
||||
if (isImage) {
|
||||
try {
|
||||
// 先压缩图片
|
||||
const compressedBlob = await compressImage(file, 1024, 1024, 0.8);
|
||||
// 再转换为 base64
|
||||
base64 = await blobToBase64(compressedBlob);
|
||||
// 使用压缩后的图片作为预览
|
||||
previewUrl = base64;
|
||||
|
||||
// 计算压缩比例
|
||||
const originalSize = (file.size / 1024).toFixed(2);
|
||||
const compressedSize = (compressedBlob.size / 1024).toFixed(2);
|
||||
console.log(`图片压缩: ${file.name} - 原始: ${originalSize}KB, 压缩后: ${compressedSize}KB`);
|
||||
} catch (error) {
|
||||
console.error('压缩图片失败:', error);
|
||||
ElMessage.error(`${file.name} 压缩失败`);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
arr.push({
|
||||
uid: crypto.randomUUID(), // 不写 uid,文件列表展示不出来,elx 1.2.0 bug 待修复
|
||||
uid: crypto.randomUUID(), // 不写 uid,文件列表展示不出来,elx 1.2.0 bug 待修复
|
||||
name: file.name,
|
||||
fileSize: file.size,
|
||||
file,
|
||||
maxWidth: '200px',
|
||||
showDelIcon: true, // 显示删除图标
|
||||
imgPreview: true, // 显示图片预览
|
||||
imgPreview: isImage, // 图片才显示预览
|
||||
imgVariant: 'square', // 图片预览的形状
|
||||
url: URL.createObjectURL(file), // 图片预览地址
|
||||
url: isImage ? previewUrl : undefined, // 使用压缩后的 base64 作为预览地址
|
||||
isUploaded: true, // 直接标记为已完成
|
||||
base64: isImage ? base64 : undefined, // 保存压缩后的base64
|
||||
});
|
||||
}
|
||||
filesStore.setFilesList([...filesStore.filesList, ...arr]);
|
||||
|
||||
if (arr.length > 0) {
|
||||
filesStore.setFilesList([...filesStore.filesList, ...arr]);
|
||||
ElMessage.success(`已添加 ${arr.length} 个文件`);
|
||||
}
|
||||
|
||||
// 重置文件选择器
|
||||
nextTick(() => reset());
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user