mrr.sj.front/utils/albumUploadImage.js

299 lines
8.4 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import request from "./request";
let loading = false;
/**
* 核心新增:校验图片比例是否符合 4:3 规范(带容错)
* @param {Number} width 图片宽度
* @param {Number} height 图片高度
* @param {Number} tolerance 容错值默认0.05,摇摆空间足够
* @returns {Boolean} 是否符合比例
*/
const checkImageRatio = (width, height, tolerance = 0.05) => {
const standardRatio = 4 / 3; // 标准4:3比例
const actualRatio = width / height; // 实际图片宽高比
// 支持 横版4:3 或 竖版3:4 两种情况
console.log(actualRatio, standardRatio)
//const isStandardHorizontal = Math.abs(actualRatio - standardRatio) <= tolerance;
// const isStandardVertical = Math.abs(actualRatio - (3 / 4)) <= tolerance;
// return isStandardHorizontal || isStandardVertical;
const isStandardHorizontal = standardRatio - actualRatio <= 0.334 || actualRatio - standardRatio <= tolerance;
return isStandardHorizontal;
};
// 触发上传
const handleUpload = async (userId, type, sourceType = ['album', 'camera'], uploadType = 'image') => {
if (loading) return
try {
loading = true
let file = null
if (uploadType == 'image') {
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 表示用户取消
}
file = res.tempFiles[0]
// ========== 【核心新增:图片比例校验 开始】 ==========
// 获取图片宽高信息uniapp多端兼容APIAPP/小程序/H5都支持
const imageInfo = await uni.getImageInfo({
src: file.path
});
const {
width,
height
} = imageInfo;
console.log('图片宽高:', width, height, '实际比例:', (width / height).toFixed(4));
// 校验4:3比例容错0.05
const isRatioValid = checkImageRatio(width, height, 0.05);
if (!isRatioValid) {
uni.showToast({
title: '图片比例需为4:3允许轻微偏差',
icon: 'none',
duration: 2000
});
return null; // 比例不符,终止上传流程
}
// ========== 【核心新增:图片比例校验 结束】 ==========
} else if (uploadType == 'video') {
const res = await uni.chooseVideo({
count: 1,
sourceType: ['album', 'camera'],
compressed: false
})
// #ifdef H5
file = res.tempFile;
// #endif
// #ifdef APP-PLUS || MP-WEIXIN
file = res;
// #endif
}
const result = await uploadFile(file, userId, type, uploadType)
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, uploadType) => {
console.log('file=======', file)
console.log('userId=======', userId)
// 检查文件大小
if (uploadType == 'image') {
if (file.size > 5 * 1024 * 1024) {
uni.showToast({
title: `文件大小不能超过5MB`,
icon: 'none'
})
return Promise.reject(new Error('文件大小超出限制'))
}
} else if (uploadType == 'video') {
if (file.size > 100 * 1024 * 1024) {
uni.showToast({
title: `文件大小不能超过100MB`,
icon: 'none'
})
return Promise.reject(new Error('文件大小超出限制'))
}
}
let date = new Date().getTime()
console.log('file', file)
// let imageType = file.path.split('.')
let imageType;
if (uploadType == 'image') {
//imageType = file.path.split('.')
imageType = file.name.split('.')
} else if (uploadType == 'video') {
// #ifdef H5
imageType = file.name.split('.')
// #endif
// #ifdef APP-PLUS || MP-WEIXIN
imageType = file.tempFilePath.split('.')
// #endif
}
let artisan = type == 1 ? 'yh' : type == 2 ? 'syr' : type == 3 ? 'sj' : '';
let name = `${userId}_${artisan}_${date}.${imageType[imageType.length - 1]}`
console.log('file.path', file.path)
console.log('imageType', imageType)
console.log('name', name)
try {
// 1. 获取OSS上传凭证
const ossConfig = await getOssConfig(type)
// 2. 上传文件
const uploadRes = await uploadToOss(file, ossConfig, name, uploadType)
// 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, uploadType) => {
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;
let path;
if (uploadType == 'image') {
path = file.path
// 获取文件扩展名并设置 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'] = mimeTypes[ext],
formData['x-oss-meta-content-type'] = mimeTypes[ext]
}
console.log('formData', formData)
} else if (uploadType == 'video') {
// #ifdef H5
path = file.name
// #endif
// #ifdef APP-PLUS || MP-WEIXIN
path = file.tempFilePath
// #endif
}
uni.uploadFile({
url: ossConfig.host,
filePath: 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)
}
});
// #endif
})
}
export default {
handleUpload
}