index.vue 4.94 KB

<template>
  <next-tree
      :changeVerify="changeVerify"
      :title="getTitle"
      ref="nextTreeRef"
      :checkStrictly="checkStrictly"
      :selectParent="selectParent"
      :multiple="multiple"
      :treeData="filteredTreeData"
      @cancel="close"
      @confirm="onconfirm">
    <template #topBar>
      <view class="search-container">
        <view class="search-box">
          <text class="search-icon">🔍</text>
          <input
              class="search-input"
              placeholder="搜索处置场所负责人姓名"
              v-model="searchText" />
          <text
              v-if="searchText"
              class="clear-icon"
              @click="clearSearch">✕</text>
        </view>
      </view>
    </template>
  </next-tree>
</template>

<script setup>import { nextTick, ref, unref, computed } from 'vue';
// @ts-ignore
import nextTree from '../next-tree/next-tree.vue';

const props = defineProps({
  dataList: {
    type: Array,
    default: []
  },
  valueKey: {
    type: String,
    default: 'id'
  },
  multiple: {
    type: Boolean,
    default: true
  },
  selectParent: {
    type: Boolean,
    default: false
  },
  checkStrictly: {
    type: Boolean,
    default: false
  },
  onconfirm: {
    type: Function,
    default: () => { }
  }
})

const treeData = ref([])
const nextTreeRef = ref()
const searchText = ref('')

// 添加计算属性用于过滤数据
const filteredTreeData = computed(() => {
  if (!searchText.value) {
    return treeData.value
  }

  return treeData.value.map(item => {
    const filteredChildren = item.children.filter(child =>
        child.label.toLowerCase().includes(searchText.value.toLowerCase())
    )

    return {
      ...item,
      children: filteredChildren
    }
  }).filter(item => item.children.length > 0)
})

function getTitle(checked) {
  return `已选:${checked.length}位处置场所负责人`
}

function changeVerify(current, chooseList) {
  // 注意:返回非空字符串会阻止原有行为,并提示返回的字符串
  // 如果函数体不做return返回值,即验证通过,控件正常处理业务
  // 限制条件 只能选择一个处置场所
  if (chooseList && chooseList.length < 2) {
    for (let index = 0; index < chooseList.length; index++) {
      const element = chooseList[index];
      if (current.id.indexOf(element.id) === -1 && element.label.indexOf(current.label) != -1) {
        return "该处置场所负责人已经被选中了"
      }
    }
  } else {
    return "只能选择一个处置场所"
  }
}

function open(dataList) {
  treeData.value = handlerTreeData(dataList)
  treeData.value = treeData.value.filter(item => {
    return item.children[0].id
  })
  setTimeout(() => {
    nextTick(() => {
      unref(nextTreeRef).showTree = true
    })
  }, 0)
}

function handlerTreeData(dataList) {
  return dataList
      .map((item, index) => {
        return {
          "id": (index + 1),
          "name": item.garOrderDisposalCompanyName,
          "label": item.garOrderDisposalCompanyName,
          "children": item.personnelInfo.map((childrenItem, childrenIndex) => {
            return {
              "id": (index + 1) + '-' + (childrenIndex + 1),
              "tel": childrenItem.tel,
              "companyName": item.garOrderDisposalCompanyName,
              "companyId": item.garOrderDisposalCompanyId,
              "name": childrenItem.personName,
              "personName": childrenItem.personName,
              "label": childrenItem.personName + "-" + childrenItem.tel,
              "checked": childrenItem.checked,
              "disabled": childrenItem.checked ? true : childrenItem.tel ? false : true
            }
          })
        }
      })
}

function cleanTreeData(treeData) {
  treeData.map(item => {
    item.checked = false
    if (item.children && item.children.length) {
      cleanTreeData(item.children)
    }
  })
}

function close() {
  // 清除treeData的选中状态
  cleanTreeData(unref(treeData))
  searchText.value = '' // 清空搜索文本
}

// 添加清空搜索功能
function clearSearch() {
  searchText.value = ''
}

defineExpose({
  open, close, nextTreeRef
})
</script>

<style lang="scss">.line-block {
  display: flex;
  flex-direction: row;
  justify-content: flex-start;
  align-items: center;

  .img {
    width: 40rpx;
    height: 40rpx;
    border-radius: 10rpx;
    margin: 0 20rpx;
  }
}

.search-container {
  padding: 15px 10px 10px;
  background-color: #fff;

  .search-box {
    display: flex;
    align-items: center;
    background-color: #f5f5f5;
    border-radius: 20px;
    padding: 8px 15px;

    .search-icon {
      font-size: 16px;
      margin-right: 8px;
      color: #999;
    }

    .search-input {
      flex: 1;
      border: none;
      background: transparent;
      font-size: 14px;
      outline: none;
      padding: 5px 0;

      &::placeholder {
        color: #aaa;
      }
    }

    .clear-icon {
      font-size: 16px;
      color: #999;
      padding: 2px;
      cursor: pointer;
    }
  }
}
</style>