tuqin
8 天以前 2d79937de52efd14c1796620f1930d5a7cedba25
feat(safety): 安全生产二期 - 安全风险分级管控

按客户需求「建立安全风险分级管控与隐患排查治理双重预防机制」的第一重落地。

评估方法采用 LEC 法(格雷厄姆-金尼法):
D = L × E × C
D≥320 重大风险 / 160≤D<320 较大风险 / 70≤D<160 一般风险 / D<70 低风险

后端:
- 风险单元 MesSafetyRiskUnit(风险识别最小单元:车间设备/区域/作业活动)
- 风险清单 MesSafetyRisk(含 L/E/C 输入,D 值与风险等级由服务端自动计算)
- 五类管控措施字段:工程技术/管理/培训教育/个体防护/应急处置
- 删除风险单元时校验其下是否有风险清单,避免孤儿数据
- 编码唯一性校验(单元、风险各自独立)
- 错误码 1_040_904_xxx;字典常量 MES_SAFETY_*

前端:
- 风险单元管理页(增删改查 + 车间/责任人下拉)
- 风险清单管理页(L/E/C 选择后实时联动算出 D 与等级,弹窗顶部给出评估结论)
- 四色等级标签(重大红/较大橙/一般蓝/低绿)

SQL(mes_safety_risk_init.sql,可重复执行):
- 建表 2 张,菜单挂到「安全生产」目录下,字典 4 组

