Skip to content

Latest commit

 

History

History
616 lines (522 loc) · 13.7 KB

File metadata and controls

616 lines (522 loc) · 13.7 KB

菜单管理API文档

概述

菜单管理API模块负责处理系统菜单的增删改查、菜单层级管理、动态路由生成等功能。

文件位置: src/api/menu.js

API接口

1. 获取菜单列表 - getMenuList

功能: 获取菜单列表数据,支持树形结构

请求方式: GET

接口地址: /menu/list

参数:

{
  page: number,        // 页码(可选,不传则返回全部)
  pageSize: number,    // 每页数量
  keyword: string,     // 搜索关键词(可选)
  parentId: number,    // 父菜单ID(可选)
  status: number,      // 状态筛选(可选)
  type: string        // 菜单类型筛选(可选)'menu'|'button'
}

返回数据:

{
  status: boolean,
  msg: string,
  data: {
    list: [
      {
        id: number,           // 菜单ID
        name: string,         // 菜单名称
        title: string,        // 菜单标题
        path: string,         // 路由路径
        component: string,    // 组件路径
        redirect: string,     // 重定向路径
        icon: string,         // 菜单图标
        parentId: number,     // 父菜单ID
        parentName: string,   // 父菜单名称
        level: number,        // 菜单层级
        sort: number,         // 排序权重
        type: string,         // 类型 'menu'-菜单 'button'-按钮
        status: number,       // 状态 1-启用 0-禁用
        visible: number,      // 是否显示 1-显示 0-隐藏
        cache: number,        // 是否缓存 1-缓存 0-不缓存
        breadcrumb: number,   // 是否显示面包屑 1-显示 0-隐藏
        affix: number,        // 是否固定标签 1-固定 0-不固定
        permission: string,   // 权限标识
        roles: string,        // 角色权限(JSON字符串)
        meta: {               // 路由元信息
          title: string,
          icon: string,
          roles: Array,
          noCache: boolean,
          breadcrumb: boolean,
          affix: boolean
        },
        createTime: string,   // 创建时间
        updateTime: string,   // 更新时间
        children: Array       // 子菜单列表
      }
    ],
    total: number,
    tree: Array           // 树形结构数据
  }
}

使用示例:

import { getMenuList } from '@/api/menu'

const loadMenus = async () => {
  try {
    const params = {
      status: 1,
      type: 'menu'
    }
    const result = await getMenuList(params)
    if (result.status) {
      console.log('菜单列表:', result.data.list)
      console.log('菜单树:', result.data.tree)
    }
  } catch (error) {
    console.error('获取菜单列表失败:', error)
  }
}

2. 获取菜单详情 - getMenuDetail

功能: 根据菜单ID获取菜单详细信息

请求方式: GET

接口地址: /menu/detail/{id}

参数:

{
  id: number  // 菜单ID
}

返回数据:

{
  status: boolean,
  data: {
    // 菜单详细信息,格式同列表接口中的单条记录
  }
}

3. 创建菜单 - createMenu

功能: 创建新菜单

请求方式: POST

接口地址: /menu/create

参数:

{
  name: string,         // 菜单名称(必填)
  title: string,        // 菜单标题(必填)
  path: string,         // 路由路径(必填)
  component: string,    // 组件路径(可选)
  redirect: string,     // 重定向路径(可选)
  icon: string,         // 菜单图标(可选)
  parentId: number,     // 父菜单ID(可选)
  sort: number,         // 排序权重(可选)
  type: string,         // 类型(必填)'menu'|'button'
  status: number,       // 状态(可选,默认1)
  visible: number,      // 是否显示(可选,默认1)
  cache: number,        // 是否缓存(可选,默认0)
  breadcrumb: number,   // 是否显示面包屑(可选,默认1)
  affix: number,        // 是否固定标签(可选,默认0)
  permission: string,   // 权限标识(可选)
  roles: Array         // 角色权限(可选)
}

返回数据:

{
  status: boolean,
  msg: string,
  data: {
    id: number  // 新创建的菜单ID
  }
}

4. 更新菜单 - updateMenu

功能: 更新菜单信息

请求方式: PUT

接口地址: /menu/update/{id}

参数:

{
  id: number,           // 菜单ID(必填)
  name: string,         // 菜单名称
  title: string,        // 菜单标题
  path: string,         // 路由路径
  component: string,    // 组件路径
  redirect: string,     // 重定向路径
  icon: string,         // 菜单图标
  parentId: number,     // 父菜单ID
  sort: number,         // 排序权重
  type: string,         // 类型
  status: number,       // 状态
  visible: number,      // 是否显示
  cache: number,        // 是否缓存
  breadcrumb: number,   // 是否显示面包屑
  affix: number,        // 是否固定标签
  permission: string,   // 权限标识
  roles: Array         // 角色权限
}

