u
This commit is contained in:
1 parent
3e172a1d53
commit
401a6719f6
12 files changed
+487
-277
No files matched your search
@@ -1,42 +1,42 @@
|
||||
import { getAliyunKeyApi } from "@/request/api";
|
||||
import { getAliyunKeyApi, insertFileApi } from "@/request/api";
|
||||
|
||||
/**
|
||||
* 选择并压缩图片
|
||||
*/
|
||||
export function uploadImage(options = {}) {
|
||||
const { quality = 0.9, maxSize = 512000 } = options
|
||||
const { quality = 0.9, maxSize = 512000 } = options;
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
if (typeof document === 'undefined') {
|
||||
reject(new Error('Require browser environment'))
|
||||
return
|
||||
if (typeof document === "undefined") {
|
||||
reject(new Error("Require browser environment"));
|
||||
return;
|
||||
}
|
||||
|
||||
const input = document.createElement('input')
|
||||
input.type = 'file'
|
||||
input.accept = 'image/*'
|
||||
input.style.display = 'none'
|
||||
const input = document.createElement("input");
|
||||
input.type = "file";
|
||||
input.accept = "image/*";
|
||||
input.style.display = "none";
|
||||
|
||||
input.onchange = async (e) => {
|
||||
const file = e.target.files?.[0]
|
||||
const file = e.target.files?.[0];
|
||||
if (!file) {
|
||||
reject(new Error('No file selected'))
|
||||
return
|
||||
reject(new Error("No file selected"));
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
if (!file.type.startsWith('image/')) {
|
||||
throw new Error('Invalid image file')
|
||||
if (!file.type.startsWith("image/")) {
|
||||
throw new Error("Invalid image file");
|
||||
}
|
||||
|
||||
// 创建一个临时URL来加载图片
|
||||
const url = URL.createObjectURL(file)
|
||||
const url = URL.createObjectURL(file);
|
||||
|
||||
// 调用 compressImage 进行压缩
|
||||
const compressResult = await compressImage(url, quality, maxSize)
|
||||
const compressResult = await compressImage(url, quality, maxSize);
|
||||
|
||||
// 释放临时URL
|
||||
URL.revokeObjectURL(url)
|
||||
URL.revokeObjectURL(url);
|
||||
|
||||
resolve({
|
||||
blob: compressResult.blob,
|
||||
@@ -44,19 +44,17 @@ export function uploadImage(options = {}) {
|
||||
fileName: file.name,
|
||||
fileExt: getFileExtension(file.name),
|
||||
fileSize: file.size,
|
||||
})
|
||||
});
|
||||
} catch (err) {
|
||||
reject(err);
|
||||
} finally {
|
||||
document.body.removeChild(input);
|
||||
}
|
||||
catch (err) {
|
||||
reject(err)
|
||||
}
|
||||
finally {
|
||||
document.body.removeChild(input)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
document.body.appendChild(input)
|
||||
input.click()
|
||||
})
|
||||
document.body.appendChild(input);
|
||||
input.click();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -64,26 +62,26 @@ export function uploadImage(options = {}) {
|
||||
*/
|
||||
export function uploadVideo() {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (typeof document === 'undefined') {
|
||||
reject(new Error('Require browser environment'))
|
||||
return
|
||||
if (typeof document === "undefined") {
|
||||
reject(new Error("Require browser environment"));
|
||||
return;
|
||||
}
|
||||
|
||||
const input = document.createElement('input')
|
||||
input.type = 'file'
|
||||
input.accept = 'video/*'
|
||||
input.style.display = 'none'
|
||||
const input = document.createElement("input");
|
||||
input.type = "file";
|
||||
input.accept = "video/*";
|
||||
input.style.display = "none";
|
||||
|
||||
input.onchange = (e) => {
|
||||
const file = e.target.files?.[0]
|
||||
const file = e.target.files?.[0];
|
||||
if (!file) {
|
||||
reject(new Error('No file selected'))
|
||||
return
|
||||
reject(new Error("No file selected"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!file.type.startsWith('video/')) {
|
||||
reject(new Error('Invalid video file'))
|
||||
return
|
||||
if (!file.type.startsWith("video/")) {
|
||||
reject(new Error("Invalid video file"));
|
||||
return;
|
||||
}
|
||||
|
||||
resolve({
|
||||
@@ -92,121 +90,114 @@ export function uploadVideo() {
|
||||
fileName: file.name,
|
||||
fileExt: getFileExtension(file.name),
|
||||
fileSize: file.size,
|
||||
})
|
||||
});
|
||||
|
||||
document.body.removeChild(input)
|
||||
}
|
||||
document.body.removeChild(input);
|
||||
};
|
||||
|
||||
document.body.appendChild(input)
|
||||
input.click()
|
||||
})
|
||||
document.body.appendChild(input);
|
||||
input.click();
|
||||
});
|
||||
}
|
||||
|
||||
// 压缩图片
|
||||
export async function compressImage(url, quality = 0.9, maxSize = 512000) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const img = new Image()
|
||||
img.src = url
|
||||
const img = new Image();
|
||||
img.src = url;
|
||||
|
||||
img.onload = async () => {
|
||||
try {
|
||||
// 获取原图大小
|
||||
const imgSize = await fetch(url)
|
||||
.then(res => res.blob())
|
||||
.then(blob => blob.size)
|
||||
.then((res) => res.blob())
|
||||
.then((blob) => blob.size);
|
||||
|
||||
if (imgSize <= maxSize) {
|
||||
return resolve({ url, size: imgSize, blob: await fetch(url).then(res => res.blob()) })
|
||||
return resolve({ url, size: imgSize, blob: await fetch(url).then((res) => res.blob()) });
|
||||
}
|
||||
const canvas = document.createElement('canvas')
|
||||
const ctx = canvas.getContext('2d')
|
||||
if (!ctx)
|
||||
return reject(new Error('无法获取canvas上下文'))
|
||||
const canvas = document.createElement("canvas");
|
||||
const ctx = canvas.getContext("2d");
|
||||
if (!ctx) return reject(new Error("无法获取canvas上下文"));
|
||||
|
||||
let targetWidth = img.width
|
||||
let targetHeight = img.height
|
||||
let targetWidth = img.width;
|
||||
let targetHeight = img.height;
|
||||
|
||||
// 最大边长限制
|
||||
const maxEdge = 2000
|
||||
const maxEdge = 2000;
|
||||
if (targetWidth > maxEdge || targetHeight > maxEdge) {
|
||||
if (targetWidth > targetHeight) {
|
||||
targetHeight = (maxEdge * targetHeight) / targetWidth
|
||||
targetWidth = maxEdge
|
||||
}
|
||||
else {
|
||||
targetWidth = (maxEdge * targetWidth) / targetHeight
|
||||
targetHeight = maxEdge
|
||||
targetHeight = (maxEdge * targetHeight) / targetWidth;
|
||||
targetWidth = maxEdge;
|
||||
} else {
|
||||
targetWidth = (maxEdge * targetWidth) / targetHeight;
|
||||
targetHeight = maxEdge;
|
||||
}
|
||||
}
|
||||
|
||||
canvas.width = targetWidth
|
||||
canvas.height = targetHeight
|
||||
canvas.width = targetWidth;
|
||||
canvas.height = targetHeight;
|
||||
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height)
|
||||
ctx.drawImage(img, 0, 0, targetWidth, targetHeight)
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
ctx.drawImage(img, 0, 0, targetWidth, targetHeight);
|
||||
|
||||
const getBlob = q =>
|
||||
const getBlob = (q) =>
|
||||
new Promise((resolve, reject) => {
|
||||
canvas.toBlob(
|
||||
blob => (blob ? resolve(blob) : reject(new Error('Blob转换失败'))),
|
||||
'image/jpeg',
|
||||
(blob) => (blob ? resolve(blob) : reject(new Error("Blob转换失败"))),
|
||||
"image/jpeg",
|
||||
q,
|
||||
)
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
let blob = await getBlob(quality)
|
||||
let blob = await getBlob(quality);
|
||||
|
||||
// 调整质量直到接近最大文件大小
|
||||
let minQ = 0.5
|
||||
let maxQ = quality
|
||||
let attempts = 0
|
||||
let minQ = 0.5;
|
||||
let maxQ = quality;
|
||||
let attempts = 0;
|
||||
|
||||
while (blob.size > maxSize && maxQ - minQ > 0.01 && attempts < 5) {
|
||||
const midQ = (minQ + maxQ) / 2
|
||||
blob = await getBlob(midQ)
|
||||
const midQ = (minQ + maxQ) / 2;
|
||||
blob = await getBlob(midQ);
|
||||
if (blob.size > maxSize) {
|
||||
maxQ = midQ
|
||||
maxQ = midQ;
|
||||
} else {
|
||||
minQ = midQ;
|
||||
}
|
||||
else {
|
||||
minQ = midQ
|
||||
}
|
||||
attempts++
|
||||
attempts++;
|
||||
}
|
||||
resolve({ blob, size: blob.size, url: URL.createObjectURL(blob) })
|
||||
resolve({ blob, size: blob.size, url: URL.createObjectURL(blob) });
|
||||
} catch (err) {
|
||||
reject(err);
|
||||
}
|
||||
catch (err) {
|
||||
reject(err)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
img.onerror = () => reject(new Error('图片加载失败'))
|
||||
})
|
||||
img.onerror = () => reject(new Error("图片加载失败"));
|
||||
});
|
||||
}
|
||||
|
||||
export function formatFileSize(size) {
|
||||
if (size < 1024)
|
||||
return `${size} B`
|
||||
else if (size < 1024 * 1024)
|
||||
return `${(size / 1024).toFixed(2)} KB`
|
||||
else if (size < 1024 * 1024 * 1024)
|
||||
return `${(size / (1024 * 1024)).toFixed(2)} MB`
|
||||
else return `${(size / (1024 * 1024 * 1024)).toFixed(2)} GB`
|
||||
if (size < 1024) return `${size} B`;
|
||||
else if (size < 1024 * 1024) return `${(size / 1024).toFixed(2)} KB`;
|
||||
else if (size < 1024 * 1024 * 1024) return `${(size / (1024 * 1024)).toFixed(2)} MB`;
|
||||
else return `${(size / (1024 * 1024 * 1024)).toFixed(2)} GB`;
|
||||
}
|
||||
|
||||
// 获取文件扩展名并进行分类
|
||||
export function getFileExtension(fileName) {
|
||||
// 获取文件扩展名
|
||||
const fileExt = fileName.includes('.')
|
||||
? fileName.slice(fileName.lastIndexOf('.') + 1).toLowerCase() // 获取扩展名并转为小写
|
||||
: ''
|
||||
const fileExt = fileName.includes(".")
|
||||
? fileName.slice(fileName.lastIndexOf(".") + 1).toLowerCase() // 获取扩展名并转为小写
|
||||
: "";
|
||||
|
||||
// 如果是office类文件,将其归类到 "office"
|
||||
if (['docx', 'docm', 'xls', 'xlsx'].includes(fileExt)) {
|
||||
return 'office'
|
||||
if (["docx", "docm", "xls", "xlsx"].includes(fileExt)) {
|
||||
return "office";
|
||||
}
|
||||
|
||||
// 返回扩展名
|
||||
return fileExt
|
||||
return fileExt;
|
||||
}
|
||||
|
||||
// 上传到阿里云
|
||||
@@ -216,29 +207,27 @@ export function uploadFile(blob, fileName, fileExt, fileSize, xh, moduleid, fath
|
||||
getAliyunKeyApi()
|
||||
.then(async (res) => {
|
||||
try {
|
||||
const aliyunKey = res.data
|
||||
const formData = new FormData()
|
||||
const aliyunKey = res.data;
|
||||
const formData = new FormData();
|
||||
|
||||
let uniqueName = `${Date.now()}_${Math.random()
|
||||
.toString(36)
|
||||
.slice(2)}`
|
||||
let uniqueName = `${Date.now()}_${Math.random().toString(36).slice(2)}`;
|
||||
|
||||
if (fileExt) {
|
||||
uniqueName += `.${fileExt}`
|
||||
uniqueName += `.${fileExt}`;
|
||||
}
|
||||
|
||||
formData.append('key', `${aliyunKey.dir}${uniqueName}`)
|
||||
formData.append('OSSAccessKeyId', aliyunKey.accessid)
|
||||
formData.append('policy', aliyunKey.policy)
|
||||
formData.append('Signature', aliyunKey.signature)
|
||||
formData.append('file', blob, uniqueName)
|
||||
formData.append("key", `${aliyunKey.dir}${uniqueName}`);
|
||||
formData.append("OSSAccessKeyId", aliyunKey.accessid);
|
||||
formData.append("policy", aliyunKey.policy);
|
||||
formData.append("Signature", aliyunKey.signature);
|
||||
formData.append("file", blob, uniqueName);
|
||||
|
||||
const xhr = new XMLHttpRequest()
|
||||
xhr.open('POST', aliyunKey.host, true)
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.open("POST", aliyunKey.host, true);
|
||||
|
||||
xhr.onload = async () => {
|
||||
if (xhr.status === 200 || xhr.status === 204) {
|
||||
const allFilePath = `${aliyunKey.host}/${aliyunKey.dir}${uniqueName}`
|
||||
const allFilePath = `${aliyunKey.host}/${aliyunKey.dir}${uniqueName}`;
|
||||
|
||||
const insertRes = await insertFileApi({
|
||||
father,
|
||||
@@ -248,8 +237,8 @@ export function uploadFile(blob, fileName, fileExt, fileSize, xh, moduleid, fath
|
||||
mx_mapfilename: allFilePath,
|
||||
mx_filesize: fileSize,
|
||||
mx_fileext: fileExt,
|
||||
mx_cate_id: cateid || '',
|
||||
})
|
||||
mx_cate_id: cateid || "",
|
||||
});
|
||||
|
||||
if (insertRes.success) {
|
||||
resolve({
|
||||
@@ -260,33 +249,30 @@ export function uploadFile(blob, fileName, fileExt, fileSize, xh, moduleid, fath
|
||||
mx_mapfilename: allFilePath,
|
||||
mx_filesize: fileSize,
|
||||
mx_fileext: fileExt,
|
||||
mx_cate_id: cateid || '',
|
||||
})
|
||||
}
|
||||
else {
|
||||
reject(new Error(insertRes.data.message))
|
||||
mx_cate_id: cateid || "",
|
||||
});
|
||||
} else {
|
||||
reject(new Error(insertRes.data.message));
|
||||
}
|
||||
} else {
|
||||
ElMessage.error("上传失败,请稍后再试");
|
||||
reject(new Error(`OSS 上传失败: ${xhr.responseText}`));
|
||||
}
|
||||
else {
|
||||
ElMessage.error('上传失败,请稍后再试')
|
||||
reject(new Error(`OSS 上传失败: ${xhr.responseText}`))
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
xhr.onerror = () => {
|
||||
ElMessage.error('上传失败,请稍后再试')
|
||||
reject(new Error('OSS 上传异常'))
|
||||
}
|
||||
ElMessage.error("上传失败,请稍后再试");
|
||||
reject(new Error("OSS 上传异常"));
|
||||
};
|
||||
|
||||
xhr.send(formData)
|
||||
}
|
||||
catch (err) {
|
||||
ElMessage.error('上传失败,请稍后再试')
|
||||
reject(err)
|
||||
xhr.send(formData);
|
||||
} catch (err) {
|
||||
ElMessage.error("上传失败,请稍后再试");
|
||||
reject(err);
|
||||
}
|
||||
})
|
||||
.catch(reject)
|
||||
})
|
||||
.catch(reject);
|
||||
});
|
||||
}
|
||||
|
||||
export function getAliyunFileBlob(url) {
|
||||
@@ -294,73 +280,70 @@ export function getAliyunFileBlob(url) {
|
||||
// 创建一个独立的异步函数来处理 fetch 请求
|
||||
async function fetchFile() {
|
||||
try {
|
||||
const response = await fetch(url, { mode: 'cors' })
|
||||
const response = await fetch(url, { mode: "cors" });
|
||||
|
||||
// 检查响应状态
|
||||
if (!response.ok) {
|
||||
ElMessage.error(`下载失败:${response.status}`)
|
||||
reject(new Error(`下载失败:${response.status}`))
|
||||
return
|
||||
ElMessage.error(`下载失败:${response.status}`);
|
||||
reject(new Error(`下载失败:${response.status}`));
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取文件内容
|
||||
const blob = await response.blob()
|
||||
const blob = await response.blob();
|
||||
|
||||
// 返回blob
|
||||
resolve(blob)
|
||||
}
|
||||
catch (error) {
|
||||
resolve(blob);
|
||||
} catch (error) {
|
||||
// 捕获网络请求失败或其他错误
|
||||
ElMessage.error('下载文件时发生错误')
|
||||
reject(error)
|
||||
ElMessage.error("下载文件时发生错误");
|
||||
reject(error);
|
||||
}
|
||||
}
|
||||
|
||||
// 调用异步函数
|
||||
fetchFile()
|
||||
})
|
||||
fetchFile();
|
||||
});
|
||||
}
|
||||
|
||||
export function downloadZip(
|
||||
files,
|
||||
fileName = '文件合集',
|
||||
callback,
|
||||
) {
|
||||
const zip = new JSZip()
|
||||
const addedFiles = new Set() // 用来存储已添加的文件名
|
||||
export function downloadZip(files, fileName = "文件合集", callback) {
|
||||
const zip = new JSZip();
|
||||
const addedFiles = new Set(); // 用来存储已添加的文件名
|
||||
|
||||
let result = files.map((item) => {
|
||||
let promise = getAliyunFileBlob(item.mx_mapfilename).then((res) => {
|
||||
// 处理文件名重复的情况
|
||||
let uniqueFileName = getUniqueFileName(item.mx_filename, addedFiles)
|
||||
zip.file(uniqueFileName, res, { binary: true })
|
||||
addedFiles.add(uniqueFileName) // 添加文件名到已添加的集合中
|
||||
})
|
||||
return promise
|
||||
})
|
||||
let uniqueFileName = getUniqueFileName(item.mx_filename, addedFiles);
|
||||
zip.file(uniqueFileName, res, { binary: true });
|
||||
addedFiles.add(uniqueFileName); // 添加文件名到已添加的集合中
|
||||
});
|
||||
return promise;
|
||||
});
|
||||
|
||||
Promise.all(result).then(() => {
|
||||
zip.generateAsync({ type: 'blob' }).then((res) => {
|
||||
callback && callback()
|
||||
saveAs(res, `${fileName}.zip`)
|
||||
Promise.all(result)
|
||||
.then(() => {
|
||||
zip.generateAsync({ type: "blob" }).then((res) => {
|
||||
callback && callback();
|
||||
saveAs(res, `${fileName}.zip`);
|
||||
});
|
||||
})
|
||||
}).catch(() => {
|
||||
callback && callback()
|
||||
})
|
||||
.catch(() => {
|
||||
callback && callback();
|
||||
});
|
||||
}
|
||||
|
||||
// 处理文件名重复的函数
|
||||
function getUniqueFileName(fileName, addedFiles) {
|
||||
let uniqueFileName = fileName
|
||||
let counter = 1
|
||||
let uniqueFileName = fileName;
|
||||
let counter = 1;
|
||||
|
||||
// 如果文件名已经存在,则在文件名后加上 (1), (2), ...
|
||||
while (addedFiles.has(uniqueFileName)) {
|
||||
const fileNameWithoutExtension = uniqueFileName.replace(/\.[^/.]+$/, '')
|
||||
const extension = uniqueFileName.slice(uniqueFileName.lastIndexOf('.'))
|
||||
uniqueFileName = `${fileNameWithoutExtension} (${counter})${extension}`
|
||||
counter++
|
||||
const fileNameWithoutExtension = uniqueFileName.replace(/\.[^/.]+$/, "");
|
||||
const extension = uniqueFileName.slice(uniqueFileName.lastIndexOf("."));
|
||||
uniqueFileName = `${fileNameWithoutExtension} (${counter})${extension}`;
|
||||
counter++;
|
||||
}
|
||||
|
||||
return uniqueFileName
|
||||
return uniqueFileName;
|
||||
}
|
||||
Reference in new issue
Block a user