index.vue 7.89 KB
<!--
 * @Date: 2022-08-29 14:31:20
 * @LastEditors: hookehuyr hookehuyr@gmail.com
 * @LastEditTime: 2024-05-29 14:19:52
 * @FilePath: /data-table/src/components/TreeField/index.vue
 * @Description: 树形组件
-->
<template>
  <div v-if="HideShow" class="name-field-page">
    <div :class="[isGroup ? 'group-label' : 'label']">
      <span v-if="item.component_props.required">&nbsp;*</span>
      {{ item.component_props.label }}
    </div>

    <van-popup
      v-model:show="showBottom"
      position="bottom"
      :style="{ height: '80vh' }"
    >
      <div v-if="!is_search" class="search-box" @click="onSearchFocus">
        <van-icon name="search" size="1.1rem" />&nbsp;点击搜索
      </div>
      <van-field ref="searchInputRef" v-else v-model="search_value" label="" placeholder="可通过名称,手机号或邮箱查询" :border="false" @blur="onSearchBlur" @focus="onSearchFocus">
        <template #button>
          <van-button size="small" type="primary" @click="onCloseSearch">关闭</van-button>
        </template>
      </van-field>

      <div>
        {{ value }}
      </div>

      <div v-if="!is_search" class="tab-tree-container">
        <van-tabs :color="styleColor.baseColor" v-model:active="tabActive" @click-tab="onClickTab" style="margin-bottom: 1rem;">
          <van-tab title="组织结构"></van-tab>
          <van-tab title="角色"></van-tab>
          <van-tab title="成员"></van-tab>
        </van-tabs>

        <div v-if="tabActive === 0" style="padding: 0 0 1rem 1rem;">
          <Vtree
            ref="orgTreeRef"
            v-model="select_org_value"
            checkable
            titleField="name"
            keyField="id"
            :expandOnFilter="false"
            :showCheckedButton="false"
            :showFooter="false"
            :cascade="false"
            :defaultExpandAll="false"
            @search="searchMethod"
            @checked-change="checkedChangeMethod"
          >
            <span slot="empty">暂无数据</span>
          </Vtree>
        </div>

        <div v-if="tabActive === 1" style="padding: 0 0 1rem 1rem;">
          <van-checkbox-group
            v-model="role_checked"
          >
            <van-checkbox v-for="(role, index) in roleList" :key="index" :name="role.id" shape="square" icon-size="13px" :checked-color="styleColor.baseColor" style="margin-bottom: 0.5rem;">{{ role.name }}</van-checkbox>
          </van-checkbox-group>
        </div>

        <div v-if="tabActive === 2" style="padding: 0 0 0 1rem;">
          <van-row gutter="">
            <van-col span="10" style="border-right: 1px solid #eee; height: 70vh; max-height: 60vh; overflow: scroll;">
              <Vtree
                ref="memberTreeRef"
                v-model="select_member_value"
                selectable
                titleField="name"
                keyField="id"
                :expandOnFilter="false"
                :showCheckedButton="false"
                @update:modelValue="() => {}"
              >
                <span slot="empty">暂无数据</span>
              </Vtree>
            </van-col>
            <van-col span="14">
              <!-- {{ select_member_value }} -->
              <van-checkbox-group
                v-model="member_checked"
                style="padding: 0 0 1rem 1rem;"
              >
                <van-checkbox v-for="(member, index) in memberList" :key="index" :name="member.id" shape="square" icon-size="13px" :checked-color="styleColor.baseColor" style="margin-bottom: 0.5rem;">{{ member.name }}</van-checkbox>
              </van-checkbox-group>
            </van-col>
          </van-row>
        </div>
      </div>

      <div v-else class="search-container">
        <div>
          <p>部门</p>
          <div>1</div>
        </div>
        <div>
          <p>角色</p>
          <div>2</div>
        </div>
        <div>
          <p>成员</p>
          <div>3</div>
        </div>
      </div>

    </van-popup>

  </div>
</template>

<script setup>
import { styleColor } from "@/constant.js";
// 大家可以根据需要是否引入VTreeNode, VTreeSearch, VTreeDrop
import Vtree, { VTreeNode, VTreeSearch, VTreeDrop } from '@wsfe/vue-tree'
import '@wsfe/vue-tree/style.css';

