wms-antdvue/src/components/Upload/Images.vue
2024-12-20 13:50:59 +08:00

385 lines
10 KiB
Vue
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.

<template>
<div class="upload-box">
<div v-for="(item, index) in fileList" class="items">
<img v-if="item.filePath" :src="item.filePath" class="upload-image" />
<div class="upload-handle" @click.stop>
<div class="handle-icon" @click="handleEdit(index)" v-if="!self_disabled">
<EditOutlined style="font-size: 20px" />
</div>
<div class="handle-icon" @click="onPreview(index)">
<ZoomInOutlined style="font-size: 20px" />
</div>
<div class="handle-icon" @click="handleRemove(index)" v-if="!self_disabled">
<DeleteOutlined style="font-size: 20px" />
</div>
</div>
</div>
<a-upload-dragger
action="#"
:id="uuid"
class="upload-demo my-upload-images"
:multiple="multiple"
ref="uploadRef"
:style="{ width: width, height: height }"
:disabled="loading ? true : self_disabled || fileList.length >= props.limit"
:custom-request="handleHttpUpload"
:before-upload="beforeUpload"
list-type="picture-card"
:maxCount="limit"
:file-list="fileList"
:show-upload-list="false"
v-if="!self_disabled"
:on-exceed="onExceed"
:accept="props.fileType"
>
<PlusOutlined v-if="!loading" />
<a-progress type="circle" v-else :percentage="progress" />
</a-upload-dragger>
</div>
</template>
<script setup lang="ts">
import { computed, ref } from 'vue';
import { generateUUID } from '@/utils/auth';
import {
PlusOutlined,
EditOutlined,
DeleteOutlined,
ZoomInOutlined,
} from '@ant-design/icons-vue';
import { notification } from 'ant-design-vue';
import OSS from "ali-oss";
const uploadRef = ref();
import { upload,getOssConfig } from '@/api/common';
// 接受父组件参数
const props = defineProps({
zIndex: {
default: -1,
},
multiple: {
type: Boolean,
default: false,
},
btnTip: {
type: String,
default: '',
},
limit: {
type: Number,
default: undefined,
},
width: {
type: String,
default: '120px',
},
height: {
type: String,
default: '120px',
},
borderRadius: {
type: String,
default: '8px',
},
fileList: {
type: Array,
required: true,
default: [],
},
disabled: {
default: false,
},
fileSize: {
default: 200,
},
orderNo: {
default: '',
},
fileType: {
default: '',
},
name: {
default: '',
},
});
// 生成组件唯一id
const uuid = ref('id-' + generateUUID());
// 判断是否禁用上传和删除
const self_disabled = computed(() => {
return props.disabled;
});
let editIndex = '';
const emit = defineEmits(['upload']);
const progress = ref(0);
const loading = ref(false);
//接口上传
const handleHttpUpload = async (options) => {
loading.value = true;
try {
const formData = new FormData();
formData.append('file', options.file);
formData.append('name', props.name);
const res = await upload(formData);
if (props.multiple) {
let list = JSON.parse(JSON.stringify(props.fileList));
if (editIndex !== '') {
list.splice(editIndex, 1, {
url: res.fileUrl,
name: res.originalName,
filePath: res.fileUrl,
fileName: res.originalName,
});
editIndex = '';
} else {
list.push({
url: res.fileUrl,
name: res.originalName,
filePath: res.fileUrl,
fileName: res.originalName,
});
}
emit('upload', list, props.zIndex);
} else {
emit('upload', res, props.zIndex);
}
} catch (error) {
notification.error({
message: '温馨提示',
description: '上传文件失败!',
});
if (props.multiple) {
emit('upload', props.fileList, props.zIndex);
} else {
uploadRef.value!.clearFiles();
emit('upload', '', props.zIndex);
}
options.onError(error as any);
} finally {
progress.value = 0;
loading.value = false;
}
};
//oss上传
const handleHttpUploads = async (options: UploadRequestOptions) => {
const configData = await getOssConfig()
let date = new Date();
let year = date.getFullYear();
let month: string | number = date.getMonth() + 1;
month = month < 10 ? ("0" + month) : month;
let day: string | number = date.getDate();
day = day < 10 ? ("0" + day) : day;
let h: string | number = date.getHours();
h = h < 10 ? ("0" + h) : h;
let minute: string | number = date.getMinutes();
minute = minute < 10 ? ("0" + minute) : minute;
let second: string | number = date.getSeconds();
second = second < 10 ? ("0" + second) : second;
let time = h + "" + minute + "" + second;
let fileName = (props.orderNo ? (time + '-' + props.orderNo) : time) + "-" + options.file.name
fileName = fileName.replace(/[\+\_\,\!\|\~\`\(\)\#\$\%\^\&\*\{\}\:\;\"\<\>\?]/g, '')
let filePath = props.name + "/" + year + "/" + month + "/" + day + "/" + fileName;
loading.value = true;
try {
const headers = {
"Access-Control-Allow-Origin": "*"
};
const client = new OSS({
// yourRegion填写Bucket所在地域。以华东1杭州为例yourRegion填写为oss-cn-hangzhou。
endpoint: configData.oss_endpoint,
// 从STS服务获取的临时访问密钥AccessKey ID和AccessKey Secret
secure: true,
region: configData.oss_region,
accessKeyId: configData.oss_accessKeyId,
accessKeySecret: configData.oss_accessKeySecret,
// 填写Bucket名称。
bucket: configData.oss_bucketName,
timeout: 600000
});
const res = await client.multipartUpload(filePath, options.file, {
headers: headers,
// 获取分片上传进度、断点和返回值。
progress: (p, cpt, res) => {
progress.value = parseFloat(parseFloat(p * 100).toFixed(2))
options.onProgress({ percent: parseFloat(parseFloat(p * 100).toFixed(2)) });
},
// 设置并发上传的分片数量。
parallel: 4,
// 设置分片大小。默认值为1 MB最小值为100 KB。
partSize: 1024 * 1024,
// headers,
mime: options.file.type
});
if (props.multiple) {
let list = JSON.parse(JSON.stringify(props.fileList))
if (editIndex !== '') {
list.splice(editIndex, 1, {
url:res.res.requestUrls[0],
name: options.file.name,
filePath: res.res.requestUrls[0],
fileName: options.file.name
})
editIndex = ''
} else {
list.push({
url: res.res.requestUrls[0],
name: options.file.name,
filePath: res.res.requestUrls[0],
fileName: options.file.name
})
}
emit('upload', list,props.zIndex)
} else {
emit("upload", res.res.requestUrls[0], options.file.name, props.zIndex);
}
} catch (error) {
notification.error({
message: '温馨提示',
description: '上传文件失败!',
});
if (props.multiple) {
emit('upload', props.fileList, props.zIndex);
} else {
uploadRef.value!.clearFiles();
emit('upload', '', props.zIndex);
}
options.onError(error as any);
} finally {
progress.value = 0
loading.value = false;
}
};
const onPreview = (index: any) => {
window.open(props.fileList[index].filePath);
};
const handleEdit = (index: any) => {
editIndex = index;
const dom = document.querySelector(`.ant-upload #${uuid.value}`);
dom && dom.dispatchEvent(new MouseEvent('click'));
};
const handleRemove = (index: any) => {
editIndex = index;
if (props.multiple) {
emit(
'upload',
props.fileList.filter((f, i) => !(editIndex == i)),
props.zIndex,
);
} else {
uploadRef.value!.clearFiles();
emit('upload', '', props.zIndex);
}
};
const onExceed = () => {
if (props.limit) {
notification.warning({
message: '温馨提示',
description: `最多支持上传${props.limit}张`,
});
}
};
/**
* @description 文件上传之前判断
* @param rawFile 选择的文件
* */
const beforeUpload = (rawFile) => {
const imgSize = rawFile.size / 1024 / 1024 < props.fileSize;
if (!imgSize) {
notification.warning({
message: '温馨提示',
description: `上传文件大小不能超过 ${props.fileSize}M`,
});
return false;
}
if (props.fileType) {
let fileType = props.fileType.replace(/\s/g, '');
fileType.split('.').join('|');
let fileIndex = rawFile.name.lastIndexOf('.');
let substrName = rawFile.name.substr(fileIndex);
if (fileType.indexOf(substrName) == -1) {
notification.warning({
message: '温馨提示',
description: '上传文件不符合所需的格式!',
});
return false;
}
}
return true;
};
</script>
<style scoped lang="less">
.upload-box {
position: relative;
display: flex;
flex-wrap: wrap;
> div {
margin-right: 10px;
margin-bottom: 10px;
position: relative;
&.items {
width: v-bind(width);
height: v-bind(height);
border: 1px dashed #d9d9d9;
border-radius: 4px;
padding: 5px;
}
&:hover {
.upload-handle {
opacity: 1;
}
}
}
:deep(.ant-upload) {
position: relative;
display: flex;
align-items: center;
justify-content: center;
width: v-bind(width);
height: v-bind(height);
overflow: hidden;
border-radius: 4px;
}
.upload-image {
width: 100%;
height: 100%;
object-fit: contain;
}
.upload-handle {
position: absolute;
top: 0;
right: 0;
box-sizing: border-box;
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
cursor: pointer;
background: rgb(0 0 0 / 60%);
opacity: 0;
.handle-icon {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 0 6%;
color: aliceblue;
span {
font-size: 85%;
line-height: 85%;
}
}
}
}
</style>