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.
334 lines
8.6 KiB
334 lines
8.6 KiB
7 months ago
|
<template>
|
||
|
<div>
|
||
|
<p v-if="getUrlOrName && showFile && getUrlOrName('url', tempData)">
|
||
|
<a download="" target="_blank" :href="getUrlOrName('url', tempData)">{{
|
||
|
getUrlOrName("name", tempData)
|
||
|
}}</a>
|
||
|
<span class="close">
|
||
|
<ns-icon name="close" @click="remove" />
|
||
|
</span>
|
||
|
</p>
|
||
|
<div class="clearfix container">
|
||
|
<!--:multiple="showCount != 1"-->
|
||
|
<!--:showUploadList="false"-->
|
||
|
<a-upload
|
||
|
: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 } 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: "NsUploadFile",
|
||
|
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,
|
||
|
},
|
||
|
// 固定限制的文件名称
|
||
|
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,
|
||
|
},
|
||
|
},
|
||
|
emits: ["change"],
|
||
|
setup(props, { 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({});
|
||
|
if (props.dataSouce && props.setDataSouce) {
|
||
|
tempData.value = props.setDataSouce(JSON.parse(JSON.stringify(props.dataSouce)));
|
||
|
emit("change", { data: tempData.value });
|
||
|
}
|
||
|
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;
|
||
|
console.log(data);
|
||
|
emit("change", data);
|
||
|
})
|
||
|
.catch(() => {
|
||
|
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>
|