<template>
<u-mask :show="visible" :class="['u-theme-' + cTheme]" :mask-click-able="false">
    <view class='cascader' :class="[safeAreaInsetBottom ? 'safe-area-inset-bottom' : '']">
        <!-- 头部 -->
        <view class='cascader-header'>
            <view class='cascader-header-label'>已选择：</view>
            <view class='cascader-header-selected overflow-hidden'>{{curNodeLabel}}</view>
            <image class='cascader-header-search image'  @tap='jumpToSearch' src='./image/search.svg' />
			<slot name="header-action" />
        </view>
        <!-- 选择项展示区域 -->
        <scroll-view scroll-x class='cascader-selected-scroll'>
            <view class='cascader-selected-view'>
                <view class='cascader-selected-view-item' v-for='item, index in selectedList' :key='item[useProps.key]' @tap='cascaderSelectedClick(item, index)'>
                    <image src='./image/arrow-right.svg' v-if='index !== 0' class='node-gt' />
                    <text :class='["node", index === selectedList.length - 1 ? "node-current" : ""]'>{{item[useProps.label]}}</text>
                </view>
            </view>
        </scroll-view>
        <!-- 待选列表 -->
        <scroll-view class='cascader-list' scroll-y>
            <template v-for='item in listData'>
                <view v-if='item[selectedKey]' :key='item[useProps.key]' class='cascader-list-item activate'>
                    <view class='cascader-list-item-icon'>
                        <image class='image' src='./image/success.svg' />
                    </view>
                    <text class='cascader-list-item-label overflow-hidden'>{{item[useProps.label]}}</text>
                </view>
                <view v-else :key='item[useProps.key]' class='cascader-list-item' @tap='cascaderListClick(item)' :cancelable='false'>
                    <!-- 无图片，仅占位 -->
                    <view class='cascader-list-item-icon'></view>
                    <text class='cascader-list-item-label overflow-hidden'>{{item[useProps.label]}}</text>
                </view>
            </template>
        </scroll-view>
        <view class='cascader-footer'>
            <!-- <button class='cascader-footer-botton' @tap='cancel'>取消</button> -->
            <!-- <button class='cascader-footer-botton' type='primary' :disabled="canSubmit" @tap='submit'>确定</button> -->
            <u-button size="default" shape="circle" @tap='cancel'>{{cancelText}}</u-button>
            <u-button size="default" type="primary" shape="circle" :disabled="canSubmit" @tap='submit'>{{confirmText}}</u-button>
        </view>
        <!-- 检索控件 -->
        <u-search-mask :show.sync='searchVisible' :data.sync='searchedData' :theme='cTheme' @search='search' @selected='selected' @updateData='updateData' @cancel='cancelSearch'>
            <template v-slot="scope">
                <view class='result-content'>
                    <view class='result-item' v-for='item, index in scope.row.parentList' :key='index'>
                        <image src='./image/arrow-right.svg' v-if='index !== 0' class='node-gt' />
                        <text :class='["node"]'>{{item[useProps.label]}}</text>
                    </view>
                    <view >
                        <image src='./image/arrow-right.svg' v-if='scope.row.parentList.length' class='node-gt' />
                        <text class="node node-current">{{scope.row[useProps.label]}}</text>
                    </view>
                </view>
            </template>
        </u-search-mask>
    </view>
</u-mask>
</template>

