<template>
    <div>
        <el-input placeholder="请选择" :value="opts.searchTreeText" :disabled="true">
            <el-button slot="append" icon="el-icon-search" v-if="!opts.searchTreeDisabled"
                       @click="dialogVisible = true"></el-button>
        </el-input>
        <el-dialog :title="opts.searchTreeTitle"
                   :visible.sync="dialogVisible"
                   :width="opts.searchTreeWidth"
                   :append-to-body="true"
                   @open="openEvent">
            <div>
                <el-input placeholder="关键字过滤" v-model="filterText"></el-input>
            </div>
            <div v-loading="loadingTreeFlag" v-bind:style="{height: opts.searchTreeHeight}"
                 class="ap-search-tree-ctn">
                <el-tree
                    class="filter-tree"
                    ref="searchTreeRef"
                    node-key="fdId"
                    :data="treeData"
                    :default-checked-keys="handleSearchTreeValue(opts.searchTreeValue)"
                    :props="{children: 'children', label: opts.searchTreeKey.labelKey}"
                    :default-expand-all="opts.searchTreeExpandAll"
                    :check-on-click-node="true"
                    :highlight-current="true"
                    :expand-on-click-node="false"
                    :show-checkbox="opts.searchTreeSelectMultiple"
                    :check-strictly="opts.searchTreeCheckStrictly"
                    :filter-node-method="opts.filterNodeMethod"
                    @check="checkEvent">
                    <template slot-scope="{ node, data }">
                        <template v-if="$scopedSlots['tree'] != undefined">
                            <slot name="tree" :node="node" :data="data"></slot>
                        </template>
                        <template v-else>
                            <span>{{ data.fdName }}</span>
                        </template>
                    </template>
                </el-tree>
            </div>

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

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

