<template>
	<div class="yh-upload-file">
		<el-upload ref="uploader"
			:class="hideAdd && 'el-upload-hide-add'"
			v-model:file-list="defaultFileList"
			action=""
			:accept="accept"
			:limit="limit"
			:multiple="multiple"
			:disabled="disabled"
			show-file-list
			:http-request="request"
			:before-upload="before"
			:before-remove="beforeRemove"
			:on-success="success"
			:on-error="error"
			:on-preview="handlePreview"
			:on-exceed="handleExceed">
			<slot>
				<el-button type="primary" :disabled="disabled">Click to upload</el-button>
			</slot>
			<template #tip>
				<div v-if="tip" class="el-upload__tip">{{ tip }}</div>
			</template>
		</el-upload>
		<span style="display: none!important;"><el-input v-model="value"></el-input></span>
	</div>

	<yh-image-viewer :showViewer="showPictureViewer" :imageList="previewImageList" teleported @close="showPictureViewer = false"></yh-image-viewer>
</template>

<script>
import { defineAsyncComponent } from "vue";
import Folder from "@/api/folder";

export default {
    components: {
        yhImageViewer: defineAsyncComponent(() => import("@/components/Upload/imageViewer.vue")),
    },
    props: {
        modelValue: { type: Array, default: () => [] },
        tip: { type: String, default: "" },
        accept: { type: String, default: "" },
        maxSize: { type: Number, default: 50 },
        limit: { type: Number, default: 0 },
        multiple: { type: Boolean, default: true },
        disabled: { type: Boolean, default: false },
        hideAdd: { type: Boolean, default: false },
        onSuccess: { type: Function, default: () => { return true } }
    },

    data() {
        return {
            value: "",
            defaultFileList: [],
            
            showPictureViewer: false,
            previewImageList: []
        }
    },

    watch: {
        modelValue(val) {
            if (JSON.stringify(val) != JSON.stringify(this.formatArr(this.defaultFileList))) {
                this.defaultFileList = val;
                this.value = val;
            }
        },

        defaultFileList: {
            deep: true,
            handler(val) {
                this.$emit("update:modelValue", this.formatArr(val));
                this.value = val.map(v => v.path).join(",");
            }
        }
    },

    mounted() {
        this.defaultFileList = this.modelValue;
        this.value = this.modelValue;
    },

    methods: {
        // 格式化数组值
        formatArr(arr) {
            return arr.map(item => ({ fileName: item.fileName, fileType: item.fileType, fileDomain: item.fileDomain, originalName: item.originalName, path: item.fileDomain + "/" + item.fileName }));
        },

        before(file) {
            const maxSize = file.size / 1024 / 1024 < this.maxSize;
            if (!maxSize) {
                ElMessage.warning(`上传文件大小不能超过 ${this.maxSize}MB!`);
                return false;
            }
        },

        success(res, file) {
            let os = this.onSuccess(res, file);
            if (os != undefined && os == false) return false;
        
            file.fileDomain = res.domain;
            file.fileName = res.name;
            file.fileType = res.fileType;
            file.originalName = res.originalName;
            file.path = res.domain + "/" + res.name;
        },

        error(message) {
            this.$emit("update:isUpload", false);
            ElNotification.error({ title: "上传文件未成功", message });
        },

        beforeRemove({ id, name, fileName }) { // id, name, fileName
            return ElMessageBox.confirm(`是否移除 ${name}? 此操作不可逆!`, "提示", {
                type: "warning",
                confirmButtonText: "移除"
            }).then(() => {
                const promiseArray = [Folder.rm(fileName)];
                id && promiseArray.push(Folder.fileRemove(id));

                return Promise.all(promiseArray).then(() => {
                    id && this.$emit("updateTable");
                    return true;
                }).catch(() => false);
            }).catch(() => false);
        },

        handleExceed() {
            ElMessage.warning(`当前设置最多上传 ${this.limit} 个文件，请移除后上传!`);
        },

        handlePreview(uploadFile) {
            if (["image/jpeg", "image/png"].includes(uploadFile.fileType)) {
                this.showPictureViewer = true;
                this.previewImageList = [uploadFile.path];
            } else {
                Folder.download(uploadFile.path).then(res => {
                    const a = document.createElement("a");
                    const blob = new Blob([res.data], { type: uploadFile.fileType });
                    if (uploadFile.fileType == "application/pdf") a.target = "_blank";
                    else a.download = uploadFile.name;
                    a.href = URL.createObjectURL(blob);
                    a.click();
                });
            }
        },

        request(param) {
            const data = new FormData();
            data.append(param.filename, param.file);

            this.$emit("update:isUpload", true);
            Folder.up(data, {
                onUploadProgress: e => {
                    const percent = parseInt(((e.loaded / e.total) * 100) | 0, 10);
                    param.onProgress({ percent });
                }
            }).then(res => {
                this.$emit("update:isUpload", false);
                if (res.code == 200) param.onSuccess({ ...res.data, fileType: param.file.type });
                else param.onError(res.msg || "未知错误");
            }).catch(err => param.onError(err));
        }
    }
}
</script>

<style lang="scss" scoped>
.el-form-item.is-error .yh-upload-file:deep(.el-upload-dragger) {
  border-color: var(--el-color-danger);
}

.yh-upload-file {
  width: 100%;

  :deep(.el-upload-list__item) {
    transition: none !important;
  }

  .el-upload-hide-add {
    :deep(.el-upload) {
      display: none;
    }

    :deep(.el-upload-list) {
      margin-top: 0;

      .el-upload-list__item {
        &:hover {
          background-color: transparent;
        }

        .el-upload-list__item-info {
          width: 100%;
        }

        .el-upload-list__item-status-label {
          display: none;
        }
      }
    }
  }
}
</style>