<script>
/* 
    该组件会将树结构扁平化。
    由：
    {
        id：'1',
        name: '测试',
        children: [
            {
                id: '11',
                name: '测试11'
            }
        ]
    }
    转为：
    [
        { id: '1', name: '测试', _hasChildren: true, _deep: 1, _parentList: [] },
        { id: '11', name: '测试11', _hasChildren: false, _deep: 2, _parentList: ['1'] }
    ]
    除树节点原有属性外，会挂载一些数据检索需要用到的属性
    _hasChildren： 是否有子节点，判定条件，子节点属性值为数组，且长度大于0
    _deep: 在原树上的层级深度
    _ancestorsList: 节点所有的祖先节点key
    _parent: 父节点key
*/
export default {
  emits: ["submit", "update:modelValue", "input", "update:visible", "cancel"],
    props: {
        data: { // 源数据
            type: Array,
            default() {
                return []
            }
        },
        visible: { // 组件是否可见
            type: Boolean,
            default: true
        },
        value: { // 当前选中的节点id
            type: [String, Number],
            default: ''
        },
		modelValue: { // 当前选中的节点id
			type: [String, Number],
			default: ""
		},
        mustLeaf: { // 选中的节点必须是叶子节点
            type: Boolean,
            default: false
        },
        props: { // 节点属性定义
            type: Object,
            default () {
                return {
                    key: 'id', // 节点唯一标识
                    label: 'name', // 节点显示名称
                    children: 'children' // 子节点
                }
            }
        },
        // 关怀模式: normal, care
		theme: {
			type: String,
			default: ''
		},
        safeAreaInsetBottom: {
            type: Boolean,
            default: true
        },
        //确认按钮
        confirmText: {
            type: String,
            default: '确定' //文字
        },
        //取消按钮
        cancelText: {
            type: String,
            default: '取消' //文字
        },
    },
    data () {
        return {
            selectedList: [], // 选中的列表
            selectedKey: '_selected', // 节点选中标识
            defaultDepp: 1, // 默认层级
            searchVisible: false, // 检索页显示
            searchedData: [], // 检索结果
        }
    },
    computed: {
        cTheme() {
			return this.theme || (uni.$u || {}).theme;
		},
        // 通过深度遍历，将树结构转为扁平结构
        flatData () {
            return this.treeDataToFlatData(this.data)
        },
        // 当前选中的节点名称
        curNodeLabel () {
            if (this.selectedList.length === 0) { // 暂无选中，默认第一级
                return ''
            } else {
                return this.selectedList[this.selectedList.length - 1][this.useProps.label]
            }
        },
        // 是否可提交
        canSubmit () {
            if (!this.mustLeaf) return false
            if (this.selectedList.length === 0) { // 暂无选中，默认第一级
                return true
            } else {
                return this.selectedList[this.selectedList.length - 1]._hasChildren
            }
        },
        // 候选节点列表
        listData () {
            let list = []
            if (this.selectedList.length === 0) { // 暂无选中，默认选中根节点，所以候选列表为二级节点
                this.flatData.forEach(item => {
                    if (item._deep === 2) {
                        list.push({ ...item })
                    }
                })
            } else {
                // 找到选中的最后一个节点
                const lastNode = JSON.parse(JSON.stringify(this.selectedList[this.selectedList.length - 1]))
                lastNode[this.selectedKey] = true
                list.push(lastNode)
                const lastNodeKey = lastNode[this.useProps.key]
                this.flatData.forEach(item => {
                    if (item._parent === lastNodeKey) {
                        list.push({ ...item })
                    }
                })
            }
            return list
        },
        useProps () {
            return {
                key: 'id', // 节点唯一标识
                label: 'name', // 节点显示名称
                children: 'children', // 子节点
                ...this.props
            }
        }
    },
    watch: {
        visible () {
            this.selectedList = this.getListByKey()
        }
    },
    created () {
        this.selectedList = this.getListByKey()
    },
    methods: {
        getValue() {
			// #ifndef VUE3
			return this.value;
			// #endif

			// #ifdef VUE3
			return this.modelValue;
			// #endif
		},
        /* 
            根据key值，拿到所选节点的父级列表
         */
        getListByKey (selectedNodeKey = this.getValue()) {
            let list = []
            // 当可见时
            if (this.visible === true) {
                if (selectedNodeKey) {
                    // value根据找到当前选中的及其所有祖先节点
                    let ancestorsList = []
                    let currentNode = {}
                    for (let i = 0; i < this.flatData.length; i++) {
                        if (this.flatData[i][this.useProps.key] === selectedNodeKey) {
                            ancestorsList = this.flatData[i]['_ancestorsList']
                            currentNode = this.flatData[i]
                            break
                        }
                    }
                    // 根据祖先节点id，找到祖先节点node数据
                    const ancestorsNodeList = []
                    for (let i = 0; i < this.flatData.length; i++) {
                        const index = ancestorsList.indexOf(this.flatData[i][this.useProps.key])
                        if (index >= 0) {
                            ancestorsNodeList[index] = this.flatData[i]
                        }
                    }
                    list = [...ancestorsNodeList, currentNode]
                } else {
                    // value为空，则默认选中根节点
                    for (let i = 0; i < this.flatData.length; i++) {
                        if (this.flatData[i]._deep === 1) {
                            list = [{...this.flatData[i]}]
                            break
                        }
                    }
                }
            } else {
                // 关闭时，清空已选
                list = []
            }
            return list
        },
        /* 
            将树结构数据，转为扁平结构
         */
        treeDataToFlatData (data, parentId = null, ancestorsList = [], deep = this.defaultDepp, parentList=[]) {
            let fData = []
            data.forEach(item => {
                const hasChildren = item[this.useProps.children] && Array.isArray(item[this.useProps.children]) && item[this.useProps.children].length > 0 || false
                const obj = {
                    ...item,
                    _deep: deep,
                    _hasChildren: hasChildren,
                    _parent: parentId,
                    _ancestorsList: ancestorsList,
                    parentList: parentList
                }
                // 移除原有的子节点属性
                delete obj[this.useProps.children]
                fData.push(obj)
                if (hasChildren) {
                    const cAncestorsList = [...ancestorsList, item[this.useProps.key]]
                    fData = fData.concat(this.treeDataToFlatData(item[this.useProps.children], item[this.useProps.key], cAncestorsList, deep + 1, [...parentList, obj]))
                }
            })
            return fData
        },
        /* 
            已选项点击
         */
        cascaderSelectedClick (item, index) {
            // 最后一个节点点击无效
            if (index < this.selectedList.length - 1) {
                // 将该索引后的数据清除
                this.selectedList.splice(index + 1)
            }
        },
        /* 
            候选项点击
         */
        cascaderListClick (item) {
            this.selectedList.push({ ...item })
        },
        /* 
            跳转到检索页
         */
        jumpToSearch () {
            this.searchVisible = true
            this.search()
        },
        /* 
            点击确定键
            触发emit submit，返回节点信息和全id路径
            触发emit value 返回当前选中值
         */
        submit () {
            // 选中的节点全路径
            const ids = this.selectedList.map(item => item[this.useProps.key])
            this.$emit('submit', {
                node: this.selectedList[this.selectedList.length - 1],
                path:  ids
            })
            this.$emit('input', ids[ids.length - 1])
			this.$emit("update:modelValue", ids[ids.length - 1]);
            this.$emit('update:visible', false)
        },
        /* 
            点击取消
         */
        cancel () {
            this.$emit('update:visible', false)
            this.$emit('cancel')
        },
        /* 
            搜索
         */
        search (text) {
            const data = []
            if (text) {
                // 根据关键字检索
                this.flatData.forEach(item => {
                    // 关键字匹配
                    if (item[this.useProps.label].indexOf(text) > -1) {
                        // 查询节点所有父节点
                        data.push(item)
                    }
                })
            } else {
                // 根据关键字检索
                this.flatData.forEach(item => {
                    // 查询节点所有父节点
                    data.push(item)
                })
            }
            // 将结果回传给查询页
            this.searchedData = data
        },
        /* 
            搜索结果选中
         */
        selected(data) {
            // this.selectedList = this.getListByKey(id)
            this.selectedList = [...data.parentList, data]
            this.searchVisible = false
        },
        cancelSearch() {
            this.searchVisible = false
            this.searchedData = []
        },
        updateData() {
            this.searchedData = []
        },
    }

}
</script>
<style lang="scss" scoped>
@import "../../libs/css/style.components.scss";

