提交代码

This commit is contained in:
zlwu committed 2025-08-03 14:20:32 +08:00
1 parent 82ecb8621d
commit fbb8dd6bd5
10 files changed
+4027 -211

No files matched your search

+233 -36
View File
@@ -105,7 +105,7 @@ const loadingStates = ref<Map<string, boolean>>(new Map());
const loadErrorStates = ref<Map<string, boolean>>(new Map());
// 使用环境变量
const baseUrl = '/dev-api';
const baseUrl = import.meta.env.VITE_APP_BASE_API;
const uploadImgUrl = ref(baseUrl + '/resource/oss/upload'); // 上传的图片服务器地址
const headers = ref(globalHeaders());
@@ -189,24 +189,24 @@ const getPreviewImageBlobUrl = async (imageUrl: string): Promise<string> => {
}
// 检查blob内容类型
const contentType = blob.type;
// const contentType = blob.type;
// 如果Content-Type明确表明这不是图片数据且不是通用二进制格式,进行检查
if (
contentType &&
!contentType.toLowerCase().startsWith('image/') &&
!contentType.toLowerCase().includes('octet-stream') &&
(contentType.toLowerCase().includes('text/') || contentType.toLowerCase().includes('html'))
) {
const text = await blob.text();
const preview = text.substring(0, 300);
throw new Error(`响应Content-Type不是图片格式: ${contentType}。响应内容预览: ${preview}`);
}
// if (
// contentType &&
// !contentType.toLowerCase().startsWith('image/') &&
// !contentType.toLowerCase().includes('octet-stream') &&
// (contentType.toLowerCase().includes('text/') || contentType.toLowerCase().includes('html'))
// ) {
// const text = await blob.text();
// const preview = text.substring(0, 300);
// throw new Error(`响应Content-Type不是图片格式: ${contentType}。响应内容预览: ${preview}`);
// }
// 验证是否为有效图片
if (!validateImageBlob(blob)) {
throw new Error(`无效的图片格式: ${blob.type}, 大小: ${blob.size}`);
}
// if (!validateImageBlob(blob)) {
// throw new Error(`无效的图片格式: ${blob.type}, 大小: ${blob.size}`);
// }
// 创建blob URL
const blobUrl = URL.createObjectURL(blob);
@@ -225,29 +225,29 @@ const getPreviewImageBlobUrl = async (imageUrl: string): Promise<string> => {
// 通过ossid获取预览URL
const getPreviewUrlByOssId = async (ossId: string): Promise<string> => {
try {
const response = await listByIds(ossId);
// RuoYi框架的响应格式:{code, msg, data},实际数据在data字段中
const ossList: OssVO[] = (response as any)?.data || response;
// const response = await listByIds(ossId);
// // RuoYi框架的响应格式:{code, msg, data},实际数据在data字段中
// const ossList: OssVO[] = (response as any)?.data || response;
if (!ossList || ossList.length === 0) {
throw new Error(`OSS ID ${ossId} 在数据库中不存在或已被删除`);
}
// if (!ossList || ossList.length === 0) {
// throw new Error(`OSS ID ${ossId} 在数据库中不存在或已被删除`);
// }
const ossFile = ossList[0];
// const ossFile = ossList[0];
if (!ossFile || !ossFile.url) {
throw new Error(`OSS文件缺少url属性`);
}
// if (!ossFile || !ossFile.url) {
// throw new Error(`OSS文件缺少url属性`);
// }
const imageUrl = ossFile.url;
// const imageUrl = ossFile.url;
// 检查URL是否有效
if (!imageUrl || typeof imageUrl !== 'string') {
throw new Error(`OSS接口返回的URL无效`);
}
// // 检查URL是否有效
// if (!imageUrl || typeof imageUrl !== 'string') {
// throw new Error(`OSS接口返回的URL无效`);
// }
// 获取认证的blob URL
return await getPreviewImageBlobUrl(imageUrl);
return await getPreviewImageBlobUrl('/resource/oss/download/' + ossId);
} catch (error) {
console.error('通过ossId获取预览图片失败:', error);
throw error;
@@ -265,11 +265,17 @@ const loadFileImageAsync = async (item: any, index: number): Promise<void> => {
try {
let blobUrl = '';
if (typeof item === 'string') {
if (item.ossId) {
// 优先通过OSS ID获取预览URL
console.log(`loadFileImageAsync: 通过OSS ID获取预览URL for ${item.ossId}`);
blobUrl = await getPreviewUrlByOssId(item.ossId);
} else if (typeof item === 'string') {
// 直接URL情况
console.log(`loadFileImageAsync: 直接URL情况 for ${item}`);
blobUrl = await getPreviewImageBlobUrl(item);
} else if (item.url) {
// OSS对象情况
// OSS对象情况(降级处理)
console.log(`loadFileImageAsync: OSS对象情况 for ${item.url}`);
blobUrl = await getPreviewImageBlobUrl(item.url);
}
@@ -280,6 +286,8 @@ const loadFileImageAsync = async (item: any, index: number): Promise<void> => {
if (fileIndex !== -1) {
fileList.value[fileIndex].url = blobUrl;
fileList.value[fileIndex].isLoaded = true;
fileList.value[fileIndex].isPlaceholder = false;
console.log(`loadFileImageAsync: 成功更新文件 ${item.ossId || item.url}`);
}
} else {
throw new Error('获取图片blob URL失败');
@@ -287,6 +295,24 @@ const loadFileImageAsync = async (item: any, index: number): Promise<void> => {
} catch (error) {
console.error('异步加载图片失败:', error);
loadErrorStates.value.set(fileKey, true);
// 降级处理:尝试通过OSS ID重新获取
if (item.ossId) {
try {
console.log(`loadFileImageAsync: 降级处理,重新通过OSS ID获取 ${item.ossId}`);
const fallbackBlobUrl = await getPreviewUrlByOssId(item.ossId);
const fileIndex = fileList.value.findIndex((f) => f.ossId === item.ossId);
if (fileIndex !== -1 && fallbackBlobUrl) {
fileList.value[fileIndex].url = fallbackBlobUrl;
fileList.value[fileIndex].isLoaded = true;
fileList.value[fileIndex].isPlaceholder = false;
console.log(`loadFileImageAsync: 降级处理成功 for ${item.ossId}`);
}
} catch (fallbackError) {
console.error('loadFileImageAsync: 降级处理也失败:', fallbackError);
}
}
} finally {
loadingStates.value.set(fileKey, false);
}
@@ -448,8 +474,16 @@ const handleExceed = () => {
// 上传成功回调
const handleUploadSuccess = (res: any, file: any) => {
console.log('handleUploadSuccess:res', res);
console.log('handleUploadSuccess:file', file);
if (res.code === 200) {
uploadList.value.push({ name: res.data.fileName, url: res.data.url, ossId: res.data.ossId });
const uploadItem = {
name: res.data.fileName,
url: res.data.url,
ossId: res.data.ossId
};
console.log('添加上传项到uploadList:', uploadItem);
uploadList.value.push(uploadItem);
uploadedSuccessfully();
} else {
number.value--;
@@ -489,9 +523,126 @@ const handleDelete = (file: any): boolean => {
};
// 上传结束处理
const uploadedSuccessfully = () => {
const uploadedSuccessfully = async () => {
console.log('uploadedSuccessfully called, number:', number.value, 'uploadList length:', uploadList.value.length);
if (number.value > 0 && uploadList.value.length === number.value) {
fileList.value = fileList.value.filter((f) => f.url !== undefined).concat(uploadList.value);
console.log('开始处理新上传的文件:', uploadList.value);
// 对新上传的文件进行异步加载处理
const newUploadedFiles = uploadList.value.map((item) => ({
...item,
isLoaded: false,
isPlaceholder: false
}));
console.log('处理后的新上传文件:', newUploadedFiles);
// 先显示新上传的文件(使用占位符)
const placeholderItems = newUploadedFiles.map((item, index) => ({
name: item.name,
url: 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgdmlld0JveD0iMCAwIDEwMCAxMDAiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIiBmaWxsPSIjZjVmN2ZhIi8+CjxjaXJjbGUgY3g9IjUwIiBjeT0iNTAiIHI9IjE1IiBzdHJva2U9IiM5MDkzOTkiIHN0cm9rZS13aWR0aD0iMiIgZmlsbD0ibm9uZSIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtZGFzaGFycmF5PSI2LCAzIiBzdHJva2UtbGluZWpvaW49InJvdW5kIj4KCTxhbmltYXRlVHJhbnNmb3JtIGF0dHJpYnV0ZU5hbWU9InRyYW5zZm9ybSIgdHlwZT0icm90YXRlIiB2YWx1ZXM9IjAgNTAgNTA7MzYwIDUwIDUwIiBkdXI9IjFzIiByZXBlYXRDb3VudD0iaW5kZWZpbml0ZSIvPgo8L2NpcmNsZT4KPC9zdmc+',
originalUrl: item.url,
ossId: item.ossId,
isLoaded: false,
isPlaceholder: true
}));
console.log('占位符项目:', placeholderItems);
// 合并现有文件和新上传的文件
const existingFiles = fileList.value.filter((f) => f.url !== undefined);
console.log('现有文件:', existingFiles);
fileList.value = existingFiles.concat(placeholderItems);
console.log('合并后的文件列表:', fileList.value);
// 异步加载新上传的图片
const loadPromises = newUploadedFiles.map((item, index) => {
const fileKey = item.ossId || item.url || `file_${index}`;
console.log(`开始加载文件 ${index}:`, item);
// 设置加载状态
loadingStates.value.set(fileKey, true);
loadErrorStates.value.set(fileKey, false);
return (async () => {
try {
let blobUrl = '';
if (item.ossId) {
console.log(`通过OSS ID获取预览URL for ${item.ossId}`);
// 通过OSS ID获取预览URL
blobUrl = await getPreviewUrlByOssId(item.ossId);
console.log(`获取到的blob URL for ${item.ossId}:`, blobUrl);
} else if (item.url) {
console.log(`通过URL获取blob URL for ${item.ossId}:`, item.url);
// 直接URL情况(降级处理)
blobUrl = await getPreviewImageBlobUrl(item.url);
console.log(`获取到的blob URL for ${item.ossId}:`, blobUrl);
}
if (blobUrl) {
// 更新文件列表中的对应项
const fileIndex = fileList.value.findIndex((f) => f.ossId === item.ossId);
console.log(`更新文件列表索引 ${fileIndex} for ${item.ossId}`);
if (fileIndex !== -1) {
fileList.value[fileIndex].url = blobUrl;
fileList.value[fileIndex].isLoaded = true;
fileList.value[fileIndex].isPlaceholder = false;
console.log(`成功更新文件 ${item.ossId}`);
}
} else {
throw new Error('获取图片blob URL失败');
}
} catch (error) {
console.error('异步加载新上传图片失败:', error);
loadErrorStates.value.set(fileKey, true);
// 降级处理:通过OSS ID重新获取
try {
console.log(`降级处理:重新通过OSS ID获取 ${item.ossId}`);
const fallbackBlobUrl = await getPreviewUrlByOssId(item.ossId);
const fileIndex = fileList.value.findIndex((f) => f.ossId === item.ossId);
if (fileIndex !== -1 && fallbackBlobUrl) {
fileList.value[fileIndex].url = fallbackBlobUrl;
fileList.value[fileIndex].isLoaded = true;
fileList.value[fileIndex].isPlaceholder = false;
console.log(`降级处理成功,通过OSS ID重新获取 for ${item.ossId}`);
} else {
// 最后的降级:使用原始URL
const fileIndex = fileList.value.findIndex((f) => f.ossId === item.ossId);
if (fileIndex !== -1) {
fileList.value[fileIndex].url = item.url;
fileList.value[fileIndex].isLoaded = true;
fileList.value[fileIndex].isPlaceholder = false;
console.log(`最终降级处理,使用原始URL for ${item.ossId}`);
}
}
} catch (fallbackError) {
console.error('降级处理也失败:', fallbackError);
// 最后的降级:使用原始URL
const fileIndex = fileList.value.findIndex((f) => f.ossId === item.ossId);
if (fileIndex !== -1) {
fileList.value[fileIndex].url = item.url;
fileList.value[fileIndex].isLoaded = true;
fileList.value[fileIndex].isPlaceholder = false;
console.log(`最终降级处理,使用原始URL for ${item.ossId}`);
}
}
} finally {
loadingStates.value.set(fileKey, false);
}
})();
});
// 等待所有图片加载完成
await Promise.all(loadPromises);
console.log('所有图片加载完成,最终文件列表:', fileList.value);
uploadList.value = [];
number.value = 0;
// 设置内部更新标志
@@ -592,8 +743,39 @@ const listToString = (list: any[], separator?: string) => {
opacity: 0.6;
}
}
// 占位符图片样式优化
&.placeholder-item {
.el-upload-list__item-thumbnail {
background-color: #f5f7fa;
border: 1px dashed #d9d9d9;
display: flex;
align-items: center;
justify-content: center;
img {
opacity: 0.7;
transition: opacity 0.3s ease;
}
}
&:hover .el-upload-list__item-thumbnail img {
opacity: 1;
}
}
// 加载完成后的样式
&.loaded-item {
.el-upload-list__item-thumbnail {
img {
opacity: 1;
transition: opacity 0.3s ease;
}
}
}
}
// 加载动画
@keyframes loading-rotate {
0% {
transform: rotate(0deg);
@@ -602,4 +784,19 @@ const listToString = (list: any[], separator?: string) => {
transform: rotate(360deg);
}
}
// 占位符加载动画
@keyframes placeholder-pulse {
0%,
100% {
opacity: 0.6;
}
50% {
opacity: 1;
}
}
.placeholder-loading {
animation: placeholder-pulse 1.5s ease-in-out infinite;
}
</style>