完成图片压缩功能

This commit is contained in:
宇阳
2024-08-22 13:39:56 +08:00
parent eeeac68963
commit 009ec2853c
5 changed files with 107 additions and 15 deletions

29
package-lock.json generated
View File

@@ -11,6 +11,7 @@
"antd": "^5.19.3", "antd": "^5.19.3",
"apexcharts": "^3.41.0", "apexcharts": "^3.41.0",
"axios": "^1.7.2", "axios": "^1.7.2",
"compressorjs": "^1.2.1",
"dicebear": "^9.2.1", "dicebear": "^9.2.1",
"flatpickr": "^4.6.13", "flatpickr": "^4.6.13",
"headlessui": "^0.0.0", "headlessui": "^0.0.0",
@@ -2770,6 +2771,12 @@
"node": ">=8" "node": ">=8"
} }
}, },
"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/boxen": { "node_modules/boxen": {
"version": "7.1.1", "version": "7.1.1",
"resolved": "https://registry.npmmirror.com/boxen/-/boxen-7.1.1.tgz", "resolved": "https://registry.npmmirror.com/boxen/-/boxen-7.1.1.tgz",
@@ -3264,6 +3271,16 @@
"node": ">= 6" "node": ">= 6"
} }
}, },
"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-gcd": { "node_modules/compute-gcd": {
"version": "1.2.1", "version": "1.2.1",
"resolved": "https://registry.npmmirror.com/compute-gcd/-/compute-gcd-1.2.1.tgz", "resolved": "https://registry.npmmirror.com/compute-gcd/-/compute-gcd-1.2.1.tgz",
@@ -4230,6 +4247,18 @@
"node": ">=8" "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-ci": { "node_modules/is-ci": {
"version": "3.0.1", "version": "3.0.1",
"resolved": "https://registry.npmmirror.com/is-ci/-/is-ci-3.0.1.tgz", "resolved": "https://registry.npmmirror.com/is-ci/-/is-ci-3.0.1.tgz",

View File

@@ -17,6 +17,7 @@
"antd": "^5.19.3", "antd": "^5.19.3",
"apexcharts": "^3.41.0", "apexcharts": "^3.41.0",
"axios": "^1.7.2", "axios": "^1.7.2",
"compressorjs": "^1.2.1",
"dicebear": "^9.2.1", "dicebear": "^9.2.1",
"flatpickr": "^4.6.13", "flatpickr": "^4.6.13",
"headlessui": "^0.0.0", "headlessui": "^0.0.0",

View File

@@ -1,9 +1,11 @@
import { FileDir } from '@/types/app/file'; import { FileDir } from '@/types/app/file';
import { InboxOutlined } from '@ant-design/icons'; import { InboxOutlined } from '@ant-design/icons';
import type { UploadProps } from 'antd'; import type { UploadProps } from 'antd';
import { message, Modal, Upload } from 'antd'; import { message, Modal, Radio, Select, Upload } from 'antd';
import { useUserStore } from '@/stores' import { useUserStore } from '@/stores';
import { baseURL } from '@/utils/request' import { baseURL } from '@/utils/request';
import Compressor from 'compressorjs';
import { useState } from 'react';
const { Dragger } = Upload; const { Dragger } = Upload;
@@ -15,7 +17,9 @@ interface UploadFileProps {
} }
export default ({ dir, open, onCancel, onSuccess }: UploadFileProps) => { export default ({ dir, open, onCancel, onSuccess }: UploadFileProps) => {
const store = useUserStore() const store = useUserStore();
const [quality, setQuality] = useState(1000);
const [isCompressionUpload, setIsCompressionUpload] = useState(false);
const uploadProps: UploadProps = { const uploadProps: UploadProps = {
name: 'files', name: 'files',
@@ -25,28 +29,80 @@ export default ({ dir, open, onCancel, onSuccess }: UploadFileProps) => {
headers: { headers: {
"Authorization": `Bearer ${store.token}` "Authorization": `Bearer ${store.token}`
}, },
// 上传之前触发
beforeUpload: async (file) => {
if (quality === 1000) return file
// 对图片进行压缩处理
return new Promise((resolve, reject) => {
new Compressor(file, {
quality,
success: (file) => {
resolve(file);
},
error: (err) => {
reject(err);
},
});
})
},
onChange(info) { onChange(info) {
const { status } = info.file; const { status } = info.file;
let res; let res;
if (status !== 'uploading') { if (status !== 'uploading') {
res = info?.file?.response res = info?.file?.response;
if (res.code === 400) return message.error(res.message) if (res?.code === 400) return message.error(res.message);
} }
if (status === 'done') { if (status === 'done') {
message.success(`文件上传成功`); message.success(`文件上传成功`);
onSuccess() onSuccess();
} else if (status === 'error') { } else if (status === 'error') {
message.error(`文件上传失败:${res.message}`); message.error(`文件上传失败:${res?.message}`);
} }
}, },
className: "py-4" className: "py-4"
}; };
// 初始化操作
const onCloseModel = () => {
setIsCompressionUpload(false);
setQuality(1000);
onCancel();
}
return ( return (
<> <>
<Modal title="文件上传" open={open} onCancel={onCancel} footer={null}> <Modal title="文件上传" open={open} onCancel={onCloseModel} footer={null}>
<div className='my-4'>
<Radio.Group defaultValue={0} onChange={(e) => setIsCompressionUpload(e.target.value ? true : false)}>
<Radio value={0}></Radio>
<Radio value={1}></Radio>
</Radio.Group>
{
isCompressionUpload && <Select
onChange={setQuality}
options={[
{ value: NaN, label: '自适应压缩(推荐)' },
{ value: 1, label: '轻量压缩' },
{ value: 0.9, label: '0.9' },
{ value: 0.8, label: '0.8' },
{ value: 0.7, label: '0.7' },
{ value: 0.6, label: '0.6' },
{ value: 0.5, label: '0.5' },
{ value: 0.4, label: '0.4' },
{ value: 0.3, label: '0.3' },
{ value: 0.2, label: '0.2' },
{ value: 0.1, label: '0.1' },
]}
placeholder="请选择图片压缩质量"
className='min-w-44'
/>
}
</div>
<Dragger {...uploadProps}> <Dragger {...uploadProps}>
<p className="ant-upload-drag-icon"> <p className="ant-upload-drag-icon">
<InboxOutlined /> <InboxOutlined />
@@ -56,5 +112,5 @@ export default ({ dir, open, onCancel, onSuccess }: UploadFileProps) => {
</Dragger> </Dragger>
</Modal> </Modal>
</> </>
) );
} };

View File

@@ -4,6 +4,7 @@ import { getSwiperListAPI, addSwiperDataAPI, editSwiperDataAPI, delSwiperDataAPI
import { Swiper } from '@/types/app/swiper'; import { Swiper } from '@/types/app/swiper';
import Title from '@/components/Title'; import Title from '@/components/Title';
import { ColumnsType } from 'antd/es/table'; import { ColumnsType } from 'antd/es/table';
import { CloudUploadOutlined } from '@ant-design/icons';
const SwiperPage = () => { const SwiperPage = () => {
const [loading, setLoading] = useState<boolean>(false); const [loading, setLoading] = useState<boolean>(false);
@@ -14,13 +15,13 @@ const SwiperPage = () => {
const [tab, setTab] = useState<string>('list'); const [tab, setTab] = useState<string>('list');
const columns: ColumnsType<Swiper> = [ const columns: ColumnsType<Swiper> = [
{ title: 'ID', dataIndex: 'id', key: 'id' }, { title: 'ID', dataIndex: 'id', key: 'id', align: 'center' },
{ {
title: '图片', dataIndex: 'image', key: 'image', width: 200, title: '图片', dataIndex: 'image', key: 'image', width: 200,
render: (text: string) => <img src={text} alt="swiper" className="w-full rounded cursor-pointer" onClick={() => { setViewImage(text); setIsModelOpen(true) }} /> render: (text: string) => <img src={text} alt="swiper" className="w-full rounded cursor-pointer" onClick={() => { setViewImage(text); setIsModelOpen(true) }} />
}, },
{ title: '标题', dataIndex: 'title', key: 'title' }, { title: '标题', dataIndex: 'title', key: 'title' },
{ title: '描述', dataIndex: 'description', key: 'description' }, { title: '描述', dataIndex: 'description', key: 'description', width: 500, },
{ {
title: '操作', key: 'action', align: 'center', title: '操作', key: 'action', align: 'center',
render: (text: string, record: Swiper) => ( render: (text: string, record: Swiper) => (
@@ -84,6 +85,11 @@ const SwiperPage = () => {
setSwiper({} as Swiper); setSwiper({} as Swiper);
}; };
// 文件上传
const UploadBtn = () => (
<CloudUploadOutlined className='text-xl cursor-pointer'/>
)
const tabItems = [ const tabItems = [
{ {
label: '轮播图列表', label: '轮播图列表',
@@ -131,7 +137,7 @@ const SwiperPage = () => {
</Form.Item> </Form.Item>
<Form.Item label="图片" name="image" rules={[{ required: true, message: '轮播图不能为空' }]}> <Form.Item label="图片" name="image" rules={[{ required: true, message: '轮播图不能为空' }]}>
<Input placeholder="https://blog.liuyuyang.net/swiper.jpg" /> <Input placeholder="https://blog.liuyuyang.net/swiper.jpg" addonAfter={<UploadBtn />} />
</Form.Item> </Form.Item>
<Form.Item> <Form.Item>