<template>
    <div class="plTableBox" :style="[plTableHeight]">
        <plx-grid ref="singleTable"
                  class="singleTable"
                  style="width: 100%"
                  :data="isArrayFn(data) ? data : []"
                  :show-footer="summaryMethod ? showSummary : false"
                  :max-height="newMaxHeight"
                  :height="newHeight"
                  :border="border"
                  :stripe="stripe"
                  :row-key="rowKey"
                  :size="size"
                  :show-header="showHeader"
                  :show-overflow="showOverflow"
                  :footer-method="footerMethod"
                  :show-header-overflow="showHeaderOverflow"
                  :highlight-current-row="highlightCurrentRow"
                  :highlight-hover-row="highlightCurrentRow"
                  :row-class-name="rowClassName"
                  :cell-class-name="cellClassName"
                  :header-row-class-name="headerRowClassName"
                  :header-cell-class-name="headerCellClassName"
                  :header-row-style="headerRowStyle"
                  :header-cell-style="headerCellStyle"
                  :row-style="rowStyle"
                  :cell-style="cellStyle"
                  :sort-config="{ sortMethod: sortMethod, defaultSort: defaultSort }"
                  :span-method="arraySpanMethod"
                  @current-change="currentChange"
                  @select-change="plSelect"
                  @resizable-change="headerDragend"
                  @cell-mouseenter="cellMouseEnter"
                  @cell-mouseleave="cellMouseLeave"
                  @cell-click="cellClick"
                  @cell-dblclick="cellDblclick"
                  @cell-context-menu="rowContextmenu"
                  @header-cell-context-menu="headerContextmenu"
                  @radio-change="radioChange"
                  @header-cell-click="headerClick"
                  @select-all="selectAll"
                  @filter-change="filterChange"
                  @sort-change="sortChange"
                  @scroll="tableBodyScroll">
            <!--无数据布局-->
            <template slot="empty">
                <slot name="empty">{{ emptyText }}</slot>
            </template>
            <slot/>
        </plx-grid>
        <div class="myPagination" v-if="paginationShow" ref="myPagination">
            <el-pagination
                    @size-change="handleSizeChange"
                    @current-change="handleCurrentChange"
                    :current-page="newcurrentPage"
                    :pager-count="pagerCount"
                    :page-sizes="pageSizes"
                    :page-size="newPageSize"
                    :layout="layout"
                    :total="total"/>
        </div>
        <div class="plDialog" ref="plDialog">
            <div style="width: 100%;height: 100%;" v-if="plDialogFals">
                <div class="table-cus-header">{{ fieldTitle }}</div>
                <div class="checkListBox">
                    <draggable tag="ul"
                               :options="{disabled: !fieldSort}"
                               v-model="newDialogData">
                        <li v-for="(item, index) in newDialogData" :key="index">
                            <el-checkbox v-model="item.state" :disabled="item.disabled">{{ item.name }}</el-checkbox>
                            <i class="iconfont"
                               :class="[amendBtnIcon || 'el-icon-edit']"
                               v-if="showAmend"
                               @click="amendField(item, index)"/>
                        </li>
                    </draggable>
                </div>
                <div class="table-cus-footer">
                    <el-button @click="closeModal()">取消</el-button>
                    <el-button type="primary" @click="confirmField">确定</el-button>
                    <el-button type="warning" @click="reset">重置</el-button>
                </div>
            </div>
        </div>
    </div>
</template>

