配置二级菜单

  1. {
  2. path: '/page/hospital-edit/current',
  3. name: '医院信息',
  4. iconClass: '#icon-yiyuanguanli',
  5. requiredPolicy: 'FutureClinic_HospitalMenu.Menu',
  6. order: 3,
  7. layout: eLayoutType.application,
  8. },
  9. {
  10. // 注意,这里不需要设置 path,因为他不跳转
  11. name: '科室管理',
  12. iconClass: '#icon-keshiguanli',
  13. requiredPolicy: 'FutureClinic_DepartmentMenu.Menu',
  14. order: 4,
  15. layout: eLayoutType.application,
  16. children: [
  17. {
  18. // 将 path 放到二级菜单下即可
  19. path: '/page/department-list',
  20. name: '科室列表',
  21. iconClass: '#icon-keshiguanli',
  22. requiredPolicy: 'FutureClinic_DepartmentMenu.Menu',
  23. order: 4,
  24. // 注意,这里一定要手动添加上去,否则也是下拉展开的效果,不能点击
  25. isLeaf: true,
  26. layout: eLayoutType.application,
  27. // 注意,这个属性也要手动设置,否则会导致循环溢出
  28. children: []
  29. },
  30. {
  31. path: '/page/doctor-list',
  32. name: '医生管理',
  33. requiredPolicy: 'FutureClinic_DoctorMenu.Menu',
  34. iconClass: '#icon-yishengguanli',
  35. order: 5,
  36. isLeaf: true,
  37. layout: eLayoutType.application,
  38. children: []
  39. },
  40. ]
  41. },

注意,需要设置 isLeaf/children 属性。

使用改造的 nz-menu

template

  1. <ul nz-menu nzMode="inline" nzTheme="dark">
  2. <ng-container
  3. [ngTemplateOutlet]="commonLink"
  4. [ngTemplateOutletContext]="{ $implicit: routesService.visible }"
  5. >
  6. </ng-container>
  7. <ng-template #commonLink let-routes>
  8. <ng-container *ngFor="let route of routes">
  9. <ng-container *ngIf="!isDropdown(route)">
  10. <li
  11. nz-menu-item
  12. nz-tooltip
  13. *abpPermission="route.requiredPolicy"
  14. [nzPaddingLeft]="route.iconClass ? 0 : 50"
  15. >
  16. <a [routerLink]="[route.path]">
  17. <span title class="menu-title-wrapper">
  18. <svg
  19. *ngIf="route.iconClass && route.iconClass.indexOf('#') > -1; else fontIcon1"
  20. class="icon"
  21. aria-hidden="true"
  22. >
  23. <use [attr.xlink:href]="route.iconClass"></use>
  24. </svg>
  25. <ng-template #fontIcon1>
  26. <i class="icon" *ngIf="route.iconClass" [ngClass]="route.iconClass"></i>
  27. </ng-template>
  28. <span class="name">{{ route.name | abpLocalization }}</span>
  29. </span>
  30. </a>
  31. </li>
  32. </ng-container>
  33. <ng-container *ngIf="isDropdown(route)">
  34. <li nz-submenu nz-tooltip *abpPermission="route.requiredPolicy">
  35. <span title class="menu-title-wrapper">
  36. <svg
  37. *ngIf="route.iconClass.indexOf('#') > -1; else fontIcon"
  38. class="icon"
  39. aria-hidden="true"
  40. >
  41. <use [attr.xlink:href]="route.iconClass"></use>
  42. </svg>
  43. <ng-template #fontIcon>
  44. <i class="icon" *ngIf="route.iconClass" [ngClass]="route.iconClass"></i>
  45. </ng-template>
  46. <span>{{ route.name | abpLocalization }}</span>
  47. </span>
  48. <ul>
  49. <ng-container *ngTemplateOutlet="commonLink; context: { $implicit: route.children }">
  50. </ng-container>
  51. </ul>
  52. </li>
  53. </ng-container>
  54. </ng-container>
  55. </ng-template>
  56. </ul>

scss

  1. .icon {
  2. width: 1em; height: 1em;
  3. vertical-align: -0.15em;
  4. fill: currentColor;
  5. overflow: hidden;
  6. }
  7. .ant-menu-root {
  8. padding-bottom: 120px;
  9. }
  10. .ant-menu {
  11. background-color: #082a64 !important;
  12. .ant-menu-item,
  13. .ant-menu-item a {
  14. color: #fff;
  15. height: auto;
  16. padding-top: 4px;
  17. padding-bottom: 4px;
  18. transition: none;
  19. }
  20. .ant-menu-item:hover {
  21. a {
  22. color: #fff;
  23. }
  24. }
  25. .ant-menu-item-selected {
  26. color: #fff;
  27. background-color: #6385ff;
  28. }
  29. .ant-menu-item-selected a {
  30. color: #fff;
  31. background-color: #6385ff;
  32. }
  33. ::ng-deep .ant-menu-submenu {
  34. .ant-menu-submenu-title {
  35. color: #fff;
  36. }
  37. }
  38. }
  39. ::ng-deep .ant-menu > .ant-menu-submenu > .ant-menu-sub .ant-menu-submenu-title {
  40. color: #fff;
  41. padding-left: 50px !important;
  42. }
  43. ::ng-deep .ant-menu > .ant-menu-submenu > .ant-menu-sub .ant-menu-item.ng-star-inserted {
  44. padding-left: 60px !important;
  45. }
  46. .menu-title-wrapper {
  47. // display: flex;
  48. .icon {
  49. margin-right: 10px;
  50. }
  51. .img {
  52. width: 16px;
  53. height: 16px;
  54. background-repeat: no-repeat;
  55. background-size: contain;
  56. margin-right: 12px;
  57. }
  58. }
  59. ::ng-deep .ant-menu-sub {
  60. background-color: #082a64 !important;
  61. }
  62. .img {
  63. width: 16px;
  64. height: 16px;
  65. background-repeat: no-repeat;
  66. background-size: contain;
  67. margin-right: 12px;
  68. }

ts

  1. import { ABP, RoutesService, TreeNode } from '@abp/ng.core';
  2. import {
  3. Component,
  4. ElementRef,
  5. Input,
  6. QueryList,
  7. Renderer2,
  8. TrackByFunction,
  9. ViewChildren,
  10. } from '@angular/core';
  11. @Component({
  12. selector: 'abp-routes',
  13. templateUrl: 'routes.component.html',
  14. styleUrls: ['./routes.component.scss'],
  15. })
  16. export class RoutesComponent {
  17. @Input() smallScreen?: boolean;
  18. @ViewChildren('childrenContainer') childrenContainers!: QueryList<ElementRef<HTMLDivElement>>;
  19. rootDropdownExpand = {} as { [key: string]: boolean };
  20. trackByFn: TrackByFunction<TreeNode<ABP.Route>> = (_, item) => item.name;
  21. constructor(public readonly routesService: RoutesService, protected renderer: Renderer2) {
  22. }
  23. isDropdown(node: TreeNode<ABP.Route>) {
  24. console.log('isDropdown', node);
  25. return !node?.isLeaf || this.routesService.hasChildren(node.name);
  26. }
  27. closeDropdown() {
  28. this.childrenContainers.forEach(({ nativeElement }) => {
  29. this.renderer.addClass(nativeElement, 'd-none');
  30. setTimeout(() => this.renderer.removeClass(nativeElement, 'd-none'), 0);
  31. });
  32. }
  33. }