tree-control.tsx 4.2 KB
import { TreeModel } from '@ibiz-template/model';
import { ITreeNodeData } from '@ibiz-template/service';
import { useTreeController, useNamespace } from '@ibiz-template/vue-util';
import {
  CreateElement,
  defineComponent,
  getCurrentInstance,
  h,
  PropType,
  ref,
} from 'vue';
import { Tree } from 'element-ui';
import '@ibiz-template/theme/style/components/widgets/tree/tree.scss';

export const TreeControl = defineComponent({
  name: 'TreeControl',
  props: {
    modelData: {
      type: TreeModel,
      required: true,
    },
    context: { type: Object as PropType<IContext>, required: true },
    params: { type: Object as PropType<IParams>, default: () => ({}) },
    defaultSelectKeys: { type: Array<string>, required: false },
    isSelectFirstDefault: { type: Boolean, required: false },
  },
  setup(props) {
    const ns = useNamespace('control-treeview');
    const { proxy } = getCurrentInstance()!;
    const c = useTreeController(
      proxy,
      props.modelData,
      props.context,
      props.params,
    );
    const treeRef = ref<IData>();

    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    const loadData = async (item: any, callback: any) => {
      // 根节点触发的加载不走

      if (!item.parent) {
        return;
      }
      const nodes = await c.loadNodes(item.data);
      callback(nodes);
    };

    /**
     * 当前选中节点变更
     *
     * @param {ITreeNodeData} nodeData
     */
    const onCurrentChange = (nodeData: ITreeNodeData) => {
      c.onTreeNodeClick(nodeData);
    };

    // 默认展开回显
    const defaultExpands = ref<string[]>([]);
    const currentKey = ref<string | undefined>();
    if (props.defaultSelectKeys?.length) {
      currentKey.value = props.defaultSelectKeys[0];
      const arr: string[] = currentKey.value.split(':');
      while (arr.length > 0) {
        defaultExpands.value.push(arr.join(':'));
        arr.pop();
      }
    }

    // 数据加载回来后的处理
    c.nerve.self.evt.on('onLoadSuccess', async ({ data, isFirstLoad }) => {
      if (
        isFirstLoad &&
        c.isSelectFirstDefault &&
        c.defaultSelectKeys.length === 0
      ) {
        if (data[0]?.id) {
          // UI上通过 key 设置某个节点的当前选中状态
          treeRef.value!.setCurrentKey(data[0].id);
          c.onTreeNodeClick(data[0]);
        } else {
          ibiz.log.error('树加载成功后无数据');
        }
      }
      if (
        isFirstLoad &&
        defaultExpands.value.length === 0 &&
        c.defaultExpandedKeys
      ) {
        // 因为树是懒加载,所以初次加载时计算默认展开的keys
        defaultExpands.value = c.defaultExpandedKeys;
      }
    });

    const defaultProps = ref({
      label: 'text',
      children: 'children',
      isLeaf: 'leaf',
    });

    const renderContent = (
      _h: CreateElement,
      { node, data, _store }: IData,
    ) => {
      return (
        <span class={ns.b('custom-tree-node')}>
          {data.image ? (
            <span class={ns.b('node-icon')}>
              <app-icon icon={data.image} />
            </span>
          ) : null}
          <span class={ns.b('node-label')}>{node.label}</span>
        </span>
      );
    };

    return {
      c,
      ns,
      treeRef,
      defaultExpands,
      currentKey,
      onCurrentChange,
      loadData,
      defaultProps,
      renderContent,
    };
  },
  render() {
    if (!this.c.complete) {
      return;
    }
    return (
      <control-layout modelData={this.c.model}>
        {this.c.complete &&
          h(Tree, {
            ref: 'treeRef',
            class: this.ns.b(),
            props: {
              data: this.c.treeNodes,
              props: this.defaultProps,
              'node-key': 'id',
              'highlight-current': true,
              'default-expanded-keys': this.defaultExpands,
              'current-node-key': this.currentKey,
              lazy: true,
              load: this.loadData,
              'expand-on-click-node': false,
              'render-content': this.renderContent,
            },
            on: {
              'current-change': this.onCurrentChange,
            },
          })}
      </control-layout>
    );
  },
});