export default {
    name: "ApSearchTree",
    props: {
        options: {
            type: Object,
            required: true
        },
    },
    data() {
        return {
            opts: {},
            dialogVisible: false,
            loadingTreeFlag: false,
            filterText: '',
            responseData: [],
            treeData: [],
            hasLoadTreeData: false
        }
    },
    watch: {
        opts: {
            handler(value) {
                // 深度监听，opts有修改，对应修改父组件options参数
                this.$emit('update:options', this.opts);
            },
            deep: true
        },
        filterText(val) {
            this.$refs.searchTreeRef.filter(val);
        }
    },
    created() {
        // 初始化组件前修改默认参数
        this.opts = handleDefaultParams(this.options, {
            searchTreeValue: '',
            searchTreeInitText: false,
            searchTreeTitle: '查找',
            searchTreeWidth: '400px',
            searchTreeHeight: '400px',
            searchTreeKey: {idKey: "fdId", parentKey: "fdParentId", labelKey: "fdName"},
            searchTreeUrl: "",
            searchTreeParams: {},
            searchTreeMethod: 'post',
            searchTreeCheckStrictly: true,
            searchTreeSelectMultiple: false,
            searchTreeExpandAll: true,
            searchTreeDisabled: false,
            searchTreeConfirm() {
                return true
            },
            searchTreeClear() {
                return true
            },
            filterNodeMethod: (value, data) => {
                // 树节点过滤
                let label = this.opts.searchTreeKey.labelKey;
                if (!value) return true;
                return data[label] != null && data[label].indexOf(value) !== -1;
            },
        });
    },
    mounted: function () {
        if (!this.opts.searchTreeInitText) {
            return;
        }
        // 初始化text
        this.$nextTick(function () {
            this.loadTreeData();
        })

    },
    methods: {
        // 初始化 数据
        initSearchTreeData(value, text) {
            if (typeof value === "string") {
                this.opts.searchTreeValue = value;
                // 如果是字符串，说明传入的是 Id
                if (text !== undefined && text !== null && text !== "") {
                    // 如果有 text，则说明无需请求
                    this.opts.searchTreeTitle = text;
                } else {
                    // 无 text，说明需要从服务器数组中获取
                    this.initSearchTreeText(this.responseData, true);
                }
            }
        },
        openEvent() {
            if (this.opts.searchTreeDisabled) {
                // 禁用
                return;
            }
            // 数据只加载一次
            if (!this.hasLoadTreeData) {
                this.loadTreeData();
            }
        },
        // 选中值：数组形式
        handleSearchTreeValue(value) {
            if (typeof value == "string") {
                return value.split(",");
            }
            return value;
        },
        initSearchTreeText(responseData, isConfim) {
            // 根据 Key 获取 label 需要 initText 属性为 true，否则不进行变更
            if (!this.opts.searchTreeInitText) {
                return;
            }
            let treeObj = [];
            let treeText = [];
            let treeValue = this.handleSearchTreeValue(this.opts.searchTreeValue);
            let labelKey = this.opts.searchTreeKey.labelKey;
            let idKey = this.opts.searchTreeKey.idKey;
            for (let i = 0; i < responseData.length; i++) {
                if (treeValue.includes(responseData[i][idKey])) {
                    treeObj.push(responseData[i]);
                    treeText.push(responseData[i][labelKey]);
                }
            }
            this.opts.searchTreeText = treeText.join(",");
            if (isConfim != undefined && isConfim) {
                // 触发选中动作
                this.opts.searchTreeConfirm(treeObj);
            }
        },
        // 获取参数
        getTreeParams() {
            let resParams = {};
            let params = this.opts.searchTreeParams;
            if (typeof params === 'function') {
                resParams = params();
            } else {
                resParams = params || {};
            }
            return resParams;
        },
        // 树：加载数据
        loadTreeData() {
            if (this.opts.searchTreeUrl == null) {
                return;
            }
            this.loadingTreeFlag = true;

            this.$request({
                url: this.opts.searchTreeUrl,
                method: this.opts.searchTreeMethod,
                data: this.getTreeParams()
            }).then(response => {
                this.responseData = response.data;
                this.initSearchTreeText(this.responseData);
                this.treeData = convertToTreeData(response.data, {
                    idKey: this.opts.searchTreeKey.idKey,
                    parentKey: this.opts.searchTreeKey.parentKey,
                    childrenKey: "children",
                });
            }).finally(() => {
                this.loadingTreeFlag = false;
                this.hasLoadTreeData = true;
            })
        },
        // 树：勾选事件
        checkEvent(data, node, comp) {
            if (this.opts.searchTreeSelectMultiple) {
                return;
            }
            // 单选处理
            let checkKeys = this.$refs.searchTreeRef.getCheckedKeys(false);
            for (let i = 0; i < checkKeys.length; i++) {
                this.$refs.searchTreeRef.setChecked(checkKeys[i], false, false)
            }
            this.$refs.searchTreeRef.setChecked(data, true, false)
        },
        // 清空树已选选择
        clearTreeChecked() {
            let checkedKeys = this.$refs.searchTreeRef.getCheckedKeys();
            if (checkedKeys != null && checkedKeys.length > 0) {
                for (let i = 0; i < checkedKeys.length; i++) {
                    this.$refs.searchTreeRef.setChecked(checkedKeys[i], false, false);
                }
            }
        },
        // 回调：清空
        searchTreeClear() {
            let isOk = this.opts.searchTreeClear();
            if (isOk) {
                // 手动触发修改事件
                // this.changeEvent(this.rowData)
                this.dialogVisible = false;
            }
            this.clearTreeChecked();
        },
        // 回调：确认
        searchTreeConfirm() {
            let checkedNodes = [];
            if (this.opts.searchTreeSelectMultiple) {
                checkedNodes = this.$refs.searchTreeRef.getCheckedNodes(false, false)
            } else {
                checkedNodes.push(this.$refs.searchTreeRef.getCurrentNode());
            }
            let isOk = this.opts.searchTreeConfirm(checkedNodes);
            if (isOk) {
                // 手动触发修改事件
                // this.changeEvent(this.rowData)
                this.dialogVisible = false;
            }
            this.clearTreeChecked();
        },
        getFullNameItem(id, nameArr, dataKey) {
            if (id == null || id == "") {
                return nameArr;
            }
            let idKey = this.opts.searchTreeKey.idKey;
            let parentKey = this.opts.searchTreeKey.parentKey;

            for (let i = 0; i < this.responseData.length; i++) {
                let item = this.responseData[i];
                if (item[idKey] == id) {
                    nameArr.unshift(item[dataKey]);
                    return this.getFullNameItem(item[parentKey], nameArr, dataKey);
                }
            }
            return nameArr;
        },
        getFullName(dataKey) {
            let idKey = this.opts.searchTreeKey.idKey;
            let parentKey = this.opts.searchTreeKey.parentKey;
            let checkedNodes = this.$refs.searchTreeRef.getCheckedNodes(false, false)
            let resArr = [];
            for (let i = 0; i < checkedNodes.length; i++) {
                let nameArr = [];
                nameArr.push(checkedNodes[i][dataKey])
                let fullNameArr = this.getFullNameItem(checkedNodes[i][parentKey], nameArr , dataKey);
                resArr.push(fullNameArr.join("/"));
            }
            return resArr.join(",")
        },
        getTreeRef() {
            return this.$refs.searchTreeRef;
        }
    }
}
</script>

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