You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

350 lines
9.5 KiB

7 months ago
<!-- @format -->
<template>
<div>
<p v-if="value && showFile">
<a download="" target="_blank" :href="value">{{ downloadName }}</a>
<!-- <span class="close">
<ns-icon name="close" @click="remove" />
</span> -->
</p>
<div class="clearfix container">
<!--:multiple="showCount != 1"-->
<!--:showUploadList="false"-->
<a-upload
:accept="acceptFileType.join()"
:before-upload="beforeUpload"
:customRequest="selfUpload"
:showUploadList="false">
<a-button>
<upload-outlined />
上传文件
</a-button>
<div class="upload-tips">
<!--上传提示信息-->
<p v-if="acceptType && acceptType.length > 0"> 支持扩展名{{ acceptType.join(' ') }} </p>
<p v-if="fixedFileName && fixedFileName.length > 0">
仅支持文件{{ fixedFileName.join(' ') }}
</p>
</div>
</a-upload>
</div>
<!-- 提示 -->
<div class="err-msg">
<p :style="{ color: 'red' }" v-if="error">{{ error }}</p>
</div>
<p v-if="!error" :style="{ color: uploadResult === '上传成功' ? '#51b97b' : '#323232' }">
{{ fileName }} {{ uploadResult }}
</p>
<!-- 提示 -->
</div>
</template>
<script lang="ts">
import {
UploadOutlined,
LoadingOutlined,
EyeOutlined,
DeleteOutlined,
} from '@ant-design/icons-vue';
import { defineComponent, ref, computed, reactive, PropType } from 'vue';
// import {http} from '/nerv-lib/util/http';
import { NsMessage } from '../../message';
import { NSAxios } from '/nerv-lib/util/http/axios';
import { get, isArray } from 'lodash-es';
interface FileItem {
uid: string;
type: string;
size: number;
name?: string;
status?: string;
response?: string;
percent?: number;
url?: string;
preview?: string;
originFileObj?: any;
}
interface FileInfo {
file: FileItem;
fileList: FileItem[];
}
// 转base64
function getBase64(file: File) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => resolve(reader.result);
reader.onerror = (error) => reject(error);
});
}
export interface sizeItem {
fileType: Array<string>;
maxSize: number;
errorTip?: string;
}
export default defineComponent({
name: 'NsUploadFileV2',
components: {
UploadOutlined,
LoadingOutlined,
DeleteOutlined,
EyeOutlined,
},
props: {
// 上传的地址
url: {
type: String,
require: true,
},
// 上传的图片大小
maxSize: {
type: Number || (Array as PropType<Array<sizeItem>>), // [ { 'maxSize':512488000,'fileType': ['jpg', 'png'] } ]
default: 524288000,
},
// 上传的图片类型
fileType: {
type: Array,
default: () => {
return ['.jpg', '.png', '.jpeg'];
},
},
//弹窗限制的类型
acceptFileType: {
type: Array,
default: () => {
return ['jpg', 'png', 'jpeg'];
},
},
// 固定限制的文件名称
fixedFileName: {
type: Array,
},
//随file添加固定传参
params: {
type: [Object],
},
// 展示图片数量
showCount: {
type: Number,
default: 1,
},
// 上传文件类型,0-证书,1-图片,2-身份证件
uploadType: {
type: Number,
default: 1,
},
//是否显示下载附件
showFile: {
type: Boolean,
default: false,
},
//传入数据数据源
dataSouce: {
type: Object,
},
//处理传入数据用于触发change事件
setDataSouce: {
type: Function,
},
//获取下载链接
getUrlOrName: {
type: Function,
},
//设置取值字段
valueField: {
type: String,
default: 'data.httpUrl',
},
value: {
type: String || Object,
},
downloadName: {
type: String || Object,
default: '下载文件',
},
},
emits: ['change'],
setup(props, { attrs, emit }) {
function createHttp() {
/** todo 临时去除超时时间 */
return new NSAxios({
headers: { 'Content-Type': 'application/json;charset=UTF-8' },
withCredentials: true,
});
}
const uploadHttp = createHttp();
const previewVisible = ref<boolean>(false);
const error = ref<string>('');
const uploadResult = ref<string>('');
const previewImage = ref<string | undefined>('');
const fileName = ref<string | undefined>('');
const fileList = ref<FileItem[]>([]);
const currentImg = ref<string[]>([]);
const maskShow = ref<boolean[]>([]);
let data = reactive({});
let tempData = ref({});
const acceptType = computed(() =>
props.fileType.map((item: String) => {
return item;
}),
);
const beforeUpload = (file: FileItem) => {
if (!file) {
return;
}
fileName.value = file.name;
/** 1.判断类型和大小 */
error.value = '';
uploadResult.value = '';
// 文件类型
const type = file.name.substring(file.name.lastIndexOf('.') + 1).toLowerCase();
if (acceptType.value && acceptType.value.length > 0) {
// 限定文件类型
if (acceptType.value.includes(type)) {
error.value = '';
} else {
error.value = `请选择${props.fileType.join(',')}文件`;
return false;
}
} else if (props.fixedFileName) {
// 固定文件名称
const fixedFileName = props.fixedFileName;
if (fixedFileName && fixedFileName.includes(file.name)) {
error.value = '';
} else {
console.log(props.fixedFileName.join(','));
error.value = `请选择${props.fixedFileName.join(',')}的文件`;
return false;
}
}
// 文件大小
let valid = true;
error.value = '';
if (isArray(props.maxSize)) {
props.maxSize.some((el) => {
if (el.fileType.includes(type)) {
valid = file.size <= el.maxSize;
error.value = valid
? ''
: el['errorTip'] || ` 请选择${el.maxSize / 1024 / 1024}M内的文件`;
return true;
}
});
} else if (file.size > props.maxSize) {
error.value = ` 请选择${props.maxSize / 1024 / 1024}M内的文件`;
valid = false;
}
if (!valid) return valid;
return error.value == '';
};
const selfUpload = async ({ file }) => {
currentImg.value.unshift(await getBase64(file));
const params = {
// uploadType: props.uploadType,
};
const formData = new FormData();
formData.append('file', file);
const config = {
headers: {
'Content-Type': 'multipart/form-data',
},
params: params,
};
Object.keys(props.params).map((item) => {
formData.append(item, props.params[item]);
});
uploadResult.value = '上传中...';
uploadHttp
.post(props.url, formData, config)
.then((res) => {
error.value = '';
uploadResult.value = '上传成功';
data = res;
tempData.value = res.data;
if (attrs['fieldMap']) {
emit('change', data);
} else {
emit('change', get(data, props.valueField));
}
})
.catch((err) => {
console.log('err', err);
uploadResult.value = '';
error.value = `${file.name} 上传失败,请重试`;
NsMessage.error('上传失败,请重试');
});
};
const handlePreview = async (index: number) => {
previewImage.value = (await getBase64(fileList.value[index].originFileObj)) as string;
previewVisible.value = true;
};
const deleteImg = (index: number) => {
currentImg.value.splice(index, 1);
fileList.value.splice(index, 1);
};
const handleCancel = () => {
previewVisible.value = false;
};
const mouseEnter = (index: number) => {
maskShow.value[index] = true;
};
const mouseLeave = (index: number) => {
maskShow.value[index] = false;
};
const remove = () => {
Object.keys(tempData.value).map((key) => {
tempData.value[key] = '';
});
emit('change', { data: tempData.value });
};
const doWnload = (url) => {
let a = document.createElement('a');
document.body.appendChild(a);
a.href = encodeURI(url);
//设置下载的文件名
// a.download = fileName.value;
//触发a标签的点击事件,进行下载
a.click();
};
return {
previewVisible,
previewImage,
fileList,
error,
uploadResult,
fileName,
currentImg,
maskShow,
data,
tempData,
acceptType,
selfUpload,
handleCancel,
handlePreview,
beforeUpload,
mouseEnter,
mouseLeave,
deleteImg,
doWnload,
remove,
};
},
});
</script>
<style lang="less" scoped>
.close {
cursor: pointer;
}
</style>