# FIIH质量管理模块菜单改造方案(无需修改数据库) ## 1. 需求背景 目前FIIH质量管理模块的所有质检数据都在同一个质检配置表中展示,需求是将不同对象体(`fiih_object_name`)的质检数据拆分为独立的二级菜单,并实现自动创建这些二级菜单的功能。且要求不修改数据库结构,不添加新表。 ## 2. 现有结构分析 ### 2.1 菜单结构 当前FIIH质量管理模块的菜单结构: - FIIH质量管理(一级菜单,ID: 2421) - 质检配置表(二级菜单,ID: 2422) ### 2.2 相关数据表 - `sys_menu`: 系统菜单表 - `ymes_fiih_config`: FIIH质量管理配置表(包含fiih_object_name字段) - `sys_config`: 系统参数表(用于存储菜单相关配置) ### 2.3 代码结构 - 前端: - 质检配置表页面:`mes-ui/src/views/mes/fiih/index.vue` - 质检详情页面:`mes-ui/src/views/mes/fiih/fiihDetailByTaskId.vue` - API接口:`mes-ui/src/api/mes/fiih/fiihConfig.js` - 后端: - 控制器:`FiihConfigController.java` - 服务接口:`IFiihConfigService.java` - 服务实现:`FiihConfigServiceImpl.java` ### 2.4 FIIH配置表结构 ```sql CREATE TABLE `ymes_fiih_config` ( `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID', `fiih_object_name` varchar(50) NOT NULL COMMENT '对象体名称', -- 作为菜单分类依据 `fiih_link_id` bigint NOT NULL COMMENT '环节ID(单次环节)', `fiih_link_name` varchar(100) NOT NULL COMMENT '环节名称', `fiih_task_id` bigint NOT NULL COMMENT '任务ID(总体)', `fiih_task_name` varchar(100) NOT NULL COMMENT '任务名称', -- 其他字段省略 `fiih_info_json` text COMMENT '以上信息属性JSON', `fiih_query_json` text COMMENT '以上信息查询属性JSON', -- 其他字段省略 PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=25 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='FIIH质量管理配置表'; ``` ## 3. 改造方案 ### 3.1 利用现有数据结构 不创建新表,直接利用现有的`fiih_object_name`字段作为菜单分类依据: 1. **使用`fiih_object_name`字段区分不同类型的质检数据**: 每个独特的`fiih_object_name`值对应一个二级菜单 2. **使用系统参数表(sys_config)存储已创建的菜单映射**: ```json config_key: fiih_object_menus config_value: [ {"objectName":"产品A","menuId":2450,"orderNum":1}, {"objectName":"产品B","menuId":2451,"orderNum":2} ] ``` ### 3.2 后端实现 #### 3.2.1 基于对象名称实现菜单创建 需要实现的核心功能是:对`fiih_object_name`进行分组,为每个唯一值创建一个二级菜单。 1. **添加获取所有对象名称的方法**: ```java /** * 获取所有唯一的对象名称 */ public List getAllObjectNames() { return fiihConfigMapper.selectDistinctObjectNames(); } ``` 2. **添加对应的Mapper方法**: ```xml ``` #### 3.2.2 实现菜单创建和更新 在`FiihConfigController.java`中添加自动创建菜单的方法: ```java /** * 自动创建所有对象的菜单 */ @PreAuthorize("@ss.hasPermi('fiih:config:menu')") @PostMapping("/createObjectMenus") public AjaxResult createObjectMenus() { try { // 获取所有对象名称 List objectNames = fiihConfigService.getAllObjectNames(); // 获取已存在的对象菜单映射 Map existingMenus = getExistingObjectMenus(); // 创建或更新对象菜单 List> results = new ArrayList<>(); for (String objectName : objectNames) { if (!existingMenus.containsKey(objectName)) { // 创建新菜单 Long menuId = createObjectMenu(objectName); if (menuId != null) { Map result = new HashMap<>(); result.put("objectName", objectName); result.put("menuId", menuId); result.put("status", "created"); results.add(result); // 更新已存在菜单映射 existingMenus.put(objectName, menuId); } } else { Map result = new HashMap<>(); result.put("objectName", objectName); result.put("menuId", existingMenus.get(objectName)); result.put("status", "existing"); results.add(result); } } // 更新系统参数中的对象菜单映射 updateObjectMenusConfig(existingMenus); return AjaxResult.success("FIIH对象菜单创建成功", results); } catch (Exception e) { log.error("创建对象菜单失败", e); return AjaxResult.error("创建对象菜单失败: " + e.getMessage()); } } /** * 为对象创建二级菜单 */ private Long createObjectMenu(String objectName) { try { // 生成路径:将对象名称转换为小写并移除空格 String path = objectName.toLowerCase().replaceAll("\\s+", ""); // 检查菜单是否已存在 SysMenu existingMenu = sysMenuMapper.selectMenuByPath("fiih/" + path); if (existingMenu != null) { return existingMenu.getMenuId(); } // 获取FIIH质量管理菜单ID Long parentId = 2421L; // FIIH质量管理的菜单ID // 创建新菜单 SysMenu menu = new SysMenu(); menu.setMenuName(objectName); menu.setParentId(parentId); menu.setOrderNum(10); menu.setPath(path); menu.setComponent("mes/fiih/objectView/index"); menu.setIsFrame("1"); menu.setIsCache("0"); menu.setMenuType("C"); menu.setVisible("0"); menu.setStatus("0"); menu.setPerms("fiih:config:list"); menu.setIcon("clipboard"); int result = sysMenuMapper.insertMenu(menu); if (result > 0) { return menu.getMenuId(); } } catch (Exception e) { log.error("创建对象菜单失败: " + objectName, e); } return null; } /** * 获取已存在的对象菜单映射 */ private Map getExistingObjectMenus() { String configValue = configService.selectConfigByKey("fiih_object_menus"); Map result = new HashMap<>(); if (StringUtils.isNotEmpty(configValue)) { try { JSONArray jsonArray = JSON.parseArray(configValue); for (int i = 0; i < jsonArray.size(); i++) { JSONObject json = jsonArray.getJSONObject(i); String objectName = json.getString("objectName"); Long menuId = json.getLong("menuId"); if (StringUtils.isNotEmpty(objectName) && menuId != null) { result.put(objectName, menuId); } } } catch (Exception e) { log.error("解析对象菜单映射失败", e); } } return result; } /** * 更新系统参数中的对象菜单映射 */ private void updateObjectMenusConfig(Map objectMenus) { JSONArray jsonArray = new JSONArray(); int orderNum = 1; for (Map.Entry entry : objectMenus.entrySet()) { JSONObject json = new JSONObject(); json.put("objectName", entry.getKey()); json.put("menuId", entry.getValue()); json.put("orderNum", orderNum++); jsonArray.add(json); } String configValue = jsonArray.toJSONString(); // 检查配置是否已存在 SysConfig config = configService.checkConfigKeyUnique("fiih_object_menus"); if (config != null) { // 更新现有配置 config.setConfigValue(configValue); configService.updateConfig(config); } else { // 创建新配置 config = new SysConfig(); config.setConfigName("FIIH对象菜单映射"); config.setConfigKey("fiih_object_menus"); config.setConfigValue(configValue); config.setConfigType("N"); // 非内置 configService.insertConfig(config); } } ``` #### 3.2.3 实现按对象名称查询配置的接口 在`FiihConfigController.java`中添加方法: ```java /** * 根据对象名称查询FIIH质量管理配置列表 */ @PreAuthorize("@ss.hasPermi('fiih:config:list')") @GetMapping("/listByObject/{objectName}") public TableDataInfo listByObjectName(@PathVariable("objectName") String objectName) { startPage(); FiihConfig fiihConfig = new FiihConfig(); fiihConfig.setFiihObjectName(objectName); List list = fiihConfigService.selectFiihConfigList(fiihConfig); return getDataTable(list); } /** * 获取所有对象名称及其菜单ID */ @PreAuthorize("@ss.hasPermi('fiih:config:list')") @GetMapping("/objects") public AjaxResult getAllObjects() { List objectNames = fiihConfigService.getAllObjectNames(); Map objectMenus = getExistingObjectMenus(); List> result = new ArrayList<>(); for (String objectName : objectNames) { Map obj = new HashMap<>(); obj.put("objectName", objectName); obj.put("menuId", objectMenus.getOrDefault(objectName, null)); result.add(obj); } return AjaxResult.success(result); } ### 3.3 前端实现 #### 3.3.1 创建对象菜单API接口 在 `mes-ui/src/api/mes/fiih/fiihConfig.js` 中添加新的接口方法: ```javascript import request from '@/utils/request' // 获取所有对象名称 export function getAllObjects() { return request({ url: '/fiih/config/objects', method: 'get' }) } // 根据对象名称查询配置数据 export function listFiihConfigByObject(objectName) { return request({ url: '/fiih/config/listByObject/' + encodeURIComponent(objectName), method: 'get' }) } // 自动创建所有对象菜单 export function createObjectMenus() { return request({ url: '/fiih/config/createObjectMenus', method: 'post' }) } ``` #### 3.3.2 创建对象视图组件 创建 `mes-ui/src/views/mes/fiih/objectView/index.vue` 页面,用于展示特定对象的数据: ```vue ``` #### 3.3.3 修改主页面以添加菜单创建功能 在 `mes-ui/src/views/mes/fiih/index.vue` 中添加自动创建菜单的功能: ```vue 创建对象菜单 ``` 添加对应的方法: ```javascript // 自动创建对象菜单 handleCreateMenus() { this.$modal.confirm('确认要自动创建所有对象的菜单吗?').then(() => { this.loading = true; createObjectMenus().then(response => { this.$modal.msgSuccess("菜单创建成功"); this.loading = false; // 刷新页面以显示新菜单 setTimeout(() => { window.location.reload(); }, 1000); }).catch(() => { this.loading = false; }); }); } ``` #### 3.3.4 添加对象名称筛选功能 在 `mes-ui/src/views/mes/fiih/index.vue` 中添加对象名称筛选功能: ```vue ``` 添加相关数据和方法: ```javascript data() { return { // 其他数据... objectOptions: [], // 对象名称选项 queryParams: { // 原有参数... fiihObjectName: null } } }, created() { this.getList(); this.getObjectOptions(); }, methods: { // 获取对象名称选项 getObjectOptions() { getAllObjects().then(response => { this.objectOptions = response.data; }); } } ``` #### 3.3.5 修改动态路由处理 在系统的路由配置中添加对象视图的路由处理。由于对象视图的路由是动态创建的,需要确保路由配置能正确处理。 在Vue路由配置中,确保有如下配置: ```javascript // 在路由文件中添加动态路由匹配(默认系统已有) { path: 'fiih/:path*', component: () => import('@/views/mes/fiih/objectView/index'), name: 'FiihObjectView', meta: { title: 'FIIH对象视图', activeMenu: '/mes/fiih' } } ``` ## 4. 使用流程 ### 4.1 管理员配置流程 1. 管理员进入FIIH质量管理配置页面 2. 点击创建对象菜单按钮,自动扫描已有的`fiih_object_name`值 3. 系统自动创建对应的二级菜单,并将映射保存在`sys_config`表中 ### 4.2 数据管理流程 1. 添加新配置时,指定`fiih_object_name`值 2. 系统自动将该数据与对应的对象菜单关联 3. 可通过对象名称筛选相关配置数据 ### 4.3 用户访问流程 1. 用户点击FIIH质量管理下的二级菜单(如某个对象名称) 2. 系统自动调用`listByObject`接口,查询并显示对应对象的所有数据 ## 5. 测试计划 1. 测试自动获取对象名称 - 验证`selectDistinctObjectNames`方法是否正常返回所有唯一对象名称 - 验证数据完整性 2. 测试自动创建菜单功能 - 用不同的对象名称测试菜单创建 - 验证菜单权限是否正确 - 验证菜单映射存储是否正常 3. 测试对象数据筛选 - 在主页面上验证对象名称筛选功能 - 验证筛选结果的准确性 4. 测试二级菜单数据访问 - 通过生成的二级菜单访问特定对象数据 - 验证数据筛选是否正确 - 验证数据展示是否正常 ## 6. 无需修改数据库的部署计划 1. 系统参数初始化 ```sql -- 初始化对象菜单映射配置 INSERT INTO `sys_config` (`config_name`, `config_key`, `config_value`, `config_type`, `create_by`, `create_time`, `remark`) VALUES ('FIIH对象菜单映射', 'fiih_object_menus', '[]', 'N', 'admin', NOW(), 'FIIH对象菜单映射,用于存储对象和菜单的关联关系'); ``` 2. 后端代码部署 - 增加获取所有对象名称的方法 - 实现自动创建菜单的功能 - 添加按对象名称查询的接口 - 实现对象菜单映射的存储和读取 3. 前端代码部署 - 添加创建对象菜单按钮 - 添加对象名称筛选功能 - 创建对象视图组件,用于显示特定对象的数据 - 更新路由配置以支持动态对象菜单 ## 7. 方案优势 1. **利用现有数据结构**:直接使用现有表中的`fiih_object_name`字段作为分类依据,无需添加额外字段或新表 2. **实现简单**:只需实现自动扫描和菜单创建功能,无需修改现有数据存储逻辑 3. **自动发现**:系统自动发现并创建所有对象菜单,无需手动配置 4. **动态扩展**:新添加的对象名称可自动创建相应菜单,无需修改代码 5. **向后兼容**:不破坏现有功能,原有的质检配置表页面保持不变 6. **部署简便**:无需执行数据库变更脚本,降低了部署风险