验证(线上实测):
- L=3,E=6,C=15 => D=270 较大风险
- L=10,E=10,C=100 => D=10000 重大风险
- L=1,E=1,C=1 => D=1 低风险
- 重复编码、删除有风险的单元均被正确拦截
已添加17个文件
已修改2个文件
1541 ■■■■■ 文件已修改
sql/mysql/mes_safety_risk_init.sql 173 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/safety/MesSafetyRiskController.java 165 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/safety/MesSafetyRiskUnitController.java 141 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/safety/vo/risk/MesSafetyRiskPageReqVO.java 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/safety/vo/risk/MesSafetyRiskRespVO.java 92 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/safety/vo/risk/MesSafetyRiskSaveReqVO.java 76 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/safety/vo/unit/MesSafetyRiskUnitPageReqVO.java 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/safety/vo/unit/MesSafetyRiskUnitRespVO.java 51 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/safety/vo/unit/MesSafetyRiskUnitSaveReqVO.java 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/safety/MesSafetyRiskDO.java 143 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/safety/MesSafetyRiskUnitDO.java 76 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/safety/MesSafetyRiskMapper.java 63 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/safety/MesSafetyRiskUnitMapper.java 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/DictTypeConstants.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/safety/MesSafetyRiskService.java 66 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/safety/MesSafetyRiskServiceImpl.java 160 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/safety/MesSafetyRiskUnitService.java 60 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/safety/MesSafetyRiskUnitServiceImpl.java 116 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
sql/mysql/mes_safety_risk_init.sql
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,173 @@
-- =====================================================================
-- å®‰å…¨ç”Ÿäº§æ¨¡å— â€”— äºŒæœŸï¼šå®‰å…¨é£Žé™©åˆ†çº§ç®¡æŽ§
--
-- å®šä½ï¼šåŒé‡é¢„防机制的第一重(风险分级管控)。先识别风险点、评估风险等级,
--       æ‰èƒ½æ®æ­¤å¼€å±•隐患排查(二期之后的能力点)。
--
-- è¯„估方法:LEC æ³•(格雷厄姆-金尼法)
--   D = L Ã— E Ã— C
--   L äº‹æ•…发生可能性        1 / 3 / 6 / 10
--   E æš´éœ²äºŽå±é™©çŽ¯å¢ƒé¢‘çŽ‡    0.5 / 1 / 2 / 3 / 6 / 10
--   C äº‹æ•…后果严重性        1 / 3 / 5 / 7 / 15 / 40 / 100
--   ç­‰çº§åˆ’分:D≥320 é‡å¤§(红);160≤D<320 è¾ƒå¤§(橙);70≤D<160 ä¸€èˆ¬(黄);D<70 ä½Ž(蓝)
--
-- å†…容:
--   1. å»ºè¡¨ mes_safety_risk_unit(风险单元/风险点)
--   2. å»ºè¡¨ mes_safety_risk(风险事件清单 + LEC è¯„估)
--   3. å­—典:风险等级 / é£Žé™©ç±»åˆ« / äº‹æ•…类型 / å•元状态
--   4. èœå•:挂在「安全生产」目录下
--   5. æŽˆæƒè¶…级管理员
--
-- ç‰¹æ€§ï¼šå¯é‡å¤æ‰§è¡Œ
-- =====================================================================
-- ---------------------------------------------------------------------
-- 1. é£Žé™©å•元(风险点):风险识别的最小单元,如"造纸车间1#烘缸""配电室"
-- ---------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS `mes_safety_risk_unit` (
  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号',
  `code` varchar(64) NOT NULL COMMENT '风险单元编码',
  `name` varchar(200) NOT NULL COMMENT '风险单元名称',
  `workshop_id` bigint DEFAULT NULL COMMENT '所属车间编号',
  `location` varchar(255) DEFAULT NULL COMMENT '具体位置',
  `risk_category` tinyint DEFAULT NULL COMMENT '风险类别(字典 mes_safety_risk_category)',
  `charge_user_id` bigint DEFAULT NULL COMMENT '责任人编号',
  `status` tinyint NOT NULL DEFAULT '1' COMMENT '状态:1=启用,0=停用',
  `remark` varchar(500) DEFAULT NULL COMMENT '备注',
  `creator` varchar(64) DEFAULT '' COMMENT '创建者',
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `updater` varchar(64) DEFAULT '' COMMENT '更新者',
  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
  PRIMARY KEY (`id`) USING BTREE,
  UNIQUE KEY `uk_code` (`code`) USING BTREE,
  KEY `idx_workshop` (`workshop_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='安全生产-风险单元';
-- ---------------------------------------------------------------------
-- 2. é£Žé™©äº‹ä»¶æ¸…单(含 LEC è¯„估结果)
-- ---------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS `mes_safety_risk` (
  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号',
  `unit_id` bigint NOT NULL COMMENT '风险单元编号',
  `code` varchar(64) NOT NULL COMMENT '风险编码',
  `name` varchar(200) NOT NULL COMMENT '风险名称/描述',
  `accident_type` tinyint DEFAULT NULL COMMENT '可能导致的事故类型(字典 mes_safety_accident_type)',
  `possible_consequence` varchar(500) DEFAULT NULL COMMENT '可能导致的后果说明',
  `likelihood` decimal(6,2) DEFAULT NULL COMMENT 'L äº‹æ•…发生可能性',
  `exposure` decimal(6,2) DEFAULT NULL COMMENT 'E æš´éœ²äºŽå±é™©çŽ¯å¢ƒé¢‘çŽ‡',
  `consequence` decimal(6,2) DEFAULT NULL COMMENT 'C äº‹æ•…后果严重性',
  `risk_value` decimal(10,2) DEFAULT NULL COMMENT 'D é£Žé™©å€¼ = L×E×C',
  `risk_level` tinyint DEFAULT NULL COMMENT '风险等级(字典 mes_safety_risk_level:1重大 2较大 3一般 4低)',
  `control_engineering` varchar(1000) DEFAULT NULL COMMENT '工程技术措施',
  `control_management` varchar(1000) DEFAULT NULL COMMENT '管理措施',
  `control_training` varchar(1000) DEFAULT NULL COMMENT '培训教育措施',
  `control_ppe` varchar(1000) DEFAULT NULL COMMENT '个体防护措施',
  `control_emergency` varchar(1000) DEFAULT NULL COMMENT '应急处置措施',
  `evaluate_date` date DEFAULT NULL COMMENT '本次评估日期',
  `next_evaluate_date` date DEFAULT NULL COMMENT '下次评估日期',
  `charge_user_id` bigint DEFAULT NULL COMMENT '管控责任人编号',
  `status` tinyint NOT NULL DEFAULT '1' COMMENT '状态:1=有效,0=已失效',
  `remark` varchar(500) DEFAULT NULL COMMENT '备注',
  `creator` varchar(64) DEFAULT '' COMMENT '创建者',
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `updater` varchar(64) DEFAULT '' COMMENT '更新者',
  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
  PRIMARY KEY (`id`) USING BTREE,
  UNIQUE KEY `uk_code` (`code`) USING BTREE,
  KEY `idx_unit` (`unit_id`) USING BTREE,
  KEY `idx_level` (`risk_level`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='安全生产-风险事件清单';
-- ---------------------------------------------------------------------
-- 3. å­—å…¸
-- ---------------------------------------------------------------------
DELETE FROM system_dict_data WHERE dict_type IN
  ('mes_safety_risk_level', 'mes_safety_risk_category', 'mes_safety_accident_type', 'mes_safety_unit_status');
DELETE FROM system_dict_type WHERE type IN
  ('mes_safety_risk_level', 'mes_safety_risk_category', 'mes_safety_accident_type', 'mes_safety_unit_status');
INSERT INTO system_dict_type (name, type, status, remark, creator, create_time, updater, update_time, deleted)
VALUES ('安全生产-风险等级', 'mes_safety_risk_level', 0, '按 LEC é£Žé™©å€¼ D åˆ’分:1重大 2较大 3一般 4低', '1', NOW(), '1', NOW(), b'0'),
       ('安全生产-风险类别', 'mes_safety_risk_category', 0, '风险单元的风险类别', '1', NOW(), '1', NOW(), b'0'),
       ('安全生产-事故类型', 'mes_safety_accident_type', 0, 'GB6441 ä¼ä¸šèŒå·¥ä¼¤äº¡äº‹æ•…分类(常用项)', '1', NOW(), '1', NOW(), b'0'),
       ('安全生产-单元状态', 'mes_safety_unit_status', 0, '风险单元状态', '1', NOW(), '1', NOW(), b'0');
INSERT INTO system_dict_data (sort, label, value, dict_type, status, color_type, creator, create_time, updater, update_time, deleted)
VALUES
-- é£Žé™©ç­‰çº§ï¼ˆå››è‰²ï¼‰
(1, '重大风险', '1', 'mes_safety_risk_level', 0, 'error',      '1', NOW(), '1', NOW(), b'0'),
(2, '较大风险', '2', 'mes_safety_risk_level', 0, 'warning',    '1', NOW(), '1', NOW(), b'0'),
(3, '一般风险', '3', 'mes_safety_risk_level', 0, 'processing', '1', NOW(), '1', NOW(), b'0'),
(4, '低风险',   '4', 'mes_safety_risk_level', 0, 'success',    '1', NOW(), '1', NOW(), b'0'),
-- é£Žé™©ç±»åˆ«
(1, '设备设施', '1', 'mes_safety_risk_category', 0, 'default', '1', NOW(), '1', NOW(), b'0'),
(2, '作业活动', '2', 'mes_safety_risk_category', 0, 'default', '1', NOW(), '1', NOW(), b'0'),
(3, '作业环境', '3', 'mes_safety_risk_category', 0, 'default', '1', NOW(), '1', NOW(), b'0'),
(4, '安全管理', '4', 'mes_safety_risk_category', 0, 'default', '1', NOW(), '1', NOW(), b'0'),
-- äº‹æ•…类型
(1, '物体打击',   '1',  'mes_safety_accident_type', 0, 'default', '1', NOW(), '1', NOW(), b'0'),
(2, '车辆伤害',   '2',  'mes_safety_accident_type', 0, 'default', '1', NOW(), '1', NOW(), b'0'),
(3, '机械伤害',   '3',  'mes_safety_accident_type', 0, 'default', '1', NOW(), '1', NOW(), b'0'),
(4, '起重伤害',   '4',  'mes_safety_accident_type', 0, 'default', '1', NOW(), '1', NOW(), b'0'),
(5, '触电',       '5',  'mes_safety_accident_type', 0, 'default', '1', NOW(), '1', NOW(), b'0'),
(6, '淹溺',       '6',  'mes_safety_accident_type', 0, 'default', '1', NOW(), '1', NOW(), b'0'),
(7, '灼烫',       '7',  'mes_safety_accident_type', 0, 'default', '1', NOW(), '1', NOW(), b'0'),
(8, '火灾',       '8',  'mes_safety_accident_type', 0, 'default', '1', NOW(), '1', NOW(), b'0'),
(9, '高处坠落',   '9',  'mes_safety_accident_type', 0, 'default', '1', NOW(), '1', NOW(), b'0'),
(10, '坍塌',      '10', 'mes_safety_accident_type', 0, 'default', '1', NOW(), '1', NOW(), b'0'),
(11, '锅炉爆炸',  '11', 'mes_safety_accident_type', 0, 'default', '1', NOW(), '1', NOW(), b'0'),
(12, '容器爆炸',  '12', 'mes_safety_accident_type', 0, 'default', '1', NOW(), '1', NOW(), b'0'),
(13, '中毒和窒息', '13', 'mes_safety_accident_type', 0, 'default', '1', NOW(), '1', NOW(), b'0'),
(14, '其他伤害',  '14', 'mes_safety_accident_type', 0, 'default', '1', NOW(), '1', NOW(), b'0'),
-- å•元状态
(1, '启用', '1', 'mes_safety_unit_status', 0, 'success', '1', NOW(), '1', NOW(), b'0'),
(2, '停用', '0', 'mes_safety_unit_status', 0, 'default', '1', NOW(), '1', NOW(), b'0');
-- ---------------------------------------------------------------------
-- 4. èœå•(挂在 1065910 å®‰å…¨ç”Ÿäº§ä¸‹ï¼‰
-- ---------------------------------------------------------------------
DELETE FROM system_role_menu WHERE menu_id BETWEEN 1065917 AND 1065929;
DELETE FROM system_menu WHERE id BETWEEN 1065917 AND 1065929;
INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon,
                         component, component_name, status, visible, keep_alive, always_show,
                         creator, create_time, updater, update_time, deleted)
VALUES
-- é£Žé™©å•元管理
(1065917, '风险单元管理', '', 2, 2, 1065910, 'risk-unit', 'ep:location',
 'safety/risk/unit/index', 'SafetyRiskUnit', 0, b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0'),
(1065918, '风险单元查询', 'mes:safety-risk-unit:query',  3, 1, 1065917, '', '', NULL, NULL, 0, b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0'),
(1065919, '风险单元创建', 'mes:safety-risk-unit:create', 3, 2, 1065917, '', '', NULL, NULL, 0, b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0'),
(1065920, '风险单元更新', 'mes:safety-risk-unit:update', 3, 3, 1065917, '', '', NULL, NULL, 0, b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0'),
(1065921, '风险单元删除', 'mes:safety-risk-unit:delete', 3, 4, 1065917, '', '', NULL, NULL, 0, b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0'),
-- é£Žé™©æ¸…单管理
(1065922, '风险清单管理', '', 2, 3, 1065910, 'risk-list', 'ep:warning',
 'safety/risk/list/index', 'SafetyRiskList', 0, b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0'),
(1065923, '风险清单查询', 'mes:safety-risk:query',  3, 1, 1065922, '', '', NULL, NULL, 0, b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0'),
(1065924, '风险清单创建', 'mes:safety-risk:create', 3, 2, 1065922, '', '', NULL, NULL, 0, b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0'),
(1065925, '风险清单更新', 'mes:safety-risk:update', 3, 3, 1065922, '', '', NULL, NULL, 0, b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0'),
(1065926, '风险清单删除', 'mes:safety-risk:delete', 3, 4, 1065922, '', '', NULL, NULL, 0, b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0');
-- ---------------------------------------------------------------------
-- 5. æŽˆæƒè¶…级管理员
-- ---------------------------------------------------------------------
INSERT INTO system_role_menu (role_id, menu_id, creator, create_time, updater, update_time, deleted)
SELECT 1, m.id, '1', NOW(), '1', NOW(), b'0'
FROM system_menu m
WHERE m.id BETWEEN 1065917 AND 1065929;
-- ---------------------------------------------------------------------
-- 6. éªŒè¯
-- ---------------------------------------------------------------------
SELECT id, parent_id, name, path, component, permission, type
FROM system_menu WHERE id BETWEEN 1065910 AND 1065929 ORDER BY id;
SELECT dict_type, label, value FROM system_dict_data
WHERE dict_type LIKE 'mes_safety_%' ORDER BY dict_type, sort;
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/safety/MesSafetyRiskController.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,165 @@
package cn.iocoder.yudao.module.mes.controller.admin.safety;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.mes.controller.admin.safety.vo.risk.MesSafetyRiskPageReqVO;
import cn.iocoder.yudao.module.mes.controller.admin.safety.vo.risk.MesSafetyRiskRespVO;
import cn.iocoder.yudao.module.mes.controller.admin.safety.vo.risk.MesSafetyRiskSaveReqVO;
import cn.iocoder.yudao.module.mes.dal.dataobject.md.workstation.MesMdWorkshopDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.safety.MesSafetyRiskDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.safety.MesSafetyRiskUnitDO;
import cn.iocoder.yudao.module.mes.dal.mysql.md.workstation.MesMdWorkshopMapper;
import cn.iocoder.yudao.module.mes.service.safety.MesSafetyRiskService;
import cn.iocoder.yudao.module.mes.service.safety.MesSafetyRiskUnitService;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.*;
import java.util.stream.Collectors;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
/**
 * å®‰å…¨ç”Ÿäº§ - é£Žé™©æ¸…单 Controller
 *
 * @author è¶…级管理员
 */
@Tag(name = "管理后台 - å®‰å…¨ç”Ÿäº§-风险清单")
@RestController
@RequestMapping("/mes/safety/risk")
@Validated
public class MesSafetyRiskController {
    @Resource
    private MesSafetyRiskService riskService;
    @Resource
    private MesSafetyRiskUnitService riskUnitService;
    @Resource
    private MesMdWorkshopMapper workshopMapper;
    @Resource
    private AdminUserApi adminUserApi;
    @PostMapping("/create")
    @Operation(summary = "创建风险清单")
    @PreAuthorize("@ss.hasPermission('mes:safety-risk:create')")
    public CommonResult<Long> createRisk(@Valid @RequestBody MesSafetyRiskSaveReqVO createReqVO) {
        return success(riskService.createRisk(createReqVO));
    }
    @PutMapping("/update")
    @Operation(summary = "更新风险清单")
    @PreAuthorize("@ss.hasPermission('mes:safety-risk:update')")
    public CommonResult<Boolean> updateRisk(@Valid @RequestBody MesSafetyRiskSaveReqVO updateReqVO) {
        riskService.updateRisk(updateReqVO);
        return success(true);
    }
    @DeleteMapping("/delete")
    @Operation(summary = "删除风险清单")
    @Parameter(name = "id", description = "编号", required = true)
    @PreAuthorize("@ss.hasPermission('mes:safety-risk:delete')")
    public CommonResult<Boolean> deleteRisk(@RequestParam("id") Long id) {
        riskService.deleteRisk(id);
        return success(true);
    }
    @GetMapping("/get")
    @Operation(summary = "获得风险清单")
    @Parameter(name = "id", description = "编号", required = true, example = "1024")
    @PreAuthorize("@ss.hasPermission('mes:safety-risk:query')")
    public CommonResult<MesSafetyRiskRespVO> getRisk(@RequestParam("id") Long id) {
        MesSafetyRiskDO risk = riskService.getRisk(id);
        if (risk == null) {
            return success(null);
        }
        List<MesSafetyRiskRespVO> list = buildRespList(Collections.singletonList(risk));
        return success(list.isEmpty() ? null : list.get(0));
    }
    @GetMapping("/page")
    @Operation(summary = "获得风险清单分页")
    @PreAuthorize("@ss.hasPermission('mes:safety-risk:query')")
    public CommonResult<PageResult<MesSafetyRiskRespVO>> getRiskPage(@Valid MesSafetyRiskPageReqVO pageReqVO) {
        PageResult<MesSafetyRiskDO> pageResult = riskService.getRiskPage(pageReqVO);
        List<MesSafetyRiskRespVO> list = buildRespList(pageResult.getList());
        return success(new PageResult<>(list, pageResult.getTotal()));
    }
    @GetMapping("/list-by-unit")
    @Operation(summary = "获得指定风险单元下的风险清单")
    @Parameter(name = "unitId", description = "风险单元编号", required = true)
    @PreAuthorize("@ss.hasPermission('mes:safety-risk:query')")
    public CommonResult<List<MesSafetyRiskRespVO>> getRiskListByUnit(@RequestParam("unitId") Long unitId) {
        return success(buildRespList(riskService.getRiskListByUnitId(unitId)));
    }
    /**
     * è½¬æ¢ä¸º VO å¹¶å¡«å……风险单元名称、车间名称、责任人姓名、风险等级名称
     */
    private List<MesSafetyRiskRespVO> buildRespList(List<MesSafetyRiskDO> list) {
        if (list == null || list.isEmpty()) {
            return Collections.emptyList();
        }
        List<MesSafetyRiskRespVO> respList = BeanUtils.toBean(list, MesSafetyRiskRespVO.class);
        // é£Žé™©å•å…ƒ
        Set<Long> unitIds = list.stream().map(MesSafetyRiskDO::getUnitId)
                .filter(Objects::nonNull).collect(Collectors.toSet());
        Map<Long, MesSafetyRiskUnitDO> unitMap = riskUnitService.getRiskUnitMap(unitIds);
        // è½¦é—´åç§°ï¼ˆç»é£Žé™©å•元的 workshopId å–)
        Set<Long> workshopIds = unitMap.values().stream().map(MesSafetyRiskUnitDO::getWorkshopId)
                .filter(Objects::nonNull).collect(Collectors.toSet());
        Map<Long, String> workshopNameMap = new HashMap<>();
        if (!workshopIds.isEmpty()) {
            List<MesMdWorkshopDO> workshops = workshopMapper.selectByIds(workshopIds);
            workshops.forEach(w -> workshopNameMap.put(w.getId(), w.getName()));
        }
        // è´£ä»»äººå§“名
        Set<Long> userIds = list.stream().map(MesSafetyRiskDO::getChargeUserId)
                .filter(Objects::nonNull).collect(Collectors.toSet());
        Map<Long, AdminUserRespDTO> userMap = userIds.isEmpty()
                ? Collections.emptyMap() : adminUserApi.getUserMap(userIds);
        for (MesSafetyRiskRespVO vo : respList) {
            MesSafetyRiskUnitDO unit = unitMap.get(vo.getUnitId());
            if (unit != null) {
                vo.setUnitName(unit.getName());
                vo.setWorkshopName(workshopNameMap.get(unit.getWorkshopId()));
            }
            AdminUserRespDTO user = userMap.get(vo.getChargeUserId());
            if (user != null) {
                vo.setChargeUserName(user.getNickname());
            }
            vo.setRiskLevelName(riskLevelName(vo.getRiskLevel()));
        }
        return respList;
    }
    private String riskLevelName(Integer level) {
        if (level == null) {
            return null;
        }
        switch (level) {
            case 1: return "重大风险";
            case 2: return "较大风险";
            case 3: return "一般风险";
            case 4: return "低风险";
            default: return null;
        }
    }
}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/safety/MesSafetyRiskUnitController.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,141 @@
package cn.iocoder.yudao.module.mes.controller.admin.safety;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.mes.controller.admin.safety.vo.unit.MesSafetyRiskUnitPageReqVO;
import cn.iocoder.yudao.module.mes.controller.admin.safety.vo.unit.MesSafetyRiskUnitRespVO;
import cn.iocoder.yudao.module.mes.controller.admin.safety.vo.unit.MesSafetyRiskUnitSaveReqVO;
import cn.iocoder.yudao.module.mes.dal.dataobject.md.workstation.MesMdWorkshopDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.safety.MesSafetyRiskUnitDO;
import cn.iocoder.yudao.module.mes.dal.mysql.md.workstation.MesMdWorkshopMapper;
import cn.iocoder.yudao.module.mes.dal.mysql.safety.MesSafetyRiskMapper;
import cn.iocoder.yudao.module.mes.service.safety.MesSafetyRiskUnitService;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.*;
import java.util.stream.Collectors;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
/**
 * å®‰å…¨ç”Ÿäº§ - é£Žé™©å•å…ƒ Controller
 *
 * @author è¶…级管理员
 */
@Tag(name = "管理后台 - å®‰å…¨ç”Ÿäº§-风险单元")
@RestController
@RequestMapping("/mes/safety/risk-unit")
@Validated
public class MesSafetyRiskUnitController {
    @Resource
    private MesSafetyRiskUnitService riskUnitService;
    @Resource
    private MesMdWorkshopMapper workshopMapper;
    @Resource
    private MesSafetyRiskMapper riskMapper;
    @Resource
    private AdminUserApi adminUserApi;
    @PostMapping("/create")
    @Operation(summary = "创建风险单元")
    @PreAuthorize("@ss.hasPermission('mes:safety-risk-unit:create')")
    public CommonResult<Long> createRiskUnit(@Valid @RequestBody MesSafetyRiskUnitSaveReqVO createReqVO) {
        return success(riskUnitService.createRiskUnit(createReqVO));
    }
    @PutMapping("/update")
    @Operation(summary = "更新风险单元")
    @PreAuthorize("@ss.hasPermission('mes:safety-risk-unit:update')")
    public CommonResult<Boolean> updateRiskUnit(@Valid @RequestBody MesSafetyRiskUnitSaveReqVO updateReqVO) {
        riskUnitService.updateRiskUnit(updateReqVO);
        return success(true);
    }
    @DeleteMapping("/delete")
    @Operation(summary = "删除风险单元")
    @Parameter(name = "id", description = "编号", required = true)
    @PreAuthorize("@ss.hasPermission('mes:safety-risk-unit:delete')")
    public CommonResult<Boolean> deleteRiskUnit(@RequestParam("id") Long id) {
        riskUnitService.deleteRiskUnit(id);
        return success(true);
    }
    @GetMapping("/get")
    @Operation(summary = "获得风险单元")
    @Parameter(name = "id", description = "编号", required = true, example = "1024")
    @PreAuthorize("@ss.hasPermission('mes:safety-risk-unit:query')")
    public CommonResult<MesSafetyRiskUnitRespVO> getRiskUnit(@RequestParam("id") Long id) {
        MesSafetyRiskUnitDO unit = riskUnitService.getRiskUnit(id);
        if (unit == null) {
            return success(null);
        }
        List<MesSafetyRiskUnitRespVO> list = buildRespList(Collections.singletonList(unit));
        return success(list.isEmpty() ? null : list.get(0));
    }
    @GetMapping("/page")
    @Operation(summary = "获得风险单元分页")
    @PreAuthorize("@ss.hasPermission('mes:safety-risk-unit:query')")
    public CommonResult<PageResult<MesSafetyRiskUnitRespVO>> getRiskUnitPage(@Valid MesSafetyRiskUnitPageReqVO pageReqVO) {
        PageResult<MesSafetyRiskUnitDO> pageResult = riskUnitService.getRiskUnitPage(pageReqVO);
        List<MesSafetyRiskUnitRespVO> list = buildRespList(pageResult.getList());
        return success(new PageResult<>(list, pageResult.getTotal()));
    }
    @GetMapping("/simple-list")
    @Operation(summary = "获得风险单元精简列表(启用状态),用于下拉选择")
    @PreAuthorize("@ss.hasPermission('mes:safety-risk-unit:query')")
    public CommonResult<List<MesSafetyRiskUnitRespVO>> getRiskUnitSimpleList() {
        return success(buildRespList(riskUnitService.getRiskUnitSimpleList()));
    }
    /**
     * è½¬æ¢ä¸º VO å¹¶å¡«å……车间名称、责任人姓名、风险条数
     */
    private List<MesSafetyRiskUnitRespVO> buildRespList(List<MesSafetyRiskUnitDO> list) {
        if (list == null || list.isEmpty()) {
            return Collections.emptyList();
        }
        List<MesSafetyRiskUnitRespVO> respList = BeanUtils.toBean(list, MesSafetyRiskUnitRespVO.class);
        // è½¦é—´åç§°
        Set<Long> workshopIds = list.stream().map(MesSafetyRiskUnitDO::getWorkshopId)
                .filter(Objects::nonNull).collect(Collectors.toSet());
        Map<Long, String> workshopNameMap = new HashMap<>();
        if (!workshopIds.isEmpty()) {
            List<MesMdWorkshopDO> workshops = workshopMapper.selectByIds(workshopIds);
            workshops.forEach(w -> workshopNameMap.put(w.getId(), w.getName()));
        }
        // è´£ä»»äººå§“名
        Set<Long> userIds = list.stream().map(MesSafetyRiskUnitDO::getChargeUserId)
                .filter(Objects::nonNull).collect(Collectors.toSet());
        Map<Long, AdminUserRespDTO> userMap = userIds.isEmpty()
                ? Collections.emptyMap() : adminUserApi.getUserMap(userIds);
        for (MesSafetyRiskUnitRespVO vo : respList) {
            vo.setWorkshopName(workshopNameMap.get(vo.getWorkshopId()));
            AdminUserRespDTO user = userMap.get(vo.getChargeUserId());
            if (user != null) {
                vo.setChargeUserName(user.getNickname());
            }
            Long count = riskMapper.selectCountByUnitIds(Collections.singletonList(vo.getId()));
            vo.setRiskCount(count == null ? 0L : count);
        }
        return respList;
    }
}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/safety/vo/risk/MesSafetyRiskPageReqVO.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,33 @@
package cn.iocoder.yudao.module.mes.controller.admin.safety.vo.risk;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
@Schema(description = "管理后台 - å®‰å…¨ç”Ÿäº§-风险清单分页 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class MesSafetyRiskPageReqVO extends PageParam {
    @Schema(description = "风险编码", example = "FX-001-01")
    private String code;
    @Schema(description = "风险名称", example = "烘缸超压爆炸")
    private String name;
    @Schema(description = "风险单元编号", example = "1")
    private Long unitId;
    @Schema(description = "事故类型", example = "12")
    private Integer accidentType;
    @Schema(description = "风险等级", example = "1")
    private Integer riskLevel;
    @Schema(description = "状态", example = "1")
    private Integer status;
}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/safety/vo/risk/MesSafetyRiskRespVO.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,92 @@
package cn.iocoder.yudao.module.mes.controller.admin.safety.vo.risk;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
@Schema(description = "管理后台 - å®‰å…¨ç”Ÿäº§-风险清单 Response VO")
@Data
public class MesSafetyRiskRespVO {
    @Schema(description = "编号", example = "1024")
    private Long id;
    @Schema(description = "风险单元编号", example = "1")
    private Long unitId;
    @Schema(description = "风险单元名称", example = "造纸车间1#烘缸")
    private String unitName;
    @Schema(description = "所属车间名称", example = "造纸车间")
    private String workshopName;
    @Schema(description = "风险编码", example = "FX-001-01")
    private String code;
    @Schema(description = "风险名称", example = "烘缸超压爆炸")
    private String name;
    @Schema(description = "事故类型", example = "12")
    private Integer accidentType;
    @Schema(description = "可能导致的后果说明")
    private String possibleConsequence;
    @Schema(description = "L äº‹æ•…发生可能性", example = "3")
    private BigDecimal likelihood;
    @Schema(description = "E æš´éœ²äºŽå±é™©çŽ¯å¢ƒé¢‘çŽ‡", example = "6")
    private BigDecimal exposure;
    @Schema(description = "C äº‹æ•…后果严重性", example = "15")
    private BigDecimal consequence;
    @Schema(description = "D é£Žé™©å€¼", example = "270")
    private BigDecimal riskValue;
    @Schema(description = "风险等级", example = "2")
    private Integer riskLevel;
    @Schema(description = "风险等级名称", example = "较大风险")
    private String riskLevelName;
    @Schema(description = "工程技术措施")
    private String controlEngineering;
    @Schema(description = "管理措施")
    private String controlManagement;
    @Schema(description = "培训教育措施")
    private String controlTraining;
    @Schema(description = "个体防护措施")
    private String controlPpe;
    @Schema(description = "应急处置措施")
    private String controlEmergency;
    @Schema(description = "本次评估日期")
    private LocalDate evaluateDate;
    @Schema(description = "下次评估日期")
    private LocalDate nextEvaluateDate;
    @Schema(description = "管控责任人编号", example = "1")
    private Long chargeUserId;
    @Schema(description = "管控责任人姓名", example = "张睿")
    private String chargeUserName;
    @Schema(description = "状态", example = "1")
    private Integer status;
    @Schema(description = "备注")
    private String remark;
    @Schema(description = "创建时间")
    private LocalDateTime createTime;
}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/safety/vo/risk/MesSafetyRiskSaveReqVO.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,76 @@
package cn.iocoder.yudao.module.mes.controller.admin.safety.vo.risk;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDate;
@Schema(description = "管理后台 - å®‰å…¨ç”Ÿäº§-风险清单新增/修改 Request VO")
@Data
public class MesSafetyRiskSaveReqVO {
    @Schema(description = "编号", example = "1024")
    private Long id;
    @Schema(description = "风险单元编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
    @NotNull(message = "风险单元不能为空")
    private Long unitId;
    @Schema(description = "风险编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "FX-001-01")
    @NotEmpty(message = "风险编码不能为空")
    private String code;
    @Schema(description = "风险名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "烘缸超压爆炸")
    @NotEmpty(message = "风险名称不能为空")
    private String name;
    @Schema(description = "事故类型", example = "12")
    private Integer accidentType;
    @Schema(description = "可能导致的后果说明", example = "人员伤亡、设备损毁")
    private String possibleConsequence;
    @Schema(description = "L äº‹æ•…发生可能性", example = "3")
    private BigDecimal likelihood;
    @Schema(description = "E æš´éœ²äºŽå±é™©çŽ¯å¢ƒé¢‘çŽ‡", example = "6")
    private BigDecimal exposure;
    @Schema(description = "C äº‹æ•…后果严重性", example = "15")
    private BigDecimal consequence;
    @Schema(description = "工程技术措施")
    private String controlEngineering;
    @Schema(description = "管理措施")
    private String controlManagement;
    @Schema(description = "培训教育措施")
    private String controlTraining;
    @Schema(description = "个体防护措施")
    private String controlPpe;
    @Schema(description = "应急处置措施")
    private String controlEmergency;
    @Schema(description = "本次评估日期")
    private LocalDate evaluateDate;
    @Schema(description = "下次评估日期")
    private LocalDate nextEvaluateDate;
    @Schema(description = "管控责任人编号", example = "1")
    private Long chargeUserId;
    @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
    @NotNull(message = "状态不能为空")
    private Integer status;
    @Schema(description = "备注")
    private String remark;
}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/safety/vo/unit/MesSafetyRiskUnitPageReqVO.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,30 @@
package cn.iocoder.yudao.module.mes.controller.admin.safety.vo.unit;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
@Schema(description = "管理后台 - å®‰å…¨ç”Ÿäº§-风险单元分页 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class MesSafetyRiskUnitPageReqVO extends PageParam {
    @Schema(description = "风险单元编码", example = "FX-001")
    private String code;
    @Schema(description = "风险单元名称", example = "造纸车间1#烘缸")
    private String name;
    @Schema(description = "所属车间编号", example = "7")
    private Long workshopId;
    @Schema(description = "风险类别", example = "1")
    private Integer riskCategory;
    @Schema(description = "状态", example = "1")
    private Integer status;
}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/safety/vo/unit/MesSafetyRiskUnitRespVO.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,51 @@
package cn.iocoder.yudao.module.mes.controller.admin.safety.vo.unit;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDateTime;
@Schema(description = "管理后台 - å®‰å…¨ç”Ÿäº§-风险单元 Response VO")
@Data
public class MesSafetyRiskUnitRespVO {
    @Schema(description = "编号", example = "1024")
    private Long id;
    @Schema(description = "风险单元编码", example = "FX-001")
    private String code;
    @Schema(description = "风险单元名称", example = "造纸车间1#烘缸")
    private String name;
    @Schema(description = "所属车间编号", example = "7")
    private Long workshopId;
    @Schema(description = "所属车间名称", example = "造纸车间")
    private String workshopName;
    @Schema(description = "具体位置", example = "造纸车间东侧")
    private String location;
    @Schema(description = "风险类别", example = "1")
    private Integer riskCategory;
    @Schema(description = "责任人编号", example = "1")
    private Long chargeUserId;
    @Schema(description = "责任人姓名", example = "张睿")
    private String chargeUserName;
    @Schema(description = "状态", example = "1")
    private Integer status;
    @Schema(description = "该单元下的风险条数", example = "3")
    private Long riskCount;
    @Schema(description = "备注")
    private String remark;
    @Schema(description = "创建时间")
    private LocalDateTime createTime;
}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/safety/vo/unit/MesSafetyRiskUnitSaveReqVO.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,42 @@
package cn.iocoder.yudao.module.mes.controller.admin.safety.vo.unit;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
@Schema(description = "管理后台 - å®‰å…¨ç”Ÿäº§-风险单元新增/修改 Request VO")
@Data
public class MesSafetyRiskUnitSaveReqVO {
    @Schema(description = "编号", example = "1024")
    private Long id;
    @Schema(description = "风险单元编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "FX-001")
    @NotEmpty(message = "风险单元编码不能为空")
    private String code;
    @Schema(description = "风险单元名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "造纸车间1#烘缸")
    @NotEmpty(message = "风险单元名称不能为空")
    private String name;
    @Schema(description = "所属车间编号", example = "7")
    private Long workshopId;
    @Schema(description = "具体位置", example = "造纸车间东侧")
    private String location;
    @Schema(description = "风险类别", example = "1")
    private Integer riskCategory;
    @Schema(description = "责任人编号", example = "1")
    private Long chargeUserId;
    @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
    @NotNull(message = "状态不能为空")
    private Integer status;
    @Schema(description = "备注")
    private String remark;
}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/safety/MesSafetyRiskDO.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,143 @@
package cn.iocoder.yudao.module.mes.dal.dataobject.safety;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.*;
import java.math.BigDecimal;
import java.time.LocalDate;
/**
 * å®‰å…¨ç”Ÿäº§ - é£Žé™©äº‹ä»¶æ¸…单 DO
 *
 * é‡‡ç”¨ LEC æ³•(格雷厄姆-金尼法)评估:
 * D = L Ã— E Ã— C
 * D≥320 é‡å¤§(1) / 160≤D<320 è¾ƒå¤§(2) / 70≤D<160 ä¸€èˆ¬(3) / D<70 ä½Ž(4)
 *
 * @author è¶…级管理员
 */
@TableName("mes_safety_risk")
@KeySequence("mes_safety_risk_seq")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class MesSafetyRiskDO extends BaseDO {
    /**
     * ç¼–号
     */
    @TableId
    private Long id;
    /**
     * é£Žé™©å•元编号
     */
    private Long unitId;
    /**
     * é£Žé™©ç¼–码
     */
    private String code;
    /**
     * é£Žé™©åç§° / æè¿°
     */
    private String name;
    /**
     * å¯èƒ½å¯¼è‡´çš„事故类型
     *
     * å­—å…¸ mes_safety_accident_type
     */
    private Integer accidentType;
    /**
     * å¯èƒ½å¯¼è‡´çš„后果说明
     */
    private String possibleConsequence;
    /**
     * L äº‹æ•…发生可能性
     */
    private BigDecimal likelihood;
    /**
     * E æš´éœ²äºŽå±é™©çŽ¯å¢ƒé¢‘çŽ‡
     */
    private BigDecimal exposure;
    /**
     * C äº‹æ•…后果严重性
     */
    private BigDecimal consequence;
    /**
     * D é£Žé™©å€¼ = L Ã— E Ã— C
     */
    private BigDecimal riskValue;
    /**
     * é£Žé™©ç­‰çº§
     *
     * å­—å…¸ mes_safety_risk_level:1=重大 2=较大 3=一般 4=低
     */
    private Integer riskLevel;
    /**
     * å·¥ç¨‹æŠ€æœ¯æŽªæ–½
     */
    private String controlEngineering;
    /**
     * ç®¡ç†æŽªæ–½
     */
    private String controlManagement;
    /**
     * åŸ¹è®­æ•™è‚²æŽªæ–½
     */
    private String controlTraining;
    /**
     * ä¸ªä½“防护措施
     */
    private String controlPpe;
    /**
     * åº”急处置措施
     */
    private String controlEmergency;
    /**
     * æœ¬æ¬¡è¯„估日期
     */
    private LocalDate evaluateDate;
    /**
     * ä¸‹æ¬¡è¯„估日期
     */
    private LocalDate nextEvaluateDate;
    /**
     * ç®¡æŽ§è´£ä»»äººç¼–号
     */
    private Long chargeUserId;
    /**
     * çŠ¶æ€
     *
     * 1=有效 0=已失效
     */
    private Integer status;
    /**
     * å¤‡æ³¨
     */
    private String remark;
}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/safety/MesSafetyRiskUnitDO.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,76 @@
package cn.iocoder.yudao.module.mes.dal.dataobject.safety;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.*;
/**
 * å®‰å…¨ç”Ÿäº§ - é£Žé™©å•元(风险点) DO
 *
 * é£Žé™©è¯†åˆ«çš„æœ€å°å•元,例如「造纸车间 1# çƒ˜ç¼¸ã€ã€Œé…ç”µå®¤ã€ã€Œæˆå“ä»“库」
 *
 * @author è¶…级管理员
 */
@TableName("mes_safety_risk_unit")
@KeySequence("mes_safety_risk_unit_seq")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class MesSafetyRiskUnitDO extends BaseDO {
    /**
     * ç¼–号
     */
    @TableId
    private Long id;
    /**
     * é£Žé™©å•元编码
     */
    private String code;
    /**
     * é£Žé™©å•元名称
     */
    private String name;
    /**
     * æ‰€å±žè½¦é—´ç¼–号
     */
    private Long workshopId;
    /**
     * å…·ä½“位置
     */
    private String location;
    /**
     * é£Žé™©ç±»åˆ«
     *
     * å­—å…¸ mes_safety_risk_category:1=设备设施 2=作业活动 3=作业环境 4=安全管理
     */
    private Integer riskCategory;
    /**
     * è´£ä»»äººç¼–号
     */
    private Long chargeUserId;
    /**
     * çŠ¶æ€
     *
     * 1=启用 0=停用
     */
    private Integer status;
    /**
     * å¤‡æ³¨
     */
    private String remark;
}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/safety/MesSafetyRiskMapper.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,63 @@
package cn.iocoder.yudao.module.mes.dal.mysql.safety;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.mes.controller.admin.safety.vo.risk.MesSafetyRiskPageReqVO;
import cn.iocoder.yudao.module.mes.dal.dataobject.safety.MesSafetyRiskDO;
import org.apache.ibatis.annotations.Mapper;
import java.util.Collection;
import java.util.List;
/**
 * å®‰å…¨ç”Ÿäº§ - é£Žé™©äº‹ä»¶æ¸…单 Mapper
 *
 * @author è¶…级管理员
 */
@Mapper
public interface MesSafetyRiskMapper extends BaseMapperX<MesSafetyRiskDO> {
    default PageResult<MesSafetyRiskDO> selectPage(MesSafetyRiskPageReqVO reqVO) {
        return selectPage(reqVO, new LambdaQueryWrapperX<MesSafetyRiskDO>()
                .likeIfPresent(MesSafetyRiskDO::getCode, reqVO.getCode())
                .likeIfPresent(MesSafetyRiskDO::getName, reqVO.getName())
                .eqIfPresent(MesSafetyRiskDO::getUnitId, reqVO.getUnitId())
                .eqIfPresent(MesSafetyRiskDO::getAccidentType, reqVO.getAccidentType())
                .eqIfPresent(MesSafetyRiskDO::getRiskLevel, reqVO.getRiskLevel())
                .eqIfPresent(MesSafetyRiskDO::getStatus, reqVO.getStatus())
                .orderByDesc(MesSafetyRiskDO::getRiskValue)
                .orderByDesc(MesSafetyRiskDO::getId));
    }
    default MesSafetyRiskDO selectByCode(String code) {
        return selectOne(MesSafetyRiskDO::getCode, code);
    }
    default List<MesSafetyRiskDO> selectListByUnitId(Long unitId) {
        return selectList(new LambdaQueryWrapperX<MesSafetyRiskDO>()
                .eq(MesSafetyRiskDO::getUnitId, unitId)
                .orderByDesc(MesSafetyRiskDO::getRiskValue));
    }
    default Long selectCountByUnitIds(Collection<Long> unitIds) {
        return selectCount(new LambdaQueryWrapperX<MesSafetyRiskDO>()
                .in(MesSafetyRiskDO::getUnitId, unitIds));
    }
    default List<MesSafetyRiskDO> selectListByStatus(Integer status) {
        return selectList(new LambdaQueryWrapperX<MesSafetyRiskDO>()
                .eqIfPresent(MesSafetyRiskDO::getStatus, status)
                .orderByDesc(MesSafetyRiskDO::getRiskValue));
    }
    /**
     * æŒ‰é£Žé™©ç­‰çº§ç»Ÿè®¡æ•°é‡ï¼ˆç”¨äºŽçœ‹æ¿/统计)
     */
    default List<MesSafetyRiskDO> selectAllList() {
        return selectList(new LambdaQueryWrapperX<MesSafetyRiskDO>()
                .eq(MesSafetyRiskDO::getStatus, 1)
                .orderByDesc(MesSafetyRiskDO::getRiskValue));
    }
}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/safety/MesSafetyRiskUnitMapper.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,40 @@
package cn.iocoder.yudao.module.mes.dal.mysql.safety;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.mes.controller.admin.safety.vo.unit.MesSafetyRiskUnitPageReqVO;
import cn.iocoder.yudao.module.mes.dal.dataobject.safety.MesSafetyRiskUnitDO;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
/**
 * å®‰å…¨ç”Ÿäº§ - é£Žé™©å•å…ƒ Mapper
 *
 * @author è¶…级管理员
 */
@Mapper
public interface MesSafetyRiskUnitMapper extends BaseMapperX<MesSafetyRiskUnitDO> {
    default PageResult<MesSafetyRiskUnitDO> selectPage(MesSafetyRiskUnitPageReqVO reqVO) {
        return selectPage(reqVO, new LambdaQueryWrapperX<MesSafetyRiskUnitDO>()
                .likeIfPresent(MesSafetyRiskUnitDO::getCode, reqVO.getCode())
                .likeIfPresent(MesSafetyRiskUnitDO::getName, reqVO.getName())
                .eqIfPresent(MesSafetyRiskUnitDO::getWorkshopId, reqVO.getWorkshopId())
                .eqIfPresent(MesSafetyRiskUnitDO::getRiskCategory, reqVO.getRiskCategory())
                .eqIfPresent(MesSafetyRiskUnitDO::getStatus, reqVO.getStatus())
                .orderByDesc(MesSafetyRiskUnitDO::getId));
    }
    default MesSafetyRiskUnitDO selectByCode(String code) {
        return selectOne(MesSafetyRiskUnitDO::getCode, code);
    }
    default List<MesSafetyRiskUnitDO> selectSimpleList() {
        return selectList(new LambdaQueryWrapperX<MesSafetyRiskUnitDO>()
                .eq(MesSafetyRiskUnitDO::getStatus, 1)
                .orderByAsc(MesSafetyRiskUnitDO::getCode));
    }
}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/DictTypeConstants.java
@@ -119,4 +119,10 @@
    // ========== å®‰å…¨ç”Ÿäº§ (Safety) ==========
    String MES_PRO_EMERGENCY_PLAN_TYPE = "mes_pro_emergency_plan_type"; // åº”急处置预案类型
    // å®‰å…¨é£Žé™©åˆ†çº§ç®¡æŽ§
    String MES_SAFETY_RISK_LEVEL = "mes_safety_risk_level";         // é£Žé™©ç­‰çº§ï¼ˆ1重大 2较大 3一般 4低)
    String MES_SAFETY_RISK_CATEGORY = "mes_safety_risk_category";   // é£Žé™©ç±»åˆ«
    String MES_SAFETY_ACCIDENT_TYPE = "mes_safety_accident_type";   // äº‹æ•…类型
    String MES_SAFETY_UNIT_STATUS = "mes_safety_unit_status";       // é£Žé™©å•元状态
}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java
@@ -846,4 +846,12 @@
    ErrorCode MES_PRO_EMERGENCY_PLAN_CODE_DUPLICATE = new ErrorCode(1_040_903_001, "预案编码已存在");
    ErrorCode MES_PRO_EMERGENCY_PLAN_IMPORT_LIST_IS_EMPTY = new ErrorCode(1_040_903_002, "导入数据不能为空");
    // ========== MES å®‰å…¨ç”Ÿäº§ - é£Žé™©åˆ†çº§ç®¡æŽ§ï¼ˆ1-040-904-000) ==========
    ErrorCode MES_SAFETY_RISK_UNIT_NOT_EXISTS = new ErrorCode(1_040_904_000, "风险单元不存在");
    ErrorCode MES_SAFETY_RISK_UNIT_CODE_DUPLICATE = new ErrorCode(1_040_904_001, "风险单元编码已存在");
    ErrorCode MES_SAFETY_RISK_UNIT_HAS_RISK = new ErrorCode(1_040_904_002, "该风险单元下已存在风险清单,无法删除");
    ErrorCode MES_SAFETY_RISK_NOT_EXISTS = new ErrorCode(1_040_904_010, "风险清单记录不存在");
    ErrorCode MES_SAFETY_RISK_CODE_DUPLICATE = new ErrorCode(1_040_904_011, "风险编码已存在");
    ErrorCode MES_SAFETY_RISK_LEC_INVALID = new ErrorCode(1_040_904_012, "LEC è¯„估值不合法:L、E、C éƒ½å¿…须大于 0");
}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/safety/MesSafetyRiskService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,66 @@
package cn.iocoder.yudao.module.mes.service.safety;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.mes.controller.admin.safety.vo.risk.MesSafetyRiskPageReqVO;
import cn.iocoder.yudao.module.mes.controller.admin.safety.vo.risk.MesSafetyRiskSaveReqVO;
import cn.iocoder.yudao.module.mes.dal.dataobject.safety.MesSafetyRiskDO;
import java.util.List;
/**
 * å®‰å…¨ç”Ÿäº§ - é£Žé™©æ¸…单 Service æŽ¥å£
 *
 * é£Žé™©è¯„估采用 LEC æ³•:D = L Ã— E Ã— C
 *
 * @author è¶…级管理员
 */
public interface MesSafetyRiskService {
    /**
     * èŽ·å¾—é£Žé™©æ¸…å•åˆ†é¡µ
     */
    PageResult<MesSafetyRiskDO> getRiskPage(MesSafetyRiskPageReqVO pageReqVO);
    /**
     * èŽ·å¾—é£Žé™©æ¸…å•
     */
    MesSafetyRiskDO getRisk(Long id);
    /**
     * åˆ›å»ºé£Žé™©æ¸…单(自动计算 D å€¼ä¸Žé£Žé™©ç­‰çº§ï¼‰
     */
    Long createRisk(MesSafetyRiskSaveReqVO createReqVO);
    /**
     * æ›´æ–°é£Žé™©æ¸…单(自动重算 D å€¼ä¸Žé£Žé™©ç­‰çº§ï¼‰
     */
    void updateRisk(MesSafetyRiskSaveReqVO updateReqVO);
    /**
     * åˆ é™¤é£Žé™©æ¸…单
     */
    void deleteRisk(Long id);
    /**
     * èŽ·å¾—æŒ‡å®šé£Žé™©å•å…ƒä¸‹çš„é£Žé™©æ¸…å•
     */
    List<MesSafetyRiskDO> getRiskListByUnitId(Long unitId);
    /**
     * æ ¡éªŒé£Žé™©æ¸…单存在
     */
    MesSafetyRiskDO validateRiskExists(Long id);
    /**
     * è®¡ç®—风险值 D = L Ã— E Ã— C
     */
    java.math.BigDecimal calculateRiskValue(java.math.BigDecimal likelihood,
                                            java.math.BigDecimal exposure,
                                            java.math.BigDecimal consequence);
    /**
     * æŒ‰é£Žé™©å€¼è®¡ç®—风险等级:D≥320 é‡å¤§(1);160≤D<320 è¾ƒå¤§(2);70≤D<160 ä¸€èˆ¬(3);D<70 ä½Ž(4)
     */
    Integer calculateRiskLevel(java.math.BigDecimal riskValue);
}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/safety/MesSafetyRiskServiceImpl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,160 @@
package cn.iocoder.yudao.module.mes.service.safety;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.mes.controller.admin.safety.vo.risk.MesSafetyRiskPageReqVO;
import cn.iocoder.yudao.module.mes.controller.admin.safety.vo.risk.MesSafetyRiskSaveReqVO;
import cn.iocoder.yudao.module.mes.dal.dataobject.safety.MesSafetyRiskDO;
import cn.iocoder.yudao.module.mes.dal.mysql.safety.MesSafetyRiskMapper;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import java.math.BigDecimal;
import java.util.List;
import java.util.Objects;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*;
/**
 * å®‰å…¨ç”Ÿäº§ - é£Žé™©æ¸…单 Service å®žçް
 *
 * LEC æ³•(格雷厄姆-金尼法):
 * D = L Ã— E Ã— C
 * ç­‰çº§ï¼šD≥320 é‡å¤§(1);160≤D<320 è¾ƒå¤§(2);70≤D<160 ä¸€èˆ¬(3);D<70 ä½Ž(4)
 *
 * @author è¶…级管理员
 */
@Service
@Validated
public class MesSafetyRiskServiceImpl implements MesSafetyRiskService {
    /** é£Žé™©ç­‰çº§é˜ˆå€¼ */
    private static final BigDecimal LEVEL_1_THRESHOLD = new BigDecimal("320");
    private static final BigDecimal LEVEL_2_THRESHOLD = new BigDecimal("160");
    private static final BigDecimal LEVEL_3_THRESHOLD = new BigDecimal("70");
    @Resource
    private MesSafetyRiskMapper riskMapper;
    @Resource
    private MesSafetyRiskUnitService riskUnitService;
    @Override
    public PageResult<MesSafetyRiskDO> getRiskPage(MesSafetyRiskPageReqVO pageReqVO) {
        return riskMapper.selectPage(pageReqVO);
    }
    @Override
    public MesSafetyRiskDO getRisk(Long id) {
        return riskMapper.selectById(id);
    }
    @Override
    public Long createRisk(MesSafetyRiskSaveReqVO createReqVO) {
        // 1. é£Žé™©å•元必须存在
        riskUnitService.validateRiskUnitExists(createReqVO.getUnitId());
        // 2. ç¼–码唯一
        validateCodeUnique(null, createReqVO.getCode());
        // 3. è½¬æ¢å¹¶è®¡ç®— LEC
        MesSafetyRiskDO risk = BeanUtils.toBean(createReqVO, MesSafetyRiskDO.class);
        applyLecEvaluation(risk);
        riskMapper.insert(risk);
        return risk.getId();
    }
    @Override
    public void updateRisk(MesSafetyRiskSaveReqVO updateReqVO) {
        validateRiskExists(updateReqVO.getId());
        riskUnitService.validateRiskUnitExists(updateReqVO.getUnitId());
        validateCodeUnique(updateReqVO.getId(), updateReqVO.getCode());
        MesSafetyRiskDO updateObj = BeanUtils.toBean(updateReqVO, MesSafetyRiskDO.class);
        applyLecEvaluation(updateObj);
        riskMapper.updateById(updateObj);
    }
    @Override
    public void deleteRisk(Long id) {
        validateRiskExists(id);
        riskMapper.deleteById(id);
    }
    @Override
    public List<MesSafetyRiskDO> getRiskListByUnitId(Long unitId) {
        return riskMapper.selectListByUnitId(unitId);
    }
    @Override
    public MesSafetyRiskDO validateRiskExists(Long id) {
        if (id == null) {
            throw exception(MES_SAFETY_RISK_NOT_EXISTS);
        }
        MesSafetyRiskDO risk = riskMapper.selectById(id);
        if (risk == null) {
            throw exception(MES_SAFETY_RISK_NOT_EXISTS);
        }
        return risk;
    }
    @Override
    public BigDecimal calculateRiskValue(BigDecimal likelihood, BigDecimal exposure, BigDecimal consequence) {
        if (likelihood == null || exposure == null || consequence == null) {
            return null;
        }
        if (likelihood.compareTo(BigDecimal.ZERO) <= 0
                || exposure.compareTo(BigDecimal.ZERO) <= 0
                || consequence.compareTo(BigDecimal.ZERO) <= 0) {
            throw exception(MES_SAFETY_RISK_LEC_INVALID);
        }
        // D = L Ã— E Ã— C,保留 2 ä½å°æ•°
        return likelihood.multiply(exposure).multiply(consequence)
                .setScale(2, java.math.RoundingMode.HALF_UP);
    }
    @Override
    public Integer calculateRiskLevel(BigDecimal riskValue) {
        if (riskValue == null) {
            return null;
        }
        if (riskValue.compareTo(LEVEL_1_THRESHOLD) >= 0) {
            return 1; // é‡å¤§é£Žé™©
        }
        if (riskValue.compareTo(LEVEL_2_THRESHOLD) >= 0) {
            return 2; // è¾ƒå¤§é£Žé™©
        }
        if (riskValue.compareTo(LEVEL_3_THRESHOLD) >= 0) {
            return 3; // ä¸€èˆ¬é£Žé™©
        }
        return 4;     // ä½Žé£Žé™©
    }
    /**
     * è®¡ç®—并回填 D å€¼ä¸Žé£Žé™©ç­‰çº§
     */
    private void applyLecEvaluation(MesSafetyRiskDO risk) {
        // L/E/C éƒ½ä¸ºç©ºæ—¶è§†ä¸ºæœªè¯„估,保持空值
        if (risk.getLikelihood() == null && risk.getExposure() == null && risk.getConsequence() == null) {
            risk.setRiskValue(null);
            risk.setRiskLevel(null);
            return;
        }
        BigDecimal riskValue = calculateRiskValue(risk.getLikelihood(), risk.getExposure(), risk.getConsequence());
        risk.setRiskValue(riskValue);
        risk.setRiskLevel(calculateRiskLevel(riskValue));
    }
    /**
     * æ ¡éªŒç¼–码唯一(id ä¸ºç©ºè¡¨ç¤ºæ–°å¢žï¼‰
     */
    private void validateCodeUnique(Long id, String code) {
        MesSafetyRiskDO exists = riskMapper.selectByCode(code);
        if (exists == null) {
            return;
        }
        if (id == null || !Objects.equals(exists.getId(), id)) {
            throw exception(MES_SAFETY_RISK_CODE_DUPLICATE);
        }
    }
}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/safety/MesSafetyRiskUnitService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,60 @@
package cn.iocoder.yudao.module.mes.service.safety;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.mes.controller.admin.safety.vo.unit.MesSafetyRiskUnitPageReqVO;
import cn.iocoder.yudao.module.mes.controller.admin.safety.vo.unit.MesSafetyRiskUnitSaveReqVO;
import cn.iocoder.yudao.module.mes.dal.dataobject.safety.MesSafetyRiskUnitDO;
import java.util.Collection;
import java.util.List;
/**
 * å®‰å…¨ç”Ÿäº§ - é£Žé™©å•å…ƒ Service æŽ¥å£
 *
 * @author è¶…级管理员
 */
public interface MesSafetyRiskUnitService {
    /**
     * èŽ·å¾—é£Žé™©å•å…ƒåˆ†é¡µ
     */
    PageResult<MesSafetyRiskUnitDO> getRiskUnitPage(MesSafetyRiskUnitPageReqVO pageReqVO);
    /**
     * èŽ·å¾—é£Žé™©å•å…ƒ
     */
    MesSafetyRiskUnitDO getRiskUnit(Long id);
    /**
     * åˆ›å»ºé£Žé™©å•å…ƒ
     */
    Long createRiskUnit(MesSafetyRiskUnitSaveReqVO createReqVO);
    /**
     * æ›´æ–°é£Žé™©å•å…ƒ
     */
    void updateRiskUnit(MesSafetyRiskUnitSaveReqVO updateReqVO);
    /**
     * åˆ é™¤é£Žé™©å•å…ƒ
     *
     * å•元下若已有风险清单,禁止删除
     */
    void deleteRiskUnit(Long id);
    /**
     * èŽ·å¾—é£Žé™©å•å…ƒç²¾ç®€åˆ—è¡¨ï¼ˆå¯ç”¨çŠ¶æ€ï¼‰ï¼Œç”¨äºŽä¸‹æ‹‰é€‰æ‹©
     */
    List<MesSafetyRiskUnitDO> getRiskUnitSimpleList();
    /**
     * æ ¡éªŒé£Žé™©å•元存在
     */
    MesSafetyRiskUnitDO validateRiskUnitExists(Long id);
    /**
     * æ‰¹é‡èŽ·å¾—é£Žé™©å•å…ƒ Map(key ä¸º id)
     */
    java.util.Map<Long, MesSafetyRiskUnitDO> getRiskUnitMap(Collection<Long> ids);
}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/safety/MesSafetyRiskUnitServiceImpl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,116 @@
package cn.iocoder.yudao.module.mes.service.safety;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.mes.controller.admin.safety.vo.unit.MesSafetyRiskUnitPageReqVO;
import cn.iocoder.yudao.module.mes.controller.admin.safety.vo.unit.MesSafetyRiskUnitSaveReqVO;
import cn.iocoder.yudao.module.mes.dal.dataobject.safety.MesSafetyRiskUnitDO;
import cn.iocoder.yudao.module.mes.dal.mysql.safety.MesSafetyRiskMapper;
import cn.iocoder.yudao.module.mes.dal.mysql.safety.MesSafetyRiskUnitMapper;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*;
/**
 * å®‰å…¨ç”Ÿäº§ - é£Žé™©å•å…ƒ Service å®žçް
 *
 * @author è¶…级管理员
 */
@Service
@Validated
public class MesSafetyRiskUnitServiceImpl implements MesSafetyRiskUnitService {
    @Resource
    private MesSafetyRiskUnitMapper riskUnitMapper;
    @Resource
    private MesSafetyRiskMapper riskMapper;
    @Override
    public PageResult<MesSafetyRiskUnitDO> getRiskUnitPage(MesSafetyRiskUnitPageReqVO pageReqVO) {
        return riskUnitMapper.selectPage(pageReqVO);
    }
    @Override
    public MesSafetyRiskUnitDO getRiskUnit(Long id) {
        return riskUnitMapper.selectById(id);
    }
    @Override
    public Long createRiskUnit(MesSafetyRiskUnitSaveReqVO createReqVO) {
        // ç¼–码唯一性校验
        validateCodeUnique(null, createReqVO.getCode());
        MesSafetyRiskUnitDO unit = BeanUtils.toBean(createReqVO, MesSafetyRiskUnitDO.class);
        riskUnitMapper.insert(unit);
        return unit.getId();
    }
    @Override
    public void updateRiskUnit(MesSafetyRiskUnitSaveReqVO updateReqVO) {
        validateRiskUnitExists(updateReqVO.getId());
        validateCodeUnique(updateReqVO.getId(), updateReqVO.getCode());
        MesSafetyRiskUnitDO updateObj = BeanUtils.toBean(updateReqVO, MesSafetyRiskUnitDO.class);
        riskUnitMapper.updateById(updateObj);
    }
    @Override
    public void deleteRiskUnit(Long id) {
        validateRiskUnitExists(id);
        // å•元下已有风险清单时不允许删除,避免产生孤儿数据
        Long riskCount = riskMapper.selectCountByUnitIds(Collections.singletonList(id));
        if (riskCount != null && riskCount > 0) {
            throw exception(MES_SAFETY_RISK_UNIT_HAS_RISK);
        }
        riskUnitMapper.deleteById(id);
    }
    @Override
    public List<MesSafetyRiskUnitDO> getRiskUnitSimpleList() {
        return riskUnitMapper.selectSimpleList();
    }
    @Override
    public MesSafetyRiskUnitDO validateRiskUnitExists(Long id) {
        if (id == null) {
            throw exception(MES_SAFETY_RISK_UNIT_NOT_EXISTS);
        }
        MesSafetyRiskUnitDO unit = riskUnitMapper.selectById(id);
        if (unit == null) {
            throw exception(MES_SAFETY_RISK_UNIT_NOT_EXISTS);
        }
        return unit;
    }
    @Override
    public Map<Long, MesSafetyRiskUnitDO> getRiskUnitMap(Collection<Long> ids) {
        if (ids == null || ids.isEmpty()) {
            return Collections.emptyMap();
        }
        List<MesSafetyRiskUnitDO> list = riskUnitMapper.selectByIds(ids);
        return list.stream().collect(Collectors.toMap(MesSafetyRiskUnitDO::getId, u -> u, (a, b) -> a));
    }
    /**
     * æ ¡éªŒç¼–码唯一(id ä¸ºç©ºè¡¨ç¤ºæ–°å¢žï¼‰
     */
    private void validateCodeUnique(Long id, String code) {
        MesSafetyRiskUnitDO exists = riskUnitMapper.selectByCode(code);
        if (exists == null) {
            return;
        }
        if (id == null || !Objects.equals(exists.getId(), id)) {
            throw exception(MES_SAFETY_RISK_UNIT_CODE_DUPLICATE);
        }
    }
}