<template>
    <div class="plr">
        <el-table ref="theTable" @row-click="_onRowClick" v-loading="loading" :lazy="lazy" :load="_lazyLoad" :data="listSync" :default-expand-all="defaultExpandAll"
                  :empty-text="emptyText" :row-key="rowKey" :tree-props="treeProps" border="border" @selection-change="_onSectionChange">

            <template v-for="(item,cIndex) in tableColumns" :key="item.name">

                <el-table-column v-if="item.type == 'selection'" fixed="left" type="selection"></el-table-column>

                <el-table-column v-else :prop="item._prop" :label="item.label" :align="item.align" :width="item.width"
                                 :fixed="item.fixed">
                    <template #default="{row,$index}">

                        <!-- 自定义插槽 -->
                        <slot v-if="item.type == 'slot'" :prop="item.name" :value="row[item.name]"
                              :labelValue="row[item.dictProp]" :column="item" :row="row"
                              :rowIndex="$index"></slot>

                        <!-- 时间格式化 -->
                        <st-time v-else-if="item.type == 'st-time'" :date="row[item.name]" :format="item.format"
                                 :default-str="item.defaultStr" :differ="item.differ"
                                 :showTime="item.showTime"></st-time>

                        <!--index-->
                        <div v-else-if="item.type == 'index'" :class="textClass">
                            {{ $index + 1 + startIndexValue }}
                        </div>

                        <!-- 文本 -->
                        <div v-else :class="item.textClass">
                            <st-table-tooltip :props="item" :text="row[item._prop]" :prepend="row.prepend" :append="item.append" :defaultText="defaultText"></st-table-tooltip>
                        </div>

                    </template>
                </el-table-column>
            </template>
        </el-table>
    </div>
</template>

<script>
import tableStore from "@/modules/st-core/js_sdk/store";
import dictDataStore from "@/modules/st-core/js_sdk/store/dict-data-store";
import {createAuth} from "@/modules/st-core/js_sdk/util/create-auth";
import StTextGroup from "@/modules/st-core/components/st-text-group/st-text-group";
import StTableTooltip from "@/modules/st-core/components/st-table/st-table-tooltip";