@include themify($themes) {
    .cascader {
        display: flex;
        position: absolute;
        top: 0;
        bottom: 0;
        left: 0;
        right: 0;
        text-align: left;
        flex-direction: column;
        background-color: #fff;
        z-index: 1;
        /* 头部样式 */
        .cascader-header {
            // flex: 0;
            padding: themed('grid-size-16');
            display: flex;
            // height: themed('grid-size-24');
            // line-height: 24px;
            align-items: center;

            .cascader-header-label {
                font-size: themed('font-size-14');
                width: themed('grid-size-56');
                text-align: right;
                color: themed('u-tips-color');
            }

            .cascader-header-selected {
                flex: 1;
                color: themed('u-main-color');
                font-size: themed('font-size-18');
                font-weight: 500;
                margin-right: themed('grid-size-4');
                height: themed('grid-size-24');
            }
            .cascader-header-search {
                width: themed('grid-size-16');
                height: themed('grid-size-16');
            }
        }
        .cascader-selected-scroll {
            // flex: 0;
            /* 已选列表样式 */
            .cascader-selected-view {
                color: themed('u-tips-color');
                width: max-content;
                // height: themed('grid-size-18');
                padding: themed('grid-size-16');
                font-size: themed('font-size-12');
                font-weight: normal;
                display: flex;
                align-items: center;
                .cascader-selected-view-item {
                    display: flex;
                    align-items: center;
                }
                .node-gt {
                    margin: 0 themed('grid-size-8');
                    width: themed('grid-size-4');
                    height: themed('grid-size-16');
                }
                .node {
                    padding: themed('grid-size-4') 0;
                }
                .node-current {
                    color: themed('u-main-color');
                    font-weight: 500;
                    border-bottom: themed('grid-size-2') solid themed('u-type-primary');
                    padding-bottom: themed('grid-size-2');
                }
            }
        }

        /* 待选列表样式 */
        .cascader-list {
            flex: 1;
            // 不设定最小高度/高度，导致滚动条无效
            min-height: 0;
            // border的1px大小应是固定值
            border-top: 1px solid themed('u-border-color-disabled');
            border-bottom: 1px solid themed('u-border-color-disabled');
            // height: calc(100% - 170px);
            .cascader-list-item {
                color: themed('u-content-color');
                font-size: themed('font-size-12');
                display: flex;
                padding: themed('grid-size-12') themed('grid-size-16');
                .cascader-list-item-icon {
                    width: themed('grid-size-16');
                    height: themed('grid-size-16');
                    text-align: right;
                    margin-right: themed('grid-size-4');
                    .image {
                        width: themed('grid-size-16');
                        height: themed('grid-size-16');
                    }
                }
                .cascader-list-item-label {
                    flex: 1;
                    color: themed('u-content-color');
                }
                &.activate {
                    .cascader-list-item-label {
                        color: themed('u-main-color');
                        font-weight: bold;
                    }
                }
            }
        }

        /* 底部样式 */
        .cascader-footer {
            // flex: 0;
            padding: themed('grid-size-14') 0;
            display: flex;
            justify-content: space-evenly;
            // .cascader-footer-botton {
            //     font-size: themed('font-size-14');
            //     width: themed('grid-size-120');
            //     height: themed('grid-size-36');
            //     line-height: themed('grid-size-36');
            //     border-radius: themed('grid-size-36');
            //     &::after {
            //         border-radius: themed('grid-size-36');
            //     }
            // }
        }

        /* 超出隐藏样式 */
        .overflow-hidden {
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
        }
    }
    .result-content {
        display: flex;
        width: max-content;
        align-items: center;
        .result-item {
            display: flex;
            align-items: center;
            .node {
                font-size: themed('grid-size-14');
            }
            .node-current {
                color: themed('u-type-primary');
            }
        }
        .node-gt {
            margin: 0 themed('grid-size-8');
            width: themed('grid-size-4');
            height: themed('grid-size-16');
        }
    }
}
</style>