<template>
    <component :is="render" />
</template>
<script setup lang="jsx">
    import SortableTable from './SortableTable.vue';
    import { ElTable, ElTableColumn } from 'element-plus/es/components/table/index';
    import 'element-plus/es/components/table/style/css';
    const props = defineProps({
        code: {
            type: String,
            default: '',
        },
        title: {
            type: String,
            default: '',
        },
        sortable: {
            type: Boolean,
            default: false,
        },
        config: {
            type: Object,
            required: true,
        },
        operation: {
            type: Array,
            default() {
                return ['create', 'remove', 'search'];
            },
        },
        total: {
            type: Number,
            default: 0,
        },
    });
    const emits = defineEmits([
        'create',
        'save',
        'remove',
        'search',
        'select',
        'selectAll',
        'selectionChange',
        'currentChange',
        'reset',
        'template',
        'import',
        'export',
    ]);
    const attrs = useAttrs();
    const slots = useSlots();
    const { proxy } = getCurrentInstance();
    const store = useStore();

    // 获取只包含对象基础属性的副本
    const getObjectProps = (obj) => {
        return _.clone(Object.fromEntries(Object.entries(obj).filter((entry) => typeof entry[1] !== 'object')));
    };
    // 初始化设置
    const settings = computed(() => store.state.local.listSettings);
    const handleInit = (clear = false) => {
        // 修改过表格配置源码需要清空本地缓存配置
        if (props.code && clear) {
            store.commit('local/setListSettings', {
                ...unref(settings),
                [props.code]: null,
            });
            console.info('[list] reset:' + props.code);
        }
        let config = null;
        if (
            !props.code ||
            !unref(settings) ||
            !unref(settings)[props.code] ||
            !(unref(settings)[props.code] instanceof Array)
        ) {
            // 如果找不到本地缓存配置则重新初始化
            config = props.config.columns
                .map((item, index) => {
                    return {
                        _sort: index + 1,
                        _index: index,
                        _visible: true,
                        width: '',
                        fixed: false,
                        ...getObjectProps(item),
                    };
                })
                .sort((prev, next) => prev._sort - next._sort);
            if (props.code) {
                // 保存本地缓存配置
                store.commit('local/setListSettings', {
                    ...unref(settings),
                    [props.code]: config,
                });
            }
        } else {
            config = unref(settings)[props.code];
        }
        // 配置源码修改过的标识
        let needReset = false;
        config = props.config.columns.map((item, index) => {
            //
            let old = config.find((temp) => temp._index === index);
            if (
                old &&
                Object.entries(getObjectProps(item)).every((entry) => {
                    return old[entry[0]] === entry[1];
                })
            ) {
                item = {
                    ...old,
                    ...item,
                };
            } else {
                needReset = true;
            }
            return item;
        });
        return needReset ? handleInit(true) : config;
    };
    const setting = ref(handleInit());
    console.info('[list] setting:' + props.code, unref(setting));
    // 设置窗口
    let rollback = ref([]);
    const settingVisible = ref(false);
    const handleSetting = () => {
        rollback.value = _.cloneDeep(unref(setting));
        settingVisible.value = true;
    };
    const handleCancel = () => {
        settingVisible.value = false;
    };
    const handleSave = () => {
        rollback.value = null;
        store.commit('local/setListSettings', {
            ...unref(settings),
            [props.code]: unref(setting).map((item) => getObjectProps(item)),
        });
        settingVisible.value = false;
    };
    const handleCloseSetting = () => {
        if (unref(rollback)) {
            setting.value = unref(rollback);
        }
    };
    // 导入窗口
    const refsUpload = ref(null);
    const importVisible = ref(false);
    const handleShowImport = () => {
        importVisible.value = true;
    };
    const handleCancelImport = () => {
        importVisible.value = false;
    };
    const handleSaveImport = (file) => {
        const files = unref(refsUpload).refsUpload.uploadFiles;
        if (!files.length) {
            proxy.$baseMessage('请上传要导入的文件', 'error');
        } else {
            if (file === false) {
                unref(refsUpload).refsUpload.submit();
            } else {
                handleImport(file);
                importVisible.value = false;
            }
        }
    };
    // 选中数据
    const refTable = ref(null);
    const checked = ref(null);
    const selection = ref([]);
    const handleSelect = (arr, row) => {
        setTimeout(() => {
            let res = [],
                selected = arr.indexOf(row) !== -1;
            (function deep(item) {
                res.push(item);
                (item.children || []).forEach(deep);
            })(row);
            res.forEach((item) => {
                toggleRowExpansion(item, selected);
                toggleRowSelection(item, selected);
            });
        }, 0);
        emits('select', arr, row);
    };
    // 分页查询
    const pages = computed(() => store.state.local.listPage);
    const search = ref(
        props.code
            ? store.state.local.listPage[props.code]
            : {
                  pageIndex: 1,
                  length: 10,
              }
    );
    const resetPage = (
        page = {
            pageIndex: 1,
            length: 10,
        }
    ) => {
        if (props.code) {
            store.commit('local/setListPage', {
                ...unref(pages),
                [props.code]: page,
            });
        }
        search.value = page;
    };
    if (!unref(search)) {
        resetPage();
    }
    watch(
        () => props.total,
        (value) => {
            if (!value) {
                resetPage();
            }
        }
    );
    // 事件封装
    const handleSearch = () => {
        emits('search', unref(search));
    };
    const handleReset = () => {
        emits('reset');
        search.value = { pageIndex: 1, length: 10 };
        handleSearch();
    };
    const handleTemplate = () => {
        emits('template');
    };
    const handleImport = (files) => {
        emits('import', files);
    };
    const handleExport = () => {
        emits('export');
    };
    const handleCreate = () => {
        emits('create', unref(checked));
    };
    const handleUpdate = () => {
        emits('save', unref(selection));
    };
    const handleRemove = () => {
        emits('remove', unref(selection));
    };
    const listeners = {
        onSelect: handleSelect,
        onSelectAll: (arr) => {
            setTimeout(() => {
                attrs.data.forEach((item) => handleSelect(arr, item));
            }, 0);
            emits('selectAll', arr);
        },
        onSelectionChange: (arr) => {
            selection.value = arr;
            emits('selectionChange', arr);
        },
        onCurrentChange: (row) => {
            checked.value = row;
            emits('currentChange', row);
        },
    };
    // 自动查询
    watch(
        search,
        (value) => {
            if (value && props.code) {
                resetPage(value);
            }
            handleSearch();
        },
        { deep: true, immediate: props.config.autoSearch !== false }
    );
    // 代理原生函数
    const handleProxy = (fnName, args) => {
        return unref(refTable)[fnName]?.apply(unref(refTable), args);
    };
    const clearSelection = function () {
        return handleProxy('clearSelection', arguments);
    };
    const toggleRowSelection = function () {
        return handleProxy('toggleRowSelection', arguments);
    };
    const toggleAllSelection = function () {
        return handleProxy('toggleAllSelection', arguments);
    };
    const toggleRowExpansion = function () {
        return handleProxy('toggleRowExpansion', arguments);
    };
    const setCurrentRow = function () {
        return handleProxy('setCurrentRow', arguments);
    };
    const clearSort = function () {
        return handleProxy('clearSort', arguments);
    };
    const clearFilter = function () {
        return handleProxy('clearFilter', arguments);
    };
    const doLayout = function () {
        return handleProxy('doLayout', arguments);
    };
    const sort = function () {
        return handleProxy('sort', arguments);
    };
    // 抛出
    defineExpose({
        search: handleSearch,
        selection,
        refTable,
        clearSelection,
        toggleRowSelection,
        toggleAllSelection,
        toggleRowExpansion,
        setCurrentRow,
        clearSort,
        clearFilter,
        doLayout,
        sort,
    });
    const Component = props.sortable ? SortableTable : ElTable;
    const render = () => (
        <div class="common-list">
            {slots.search ? <div class="search-box">{slots.search()}</div> : ''}
            <div class="operation-box">
                {props.operation.includes('create') ? (
                    <ElButton type="primary" onClick={() => handleCreate()}>
                        <ElIcon name="Plus" />
                        <span>新增{props.title}</span>
                    </ElButton>
                ) : (
                    ''
                )}
                {props.operation.includes('save') ? (
                    <ElButton type="primary" onClick={() => handleUpdate()}>
                        <ElIcon name="Tickets" />
                        <span>批量保存</span>
                    </ElButton>
                ) : (
                    ''
                )}
                {props.operation.includes('remove') ? (
                    <ElButton type="danger" onClick={() => handleRemove()}>
                        <ElIcon name="Delete" />
                        <span>批量移除</span>
                    </ElButton>
                ) : (
                    ''
                )}
                {props.operation.includes('search') ? (
                    <ElButton type="success" onClick={() => handleSearch()}>
                        <ElIcon name="Search" />
                        <span>查询</span>
                    </ElButton>
                ) : (
                    ''
                )}
                {props.operation.includes('search') ? (
                    <ElButton onClick={() => handleReset()}>
                        <ElIcon name="MagicStick" />
                        <span>重置</span>
                    </ElButton>
                ) : (
                    ''
                )}
                {props.operation.includes('import') ? (
                    <ElButton type="warning" onClick={() => handleShowImport()}>
                        <ElIcon name="Document" />
                        <span>模板导入</span>
                    </ElButton>
                ) : (
                    ''
                )}
                {props.operation.includes('export') ? (
                    <ElButton type="warning" onClick={() => handleExport()}>
                        <ElIcon name="Download" />
                        <span>导出</span>
                    </ElButton>
                ) : (
                    ''
                )}
                {slots.operation?.()}
                {props.operation.includes('import') ? (
                    <ElDialog
                        title={'模板导入 - ' + props.title}
                        v-model={importVisible.value}
                        width="765px"
                        v-slots={{
                            footer: () => {
                                return (
                                    <div>
                                        <ElButton type="danger" onClick={() => handleCancelImport()}>
                                            取消
                                        </ElButton>
                                        <ElButton type="primary" onClick={() => handleSaveImport(false)}>
                                            导入
                                        </ElButton>
                                    </div>
                                );
                            },
                        }}
                    >
                        <ElButton icon="Document" type="warning" onClick={() => handleTemplate()}>
                            下载模板
                        </ElButton>
                        <br />
                        <br />
                        <ElUpload
                            ref={refsUpload}
                            auto-upload={false}
                            before-upload={(e) => {
                                handleSaveImport(e);
                                return false;
                            }}
                        />
                    </ElDialog>
                ) : (
                    ''
                )}
                {props.code ? (
                    <ElButton class="setting-btn" icon="setting" type="text" onClick={() => handleSetting()}>
                        设置
                    </ElButton>
                ) : (
                    ''
                )}
                <ElDialog
                    title={'表格设置 - ' + props.code}
                    v-model={settingVisible.value}
                    width="765px"
                    onClose={() => handleCloseSetting()}
                    v-slots={{
                        footer: () => {
                            return (
                                <div>
                                    <ElButton type="danger" onClick={() => handleCancel()}>
                                        取消
                                    </ElButton>
                                    <ElButton type="primary" onClick={() => handleSave()}>
                                        保存
                                    </ElButton>
                                </div>
                            );
                        },
                    }}
                >
                    <p>修改后如果显示异常，刷新页面即可恢复正常</p>
                    <br />
                    <ElTable border stripe highlightCurrentRow data={setting.value} height="50vh">
                        <ElTableColumn
                            headerAlign="center"
                            align="center"
                            label="排序"
                            prop="_sort"
                            width="72px"
                            v-slots={{
                                default: ({ row }) => (
                                    <ElInputNumber controls={false} v-model={row._sort} style="width:48px;" />
                                ),
                            }}
                        />
                        <ElTableColumn
                            headerAlign="center"
                            align="center"
                            label="列名"
                            prop="label"
                            width="200px"
                            v-slots={{
                                default: ({ row }) =>
                                    row.type === 'index' ? (
                                        '序号'
                                    ) : row.type === 'selection' ? (
                                        '选择框'
                                    ) : (
                                        <ElInput
                                            v-model={row.label}
                                            placeholder={props.config.columns[row._index].label}
                                        />
                                    ),
                            }}
                        />
                        <ElTableColumn
                            headerAlign="center"
                            align="center"
                            label="宽度"
                            prop="width"
                            width="140px"
                            v-slots={{
                                default: ({ row }) => <ElInput v-model={row.width} style="width:104px;" />,
                            }}
                        />
                        <ElTableColumn
                            headerAlign="center"
                            align="center"
                            label="固定"
                            prop="fixed"
                            width="240px"
                            v-slots={{
                                default: ({ row }) => (
                                    <ElRadioGroup
                                        v-model={row.fixed}
                                        button
                                        opts={[
                                            { label: '左侧', value: 'left' },
                                            { label: '取消', value: false },
                                            { label: '右侧', value: 'right' },
                                        ]}
                                    ></ElRadioGroup>
                                ),
                            }}
                        />
                        <ElTableColumn
                            headerAlign="center"
                            align="center"
                            label="显示"
                            prop="_visible"
                            width="72px"
                            v-slots={{
                                default: ({ row }) => <ElSwitch v-model={row._visible} />,
                            }}
                        />
                    </ElTable>
                </ElDialog>
            </div>
            <div class="content-box">
                <Component
                    ref={refTable}
                    border
                    stripe
                    highlightCurrentRow={false}
                    rowKey="id"
                    height="100%"
                    {...listeners}
                    {...attrs}
                    {...props.config.table}
                    v-slots={{
                        empty: () => (
                            <div class="empty-content">
                                <ElEmpty description="没有查询到符合条件的数据" />
                            </div>
                        ),
                        ...props.config.table?.slots,
                    }}
                >
                    {unref(setting).map((col) =>
                        col._visible ? (
                            <ElTableColumn
                                showOverflowTooltip={!col.slots?.default}
                                headerAlign="center"
                                align="center"
                                selectable={(row) => !row.baseData}
                                v-slots={{ ...col.slots }}
                                {...col}
                            ></ElTableColumn>
                        ) : (
                            ''
                        )
                    )}
                </Component>
            </div>
            <div class="pagination-box">
                {props.config.page === false ? (
                    ''
                ) : (
                    <ElPagination
                        background
                        hide-on-single-page={false}
                        page-sizes={props.config.page?.sizes || [10, 15, 20, 30, 50, 100]}
                        layout={props.config.page?.layout || 'total, sizes, prev, pager, next, jumper'}
                        total={props.total}
                        v-model:current-page={unref(search).pageIndex}
                        v-model:page-size={unref(search).length}
                    />
                )}
            </div>
        </div>
    );
</script>
<style lang="less" scoped>
    .common-list {
        width: 100%;
        height: 100%;
        flex: 1;
        display: flex;
        flex-direction: column;
        overflow: hidden;
        :deep(.search-box) {
            border-radius: 5px;
        }
        :deep(.operation-box) {
            border-radius: 5px;
            padding-bottom: 10px;
            display: flex;
            align-items: center;
            .setting-btn {
                margin-left: auto;
            }
        }
        :deep(.content-box) {
            flex: 1;
            overflow: hidden;
            margin-bottom: 10px;
            display: flex;
            flex-direction: column;
            .el-table {
                max-height: 100%;
                flex: 1;
            }
        }
        :deep(.pagination-box) {
            display: flex;
            justify-content: center;
            .el-pagination {
                margin: 0;
            }
        }
    }
</style>
