<!-- Created by henian.xu on 2018/8/13. -->

<template>
    <div :class="['upload-wrap',{disabled:isDisabled}]">
        <draggable
            :class="['upload-list',listType,{draggable:!isDraggableDisabled}]"
            v-bind="{draggable:'.item',disabled:isDraggableDisabled}"
            v-model="uploadFiles"
        >
            <transition-group
                class="transition"
                tag="div"
            >
                <div
                    class="item"
                    v-for="(item,index) in uploadFiles"
                    :style="itemStyle"
                    :key="item.id||`index_${index}`"
                >
                    <!--<div
                        v-if="listType==='picture'"
                        class="inner"
                        :style="`background-image: url('${$options.filters.imgCropping(getIcon(item.name || item.address) || item.url || item.address || $defaultImg,{width:200})}');`"
                    />-->
                    <XImage
                        v-if="listType==='picture'"
                        :src="getIcon(item.name || item.address) || item.url || item.address || $defaultImg"
                        :width="itemWidth"
                        :aspect-ratio="aspectRatio_"
                        :cut="cut_"
                        v-bind="elImageProps"
                    ></XImage>
                    <div
                        v-else
                        :is="item.address?'Linker':'div'"
                        :to="item.address"
                        :title="item.fileName||item.name"
                        class="inner"
                    >
                        {{ item.fileName||item.name }}
                    </div>
                    <div :class="['ctrl-wrap',{uploading:item.status==='uploading'}]">
                        <template v-if="listType==='picture' && item.status==='uploading'">
                            <el-progress
                                type="circle"
                                :percentage="item.percentage|number(0,false)"
                                :width="80"
                            />
                            <div
                                v-if='item.isMd5ing'
                                class='tip-txt'>计算文件...</div>
                        </template>
                        <template v-if="item.status==='success'">
                            <i
                                class="icon el-icon-delete"
                                @click="onDelete(item)"
                            />
                            <i
                                v-if="cropper && !getIcon(item.name || item.address)"
                                class="icon el-icon-edit-outline"
                                @click="()=>{onEditImg(item,index)}"
                            />
                            <template v-if="listType==='picture'">
                                <template v-if="!!isMedia(item.name || item.address)">
                                    <i
                                        class="icon el-icon-search"
                                        @click="onPreview(item,index)"
                                    />
                                    <a
                                        v-if="showDownloadIcon"
                                        class="icon el-icon-download"
                                        target='_blank'
                                        :href='item.address || ((item.response || {}).data || {}).address'
                                    />
                                </template>
                                <a
                                    v-else
                                    class="icon el-icon-download"
                                    target='_blank'
                                    :href='item.address || ((item.response || {}).data || {}).address'
                                />
                            </template>
                        </template>
                    </div>
                </div>
                <el-upload
                    key="ELUpload"
                    :style="itemStyle"
                    list-type="picture"
                    :show-file-list="false"
                    v-show="!isLimit"
                    ref="ELUpload"
                    class="ELUpload"
                    :action="action"
                    :oss-action="ossAction"
                    :headers="headers"
                    :accept="accept"
                    :validate-md5="validateMd5"
                    :check-type="checkType"
                    multiple
                    :limit="limit"
                    :on-change="onChange"
                    :before-upload="onBeforeUpload"
                    :on-success="onSuccess"
                    :on-error="onError"
                    :on-exceed="onExceed"
                    :file-list="VFileList"
                    :disabled="isDisabled"
                >
                    <slot name="trigger">
                        <template v-if="listType==='picture'">
                            <div
                                class="mask"
                                :style="maskStyles"
                            />
                            <div class="inner">
                                <div class="inner-wrap">
                                    <i class="el-icon-plus"/>
                                    <span
                                        v-if="placeholder"
                                        style="font-size: 14px;color: #ccc;word-break: break-all">{{placeholder}}</span>
                                </div>
                            </div>
                        </template>
                        <el-button
                            v-else
                            slot="trigger"
                            size="small"
                            type="primary"
                        >
                            {{ $$t('vmf_select_file', '选择文件') }}
                        </el-button>
                    </slot>
                </el-upload>
            </transition-group>
        </draggable>
        <div
            v-if="tips"
            slot="tip"
            class="el-upload__tip"
        >
            {{ tips }}
        </div>
        <template v-if="imgList && imgList.length">
            <image-viewer
                ref="imageViewer"
                :z-index="zIndex"
                :append-to-body="appendToBody"
                v-show="showViewer"
                :on-close="closeViewer"
                :url-list="imgList"
            />
        </template>
        <el-dialog
            :title="$$t('vmf_tailor', '裁剪')"
            width="50%"
            fullscreen
            :show-close="false"
            :visible.sync="dialog.visible"
            append-to-body
            center
        >
            <div class="upload-dialog-img-wrap">
                <img
                    ref="editImg"
                    class="edit-img"
                    :src="editFile && editFile.url"
                >
                <div
                    v-if="autoCropFile || autoCroping"
                    class="auto-crop-img-wrap"
                    element-loading-text="图片处理中"
                    v-loading="autoCroping">
                    <img
                        v-if="autoCropFile"
                        :src="autoCropFile.url">
                </div>
            </div>
            <div
                slot="footer"
                class="dialog-footer"
            >
                <el-button
                    type="primary"
                    @click="onRotate(-1)"
                >
                    <i class="el-icon-refresh-left"></i>
                </el-button>
                <el-button
                    type="primary"
                    @click="onRotate(1)"
                >
                    <i class="el-icon-refresh-right"></i>
                </el-button>
                <el-button
                    type="primary"
                    @click="onEditImgSave"
                >
                    {{ $$t('vmf_confirm', '确 定') }}
                </el-button>
                <el-button
                    v-if="cropType === 'auto'"
                    :type="autoCropFile?'danger':'success'"
                    @click="()=>{autoCrop()}"
                >
                    <template  v-if="autoCropFile">{{ $$t('vmf_cancel_auto_crop', '取消自动裁剪') }}</template>
                    <template v-else>{{ $$t('vmf_auto_crop', '自动裁剪') }}</template>

                </el-button>
                <el-button
                    v-if="!dialog.hideDirectUpload"
                    type="danger"
                    @click="complete(editFile)"
                >
                    {{ $$t('vmf_no_tailor_upload', '不裁剪直接上传') }}
                </el-button>
                <el-button @click="complete()">
                    {{ $$t('vmf_cancel', '取 消') }}
                </el-button>
            </div>
        </el-dialog>

        <el-dialog
            :title="$$t('vmf_video_preview', '视频预览')"
            width="50%"
            :visible.sync="videoDialog.visible"
            append-to-body
            center
        >
            <XVideo
                v-if='videoDialog.visible'
                :src='videoDialog.url'></XVideo>
        </el-dialog>
    </div>
