<template>
	<div class="sc-upload-file">
		<el-upload ref="uploader"
			:class="hideAdd && 'el-upload-hide-add'"
			v-model:file-list="defaultFileList"
			action=""
			:accept="accept"
			:limit="limit"
			:drag="drag"
			: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>
                <div v-if="drag" class="file-empty">
                    <el-icon><el-icon-upload-filled /></el-icon>
                    <h4>将文件拖到此处，或<el-text type="primary">点击上传</el-text></h4>
                </div>
                <vxe-button v-else status="primary" size="mini" content="点击上传" :disabled="disabled"></vxe-button>
			</slot>
			<template #tip>
				<div v-if="tip" :class="['el-upload__tip', tipRequired && 'el-upload__tip-required']">{{ tip }}</div>
			</template>
		</el-upload>
		<span style="display: none!important;"><el-input v-model="value"></el-input></span>
	</div>

    <file-viewer v-if="showViewer" ref="fileViewer" @closed="showViewer = false"></file-viewer>
</template>

<script>
import XEUtils from "xe-utils";

export default {
    props: {
        modelValue: { type: Array, default: () => [] },
        tip: { type: String, default: "" },
        tipRequired: { type: Boolean, default: false },
        accept: { type: String, default: "" },
        maxSize: { type: Number, default: 50 },
        limit: { type: Number, default: 0 },
        drag: { type: Boolean, default: false },
        multiple: { type: Boolean, default: true },
        disabled: { type: Boolean, default: false },
        hideAdd: { type: Boolean, default: false },
        onSuccess: { type: Function, default: () => true },
        params: { type: Object, default: () => ({}) }
    },

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

    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 => ({ id: item.id, name: item.name, contentType: item.contentType, path: item.path }));
        },

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

        success(res, file) {
            const os = this.onSuccess(res, file);
            if (os === false) return false;
            
            file.path = res.path;
            file.contentType = file.raw.type;
        },

        error(message) {
            message && this.$notify.error({ title: "上传文件未成功", message });
        },

        beforeRemove(file) {
            if (file.status == "success") {
                return new Promise((resolve, reject) => {
                    this.$confirm(`是否移除 ${file.name}? 此操作不可逆!`, "提示", {
                        type: "warning",
                        confirmButtonText: "移除"
                    }).then(() => {
                        this.$API.common.minio.rm(XEUtils.pick(file, "id", "path")).then(res => {
                            this.$emit("removeSuccess");
                            resolve();
                        }).catch(() => reject());
                    }).catch(() => reject());
                });
            }
        },

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

        handlePreview(uploadFile) {
            this.showViewer = true;
            nextTick(() => this.$refs.fileViewer.init(uploadFile));
        },

        request(param) {
            const data = new FormData();
            data.append(param.filename, param.file);
            XEUtils.objectEach(this.params, (value, key) => data.append(key, value));

            this.$API.common.minio.up(data, {
                onUploadProgress: e => {
                    const percent = parseInt(((e.loaded / e.total) * 100) | 0, 10);
                    param.onProgress({ percent });
                },
                transformRequest: [function (data, headers) {
                    // 移除 Axios 可能自动设置的 Content-Type，让浏览器自动设置
                    delete headers["Content-Type"];
                    return data;
                }]
            }).then(res => {
                if (res.code == 200) param.onSuccess({ path: res.expands.file });
                else param.onError();
            }).catch(() => param.onError());
        }
    }
}
</script>

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

.sc-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 {
                &:last-child {margin-bottom: 0;}
                &:hover {background-color: transparent;}
                .el-upload-list__item-info {width: 100%;}
                .el-upload-list__item-status-label {display: none;}
            }
        }
    }

    .file-empty i {font-size: 28px;}
    .file-empty h4 {
        font-size: 13px;
        font-weight: normal;
        color: #8c939d;
        
        .el-text {font-size: inherit;}
    }
    
    .el-upload__tip {color: #999;}
    .el-upload__tip-required {
        position: relative;
        &::before {
            content: "*";
            margin-right: 4px;
            color: var(--el-color-danger);
        }
    }
}
</style>