| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262 |
- <!--
- * 文件上传
- *
- * @Author: DCCloud
- * @Date: 2022-08-12 20:19:39
- *
- -->
- <template>
- <div class="clearfix">
- <a-upload
- multiple
- :accept="props.accept"
- :before-upload="beforeUpload"
- :customRequest="customRequest"
- :file-list="fileList"
- :headers="{ 'x-access-token': useUserStore().getToken }"
- :list-type="listType"
- @change="handleChange"
- @preview="handlePreview"
- @remove="handleRemove"
- :showUploadList="showUploadList"
- :disabled="disabled"
- >
- <div v-if="fileList.length < props.maxUploadSize && !slot.customUploadBtnSlot">
- <template v-if="listType === 'picture-card'">
- <PlusOutlined />
- <div class="ant-upload-text">
- {{ buttonText }}
- </div>
- </template>
- <template v-if="listType === 'text'">
- <a-button :type="btnType">
- <upload-outlined v-if="btnIcon" />
- {{ buttonText }}
- </a-button>
- </template>
- </div>
- <slot name="customUploadBtnSlot"></slot>
- </a-upload>
- <a-modal :footer="null" :open="previewVisible" @cancel="handleCancel">
- <img :src="previewUrl" alt="example" style="width: 100%" />
- </a-modal>
- </div>
- </template>
- <script setup>
- import { computed, ref, useSlots, watch } from 'vue';
- import { Modal } from 'ant-design-vue';
- import { fileApi } from '/src/api/support/file-api';
- import { useUserStore } from '/@/store/modules/system/user';
- import { SmartLoading } from '/@/components/framework/smart-loading';
- import { FILE_FOLDER_TYPE_ENUM } from '/@/constants/support/file-const';
- import { smartSentry } from '/@/lib/smart-sentry';
- const props = defineProps({
- value: String,
- buttonText: {
- type: String,
- default: '点击上传附件',
- },
- showUploadBtn: {
- type: Boolean,
- default: true,
- },
- defaultFileList: {
- type: Array,
- default: () => [],
- },
- multiple: {
- type: Boolean,
- default: false,
- },
- // 最多上传文件数量
- maxUploadSize: {
- type: Number,
- default: 10,
- },
- maxSize: {
- type: Number,
- default: 500,
- },
- // 上传的文件类型
- accept: {
- type: String,
- default: '',
- },
- // 文件上传类型
- folder: {
- type: Number,
- default: FILE_FOLDER_TYPE_ENUM.COMMON.value,
- },
- // 上传列表的内建样式,支持三种基本样式 text, picture 和 picture-card
- listType: {
- type: String,
- default: 'picture-card',
- },
- // 上传按钮样式
- btnType: {
- type: String,
- default: 'default',
- },
- // 是否显示上传按钮图标
- btnIcon: {
- type: Boolean,
- default: true,
- },
- //是否显示上传列表
- showUploadList: {
- type: Boolean,
- default: true,
- },
- //是否上传后清空文件列表
- uploadAterClear: {
- type: Boolean,
- default: false,
- },
- //是否禁用上传
- disabled: {
- type: Boolean,
- default: false,
- },
- });
- const slot = useSlots();
- // 图片类型的后缀名
- const imgFileType = ['jpg', 'jpeg', 'png', 'gif'];
- // 重新修改图片展示字段
- const files = computed(() => {
- let res = [];
- if (props.defaultFileList && props.defaultFileList.length > 0) {
- props.defaultFileList.forEach((element) => {
- element.url = element.fileUrl;
- element.name = element.fileName;
- res.push(element);
- });
- return res;
- }
- return res;
- });
- // -------------------- 逻辑 --------------------
- const previewVisible = ref(false);
- const fileList = ref([]);
- const previewUrl = ref('');
- watch(
- files,
- (value) => {
- fileList.value = value;
- },
- {
- immediate: true,
- }
- );
- const emit = defineEmits(['update:value', 'change']);
- const customRequest = async (options) => {
- SmartLoading.show();
- try {
- // console.log(options);
- const formData = new FormData();
- formData.append('file', options.file);
- // console.log(formData)
- let res = await fileApi.uploadFile(formData, props.folder);
- // console.log(res)
- let file = res.data;
- file.url = file.fileUrl;
- file.name = file.fileName;
- if (props.uploadAterClear) {
- fileList.value = [];
- }
- fileList.value.push(file);
- emit('change', fileList.value);
- } catch (e) {
- smartSentry.captureError(e);
- } finally {
- SmartLoading.hide();
- }
- };
- function handleChange(info) {
- // console.log(info)
- let fileStatus = info.file.status;
- let file = info.file;
- if (fileStatus === 'removed') {
- let index = fileList.value.findIndex((e) => e.fileId === file.fileId);
- if (index !== -1) {
- fileList.value.splice(index, 1);
- emit('change', fileList.value);
- }
- }
- }
- function handleRemove(file) {
- // console.log(fileList.value);
- }
- function beforeUpload(file, files) {
- if (fileList.value.length + files.length > props.maxUploadSize) {
- showErrorMsgOnce(`最多支持上传 ${props.maxUploadSize} 个文件哦!`);
- return false;
- }
- if (props.accept) {
- const suffixIndex = file.name.lastIndexOf('.');
- const fileSuffix = file.name.substring(suffixIndex <= -1 ? 0 : suffixIndex);
- if (props.accept.indexOf(fileSuffix) === -1) {
- showErrorMsgOnce(`只支持上传 ${props.accept.replaceAll(',', ' ')} 格式的文件`);
- return false;
- }
- }
- const isLimitSize = file.size / 1024 / 1024 < props.maxSize;
- if (!isLimitSize) {
- showErrorMsgOnce(`单个文件大小必须小于 ${props.maxSize} Mb`);
- }
- return isLimitSize;
- }
- const showErrorModalFlag = ref(true);
- const showErrorMsgOnce = (content) => {
- if (showErrorModalFlag.value) {
- Modal.error({
- title: '提示',
- content: content,
- okType: 'danger',
- centered: true,
- onOk() {
- showErrorModalFlag.value = true;
- },
- });
- showErrorModalFlag.value = false;
- }
- };
- function handleCancel() {
- previewVisible.value = false;
- }
- const handlePreview = async (file) => {
- if (imgFileType.some((e) => e === file.fileType)) {
- previewUrl.value = file.url || file.preview;
- previewVisible.value = true;
- } else {
- fileApi.downLoadFile(file.fileKey);
- }
- };
- // ------------------------ 清空 上传 ------------------------
- function clear() {
- fileList.value = [];
- }
- defineExpose({
- clear,
- });
- </script>
- <style lang="less" scoped>
- :deep(.ant-upload-picture-card-wrapper) {
- display: flex;
- }
- </style>
|