export default {
    name: "st-table",
    components: {StTableTooltip, StTextGroup},
    emits:["sectionChange"],
    props: {
        rowKey: String,
        loading: Boolean,
        lazy: Boolean,
        load: Function,
        treeProps: {
            type: Object,
            default() {
                return {};
            }
        },
        list: {
            type: Array,
            default() {
                return [];
            }
        },
        dictKeys: { //columns中未指定的额外的字典数据键名集合
            type: Array,
            default() {
                return [];
            }
        },
        columns: {
            type: Array,
            default() {
                return [];
            },
            validator(value) {
                for (let item of value) {
                    if (item.type != 'index' && (!item.label || !item.name)) {
                        console.error("columns内部元素的label、prop属性为必填项: ", item);
                        return false;
                    }
                }
                return true;
            }
        },
        emptyText: {
            type: String,
            default: "抱歉，暂无数据~"
        },
        defaultLabel: { //字典名未定义时默认的名称
            type: String,
            default: "--"
        },
        defaultText: { //值为空时占位符
            type: String,
            default: "--"
        },
        textClass: { //非自定义插槽文字显示的class名称
            type: String,
            default: "clip c1"
        },
        auth: {
            type: Boolean,
            default() {
                return situ.getConfig("auths", false);
            }
        },
        defaultExpandAll: {
            type: Boolean,
            default: false
        }
    },
    data() {
        return {
            transferShow: false,
            hideSearchKeys: [] ,
            tableWidth : -1
        };
    },
    inject: ["startIndex"],
    computed: {
        startIndexValue() {
            return this.startIndex ? this.startIndex : 0;
        },

        listSync() {
            if(this.loading && this.list.length == 0) return [{}];
            this.setDictData(this.list);
            return this.list ;
        },

        columnsSync() {
            return this.columns.map(item => {
                let dictProp = item.dictKey ? `${item.name}_dictName` : "";
                let defaultAuth = createAuth(item.auth, this.$route.path, item.name)
                return {
                    ...item,
                    defaultLabel: item.defaultLabel || this.defaultLabel,
                    align: item.align || "left",
                    textClass: item.textClass || this.textClass,
                    width: this._getWidth(item),
                    defaultAuth ,
                    dictProp,
                    _prop : dictProp || item.name
                };
            }).filter(item => ( this.auth === false && !item.auth ) ||  this.$s.hasAuth(item.defaultAuth) );
        },

        tableColumns() {
            let list = this.columnsSync.filter(item => !this.hideKeys.includes(item.name));
            let allFixWidth = list.every(item => item.width && item.width != "auto") ;
            if(!allFixWidth || this.tableWidth == -1) return list ;
            let totalWidth = list.reduce((total,item) => total + item.width , 0) ;
            if(this.tableWidth <= totalWidth) return list ;
            let lastNotFixedIndex = list.reduce((curIndex,item,index) => item.fixed ? curIndex : index , 0) ;
            return list.map((item,index) => {
                if(index == lastNotFixedIndex) return { ...item , width : "auto"} ;
                return item ;
            }) ;
        },

        dictKeysSync() {
            return this.columns.filter(item => !!item.dictKey).map(item => item.dictKey).concat(this.dictKeys);
        },

        toggleRowKeys() {
            return this.columnsSync.filter(c => c.toggleRow).map(c => c.name);
        },

        hideKeys() {
            return tableStore.state.hideKeys;
        },

        sectionProp(){
            let column = this.columnsSync.find(item => item.type == "selection") || {};
            return column.name ;
        }
    },

    async created() {
        await dictDataStore.dispatch("load" , this.dictKeysSync);
        this.$watch(() => this.dictKeysSync.join(","), async () => {
            await dictDataStore.dispatch("load" , this.dictKeysSync);
        }, {immediate: true});
    },

    async mounted() {
        await this.$nextTick();
        setTimeout(()=>{
            this.tableWidth = this.$refs.theTable.$el.offsetWidth ;
        },200)
    },

    methods: {

        setDictData(list=[]){
            if(!Array.isArray(list)) return ;
            list.forEach(item => {
                for (let key in item) {
                    let column = this.columnsSync.find(c => c.name === key);
                    if (!column || !column.dictKey) {
                        continue;
                    }
                    let datas = this.dictData[column.dictKey];
                    if (!datas) {
                        continue;
                    }
                    let value = item[key];
                    let dictItem = datas.find(d => d.value == value) || {};
                    item[`${key}_dictName`] = dictItem.label || column.defaultLabel;
                }
                let childrenKey = this.treeProps.children || "children" ;
                this.setDictData(item[childrenKey]);
            })
        },

        _getWidth({width, label}) {
            if (width) return width;
            let autoWidth = label.length * 15 + 25;
            return autoWidth < 85 ? 85 : autoWidth;
        },

        async _onRowClick(row, {property}, event) {
            let expandIcon = this._findExpandIcon(event);
            if ( !expandIcon || !this.rowKey || !this.toggleRowKeys.includes(property)) return;
            if(expandIcon) expandIcon.click();
        },

        _findExpandIcon(event){
            let tr = this._findTrNode(event.target);
            return tr.querySelector(".el-table__expand-icon");
        },

        _findTrNode(target){
            let parent = target.parentElement ;
            if(!parent) return ;
            return parent.tagName.toLowerCase() == "tr" ? parent : this._findTrNode(parent) ;
        },

        _load(data , nodes){
            return new Promise(resolve => {
                this.load(data , nodes , resolve ) ;
            })
        },

        async _lazyLoad(data , nodes , resolve){
            let children = await this._load( data , nodes ) ;
            this.setDictData(children);
            resolve(children) ;
        },

        _onSectionChange(values){
            let props = this.sectionProp ? values.map(item => item[this.sectionProp]) : [] ;
            this.$emit("sectionChange" , {values , props});
        }
    }
}
</script>

<style lang="scss">
.el-table__empty-block {
    width: 100% !important;
    max-width: calc(100vw - 300px);
}

.el-table th.el-table__cell, .el-table__body-wrapper tr th.el-table-fixed-column--left, .el-table__body-wrapper tr th.el-table-fixed-column--right, .el-table__footer-wrapper tr td.el-table-fixed-column--left, .el-table__footer-wrapper tr td.el-table-fixed-column--right, .el-table__footer-wrapper tr th.el-table-fixed-column--left, .el-table__footer-wrapper tr th.el-table-fixed-column--right, .el-table__header-wrapper tr td.el-table-fixed-column--left, .el-table__header-wrapper tr td.el-table-fixed-column--right, .el-table__header-wrapper tr th.el-table-fixed-column--left, .el-table__header-wrapper tr th.el-table-fixed-column--right {
    background-color: #fbfbfb!important;
    color: #000;
}
</style>