yanderong
2026-08-25 1b137a662cf48ddad94b48de606ac36061fac4dd
feat 用户角色菜单配置相关功能
2个文件已添加
14个文件已修改
429 ■■■■■ 已修改文件
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysMenuController.java 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRoleController.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysUserController.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/TBatteryGroupFieldController.java 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/TokenService.java 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/MenuPermissionVo.java 149 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysRoleMenuMapper.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/ISysMenuService.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserService.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysMenuServiceImpl.java 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysRoleServiceImpl.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/resources/mapper/system/SysRoleMapper.xml 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/resources/mapper/system/SysRoleMenuMapper.xml 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
sql/sys_menu_battery_detection.sql 101 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysMenuController.java
@@ -2,6 +2,7 @@
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
@@ -33,6 +34,16 @@
{
    @Autowired
    private ISysMenuService menuService;
    /**
     * 获取权限配置页面使用的全部模块、页面和按钮。
     */
    @PreAuthorize("@ss.hasPermi('system:menu:list')")
    @GetMapping("/permissionList")
    public AjaxResult permissionList()
    {
        return success(menuService.selectMenuPermissionList());
    }
    /**
     * 获取菜单列表
@@ -162,4 +173,4 @@
        }
        return toAjax(menuService.deleteMenuById(menuId));
    }
}
}
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRoleController.java
@@ -95,10 +95,10 @@
        {
            return error("新增角色'" + role.getRoleName() + "'失败,角色名称已存在");
        }
        else if (!roleService.checkRoleKeyUnique(role))
     /*   else if (!roleService.checkRoleKeyUnique(role))
        {
            return error("新增角色'" + role.getRoleName() + "'失败,角色权限已存在");
        }
        }*/
        role.setCreateBy(getUsername());
        return toAjax(roleService.insertRole(role));
@@ -117,10 +117,6 @@
        if (!roleService.checkRoleNameUnique(role))
        {
            return error("修改角色'" + role.getRoleName() + "'失败,角色名称已存在");
        }
        else if (!roleService.checkRoleKeyUnique(role))
        {
            return error("修改角色'" + role.getRoleName() + "'失败,角色权限已存在");
        }
        role.setUpdateBy(getUsername());
        
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysUserController.java
@@ -124,7 +124,6 @@
    @PostMapping
    public AjaxResult add(@Validated @RequestBody SysUser user)
    {
        deptService.checkDeptDataScope(user.getDeptId());
        roleService.checkRoleDataScope(user.getRoleIds());
        if (!userService.checkUserNameUnique(user))
        {
@@ -153,7 +152,6 @@
    {
        userService.checkUserAllowed(user);
        userService.checkUserDataScope(user.getUserId());
        deptService.checkDeptDataScope(user.getDeptId());
        roleService.checkRoleDataScope(user.getRoleIds());
        if (!userService.checkUserNameUnique(user))
        {
@@ -162,10 +160,6 @@
        else if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user))
        {
            return error("修改用户'" + user.getUserName() + "'失败,手机号码已存在");
        }
        else if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user))
        {
            return error("修改用户'" + user.getUserName() + "'失败,邮箱账号已存在");
        }
        user.setUpdateBy(getUsername());
        return toAjax(userService.updateUser(user));
@@ -253,4 +247,14 @@
    {
        return success(deptService.selectDeptTreeList(dept));
    }
    /**
     * 获取添加人选择框列表
     */
    @PreAuthorize("@ss.hasPermi('system:user:query')")
    @GetMapping("/optionselect")
    public AjaxResult optionselect()
    {
        return success(userService.selectUserAll());
    }
}
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/TBatteryGroupFieldController.java
@@ -56,7 +56,6 @@
    @PostMapping
    public AjaxResult add(@Validated @RequestBody TBatteryGroupField field)
    {
        field.setCreateBy(getUsername());
        return toAjax(batteryGroupFieldService.insertBatteryGroupField(field));
    }
ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/TokenService.java
@@ -9,6 +9,7 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import com.alibaba.fastjson2.JSON;
import com.ruoyi.common.constant.CacheConstants;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.model.LoginUser;
@@ -248,7 +249,8 @@
        }
        for (String key : keys)
        {
            LoginUser loginUser = redisCache.getCacheObject(key);
            Object cachedValue = redisCache.getCacheObject(key);
            LoginUser loginUser = toLoginUser(cachedValue, key);
            if (loginUser == null || loginUser.getUser() == null || loginUser.getUser().isAdmin())
            {
                // 管理员拥有所有权限,跳过
@@ -267,4 +269,29 @@
            log.info("角色[{}]权限变更,已刷新在线用户[{}]的权限缓存", roleId, loginUser.getUsername());
        }
    }
    /**
     * 兼容 Redis 中由旧序列化配置读取为 JSONObject 的登录缓存。
     */
    private LoginUser toLoginUser(Object cachedValue, String key)
    {
        if (cachedValue == null)
        {
            return null;
        }
        if (cachedValue instanceof LoginUser)
        {
            return (LoginUser) cachedValue;
        }
        try
        {
            return JSON.to(LoginUser.class, cachedValue);
        }
        catch (RuntimeException e)
        {
            log.warn("忽略无法转换的登录缓存[{}],实际类型为[{}]", key,
                    cachedValue.getClass().getName(), e);
            return null;
        }
    }
}
ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/MenuPermissionVo.java
New file
@@ -0,0 +1,149 @@
package com.ruoyi.system.domain.vo;
import java.util.ArrayList;
import java.util.List;
/**
 * 权限配置页面使用的模块、页面及按钮权限结构。
 */