<script type="text/babel">
    import Vue from 'vue'
    import draggable from 'vuedraggable'
    import ElPagination from 'pl-table/packages/pagination'
    import { parseHeight } from './util'
    export default {
        name:'PlxTableGrid',
        components: {draggable, ElPagination},
        props: {
            showOverflow: { type: Boolean, default: true },
            showHeaderOverflow: { type: Boolean, default: true },
            data: {type: Array, default: () => []}, // 表格数据
            height: [String, Number],
            maxHeight: [String, Number],
            sortMethod: Function,
            dialogData: {type: Array, default: () => []}, // 选择显示字段数组
            defaultSort: Object, // 默认的排序列的 prop 和顺序
            stripe: {default: false, type: Boolean}, // 是否为斑马纹
            size: {default: '', type: String}, // Table 的尺寸
            showHeader: {default: true, type: Boolean}, // 是否显示表头
            emptyText: {default: '暂无数据', type: String}, // 空数据时显示的文本内容
            border: {default: true, type: Boolean}, // 是否显示纵向边框
            showSummary: {default: false, type: Boolean}, // 是否需要合计
            summaryMethod: Function, // 自定义的合计计算方法
            fieldSort: { default: true, type: Boolean }, // 字段排序
            rowKey: Boolean, // 支持树类型的数据。此时,必须要指定 row-key (注意,当开启useVirtual时,无效)
            highlightCurrentRow: { default: true, type: Boolean }, // 是否要高亮当前行
            showAmend: { default: false, type: Boolean }, // 是否显示修改字段名按钮(侧滑框)
            amendBtnIcon: { default: '', type: String }, // 修改字段按钮的图标(侧滑框)
            fieldTitle: { default: '选择显示字段', type: String }, // 弹框的标题(侧滑框)
            spanMethod: Function, // 合并行或列的计算方法
            rowClassName: [String, Function], // 行的 className 的回调方法,也可以使用字符串为所有行设置一个固定的 className。
            rowStyle: [Object, Function], // 行的 style 的回调方法
            cellClassName: [String, Function], // 行单元格的 className 的回调方法
            cellStyle: [Object, Function], // 行单元格的 style 的回调方法
            headerRowClassName: [String, Function], // 表头行的 className 的回调方法
            headerRowStyle: [Object, Function], // 表头行的 style 的回调方法
            headerCellClassName: [String, Function], // 表头单元格的 className 的回调方法
            headerCellStyle: [Object, Function], // 表头单元格的 style 的回调方法
            paginationShow: {default: false, type: Boolean}, // 是否需要分页器
            total: {default: 0, type: Number}, // 总条数
            pagerCount: { default: 5, type: Number }, // 页码按钮的数量,当总页数超过该值时会折叠
            pageSize:{ default: 10, type: Number }, // 每页条数
            currentPage: { default: 1, type: Number }, // 当前页
            pageSizes: { default: () => [10, 20, 30, 50], type: Array }, // 每页显示个数选择器的选项设置
            layout: { default: 'total, sizes, prev, pager, next, jumper', type: String } // 分页组件布局,子组件名用逗号分隔
        },
        data () {
            return {
                _times: '', // 弹框定时器
                plDialogFals: false, // 侧滑弹框是否开启
                newDialogData: [], // 新自定义字段的数据
                aBox: '', // 蒙层节点
                newPageSize: '', // 每页条数
                newcurrentPage: '', // 当前页
                newHeight: null, // 表格高度
                newMaxHeight: null // 表格最大高度
            }
        },
        created () {
            this.newPageSize = this.pageSize
            this.newcurrentPage = this.currentPage
        },
        mounted () {
            this.$ready = true
        },
        computed: {
            plTableHeight() {
                if (this.height) {
                    return {
                        height: this.height + 'px'
                    };
                } else if (this.maxHeight) {
                    const maxHeight = parseHeight(this.maxHeight);
                    if (typeof maxHeight === 'number') {
                        return {
                            'max-height': this.maxHeight + 'px'
                        };
                    }
                }
                return {};
            }
        },
        methods: {
            // 分页器的事件
            handleSizeChange (val) {
                this.newPageSize = val
                this.$emit('handlePageSize', { size: this.newPageSize, page: this.newcurrentPage })
            },
            handleCurrentChange (val) {
                this.newcurrentPage = val
                this.$emit('handlePageSize', { size: this.newPageSize, page: this.newcurrentPage })
            },
            // 判断数组
            isArrayFn (value){
                if (typeof Array.isArray === 'function') {
                    return Array.isArray(value);
                } else {
                    return Object.prototype.toString.call(value) === '[object Array]';
                }
            },
            // 利用数组中的filter方法数组去重
            removal (data) {
                if (this.isArrayFn(data)) {
                    return data.filter(function(element,index,self){
                        return self.indexOf(element) === index;
                    })
                } else {
                    throw new Error('需要的是数组');
                }
            },
            // 数组对象去重的方法
            removalDataObj (arr, key) {
                if (this.isArrayFn(arr)) {
                    let result = [];
                    let obj = {};
                    for(let i =0; i<arr.length; i++){
                        if(!obj[arr[i].row[key]]){
                            result.push(arr[i]);
                            obj[arr[i].row[key]] = true;
                        }
                    }
                    return result
                } else {
                    throw new Error('需要的是数组');
                }
            },
            // 打开自定义字段框
            plDialogOpens () {
                this._times = null
                this.$refs.plDialog.style.width = 300 + 'px'
                this._times = setTimeout(() => {
                    this.plDialogFals = true
                }, 100)
                // 创建节点(主要用来弹出menu窗口时,不让起点击外面)
                this.aBox = document.createElement('div')
                this.aBox.className = 'modal-backdrop'
                this.aBox.style.display = 'block'
                this.aBox.onclick = () => {
                    this.closeModal()
                }
                document.body.appendChild(this.aBox)
            },
            // 关闭自定义字段框(取消选择)
            closeModal () {
                this.plDialogFals = false
                clearTimeout(this._times)
                this.$refs.plDialog.style.width = 0 + 'px'
                this.aBox.style.display = 'none'
                this.clearNode()
                this.newDialogData = JSON.parse(JSON.stringify(this.dialogData))
            },
            // 确认按钮
            confirmField () {
                this.$emit('show-field', this.newDialogData)
                this.plDialogFals = false
                clearTimeout(this._times)
                this.$refs.plDialog.style.width = 0 + 'px'
                this.aBox.style.display = 'none'
                this.clearNode()
            },
            // 重置按钮
            reset () {
                this.$emit('reset', this.newDialogData)
                this.plDialogFals = false
                clearTimeout(this._times)
                this.$refs.plDialog.style.width = 0 + 'px'
                this.aBox.style.display = 'none'
                this.clearNode()
            },
            // 修改字段名按钮事件
            amendField (item, index) {
                this.$emit('amend-field', item, index)
            },
            // 删除节点
            clearNode () {
                // 删除节点
                let parent = this.aBox ? this.aBox.parentNode : ''
                parent && parent.removeChild(this.aBox)
                let doms = document.getElementsByClassName('modal-backdrop')
                if (doms.length > 0) {
                    document.body.removeChild(doms[0])
                }
                this.aBox = null
            },

            // 表格方法

            // 合计的方法summaryMethod
            footerMethod (param) {
                if (typeof this.summaryMethod === 'function' && this.summaryMethod) {
                    return this.summaryMethod(param)
                } else {
                    return []
                }
            },
            // 合并行或列的计算方法
            arraySpanMethod (objs) {
                // 是否有条件开启合并列
                if (typeof this.spanMethod === 'function') {
                    return this.spanMethod(objs)
                } else {
                    return ''
                }
            },
            // 用于单选表格,设定某一行为选中行
            setCurrentRow (row) {
                if (row) {
                    this.$refs.singleTable.setCurrentRow(row);
                } else {
                    this.$refs.singleTable.setCurrentRow();
                }
            },
            // 用于多选表格,切换某一行的选中状态,如果使用了第二个参数,则是设置这一行选中与否(selected 为 true 则选中)
            toggleRowSelection (rows) {
                if (rows && this.isArrayFn(rows)) {
                    this.newtoggleRowSelections(rows)
                } else {
                    console.error('数据格式需要一个数组')
                }
            },
            // 用于多选表格,切换某一行的选中状态
            newtoggleRowSelections (datas) {
                if (datas.length > 0 && this.$refs.singleTable) {
                    datas.forEach(item => {
                        if (item.selected) {
                            this.$refs.singleTable.setCheckboxRow(item.row, item.selected)
                        } else if (item.selected === false) {
                            this.$refs.singleTable.setCheckboxRow(item.row, false)
                        } else if (item.selected === undefined) {
                            this.$refs.singleTable.setCheckboxRow(item.row, '')
                        }
                    })
                    // 当选择项发生变化时会触发该事件
                    const data = this.$refs.singleTable.getCheckboxRecords()
                    this.$emit('selection-change', data)
                }
            },
            // 用于多选表格,切换所有行的选中状态
            toggleAllSelection (checked = true) {
                if (this.$refs.singleTable) {
                    this.$refs.singleTable.setAllCheckboxRow(checked)
                    // 当选择项发生变化时会触发该事件
                    const data = this.$refs.singleTable.getCheckboxRecords()
                    this.$emit('selection-change', data)
                } else {
                    console.error('toggleAllSelection方法为找到,可能表格未加载完毕')
                }
            },
            // 用于多选表格,清空用户的选择
            clearSelection () {
                if (this.$refs.singleTable) {
                    this.$refs.singleTable.clearCheckboxRow()
                    // 当选择项发生变化时会触发该事件
                    const data = this.$refs.singleTable.getCheckboxRecords()
                    this.$emit('selection-change', data)
                } else {
                    console.error('clearSelection方法为找到,可能表格未加载完毕')
                }
            },
            // 用于清空排序条件,数据会恢复成未排序的状态
            clearSort () {
                this.$refs.singleTable.clearSort()
            },
            // 不传入参数时用于清空所有过滤条件,数据会恢复成未过滤的状态
            clearFilter (columnKey) {
                this.$refs.singleTable.clearFilter(columnKey)
            },
            // 手动对 Table 进行排序
            sort (prop, order) {
                this.$refs.singleTable.sort(prop, order)
            },
            // 对 Table 进行重新布局。当 Table 或其祖先元素由隐藏切换为显示时,可能需要调用此方法
            doLayout () {
                this.$refs.singleTable.recalculate()
            },
            // 让表格滚动条回到顶部,和左侧
            pagingScrollTopLeft (top = 0, left = 0) {
                this.$refs.singleTable.scrollTo(left, top)
            },
            // 设置表格数据
            reloadData (data) {
                this.$refs.singleTable.reloadData(data)
            },
            // 设置表格高度
            setHeight () {
                if (!this.$ready && this.paginationShow) return Vue.nextTick(() => this.setHeight());
                const { myPagination } = this.$refs;
                if (this.height) {
                    this.newHeight = parseHeight(this.height) - (myPagination ? myPagination.offsetHeight : 0)
                    this.newMaxHeight = null
                } else if (this.maxHeight) {
                    this.newMaxHeight = parseHeight(this.maxHeight) - (myPagination ? myPagination.offsetHeight : 0)
                    this.newHeight = null
                }
            },

            // 表格事件

            // 表格滚动时会触发该事件
            tableBodyScroll ({type,fixed,scrollTop,scrollLeft,isX,isY},event) {
                let obj = {type,fixed,scrollTop,scrollLeft,isX,isY}
                // 当表格滚动暴露滚动事件
                this.$emit('table-body-scroll', obj, event)
            },
            // 当用户手动勾选全选 Checkbox 时触发的事件	selection
            selectAll ({selection}) {
                this.$emit('select-all', selection)
                // 当选择项发生变化时会触发该事件
                this.$emit('selection-change', selection)
            },
            // 当用户手动勾选数据行的 Checkbox 时触发的事件
            plSelect ({selection,reserves,checked,row}) {
                this.$emit('select', selection, row)
                // 当选择项发生变化时会触发该事件
                this.$emit('selection-change', selection)
            },
            // 只对 type=radio 有效,当手动勾选并且值发生改变时触发的事件
            radioChange ({row,rowIndex,$rowIndex,column,columnIndex,$columnIndex,cell},event) {
                this.$emit('radio-change', row, column)
            },
            // 当表格的排序条件发生变化的时候会触发该事件
            sortChange ({column,property,order}) {
                let objs = {column, prop: property, order}
                this.$emit('sort-change', objs)
            },
            // 当表格的当前行发生变化的时候会触发该事件
            currentChange ({row,rowIndex,$rowIndex,column,columnIndex,$columnIndex,cell},event) {
                this.$emit('current-change', row)
            },
            // 当表格的筛选条件发生变化的时候会触发该事件
            filterChange ({column,property,values,datas,filters}) {
                this.$emit('filter-change', filters)
            },
            // 当单元格 hover 进入时会触发该事件
            cellMouseEnter ({row,rowIndex,$rowIndex,column,columnIndex,$columnIndex,cell},event) {
                this.$emit('cell-mouse-enter', row, column, cell, event)
            },
            // 当单元格 hover 退出时会触发该事件
            cellMouseLeave ({row,rowIndex,$rowIndex,column,columnIndex,$columnIndex,cell}, event) {
                this.$emit('cell-mouse-leave', row, column, cell, event)
            },
            // 当某个单元格被点击时会触发该事件
            cellClick ({row,rowIndex,$rowIndex,column,columnIndex,$columnIndex,cell}, event) {
                this.$emit('cell-click', row, column, cell, event)
                // row-click	当某一行被点击时会触发该事件	row, event, column
                this.$emit('row-click', row, event, column)
            },
            // 当某个单元格被双击击时会触发该事件
            cellDblclick ({row,rowIndex,$rowIndex,column,columnIndex,$columnIndex,cell},event) {
                this.$emit('cell-dblclick', row, column, cell, event)
                // 当某一行被双击时会触发该事件
                this.$emit('row-dblclick', row, column, event)
            },
            // 单元格被鼠标右键点击时触发该事件
            rowContextmenu ({type,row,rowIndex,column,columnIndex,cell},event) {
                console.log(213121)
                this.$emit('row-contextmenu', row, column, event)
            },
            // 当某一列的表头被点击时会触发该事件
            headerClick ({triggerResizable,triggerSort,triggerFilter,$rowIndex,column,columnIndex,$columnIndex,cell},event) {
                this.$emit('header-click', column, event)
            },
            // 当某一列的表头被鼠标右键点击时触发该事件	column, event
            headerContextmenu ({type,column,columnIndex,cell},event) {
                this.$emit('header-contextmenu', column, event)
            },
            // 当拖动表头改变了列的宽度的时候会触发该事件(newWidth, oldWidth, column, event)
            headerDragend ({$rowIndex, column, columnIndex, $columnIndex, fixed, isHidden}) {
                let obj = {$rowIndex, column, columnIndex, $columnIndex, fixed, isHidden}
                this.$emit('header-dragend', obj)
            }
        },
        watch: {
            data: {
                immediate: true,
                handler (val) {
                    if (!this.isArrayFn(val)) {
                        throw new Error('表格数据需要的是数组格式,请检查你的数据格式');
                    }
                }
            },
            dialogData: {
                deep: true,
                immediate: true,
                handler (val) {
                    this.newDialogData = JSON.parse(JSON.stringify(val))
                }
            },
            currentPage (val) {
                this.newcurrentPage = val
            },
            pageSize (val) {
                this.newPageSize = val
            },
            height: {
                immediate: true,
                handler(value) {
                    this.setHeight();
                }
            },
            maxHeight: {
                immediate: true,
                handler(value) {
                    this.setHeight();
                }
            }
        }
    }
</script>