</template>

<script>
import emitter from 'element-ui/src/mixins/emitter';
import ImageViewer from 'element-ui/packages/image/src/image-viewer';
import { Utils } from 'vmf';
import * as icons from './icons';
import { registeredChange, destroyChange } from './elUploadHook';
import cropperImageMixin from './cropperImageMixin';

const { isObject, isString, transformCssValue, isDef } = Utils;

let prevOverflow = '';
export default {
    name: 'Upload',
    mixins: [emitter, cropperImageMixin],
    components: { ImageViewer },
    inject: {
        elForm: {
            default: '',
        },
        elFormItem: {
            default: '',
        },
    },
    data() {
        return {
            VFileList: [],
            isMounted: false,
            videoDialog: {
                visible: false,
                url: '',
            },
            isInnerCtrl__: false,
            showViewer: false,
        };
    },
    props: {
        value: {
            type: Array,
            default() {
                return [];
            },
        },
        action: {
            type: String,
            required: true,
        },
        headers: {
            type: Object,
            default: () => ({}),
        },
        limit: {
            type: Number,
            default: null,
        },
        tips: {
            type: String,
            default() {
                return this.$$t('vmf_upload_tips', '只能上传jpg/png文件，且不超过500kb');
            },
        },
        placeholder: {
            type: String,
            default: '',
        },
        accept: {
            type: String,
            default: '',
        },
        beforeUpload: {
            type: Function,
            default: () => {},
        },
        returnFiles: {
            type: Boolean,
            default: false,
        },
        disabled: {
            type: Boolean,
            default: false,
        },
        draggable: {
            type: Boolean,
            default: false,
        },
        listType: {
            type: String,
            default: 'picture', // text,picture
        },
        validateMd5: {
            type: Boolean,
            default: false,
        },
        ossAction: {
            type: String,
            default: '',
        },
        checkType: {
            type: String,
            default: '',
        },

        zIndex: {
            type: Number,
            default: 2000,
        },
        appendToBody: {
            type: Boolean,
            default: true,
        },
        itemWidth: {
            type: [Number, String],
            default: 100,
        },
        itemHeight: {
            type: [String, Number],
            default: '',
        },
        // 值必须是大于 0 的数值, 设置此值后组件的 display 为 block
        aspectRatio: {
            type: Number,
            default: 1,
            validator(val) {
                return val >= 0;
            },
        },
        cut: {
            type: [String, Object],
            default: '',
        },
        demoImage: {
            type: String,
            default: '',
        },
        fit: { type: String, default: 'cover' },
        showDownloadIcon: { type: Boolean, default: false },
    },
    computed: {
        $$ELUpload() {
            const { ELUpload } = this.$refs;
            const { isMounted } = this;
            if (!ELUpload || !isMounted) return null;
            return ELUpload;
        },
        $$uploadInner() {
            const { $$ELUpload } = this;
            if (!$$ELUpload) return null;
            return this.$$ELUpload.$refs['upload-inner'];
        },
        $$inputEl() {
            const { $$uploadInner } = this;
            if (!$$uploadInner) return null;
            return this.$$uploadInner.$refs.input;
        },
        uploadFiles: {
            get() {
                const { $$ELUpload } = this;
                if (!$$ELUpload) return [];
                return $$ELUpload.uploadFiles;
            },
            set(val) {
                const { $$ELUpload } = this;
                if (!$$ELUpload) return;
                $$ELUpload.uploadFiles = val;
                this.updateValue();
            },
        },
        fileMap() {
            return this.uploadFiles.reduce((prev, curr) => {
                prev[curr.uid] = curr;
                return prev;
            }, {});
        },
        isComplete() {
            const { uploadFiles } = this;
            if (!uploadFiles || !uploadFiles.length) return true;
            return !uploadFiles.some(item => item.status !== 'success');
        },
        isLimit() {
            const { limit, uploadFiles } = this;
            if (typeof limit === 'number') {
                return uploadFiles.length === limit;
            }
            return false;
        },
        isDisabled() {
            return this.disabled || (this.elForm || {}).disabled;
        },
        isDraggableDisabled() {
            return !this.draggable || this.isDisabled || this.uploadFiles.some(item => item.status === 'uploading');
        },
        model: {
            get() {
                return this.value;
            },
            set(value) {
                this.isInnerCtrl__ = true;
                this.$emit('input', value);
                this.dispatch('ElFormItem', 'el.form.change', [value]);
            },
        },
        elImageProps() {
            const {
                fit,
                lazy,
                scrollContainer,
                $attrs,
                // add
            } = this;
            return {
                ...$attrs,
                fit,
                lazy,
                scrollContainer,
            };
        },
        imgList() {
            return this.model.map(item => item.address);
        },
        cut_() {
            const { cut } = this;
            if (cut) return cut;
            const { itemWidth } = this;
            const width = parseFloat(itemWidth);
            return { width };
        },
        itemStyle() {
            const { itemWidth, listType } = this;
            if (listType !== 'picture') return {};
            let width = itemWidth;
            if (typeof itemWidth === 'number') {
                width += 'px';
            }
            return { width };
        },
        itemHeight_() {
            const { itemHeight } = this;
            return transformCssValue(itemHeight);
        },
        aspectRatio_() {
            const { itemHeight_, aspectRatio } = this;
            if (!itemHeight_) return aspectRatio;
            if (!/%$/.test(itemHeight_)) return 0;
            const val = parseFloat(itemHeight_);
            if (!val) return 0;
            return val / 100;
        },
        maskStyles() {
            const { aspectRatio_: aspectRatio, demoImage } = this;
            const res = {};
            if (aspectRatio) {
                res.paddingTop = `${aspectRatio * 100}%`;
            }
            if (demoImage) {
                res.backgroundImage = `url(${demoImage})`;
                res.backgroundColor = `transparent`;
            }
            return res;
        },
    },
    watch: {
        value: {
            handler(val) {
                // console.log(val);
                if (this.isInnerCtrl__) {
                    this.isInnerCtrl__ = false;
                    return;
                }
                this.VFileList = val.reduce((pre, cur) => {
                    if (isObject(cur) && cur.address) {
                        const data = { ...cur };
                        data.url = data.address;
                        data.isOutside = true;
                        pre.push(data);
                    }
                    return pre;
                }, []);
            },
            immediate: true,
        },
    },
    methods: {
        getImageSize(url) {
            return new Promise(resolve => {
                const img = new Image();
                img.onload = () => {
                    const { naturalWidth, naturalHeight } = img;
                    resolve({
                        naturalWidth,
                        naturalHeight,
                    });
                };
                img.onerror = () => {
                    resolve({
                        naturalWidth: null,
                        naturalHeight: null,
                    });
                };
                img.src = url;
            });
        },
        async onBeforeUpload(file) {
            await this.beforeUpload(file);
            if (!file.url) {
                file.url = '';
                const URL = window.URL || window.webkitURL;
                if (URL && URL.createObjectURL) {
                    file.url = URL.createObjectURL(file);
                }
            }
            const isImage = this.isImage(file.name);

            if (isImage) {
                const { naturalWidth, naturalHeight } = await this.getImageSize(file.url);
                file.naturalWidth = naturalWidth;
                file.naturalHeight = naturalHeight;
            }

            if (file.edited || !this.cropper) {
                delete file.edited;
                return null;
            }
            if (file.error === 'editing') return null;
            console.log(1122, isImage, file.error);
            if (isImage) {
                return this.editImg(file);
            }
            return null;
        },
        onChange(/* file, fileList */) {
            // file.status ready:就绪;uploading:上传中;success:上传成功;fail:上传失败;
            // const {fileMap} = this;
            // console.log('onChange', file === fileList[0], {...file}, fileList, fileMap);
        },
        onSuccess(res, file) {
            this.$emit('success', res);
            this.updateValue();
            const { raw: { promise } = {} } = file || {};
            if (promise) {
                const { returnFiles } = this;
                if (returnFiles) {
                    promise.resolve({
                        ...res.data,
                        file,
                        rawFile: file.file || file.raw || file,
                    });
                } else {
                    promise.resolve(res.data);
                }
            }
        },
        onError(err, file) {
            this.$emit('error', err);
            const { raw: { promise } = {} } = file || {};
            if (promise) promise.reject(err);
        },
        updateValue() {
            const { uploadFiles, returnFiles } = this;
            const value = uploadFiles.reduce((pre, cur) => {
                if (cur.status !== 'success') return pre;
                const { isOutside, response, raw } = cur;
                if (response && !response.success) return pre;
                const data = isOutside || !response || !response.success ? cur : response.data;
                if (!data) return pre;
                const res = {
                    ...(returnFiles ? { ...cur } : {}),
                    name: data.name,
                    fileName: (raw && raw.name) || data.fileName,
                    address: data.address,
                };
                const naturalWidth = (raw || {}).naturalWidth || cur.naturalWidth || undefined;
                const naturalHeight = (raw || {}).naturalHeight || cur.naturalHeight || undefined;
                if (isDef(naturalWidth)) res.naturalWidth = naturalWidth;
                if (isDef(naturalHeight)) res.naturalHeight = naturalHeight;

                pre.push(res);
                return pre;
            }, []);
            this.model = value;
        },
        onExceed() {
            // console.log('onExceed');
            this.$message.error(
                `${this.$$t('vmf_upload_max_tips1', '最多只能上传')} ${this.limit} ${this.$$t('vmf_zhang', '张')}`,
            );
        },
        onDelete(file) {
            // console.log('onDelete');
            if (this.isDisabled) return;
            const { $$ELUpload } = this;
            $$ELUpload.handleRemove(file);
            this.updateValue();
        },
        onPreview(item, index) {
            if (this.isImage(item.name || item.address)) {
                const { imageViewer } = this.$refs;
                if (!imageViewer) return;
                // console.log('onPreview', index, imageViewer);
                imageViewer.index = index;
                prevOverflow = document.body.style.overflow;
                document.body.style.overflow = 'hidden';
                this.showViewer = true;
            } else if (this.isVideo(item.name || item.address)) {
                this.videoDialog.visible = true;
                this.videoDialog.url = item.url || item.address;
            }
        },
        closeViewer() {
            document.body.style.overflow = prevOverflow;
            this.showViewer = false;
            const { imageViewer } = this.$refs;
            if (!imageViewer) return;
            imageViewer.index = 0;
        },
        clear() {
            this.VFileList = [];
        },
        isImage(name) {
            const fileExt = (name.replace(/.+\./, '') || '').toLocaleLowerCase();
            return /jpg|jpeg|png|gif|webp/.test(fileExt);
        },
        isVideo(name) {
            const fileExt = (name.replace(/.+\./, '') || '').toLocaleLowerCase();
            return /mp4|m3u8/.test(fileExt);
        },
        isMedia(data) {
            if (isString(data)) {
                return this.isImage(data) || this.isVideo(data);
            }
            return false;
        },
        getIcon(name) {
            // const reg = /\.[^\.]+$/;
            const fileExt = (name.replace(/.+\./, '') || '').toLocaleLowerCase();
            // .exec(importUrl)
            if (/jpg|jpeg|png|gif|webp/.test(fileExt)) {
                // 排除图片格式
                return '';
            }
            if (icons[fileExt]) {
                return icons[fileExt];
            }
            if (/xls|xlsx|xltx|xltm|xlsb|xlam|xlsm/.test(fileExt)) {
                return icons.xls;
            }
            return icons.other;
        },
        addFile(file) {
            const promise = new Promise((resolve, reject) => {
                file.promise = { resolve, reject };
            });
            this.$$uploadInner.uploadFiles([file]);
            return promise;
        },
        selectFile() {
            return new Promise((resolve, reject) => {
                const { $$inputEl } = this;
                if ($$inputEl) {
                    $$inputEl.isVirtualClick = true;
                    $$inputEl.click();
                    $$inputEl.selectFilePromise = { resolve, reject };
                }
            });
        },
    },
    mounted() {
        this.isMounted = true;
        this.$nextTick(() => {
            registeredChange(this.$$inputEl);
        });
    },
    beforeDestroy() {
        destroyChange(this.$$inputEl);
    },
};
</script>