5. 删除菜单 - deleteMenu

功能: 删除菜单(软删除)

请求方式: DELETE

接口地址: /menu/delete/{id}

参数:

{
  id: number  // 菜单ID
}

返回数据:

{
  status: boolean,
  msg: string
}

6. 获取菜单树 - getMenuTree

功能: 获取菜单的树形结构,用于下拉选择

请求方式: GET

接口地址: /menu/tree

参数:

{
  type: string,        // 菜单类型筛选(可选)
  status: number,      // 状态筛选(可选)
  excludeId: number    // 排除的菜单ID(可选)
}

返回数据:

{
  status: boolean,
  data: [
    {
      id: number,
      name: string,
      title: string,
      level: number,
      children: [
        // 子菜单数据
      ]
    }
  ]
}

7. 移动菜单 - moveMenu

功能: 移动菜单到新的父菜单下

请求方式: PUT

接口地址: /menu/move

参数:

{
  id: number,              // 要移动的菜单ID
  targetParentId: number,  // 目标父菜单ID
  targetSort: number       // 目标排序位置
}

8. 批量更新菜单状态 - batchUpdateMenuStatus

功能: 批量启用或禁用菜单

请求方式: PUT

接口地址: /menu/batch-status

参数:

{
  ids: Array,          // 菜单ID数组
  status: number       // 目标状态 1-启用 0-禁用
}

9. 获取用户菜单 - getUserMenus

功能: 根据用户权限获取可访问的菜单

请求方式: GET

接口地址: /menu/user-menus

参数: 无(从token中获取用户信息)

返回数据:

{
  status: boolean,
  data: [
    {
      id: number,
      name: string,
      title: string,
      path: string,
      component: string,
      redirect: string,
      icon: string,
      meta: {
        title: string,
        icon: string,
        roles: Array,
        noCache: boolean,
        breadcrumb: boolean,
        affix: boolean
      },
      children: Array
    }
  ]
}

10. 刷新菜单缓存 - refreshMenuCache

功能: 刷新菜单缓存,重新生成路由

请求方式: POST

接口地址: /menu/refresh-cache

参数: 无

返回数据:

{
  status: boolean,
  msg: string
}

数据结构

Menu - 菜单信息

{
  id: number,           // 菜单ID
  name: string,         // 菜单名称(路由name)
  title: string,        // 菜单标题(显示名称)
  path: string,         // 路由路径
  component: string,    // 组件路径
  redirect: string,     // 重定向路径
  icon: string,         // 菜单图标
  parentId: number,     // 父菜单ID
  parentName: string,   // 父菜单名称
  level: number,        // 菜单层级(1为顶级)
  sort: number,         // 排序权重
  type: string,         // 类型 'menu'-菜单 'button'-按钮
  status: number,       // 状态 1-启用 0-禁用
  visible: number,      // 是否显示 1-显示 0-隐藏
  cache: number,        // 是否缓存 1-缓存 0-不缓存
  breadcrumb: number,   // 是否显示面包屑 1-显示 0-隐藏
  affix: number,        // 是否固定标签 1-固定 0-不固定
  permission: string,   // 权限标识
  roles: string,        // 角色权限(JSON字符串)
  meta: {               // 路由元信息
    title: string,
    icon: string,
    roles: Array,
    noCache: boolean,
    breadcrumb: boolean,
    affix: boolean
  },
  createTime: string,   // 创建时间
  updateTime: string,   // 更新时间
  children: Array       // 子菜单列表
}

MenuMeta - 路由元信息

{
  title: string,        // 菜单标题
  icon: string,         // 菜单图标
  roles: Array,         // 允许访问的角色
  noCache: boolean,     // 是否不缓存
  breadcrumb: boolean,  // 是否显示面包屑
  affix: boolean,       // 是否固定在标签栏
  hidden: boolean,      // 是否隐藏菜单
  alwaysShow: boolean,  // 是否总是显示根菜单
  activeMenu: string    // 高亮的菜单路径
}

业务规则

菜单层级

  • 支持多级菜单结构
  • 建议最大层级不超过3级
  • 删除父菜单时需要先处理子菜单

