280 lines
9.0 KiB
JavaScript
280 lines
9.0 KiB
JavaScript
|
|
import request from "./request";
|
|||
|
|
let loading = false;
|
|||
|
|
// 触发上传
|
|||
|
|
const handleUpload = async (userId, type,sourceType = ['album', 'camera'])=> {
|
|||
|
|
if (loading) return
|
|||
|
|
|
|||
|
|
try {
|
|||
|
|
loading = true
|
|||
|
|
const res = await uni.chooseImage({
|
|||
|
|
count: 1,
|
|||
|
|
sizeType: ['original', 'compressed'],
|
|||
|
|
sourceType: sourceType
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
console.log('res======',res)
|
|||
|
|
|
|||
|
|
// 检查用户是否真的选择了图片
|
|||
|
|
if (!res || !res.tempFiles || res.tempFiles.length === 0) {
|
|||
|
|
console.log('用户取消了图片选择')
|
|||
|
|
return null // 明确返回 null 表示用户取消
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const file = res.tempFiles[0]
|
|||
|
|
// return file.path
|
|||
|
|
// 关键步骤2:iOS系统格式转换 (HEIC → JPEG)
|
|||
|
|
// let convertedPath = file.path
|
|||
|
|
// if (uni.getSystemInfoSync().platform === 'ios' &&
|
|||
|
|
// (file.path.toLowerCase().endsWith('.heic') ||
|
|||
|
|
// file.path.toLowerCase().endsWith('.heif'))) {
|
|||
|
|
// convertedPath = await this.convertHEICtoJPG(file.path)
|
|||
|
|
// }
|
|||
|
|
// file.path = convertedPath;
|
|||
|
|
// console.log(file.path)
|
|||
|
|
// return file.path;
|
|||
|
|
// return '_doc/uniapp_temp_1750408403627/camera/photo_001.jpg'
|
|||
|
|
const result = await uploadFile(file, userId, type)
|
|||
|
|
// const result = await compressAndUpload(file, userId, type).tempFilePath
|
|||
|
|
|
|||
|
|
return result;
|
|||
|
|
} catch (error) {
|
|||
|
|
console.error('上传出错:', error)
|
|||
|
|
|
|||
|
|
// 如果是用户取消操作,不抛出错误,返回 null
|
|||
|
|
if (error.errMsg && error.errMsg.includes('cancel')) {
|
|||
|
|
console.log('用户取消了操作')
|
|||
|
|
return null
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
throw error
|
|||
|
|
} finally {
|
|||
|
|
loading = false
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
// iOS专用:HEIC转JPG
|
|||
|
|
const convertHEICtoJPG = async (heicPath)=> {
|
|||
|
|
return new Promise((resolve, reject) => {
|
|||
|
|
plus.zip.compressImage({
|
|||
|
|
src: heicPath,
|
|||
|
|
dst: heicPath.replace(/\.heic$|\.heif$/i, '.jpg'),
|
|||
|
|
format: 'jpg',
|
|||
|
|
quality: 90
|
|||
|
|
}, resolve, reject)
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
// 获取二进制数据(兼容iOS)
|
|||
|
|
const getFileBinary = async (filePath)=> {
|
|||
|
|
return new Promise((resolve) => {
|
|||
|
|
const reader = new plus.io.FileReader()
|
|||
|
|
reader.onloadend = (e) => {
|
|||
|
|
resolve(e.target.result)
|
|||
|
|
}
|
|||
|
|
reader.readAsArrayBuffer(filePath)
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
const compressAndUpload = async (file, userId, type)=> {
|
|||
|
|
try {
|
|||
|
|
console.log('file=====',file)
|
|||
|
|
// 压缩图片
|
|||
|
|
const compressedResult = await uni.compressImage({
|
|||
|
|
src: file.path,
|
|||
|
|
quality: 80, // 压缩质量,范围0-100
|
|||
|
|
format: 'jpg', // 指定输出为jpg格式
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 获取压缩后的临时文件路径
|
|||
|
|
const compressedPath = compressedResult.tempFilePath;
|
|||
|
|
console.log('compressedPath',compressedPath)
|
|||
|
|
file.path = compressedPath;
|
|||
|
|
console.log('file.path',file.path)
|
|||
|
|
// 上传图片
|
|||
|
|
const result = await uploadFile(file, userId, type)
|
|||
|
|
return result;
|
|||
|
|
} catch (error) {
|
|||
|
|
console.error('压缩或上传失败:', error);
|
|||
|
|
uni.showToast({
|
|||
|
|
title: '图片处理失败',
|
|||
|
|
icon: 'none'
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
// 上传文件到OSS
|
|||
|
|
const uploadFile = async (file, userId, type)=> {
|
|||
|
|
console.log('file=======',file)
|
|||
|
|
console.log('userId=======',userId)
|
|||
|
|
// 检查文件大小
|
|||
|
|
if (file.size > 5 * 1024 * 1024) {
|
|||
|
|
uni.showToast({
|
|||
|
|
title: `文件大小不能超过5MB`,
|
|||
|
|
icon: 'none'
|
|||
|
|
})
|
|||
|
|
return Promise.reject(new Error('文件大小超出限制'))
|
|||
|
|
}
|
|||
|
|
let date = new Date().getTime()
|
|||
|
|
console.log('file',file)
|
|||
|
|
let imageType = file.path.split('.')
|
|||
|
|
let artisan = type==1 ? 'yh' : type==2 ? 'syr' : type==3 ? 'sj' : '';
|
|||
|
|
// let fileType = imageType[imageType.length - 1].toLowerCase();
|
|||
|
|
let name = `${userId}_${artisan}_${date}.${imageType[imageType.length - 1]}`
|
|||
|
|
console.log('name',name)
|
|||
|
|
try {
|
|||
|
|
// 1. 获取OSS上传凭证
|
|||
|
|
const ossConfig = await getOssConfig(type)
|
|||
|
|
// console.log('ossConfig',ossConfig)
|
|||
|
|
// return;
|
|||
|
|
// 2. 上传文件
|
|||
|
|
const uploadRes = await uploadToOss(file, ossConfig, name)
|
|||
|
|
// 3. 添加到文件列表
|
|||
|
|
const fileUrl = `${ossConfig.host}/${ossConfig.dir}${name}`
|
|||
|
|
return fileUrl
|
|||
|
|
} catch (error) {
|
|||
|
|
console.error('上传失败:', error)
|
|||
|
|
throw error
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 获取OSS配置
|
|||
|
|
const getOssConfig = async (type)=> {
|
|||
|
|
try {
|
|||
|
|
const res = await request.post('/user/getalioss',{type: type,kind: 1})
|
|||
|
|
return res
|
|||
|
|
} catch (error) {
|
|||
|
|
console.error('获取OSS配置失败:', error)
|
|||
|
|
throw error
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 上传到OSS
|
|||
|
|
const uploadToOss = (file, ossConfig, name)=> {
|
|||
|
|
console.log(ossConfig)
|
|||
|
|
return new Promise((resolve, reject) => {
|
|||
|
|
// #ifdef H5
|
|||
|
|
const formData = new FormData()
|
|||
|
|
formData.append('name',name);
|
|||
|
|
formData.append('policy', ossConfig.policy);
|
|||
|
|
formData.append('OSSAccessKeyId', ossConfig.ossAccessKeyId);
|
|||
|
|
formData.append('success_action_status', '200');
|
|||
|
|
formData.append('signature', ossConfig.signature);
|
|||
|
|
formData.append('key', ossConfig.dir + name);
|
|||
|
|
// file必须为最后一个表单域,除file以外的其他表单域无顺序要求。
|
|||
|
|
formData.append('file', file);
|
|||
|
|
fetch(ossConfig.host, { method: 'POST', body: formData},).then((res) => {
|
|||
|
|
resolve(`${ossConfig.host}/${ossConfig.dir}${name}`)
|
|||
|
|
}).catch(()=>{
|
|||
|
|
reject(new Error(`上传失败: ${res.statusCode}`))
|
|||
|
|
})
|
|||
|
|
// #endif
|
|||
|
|
// #ifdef APP-PLUS || MP-WEIXIN
|
|||
|
|
let formData = {};
|
|||
|
|
formData.name = name;
|
|||
|
|
formData.policy = ossConfig.policy;
|
|||
|
|
formData.OSSAccessKeyId = ossConfig.ossAccessKeyId;
|
|||
|
|
formData.success_action_status = '200';
|
|||
|
|
formData.signature = ossConfig.signature;
|
|||
|
|
formData.key = ossConfig.dir + name;
|
|||
|
|
formData.file = file;
|
|||
|
|
// formData.file = name;
|
|||
|
|
// formData['x-oss-forbid-overwrite'] = 'false'; // iOS 可能需要显式设置
|
|||
|
|
// formData['x-oss-object-acl'] = 'public-read'; // 显式设置公开读
|
|||
|
|
// formData['Content-Disposition'] = 'inline'; // 确保浏览器直接显示
|
|||
|
|
|
|||
|
|
// 获取文件扩展名并设置 Content-Type
|
|||
|
|
const ext = file.path.split('.').pop().toLowerCase()
|
|||
|
|
const mimeTypes = {
|
|||
|
|
jpg: 'image/jpeg',
|
|||
|
|
jpeg: 'image/jpeg',
|
|||
|
|
png: 'image/png',
|
|||
|
|
gif: 'image/gif'
|
|||
|
|
}
|
|||
|
|
if (mimeTypes[ext]) {
|
|||
|
|
// formData['Content-Type'] = 'multipart/form-data'
|
|||
|
|
formData['Content-Type'] = mimeTypes[ext],
|
|||
|
|
formData['x-oss-meta-content-type'] = mimeTypes[ext]
|
|||
|
|
}
|
|||
|
|
console.log('formData',formData)
|
|||
|
|
// 使用 uni.uploadFile 上传文件(支持多平台)
|
|||
|
|
console.log(file.path)
|
|||
|
|
|
|||
|
|
// formData: {
|
|||
|
|
// key: filePath, // 文件名
|
|||
|
|
// policy: ossData.policy, // 后台获取超时时间
|
|||
|
|
// OSSAccessKeyId: ossData.accessid, // 后台获取临时ID
|
|||
|
|
// success_action_status: 200, // 让服务端返回200,不然,默认会返回204
|
|||
|
|
// signature: ossData.signature // 后台获取签名
|
|||
|
|
// },
|
|||
|
|
|
|||
|
|
|
|||
|
|
uni.uploadFile({
|
|||
|
|
url: ossConfig.host,
|
|||
|
|
filePath: file.path, // 手机端文件路径
|
|||
|
|
name: 'file',
|
|||
|
|
formData: {
|
|||
|
|
key: ossConfig.dir + name, // 文件名
|
|||
|
|
policy: ossConfig.policy, // 后台获取超时时间
|
|||
|
|
OSSAccessKeyId: ossConfig.ossAccessKeyId, // 后台获取临时ID
|
|||
|
|
success_action_status: 200, // 让服务端返回200,不然,默认会返回204
|
|||
|
|
signature: ossConfig.signature // 后台获取签名
|
|||
|
|
},
|
|||
|
|
success(res) {
|
|||
|
|
resolve(`${ossConfig.host}/${ossConfig.dir}${name}`)
|
|||
|
|
},
|
|||
|
|
complete(err) {
|
|||
|
|
console.log('err',err)
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
// uni.uploadFile({
|
|||
|
|
// url: ossConfig.host,
|
|||
|
|
// filePath: file.path, // 手机端文件路径
|
|||
|
|
// name: 'file',
|
|||
|
|
// formData: formData, // 附加的表单数据
|
|||
|
|
// header: {
|
|||
|
|
// 'Content-Type': mimeTypes[ext],
|
|||
|
|
// 'User-Agent': 'uni-app'
|
|||
|
|
// },
|
|||
|
|
// success(res) {
|
|||
|
|
// resolve(`${ossConfig.host}/${ossConfig.dir}${name}`)
|
|||
|
|
// },
|
|||
|
|
// complete(err) {
|
|||
|
|
// console.log('err',err)
|
|||
|
|
// }
|
|||
|
|
// });
|
|||
|
|
// uni.uploadFile({
|
|||
|
|
// url: 'https://mrrplus.oss-cn-beijing.aliyuncs.com', // 替换为你的OSS地址
|
|||
|
|
// filePath: '_doc/uniapp_temp_1750408403627/camera/photo_001.jpg',
|
|||
|
|
// name: 'file', // 文件字段名,必须为file
|
|||
|
|
// formData: {
|
|||
|
|
// "name": "777.jpg",
|
|||
|
|
// "policy": "eyJleHBpcmF0aW9uIjoiMjAyNi0wNi0wMlQxNDowMjozMi4wMDBaIiwiY29uZGl0aW9ucyI6W1siY29udGVudC1sZW5ndGgtcmFuZ2UiLDAsMTA0ODU3NjAwMF0sWyJzdGFydHMtd2l0aCIsIiRrZXkiLCJwaG90b1wveWhcLyJdXX0=",
|
|||
|
|
// "OSSAccessKeyId": "LTAI5tGsiEK2Zuat4bJSHXs9",
|
|||
|
|
// "success_action_status": "200",
|
|||
|
|
// "signature": "SpdrnDXiFc6PRPDKA2cP2YYGSdY=",
|
|||
|
|
// "key": "photo/yh/777.jpg",
|
|||
|
|
// "file": {
|
|||
|
|
// "path": "_doc/uniapp_temp_1750408403627/camera/photo_001.jpg",
|
|||
|
|
// "size": 1926161
|
|||
|
|
// }
|
|||
|
|
// },
|
|||
|
|
// header: {
|
|||
|
|
// // 注意:这里设置的是整个请求的头部,而不是文件字段的头部。整个请求的Content-Type为multipart/form-data,且会自动生成boundary
|
|||
|
|
// "Content-Type": "multipart/form-data"
|
|||
|
|
// // 我们不需要手动设置Content-Type,否则会破坏multipart的格式
|
|||
|
|
// },
|
|||
|
|
// success: (uploadRes) => {
|
|||
|
|
// if (uploadRes.statusCode === 200) {
|
|||
|
|
// // 上传成功,解析返回结果(OSS可能返回XML,需要解析)
|
|||
|
|
// resolve(uploadRes.data);
|
|||
|
|
// } else {
|
|||
|
|
// // 上传失败,返回状态码非200
|
|||
|
|
// reject(new Error(`上传失败,状态码:${uploadRes.statusCode}`));
|
|||
|
|
// }
|
|||
|
|
// },
|
|||
|
|
// fail: (error) => {
|
|||
|
|
// reject(error);
|
|||
|
|
// }
|
|||
|
|
// });
|
|||
|
|
// #endif
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
export default {
|
|||
|
|
handleUpload
|
|||
|
|
}
|