123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183 |
- <template>
- <view class="hc-tree-node" :class="[nodeItem.level > 1 ? 'pl': '']">
- <view class="content-bar" :id="'tree-' + nodeItem.key" :class="currentNodeKey===nodeItem.key?'current-node-key':''" @click="nodeTap(nodeItem)">
- <view class="expand-icon" @click.stop="expandTap(nodeItem)" :class="nodeItem.isExpand?'is-expanded':''">
- <text class="i-ri-arrow-right-s-fill" v-if="!nodeItem.isLeaf"/>
- </view>
- <view class="tree-check" @click.stop="checkClick" v-if="isCheck">
- <text class="i-ri-checkbox-blank-line c1" v-if="nodeItem.isCheck === 0"/>
- <text class="i-ri-checkbox-fill c2" v-if="nodeItem.isCheck === 1"/>
- <text class="i-ri-checkbox-indeterminate-fill c3" v-if="nodeItem.isCheck === 2"/>
- </view>
- <view class="tree-radio" v-if="isRadio">
- <text class="i-ri-checkbox-blank-circle-line c1" v-if="!nodeItem.isRadio"/>
- <text class="i-ri-checkbox-circle-fill c2" v-else/>
- </view>
- <view class="i-ri-loader-line cuIconfont-spin" v-if="nodeItem.loading"/>
- <view class="label">{{nodeItem.label?.replace(/\r|\n/ig,"")}} {{ isCounts? `【${nodeItem.data?.submitCounts ?? 0}】` : '' }}</view>
- </view>
- <template v-if="nodeItem.isExpand">
- <view class="children-bar" v-if="nodeItem.childNodes && nodeItem.childNodes.length > 0">
- <template v-for="items in nodeItem.childNodes">
- <hc-tree-node :item="items"
- :check="isCheck"
- :strictly="isStrictly"
- :radio="isRadio"
- :currentKey="currentNodeKey"
- :counts="isCounts"
- @nodeLoad="getLazyLoad"
- @nodeTap="nodeTaps"
- />
- </template>
- </view>
- </template>
- </view>
- </template>
- <script setup>
- import {ref, watch} from "vue";
- import {getArrValue} from "js-fast-way";
- //参数
- const props = defineProps({
- item: {
- type: Object,
- default: () => ({}),
- },
- check: {
- type: Boolean,
- default: false,
- },
- radio: {
- type: Boolean,
- default: false,
- },
- strictly: {
- type: Boolean,
- default: false,
- },
- currentKey: {
- type: String,
- default: '',
- },
- counts: {
- type: Boolean,
- default: false,
- },
- })
- //事件
- const emit = defineEmits(['nodeLoad', 'nodeTap'])
- //变量
- const nodeItem = ref(props.item)
- //参数配置
- const isCheck = ref(props.check)
- const isRadio = ref(props.radio)
- const isStrictly = ref(props.strictly)
- const isCounts = ref(props.counts)
- const currentNodeKey = ref(props.currentKey)
- //监听
- watch(() => [
- props.item
- ], ([item]) => {
- nodeItem.value = item
- }, {deep: true})
- //监听
- watch(() => [
- props.currentKey
- ], ([val]) => {
- currentNodeKey.value = val
- })
- //节点被点击
- const nodeTap = (item) => {
- expandTap(item)
- nodeTaps(item)
- }
- //展开和收缩节点
- const expandTap = (item) => {
- const {isLoad, isExpand, childNodes} = item
- const children = getArrValue(childNodes)
- //加载状态
- if (!isLoad) {
- item.loading = true
- }
- //展开和折叠
- if (children.length > 0) {
- setBrotherExpand(item, item.parentNodes)
- item.isExpand = !isExpand
- }
- //触发事件
- emit('nodeLoad', item)
- }
- //设置兄弟节点展开状态
- const setBrotherExpand = (item, nodes) => {
- const children = getArrValue(nodes.childNodes)
- for (let i = 0; i < children.length; i++) {
- if (children[i].key !== item.key) {
- nodes.childNodes[i].isExpand = false
- }
- }
- }
- //子节点被点击
- const nodeTaps = (item) => {
- currentNodeKey.value = item.key
- emit('nodeTap', item)
- }
- //懒加载子节点数据
- const getLazyLoad = (item) => {
- emit('nodeLoad', item)
- }
- //复选框被点击 0未选中 1选中 2半选
- const checkClick = () => {
- const {isCheck} = nodeItem.value
- if (isStrictly.value) {
- //父子级节点不关联选择
- nodeItem.value.isCheck = isCheck !== 1 ? 1 : 0
- } else {
- // 先设置自己的状态,选中或不选中
- nodeItem.value.isCheck = isCheck !== 1 ? 1 : 0
- // 设置子节点状态
- setChildrenCheck(nodeItem.value.childNodes)
- // 设置父节点状态
- setParentCheck(nodeItem.value.parentNodes)
- }
- }
- //设置子节点复选框状态
- const setChildrenCheck = (children) => {
- for (let i = 0; i < children.length; i++) {
- children[i].isCheck = nodeItem.value.isCheck
- if (children[i].childNodes.length > 0) {
- setChildrenCheck(children[i].childNodes)
- }
- }
- }
- //设置父节点复选框状态 0未选中 1选中 2半选
- const setParentCheck = (nodes) => {
- if (nodes.level <= 0) return
- const children = getArrValue(nodes.childNodes)
- const { isCheck } = nodeItem.value
- const result = children.every((item)=> {
- return item.isCheck === isCheck
- })
- if (isCheck === 1) {
- nodes.isCheck = result ? 1 : 2
- } else {
- nodes.isCheck = result ? 0 : 2
- }
- // 递归设置父节点
- if (nodes.parentNodes) {
- setParentCheck(nodes.parentNodes)
- }
- }
- </script>
|