<template>
    <div>
        <el-input placeholder="请选择" :value="opts.searchPickText" :disabled="true">
            <el-button slot="append" icon="el-icon-search" v-if="!opts.searchPickDisabled"
                       @click="doShowDialogEvent"></el-button>
        </el-input>
        <el-dialog :title="opts.searchPickTitle" :visible.sync="dialogVisible" :width="opts.searchPickWidth"
                   :append-to-body="true" @opened="dialogOpenedEvent">
            <ap-container>
                <ap-aside margin="0000" v-bind:style="{width: treeOpts.searchTreeWidth}">
                    <div>
                        <el-input :placeholder="opts.searchPickTreePlaceholder" v-model="treeFilterText"></el-input>
                    </div>
                    <div v-loading="treeLoadingFlag"
                         v-bind:style="{height: opts.searchPickHeight}"
                         class="org-search-tree-ctn">
                        <el-tree
                            class="filter-tree"
                            ref="selectTreeRef"
                            node-key="fdId"
                            :data="treeData"
                            :props="{children: 'children', label: treeOpts.searchTreeKey.labelKey}"
                            :default-expand-all="treeOpts.searchTreeExpandAll"
                            :default-expanded-keys="treeOpts.searchTreeDefaultExpandedKeys"
                            :default-checked-keys="treeOpts.searchTreeDefaultCheckedKeys"
                            :show-checkbox="treeOpts.searchTreeSelectMultiple"
                            :check-on-click-node="true"
                            :highlight-current="true"
                            :expand-on-click-node="false"
                            :check-strictly="treeOpts.searchTreeCheckStrictly"
                            :filter-node-method="treeFilterNode"
                            @check="treeCheckEvent">
                        </el-tree>
                    </div>
                </ap-aside>
                <ap-main margin="0001" v-if="gridVisible">
                    <div class="flex-justify-between">
                        <div style="width: 200px">
                            <el-input :placeholder="opts.searchPickTablePlaceholder" v-model="gridFilterText"  @keyup.enter.native="freshTable"></el-input>
                        </div>
                        <div class="flex-1" style="margin-left: 10px;">
                            已选值：
                            <el-tag :key="index" v-for="(item,index)  in selectItems" closable
                                    @close="handleCancleSelect(item)" style="margin-right: 5px;">
                                {{ item[opts.searchPickTableLabelKey] }}
                            </el-tag>
                        </div>
                    </div>
                    <div v-bind:style="{height: opts.searchPickHeight}">
                        <ap-table ref="tableRef" :options.sync="tableOpts"></ap-table>
                    </div>
                </ap-main>
            </ap-container>

            <span slot="footer">
                <el-button @click="dialogVisible = false">取 消</el-button>
                <el-button type="warning" @click="selectClearEvent">清 空</el-button>
                <el-button type="primary" @click="selectConfirmEvent">确 定</el-button>
            </span>
        </el-dialog>
    </div>
</template>

<script>
import {deepClone, handleDefaultParams} from 'ap-util/util/ObjectUtil'
import {convertToTreeData} from 'ap-util/util/DataUtil'

