diff --git a/CHANGELOG.md b/CHANGELOG.md index 289fe4a48cfc00d6e782eab7e22f2a7871af73da..fa98e56570ca7065beed73fa189a418136144668 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,8 @@ - 日历新增支持默认选中天与月度日历 - 数据关系分页支持onTabChange事件,并添加setActive能力 - 数据关系分页栏支持侧边显示 +- 新增应用全局参数和路由参数 +- 树新增计数器 ### Change diff --git a/src/control/tree/tree.scss b/src/control/tree/tree.scss index 16437c4294f91d3d4b6340d63cfe68fe0849d837..5aedf24a8aee5946f4a540f316c2afb33329d9cc 100644 --- a/src/control/tree/tree.scss +++ b/src/control/tree/tree.scss @@ -65,7 +65,16 @@ $control-treeview-crumb: ( } .tree-button { - color: getCssVar('color', 'primary'); + position: relative; + display: flex; + align-items: center; + .van-icon { + color: getCssVar('color', 'primary'); + } + .tree-counter { + position: absolute; + right: 20px; + } } } diff --git a/src/control/tree/tree.tsx b/src/control/tree/tree.tsx index 3184b96cb8a02319a9a33f82c7a669b5313d34f9..c3da829137c730942e306569229118a3867df4c3 100644 --- a/src/control/tree/tree.tsx +++ b/src/control/tree/tree.tsx @@ -1,25 +1,25 @@ import { - useControlController, - useNamespace, IBizIcon, + useNamespace, + useControlController, } from '@ibiz-template/vue3-util'; import { - computed, - defineComponent, - PropType, + h, + App, ref, VNode, - h as vueH, + computed, + PropType, createApp, - App, onUnmounted, + defineComponent, } from 'vue'; -import { IDETree } from '@ibiz/model-core'; +import { isNil } from 'ramda'; +import { IDETree, IDETreeNode } from '@ibiz/model-core'; import { - IControlProvider, - ITreeController, ITreeNodeData, TreeController, + IControlProvider, } from '@ibiz-template/runtime'; import { debounce } from 'lodash-es'; import { createUUID } from 'qx-util'; @@ -65,7 +65,7 @@ export const TreeControl = defineComponent({ navigational: { type: Boolean, default: undefined }, }, setup() { - const c = useControlController( + const c: TreeController = useControlController( (...args) => new TreeController(...args), ); const ns = useNamespace(`control-${c.model.controlType!.toLowerCase()}`); @@ -94,7 +94,7 @@ export const TreeControl = defineComponent({ // 创建图标节点 const createIconNode = (customProps: IData) => { - const iop = vueH(IBizIcon, customProps); + const iop = h(IBizIcon, customProps); const vueApp = createApp(iop); const dom = document.createElement('span'); vueApp.mount(dom); @@ -141,22 +141,15 @@ export const TreeControl = defineComponent({ }); /** - * 根据id查找树节点数据对象 - * @export - * @param {string} key (数据的_uuid 或者 _id) - * @param {ITreeController} c - * @return {*} {(ITreeNodeData | undefined)} + * @description 查找节点模型 + * @param {string} key + * @returns {*} {(IDETreeNode | undefined)} */ - function findNodeData( - key: string, - controller: ITreeController, - ): ITreeNodeData | undefined { - const find = controller.state.items.find(item => item._id === key); - if (find) { - return find; - } - return controller.state.items.find(item => item._uuid === key); - } + const findNodeModel = (key: string): IDETreeNode | undefined => { + const nodeData = c.getNodeData(key); + if (nodeData) return c.getNodeModel(nodeData._nodeId); + return undefined; + }; /** * @description 更新vs树,防止树节点数据加载完后选中数据丢失 @@ -182,13 +175,10 @@ export const TreeControl = defineComponent({ callback: (nodes: IData[]) => void, ) => { // 没加载前拦截 - if (!c.state.isLoaded) { - return; - } - + if (!c.state.isLoaded) return; // 加载时拦截点击事件 let nodes: ITreeNodeData[]; - const nodeData = findNodeData(item.data._uuid, c)!; + const nodeData = c.getNodeData(item.data._uuid)!; // 有搜索值为搜索框搜索,必须请求后台数据过滤 if (nodeData && nodeData._children && !c.state.query) { ibiz.log.debug('节点展开加载-本地', nodeData); @@ -214,13 +204,11 @@ export const TreeControl = defineComponent({ * @param {ITreeNodeData} nodeData */ const onNodeCheck = (event: MouseEvent, opts: IData) => { - if (c.state.singleSelect) { - return; - } + if (c.state.singleSelect) return; const { originData } = opts; // 选中相关处理 const { selectedData } = c.state; - const nodeData = findNodeData(originData._uuid, c)!; + const nodeData = c.getNodeData(originData._uuid)!; // 选中里没有则添加,有则删除 const filterArr = selectedData.filter( (item: IData) => item._id !== nodeData._id, @@ -235,9 +223,6 @@ export const TreeControl = defineComponent({ const onNodeClick = (event: MouseEvent, opts: IData) => { event.stopPropagation(); const { originData } = opts; - if (!originData._leaf) { - return; - } onNodeCheck(event, opts); c.onTreeNodeClick(originData, event); }; @@ -310,24 +295,49 @@ export const TreeControl = defineComponent({ }; const renderContent = ( - h: (tag: string, opt: IData) => VNode, + _h: (tag: string, opt: IData) => VNode, opts: IData, ) => { + // 添加节点样式表 + const { loadingEl, originData } = opts; + const nodeModel = findNodeModel(originData._id); + if (loadingEl && nodeModel?.sysCss?.cssName) + loadingEl.parentNode.parentNode.classList.add( + `${nodeModel.sysCss.cssName}`, + ); if (c.state.singleSelect) handleSingleSelect(opts); - const { originData } = opts; + + const children: HTMLElement[] = []; + + // 添加计数器 + if (nodeModel?.counterId) { + const count = c.state.counterData[nodeModel.counterId]; + if (!(isNil(count) || (nodeModel.counterMode === 1 && count === 0))) { + const child = document.createElement('div'); + child.className = `ibiz-badge tree-counter`; + child.innerText = count > 99 ? `${99}+` : count; + children.push(child); + } + } + + // 非叶子节点添加展开图标 if (!originData._leaf) { - const children = document.createElement('i'); - children.className = 'van-icon van-icon-arrow'; - return h('div', { - className: 'tree-button', - click: (e: Event, _opts: IData) => { - _opts.store.breadcrumb.list.push(_opts); - _opts.setExpand(true); - handleExpandedLastKey(originData); - }, - children: [children], - }); + const child = document.createElement('i'); + child.className = 'van-icon van-icon-arrow'; + children.push(child); } + + // 节点内容区绘制 + return _h('div', { + className: 'tree-button', + click: (e: Event, _opts: IData) => { + if (originData._leaf) return; + _opts.store.breadcrumb.list.push(_opts); + _opts.setExpand(true); + handleExpandedLastKey(originData); + }, + children, + }); }; const customNodeClick = (event: MouseEvent, opts: IData) => { @@ -389,28 +399,26 @@ export const TreeControl = defineComponent({ return { c, ns, - treeRefreshKey, - treeData, + uuid, options, + treeRef, + treeData, breadcrumb, - hiddenBreadcrumb, + currentVal, checkedKeys, - uuid, - treeRef, + treeRefreshKey, + hiddenBreadcrumb, + onInput, + loadData, onNodeCheck, onNodeClick, - loadData, treeDataFormat, - currentVal, - onInput, }; }, render() { const slots: IData = { searchbar: () => { - if (!this.c.enableQuickSearch) { - return null; - } + if (!this.c.enableQuickSearch) return null; return ( ), ]; diff --git a/src/mob-app/main.ts b/src/mob-app/main.ts index a5c49f43fcfeb7ca41ba5ddad6004b53ab5d0142..67d59f2ddb1e43b194920c2eff0be24906621e72 100644 --- a/src/mob-app/main.ts +++ b/src/mob-app/main.ts @@ -5,14 +5,15 @@ import { install as installRuntime, } from '@ibiz-template/runtime'; import { - install as installDevTool, listenOpenDevTool, + install as installDevTool, } from '@ibiz-template/devtool'; - import { AppHooks, - OverlayContainer, + useAppStore, PluginFactory, + route2routePath, + OverlayContainer, } from '@ibiz-template/vue3-util'; import { Plugin } from 'vue'; // 此处必须要引入,否则无法使用 @@ -49,6 +50,20 @@ export async function runApp(plugins?: Plugin[]): Promise { installRuntime(); AppHooks.appResorceInited.call(ibiz.hub); + // 初始化getGlobalParam + ibiz.util.getGlobalParam = () => { + return useAppStore().appStore; + }; + + // 初始化getRouterParams + ibiz.util.getRouterParams = () => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any, prettier/prettier + const routePath = route2routePath( + AppRouter.getRouter().currentRoute.value as any, + ); + return routePath.pathNodes; + }; + // 插件对象初始化放置在创建 app 之前 ibiz.plugin = new PluginFactory(); ibiz.util.error.register(new UnauthorizedHandler());