diff --git a/CHANGELOG.md b/CHANGELOG.md index 55a4e4a92e2bcc44f0dead40948e37d444f532d0..f514678254403e31c22ee5e531ef1efd52e5521d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,7 @@ - 标准菜单、图标菜单、列表菜单支持计数器绘制 - 向导面板支持向导表单启用逻辑 - 向导面板支持向导步骤图标 +- 新增树部件加载更多和节点绘制器 ### Change diff --git a/src/control/tree/tree.tsx b/src/control/tree/tree.tsx index c3da829137c730942e306569229118a3867df4c3..becdc903d6f40b66323e79360efd4a215ef22949 100644 --- a/src/control/tree/tree.tsx +++ b/src/control/tree/tree.tsx @@ -1,6 +1,7 @@ import { IBizIcon, useNamespace, + IBizControlShell, useControlController, } from '@ibiz-template/vue3-util'; import { @@ -20,10 +21,12 @@ import { ITreeNodeData, TreeController, IControlProvider, + getControlPanel, } from '@ibiz-template/runtime'; import { debounce } from 'lodash-es'; import { createUUID } from 'qx-util'; -import { VsTreeComponent } from '@ibiz-template-package/vs-tree-ex'; +import { VsTreeComponent } from '../../../../vs-tree-1/types/src/main'; +import { createVueApp } from '../../mob-app/create-vue-app'; import './tree.scss'; export const TreeControl = defineComponent({ @@ -148,7 +151,20 @@ export const TreeControl = defineComponent({ const findNodeModel = (key: string): IDETreeNode | undefined => { const nodeData = c.getNodeData(key); if (nodeData) return c.getNodeModel(nodeData._nodeId); - return undefined; + }; + + /** + * @description 查找节点视图布局面板 + * @param {string} key + * @returns {*} + */ + const findNodeLayoutPanel = (key: string) => { + const nodeData = c.getNodeData(key); + if (nodeData) { + const nodeModel = c.getNodeModel(nodeData._nodeId); + const layoutPanel = nodeModel ? getControlPanel(nodeModel) : undefined; + if (layoutPanel) return { nodeData, layoutPanel }; + } }; /** @@ -294,6 +310,30 @@ export const TreeControl = defineComponent({ } }; + /** + * @description 绘制节点 + * @param {HTMLDivElement} dom 父dom元素 + * @param {IData} opts 配置 + * @returns {*} + */ + const renderNode = (dom: HTMLDivElement, opts: IData) => { + const { originData } = opts; + const nodeLayoutPanel = findNodeLayoutPanel(originData._id); + if (nodeLayoutPanel) { + const { nodeData, layoutPanel } = nodeLayoutPanel; + const nodePanel = h(IBizControlShell, { + data: nodeData, + modelData: layoutPanel, + context: c.context, + params: c.params, + }); + const vueApp = createVueApp(nodePanel); + vueApp.mount(dom); + vueApps.push(vueApp); + return dom; + } + }; + const renderContent = ( _h: (tag: string, opt: IData) => VNode, opts: IData, @@ -354,6 +394,7 @@ export const TreeControl = defineComponent({ // 不能选择父节点 nocheckParent: true, rootName: c.model.detreeNodes?.find(item => item.rootNode)?.name, + renderNode, renderContent, customNodeClick, }; @@ -388,6 +429,40 @@ export const TreeControl = defineComponent({ }); } + /** + * 滚动事件 + * - 加载更多 + */ + const onScroll = debounce( + async (event: MouseEvent) => { + const { mobExpandedKey } = c.state; + // 当前展开节点默认是根节点 + const expandNodeKey = mobExpandedKey || c.state.rootNodes[0]._uuid; + const nodeData = c.getNodeData(expandNodeKey); + if (!nodeData) return; + const infoItems = c.getLoadMoreInfoItems(nodeData._id); + if (!infoItems) return; + const result = infoItems.some(infoItem => { + return infoItem.curPage < infoItem.totalPage - 1; + }); + const { scrollTop, clientHeight, scrollHeight } = event.target as IData; + // 滚动到底部且还有下一页数据时 + if (result && scrollTop + clientHeight >= scrollHeight - 10) { + const childern = toElNodes(await c.loadNodes(nodeData, true)); + // 如果不显示根节点并且当前展开是根节点时 nodeKey为 undefined + const nodeKey = + !c.model.rootVisible && !mobExpandedKey + ? undefined + : mobExpandedKey; + const node = treeRef.value.getNodeById(nodeKey); + // 在父节点上添加子数据 + childern.forEach(child => node.append(child)); + } + }, + 300, + { leading: true }, + ); + onUnmounted(() => { // 卸载绘制的图标节点 vueApps.forEach((vueApp: App) => { @@ -410,6 +485,7 @@ export const TreeControl = defineComponent({ hiddenBreadcrumb, onInput, loadData, + onScroll, onNodeCheck, onNodeClick, treeDataFormat, @@ -467,6 +543,7 @@ export const TreeControl = defineComponent({ expandKeys={this.c.state.expandedKeys} show-checkbox={!this.c.state.singleSelect} load={this.loadData} + onScroll={this.onScroll} onCheck={this.onNodeCheck} format={this.treeDataFormat} >