|
@@ -7,10 +7,21 @@
|
|
|
-->
|
|
-->
|
|
|
<template>
|
|
<template>
|
|
|
<div class="clearfix">
|
|
<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">
|
|
|
|
|
|
|
+ <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'">
|
|
<template v-if="listType === 'picture-card'">
|
|
|
<PlusOutlined />
|
|
<PlusOutlined />
|
|
|
<div class="ant-upload-text">
|
|
<div class="ant-upload-text">
|
|
@@ -19,11 +30,12 @@
|
|
|
</template>
|
|
</template>
|
|
|
<template v-if="listType === 'text'">
|
|
<template v-if="listType === 'text'">
|
|
|
<a-button :type="btnType">
|
|
<a-button :type="btnType">
|
|
|
- <upload-outlined v-if="btnIcon"/>
|
|
|
|
|
|
|
+ <upload-outlined v-if="btnIcon" />
|
|
|
{{ buttonText }}
|
|
{{ buttonText }}
|
|
|
</a-button>
|
|
</a-button>
|
|
|
</template>
|
|
</template>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
+ <slot name="customUploadBtnSlot"></slot>
|
|
|
</a-upload>
|
|
</a-upload>
|
|
|
<a-modal :footer="null" :open="previewVisible" @cancel="handleCancel">
|
|
<a-modal :footer="null" :open="previewVisible" @cancel="handleCancel">
|
|
|
<img :src="previewUrl" alt="example" style="width: 100%" />
|
|
<img :src="previewUrl" alt="example" style="width: 100%" />
|
|
@@ -31,218 +43,220 @@
|
|
|
</div>
|
|
</div>
|
|
|
</template>
|
|
</template>
|
|
|
<script setup>
|
|
<script setup>
|
|
|
-import { computed, ref, 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 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);
|
|
|
|
|
- });
|
|
|
|
|
|
|
+ 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;
|
|
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 = []
|
|
|
|
|
|
|
+ });
|
|
|
|
|
+ // -------------------- 逻辑 --------------------
|
|
|
|
|
+
|
|
|
|
|
+ const previewVisible = ref(false);
|
|
|
|
|
+ const fileList = ref([]);
|
|
|
|
|
+ const previewUrl = ref('');
|
|
|
|
|
+
|
|
|
|
|
+ watch(
|
|
|
|
|
+ files,
|
|
|
|
|
+ (value) => {
|
|
|
|
|
+ fileList.value = value;
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ immediate: true,
|
|
|
}
|
|
}
|
|
|
- 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);
|
|
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ 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);
|
|
emit('change', fileList.value);
|
|
|
|
|
+ } catch (e) {
|
|
|
|
|
+ smartSentry.captureError(e);
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ SmartLoading.hide();
|
|
|
}
|
|
}
|
|
|
- }
|
|
|
|
|
-}
|
|
|
|
|
|
|
+ };
|
|
|
|
|
|
|
|
-function handleRemove(file) {
|
|
|
|
|
- // console.log(fileList.value);
|
|
|
|
|
-}
|
|
|
|
|
|
|
+ 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 beforeUpload(file, files) {
|
|
|
|
|
- if (fileList.value.length + files.length > props.maxUploadSize) {
|
|
|
|
|
- showErrorMsgOnce(`最多支持上传 ${props.maxUploadSize} 个文件哦!`);
|
|
|
|
|
- return false;
|
|
|
|
|
|
|
+ function handleRemove(file) {
|
|
|
|
|
+ // console.log(fileList.value);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- 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(',', ' ')} 格式的文件`);
|
|
|
|
|
|
|
+ function beforeUpload(file, files) {
|
|
|
|
|
+ if (fileList.value.length + files.length > props.maxUploadSize) {
|
|
|
|
|
+ showErrorMsgOnce(`最多支持上传 ${props.maxUploadSize} 个文件哦!`);
|
|
|
return false;
|
|
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;
|
|
|
|
|
|
|
+ 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;
|
|
|
}
|
|
}
|
|
|
-};
|
|
|
|
|
-
|
|
|
|
|
-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);
|
|
|
|
|
|
|
+
|
|
|
|
|
+ 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;
|
|
|
}
|
|
}
|
|
|
-};
|
|
|
|
|
|
|
|
|
|
-// ------------------------ 清空 上传 ------------------------
|
|
|
|
|
-function clear() {
|
|
|
|
|
- fileList.value = [];
|
|
|
|
|
-}
|
|
|
|
|
|
|
+ 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,
|
|
|
|
|
-});
|
|
|
|
|
|
|
+ defineExpose({
|
|
|
|
|
+ clear,
|
|
|
|
|
+ });
|
|
|
</script>
|
|
</script>
|
|
|
<style lang="less" scoped>
|
|
<style lang="less" scoped>
|
|
|
-:deep(.ant-upload-picture-card-wrapper) {
|
|
|
|
|
- display: flex;
|
|
|
|
|
-}
|
|
|
|
|
|
|
+ :deep(.ant-upload-picture-card-wrapper) {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ }
|
|
|
</style>
|
|
</style>
|