<template>
    <div
        class="info-dynamic"
    >
        <el-table
            :id="domId"
            :key="updateKey"
            :data="tableData"
            :header-cell-style="{
                'background-color': '#f8f8f8',
            }"
            :height="row.height"
            :size="row.tableSize"
            border
            :row-key="row.rowKey || ''"
            style="width: 100%"
        >
            <el-table-column
                v-if="row.isDrop"
                width="40px"
            >
                <template #default>
                    <div class="handle">
                        <Sort style="width: 14px; height: 14px;" />
                    </div>
                </template>
            </el-table-column>
            <el-table-column
                v-if="row.showIndex"
                :label="row.indexLabel"
                :width="row.indexWidth"
                align="center"
                type="index"
            />
            <template
                v-for="(rule, _index) in rules"
            >
                <el-table-column
                    v-if="rule.show === undefined ? true : rule.show()"
                    :key="_index"
                    :align="rule.align"
                    :label="$t(rule.label)"
                    :min-width="rule.minWidth"
                    :prop="rule.model"
                    :width="rule.width"
                >
                    <!-- 表头添加搜索-->
                    <!-- <template
                        v-if="rule.isSearch"
                        #header
                    >
                        <el-input
                            v-model="search"
                            :disabled="rule.disabledHeader()"
                            :placeholder="rule.label"
                            size="small"
                            @input="getResult(false, rule.model)"
                        />
                    </template> -->
                    <!-- 表头筛选 -->
                    <template
                        v-if="!!rule.filters"
                        v-slot:header="scope"
                    >
                        {{ scope.column.label }}
                        <ColumnFilter
                            :column="rule"
                        />
                    </template>
                    <template #default="scope">
                        <span
                            v-if="rule.type === 'text'"
                            style="display: inline-block; margin: 12px 0;"
                        >{{
                                globalFormValue(scope.row, rule.model, row.deepData)._get()
                            }}</span>
                        <el-form-item
                            v-else
                            :prop="itemProp(scope.$index, rule)"
                            :test-cy="rule.model + '_' + scope.$index"
                            :rules="rule.validate"
                        >
                            <component
                                :is="typeof rule.type === 'function' ? rule.type(scope.$index) : rule.type"
                                :key="rowKey"
                                :config="row"
                                :modelData="tableData[scope.$index]"
                                :row="rule"
                                :totalIndex="indexMethod(scope.$index)"
                            />
                        </el-form-item>
                    </template>
                </el-table-column>
            </template>
            <!-- 操作 -->
            <el-table-column
                v-if="!row.noOper?.()"
                fixed="right"
                :label="$t('operation')"
                width="90"
            >
                <template #header>
                    <div class="oper-header">
                        <el-button
                            v-if="row.showAddAll?.()"
                            :icon="Finished"
                            :title="$t('batchAdd')"
                            :disabled="row.disabledAddAll?.()"
                            text
                            circle
                            @click="row.addAll?.()"
                        />
                        <el-button
                            v-if="!row.hiddenAdd?.()"
                            :icon="Plus"
                            :title="$t('add')"
                            :disabled="row.disabledAdd?.()"
                            text
                            circle
                            @click="add(dynamicResultField.length, true)"
                        />
                        <el-button
                            v-if="row.showUpload"
                            :icon="Upload"
                            :title="$t('upload')"
                            :disabled="row.disabledUpload?.()"
                            text
                            circle
                        />
                    </div>
                </template>
                <template #default="scope">
                    <div class="oper-header">
                        <el-button
                            v-if="!row.hiddenRemove?.(scope.row, scope.$index)"
                            :icon="Delete"
                            :title="$t('delete')"
                            :size="row.tableSize"
                            :disabled="row.disabledRemove?.(scope.row, scope.$index)"
                            text
                            circle
                            @click="remove(scope.$index)"
                        />
                        <el-button
                            v-if="!row.hiddenAdd?.(scope.row, scope.$index)"
                            :icon="CirclePlus"
                            :title="$t('insert')"
                            :size="row.tableSize"
                            :disabled="row.disabledAdd?.(scope.row, scope.$index)"
                            text
                            circle
                            @click="add(scope.$index)"
                        />
                    </div>
                </template>
            </el-table-column>
            <!-- 存在operates默认显示操作列-->
            <el-table-column
                v-if="row.operates"
                :fixed="row.operates.fixed"
                :width="row.operates.width"
                :label="$t('operation')"
            >
                <template #default="scope">
                    <template v-for="(btn, __index) in row.operates.list">
                        <el-tooltip
                            v-if="btn.show?.(scope.row) === undefined ? true : btn.show(scope.row)"
                            :key="__index"
                            :content="btn.label()"
                            :disabled="btn.tipDisable"
                            effect="dark"
                            placement="top"
                        >
                            <el-button
                                :circle="btn.circle"
                                :disabled="btn.disabled?.(scope.row)"
                                :icon="btn.icon"
                                :loading="btn.loading?.(scope.$index)"
                                :plain="btn.plain"
                                :text="btn.text"
                                :type="btn.type"
                                size="small"
                                @click="()=>{
                                    btn.method && btn.method(scope.$index, scope.row, result.list)
                                }"
                            >
                                <template v-if="btn.label">{{ btn.label(scope.row) }}</template>
                            </el-button>
                        </el-tooltip>
                    </template>
                </template>
            </el-table-column> <!-- end operates -->
        </el-table>
        <el-pagination
            v-if="!row.pagination"
            v-model:current-page="currentPage"
            :default-page-size="20"
            :page-sizes="[20, 50, 100, 500]"
            :pager-count="5"
            :total="result.list.length"
            layout="total, sizes, prev, pager, next, jumper"
            @size-change="handleSizeChange"
            @current-change="handleCurrentChange"
        />
        <uploadParamater
            :isSplit="row.isSplit"
            @confirmDialog="confirmDialog"
        />
    </div>
