<template>
    <view
        class="custom-tree-select-content"
        :class="{
            border: border && node[dataChildren] && node[dataChildren].length && node.showChildren,
        }"
        :style="{ marginLeft: `${level ? 14 : 0}px` }"
    >
        <view v-if="node.visible" class="custom-tree-select-item">
            <view class="item-content">
                <view class="left">
                    <view
                        v-if="node[dataChildren] && node[dataChildren].length"
                        :class="['right-icon', { active: node.showChildren }]"
                        @click.stop="nameClick(node)"
                    >
                        <uni-icons type="forward" size="14" color="#333"></uni-icons>
                    </view>
                    <view v-else class="smallcircle-filled">
                        <uni-icons
                            class="smallcircle-filled-icon"
                            type="smallcircle-filled"
                            size="10"
                            color="#333"
                        ></uni-icons>
                    </view>
                    <view v-if="loadingArr.includes(node[dataValue])" class="loading-icon-box">
                        <uni-icons class="loading-icon" type="spinner-cycle" size="14" color="#333"></uni-icons>
                    </view>
                    <view class="name" :style="node.disabled ? 'color: #999' : ''" @click.stop="nameClick(node)">
                        <text>{{ node[dataLabel] }}</text>
                    </view>
                </view>
                <view
                    v-if="
                        choseParent ||
                        (!choseParent && !node[dataChildren]) ||
                        (!choseParent && node[dataChildren] && !node[dataChildren].length)
                    "
                    :class="['check-box', { disabled: node.disabled }]"
                    @click.stop="nodeClick(node)"
                >
                    <view v-if="!node.checked && node.partChecked && linkage" class="part-checked"></view>
                    <uni-icons
                        v-if="node.checked"
                        type="checkmarkempty"
                        size="18"
                        :color="node.disabled ? '#333' : '#007aff'"
                    ></uni-icons>
                </view>
            </view>
        </view>
        <view v-if="node.showChildren && node[dataChildren] && node[dataChildren].length">
            <data-select-item
                v-for="item in listData"
                :key="item[dataValue]"
                :node="item"
                :dataLabel="dataLabel"
                :dataValue="dataValue"
                :dataChildren="dataChildren"
                :choseParent="choseParent"
                :border="border"
                :linkage="linkage"
                :level="level + 1"
                :load="load"
                :lazyLoadChildren="lazyLoadChildren"
            ></data-select-item>
        </view>
    </view>
</template>

<script>
import dataSelectItem from './data-select-item.vue';
import { paging } from './utils';
export default {
    name: 'data-select-item',
    components: {
        'data-select-item': dataSelectItem,
    },
    props: {
        node: {
            type: Object,
            default: () => ({}),
        },
        choseParent: {
            type: Boolean,
            default: true,
        },
        dataLabel: {
            type: String,
            default: 'name',
        },
        dataValue: {
            type: String,
            default: 'value',
        },
        dataChildren: {
            type: String,
            default: 'children',
        },
        border: {
            type: Boolean,
            default: false,
        },
        linkage: {
            type: Boolean,
            default: false,
        },
        level: {
            type: Number,
            default: 0,
        },
        load: {
            type: Function,
            default: function () {},
        },
        lazyLoadChildren: {
            type: Boolean,
            default: false,
        },
    },
    data() {
        return {
            listData: [],
            clearTimerList: [],
            loadingArr: [],
        };
    },
    computed: {
        watchData() {
            const { node, dataChildren } = this;

            return {
                node,
                dataChildren,
            };
        },
    },
    watch: {
        watchData: {
            immediate: true,
            handler(newVal) {
                const { node, dataChildren } = newVal;
                if (node.showChildren && node[dataChildren] && node[dataChildren].length) {
                    this.resetClearTimerList();
                    this.renderTree(node[dataChildren]);
                }
            },
        },
    },
    methods: {
        // 懒加载
        renderTree(arr) {
            const pagingArr = paging(arr);
            this.listData.splice(0, this.listData.length, ...(pagingArr?.[0] || []));
            this.lazyRenderList(pagingArr, 1);
        },
        // 懒加载具体逻辑
        lazyRenderList(arr, startIndex) {
            for (let i = startIndex; i < arr.length; i++) {
                let timer = null;
                timer = setTimeout(() => {
                    this.listData.push(...arr[i]);
                }, i * 500);
                this.clearTimerList.push(() => clearTimeout(timer));
            }
        },
        // 中断懒加载
        resetClearTimerList() {
            const list = [...this.clearTimerList];
            this.clearTimerList.splice(0, this.clearTimerList.length);
            list.forEach((item) => item());
        },
        async nameClick(node) {
            if (!node[this.dataChildren]?.length && this.lazyLoadChildren) {
                this.loadingArr.push(node[this.dataValue]);
                try {
                    const res = await this.load(node);
                    if (Array.isArray(res)) {
                        uni.$emit('custom-tree-select-load', {
                            source: node,
                            target: res,
                        });
                    }
                } finally {
                    this.loadingArr = [];
                }
            } else {
                if (!node.showChildren && node[this.dataChildren] && node[this.dataChildren].length) {
                    // 打开
                    this.renderTree(node[this.dataChildren]);
                } else {
                    // 关闭
                    this.resetClearTimerList();
                    this.listData.splice(0, this.listData.length);
                }
                uni.$emit('custom-tree-select-name-click', node);
            }
        },
        nodeClick(node) {
            if (!node.disabled) {
                uni.$emit('custom-tree-select-node-click', node);
            }
        },
    },
    options: {
        styleIsolation: 'shared',
    },
};
</script>

<style lang="scss" scoped>
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

$primary-color: #007aff;
$col-sm: 4px;
$col-base: 8px;
$col-lg: 12px;
$row-sm: 5px;
$row-base: 10px;
$row-lg: 15px;
$radius-sm: 3px;
$radius-base: 6px;
$border-color: #c8c7cc;

.custom-tree-select-content {
    &.border {
        border-left: 1px solid $border-color;
    }

    ::v-deep .uni-checkbox-input {
        margin: 0 !important;
    }

    .item-content {
        margin: 0 0 $col-lg;
        display: flex;
        justify-content: space-between;
        align-items: center;
        position: relative;

        &::after {
            content: '';
            position: absolute;
            top: 0;
            left: 0;
            bottom: 0;
            width: 3px;
            background-color: #fff;
            transform: translateX(-2px);
            z-index: 1;
        }

        .left {
            flex: 1;
            display: flex;
            align-items: center;

            .right-icon {
                transition: 0.15s ease;

                &.active {
                    transform: rotate(90deg);
                }
            }

            .smallcircle-filled {
                width: 14px;
                height: 13.6px;
                display: flex;
                align-items: center;

                .smallcircle-filled-icon {
                    transform-origin: center;
                    transform: scale(0.55);
                }
            }

            .loading-icon-box {
                margin-right: $row-sm;
                width: 14px;
                height: 100%;
                display: flex;
                justify-content: center;
                align-items: center;

                .loading-icon {
                    transform-origin: center;
                    animation: rotating infinite 0.2s ease;
                }
            }

            .name {
                flex: 1;
            }
        }
    }
}

.check-box {
    width: 23.6px;
    height: 23.6px;
    border: 1px solid $border-color;
    border-radius: $radius-sm;
    display: flex;
    justify-content: center;
    align-items: center;

    &.disabled {
        background-color: rgb(225, 225, 225);
    }

    .part-checked {
        width: 60%;
        height: 2px;
        background-color: $primary-color;
    }
}

@keyframes rotating {
    from {
        transform: rotate(0);
    }
    to {
        transform: rotate(360deg);
    }
}
</style>
