<!-- Created by henian.xu on 2024/12/20. -->

<template>
    <div class='x-media-list'>
        <div class='inner'>
            <div
                v-for='(item,index) in options'
                :key='item.id'
                class='item'
            >
                <div class='inner'>
                    <XImage
                        :src="item.src"
                        :aspect-ratio='aspectRatio'
                        :cut="cut_"
                        :width="itemWidth"
                        v-bind="elImageProps"
                    ></XImage>
                    <div
                        v-if='isDelete||preview || $scopedSlots.ctrl'
                        class='ctrl'>
                        <i
                            v-if='preview'
                            class="icon el-icon-search"
                            @click="onPreview(item,index)"
                        />
                        <a
                            v-if="showDownloadIcon"
                            class="icon el-icon-download"
                            target='_blank'
                            :href='item.rawSrc'
                        />
                        <i
                            v-if="isDelete"
                            class="icon el-icon-delete"
                            @click="onDelete(item,index)"
                        />
                        <slot
                            name='ctrl'
                            :item='item'
                            :index='index'></slot>
                    </div>
                </div>
            </div>
        </div>

        <template v-if="preview">
            <image-viewer
                ref="imageViewer"
                :z-index="zIndex"
                v-show="showViewer"
                :append-to-body="appendToBody"
                :on-close="closeViewer"
                :url-list="viewerImgList"
            />

            <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'
                    :cover='item.cover'></XVideo>
            </el-dialog>
        </template>
    </div>
</template>

<script>
import { Utils } from 'vmf';
import ImageViewer from 'element-ui/packages/image/src/image-viewer.vue';
import * as icons from '../Upload/icons';

let prevOverflow = '';
export default {
    name: 'XMediaList',
    components: { ImageViewer },
    data() {
        return {
            showViewer: false,
            videoDialog: {
                visible: false,
                url: '',
            },
        };
    },
    props: {
        fit: { type: String, default: 'cover' },
        lazy: { type: Boolean, default: false },
        scrollContainer: { type: [String, HTMLElement], default: '' },
        dataset: { type: [Array, String], default: '' },
        // 当 data 为 String 时用于分割 data
        splitter: { type: String, default: ',' },
        aspectRatio: { type: Number, default: 1, validator: val => val >= 0 },
        cut: { type: [String, Object], default: '' },
        itemWidth: { type: [Number, String], default: 100 },
        dataPropMap: { type: Object, default: () => ({}) },
        preview: { type: Boolean, default: false },
        zIndex: { type: Number, default: 2000 },
        appendToBody: { type: Boolean, default: true },
        showDownloadIcon: { type: Boolean, default: false },
    },
    computed: {
        elImageProps() {
            const {
                fit,
                lazy,
                scrollContainer,
                $attrs,
                // add
            } = this;
            return {
                ...$attrs,
                fit,
                lazy,
                scrollContainer,
            };
        },
        cut_() {
            const { cut } = this;
            if (cut) return cut;
            const { itemWidth } = this;
            const width = parseFloat(itemWidth);
            return { width };
        },
        dataProp() {
            return {
                id: 'id',
                label: 'label',
                src: 'src',
                cover: 'cover',
                ...(this.dataPropMap || {}),
            };
        },
        options() {
            const { dataProp } = this;
            let { dataset } = this;
            if (Utils.isString(dataset)) dataset = dataset.split(this.splitter);
            let imgIndex = 0;
            return (dataset || []).reduce((pre, cur) => {
                if (!cur) return pre;
                let item = cur;
                if (Utils.isString(cur)) item = { [dataProp.src]: cur };
                const src = item[dataProp.src];
                const isVideo = this.isVideo(src);
                const isImage = this.isImage(src);
                pre.push({
                    id: item[dataProp.id] || Utils.getUniqueId('id-'),
                    label: item[dataProp.label],
                    src: this.getIcon(src) || src,
                    cover:
                        item[dataProp.cover] ||
                        (isVideo ? `${cur}?x-oss-process=video/snapshot,t_1000,f_jpg,w_800,h_600,m_fast` : ''),
                    rawSrc: src,
                    isVideo,
                    isImage,
                    imgIndex,
                    raw: cur,
                });
                if (isImage) imgIndex += 1;
                return pre;
            }, []);
        },
        viewerImgList() {
            return this.options.reduce((pre, cur) => {
                if (cur.isImage) pre.push(cur.src);
                return pre;
            }, []);
        },
        isDelete() {
            return !!this.$listeners.delete;
        },
    },
    methods: {
        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);
        },
        getIcon(name) {
            const fileExt = (name.replace(/.+\./, '') || '').toLocaleLowerCase();
            // 排除图片格式
            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;
        },
        onPreview(item) {
            if (item.isImage) {
                const { imageViewer } = this.$refs;
                if (!imageViewer) return;
                // console.log('onPreview', index, imageViewer);
                console.log(item.imgIndex);
                imageViewer.index = item.imgIndex;
                prevOverflow = document.body.style.overflow;
                document.body.style.overflow = 'hidden';
                this.showViewer = true;
            } else if (item.isVideo) {
                this.videoDialog.visible = true;
                this.videoDialog.url = item.src;
            } else {
                window.open(item.rawSrc, '_blank');
            }
        },
        closeViewer() {
            document.body.style.overflow = prevOverflow;
            this.showViewer = false;
        },
        onDelete(item, index) {
            this.$emit('delete', { item, index });
        },
    },
};
</script>

<style lang='scss'>
.x-media-list {
    > .inner {
        display: flex;
        flex-direction: row;
        justify-content: flex-start;
        align-items: stretch;
        margin-left: -($padding / 2);
        margin-right: -($padding / 2);
        > .item {
            padding: ($padding / 2);
            > .inner {
                position: relative;
                border: 1px solid $gray5;
                border-radius: $padding-small;
                //background-color: $gray3;
                overflow: hidden;

                > .ctrl {
                    display: none;
                    /*display: flex;*/
                    flex-direction: row;
                    justify-content: center;
                    align-items: center;
                    flex-wrap: wrap;
                    position: absolute;
                    gap: 5px;
                    top: 0;
                    right: 0;
                    bottom: 0;
                    left: 0;
                    background-color: rgba(#000, 0.5);
                    color: #fff;
                }

                &:hover {
                    > .ctrl {
                        display: flex;
                    }
                }
            }
        }
    }
}
</style>