export default {
    name: "ApSearchPick",
    props: {
        // 必要参数
        options: {
            type: Object,
            required: true
        },
        afterConfirm: {
            type: Function,
            required: false
        },
        param: {
            type: Object,
            required: false
        }
    },
    data() {
        return {
            // 表格 选择时需要记录上一次选择 数结构 ID
            selectTreeIdArray: [],
            // 参数
            opts: {},
            // 弹出层相关信息
            dialogVisible: false,
            // 左侧 树 相关信息
            treeLoadingFlag: false,
            treeFilterText: '',
            treeOpts: {},
            treeData: [],
            // 右侧 表格 相关信息
            gridVisible: true,
            gridFilterText: '',
            tableOpts: {},
            oldTableParams: null,
            selectItems: [],
            isFreshTable: false
        }
    },
    watch: {
        opts: {
            handler(newValue, oldValue) {
                // 深度监听，opts，对应修改父组件options参数
                this.$emit('update:options', this.opts);
            },
            deep: true
        },
        treeFilterText(val) {
            this.$refs.selectTreeRef.filter(val);
        },
    },
    created() {
        // 交互参数
        this.opts = handleDefaultParams(this.options, {
            searchPickText: "",
            searchPickValue: "",
            searchPickTextUrl: "",
            // 主要内容高度（不含 dialog 头与脚区域）
            searchPickTitle: "",
            searchPickHeight: "400px",
            searchPickWidth: "70%",
            searchPickDisabled: false,
            searchPickTableParamKey: {selectedKey: "selectedIds", filterKey: "filterText"},
            searchPickTableLabelKey: "fdName",
            searchPickTreePlaceholder: "关键字过滤",
            searchPickTablePlaceholder: "关键字过滤，回车搜索",
            searchPickConfirm() {
                return true
            },
            afterSearchPickConfirm() {},
            searchPickClear() {
                return true
            },
            afterSearchPickClear() {},
        });
        if (this.options.searchPickTableOptions == null || this.options.searchPickTreeOptions == undefined) {
            throw new Error("参数错误左侧树或表格参数为空");
        }
        // 默认 tree 参数
        this.treeOpts = handleDefaultParams(this.options.searchPickTreeOptions, {
            // 数 相关参数
            searchTreeUrl: "",
            searchTreeMethod: 'post',
            searchTreeParams: {},
            searchTreeWidth: "300px",
            searchTreeKey: {idKey: "fdId", parentKey: "fdParentId", labelKey: "fdName"},
            searchTreeExpandAll: true,
            searchTreeDefaultCheckedKeys: [],
            searchTreeDefaultExpandedKeys: [],
            searchTreeCheckStrictly: true,
            searchTreeSelectMultiple: false
        });
        // 组合成 Table Option参数
        let tableParams = this.options.searchPickTableOptions.params;
        if (typeof tableParams === 'function') {
            this.oldTableParams = tableParams;
        } else {
            this.oldTableParams = tableParams != null ? deepClone(tableParams) : {};
        }
        this.tableOpts = handleDefaultParams(this.options.searchPickTableOptions, {
            title: "数据列表",
            columns: null,
            editPk: "fdId", //默认fdId
            dataUrl: "",
            method: "post",
            initData: false,
            pagination: {
                pageSizes: [100, 200, 300],
                pageSize: 200
            },
            multiSelect: false,
            reserveSelection: false,
            selectionChangeEvent: (selection) => {
                this.selectionChangeEvent(selection);
            },
            afterAll: () => {
                this.afterAll();
            },
        });
        // 存在默认选中节点，则选中节点等于默认选中节点，同时表格默认刷新数据
        if (this.treeOpts.searchTreeDefaultCheckedKeys.length > 0) {
            this.selectTreeIdArray = this.treeOpts.searchTreeDefaultCheckedKeys;
            this.tableOpts.initData = true;
        }
        this.tableOpts.params = this.getTableParams;

        this.initSearchPickText();
    },
    methods: {
        // 对外接口：初始化显示值
        initText(value, text) {
            this.opts.searchPickValue = value;

            if (value == null || value == "") {
                this.opts.searchPickText = "";
                return;
            }
            // 如果有text，则说明无需向后台请求
            if (text !== undefined && text !== null) {
                this.opts.searchPickText = text;
            } else {
                this.initSearchPickText();
            }
        },
        // 初始化文本：id -> 名称
        initSearchPickText() {
            let initTextUrl = this.opts.searchPickTextUrl
            if (initTextUrl == null || initTextUrl == "") {
                return;
            }
            this.$request({
                url: initTextUrl,
                method: "post",
                data: {
                    ids: this.opts.searchPickValue
                }
            }).then(response => {
                let lableKey = this.opts.searchPickTableLabelKey;
                let rowKey = this.tableOpts.rowKey;

                let res = response.data;
                if (res == null || res.length < 1) {
                    return
                }
                let searchPickTextArr = [];
                for (let i = 0; i < res.length; i++) {
                    searchPickTextArr.push(res[i][lableKey]);
                }
                this.opts.searchPickText = searchPickTextArr.join(",");

                this.selectItems = res;
            })
        },
        getTableParams() {
            let params = {};
            if (typeof this.oldTableParams === 'function') {
                params = this.oldTableParams();
            } else {
                params = this.oldTableParams || {};
            }
            if (this.selectTreeIdArray != null) {
                params[this.opts.searchPickTableParamKey.selectedKey] = this.selectTreeIdArray.join(",");
            }
            params[this.opts.searchPickTableParamKey.filterKey] = this.gridFilterText;
            return params;
        },
        doShowDialogEvent() {
            if (this.opts.searchPickDisabled) {
                // 禁用
                return;
            }
            this.dialogVisible = true;
            // 树结构无数据的时候，进行加载树
            if (this.treeData.length <= 0) {
                this.loadTreeData();
            }
        },
        // 弹出层加载完成事件，期初选择动作
        dialogOpenedEvent() {

        },
        // 树：加载数据
        loadTreeData() {
            if (this.treeOpts.searchTreeUrl == null || this.treeOpts.searchTreeUrl === "") {
                return;
            }
            this.treeLoadingFlag = true;
            this.$request({
                url: this.treeOpts.searchTreeUrl,
                method: this.treeOpts.searchTreeMethod,
                data: this.treeOpts.searchTreeParams
            }).then(response => {
                this.treeData = convertToTreeData(response.data, {
                    idKey: this.treeOpts.searchTreeKey.idKey,
                    parentKey: this.treeOpts.searchTreeKey.parentKey,
                    childrenKey: "children",
                });
            }).finally(() => {
                this.treeLoadingFlag = false;
            })
        },
        // 树：过滤节点
        treeFilterNode(value, data) {
            if (!value) return true;
            return data[this.treeOpts.searchTreeKey.labelKey].indexOf(value) !== -1;
        },
        treeClearCheck() {
            // 清除已有选择 树节点
            let checkKeys = this.$refs.selectTreeRef.getCheckedKeys(false);
            for (let i = 0; i < checkKeys.length; i++) {
                this.$refs.selectTreeRef.setChecked(checkKeys[i], false, false)
            }
        },
        treeClearCurrent() {
            // 清除选中 树节点
            this.$refs.selectTreeRef.setCurrentKey(null);
        },
        // 树：勾选事件
        treeCheckEvent(data, node, comp) {
            if (!this.treeOpts.searchTreeSelectMultiple) {
                // 单选
                // 去除其他 Check
                this.treeClearCheck();
                // 选中当前节点
                this.$refs.selectTreeRef.setChecked(data, true, false);
                this.$refs.selectTreeRef.setCurrentKey(data[this.treeOpts.searchTreeKey.idKey]);
            }
            // 获取当前已选中树节点
            let nodeArr = [];
            if (this.treeOpts.searchTreeSelectMultiple) {
                // 多选，使用 checkNode
                nodeArr = this.$refs.selectTreeRef.getCheckedNodes(false, false);
            } else {
                // 单选，使用 currNode
                let currNode = this.$refs.selectTreeRef.getCurrentNode();
                if (currNode !== null) {
                    nodeArr = [currNode];
                }
            }
            let nodeIdArr = [];
            for (let i = 0; i < nodeArr.length; i++) {
                nodeIdArr.push(nodeArr[i][this.treeOpts.searchTreeKey.idKey]);
            }
            // 记录左侧树选项
            this.selectTreeIdArray = nodeIdArr;
            // 更新 grid 参数
            this.freshTable();
        },
        // 回调：清单
        selectClearEvent() {
            // 默认对象
            let isOk = this.opts.searchPickClear();
            if (isOk) {
                this.dialogVisible = false;
                this.selectItems = [];
                this.treeClearCheck();
                this.tableClearCheck();
                this.opts.afterSearchPickClear();
            }
        },
        // 回调：确认
        selectConfirmEvent() {
            let selectVal = null;
            let selectRows = this.selectItems == null ? [] : this.selectItems;
            if (this.selectItems.length > 0) {
                if (this.tableOpts.multiSelect) {
                    selectVal = selectRows;
                } else {
                    selectVal = selectRows[0];
                }
            }

            let isOk = this.opts.searchPickConfirm(selectVal);
            if (isOk) {
                this.dialogVisible = false;
                this.opts.afterSearchPickConfirm(selectVal)
                if (this.afterConfirm) {
                    this.afterConfirm(this.param, selectVal);
                }
            }
        },
        handleCancleSelect(row) {
            let rowKey = this.tableOpts.rowKey;
            this.$refs.tableRef.toggleRowSelectionByRowKey(row[rowKey], false);
            this.$nextTick(() => {
                for (let i = 0; i < this.selectItems.length; i++) {
                    if (this.selectItems[i][rowKey] == row[rowKey]) {
                        this.selectItems.splice(i, 1);
                        return;
                    }
                }
            });
        },
        selectionChangeEvent(selection) {
            if (this.isFreshTable) {
                return;
            }

            let rowKey = this.tableOpts.rowKey;
            let tableData = this.$refs.tableRef.getDataWithArray();
            let tags = JSON.parse(JSON.stringify(this.selectItems));
            // 单选，重新设定
            if (!this.tableOpts.multiSelect) {
                tags = [];
            }
            // 未添加
            for (let i = 0; i < selection.length; i++) {
                let hasAdd = false;
                for (let j = 0; j < tags.length; j++) {
                    if (tags[j][rowKey] == selection[i][rowKey]) {
                        hasAdd = true;
                        break;
                    }
                }
                if (!hasAdd) {
                    tags.push(selection[i]);
                }
            }
            // 表格未选中的行
            let unSelectedData = [];
            for (let i = 0; i < tableData.length; i++) {
                let selected = false;
                for (let j = 0; j < selection.length; j++) {
                    if (selection[j][rowKey] == tableData[i][rowKey]) {
                        selected = true;
                        break;
                    }
                }
                if (!selected) {
                    unSelectedData.push(tableData[i]);
                }
            }
            // 取消选择的行
            let newTags = [];
            for (let j = 0; j < tags.length; j++) {
                let unSelected = false;
                for (let i = 0; i < unSelectedData.length; i++) {
                    if (tags[j][rowKey] == unSelectedData[i][rowKey]) {
                        unSelected = true;
                        break;
                    }
                }
                if (!unSelected) {
                    newTags.push(tags[j]);
                }
            }
            // 判断是否有变化：动画效果
            let newTagsSize = newTags.length;
            let selectItemsSize = this.selectItems.length;
            if (newTagsSize != selectItemsSize) {
                this.selectItems = newTags;
                return;
            }
            for (let i = 0; i < newTagsSize; i++) {
                if (newTags[i][rowKey] != this.selectItems[i][rowKey]) {
                    this.selectItems = newTags;
                    return;
                }
            }

        },
        afterAll() {
            // 触发选中状态
            let rowKey = this.tableOpts.rowKey;
            let selectItems = this.selectItems;
            for (let i = 0; i < selectItems.length; i++) {
                this.$refs.tableRef.toggleRowSelectionByRowKey(selectItems[i][rowKey], true);
            }
            if (this.isFreshTable) {
                this.isFreshTable = false;
            }
        },
        tableClearCheck() {
            this.$refs.tableRef.clearSelected();
        },
        freshTable(){
            this.$refs.tableRef.refresh();
            this.isFreshTable = true;
        }
    }
}
</script>

<style scoped>
.org-search-tree-ctn {
    overflow: auto;
}
</style>