public class MenuPermissionVo
{
    private Long menuId;
    private String moduleName;
    private List<Page> pages = new ArrayList<>();
    public MenuPermissionVo()
    {
    }
    public MenuPermissionVo(Long menuId, String moduleName)
    {
        this.menuId = menuId;
        this.moduleName = moduleName;
    }
    public Long getMenuId()
    {
        return menuId;
    }
    public void setMenuId(Long menuId)
    {
        this.menuId = menuId;
    }
    public String getModuleName()
    {
        return moduleName;
    }
    public void setModuleName(String moduleName)
    {
        this.moduleName = moduleName;
    }
    public List<Page> getPages()
    {
        return pages;
    }
    public void setPages(List<Page> pages)
    {
        this.pages = pages;
    }
    public static class Page
    {
        private Long menuId;
        private String pageName;
        private List<Permission> permissions = new ArrayList<>();
        public Page()
        {
        }
        public Page(Long menuId, String pageName)
        {
            this.menuId = menuId;
            this.pageName = pageName;
        }
        public Long getMenuId()
        {
            return menuId;
        }
        public void setMenuId(Long menuId)
        {
            this.menuId = menuId;
        }
        public String getPageName()
        {
            return pageName;
        }
        public void setPageName(String pageName)
        {
            this.pageName = pageName;
        }
        public List<Permission> getPermissions()
        {
            return permissions;
        }
        public void setPermissions(List<Permission> permissions)
        {
            this.permissions = permissions;
        }
    }
    public static class Permission
    {
        private Long menuId;
        private String menuName;
        private String perms;
        public Permission()
        {
        }
        public Permission(Long menuId, String menuName, String perms)
        {
            this.menuId = menuId;
            this.menuName = menuName;
            this.perms = perms;
        }
        public Long getMenuId()
        {
            return menuId;
        }
        public void setMenuId(Long menuId)
        {
            this.menuId = menuId;
        }
        public String getMenuName()
        {
            return menuName;
        }
        public void setMenuName(String menuName)
        {
            this.menuName = menuName;
        }
        public String getPerms()
        {
            return perms;
        }
        public void setPerms(String perms)
        {
            this.perms = perms;
        }
    }
}
ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysRoleMenuMapper.java
@@ -41,4 +41,6 @@
     * @return 结果
     */
    public int batchRoleMenu(List<SysRoleMenu> roleMenuList);
    List<SysRoleMenu> selectByRoleId(Long roleId);
}
ruoyi-system/src/main/java/com/ruoyi/system/service/ISysMenuService.java
@@ -4,6 +4,7 @@
import java.util.Set;
import com.ruoyi.common.core.domain.TreeSelect;
import com.ruoyi.common.core.domain.entity.SysMenu;
import com.ruoyi.system.domain.vo.MenuPermissionVo;
import com.ruoyi.system.domain.vo.RouterVo;
/**
@@ -14,6 +15,13 @@
public interface ISysMenuService
{
    /**
     * 查询权限配置页面需要的全部模块、页面和按钮。
     *
     * @return 模块权限列表
     */
    public List<MenuPermissionVo> selectMenuPermissionList();
    /**
     * 根据用户查询系统菜单列表
     * 
     * @param userId 用户ID
ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserService.java
@@ -214,4 +214,11 @@
     * @return 结果
     */
    public String importUser(List<SysUser> userList, Boolean isUpdateSupport, String operName);
    /**
     * 查询所有人员
     *
     * @return 人员列表
     */
    List<SysUser> selectUserAll();
}
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysMenuServiceImpl.java
@@ -4,8 +4,10 @@
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import org.slf4j.Logger;
@@ -23,6 +25,7 @@
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.domain.vo.MetaVo;
import com.ruoyi.system.domain.vo.MenuPermissionVo;
import com.ruoyi.system.domain.vo.RouterVo;
import com.ruoyi.system.mapper.SysMenuMapper;
import com.ruoyi.system.mapper.SysRoleMapper;
@@ -53,6 +56,45 @@
    private SysRoleMenuMapper roleMenuMapper;
    /**
     * 查询全部菜单,并转换为权限配置表格直接使用的三级结构。
     */
    @Override
    public List<MenuPermissionVo> selectMenuPermissionList()
    {
        List<SysMenu> menus = menuMapper.selectMenuList(new SysMenu());
        Map<Long, MenuPermissionVo> modules = new LinkedHashMap<>();
        Map<Long, MenuPermissionVo.Page> pages = new LinkedHashMap<>();
        for (SysMenu menu : menus)
        {
            if (UserConstants.TYPE_DIR.equals(menu.getMenuType()) && MENU_ROOT_ID.equals(menu.getParentId()))
            {
                modules.put(menu.getMenuId(), new MenuPermissionVo(menu.getMenuId(), menu.getMenuName()));
            }
        }
        for (SysMenu menu : menus)
        {
            MenuPermissionVo module = modules.get(menu.getParentId());
            if (module != null && UserConstants.TYPE_MENU.equals(menu.getMenuType()))
            {
                MenuPermissionVo.Page page = new MenuPermissionVo.Page(menu.getMenuId(), menu.getMenuName());
                module.getPages().add(page);
                pages.put(menu.getMenuId(), page);
            }
        }
        for (SysMenu menu : menus)
        {
            MenuPermissionVo.Page page = pages.get(menu.getParentId());
            if (page != null && UserConstants.TYPE_BUTTON.equals(menu.getMenuType()))
            {
                page.getPermissions().add(new MenuPermissionVo.Permission(
                        menu.getMenuId(), menu.getMenuName(), menu.getPerms()));
            }
        }
        return new ArrayList<>(modules.values());
    }
    /**
     * 根据用户查询系统菜单列表
     * 
     * @param userId 用户ID
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysRoleServiceImpl.java
@@ -1,10 +1,8 @@
package com.ruoyi.system.service.impl;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.*;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -135,7 +133,13 @@
    @Override
    public SysRole selectRoleById(Long roleId)
    {
        return roleMapper.selectRoleById(roleId);
        SysRole role = roleMapper.selectRoleById(roleId);
        List<SysRoleMenu> menus =roleMenuMapper.selectByRoleId(roleId);
        if(CollectionUtils.isNotEmpty(menus)) {
            role.setMenuIds(menus.stream().map(SysRoleMenu::getMenuId).toArray(Long[]::new));
        }
        return role;
    }
    /**
@@ -233,6 +237,7 @@
    @Transactional
    public int insertRole(SysRole role)
    {
        role.setRoleKey(role.getRoleName());
        // 新增角色信息
        roleMapper.insertRole(role);
        return insertRoleMenu(role);
@@ -248,6 +253,7 @@
    @Transactional
    public int updateRole(SysRole role)
    {
        role.setRoleKey(role.getRoleName());
        // 修改角色信息
        roleMapper.updateRole(role);
        // 删除角色与菜单关联
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java
@@ -562,4 +562,15 @@
        }
        return successMsg.toString();
    }
    /**
     * 查询所有人员
     *
     * @return 人员列表
     */
    @Override
    public List<SysUser> selectUserAll()
    {
        return userMapper.selectUserList(new SysUser());
    }
}
ruoyi-system/src/main/resources/mapper/system/SysRoleMapper.xml
@@ -53,7 +53,7 @@
        </if>
        <!-- 数据范围过滤 -->
        ${params.dataScope}
        order by r.role_sort
        order by r.create_time desc
    </select>
    
    <select id="selectRolePermissionByUserId" parameterType="Long" resultMap="SysRoleResult">
