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
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>
|