feat:图片压缩
This commit is contained in:
1 parent
71cdf53b68
commit
e38551b153
7 files changed
+132
-61
No files matched your search
+1
-1
@@ -3,7 +3,7 @@ NODE_ENV=development
|
||||
VITE_DEV=true
|
||||
# 请求路径
|
||||
# VITE_BASE_URL= http://116.148.200.224:48089
|
||||
# VITE_BASE_URL= http://127.0.0.1:8089
|
||||
#VITE_BASE_URL=http://192.168.68.96:8089
|
||||
VITE_BASE_URL='https://xrhomeapi.asset-cloud.com.cn'
|
||||
# 文件上传类型:server - 后端上传, client - 前端直连上传,仅支持 S3 服务
|
||||
VITE_UPLOAD_TYPE=server
|
||||
|
||||
Generated
+29
@@ -24,6 +24,7 @@
|
||||
"benz-amr-recorder": "^1.1.5",
|
||||
"bpmn-js-token-simulation": "^0.36.0",
|
||||
"camunda-bpmn-moddle": "^7.0.1",
|
||||
"compressorjs": "^1.2.1",
|
||||
"cropperjs": "^1.6.1",
|
||||
"crypto-js": "^4.2.0",
|
||||
"dayjs": "^1.11.10",
|
||||
@@ -7298,6 +7299,12 @@
|
||||
"integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/blueimp-canvas-to-blob": {
|
||||
"version": "3.29.0",
|
||||
"resolved": "https://registry.npmmirror.com/blueimp-canvas-to-blob/-/blueimp-canvas-to-blob-3.29.0.tgz",
|
||||
"integrity": "sha512-0pcSSGxC0QxT+yVkivxIqW0Y4VlO2XSDPofBAqoJ1qJxgH9eiUDLv50Rixij2cDuEfx4M6DpD9UGZpRhT5Q8qg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/boolbase": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/boolbase/-/boolbase-1.0.0.tgz",
|
||||
@@ -8020,6 +8027,16 @@
|
||||
"resolved": "https://registry.npmmirror.com/component-event/-/component-event-0.2.1.tgz",
|
||||
"integrity": "sha512-wGA++isMqiDq1jPYeyv2as/Bt/u+3iLW0rEa+8NQ82jAv3TgqMiCM+B2SaBdn2DfLilLjjq736YcezihRYhfxw=="
|
||||
},
|
||||
"node_modules/compressorjs": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmmirror.com/compressorjs/-/compressorjs-1.2.1.tgz",
|
||||
"integrity": "sha512-+geIjeRnPhQ+LLvvA7wxBQE5ddeLU7pJ3FsKFWirDw6veY3s9iLxAQEw7lXGHnhCJvBujEQWuNnGzZcvCvdkLQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"blueimp-canvas-to-blob": "^3.29.0",
|
||||
"is-blob": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/compute-scroll-into-view": {
|
||||
"version": "1.0.20",
|
||||
"resolved": "https://registry.npmmirror.com/compute-scroll-into-view/-/compute-scroll-into-view-1.0.20.tgz",
|
||||
@@ -11515,6 +11532,18 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/is-blob": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmmirror.com/is-blob/-/is-blob-2.1.0.tgz",
|
||||
"integrity": "sha512-SZ/fTft5eUhQM6oF/ZaASFDEdbFVe89Imltn9uZr03wdKMcWNVYSMjQPFtg05QuNkt5l5c135ElvXEQG0rk4tw==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/is-boolean-object": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmmirror.com/is-boolean-object/-/is-boolean-object-1.2.2.tgz",
|
||||
|
||||
+2
-1
@@ -40,6 +40,7 @@
|
||||
"benz-amr-recorder": "^1.1.5",
|
||||
"bpmn-js-token-simulation": "^0.36.0",
|
||||
"camunda-bpmn-moddle": "^7.0.1",
|
||||
"compressorjs": "^1.2.1",
|
||||
"cropperjs": "^1.6.1",
|
||||
"crypto-js": "^4.2.0",
|
||||
"dayjs": "^1.11.10",
|
||||
@@ -152,4 +153,4 @@
|
||||
"node": ">= 16.0.0",
|
||||
"pnpm": ">=8.6.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,19 +1,8 @@
|
||||
<template>
|
||||
<div class="upload-box">
|
||||
<el-upload
|
||||
:id="uuid"
|
||||
:accept="fileType.join(',')"
|
||||
:action="uploadUrl"
|
||||
:before-upload="beforeUpload"
|
||||
:class="['upload', drag ? 'no-border' : '']"
|
||||
:disabled="disabled"
|
||||
:drag="drag"
|
||||
:http-request="httpRequest"
|
||||
:multiple="false"
|
||||
:on-error="uploadError"
|
||||
:on-success="uploadSuccess"
|
||||
:show-file-list="false"
|
||||
>
|
||||
<el-upload :id="uuid" :accept="fileType.join(',')" :action="uploadUrl" :before-upload="beforeUpload"
|
||||
:class="['upload', drag ? 'no-border' : '']" :disabled="disabled" :drag="drag" :http-request="httpRequest"
|
||||
:multiple="false" :on-error="uploadError" :on-success="uploadSuccess" :show-file-list="false">
|
||||
<template v-if="modelValue">
|
||||
<img :src="modelValue" class="upload-image" />
|
||||
<div class="upload-handle" @click.stop>
|
||||
@@ -52,7 +41,7 @@ import type { UploadProps } from 'element-plus'
|
||||
import { generateUUID } from '@/utils'
|
||||
import { propTypes } from '@/utils/propTypes'
|
||||
import { createImageViewer } from '@/components/ImageViewer'
|
||||
import { useUpload } from '@/components/UploadFile/src/useUpload'
|
||||
import { compressImage, useUpload } from '@/components/UploadFile/src/useUpload'
|
||||
|
||||
defineOptions({ name: 'UploadImg' })
|
||||
|
||||
@@ -106,15 +95,27 @@ const editImg = () => {
|
||||
dom && dom.dispatchEvent(new MouseEvent('click'))
|
||||
}
|
||||
|
||||
const beforeUpload: UploadProps['beforeUpload'] = (rawFile) => {
|
||||
const beforeUpload: UploadProps['beforeUpload'] = async (rawFile) => {
|
||||
const imgSize = rawFile.size / 1024 / 1024 < props.fileSize
|
||||
const imgType = props.fileType
|
||||
if (!imgType.includes(rawFile.type as FileTypes))
|
||||
message.notifyWarning('上传图片不符合所需的格式!')
|
||||
if (!imgSize) message.notifyWarning(`上传图片大小不能超过 ${props.fileSize}M!`)
|
||||
return imgType.includes(rawFile.type as FileTypes) && imgSize
|
||||
}
|
||||
|
||||
if (!imgType.includes(rawFile.type as FileTypes)) {
|
||||
message.notifyWarning('上传图片不符合所需的格式!')
|
||||
return false
|
||||
}
|
||||
if (!imgSize) {
|
||||
message.notifyWarning(`上传图片大小不能超过 ${props.fileSize}M!`)
|
||||
return false
|
||||
}
|
||||
|
||||
// ===== 新增:压缩图片 =====
|
||||
try {
|
||||
const compressed = await compressImage(rawFile, 0.8)
|
||||
return compressed
|
||||
} catch {
|
||||
return rawFile // 失败则用原图
|
||||
}
|
||||
}
|
||||
// 图片上传成功提示
|
||||
const uploadSuccess: UploadProps['onSuccess'] = (res: any): void => {
|
||||
message.success('上传成功')
|
||||
@@ -129,6 +130,7 @@ const uploadError = () => {
|
||||
<style lang="scss" scoped>
|
||||
.is-error {
|
||||
.upload {
|
||||
|
||||
:deep(.el-upload),
|
||||
:deep(.el-upload-dragger) {
|
||||
border: 1px dashed var(--el-color-danger) !important;
|
||||
@@ -141,6 +143,7 @@ const uploadError = () => {
|
||||
}
|
||||
|
||||
:deep(.disabled) {
|
||||
|
||||
.el-upload,
|
||||
.el-upload-dragger {
|
||||
cursor: not-allowed !important;
|
||||
|
||||
@@ -1,21 +1,9 @@
|
||||
<template>
|
||||
<div class="upload-box">
|
||||
<el-upload
|
||||
v-model:file-list="fileList"
|
||||
:accept="fileType.join(',')"
|
||||
:action="uploadUrl"
|
||||
:before-upload="beforeUpload"
|
||||
:class="['upload', drag ? 'no-border' : '']"
|
||||
:disabled="disabled"
|
||||
:drag="drag"
|
||||
:http-request="httpRequest"
|
||||
:limit="limit"
|
||||
:multiple="true"
|
||||
:on-error="uploadError"
|
||||
:on-exceed="handleExceed"
|
||||
:on-success="uploadSuccess"
|
||||
list-type="picture-card"
|
||||
>
|
||||
<el-upload v-model:file-list="fileList" :accept="fileType.join(',')" :action="uploadUrl"
|
||||
:before-upload="beforeUpload" :class="['upload', drag ? 'no-border' : '']" :disabled="disabled" :drag="drag"
|
||||
:http-request="httpRequest" :limit="limit" :multiple="true" :on-error="uploadError" :on-exceed="handleExceed"
|
||||
:on-success="uploadSuccess" list-type="picture-card">
|
||||
<div class="upload-empty">
|
||||
<slot name="empty">
|
||||
<Icon icon="ep:plus" />
|
||||
@@ -47,7 +35,7 @@ import { ElNotification } from 'element-plus'
|
||||
import { createImageViewer } from '@/components/ImageViewer'
|
||||
|
||||
import { propTypes } from '@/utils/propTypes'
|
||||
import { useUpload } from '@/components/UploadFile/src/useUpload'
|
||||
import { compressImage, useUpload } from '@/components/UploadFile/src/useUpload'
|
||||
|
||||
defineOptions({ name: 'UploadImgs' })
|
||||
|
||||
@@ -93,23 +81,36 @@ const uploadList = ref<UploadUserFile[]>([])
|
||||
* @description 文件上传之前判断
|
||||
* @param rawFile 上传的文件
|
||||
* */
|
||||
const beforeUpload: UploadProps['beforeUpload'] = (rawFile) => {
|
||||
const beforeUpload: UploadProps['beforeUpload'] = async (rawFile) => {
|
||||
const imgSize = rawFile.size / 1024 / 1024 < props.fileSize
|
||||
const imgType = props.fileType
|
||||
if (!imgType.includes(rawFile.type as FileTypes))
|
||||
|
||||
if (!imgType.includes(rawFile.type as FileTypes)) {
|
||||
ElNotification({
|
||||
title: '温馨提示',
|
||||
message: '上传图片不符合所需的格式!',
|
||||
type: 'warning'
|
||||
})
|
||||
if (!imgSize)
|
||||
return false
|
||||
}
|
||||
if (!imgSize) {
|
||||
ElNotification({
|
||||
title: '温馨提示',
|
||||
message: `上传图片大小不能超过 ${props.fileSize}M!`,
|
||||
type: 'warning'
|
||||
})
|
||||
return false
|
||||
}
|
||||
|
||||
uploadNumber.value++
|
||||
return imgType.includes(rawFile.type as FileTypes) && imgSize
|
||||
|
||||
// ===== 新增:压缩图片 =====
|
||||
try {
|
||||
const compressed = await compressImage(rawFile, 0.8)
|
||||
return compressed
|
||||
} catch {
|
||||
return rawFile // 失败则用原图
|
||||
}
|
||||
}
|
||||
|
||||
// 图片上传成功
|
||||
@@ -186,6 +187,7 @@ const handleExceed = () => {
|
||||
<style lang="scss" scoped>
|
||||
.is-error {
|
||||
.upload {
|
||||
|
||||
:deep(.el-upload--picture-card),
|
||||
:deep(.el-upload-dragger) {
|
||||
border: 1px dashed var(--el-color-danger) !important;
|
||||
@@ -198,6 +200,7 @@ const handleExceed = () => {
|
||||
}
|
||||
|
||||
:deep(.disabled) {
|
||||
|
||||
.el-upload--picture-card,
|
||||
.el-upload-dragger {
|
||||
cursor: not-allowed;
|
||||
|
||||
@@ -2,6 +2,7 @@ import * as FileApi from '@/api/infra/file'
|
||||
import CryptoJS from 'crypto-js'
|
||||
import { UploadRawFile, UploadRequestOptions } from 'element-plus/es/components/upload/src/upload'
|
||||
import axios from 'axios'
|
||||
import Compressor from 'compressorjs'
|
||||
|
||||
/**
|
||||
* 获得上传 URL
|
||||
@@ -104,3 +105,29 @@ enum UPLOAD_TYPE {
|
||||
// 客户端发送到后端上传
|
||||
SERVER = 'server'
|
||||
}
|
||||
|
||||
|
||||
export const compressImage = (file: File, quality = 0.6): Promise<File> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
new Compressor(file, {
|
||||
quality,
|
||||
maxWidth: 1920,
|
||||
maxHeight: 1920,
|
||||
mimeType: 'image/jpeg',
|
||||
convertSize: 5 * 1024 * 1024,
|
||||
checkOrientation: true,
|
||||
success(result) {
|
||||
const compressedFile = new File([result], file.name, {
|
||||
type: result.type,
|
||||
lastModified: Date.now()
|
||||
})
|
||||
console.log(`压缩: ${(file.size / 1024).toFixed(2)}KB → ${(compressedFile.size / 1024).toFixed(2)}KB`)
|
||||
resolve(compressedFile)
|
||||
},
|
||||
error(err) {
|
||||
console.error('压缩失败:', err)
|
||||
reject(err)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
@@ -1,21 +1,9 @@
|
||||
<template>
|
||||
<Dialog v-model="dialogVisible" title="上传文件">
|
||||
<el-upload
|
||||
ref="uploadRef"
|
||||
v-model:file-list="fileList"
|
||||
:action="uploadUrl"
|
||||
:auto-upload="false"
|
||||
:data="data"
|
||||
:disabled="formLoading"
|
||||
:limit="1"
|
||||
:on-change="handleFileChange"
|
||||
:on-error="submitFormError"
|
||||
:on-exceed="handleExceed"
|
||||
:on-success="submitFormSuccess"
|
||||
:http-request="httpRequest"
|
||||
accept=".jpg, .png, .gif"
|
||||
drag
|
||||
>
|
||||
<el-upload ref="uploadRef" v-model:file-list="fileList" :action="uploadUrl" :auto-upload="false"
|
||||
:before-upload="beforeUpload" :data="data" :disabled="formLoading" :limit="1" :on-change="handleFileChange"
|
||||
:on-error="submitFormError" :on-exceed="handleExceed" :on-success="submitFormSuccess" :http-request="httpRequest"
|
||||
accept=".jpg, .png, .gif" drag>
|
||||
<i class="el-icon-upload"></i>
|
||||
<div class="el-upload__text"> 将文件拖到此处,或 <em>点击上传</em></div>
|
||||
<template #tip>
|
||||
@@ -31,7 +19,8 @@
|
||||
</Dialog>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { useUpload } from '@/components/UploadFile/src/useUpload'
|
||||
import { useUpload, compressImage } from '@/components/UploadFile/src/useUpload'
|
||||
import type { UploadProps, UploadRawFile } from 'element-plus'
|
||||
|
||||
defineOptions({ name: 'InfraFileForm' })
|
||||
|
||||
@@ -53,6 +42,25 @@ const open = async () => {
|
||||
}
|
||||
defineExpose({ open }) // 提供 open 方法,用于打开弹窗
|
||||
|
||||
/** 文件上传之前进行压缩 */
|
||||
const beforeUpload: UploadProps['beforeUpload'] = async (file: UploadRawFile) => {
|
||||
// 验证文件类型
|
||||
const allowedTypes = ['image/jpeg', 'image/jpg', 'image/png', 'image/gif']
|
||||
if (!allowedTypes.includes(file.type)) {
|
||||
message.error('仅允许上传 jpg、png、gif 格式文件!')
|
||||
return false
|
||||
}
|
||||
|
||||
// 压缩图片
|
||||
try {
|
||||
const compressed = await compressImage(file, 0.8)
|
||||
return compressed
|
||||
} catch (error) {
|
||||
message.warning('图片压缩失败,将使用原图上传')
|
||||
return file
|
||||
}
|
||||
}
|
||||
|
||||
/** 处理上传的文件发生变化 */
|
||||
const handleFileChange = (file) => {
|
||||
data.value.path = file.name
|
||||
|
||||
Reference in new issue
Block a user