路由规则

  • 菜单路径必须以 / 开头
  • 子菜单路径可以是相对路径
  • 组件路径相对于 src/views 目录

权限控制

  • 菜单权限基于角色控制
  • 支持按钮级别的权限控制
  • 无权限的菜单不会显示

缓存策略

  • 页面组件可以设置是否缓存
  • 缓存基于路由name实现
  • 动态路由支持缓存

使用示例

创建菜单

import { createMenu } from '@/api/menu'

const addMenu = async () => {
  const menuData = {
    name: 'UserManagement',
    title: '用户管理',
    path: '/user',
    component: 'user/index',
    icon: 'user',
    parentId: 0,
    sort: 1,
    type: 'menu',
    status: 1,
    visible: 1,
    permission: 'user:view',
    roles: ['admin', 'manager']
  }
  
  try {
    const result = await createMenu(menuData)
    if (result.status) {
      ElMessage.success('菜单创建成功')
      // 刷新菜单列表
      loadMenus()
    }
  } catch (error) {
    ElMessage.error('菜单创建失败')
  }
}

获取用户菜单并生成路由

import { getUserMenus } from '@/api/menu'
import { generateRoutes } from '@/utils/dynamicRoutes'

const setupUserMenus = async () => {
  try {
    const result = await getUserMenus()
    if (result.status) {
      const menus = result.data
      
      // 生成动态路由
      const routes = generateRoutes(menus)
      
      // 添加到路由器
      routes.forEach(route => {
        router.addRoute(route)
      })
      
      // 保存到状态管理
      userStore.setMenus(menus)
    }
  } catch (error) {
    console.error('获取用户菜单失败:', error)
  }
}

菜单树形展示

<template>
  <el-tree
    :data="menuTree"
    :props="treeProps"
    node-key="id"
    :expand-on-click-node="false"
    :default-expand-all="true"
  >
    <template #default="{ node, data }">
      <div class="menu-tree-node">
        <el-icon v-if="data.icon">
          <component :is="data.icon" />
        </el-icon>
        <span>{{ data.title }}</span>
        <el-tag v-if="data.type === 'button'" size="small" type="info">
          按钮
        </el-tag>
        <el-tag v-if="data.status === 0" size="small" type="danger">
          禁用
        </el-tag>
      </div>
    </template>
  </el-tree>
</template>

<script setup>
import { ref, onMounted } from 'vue'
import { getMenuList } from '@/api/menu'

const menuTree = ref([])
const treeProps = {
  children: 'children',
  label: 'title'
}

const loadMenuTree = async () => {
  try {
    const result = await getMenuList()
    if (result.status) {
      menuTree.value = result.data.tree
    }
  } catch (error) {
    console.error('加载菜单树失败:', error)
  }
}

onMounted(() => {
  loadMenuTree()
})
</script>

错误处理

常见错误码

  • 30001: 菜单名称已存在
  • 30002: 菜单路径已存在
  • 30003: 父菜单不存在
  • 30004: 不能将菜单移动到自己的子菜单下
  • 30005: 菜单下还有子菜单,不能删除

错误处理示例

try {
  const result = await createMenu(menuData)
  if (!result.status) {
    switch (result.code) {
      case 30001:
        ElMessage.error('菜单名称已存在')
        break
      case 30002:
        ElMessage.error('菜单路径已存在')
        break
      default:
        ElMessage.error(result.msg || '操作失败')
    }
    return
  }
  // 处理成功逻辑
} catch (error) {
  console.error('菜单操作失败:', error)
  ElMessage.error('网络请求失败')
}

Mock数据

// src/mock/api.js
export const mockMenuList = {
  url: '/menu/list',
  method: 'get',
  response: {
    status: true,
    data: {
      list: [
        {
          id: 1,
          name: 'Dashboard',
          title: '首页',
          path: '/dashboard',
          component: 'dashboard/index',
          icon: 'dashboard',
          parentId: 0,
          level: 1,
          sort: 1,
          type: 'menu',
          status: 1,
          visible: 1,
          meta: {
            title: '首页',
            icon: 'dashboard',
            affix: true
          },
          children: []
        }
      ],
      tree: [
        // 树形结构数据
      ]
    }
  }
}

注意事项

  1. 路由同步: 菜单变更后需要刷新路由缓存
  2. 权限验证: 菜单权限要与后端接口权限保持一致
  3. 组件懒加载: 动态路由组件建议使用懒加载
  4. 缓存管理: 合理设置页面缓存策略
  5. 图标管理: 统一管理菜单图标资源

最后更新时间:2025-09-19