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

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>