|
@@ -0,0 +1,273 @@
|
|
|
+<template>
|
|
|
+ <el-select
|
|
|
+ v-model="state.id"
|
|
|
+ :disabled="props.disabled"
|
|
|
+ :placeholder="props.placeholder"
|
|
|
+ ref="selectRef"
|
|
|
+ :clearable="props.clearable"
|
|
|
+ @clear="clear"
|
|
|
+ :filterable="props.filterable"
|
|
|
+ :filter-method="filterMethod"
|
|
|
+ >
|
|
|
+ <template #default>
|
|
|
+ <el-option hidden key="id" :value="state.id" :label="state.name"> </el-option>
|
|
|
+ <el-tree
|
|
|
+ node-key="id"
|
|
|
+ :load="loadNode"
|
|
|
+ lazy
|
|
|
+ v-if="lazyShow"
|
|
|
+ :props="treeProps"
|
|
|
+ :filter-node-method="filterNode"
|
|
|
+ @node-click="nodeClick"
|
|
|
+ :default-expanded-keys="state.externalArr"
|
|
|
+ v-loading="loading"
|
|
|
+ highlight-current
|
|
|
+ check-strictly
|
|
|
+ ref="treeRef"
|
|
|
+ :show-checkbox="props.showCheckbox"
|
|
|
+ @check="checkChange"
|
|
|
+ check-on-click-node
|
|
|
+ :expand-on-click-node="expandOnClickNode"
|
|
|
+ />
|
|
|
+ <el-tree
|
|
|
+ ref="treeRef"
|
|
|
+ :data="state.treeData"
|
|
|
+ node-key="id"
|
|
|
+ v-else
|
|
|
+ default-expand-all
|
|
|
+ highlight-current
|
|
|
+ :props="treeProps"
|
|
|
+ v-loading="loading"
|
|
|
+ :filter-node-method="filterNode"
|
|
|
+ @node-click="nodeClick"
|
|
|
+ check-strictly
|
|
|
+ :show-checkbox="props.showCheckbox"
|
|
|
+ @check="checkChange"
|
|
|
+ check-on-click-node
|
|
|
+ />
|
|
|
+ </template>
|
|
|
+ <template #footer v-if="props.showCheckbox">
|
|
|
+ <div class="flex-end">
|
|
|
+ <el-button type="primary" @click="chooseHotSpot" size="small">确定</el-button>
|
|
|
+ <el-button @click="reset" size="small">重置</el-button>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </el-select>
|
|
|
+</template>
|
|
|
+<script setup lang="ts">
|
|
|
+import { computed, reactive, ref, watch } from "vue";
|
|
|
+import { removeDuplicate } from '@/utils/arrayOperation';
|
|
|
+import { treeEventClass, treeEventClassSearch } from '@/api/auxiliary/eventClass';
|
|
|
+
|
|
|
+const props = defineProps({
|
|
|
+ modelValue: {
|
|
|
+ type: [String, Array],
|
|
|
+ default: () => '',
|
|
|
+ },
|
|
|
+ disabled: {
|
|
|
+ type: Boolean,
|
|
|
+ default: false,
|
|
|
+ },
|
|
|
+ placeholder: {
|
|
|
+ type: String,
|
|
|
+ default: '请选择',
|
|
|
+ },
|
|
|
+ externalArr: {
|
|
|
+ // 外部传入的父级id数组 懒加载时使用
|
|
|
+ type: Array,
|
|
|
+ default: () => [],
|
|
|
+ },
|
|
|
+ showCheckbox: {
|
|
|
+ // 是否显示多选
|
|
|
+ type: Boolean,
|
|
|
+ default: false,
|
|
|
+ },
|
|
|
+ clearable: {
|
|
|
+ type: Boolean,
|
|
|
+ default: false,
|
|
|
+ },
|
|
|
+ checkStrictly: {
|
|
|
+ // 任意一级
|
|
|
+ type: Boolean,
|
|
|
+ default: false,
|
|
|
+ },
|
|
|
+ filterable: {
|
|
|
+ type: Boolean,
|
|
|
+ default: true,
|
|
|
+ },
|
|
|
+} as any);
|
|
|
+// 选择节点展开
|
|
|
+const expandOnClickNode = computed(() => {
|
|
|
+ return !props.checkStrictly;
|
|
|
+});
|
|
|
+const treeProps = computed(() => {
|
|
|
+ return {
|
|
|
+ label: 'eventFullName',
|
|
|
+ children: 'children',
|
|
|
+ isLeaf: 'hasChild',
|
|
|
+ };
|
|
|
+});
|
|
|
+
|
|
|
+const emit = defineEmits(['choose', 'update:modelValue', 'confirm']);
|
|
|
+
|
|
|
+const state = reactive<any>({
|
|
|
+ id: '',
|
|
|
+ name: '',
|
|
|
+ treeData: [],
|
|
|
+ externalArr: [],
|
|
|
+ external: [],
|
|
|
+ checkedKeys: [],
|
|
|
+ checkNodes: [],
|
|
|
+});
|
|
|
+
|
|
|
+watch(
|
|
|
+ () => props.externalArr,
|
|
|
+ (val) => {
|
|
|
+ if (val) {
|
|
|
+ state.externalArr = val;
|
|
|
+ }
|
|
|
+ },
|
|
|
+ { immediate: true }
|
|
|
+);
|
|
|
+
|
|
|
+const lazyShow = ref(true);
|
|
|
+const loading = ref(false);
|
|
|
+// 懒加载
|
|
|
+const treeRef = ref<RefType>();
|
|
|
+const loadNode = async (node: any, resolve: any) => {
|
|
|
+ if (node.isLeaf) return resolve([]);
|
|
|
+ const { showCheckbox, modelValue } = props;
|
|
|
+ try {
|
|
|
+ loading.value = true;
|
|
|
+ const { result } = await treeEventClass({ id: node.data.id ? node.data.id : null });
|
|
|
+ resolve(result);
|
|
|
+ state.id = modelValue;
|
|
|
+ if (showCheckbox) {
|
|
|
+ treeRef.value.setCheckedKeys(modelValue);
|
|
|
+ const nodes = treeRef.value.getCheckedNodes();
|
|
|
+ state.name = nodes.map((item: any) => item.eventFullName).join(',') ?? '';
|
|
|
+ } else {
|
|
|
+ treeRef.value.setCurrentKey(modelValue);
|
|
|
+ const currentNode = treeRef.value.getNode(modelValue);
|
|
|
+ state.name = currentNode.data.eventFullName;
|
|
|
+ }
|
|
|
+ loading.value = false;
|
|
|
+ } catch (e) {
|
|
|
+ loading.value = false;
|
|
|
+ }
|
|
|
+};
|
|
|
+// 搜索
|
|
|
+const filterMethod = (value: string) => {
|
|
|
+ if (value) {
|
|
|
+ lazyShow.value = false; //当输入框有值时关闭懒加载
|
|
|
+ loading.value = true;
|
|
|
+ treeEventClassSearch(value)
|
|
|
+ .then((res) => {
|
|
|
+ //获取后端搜索的数据 //selectMacTree是我自己的后端接口,你们换成自己的
|
|
|
+ state.treeData.length = 0;
|
|
|
+ state.treeData = res.result ?? [];
|
|
|
+ treeRef.value!.filter(value);
|
|
|
+ if (props.showCheckbox && state.checkedKeys.length) {
|
|
|
+ treeRef.value.setCheckedKeys(state.checkedKeys);
|
|
|
+ }
|
|
|
+ if (props.modelValue) {
|
|
|
+ setTimeout(() => {
|
|
|
+ treeRef.value.setCurrentKey(props.modelValue);
|
|
|
+ }, 100);
|
|
|
+ }
|
|
|
+ loading.value = false;
|
|
|
+ })
|
|
|
+ .catch((e) => {
|
|
|
+ loading.value = false;
|
|
|
+ });
|
|
|
+ } else if (value == '' || value == ' ' || value == null) {
|
|
|
+ lazyShow.value = true; // 懒加载树显示
|
|
|
+ }
|
|
|
+};
|
|
|
+// 查询
|
|
|
+const filterNode = (value: string, data: any) => {
|
|
|
+ if (!value) return true;
|
|
|
+ return data.hotSpotFullName.includes(value);
|
|
|
+};
|
|
|
+// 单选
|
|
|
+const selectRef = ref<RefType>();
|
|
|
+const nodeClick = async (val: any, node: any) => {
|
|
|
+ const { showCheckbox, checkStrictly } = props;
|
|
|
+ if (showCheckbox) return;
|
|
|
+ if (checkStrictly) {
|
|
|
+ state.externalArr = [];
|
|
|
+ state.external = [];
|
|
|
+ state.externalArr = getParentId(node, state.external);
|
|
|
+ state.name = val.eventFullName;
|
|
|
+ state.id = val.id;
|
|
|
+ emit('update:modelValue', val.id);
|
|
|
+ emit('choose', { externalArr: state.externalArr, ...val });
|
|
|
+ selectRef.value.blur();
|
|
|
+ }
|
|
|
+ if (!node?.isLeaf) return;
|
|
|
+ state.externalArr = [];
|
|
|
+ state.external = [];
|
|
|
+ state.externalArr = getParentId(node, state.external);
|
|
|
+ state.name = val.eventFullName;
|
|
|
+ state.id = val.id;
|
|
|
+ emit('update:modelValue', val.id);
|
|
|
+ emit('choose', { externalArr: state.externalArr, ...val });
|
|
|
+ selectRef.value.blur();
|
|
|
+};
|
|
|
+// 多选
|
|
|
+const checkChange = (val: any, e: any) => {
|
|
|
+ const { showCheckbox } = props;
|
|
|
+ if (!showCheckbox) return;
|
|
|
+ const current = treeRef.value.getNode(val);
|
|
|
+ state.checkedKeys = e.checkedKeys;
|
|
|
+ state.checkedNodes = e.checkedNodes;
|
|
|
+ state.id = e.checkedKeys;
|
|
|
+ state.name = e.checkedNodes.map((item: any) => item.eventFullName).join(',') ?? '';
|
|
|
+ if (props.externalArr.length) {
|
|
|
+ state.externalArr = props.externalArr.concat(getParentId(current, state.external));
|
|
|
+ } else {
|
|
|
+ state.externalArr = getParentId(current, state.external);
|
|
|
+ }
|
|
|
+ emit('choose', state.checkedKeys, state.checkedNodes, state.externalArr);
|
|
|
+ emit('update:modelValue', e.checkedKeys);
|
|
|
+};
|
|
|
+// 多选确定
|
|
|
+const chooseHotSpot = () => {
|
|
|
+ emit('confirm', state.checkedKeys, state.checkedNodes, state.externalArr);
|
|
|
+ selectRef.value.blur();
|
|
|
+};
|
|
|
+// 重置
|
|
|
+const reset = () => {
|
|
|
+ state.checkedKeys = [];
|
|
|
+ treeRef.value.setCheckedKeys([]);
|
|
|
+ state.name = '';
|
|
|
+ emit('update:modelValue', []);
|
|
|
+};
|
|
|
+// 递归查找父级Id
|
|
|
+const getParentId = (val: any, arr: string[]) => {
|
|
|
+ if (val.data.parentId) {
|
|
|
+ arr.push(val.data.parentId);
|
|
|
+ getParentId(val.parent, arr);
|
|
|
+ }
|
|
|
+ return removeDuplicate(arr);
|
|
|
+};
|
|
|
+// 清空
|
|
|
+const clear = () => {
|
|
|
+ if (props.showCheckbox) {
|
|
|
+ state.checkedKeys = [];
|
|
|
+ treeRef.value.setCheckedKeys([]);
|
|
|
+ state.name = '';
|
|
|
+ state.id = [];
|
|
|
+ emit('update:modelValue', []);
|
|
|
+ } else {
|
|
|
+ state.id = '';
|
|
|
+ state.name = '';
|
|
|
+ treeRef.value.setCurrentKey(null);
|
|
|
+ emit('update:modelValue', '');
|
|
|
+ }
|
|
|
+};
|
|
|
+defineExpose({
|
|
|
+ reset,
|
|
|
+ clear,
|
|
|
+});
|
|
|
+</script>
|