import { IBizContext, Namespace } from '@ibiz-template/core'; import { AppMenuModel, AppMenuItemModel, IPSAppMenuItem, } from '@ibiz-template/model'; import { useAppMenuController, useNamespace } from '@ibiz-template/vue-util'; import { defineComponent, getCurrentInstance, onMounted, Ref, ref, watch, } from 'vue'; import { AppMenuController } from '@ibiz-template/controller'; import '@ibiz-template/theme/style/components/widgets/app-menu/app-menu.scss'; /** * 递归生成菜单数据,递给 antd 的 Menu 组件 * * @author chitanda * @date 2022-07-25 10:07:28 * @param {AppMenuItemModel[]} items * @return {*} {any[]} */ function getMenus(items: AppMenuItemModel[]): IData[] { return items.map(item => { const data: IData = { key: item.source.id, label: item.label, image: item.image, }; if (item.children) { data.children = getMenus(item.children); } return data; }); } /** * 绘制菜单项 * @author lxm * @date 2022-08-16 14:08:20 * @param {IData} menu * @returns {*} */ function renderMenuItem( menu: IData, collapseChange: boolean, ns: Namespace, c: AppMenuController, ) { if (!c.menuItemsState[menu.key].visible) { return; } return !collapseChange ? ( <i-menu-item class={ns.e('item')} name={menu.key}> <app-icon class={ns.e('icon')} icon={menu.image}></app-icon> {menu.label} </i-menu-item> ) : ( <i-tooltip class={ns.b('tooltip')} content={menu.label} placement={'left'} theme='light' > <i-menu-item class={ns.e('item')} name={menu.key}> <app-icon class={ns.e('icon')} icon={menu.image}></app-icon> {!menu.image ? menu.label.slice(0, 1) : null} </i-menu-item> </i-tooltip> ); } /** * 绘制收缩分组菜单项 * @param {IData} menu * @return {*} * @author: zhujiamin * @Date: 2022-09-08 16:39:15 */ function renderDropDownMenuItem( menu: IData, collapseChange: boolean, ns: Namespace, c: AppMenuController, ) { if (!c.menuItemsState[menu.key].visible) { return; } return ( <i-dropdown-item class={ns.be('submenu', 'item')} name={menu.key}> <i-menu-item name={menu.key}>{menu.label}</i-menu-item> </i-dropdown-item> ); } /** * 绘制子菜单 * @author lxm * @date 2022-08-16 14:08:29 * @param {IData} subMenu * @returns {*} */ function renderSubmenu( isFirst: boolean, subMenu: IData, collapseChange: boolean, ns: Namespace, c: AppMenuController, ) { if (!c.menuItemsState[subMenu.key].visible) { return; } return !collapseChange ? ( <i-submenu name={subMenu.key}> <template slot='title'> <app-icon class={ns.e('icon')} icon={subMenu.image}></app-icon> {subMenu.label} </template> {subMenu.children.map((item: IData) => { if (item.children) { return renderSubmenu(false, item, collapseChange, ns, c); } return renderMenuItem(item, collapseChange, ns, c); })} </i-submenu> ) : ( <i-dropdown placement='left' class={ns.b('submenu')}> <div class={ns.be('submenu', 'title')}> {isFirst ? [ <app-icon class={ns.e('icon')} icon={subMenu.image}></app-icon>, !subMenu.image ? subMenu.label.slice(0, 1) : null, ] : [ <app-icon class={ns.e('icon')} icon={subMenu.image}></app-icon>, subMenu.label, ]} {isFirst ? null : <i-icon type='ios-arrow-forward' />} </div> <i-dropdown-menu class={ns.be('submenu', 'list')} slot='list'> {subMenu.children.map((item: IData) => { if (item.children) { return renderSubmenu(false, item, collapseChange, ns, c); } return renderDropDownMenuItem(item, collapseChange, ns, c); })} </i-dropdown-menu> </i-dropdown> ); } export const AppMenu = defineComponent({ name: 'AppMenu', props: { modelData: AppMenuModel, context: IBizContext, collapseChange: Boolean, currentPath: String, }, setup(props, { emit }) { const { proxy } = getCurrentInstance()!; const c = useAppMenuController(proxy, props.modelData!, props.context!, {}); const menus = ref<IData[]>([]); // 默认激活菜单项 const defaultActive = ref(''); // 默认展开菜单项数组 const defaultOpens: Ref<string[]> = ref([]); // 路由对象 const route = proxy.$route; c.nerve.self.evt.on('created', () => { menus.value = getMenus(c.model.items); }); let menuClickDoing = false; const onClick = async (key: string) => { menuClickDoing = true; await c.onClickMenuItem(key); menuClickDoing = false; }; const ns = useNamespace('app-menu'); // 手动更新iView菜单 const updateMenu = () => { setTimeout(() => { if (proxy.$refs.menu) { const menu: IData = proxy.$refs.menu; menu.updateActiveName(); menu.updateOpened(); } }, 500); }; // 菜单选中回显,监听视图传进来的currentPath watch( () => props.currentPath, (newVal, oldVal) => { // 新旧值不一样,且新值不为空时变更 if (newVal !== oldVal && newVal) { if (menuClickDoing === true) { emit('menuRouteChange'); } const findItem = c.model.allItems.find(item => { return item.viewModelPath === newVal; }); if (findItem) { defaultActive.value = findItem.source.id; updateMenu(); } } }, { deep: true, immediate: true }, ); // 处理默认展开父菜单 const handleDefaultOpen = (parent: IPSAppMenuItem) => { if (parent && parent.itemType === 'MENUITEM') { const findIndex = defaultOpens.value.findIndex(open => { return open === parent.id; }); if (findIndex === -1) { defaultOpens.value.push(parent.id); } const gParent = parent.getParentPSModelObject() as IPSAppMenuItem; if (gParent) { handleDefaultOpen(gParent); } } }; // 回显完成后,遍历展开父菜单 watch( () => defaultActive.value, newVal => { const findItem = c.model.allItems.find(item => { return newVal === item.id; }); if (findItem) { const parent = findItem.source.getParentPSModelObject() as IPSAppMenuItem; // 遍历取父菜单项 handleDefaultOpen(parent); updateMenu(); } }, ); onMounted(() => { // 默认激活的菜单项 const defaultActiveMenuItem = c.model.allItems.find(item => { return item.source.openDefault && !item.source.hidden; }); if (defaultActiveMenuItem && !route.params.view2) { defaultActive.value = defaultActiveMenuItem.id; onClick(defaultActive.value); } // 默认展开的菜单项数组 const defaultOpensArr = c.model.allItems.filter(item => { return item.source.expanded && !item.source.hidden; }); if (defaultOpensArr.length > 0) { defaultOpensArr.forEach(item => { defaultOpens.value.push(item.id); }); } updateMenu(); }); return { menus, c, onClick, ns, defaultActive, defaultOpens }; }, render() { return ( <i-menu ref={'menu'} active-name={this.defaultActive} open-names={this.defaultOpens} on-on-select={this.onClick} theme='light' width='auto' class={[this.ns.b(), this.ns.is('collapse', this.collapseChange)]} > {this.menus.map(item => { if (item.children?.length > 0) { return renderSubmenu( true, item, this.collapseChange, this.ns, this.c, ); } return renderMenuItem(item, this.collapseChange, this.ns, this.c); })} </i-menu> ); }, });