</template>
<script lang="ts">
import {
    defineComponent,
    reactive,
    ref,
    computed,
    watch,
    PropType,
    onMounted,
    onUnmounted,
    nextTick
} from 'vue'
import { globalFormValue, ObjectInterface, isValidKey } from '../../../script/index'
import { GetResultInter, RuleInterInter, ResultInterface, DynamicInterface } from './index'
import ColumnFilter from '../../table/ColumnFilter.vue'
import { Plus, Upload, CirclePlus, Delete, Finished, Sort } from '@element-plus/icons-vue'
import publicComponent from '../../../script/useComponent'
import { FormRule } from '../formConfig'
import Sortable from 'sortablejs'

export default defineComponent({
    name: 'Dynamic',
    components: {
        Plus,
        Sort,
        Finished,
        Upload,
        CirclePlus,
        Delete,
        ColumnFilter, ...publicComponent()
    },
    props: {
        row: {
            type: Object as PropType<DynamicInterface>,
            default: () => {
            }
        },
        // eslint-disable-next-line
        config: {
            type: Object,
            default: () => {
            }
        },
        modelData: {
            type: Object,
            default: () => {
            }
        },
        addIndex: { // 当前Tabs的索引
            type: [Number, String],
            default: ''
        }
    },
    setup (props) {
        const { row } = props
        const modelData = typeof props.addIndex === 'number' ? props.modelData[props.addIndex] : props.modelData // 通过addIndex区分正常form表单，还是在Tabs
        const rules = computed(() => {
            const rule = [] as any[]
            if (typeof row.rule === 'function') {
                const formRule = new FormRule()
                row.rule(formRule)
                rule.push(...formRule.rule)
            } else { // []
                rule.push(...row.rule)
            }
            if (row.disabled !== undefined && rule.length > 0) {
                rule.forEach((item) => {
                    if (item.ignoreItemsDisabled) return
                    const disabled = item.disabled
                    item.disabled = (obj) => {
                        return disabled(obj) || row.disabled?.()
                    }
                })
            }
            return rule
        })
        // const { ctx: that } = getCurrentInstance() as any
        const rowKey = ref<number>(0) // 自定义key，（用于更新组件渲染）
        const pageSize = ref<number>(20) // 分页
        const currentPage = ref<number>(1)
        const search = ref<string>('') // 搜索
        const result: any = reactive<ResultInterface>({ list: [] }) // 搜索结果
        const domId = ref<string>('')
        const updateKey = ref(0)
        const getTotalIndex = (index: number): number => { // 获取当前分页索引在所有数据的位置
            return index + pageSize.value * (currentPage.value - 1)
        }
        const dynamicResultField = ref<any>(globalFormValue(modelData, row.model, row.deepData)._get()) // 获取当前所有数据
        const tableData = computed(() => { // table数据，如果没有分页那么展示全部，否则通过页码截取
            if (row.pagination) {
                return result.list?.slice(0, result.list.length) // slice使list数据变化然后重新渲染页面
            } else {
                return result.list?.slice((currentPage.value - 1) * pageSize.value, currentPage.value * pageSize.value)
            }
        })
        const itemProp = computed(() => (index: number, rule: ObjectInterface) => {
            const key = row.model.split('.')
            const isDot = key.length === 2
            let model = isDot && !row.modelFormat ? `${key[0]}[${index}].${key[1]}` : row.model
            if (row.noOper?.() && row.pagination) {
                return `${model}[${index}][${rule.model}]`
            }
            const realIndex = getTotalIndex(index)
            return `${model}[${realIndex}].${rule.model}`
        })
        /**
         * @param init
         * @param searchFiled 需要搜索的字段
         */

        const getResult: GetResultInter = (init, searchFiled) => { // 获取table数据，如果有搜索的话，展示全部搜索结果
            result.list = dynamicResultField.value
            // modelData[row.model] = result.list
            globalFormValue(modelData, row.model)._set(result.list)
            if (searchFiled && modelData[searchFiled]) {
                currentPage.value = 1
                setTimeout(() => {
                    result.list = dynamicResultField.value.filter((data: ObjectInterface, index: number) => {
                        data.originIndex = index
                        return !search.value || (data[searchFiled] as string).toLowerCase().indexOf(search.value.toLowerCase()) !== -1
                    })
                }, 500)
            }
            // if (!init) {
            //     let form = that.$parent.$parent.$parent
            //     if (!form.validateField) {
            //         form = form.$parent.$parent
            //     }
            //     form.validateField?.(row.key)
            // }
        }
        const init = (): ObjectInterface => { // 初始化数据对象，动态添加行的时候
            const obj: ObjectInterface = {}
            for (let item of rules.value) {
                let defaultVal = item.defaultVal?.()
                obj[item.model] = defaultVal === undefined ? '' : defaultVal
                if (item.append) {
                    obj[item.append.key] = ''
                }
            }
            return obj
        }
        const add = (j: number, isTableAdd = false): void => { // table 添加一行
            if (!row.pagination) j = indexMethod(j)
            let newObj = init()
            dynamicResultField.value.splice((j + 1), 0, newObj)
            if (isTableAdd && !row.pagination) {
                currentPage.value = Math.ceil(dynamicResultField.value.length / pageSize.value)
            } else {
                if (j === pageSize.value - 1) {
                    currentPage.value += 1
                }
            }
            row?.addRow?.(j, isTableAdd)
            getResult()
            rowKey.value++
        }
        const remove = (j: number): void => { // 移除
            // row.deleteRow?.(j)
            if (!row.pagination) j = indexMethod(j)
            let deleteList = dynamicResultField.value.splice(j, 1)
            if (currentPage.value > Math.ceil(dynamicResultField.value.length / pageSize.value)) {
                currentPage.value = Math.ceil(dynamicResultField.value.length / pageSize.value)
            }
            row?.delRow?.(j, deleteList[0])
            getResult()
            rowKey.value++
        }
        const getTips = (rule: RuleInterInter): string => { // 获取tips信息
            let tips = rule.tips()
            return tips.split('\n').join('<br/>')
        }
        const indexMethod = (index: number): number => { // 获取当前行的索引(处理分页)
            return (pageSize.value * (currentPage.value - 1)) + index
        }
        const confirmDialog = (data: object[]): void => { // 上传弹窗回调
            for (let val of data) {
                let obj: ObjectInterface = {}
                for (let item in row.rule) {
                    if (isValidKey(item, row.rule)) {
                        let obj: ObjectInterface = row.rule[item]
                        obj[obj.model] = val[item]
                    }
                }
                dynamicResultField.value.push(obj)
            }
            currentPage.value = Math.ceil(dynamicResultField.value.length / pageSize.value)
            getResult()
        }
        const handleSizeChange = (val: number): void => {
            pageSize.value = val
        }
        const handleCurrentChange = (val: number): void => {
            currentPage.value = val
            rowKey.value++
        }
        watch(() => dynamicResultField.value, () => {
            getResult(true)
        }, {
            immediate: true,
            deep: true
        })
        /**
         * 动态组件支持的三种情况：
         * 1 标准模式 [{'key': 'value'}, {}]
         * 2 纯数组模式 ['', '']
         *  row: {
         *      getArr: true,
         *      pagination: true, // 无分页
         *  }
         * 3 对象模式(单条) {'key': 'value'}
         *  如 settings 中 format:'single'
         *  转换为标准模式处理
         *  row: {
         *      noOper: true, // 无操作
         *      pagination: true // 无分页
         *  }
         */
        if (Object.prototype.toString.call(modelData[row.model]) === '[object Object]') { // 处理回显，如果是数据对象 重新赋值
            result.list = []
            result.list.push(modelData[row.model])
        } else {
            getResult(true)
        }
        domId.value = row.id || 'dynamicTable'
        let sortable: any = null
        const rowDrop = () => {
            let element = document.querySelector(`[test-cy="${row.model}"]`)
            let tbody = (element || document).querySelector('.info-dynamic .ep-table__body tbody')
            sortable = Sortable.create(tbody, {
                animation: 150,
                handle: '.handle',
                onEnd ({ newIndex, oldIndex }: { newIndex: number, oldIndex: number }) {
                    const currentRow = dynamicResultField.value.splice(oldIndex, 1)[0]
                    dynamicResultField.value.splice(newIndex, 0, currentRow)
                    nextTick(() => {
                        updateKey.value = Math.random()
                        setTimeout(() => {
                            if (row.isDrop) {
                                createSort()
                            }
                        }, 20)
                    })
                    row?.dropEnd?.({ oldIndex, newIndex, currentRow, list: dynamicResultField.value })
                }
            })
        }
        let timer = 0
        const createSort = () => {
            timer = window.setTimeout(() => {
                rowDrop()
            }, 500)
        }
        const destroySort = () => {
            timer && clearTimeout(timer)
            if (sortable) {
                sortable = null
            }
        }
        onMounted(() => {
            setTimeout(() => {
                if (row.isDrop) {
                    createSort()
                }
            }, 20)
        })
        onUnmounted(() => {
            destroySort()
        })
        return {
            pageSize,
            currentPage,
            search,
            result,
            domId,
            getTotalIndex,
            dynamicResultField,
            tableData,
            itemProp,
            add,
            remove,
            getTips,
            indexMethod,
            confirmDialog,
            handleSizeChange,
            handleCurrentChange,
            getResult,
            globalFormValue,
            rowKey,
            rules,
            updateKey,
            row,
            Finished,
            Plus,
            Upload,
            Delete,
            CirclePlus
        }
    }
})
</script>
<style lang="scss" scoped>
.info-dynamic {
    width: 100%;
}
:deep(.el-table__row) {
    td {
        padding: 0;
        .el-form-item {
            margin: 12px 0 16px; // validate error
        }
    }
}
[class^=el-icon-] {
    margin: 0 10px;
}
.dynamic-tip-icon {
    color: #000;
    top: 6px !important;
    left: auto !important;
    margin-left: 5px;
}
.el-pagination {
    margin-top: 8px;
    float: right;
}
.contentTip {
    max-width: calc(50vw)
}
.oper-header {
    display: flex;
    justify-content: space-around;
    align-items: center;
}
</style>