const props = defineProps({
  item: Object,
});

// 隐藏显示
const HideShow = computed(() => {
  return !props.item.component_props.disabled
});

// 集合组标识
const isGroup = computed(() => {
  return props.item.component_props.is_field_group
});

const showBottom = ref(true);

const search_value = ref('');
const onSearch = (val) => {
  console.log(val);
};
const onCancel = () => {
  search_value.value = '';
};

const tabActive = ref(2);
const select_org_value = ref();
const orgTreeRef = ref();
const role_checked = ref([]);
const roleList = ref([{
  id: 'a',
  name: '法务组长',
}, {
  id: 'b',
  name: '接待组长',
}, {
  id: 'c',
  name: '场地管理',
}]);
const select_member_value = ref();
const memberTreeRef = ref();
const member_checked = ref([]);
const memberList = ref([{
  id: 'a',
  name: '法务组长',
}, {
  id: 'b',
  name: '接待组长',
}, {
  id: 'c',
  name: '场地管理',
}]);

const onClickTab = ({ title }) => { // tab点击事件
  if (title === '组织结构') {
    nextTick(() => {
      orgListReset();
    });
  }
  if (title === '角色') {
    nextTick(() => {
      roleListReset();
    });
  }
  if (title === '成员') {
    nextTick(() => {
      memberListReset();
    });
  }
};

const testData = [{
  id: 1,
  name: '西园寺',
  children: [{
    name: '保安',
    id: 2,
    children: [{
      name: '1号',
      id: 3
    }]
  }, {
    name: '餐饮',
    id: 4,
    children: [{
      name: '5号',
      id: 5
    }]
  }, {
    name: '保安',
    id: 21,
    children: [{
      name: '1号',
      id: 31
    }]
  }, {
    name: '餐饮',
    id: 41,
    children: [{
      name: '5号',
      id: 51
    }]
  }, {
    name: '保安',
    id: 22,
    children: [{
      name: '1号',
      id: 32
    }]
  }, {
    name: '餐饮',
    id: 42,
    children: [{
      name: '5号',
      id: 52
    }]
  }]
}]

onMounted(() => {
  props.item.value = props.item.component_props.default;

  // TODO:获取数据
  memberTreeRef.value.setData(testData);
  // 默认展开第一个
  memberTreeRef.value.setExpand(1, true)
});

const searchMethod = (value) => {
  console.log(value)
}

const checkedChangeMethod = (value) => {
  console.log(value)
  // console.log(orgTreeRef.value.getCheckedNodes())
}

const is_search = ref(false); // 默认不显示搜索框

const onSearchBlur = () => { // 搜索框失去焦点

}
const onSearchFocus = () => { // 搜索框获取焦点
  is_search.value = true;
  nextTick(() => {
    searchInputRef.value.focus()
  })
}

const onCloseSearch = () => {
  is_search.value = false;
}

const searchInputRef = ref(null);

const orgListReset = () => { // 组织重置列表
  orgTreeRef.value.setData(testData);

  orgTreeRef.value.setExpand(1, true)
}
const roleListReset = () => {

}
const memberListReset = () => {
  memberTreeRef.value.setData(testData);

  memberTreeRef.value.setExpand(1, true)
}
</script>

<style lang="less" scoped>
.name-field-page {
  .label {
    padding: 1rem 1rem 0 1rem;
    font-size: 0.9rem;
    font-weight: bold;
    span {
      color: red;
    }
  }

  .group-label {
    padding: 0.75rem 0 0.75rem 1rem;
    font-size: 0.9rem;
    font-weight: bold;
    background-color: #f9f9f9;
    color: #666;
    border-top: 1px solid #eee;
    border-bottom: 1px solid #eee;

    span {
      color: red;
    }
  }
}

:deep(.van-field__body) {
  border: 1px solid #eaeaea;
  border-radius: 0.25rem;
  padding: 0.25rem 0.5rem;
}

.search-box {
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: #eee;
  margin: 1rem;
  border-radius: 3px;
  padding: 0.6rem;
  font-size: 0.9rem;
}

:deep(.ctree-tree-node__checkbox_checked) {
  border-color: #C2915F;
  background-color: #C2915F;
}

:deep(.ctree-tree-node__title_selected) {
  background-color: #f8e2cb;
}
</style>