ruoyi-system/src/main/resources/mapper/system/SysRoleMenuMapper.xml
@@ -8,7 +8,7 @@
        <result property="roleId"     column="role_id"      />
        <result property="menuId"     column="menu_id"      />
    </resultMap>
    <select id="checkMenuExistRole" resultType="Integer">
        select count(1) from sys_role_menu where menu_id = #{menuId}
    </select>
@@ -30,5 +30,8 @@
            (#{item.roleId},#{item.menuId})
        </foreach>
    </insert>
    <select id="selectByRoleId" resultMap="SysRoleMenuResult">
        select * from sys_role_menu where role_id = #{roleId}
    </select>
</mapper> 
ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml
@@ -7,6 +7,7 @@
    <resultMap type="SysUser" id="SysUserResult">
        <id     property="userId"        column="user_id"         />
        <result property="deptId"        column="dept_id"         />
        <result property="roleId"        column="role_id"         />
        <result property="userName"      column="user_name"       />
        <result property="nickName"      column="nick_name"       />
        <result property="email"         column="email"           />
@@ -58,14 +59,17 @@
    </sql>
    
    <select id="selectUserList" parameterType="SysUser" resultMap="SysUserResult">
        select u.user_id, u.dept_id, u.nick_name, u.user_name, u.email, u.avatar, u.phonenumber, u.sex, u.status, u.del_flag, u.login_ip, u.login_date, u.create_by, u.create_time, u.remark, d.dept_name, d.leader from sys_user u
        left join sys_dept d on u.dept_id = d.dept_id
        select u.user_id, u.dept_id, u.nick_name, u.user_name, u.email, u.avatar, u.phonenumber, u.sex, u.status, u.del_flag, u.login_ip, u.login_date, u.create_by, u.create_time, u.remark, r.role_id from sys_user u
        left join sys_user_role r on u.user_id = r.user_id
        where u.del_flag = '0'
        <if test="userId != null and userId != 0">
            AND u.user_id = #{userId}
        </if>
        <if test="userName != null and userName != ''">
            AND u.user_name like concat('%', #{userName}, '%')
        </if>
        <if test="nickName != null and nickName != ''">
            AND u.nick_name like concat('%', #{nickName}, '%')
        </if>
        <if test="status != null and status != ''">
            AND u.status = #{status}
@@ -79,11 +83,10 @@
        <if test="params.endTime != null and params.endTime != ''"><!-- 结束时间检索 -->
            AND date_format(u.create_time,'%Y%m%d') &lt;= date_format(#{params.endTime},'%Y%m%d')
        </if>
        <if test="deptId != null and deptId != 0">
            AND (u.dept_id = #{deptId} OR u.dept_id IN ( SELECT t.dept_id FROM sys_dept t WHERE find_in_set(#{deptId}, ancestors) ))
        <if test="roleId != null and roleId != 0">
            AND r.role_id = #{roleId}
        </if>
        <!-- 数据范围过滤 -->
        ${params.dataScope}
        order by u.create_time desc
    </select>
    
    <select id="selectAllocatedList" parameterType="SysUser" resultMap="SysUserResult">
sql/sys_menu_battery_detection.sql
New file
@@ -0,0 +1,101 @@
-- BatteryDetection 菜单及按钮权限。
-- ID 从 sys_menu 当前最大值之后分配,可重复用于不同初始数据环境;本脚本本身请勿重复执行。
SET @menu_base := (SELECT COALESCE(MAX(menu_id), 0) FROM sys_menu);
INSERT INTO sys_menu
    (menu_id, menu_name, parent_id, order_num, path, component, query, route_name,
     is_frame, is_cache, menu_type, visible, status, perms, icon,
     create_by, create_time, update_by, update_time, remark)
VALUES
    -- 首页
    (@menu_base + 1,  '首页', 0, 1, 'home', NULL, NULL, 'Home', 1, 0, 'M', '0', '0', NULL, 'dashboard', 'admin', NOW(), '', NULL, '首页目录'),
    (@menu_base + 2,  '工作台', @menu_base + 1, 1, 'workbench', 'dashboard/workbench/index', NULL, 'Workbench', 1, 0, 'C', '0', '0', 'dashboard:workbench:list', 'dashboard', 'admin', NOW(), '', NULL, '工作台菜单'),
    (@menu_base + 3,  '工作台查看', @menu_base + 2, 1, '', NULL, NULL, '', 1, 0, 'F', '0', '0', 'dashboard:workbench:query', '#', 'admin', NOW(), '', NULL, ''),
    -- 测试管理
    (@menu_base + 4,  '测试管理', 0, 2, 'testManagement', NULL, NULL, 'TestManagement', 1, 0, 'M', '0', '0', NULL, 'experiment', 'admin', NOW(), '', NULL, '测试管理目录'),
    (@menu_base + 5,  '测试列表', @menu_base + 4, 1, 'test', 'system/test/index', NULL, 'Test', 1, 0, 'C', '0', '0', 'system:test:list', 'list', 'admin', NOW(), '', NULL, '测试列表菜单'),
    (@menu_base + 6,  '测试查看', @menu_base + 5, 1, '', NULL, NULL, '', 1, 0, 'F', '0', '0', 'system:test:query', '#', 'admin', NOW(), '', NULL, ''),
    (@menu_base + 7,  '测试新增', @menu_base + 5, 2, '', NULL, NULL, '', 1, 0, 'F', '0', '0', 'system:test:add', '#', 'admin', NOW(), '', NULL, ''),
    (@menu_base + 8,  '测试编辑', @menu_base + 5, 3, '', NULL, NULL, '', 1, 0, 'F', '0', '0', 'system:test:edit', '#', 'admin', NOW(), '', NULL, ''),
    (@menu_base + 9,  '测试删除', @menu_base + 5, 4, '', NULL, NULL, '', 1, 0, 'F', '0', '0', 'system:test:remove', '#', 'admin', NOW(), '', NULL, ''),
    (@menu_base + 10, '测试下载', @menu_base + 5, 5, '', NULL, NULL, '', 1, 0, 'F', '0', '0', 'system:test:export', '#', 'admin', NOW(), '', NULL, ''),
    (@menu_base + 11, '电池组管理', @menu_base + 4, 2, 'batteryGroup', 'system/batteryGroup/index', NULL, 'BatteryGroup', 1, 0, 'C', '0', '0', 'system:batteryGroup:list', 'tree', 'admin', NOW(), '', NULL, '电池组管理菜单'),
    (@menu_base + 12, '电池组查看', @menu_base + 11, 1, '', NULL, NULL, '', 1, 0, 'F', '0', '0', 'system:batteryGroup:query', '#', 'admin', NOW(), '', NULL, ''),
    (@menu_base + 13, '电池组新增', @menu_base + 11, 2, '', NULL, NULL, '', 1, 0, 'F', '0', '0', 'system:batteryGroup:add', '#', 'admin', NOW(), '', NULL, ''),
    (@menu_base + 14, '电池组编辑', @menu_base + 11, 3, '', NULL, NULL, '', 1, 0, 'F', '0', '0', 'system:batteryGroup:edit', '#', 'admin', NOW(), '', NULL, ''),
    (@menu_base + 15, '电池组启用/禁用', @menu_base + 11, 4, '', NULL, NULL, '', 1, 0, 'F', '0', '0', 'system:batteryGroup:changeStatus', '#', 'admin', NOW(), '', NULL, ''),
    (@menu_base + 16, '电池组删除', @menu_base + 11, 5, '', NULL, NULL, '', 1, 0, 'F', '0', '0', 'system:batteryGroup:remove', '#', 'admin', NOW(), '', NULL, ''),
    (@menu_base + 17, '测试类型管理', @menu_base + 4, 3, 'testType', 'system/testType/index', NULL, 'TestType', 1, 0, 'C', '0', '0', 'system:testType:list', 'dict', 'admin', NOW(), '', NULL, '测试类型管理菜单'),
    (@menu_base + 18, '测试类型查看', @menu_base + 17, 1, '', NULL, NULL, '', 1, 0, 'F', '0', '0', 'system:testType:query', '#', 'admin', NOW(), '', NULL, ''),
    (@menu_base + 19, '测试类型新增', @menu_base + 17, 2, '', NULL, NULL, '', 1, 0, 'F', '0', '0', 'system:testType:add', '#', 'admin', NOW(), '', NULL, ''),
    (@menu_base + 20, '测试类型编辑', @menu_base + 17, 3, '', NULL, NULL, '', 1, 0, 'F', '0', '0', 'system:testType:edit', '#', 'admin', NOW(), '', NULL, ''),
    (@menu_base + 21, '测试类型启用/禁用', @menu_base + 17, 4, '', NULL, NULL, '', 1, 0, 'F', '0', '0', 'system:testType:edit', '#', 'admin', NOW(), '', NULL, ''),
    (@menu_base + 22, '测试类型删除', @menu_base + 17, 5, '', NULL, NULL, '', 1, 0, 'F', '0', '0', 'system:testType:remove', '#', 'admin', NOW(), '', NULL, ''),
    (@menu_base + 23, '数据修订记录', @menu_base + 4, 4, 'dataRevision', 'system/dataRevision/index', NULL, 'DataRevision', 1, 0, 'C', '0', '0', 'system:dataRevision:list', 'documentation', 'admin', NOW(), '', NULL, '数据修订记录菜单'),
    (@menu_base + 24, '修订记录查看', @menu_base + 23, 1, '', NULL, NULL, '', 1, 0, 'F', '0', '0', 'system:dataRevision:query', '#', 'admin', NOW(), '', NULL, ''),
    (@menu_base + 25, '修订记录下载', @menu_base + 23, 2, '', NULL, NULL, '', 1, 0, 'F', '0', '0', 'system:dataRevision:export', '#', 'admin', NOW(), '', NULL, ''),
    (@menu_base + 26, '异常管理', @menu_base + 4, 5, 'exception', 'system/exception/index', NULL, 'ExceptionManagement', 1, 0, 'C', '0', '0', 'system:exception:list', 'warning', 'admin', NOW(), '', NULL, '异常管理菜单'),
    (@menu_base + 27, '异常查看', @menu_base + 26, 1, '', NULL, NULL, '', 1, 0, 'F', '0', '0', 'system:exception:query', '#', 'admin', NOW(), '', NULL, ''),
    (@menu_base + 28, '异常处理', @menu_base + 26, 2, '', NULL, NULL, '', 1, 0, 'F', '0', '0', 'system:exception:handle', '#', 'admin', NOW(), '', NULL, ''),
    (@menu_base + 29, '异常删除', @menu_base + 26, 3, '', NULL, NULL, '', 1, 0, 'F', '0', '0', 'system:exception:remove', '#', 'admin', NOW(), '', NULL, ''),
    (@menu_base + 30, '异常下载', @menu_base + 26, 4, '', NULL, NULL, '', 1, 0, 'F', '0', '0', 'system:exception:export', '#', 'admin', NOW(), '', NULL, ''),
    -- 设备管理
    (@menu_base + 31, '设备管理', 0, 3, 'deviceManagement', NULL, NULL, 'DeviceManagement', 1, 0, 'M', '0', '0', NULL, 'component', 'admin', NOW(), '', NULL, '设备管理目录'),
    (@menu_base + 32, '检测柜', @menu_base + 31, 1, 'detectionCabinet', 'system/detectionCabinet/index', NULL, 'DetectionCabinet', 1, 0, 'C', '0', '0', 'system:detectionCabinet:list', 'server', 'admin', NOW(), '', NULL, '检测柜菜单'),
    (@menu_base + 33, '检测柜查看', @menu_base + 32, 1, '', NULL, NULL, '', 1, 0, 'F', '0', '0', 'system:detectionCabinet:query', '#', 'admin', NOW(), '', NULL, ''),
    (@menu_base + 34, '检测柜新增', @menu_base + 32, 2, '', NULL, NULL, '', 1, 0, 'F', '0', '0', 'system:detectionCabinet:add', '#', 'admin', NOW(), '', NULL, ''),
    (@menu_base + 35, '检测柜编辑', @menu_base + 32, 3, '', NULL, NULL, '', 1, 0, 'F', '0', '0', 'system:detectionCabinet:edit', '#', 'admin', NOW(), '', NULL, ''),
    (@menu_base + 36, '检测柜启用/禁用', @menu_base + 32, 4, '', NULL, NULL, '', 1, 0, 'F', '0', '0', 'system:detectionCabinet:changeStatus', '#', 'admin', NOW(), '', NULL, ''),
    (@menu_base + 37, '检测柜删除', @menu_base + 32, 5, '', NULL, NULL, '', 1, 0, 'F', '0', '0', 'system:detectionCabinet:remove', '#', 'admin', NOW(), '', NULL, ''),
    (@menu_base + 38, '采集器', @menu_base + 31, 2, 'collector', 'system/collector/index', NULL, 'Collector', 1, 0, 'C', '0', '0', 'system:collector:list', 'monitor', 'admin', NOW(), '', NULL, '采集器菜单'),
    (@menu_base + 39, '采集器查看', @menu_base + 38, 1, '', NULL, NULL, '', 1, 0, 'F', '0', '0', 'system:collector:query', '#', 'admin', NOW(), '', NULL, ''),
    (@menu_base + 40, '采集器新增', @menu_base + 38, 2, '', NULL, NULL, '', 1, 0, 'F', '0', '0', 'system:collector:add', '#', 'admin', NOW(), '', NULL, ''),
    (@menu_base + 41, '采集器编辑', @menu_base + 38, 3, '', NULL, NULL, '', 1, 0, 'F', '0', '0', 'system:collector:edit', '#', 'admin', NOW(), '', NULL, ''),
    (@menu_base + 42, '采集器启用/禁用', @menu_base + 38, 4, '', NULL, NULL, '', 1, 0, 'F', '0', '0', 'system:collector:edit', '#', 'admin', NOW(), '', NULL, ''),
    (@menu_base + 43, '采集器删除', @menu_base + 38, 5, '', NULL, NULL, '', 1, 0, 'F', '0', '0', 'system:collector:remove', '#', 'admin', NOW(), '', NULL, ''),
    -- 数据分析
    (@menu_base + 44, '数据分析', 0, 4, 'dataAnalysis', NULL, NULL, 'DataAnalysis', 1, 0, 'M', '0', '0', NULL, 'chart', 'admin', NOW(), '', NULL, '数据分析目录'),
    (@menu_base + 45, '对比报表', @menu_base + 44, 1, 'comparisonReport', 'analysis/comparisonReport/index', NULL, 'ComparisonReport', 1, 0, 'C', '0', '0', 'analysis:comparisonReport:list', 'chart', 'admin', NOW(), '', NULL, '对比报表菜单'),
    (@menu_base + 46, '对比报表查看', @menu_base + 45, 1, '', NULL, NULL, '', 1, 0, 'F', '0', '0', 'analysis:comparisonReport:query', '#', 'admin', NOW(), '', NULL, ''),
    (@menu_base + 47, '对比报表新增', @menu_base + 45, 2, '', NULL, NULL, '', 1, 0, 'F', '0', '0', 'analysis:comparisonReport:add', '#', 'admin', NOW(), '', NULL, ''),
    (@menu_base + 48, '对比报表编辑', @menu_base + 45, 3, '', NULL, NULL, '', 1, 0, 'F', '0', '0', 'analysis:comparisonReport:edit', '#', 'admin', NOW(), '', NULL, ''),
    (@menu_base + 49, '对比报表删除', @menu_base + 45, 4, '', NULL, NULL, '', 1, 0, 'F', '0', '0', 'analysis:comparisonReport:remove', '#', 'admin', NOW(), '', NULL, ''),
    (@menu_base + 50, '对比报表下载', @menu_base + 45, 5, '', NULL, NULL, '', 1, 0, 'F', '0', '0', 'analysis:comparisonReport:export', '#', 'admin', NOW(), '', NULL, ''),
    (@menu_base + 51, '化成报表', @menu_base + 44, 2, 'formationReport', 'analysis/formationReport/index', NULL, 'FormationReport', 1, 0, 'C', '0', '0', 'analysis:formationReport:list', 'form', 'admin', NOW(), '', NULL, '化成报表菜单'),
    (@menu_base + 52, '化成报表查看', @menu_base + 51, 1, '', NULL, NULL, '', 1, 0, 'F', '0', '0', 'analysis:formationReport:query', '#', 'admin', NOW(), '', NULL, ''),
    (@menu_base + 53, '化成报表新增', @menu_base + 51, 2, '', NULL, NULL, '', 1, 0, 'F', '0', '0', 'analysis:formationReport:add', '#', 'admin', NOW(), '', NULL, ''),
    (@menu_base + 54, '化成报表编辑', @menu_base + 51, 3, '', NULL, NULL, '', 1, 0, 'F', '0', '0', 'analysis:formationReport:edit', '#', 'admin', NOW(), '', NULL, ''),
    (@menu_base + 55, '化成报表删除', @menu_base + 51, 4, '', NULL, NULL, '', 1, 0, 'F', '0', '0', 'analysis:formationReport:remove', '#', 'admin', NOW(), '', NULL, ''),
    (@menu_base + 56, '化成报表下载', @menu_base + 51, 5, '', NULL, NULL, '', 1, 0, 'F', '0', '0', 'analysis:formationReport:export', '#', 'admin', NOW(), '', NULL, ''),
    (@menu_base + 57, '拼接报表', @menu_base + 44, 3, 'spliceReport', 'analysis/spliceReport/index', NULL, 'SpliceReport', 1, 0, 'C', '0', '0', 'analysis:spliceReport:list', 'table', 'admin', NOW(), '', NULL, '拼接报表菜单'),
    (@menu_base + 58, '拼接报表查看', @menu_base + 57, 1, '', NULL, NULL, '', 1, 0, 'F', '0', '0', 'analysis:spliceReport:query', '#', 'admin', NOW(), '', NULL, ''),
    (@menu_base + 59, '拼接报表新增', @menu_base + 57, 2, '', NULL, NULL, '', 1, 0, 'F', '0', '0', 'analysis:spliceReport:add', '#', 'admin', NOW(), '', NULL, ''),
    (@menu_base + 60, '拼接报表编辑', @menu_base + 57, 3, '', NULL, NULL, '', 1, 0, 'F', '0', '0', 'analysis:spliceReport:edit', '#', 'admin', NOW(), '', NULL, ''),
    (@menu_base + 61, '拼接报表删除', @menu_base + 57, 4, '', NULL, NULL, '', 1, 0, 'F', '0', '0', 'analysis:spliceReport:remove', '#', 'admin', NOW(), '', NULL, ''),
    -- 代办管理(名称按图片原文)
    (@menu_base + 62, '代办管理', 0, 5, 'todoManagement', NULL, NULL, 'TodoManagement', 1, 0, 'M', '0', '0', NULL, 'todo', 'admin', NOW(), '', NULL, '代办管理目录'),
    (@menu_base + 63, '待办列表', @menu_base + 62, 1, 'todo', 'todo/list/index', NULL, 'TodoList', 1, 0, 'C', '0', '0', 'todo:list:list', 'list', 'admin', NOW(), '', NULL, '待办列表菜单'),
    (@menu_base + 64, '待办查看', @menu_base + 63, 1, '', NULL, NULL, '', 1, 0, 'F', '0', '0', 'todo:list:query', '#', 'admin', NOW(), '', NULL, ''),
    (@menu_base + 65, '待办新增', @menu_base + 63, 2, '', NULL, NULL, '', 1, 0, 'F', '0', '0', 'todo:list:add', '#', 'admin', NOW(), '', NULL, ''),
    (@menu_base + 66, '待办处理', @menu_base + 63, 3, '', NULL, NULL, '', 1, 0, 'F', '0', '0', 'todo:list:handle', '#', 'admin', NOW(), '', NULL, ''),
    (@menu_base + 67, '待办删除', @menu_base + 63, 4, '', NULL, NULL, '', 1, 0, 'F', '0', '0', 'todo:list:remove', '#', 'admin', NOW(), '', NULL, ''),
    -- 角色与权限
    (@menu_base + 68, '角色与权限', 0, 6, 'rolePermission', NULL, NULL, 'RolePermission', 1, 0, 'M', '0', '0', NULL, 'peoples', 'admin', NOW(), '', NULL, '角色与权限目录'),
    (@menu_base + 69, '账号管理', @menu_base + 68, 1, 'account', 'system/user/index', NULL, 'Account', 1, 0, 'C', '0', '0', 'system:user:list', 'user', 'admin', NOW(), '', NULL, '账号管理菜单'),
    (@menu_base + 70, '账号查看', @menu_base + 69, 1, '', NULL, NULL, '', 1, 0, 'F', '0', '0', 'system:user:query', '#', 'admin', NOW(), '', NULL, ''),
    (@menu_base + 71, '账号新增', @menu_base + 69, 2, '', NULL, NULL, '', 1, 0, 'F', '0', '0', 'system:user:add', '#', 'admin', NOW(), '', NULL, ''),
    (@menu_base + 72, '账号编辑', @menu_base + 69, 3, '', NULL, NULL, '', 1, 0, 'F', '0', '0', 'system:user:edit', '#', 'admin', NOW(), '', NULL, ''),
    (@menu_base + 73, '账号启用/禁用', @menu_base + 69, 4, '', NULL, NULL, '', 1, 0, 'F', '0', '0', 'system:user:edit', '#', 'admin', NOW(), '', NULL, ''),
    (@menu_base + 74, '重置密码', @menu_base + 69, 5, '', NULL, NULL, '', 1, 0, 'F', '0', '0', 'system:user:resetPwd', '#', 'admin', NOW(), '', NULL, ''),
    (@menu_base + 75, '账号删除', @menu_base + 69, 6, '', NULL, NULL, '', 1, 0, 'F', '0', '0', 'system:user:remove', '#', 'admin', NOW(), '', NULL, ''),
    (@menu_base + 76, '角色管理', @menu_base + 68, 2, 'role', 'system/role/index', NULL, 'Role', 1, 0, 'C', '0', '0', 'system:role:list', 'peoples', 'admin', NOW(), '', NULL, '角色管理菜单'),
    (@menu_base + 77, '角色查看', @menu_base + 76, 1, '', NULL, NULL, '', 1, 0, 'F', '0', '0', 'system:role:query', '#', 'admin', NOW(), '', NULL, ''),
    (@menu_base + 78, '角色新增', @menu_base + 76, 2, '', NULL, NULL, '', 1, 0, 'F', '0', '0', 'system:role:add', '#', 'admin', NOW(), '', NULL, ''),
    (@menu_base + 79, '角色编辑', @menu_base + 76, 3, '', NULL, NULL, '', 1, 0, 'F', '0', '0', 'system:role:edit', '#', 'admin', NOW(), '', NULL, ''),
    (@menu_base + 80, '角色删除', @menu_base + 76, 4, '', NULL, NULL, '', 1, 0, 'F', '0', '0', 'system:role:remove', '#', 'admin', NOW(), '', NULL, '');