fix: OSS客户端直传

This commit is contained in:
2025-12-23 14:34:22 +08:00
parent e9b79b2963
commit 84cafd66ae
7 changed files with 686 additions and 38 deletions

View File

@@ -2,7 +2,10 @@
import { useVModel } from '@vueuse/core';
import { Upload } from 'ant-design-vue';
// 导入上传相关API和工具函数
import { uploadFile } from '#/api/core/upload';
import { uploadToOss } from '#/utils/oss-upload';
import { preferences } from '@vben/preferences';
import { Icon } from '#/components/icon';
defineOptions({
@@ -19,12 +22,59 @@ const mValue = useVModel(props, 'value', emits, {
defaultValue: props.value,
passive: true,
});
const customRequest = (e: any) => {
uploadFile({
file: e.file,
}).then((data: any) => {
/**
* 自定义上传请求处理函数
*
* 该函数根据preferences配置的上传方式选择使用OSS直传或后端上传
* - 'direct': OSS直传模式文件直接从浏览器上传到阿里云OSS
* - 'backend': 后端上传模式文件先上传到后端服务器再由后端上传到OSS
*
* 上传方式说明:
* 1. OSS直传direct
* - 调用uploadToOss函数直接上传到OSS
* - 减少服务器负载,上传速度更快
*
* 2. 后端上传backend
* - 调用uploadFile API通过后端服务器上传
* - 兼容现有功能,所有上传逻辑由后端统一处理
*
* 兼容性处理:
* - 两种上传方式返回的数据结构保持一致:{ url: string }
* - 上传成功后将URL赋值给mValue触发组件更新
*
* @param e 上传事件对象包含file字段文件对象
*/
const customRequest = async (e: any) => {
try {
// 从preferences中读取上传方式配置
// uploadMethod可能的值'direct'OSS直传或 'backend'(后端上传)
const uploadMethod = preferences.app.uploadMethod || 'direct';
let data: { url: string };
// 根据配置选择上传方式
if (uploadMethod === 'direct') {
// OSS直传模式文件直接从浏览器上传到OSS
// uploadToOss函数会处理签名获取、文件上传等所有逻辑
data = await uploadToOss({
file: e.file as File,
});
} else {
// 后端上传模式文件先上传到后端服务器再由后端上传到OSS
// uploadFile函数会将文件发送到后端API/upload/image
data = await uploadFile({
file: e.file,
});
}
// 上传成功将URL赋值给mValue
// mValue是双向绑定的值更新后会触发父组件的更新
mValue.value = data.url;
});
} catch (error) {
// 上传失败,记录错误信息
// 注意这里没有显示错误提示如果需要可以添加message.error
console.error('头像上传失败', error);
}
};
const handleRemove = (e: Event) => {
e.stopPropagation();

View File

@@ -7,7 +7,10 @@ import '@vueup/vue-quill/dist/vue-quill.snow.css';
import { useVModel } from '@vueuse/core';
import { message } from 'ant-design-vue';
// 导入上传相关API和工具函数
import { uploadFile } from '#/api/core/upload';
import { uploadToOss } from '#/utils/oss-upload';
import { preferences } from '@vben/preferences';
const props = defineProps({
value: {
@@ -136,33 +139,82 @@ const insertImageToEditor = (quill: any, imageUrl: string): void => {
};
/**
* 图片上传函数
*
* 该函数根据preferences配置的上传方式选择使用OSS直传或后端上传
* - 'direct': OSS直传模式文件直接从浏览器上传到阿里云OSS
* - 'backend': 后端上传模式文件先上传到后端服务器再由后端上传到OSS
*
* 上传方式说明:
* 1. OSS直传direct
* - 调用uploadToOss函数直接上传到OSS
* - 减少服务器负载,上传速度更快
* - 支持上传进度回调(如果需要可以添加)
*
* 2. 后端上传backend
* - 调用uploadFile API通过后端服务器上传
* - 兼容现有功能,所有上传逻辑由后端统一处理
*
* 兼容性处理:
* - 两种上传方式返回的数据结构保持一致:{ url: string }
* - 上传成功或失败都会显示相应的提示信息
* - 上传完成后将isUpload标记设置为false允许下次上传
*
* @param {File} file - 要上传的图片文件
* @returns {Promise<string>} - 返回上传后的图片URL
* @returns {Promise<string>} - 返回上传后的图片URL,如果上传失败返回空字符串
*/
const uploadImage = async (file: File): Promise<string> => {
try {
// 创建FormData对象用于发送文件数据
const formData = new FormData();
formData.append('file', file);
// 显示上传中的提示
message.loading({ content: '图片上传中...', key: 'imageUpload' });
return uploadFile({
file,
}).then((data: any) => {
message.success({
content: '图片上传成功',
key: 'imageUpload',
duration: 2,
// 从preferences中读取上传方式配置
// uploadMethod可能的值'direct'OSS直传或 'backend'(后端上传)
const uploadMethod = preferences.app.uploadMethod || 'direct';
let data: { url: string };
// 根据配置选择上传方式
if (uploadMethod === 'direct') {
// OSS直传模式文件直接从浏览器上传到OSS
// uploadToOss函数会处理签名获取、文件上传等所有逻辑
data = await uploadToOss({
file: file,
// 如果需要显示上传进度可以添加onProgress回调
// onProgress: (percent) => {
// message.loading({ content: `图片上传中... ${percent}%`, key: 'imageUpload' });
// },
});
isUpload.value = false;
return data.url;
} else {
// 后端上传模式文件先上传到后端服务器再由后端上传到OSS
// uploadFile函数会将文件发送到后端API/upload/image
data = await uploadFile({
file,
});
}
// 上传成功,显示成功提示
message.success({
content: '图片上传成功',
key: 'imageUpload',
duration: 2,
});
// 重置上传标记,允许下次上传
isUpload.value = false;
// 返回上传后的图片URL
return data.url;
} catch (error) {
// 处理上传错误
console.error('图片上传错误:', error);
// 显示错误提示
message.error({ content: '图片上传失败', key: 'imageUpload', duration: 2 });
// 重置上传标记,允许重试
isUpload.value = false;
// 返回空字符串,表示上传失败
return '';
}
};

View File

@@ -4,7 +4,10 @@ import { computed, nextTick, onMounted, ref, watch } from 'vue';
import { Modal, Upload } from 'ant-design-vue';
import type { UploadFile } from 'ant-design-vue';
// 导入上传相关API和工具函数
import { uploadFile } from '#/api/core/upload';
import { uploadToOss } from '#/utils/oss-upload';
import { preferences } from '@vben/preferences';
import { Icon } from '#/components/icon';
defineOptions({
@@ -132,11 +135,36 @@ const initSortable = () => {
});
};
// 使用原有的uploadFile接口与upload-image.vue保持一致
/**
* 自定义上传请求处理函数
*
* 该函数根据preferences配置的上传方式选择使用OSS直传或后端上传
* - 'direct': OSS直传模式文件直接从浏览器上传到阿里云OSS
* - 'backend': 后端上传模式文件先上传到后端服务器再由后端上传到OSS
*
* 两种上传方式的区别:
* 1. OSS直传direct
* - 优点:减少服务器负载,上传速度更快,用户体验更好
* - 缺点:需要后端提供签名接口,配置相对复杂
* - 实现调用uploadToOss函数直接上传到OSS
*
* 2. 后端上传backend
* - 优点:兼容现有功能,所有上传逻辑由后端统一处理
* - 缺点:增加服务器负载,上传速度相对较慢
* - 实现调用uploadFile API通过后端服务器上传
*
* 兼容性处理:
* - 两种上传方式返回的数据结构保持一致:{ url: string }
* - 确保无论使用哪种方式,组件的行为都是一致的
* - 上传成功后,会重新初始化拖拽排序功能
* - 如果上传失败会更新文件状态为error并调用onError回调
*
* @param options 上传选项包含file、onProgress、onSuccess、onError等
*/
const customRequest = async (options: any) => {
const { file, onProgress, onSuccess, onError } = options;
// 创建上传中的文件项
// 创建上传中的文件项用于在UI中显示上传状态
const uploadingFile: FileItem = {
uid: file.uid,
name: file.name,
@@ -144,15 +172,48 @@ const customRequest = async (options: any) => {
url: '',
};
// 将上传中的文件添加到文件列表
fileList.value = [...fileList.value, uploadingFile];
try {
// 使用原有的uploadFile接口
const res = await uploadFile({
file: file,
});
// 从preferences中读取上传方式配置
// uploadMethod可能的值'direct'OSS直传或 'backend'(后端上传)
const uploadMethod = preferences.app.uploadMethod || 'direct';
// 更新文件状态为完成
let res: { url: string };
// 根据配置选择上传方式
if (uploadMethod === 'direct') {
// OSS直传模式文件直接从浏览器上传到OSS
// uploadToOss函数会
// 1. 从后端获取OSS签名信息
// 2. 生成全局唯一的文件名UUID + 时间戳)
// 3. 使用FormData构造POST请求直接上传到OSS
// 4. 处理上传进度和错误
// 5. 返回上传后的文件URL
res = await uploadToOss({
file: file as File,
onProgress: (percent) => {
// 将OSS上传进度传递给组件
// percent范围0-100表示上传百分比
if (onProgress) {
onProgress(percent);
}
},
});
} else {
// 后端上传模式文件先上传到后端服务器再由后端上传到OSS
// uploadFile函数会
// 1. 将文件发送到后端API/upload/image
// 2. 后端接收文件后上传到OSS
// 3. 返回上传后的文件URL
res = await uploadFile({
file: file,
});
}
// 上传成功,更新文件状态为完成
// 将上传结果中的URL赋值给文件项
const updatedFileList = fileList.value.map(item =>
item.uid === file.uid
? { ...item, status: 'done' as const, url: res.url }
@@ -160,17 +221,24 @@ const customRequest = async (options: any) => {
);
fileList.value = updatedFileList;
// 更新组件的modelValue触发父组件的更新
updateModelValue();
// 重新初始化排序
// 重新初始化拖拽排序功能
// 因为文件列表发生了变化,需要重新绑定拖拽事件
nextTick(() => {
initSortable();
});
// 调用成功回调,通知上传组件上传已完成
onSuccess(res);
} catch (error) {
// 上传失败,记录错误信息
console.error('上传失败', error);
// 更新文件状态为错误
// 错误状态的文件会在UI中显示错误图标
const updatedFileList = fileList.value.map(item =>
item.uid === file.uid
? { ...item, status: 'error' as const }
@@ -178,6 +246,8 @@ const customRequest = async (options: any) => {
);
fileList.value = updatedFileList;
// 调用错误回调,通知上传组件上传失败
onError(error);
}
};

View File

@@ -3,8 +3,10 @@ import { computed, ref, watch } from 'vue';
import { Modal, Upload } from 'ant-design-vue';
import type { UploadFile } from 'ant-design-vue';
// 恢复使用原有的上传接口
// 导入上传相关API和工具函数
import { uploadFile } from '#/api/core/upload';
import { uploadToOss } from '#/utils/oss-upload';
import { preferences } from '@vben/preferences';
import { Icon } from '#/components/icon';
// 定义接口
@@ -68,11 +70,35 @@ const updateModelValue = () => {
emit('update:modelValue', urls);
};
// 使用原有的uploadFile接口
/**
* 自定义上传请求处理函数
*
* 该函数根据preferences配置的上传方式选择使用OSS直传或后端上传
* - 'direct': OSS直传模式文件直接从浏览器上传到阿里云OSS
* - 'backend': 后端上传模式文件先上传到后端服务器再由后端上传到OSS
*
* 两种上传方式的区别:
* 1. OSS直传direct
* - 优点:减少服务器负载,上传速度更快,用户体验更好
* - 缺点:需要后端提供签名接口,配置相对复杂
* - 实现调用uploadToOss函数直接上传到OSS
*
* 2. 后端上传backend
* - 优点:兼容现有功能,所有上传逻辑由后端统一处理
* - 缺点:增加服务器负载,上传速度相对较慢
* - 实现调用uploadFile API通过后端服务器上传
*
* 兼容性处理:
* - 两种上传方式返回的数据结构保持一致:{ url: string }
* - 确保无论使用哪种方式,组件的行为都是一致的
* - 如果上传失败会更新文件状态为error并调用onError回调
*
* @param options 上传选项包含file、onProgress、onSuccess、onError等
*/
const customRequest = async (options: any) => {
const { file, onProgress, onSuccess, onError } = options;
// 创建上传中的文件项
// 创建上传中的文件项用于在UI中显示上传状态
const uploadingFile: FileItem = {
uid: file.uid,
name: file.name,
@@ -80,15 +106,48 @@ const customRequest = async (options: any) => {
url: '',
};
// 将上传中的文件添加到文件列表
fileList.value = [...fileList.value, uploadingFile];
try {
// 使用原有的uploadFile接口
const res = await uploadFile({
file: file,
});
// 从preferences中读取上传方式配置
// uploadMethod可能的值'direct'OSS直传或 'backend'(后端上传)
const uploadMethod = preferences.app.uploadMethod || 'direct';
// 更新文件状态为完成
let res: { url: string };
// 根据配置选择上传方式
if (uploadMethod === 'direct') {
// OSS直传模式文件直接从浏览器上传到OSS
// uploadToOss函数会
// 1. 从后端获取OSS签名信息
// 2. 生成全局唯一的文件名UUID + 时间戳)
// 3. 使用FormData构造POST请求直接上传到OSS
// 4. 处理上传进度和错误
// 5. 返回上传后的文件URL
res = await uploadToOss({
file: file as File,
onProgress: (percent) => {
// 将OSS上传进度传递给组件
// percent范围0-100表示上传百分比
if (onProgress) {
onProgress(percent);
}
},
});
} else {
// 后端上传模式文件先上传到后端服务器再由后端上传到OSS
// uploadFile函数会
// 1. 将文件发送到后端API/upload/image
// 2. 后端接收文件后上传到OSS
// 3. 返回上传后的文件URL
res = await uploadFile({
file: file,
});
}
// 上传成功,更新文件状态为完成
// 将上传结果中的URL赋值给文件项
const updatedFileList = fileList.value.map(item =>
item.uid === file.uid
? { ...item, status: 'done' as const, url: res.url }
@@ -96,11 +155,18 @@ const customRequest = async (options: any) => {
);
fileList.value = updatedFileList;
// 更新组件的modelValue触发父组件的更新
updateModelValue();
// 调用成功回调,通知上传组件上传已完成
onSuccess(res);
} catch (error) {
// 上传失败,记录错误信息
console.error('上传失败', error);
// 更新文件状态为错误
// 错误状态的文件会在UI中显示错误图标
const updatedFileList = fileList.value.map(item =>
item.uid === file.uid
? { ...item, status: 'error' as const }
@@ -108,6 +174,8 @@ const customRequest = async (options: any) => {
);
fileList.value = updatedFileList;
// 调用错误回调,通知上传组件上传失败
onError(error);
}
};