<style lang="scss">
$itemWidth: 100px !default;
.upload-wrap {
    > .upload-list {
        &.text {
            > .transition {
                > .item {
                    display: flex;
                    flex-direction: row;
                    justify-content: space-between;
                    align-items: center;
                    + .item {
                        //border-top: 1px solid $color-border;
                        margin-top: $margin-small;
                    }
                    > .inner {
                        flex: 1 1 1%;
                        padding: $padding-small;
                        background-color: $gray1;
                        @include text-line(1);
                    }
                    > .ctrl-wrap {
                        padding: $padding-small;
                        flex: 0 0 auto;
                        background-color: $color-danger;
                        color: #fff;
                    }
                }
                > .ELUpload {
                    margin-top: $margin-small;
                }
            }
        }

        &.picture {
            > .transition {
                display: flex;
                flex-direction: row;
                justify-content: flex-start;
                align-items: center;
                flex-wrap: wrap;
                > .item {
                    position: relative;
                    width: $itemWidth;
                    border: 1px solid $gray5;
                    background-color: $gray3;
                    border-radius: 3px;
                    margin-right: $margin;
                    > .inner {
                        width: 100%;
                        padding-top: 100%;
                        background-position: center;
                        background-repeat: no-repeat;
                        background-size: cover;
                    }
                    > .ctrl-wrap {
                        display: none;
                        /*display: flex;*/
                        flex-direction: row;
                        justify-content: center;
                        align-items: center;
                        position: absolute;
                        top: 0;
                        right: 0;
                        bottom: 0;
                        left: 0;
                        background-color: rgba(0, 0, 0, 0.5);
                        padding: $padding;

                        > .el-progress {
                            > .el-progress__text {
                                color: #fff;
                            }
                        }
                        > .tip-txt {
                            position: absolute;
                            top: 50%;
                            text-align: center;
                            font-size: 10px;
                            left: 0;
                            right: 0;
                            color: #fff;
                        }
                        > .icon {
                            color: #fff;
                            margin: 0 $margin-small;
                            cursor: pointer;
                        }

                        &.uploading {
                            display: flex;
                        }
                    }

                    &:hover {
                        > .ctrl-wrap {
                            display: flex;
                        }
                    }
                }
                > .ELUpload {
                    position: relative;
                    width: $itemWidth;
                    > .el-upload {
                        position: relative;
                        display: block;
                        border: 1px dashed $color-border;
                        border-radius: 3px;
                        font-size: 20px;
                        background-color: #fff;
                        > .mask {
                            background: center no-repeat;
                            background-size: contain;
                        }
                        > .inner {
                            position: absolute;
                            top: 0;
                            right: 0;
                            bottom: 0;
                            left: 0;
                            display: flex;
                            flex-direction: column;
                            justify-content: center;
                            align-items: center;
                            width: 100%;
                            > .inner-wrap {
                                padding: $padding;
                                border-radius: $padding-small;
                                background-color: rgba(255, 255, 255, 0.7);
                            }
                        }
                    }
                }
            }
        }
        &.draggable {
            > .transition {
                > .item {
                    cursor: pointer;
                }
            }
        }
    }

    &.disabled {
        /*background-color: #f5f7fa;*/
        /*border-color: #e4e7ed;*/
        color: #c0c4cc;
        cursor: not-allowed;
        .ELUpload {
            > .el-upload {
                cursor: not-allowed;
            }
        }
    }
}
.upload-dialog-img-wrap {
    height: 100%;
    position: relative;
    > .auto-crop-img-wrap {
        position: absolute;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        display: flex;
        flex-direction: row;
        justify-content: center;
        align-items: center;
        background-color: #fff;
        > img {
            height: 100%;
            width: 100%;
            object-fit: contain;
        }
    }
}
</style>
