<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      (系列十四)Vue3+WebApi 搭建動態菜單

      說明

          該文章是屬于OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。

          該系統文章,我會盡量說的非常詳細,做到不管新手、老手都能看懂。

          說明:OverallAuth2.0 是一個簡單、易懂、功能強大的權限+可視化流程管理系統。

      友情提醒:本篇文章是屬于系列文章,看該文章前,建議先看之前文章,可以更好理解項目結構。

      qq群:801913255,進群有什么不懂的盡管問,群主都會耐心解答。

      有興趣的朋友,請關注我吧(*^▽^*)。

      關注我,學不會你來打我

      問題修復

        說明:不是跟著系列文章搭建系統的請自行忽略,往下看搭建動態菜單的過程。

        問題1:

      修改代碼如下

      路徑:framework->index.vue

      <el-main>
                <el-affix :offset="60">
                  <el-tabs
                    v-if="tabsList.length > 0"
                    v-model="defaultActive"
                    class="demo-tabs"
                    @click="tabsClick(defaultActive)"
                    @tab-remove="tabRemoveClick"
                  >
                    <el-tab-pane
                      v-for="item in tabsList"
                      :label="item.name"
                      :name="item.path"
                      :key="item.path"
                      :closable="item.path == '/panel' ? false : true"
                      style="font-size: 16px"
                    >
                    </el-tab-pane>
                  </el-tabs>
                </el-affix>
                <router-view></router-view>
              </el-main>
      View Code

      樣式.demo-tabs中加入白色背景樣式:background-color: white;

        問題2:

      中國地圖中,波紋會隨著各省的數值變大而變大

      路徑:echarts.ts

      把value: chinaGeoCoordMap[dataItem[0].name].concat([dataItem[0].value])修改成value: chinaGeoCoordMap[dataItem[0].name].concat(0)

      實現功能

          把以下菜單換成動態菜單

        不是跟著系列走的朋友,可直接觀看動態路由菜單的關鍵代碼 ,在后面的第三步中!!!

        注意:該篇文章是實現OverallAuth2.0 功能級權限之一,菜單權限的重要篇幅。

      routes.push(
        {
          path: '/framework',
          component: Framework,
          name: "架構",
      
        },
        {
          path: '/login',
          component: Login,
          name: "登錄頁面",
        },
        {
          path: '/panel',
          redirect: '/panel/index',
          meta: { title: '工作空間' },
          name: "工作空間",
          component: Framework,
          children: [
            {
              path: '/panel',
              name: '工作臺',
              component: () => import('../../views/panel/index.vue'),
              meta: { title: '工作臺', requireAuth: true, affix: true, closable: false },
            }
          ]
        },
        {
          path: '/menu',
          redirect: '/menu/index',
          meta: { title: '菜單管理' },
          name: "菜單管理",
          component: Framework,
          children: [
            {
              path: '/menu',
              name: '菜單',
              component: () => import('../../views/menu/index.vue'),
              meta: { title: '菜單', requireAuth: true, affix: true, closable: false },
            }
          ]
        },
        {
          path: '/user',
          meta: { title: '用戶管理' },
          name: "用戶管理",
          component: Framework,
          children: [
            {
              path: '/user',
              name: '用戶',
              component: () => import('../../views/user/index.vue'),
              meta: { title: '用戶' },
            }]
        },
      )
      View Code

      創建數據庫表

         根據菜單格式創建數據庫表,并創建初始值。

      CREATE TABLE [dbo].[Sys_Menu](
          [Id] [uniqueidentifier] NOT NULL,
          [Pid] [varchar](50) NOT NULL,
          [CorporationKey] [varchar](50) NOT NULL,
          [SystemKey] [varchar](50) NOT NULL,
          [MenuUrl] [varchar](50) NOT NULL,
          [MenuIcon] [varchar](50) NULL,
          [MenuTitle] [nvarchar](50) NOT NULL,
          [Component] [varchar](500) NOT NULL,
          [Sort] [int] NOT NULL,
          [IsOpen] [bit] NOT NULL,
          [CreateTime] [datetime] NOT NULL,
          [CreateUser] [varchar](50) NOT NULL,
          [RequireAuth] [bit] NULL,
          [Redirect] [varchar](500) NULL,
       CONSTRAINT [PK_Menu] PRIMARY KEY CLUSTERED 
      (
          [Id] ASC
      )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
      ) ON [PRIMARY]
      GO
      INSERT [dbo].[Sys_Menu] ([Id], [Pid], [CorporationKey], [SystemKey], [MenuUrl], [MenuIcon], [MenuTitle], [Component], [Sort], [IsOpen], [CreateTime], [CreateUser], [RequireAuth], [Redirect]) VALUES (N'380ca40b-8b62-4ebe-86d7-91ae48292f43', N'0', N'6a75ec49-2093-4b89-950f-65e6e72746da', N'6e746ed0-12e9-4002-9887-d84a19142304', N'/panel', N'layui-icon-engine', N'工作空間', N'frameWork', 1, 1, CAST(N'2024-12-05T00:00:00.000' AS DateTime), N'1', 1, NULL)
      INSERT [dbo].[Sys_Menu] ([Id], [Pid], [CorporationKey], [SystemKey], [MenuUrl], [MenuIcon], [MenuTitle], [Component], [Sort], [IsOpen], [CreateTime], [CreateUser], [RequireAuth], [Redirect]) VALUES (N'380ca40b-8b62-4ebe-86d7-91ae48292f44', N'380ca40b-8b62-4ebe-86d7-91ae48292f43', N'6a75ec49-2093-4b89-950f-65e6e72746da', N'6e746ed0-12e9-4002-9887-d84a19142304', N'/panel', N'layui-icon-engine', N'工作臺', N'../views/panel/index', 1, 1, CAST(N'2024-12-05T00:00:00.000' AS DateTime), N'1', 1, NULL)
      INSERT [dbo].[Sys_Menu] ([Id], [Pid], [CorporationKey], [SystemKey], [MenuUrl], [MenuIcon], [MenuTitle], [Component], [Sort], [IsOpen], [CreateTime], [CreateUser], [RequireAuth], [Redirect]) VALUES (N'380ca40b-8b62-4ebe-86d7-91ae48292f45', N'0', N'6a75ec49-2093-4b89-950f-65e6e72746da', N'6e746ed0-12e9-4002-9887-d84a19142304', N'/menu', N'layui-icon-engine', N'菜單管理', N'frameWork', 1, 1, CAST(N'2024-12-05T00:00:00.000' AS DateTime), N'1', 1, NULL)
      INSERT [dbo].[Sys_Menu] ([Id], [Pid], [CorporationKey], [SystemKey], [MenuUrl], [MenuIcon], [MenuTitle], [Component], [Sort], [IsOpen], [CreateTime], [CreateUser], [RequireAuth], [Redirect]) VALUES (N'380ca40b-8b62-4ebe-86d7-91ae48292f46', N'380ca40b-8b62-4ebe-86d7-91ae48292f45', N'6a75ec49-2093-4b89-950f-65e6e72746da', N'6e746ed0-12e9-4002-9887-d84a19142304', N'/menu', N'layui-icon-engine', N'菜單', N'../views/menu/index', 1, 1, CAST(N'2024-12-05T00:00:00.000' AS DateTime), N'1', 1, NULL)
      INSERT [dbo].[Sys_Menu] ([Id], [Pid], [CorporationKey], [SystemKey], [MenuUrl], [MenuIcon], [MenuTitle], [Component], [Sort], [IsOpen], [CreateTime], [CreateUser], [RequireAuth], [Redirect]) VALUES (N'380ca40b-8b62-4ebe-86d7-91ae48292f47', N'0', N'6a75ec49-2093-4b89-950f-65e6e72746da', N'6e746ed0-12e9-4002-9887-d84a19142304', N'/user', N'layui-icon-engine', N'用戶管理', N'frameWork', 1, 1, CAST(N'2024-12-05T00:00:00.000' AS DateTime), N'1', 1, NULL)
      INSERT [dbo].[Sys_Menu] ([Id], [Pid], [CorporationKey], [SystemKey], [MenuUrl], [MenuIcon], [MenuTitle], [Component], [Sort], [IsOpen], [CreateTime], [CreateUser], [RequireAuth], [Redirect]) VALUES (N'380ca40b-8b62-4ebe-86d7-91ae48292f48', N'380ca40b-8b62-4ebe-86d7-91ae48292f47', N'6a75ec49-2093-4b89-950f-65e6e72746da', N'6e746ed0-12e9-4002-9887-d84a19142304', N'/user', N'layui-icon-engine', N'用戶', N'../views/user/index', 1, 1, CAST(N'2024-12-05T00:00:00.000' AS DateTime), N'1', 1, NULL)
      ALTER TABLE [dbo].[Sys_Menu] ADD  CONSTRAINT [DF_Sys_Menu_Sort]  DEFAULT ((0)) FOR [Sort]
      GO
      EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'菜單id' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'Sys_Menu', @level2type=N'COLUMN',@level2name=N'Id'
      GO
      EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'父級id' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'Sys_Menu', @level2type=N'COLUMN',@level2name=N'Pid'
      GO
      EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'公司Key' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'Sys_Menu', @level2type=N'COLUMN',@level2name=N'CorporationKey'
      GO
      EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'系統Key' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'Sys_Menu', @level2type=N'COLUMN',@level2name=N'SystemKey'
      GO
      EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'菜單路徑' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'Sys_Menu', @level2type=N'COLUMN',@level2name=N'MenuUrl'
      GO
      EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'菜單圖標' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'Sys_Menu', @level2type=N'COLUMN',@level2name=N'MenuIcon'
      GO
      EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'菜單標題' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'Sys_Menu', @level2type=N'COLUMN',@level2name=N'MenuTitle'
      GO
      EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'排序' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'Sys_Menu', @level2type=N'COLUMN',@level2name=N'Sort'
      GO
      EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'是否開啟菜單' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'Sys_Menu', @level2type=N'COLUMN',@level2name=N'IsOpen'
      GO
      EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'創建時間' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'Sys_Menu', @level2type=N'COLUMN',@level2name=N'CreateTime'
      GO
      EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'創建人員' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'Sys_Menu', @level2type=N'COLUMN',@level2name=N'CreateUser'
      GO
      EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'是否驗證' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'Sys_Menu', @level2type=N'COLUMN',@level2name=N'RequireAuth'
      GO
      EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'重定向' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'Sys_Menu', @level2type=N'COLUMN',@level2name=N'Redirect'
      GO
      EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'菜單表' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'Sys_Menu'
      GO
      View Code

      編寫后端代碼

        注意:底層倉儲我已經搭建好,只需要實現菜單查詢的業務邏輯即可,如果需要了解底層倉儲的,請查看《dapper搭建底層倉儲

        1:創建模型(我的創建路徑:Model->DomainModel->Sys)

      /// <summary>
      /// 菜單表模型
      /// </summary>
      public class SysMenu
      {
          /// <summary>
          /// 菜單主鍵
          /// </summary>
          public Guid Id { get; set; }
      
          /// <summary>
          /// 上級菜單
          /// </summary>
          public string? Pid { get; set; }
      
          /// <summary>
          /// 公司key
          /// </summary>
          public string? CorporationKey { get; set; }
      
          /// <summary>
          /// 系統Key
          /// </summary>
          public string? SystemKey { get; set; }
      
          /// <summary>
          /// 菜單路徑
          /// </summary>
          public string? MenuUrl { get; set; }
      
          /// <summary>
          /// 菜單圖標
          /// </summary>
          public string? MenuIcon { get; set; }
      
          /// <summary>
          /// 菜單標題
          /// </summary>
          public string? MenuTitle { get; set; }
      
          /// <summary>
          /// 菜單模板
          /// </summary>
          public string? Component { get; set; }
      
          /// <summary>
          /// 是否開啟
          /// </summary>
          public bool IsOpen { get; set; }
      
          /// <summary>
          /// 排序
          /// </summary>
          public int Sort { get; set; }
      
          /// <summary>
          /// 創建時間
          /// </summary>
          public DateTime CreateTime { get; set; }
      
          /// <summary>
          /// 創建人員
          /// </summary>
          public string? CreateUser { get; set; }
      
          /// <summary>
          /// 是否驗證
          /// </summary>
          public bool RequireAuth { get; set; }
      
          /// <summary>
          /// 重定向目錄
          /// </summary>
          public string? Redirect { get; set; }
      }
      View Code

        2:創建菜單表的倉儲(我的創建路徑:Infrastructure->IRepository和Repository->Sys)

      /// <summary>
      /// 系統菜單倉儲接口
      /// </summary>
      public interface ISysMenuRepository : IRepository<SysMenu>
      {
      }
      /// <summary>
      /// 系統菜單倉儲接口實現
      /// </summary>
      public class SysMenuRepository : Repository<SysMenu>, ISysMenuRepository
      {
      }

        3:創建領域服務(我的創建路徑:DomainService->IService和Service->Sys)

      /// <summary>
      /// 菜單服務接口
      /// </summary>
      public interface ISysMenuService
      {
          /// <summary>
          /// 獲取樹形菜單
          /// </summary>
          /// <returns></returns>
          List<SysMenuOutPut> GetMenuTreeList();
      }
       /// <summary>
       /// 菜單服務實現
       /// </summary>
       public class SysMenuService : ISysMenuService
       {
           #region 構造實例化
      
           /// <summary>
           /// 菜單倉儲接口
           /// </summary>
           private readonly ISysMenuRepository _menuRepository;
      
           /// <summary>
           /// 構造函數
           /// </summary>
           /// <param name="menuRepository"></param>
           public SysMenuService(ISysMenuRepository menuRepository)
           {
               _menuRepository = menuRepository;
           }
      
           #endregion
      
      
           #region 業務邏輯
      
           /// <summary>
           /// 獲取樹形菜單
           /// </summary>
           /// <returns></returns>
           public List<SysMenuOutPut> GetMenuTreeList()
           {
                return new List<SysMenuOutPut>();
           }
      
           #endregion
       }

        4:遞歸獲取菜單,呈現上下級關系

        這塊主要是把數據庫取出的數據,轉換成前端能識別的樹形結構。要實現該功能,先要建立一個支持樹形結構的輸出模型(Model->BusinessModel->OutPut)。

      /// <summary>
      /// 菜單輸出模型
      /// </summary>
      public class SysMenuOutPut
      {
          /// <summary>
          /// 菜單主鍵
          /// </summary>
          public Guid Id { get; set; }
      
          /// <summary>
          /// 上級菜單
          /// </summary>
          public string? Pid { get; set; }
      
          /// <summary>
          /// 公司key
          /// </summary>
          public string? CorporationKey { get; set; }
      
          /// <summary>
          /// 系統Key
          /// </summary>
          public string? SystemKey { get; set; }
      
          /// <summary>
          /// 菜單路徑
          /// </summary>
          public string? Path { get; set; }
      
          /// <summary>
          /// 菜單圖標
          /// </summary>
          public string? MenuIcon { get; set; }
      
          /// <summary>
          /// 菜單標題
          /// </summary>
          public string? Name { get; set; }
      
          /// <summary>
          /// 菜單模板
          /// </summary>
          public string? Component { get; set; }
      
          /// <summary>
          /// 是否開啟
          /// </summary>
          public bool IsOpen { get; set; }
      
          /// <summary>
          /// 排序
          /// </summary>
          public int Sort { get; set; }
      
          /// <summary>
          /// 創建時間
          /// </summary>
          public DateTime CreateTime { get; set; }
      
          /// <summary>
          /// 創建人員
          /// </summary>
          public string? CreateUser { get; set; }
      
          /// <summary>
          /// 是否驗證
          /// </summary>
          public bool RequireAuth { get; set; }
      
          /// <summary>
          /// 重定向目錄
          /// </summary>
          public string? Redirect { get; set; }
      
          /// <summary>
          /// 子節點
          /// </summary>
          public List<SysMenuOutPut>? Children { get; set; }
      }
      View Code

        然后我們要創建一個菜單的核心操作類,以便系統后續的使用(CoreDomain->BusinessCore)

      /// <summary>
      /// 菜單核心
      /// </summary>
      public static class MenuCore
      {
          /// <summary>
          /// 遞歸獲取菜單,組成樹形結構
          /// </summary>
          /// <param name="menuList">菜單數據</param>
          /// <returns>返回菜單的樹形結構</returns>
          public static List<SysMenuOutPut> GetMenuTreeList(List<SysMenu> menuList)
          {
              List<SysMenuOutPut> list = new();
              List<SysMenuOutPut> menuListDto = new();
              //模型的轉換
              foreach (var item in menuList)
              {
                  SysMenuOutPut model = new()
                  {
                      Id = item.Id,
                      Pid = item.Pid,
                      CorporationKey = item.CorporationKey,
                      SystemKey = item.SystemKey,
                      Path = item.MenuUrl,
                      Name = item.MenuTitle,
                      MenuIcon = item.MenuIcon,
                      Component = item.Component,
                      IsOpen = item.IsOpen,
                      Sort = item.Sort,
                      RequireAuth = item.RequireAuth,
                      Redirect = item.Redirect,
                      CreateTime = item.CreateTime,
                      CreateUser = item.CreateUser,
                  };
                  list.Add(model);
              }
              //遞歸所有父級菜單
              foreach (var data in list.Where(f => f.Pid == "0" && f.IsOpen))
              {
                  var childrenList = GetChildrenMenu(list, data.Id).OrderBy(f => f.Sort).ToList();
                  data.Children = childrenList.Count == 0 ? null : childrenList;
                  menuListDto.Add(data);
              }
              return menuListDto;
          }
      
          /// <summary>
          /// 實現遞歸
          /// </summary>
          /// <param name="moduleOutput">菜單數據</param>
          /// <param name="id">菜單ID</param>
          /// <returns></returns>
          private static List<SysMenuOutPut> GetChildrenMenu(List<SysMenuOutPut> moduleOutput, Guid id)
          {
              List<SysMenuOutPut> sysShowTempMenus = new();
              //得到子菜單
              var info = moduleOutput.Where(w => w.Pid == id.ToString() && w.IsOpen).ToList();
              //循環
              foreach (var sysMenuInfo in info)
              {
                  var childrenList = GetChildrenMenu(moduleOutput, sysMenuInfo.Id);
                  //把子菜單放到Children集合里
                  sysMenuInfo.Children = childrenList.Count == 0 ? null : childrenList;
                  //添加父級菜單
                  sysShowTempMenus.Add(sysMenuInfo);
              }
              return sysShowTempMenus;
          }
      }
      View Code

        在領域服務中實現接口GetMenuTreeList();

      /// <summary>
      /// 獲取樹形菜單
      /// </summary>
      /// <returns></returns>
      public List<SysMenuOutPut> GetMenuTreeList()
      {
          var menuList = _menuRepository.GetAll(BaseSqlRepository.sysMenu_selectAllSql);
          var menuTreeList = MenuCore.GetMenuTreeList(menuList);
          return menuTreeList;
      }

      注意:BaseSqlRepository.sysMenu_selectAllSql 是查詢sql的語句,我放在了一個基礎sql倉儲中,統一管理

        5:編寫接口(Controllers->Sys)

       /// <summary>
       /// 系統模塊
       /// </summary>
       [ApiController]
       [Route("api/[controller]/[action]")]
       [ApiExplorerSettings(GroupName = nameof(ModeuleGroupEnum.SysMenu))]
       public class SysMenuController : BaseController
       {
      
           #region 構造實列化
      
           /// <summary>
           /// 菜單服務服務
           /// </summary>
           public ISysMenuService _sysMenuService;
      
           /// <summary>
           /// 構造函數
           /// </summary>
           /// <param name="sysMenuService"></param>
           public SysMenuController(ISysMenuService sysMenuService)
           {
               _sysMenuService = sysMenuService;
           }
      
           #endregion
      
           #region 菜單接口
      
           /// <summary>
           /// 獲取樹形菜單
           /// </summary>
           /// <returns></returns>
           [HttpGet]
           public ReceiveStatus<SysMenuOutPut> GetMenuTreeList()
           {
               ReceiveStatus<SysMenuOutPut> receiveStatus = new();
               var list = _sysMenuService.GetMenuTreeList();
               receiveStatus.data = list;
               return receiveStatus;
           }
      
           #endregion
      
       }
      View Code

        6:測試接口

      編寫前端代碼

        后端接口已經準備就緒,那么接下來就要編寫前端的代碼,把靜態的json數據轉換成接口返回的動態數據。

       第一步:修改靜態路由

      把base-routes.ts文件中的路由換成

      routes.push(
        {
          path: '/framework',
          component: frameWork,
          name: "架構",
      
        },
        {
          path: '/login',
          component: Login,
          name: "登錄頁面",
        },
        {
          path: '/panel',
          redirect: '/panel/index',
          meta: { title: '工作空間' },
          name: "工作空間",
          component: frameWork,
          children: [
            {
              path: '/panel',
              name: '工作臺',
              component: () => import('../../views/panel/index.vue'),
              meta: { title: '工作臺', requireAuth: true, affix: true, closable: false },
            }
          ]
        })
      View Code

      只留下固定的路由菜單,把菜單管理、用戶管理等菜單去掉,我們做動態獲取。

      修改路由守衛如下

      router.beforeEach((to: RouteLocationNormalized, from: RouteLocationNormalized, next: NavigationGuardNext) => {
        NProgress.start();
        const userStore = useUserStore();
        const endTime = new Date(userStore.expiresDate);
        const currentTime = new Date();
        to.path = to.path;
        if (to.meta.requireAuth && endTime < currentTime) {
          router.push('/login')
        }
        if (to.meta.requireAuth) {
          next();
        } else if (to.matched.length == 0) {
          next({ path: '/panel' })
        } else {
          next();
        }
      })

      這塊對比上次的代碼,是把next({ path: '/login' })換成了next({ path: '/panel' })。

      第二步:添加接口

      新建文件api->menu->index.ts

      import Http from '../http';
      export const getMenuTreeData = async function() {
          return await Http.get('/api/SysMenu/GetMenuTreeList');
       }

      該接口是上面我們編寫的獲取菜單接口

      第三步:遞歸菜單,并動態添加到路由中

        在store->user.ts文件如下,添加如下代碼

        該代碼是把后端獲取的樹形菜單數據,轉換成路由能認識的菜單。

      const defineRouteComponents: Record<string, any> = {
        frameWork: () => import('@/views/frameWork/index.vue')
      };
      const defineRouteComponentKeys = Object.keys(defineRouteComponents);
      export const setMenuData = (
        routeMap: any[],
      ) => {
        return routeMap
          .map(item => {
            const pathArray = item.component.split('/');
            const url = ref<any>();
            if (pathArray.length > 0) {
              if (pathArray.length === 3)
                url.value = import(`../${pathArray[1]}/${pathArray[2]}.vue`);
              if (pathArray.length === 4)
                url.value = import(`../${pathArray[1]}/${pathArray[2]}/${pathArray[3]}.vue`);
              if (pathArray.length === 5)
                url.value = import(`../${pathArray[1]}/${pathArray[2]}/${pathArray[3]}/${pathArray[4]}.vue`);
            };
            const { name, requireAuth, id } = item || {};
            const currentRouter: RouteRecordRaw = {
              // 如果路由設置了 path,則作為默認 path,否則 路由地址 動態拼接生成如 /dashboard/workplace
              path: item.path,
              // 路由名稱,建議唯一
              //name: `${item.id}`,
              // meta: 頁面標題, 菜單圖標, 頁面權限(供指令權限用,可去掉)
              meta: {
                name,
                requireAuth,
                id
              },
              name: item.name,
              children: [],
              // 該路由對應頁面的 組件 (動態加載 @/views/ 下面的路徑文件)
              component: item.component && defineRouteComponentKeys.includes(item.component)
                ? defineRouteComponents[item.component]
                : () => url.value,
      
            };
      
            // 為了防止出現后端返回結果不規范,處理有可能出現拼接出兩個 反斜杠
            if (!currentRouter.path.startsWith('http')) {
              currentRouter.path = currentRouter.path.replace('//', '/');
            }
      
            // 重定向
            item.redirect && (currentRouter.redirect = item.redirect);
            if (item.children != null) {
              // 子菜單,遞歸處理
              currentRouter.children = setMenuData(item.children);
            }
            if (currentRouter.children === undefined || currentRouter.children.length <= 0) {
              currentRouter.children;
            }
            return currentRouter;
          })
          .filter(item => item);
      };

      然后在defineStore的actions中添加如下方法

        actions: {
          //獲取菜單數據,并遞歸實現動態路由菜單
          async loadMenus() {
            new Promise<any>(async (resolve, reject) => {
              const { data, code, msg } = await getMenuTreeData();
              if (code == 200) {
                this.menus = data;
                var menuList = setMenuData(data) as RouteRecordRaw[]
                menuList.map(d => {
                  router.addRoute(d);
                })
                resolve(menuList);
              }
              else {
                this.menus = [];
                ElMessage({
                  message: msg,
                  type: "error",
                });
              }
            });
          },
        },

      user.ts完整代碼如下(動態路由菜單的核心)

      import { getMenuTreeData } from '@/api/menu';
      import router from '@/router';
      import { ElMessage } from 'element-plus';
      import { defineStore } from 'pinia'
      import { ref } from 'vue';
      import { RouteRecordRaw } from 'vue-router';
      export const useUserStore = defineStore(
        'user', {
        state: () => ({
          token: '',
          expiresDate: '',
          userInfo: {},
          menus: [] as any,
        }),
      
        actions: {
          //獲取菜單數據,并遞歸實現動態路由菜單
          async loadMenus() {
            new Promise<any>(async (resolve, reject) => {
              const { data, code, msg } = await getMenuTreeData();
              if (code == 200) {
                this.menus = data;
                var menuList = setMenuData(data) as RouteRecordRaw[]
                menuList.map(d => {
                  router.addRoute(d);
                })
                resolve(menuList);
              }
              else {
                this.menus = [];
                ElMessage({
                  message: msg,
                  type: "error",
                });
              }
            });
          },
        },
        persist: {
          enabled: true,
          strategies: [
            {
              // 可以是localStorage或sessionStorage
              storage: localStorage,
              // 指定需要持久化的屬性
              paths: ['token', 'expiresDate', 'userInfo', 'menus']
            }
          ]
        },
      })
      
      
      const defineRouteComponents: Record<string, any> = {
        frameWork: () => import('@/views/frameWork/index.vue')
      };
      const defineRouteComponentKeys = Object.keys(defineRouteComponents);
      export const setMenuData = (
        routeMap: any[],
      ) => {
        return routeMap
          .map(item => {
            const pathArray = item.component.split('/');
            const url = ref<any>();
            if (pathArray.length > 0) {
              if (pathArray.length === 3)
                url.value = import(`../${pathArray[1]}/${pathArray[2]}.vue`);
              if (pathArray.length === 4)
                url.value = import(`../${pathArray[1]}/${pathArray[2]}/${pathArray[3]}.vue`);
              if (pathArray.length === 5)
                url.value = import(`../${pathArray[1]}/${pathArray[2]}/${pathArray[3]}/${pathArray[4]}.vue`);
            };
            const { name, requireAuth, id } = item || {};
            const currentRouter: RouteRecordRaw = {
              // 如果路由設置了 path,則作為默認 path,否則 路由地址 動態拼接生成如 /dashboard/workplace
              path: item.path,
              // 路由名稱,建議唯一
              //name: `${item.id}`,
              // meta: 頁面標題, 菜單圖標, 頁面權限(供指令權限用,可去掉)
              meta: {
                name,
                requireAuth,
                id
              },
              name: item.name,
              children: [],
              // 該路由對應頁面的 組件 (動態加載 @/views/ 下面的路徑文件)
              component: item.component && defineRouteComponentKeys.includes(item.component)
                ? defineRouteComponents[item.component]
                : () => url.value,
      
            };
      
            // 為了防止出現后端返回結果不規范,處理有可能出現拼接出兩個 反斜杠
            if (!currentRouter.path.startsWith('http')) {
              currentRouter.path = currentRouter.path.replace('//', '/');
            }
      
            // 重定向
            item.redirect && (currentRouter.redirect = item.redirect);
            if (item.children != null) {
              // 子菜單,遞歸處理
              currentRouter.children = setMenuData(item.children);
            }
            if (currentRouter.children === undefined || currentRouter.children.length <= 0) {
              currentRouter.children;
            }
            return currentRouter;
          })
          .filter(item => item);
      };
      View Code

      編寫完以上代碼,我們已經獲取到后端的菜單,并且已添加到動態路由中。接下來只需要在登錄時,調用loadMenus()方法即可。

      第四步:登錄后獲取動態路由菜單

      如圖

      注意:替換frameWork文件夾下index.vue 文件中的代碼片段,如下圖

      第五步:傳入token

        當你辛苦完成以上步驟后,你迫不及待的想查看下效果。但是系統給你潑了一盆冷水,提示接口401錯誤。

      沒錯,會出現錯誤,因為我們系統使用了jwt鑒權,所以我們需要把token傳給后端,然后進行驗證。只有通過后才能訪問接口。

      那么要如何做才能把token傳給后端呢。

      在我們之前寫好的請求攔截中,加入如下代碼

      ps:不清楚請求攔截的,請觀看(系列十一)Vue3框架中路由守衛及請求攔截(實現前后端交互)

       /* 請求攔截 */
              this.service.interceptors.request.use((config: InternalAxiosRequestConfig) => {
                  //可以在這里做請求攔截處理   如:請求接口前,需要傳入的token
                  const userInfoStore = useUserStore();
                  if (userInfoStore.token) {
                      (config.headers as AxiosRequestHeaders).token = userInfoStore.token as string
                      config.headers["Authorization"] = "Bearer " + userInfoStore.token;
                  } else {
                      if (router.currentRoute.value.path !== '/login') {
                          router.push('/login');
                      }
                  }
                  return config
              }, (error: any) => {
                  ElMessage({
                      message: "接口調用失敗",
                      type: "error",
                  });
                  return error.message;
                  //return Promise.reject(error);
              })

      然后運行項目,你會發現,你的菜單實現了動態路由,全部由數據庫獲取。

      以上就是本篇文章的全部內容,感謝耐心觀看

      后端WebApi 預覽地址:http://139.155.137.144:8880/swagger/index.html

      前端vue 預覽地址:http://139.155.137.144:8881

      關注公眾號:發送【權限】,獲取前后端代碼

      有興趣的朋友,請關注我微信公眾號吧(*^▽^*)。

      關注我:一個全棧多端的寶藏博主,定時分享技術文章,不定時分享開源項目。關注我,帶你認識不一樣的程序世界

      posted @ 2024-12-10 17:12  陳逸子風  閱讀(1431)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 99热精品毛片全部国产无缓冲| 国产亚洲精品第一综合另类| 精品国产免费人成在线观看| 巨爆乳中文字幕爆乳区| 潮喷无码正在播放| 国产精品一区二区久久毛片| 丰满岳乱妇久久久| 亚洲精品成人一二三专区| 欧美午夜精品久久久久久浪潮| 亚洲国产一区二区精品专| 免费无码AV一区二区波多野结衣| 新绛县| 性做久久久久久久| 制服丝袜另类专区制服| 亚洲国产午夜精品理论片| 国产女人在线视频| 99热这里只有成人精品国产| 福利一区二区不卡国产| 青草青草久热国产精品| 中文国产成人精品久久一| 迁西县| 澳门永久av免费网站| 国产熟睡乱子伦视频在线播放| 欧美成人精品手机在线| 四虎永久精品在线视频| 国产又色又爽无遮挡免费动态图 | 99在线精品视频观看免费| 天天做天天躁天天躁| 国产一区二区不卡91| 亚洲Av综合日韩精品久久久| 人妻有码中文字幕在线| 国产偷人妻精品一区二区在线| 国产麻豆精品手机在线观看| 日韩精品一二区在线观看| 好男人官网资源在线观看| 日韩加勒比一本无码精品| 成人福利一区二区视频在线| 日韩福利视频导航| 色老头亚洲成人免费影院| 久久一卡二卡三卡四卡| 成av人片一区二区久久|