L13_若依数据权限

作业

image

参考

链接1:https://blog.csdn.net/2301_80971512/article/details/155494234?fromshare=blogdetail&sharetype=blogdetail&sharerId=155494234&sharerefer=PC&sharesource=2301_80971512&sharefrom=from_link

抄了部分:https://blog.csdn.net/2301_80194233/article/details/155482968?spm=1011.2415.3001.5331

正文 作业1

菜单权限

image

部门权限

image

超级管理员下的权限

image

普通角色的权限

image

数据库SQL语句位置

image

整体框架上的作用

例子代码
@Before("@annotation(controllerDataScope)")  // 拦截所有标记了@DataScope注解的方法
public void doBefore(JoinPoint point, DataScope controllerDataScope) {
    clearDataScope(point);   // 清空,防止SQL注入
    handleDataScope(point, controllerDataScope); // 再添加真正的权限SQL
}
根据对应权限设置,设置对应的查询语句

标签汇总

常量 含义 SQL效果
DATA_SCOPE_ALL "1" 全部数据权限 查询所有的数据
DATA_SCOPE_CUSTOM "2" 自定义数据权限 可设置权限,查询指定的内容
DATA_SCOPE_DEPT "3" 本部门数据权限 只看自己部门
DATA_SCOPE_DEPT_AND_CHILD "4" 本部门及以下权限 看自己和所有子部门
DATA_SCOPE_SELF "5" 仅本人数据权限 只看自己创建的数据

权限判断

DATA_SCOPE_ALL

点击查看代码
if (DATA_SCOPE_ALL.equals(dataScope))
{
    sqlString = new StringBuilder();  // 全部清空
    conditions.add(dataScope);
    break;  // 不执行后面的权限判断
}
如果你是超级管理员,或角色配置了"全部权限",直接清空之前拼的所有SQL break语句让循环立即结束,其他权限规则不再处理 最终查询返回全量数据:SELECT * FROM sys_user

DATA_SCOPE_CUSTOM

收集用户ID确认权限
user.getRoles().forEach(role -> {
    if (DATA_SCOPE_CUSTOM.equals(role.getDataScope()) 
        && role是正常的 
        && 角色包含所需权限字符) {
        scopeCustomIds.add(role.getRoleId().toString());
    }
});
生成查询SQL
if (scopeCustomIds.size() > 1)
                {
                    // 多个自定数据权限使用in查询,避免多次拼接。
                    sqlString.append(StringUtils.format(" OR {}.dept_id IN ( SELECT dept_id FROM sys_role_dept WHERE role_id in ({}) ) ", deptAlias, String.join(",", scopeCustomIds)));
                }
                else
                {
                    sqlString.append(StringUtils.format(" OR {}.dept_id IN ( SELECT dept_id FROM sys_role_dept WHERE role_id = {} ) ", deptAlias, role.getRoleId()));
                }
SQL示例:

AND (u.dept_id IN ( SELECT dept_id FROM sys_role_dept WHERE role_id IN (1, 2) ))
查询sys_role_dept关联表:这个角色能看哪些部门?
把查出来的部门ID列表,作为IN条件过滤主表数据

DATA_SCOPE_DEPT

点击查看代码
else if (DATA_SCOPE_DEPT.equals(dataScope))
{
    sqlString.append(StringUtils.format(" OR {}.dept_id = {} ", deptAlias, user.getDeptId()));
}
SQL示例:

AND (u.dept_id = 105)
只看dept_id等于自己部门ID的数据

DATA_SCOPE_DEPT_AND_CHILD

点击查看代码
else if (DATA_SCOPE_DEPT_AND_CHILD.equals(dataScope))
{
    sqlString.append(StringUtils.format(" OR {}.dept_id IN ( SELECT dept_id FROM sys_dept WHERE dept_id = {} or find_in_set( {} , ancestors ) )", 
                     deptAlias, user.getDeptId(), user.getDeptId()));
}
SQL示例:

AND (u.dept_id IN ( SELECT dept_id FROM sys_dept WHERE dept_id = 105 OR find_in_set(105, ancestors) ))

查询结果示例:

dept_id dept_name ancestors
100 总公司 0
105 研发部 0,100
106 后端组 0,100,105
107 前端组 0,100,105

DATA_SCOPE_SELF

点击查看代码
else if (DATA_SCOPE_SELF.equals(dataScope))
{
    if (StringUtils.isNotBlank(userAlias)) {
        // 正常情况:过滤user_id
        sqlString.append(" OR {}.user_id = {} ", userAlias, user.getUserId());
    } else {
        // 异常情况:开发者没配userAlias,直接查空数据,保护隐私
        sqlString.append(" OR {}.dept_id = 0 ", deptAlias);
    }
}

最终拼接语句

点击查看代码
     if (StringUtils.isNotBlank(sqlString.toString()))
        {
            Object params = joinPoint.getArgs()[0];
            if (StringUtils.isNotNull(params) && params instanceof BaseEntity)
            {
                BaseEntity baseEntity = (BaseEntity) params;
                baseEntity.getParams().put(DATA_SCOPE, " AND (" + sqlString.substring(4) + ")");
            }
        }

substring(4):循环中每个条件都是 OR xxx,第一个" OR "没用,需要砍掉。

拼接过程
// 循环第一个角色(自定义)
sqlString = " OR u.dept_id IN (SELECT...)"

// 循环第二个角色(仅本人)
sqlString = " OR u.dept_id IN (SELECT...) OR u.user_id = 1001"

// 最终处理
" AND (" + " OR u.dept_id IN (SELECT...) OR u.user_id = 1001".substring(4) + ")"
// 结果:
" AND (u.dept_id IN (SELECT...) OR u.user_id = 1001)"

流程

流程
用户请求
   ↓
@DataScope注解触发AOP
   ↓
获取当前登录用户
   ↓
是超级管理员? → 是 → SQL = "" → 直接放行
   ↓ 否
遍历用户的所有角色
   ↓
根据dataScope类型拼接SQL
   ├─ 1: 清空SQL,break
   ├─ 2: dept_id IN (SELECT dept_id FROM sys_role_dept...)
   ├─ 3: dept_id = 用户部门ID
   ├─ 4: dept_id IN (SELECT...find_in_set...)
   └─ 5: user_id = 用户ID (或 dept_id = 0)
   ↓
把SQL塞进params.dataScope
   ↓
Mybatis XML中 ${params.dataScope} 动态执行
   ↓
返回过滤后的数据

正文 作业2

sql语句

点击查看代码
-- ----------------------------
-- 车间设备管理表
-- ----------------------------
DROP TABLE IF EXISTS `mes_workshop_device`;
CREATE TABLE `mes_workshop_device` (
  `device_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '设备ID',
  `device_code` varchar(64) NOT NULL COMMENT '设备编号(如:LiuYi_001)',
  `device_name` varchar(50) NOT NULL COMMENT '设备名称',
  `device_type` varchar(30) DEFAULT '' COMMENT '设备类型(加工设备、检测设备、辅助设备)',
  `workshop_id` bigint(20) NOT NULL COMMENT '所属车间ID',
  `workshop_name` varchar(50) DEFAULT '' COMMENT '所属车间名称',
  `device_status` char(1) DEFAULT '0' COMMENT '设备状态(0正常 1停机 2维修 3报废)',
  `device_model` varchar(100) DEFAULT '' COMMENT '设备型号',
  `manufacturer` varchar(100) DEFAULT '' COMMENT '生产厂家',
  `purchase_date` datetime DEFAULT NULL COMMENT '购买日期',
  `price` decimal(10,2) DEFAULT '0.00' COMMENT '设备价格(万元)',
  `remark` varchar(500) DEFAULT '' COMMENT '备注',
  `del_flag` char(1) DEFAULT '0' COMMENT '删除标志(0代表存在 2代表删除)',
  `create_by` varchar(64) DEFAULT '' COMMENT '创建者',
  `create_time` datetime DEFAULT NULL COMMENT '创建时间',
  `update_by` varchar(64) DEFAULT '' COMMENT '更新者',
  `update_time` datetime DEFAULT NULL COMMENT '更新时间',
  PRIMARY KEY (`device_id`),
  UNIQUE KEY `device_code` (`device_code`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='车间设备管理表';

-- ----------------------------
-- 插入示例数据(帮你测试)
-- ----------------------------
INSERT INTO `mes_workshop_device` VALUES 
(1, 'LiuYi_001', '数控车床CNC-01', '加工设备', 101, '一车间', '0', 'CK-6140', '沈阳机床', '2023-03-15', 25.50, '精加工设备', '0', 'admin', '2024-01-10 10:00:00', 'admin', '2024-01-10 10:00:00'),
(2, 'LiuYi_002', '数控车床CNC-02', '加工设备', 101, '一车间', '1', 'CK-6140', '沈阳机床', '2023-03-15', 25.50, '精加工设备', '0', 'admin', '2024-01-10 10:30:00', 'admin', '2024-01-10 10:30:00'),
(3, 'LiuYi_003', '三坐标测量仪', '检测设备', 102, '二车间', '0', 'CMM-665', '海克斯康', '2024-01-20', 45.80, '精度检测', '0', 'admin', '2024-01-20 14:00:00', 'admin', '2024-01-20 14:00:00');

复制粘贴数据库执行
image

表创建完成,把表导入代码生成一键生成,作业完成

手写代码——后端

创建一个模块

image
image

将模块添加到ruoyi下进行管理

在主目录的pom文件下添加
image
在ruoyi-admin的pom文件下添加
image
添加完成后刷新maven

实体类:MesWorkshopDevice.java

路径:com.ruoyi.mes.domain.MesWorkshopDevice
创建java类

image
image

编写代码
点击查看代码
public class MesWorkshopDevice extends BaseEntity
{
    private static final long serialVersionUID = 1L;

    /** 设备ID */
    private Long deviceId;

    /** 设备编号(如:LiuYi_001) */
    @Excel(name = "设备编号")
    private String deviceCode;

    /** 设备名称 */
    @Excel(name = "设备名称")
    private String deviceName;

    /** 设备类型 */
    @Excel(name = "设备类型")
    private String deviceType;

    /** 所属车间ID */
    private Long workshopId;

    /** 所属车间名称 */
    @Excel(name = "所属车间")
    private String workshopName;

    /** 设备状态(0正常 1停机 2维修 3报废) */
    @Excel(name = "设备状态", readConverterExp = "0=正常,1=停机,2=维修,3=报废")
    private String deviceStatus;

    /** 设备型号 */
    @Excel(name = "设备型号")
    private String deviceModel;

    /** 生产厂家 */
    @Excel(name = "生产厂家")
    private String manufacturer;

    /** 购买日期 */
    @JsonFormat(pattern = "yyyy-MM-dd")
    @Excel(name = "购买日期", width = 30, dateFormat = "yyyy-MM-dd")
    private Date purchaseDate;

    /** 设备价格(万元) */
    @Excel(name = "设备价格(万元)")
    private BigDecimal price;

    /** 备注 */
    @Excel(name = "备注")
    private String remark;

    /** 删除标志(0代表存在 2代表删除) */
    private String delFlag;

不使用@Data,快捷键Alt+F12,生成getter和setter
image
Alt+F12,生成toString()
image

Mapper接口:MesWorkshopDeviceMapper.java

路径:com.ruoyi.mes.mapper.MesWorkshopDeviceMapper
代码
点击查看代码
@Mapper
public interface MesWorkshopDeviceMapper
{
    /**
     * 查询车间设备管理
     *
     * @param deviceId 车间设备管理主键
     * @return 车间设备管理
     */
    public MesWorkshopDevice selectMesWorkshopDeviceByDeviceId(Long deviceId);

    /**
     * 根据设备编号查询
     *
     * @param deviceCode 设备编号
     * @return 车间设备管理
     */
    public MesWorkshopDevice selectMesWorkshopDeviceByDeviceCode(String deviceCode);

    /**
     * 查询车间设备管理列表
     *
     * @param mesWorkshopDevice 车间设备管理
     * @return 车间设备管理集合
     */
    public List<MesWorkshopDevice> selectMesWorkshopDeviceList(MesWorkshopDevice mesWorkshopDevice);

    /**
     * 新增车间设备管理
     *
     * @param mesWorkshopDevice 车间设备管理
     * @return 结果
     */
    public int insertMesWorkshopDevice(MesWorkshopDevice mesWorkshopDevice);

    /**
     * 修改车间设备管理
     *
     * @param mesWorkshopDevice 车间设备管理
     * @return 结果
     */
    public int updateMesWorkshopDevice(MesWorkshopDevice mesWorkshopDevice);

    /**
     * 删除车间设备管理
     *
     * @param deviceId 车间设备管理主键
     * @return 结果
     */
    public int deleteMesWorkshopDeviceByDeviceId(Long deviceId);

    /**
     * 批量删除车间设备管理
     *
     * @param deviceIds 需要删除的数据主键集合
     * @return 结果
     */
    public int deleteMesWorkshopDeviceByDeviceIds(Long[] deviceIds);
}

Mapper XML:MesWorkshopDeviceMapper.xml

路径:src/main/resources/mapper/mes/MesWorkshopDeviceMapper.xml
代码
点击查看代码
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.ruoyi.mes.mapper.MesWorkshopDeviceMapper">
    <!-- 结果映射 -->
    <resultMap type="com.ruoyi.mes.domain.MesWorkshopDevice" id="MesWorkshopDeviceResult">
        <result property="deviceId"    column="device_id"    />
        <result property="deviceCode"    column="device_code"    />
        <result property="deviceName"    column="device_name"    />
        <result property="deviceType"    column="device_type"    />
        <result property="workshopId"    column="workshop_id"    />
        <result property="workshopName"    column="workshop_name"    />
        <result property="deviceStatus"    column="device_status"    />
        <result property="deviceModel"    column="device_model"    />
        <result property="manufacturer"    column="manufacturer"    />
        <result property="purchaseDate"    column="purchase_date"    />
        <result property="price"    column="price"    />
        <result property="remark"    column="remark"    />
        <result property="delFlag"    column="del_flag"    />
        <result property="createBy"    column="create_by"    />
        <result property="createTime"    column="create_time"    />
        <result property="updateBy"    column="update_by"    />
        <result property="updateTime"    column="update_time"    />
    </resultMap>

    <!-- 根据ID查询 -->
    <sql id="selectMesWorkshopDeviceVo">
        select device_id, device_code, device_name, device_type, workshop_id, workshop_name, device_status, device_model, manufacturer, purchase_date, price, remark, del_flag, create_by, create_time, update_by, update_time from mes_workshop_device
    </sql>

    <!-- 查询单个 -->
    <select id="selectMesWorkshopDeviceByDeviceId" parameterType="Long" resultMap="MesWorkshopDeviceResult">
        <include refid="selectMesWorkshopDeviceVo"/>
        where device_id = #{deviceId}
    </select>
    <!-- 根据设备编号查询 -->
    <select id="selectMesWorkshopDeviceByDeviceCode" parameterType="String" resultMap="MesWorkshopDeviceResult">
        <include refid="selectMesWorkshopDeviceVo"/>
        where device_code = #{deviceCode}
    </select>

    <!-- 查询列表(核心:数据权限在此生效) -->
    <select id="selectMesWorkshopDeviceList" parameterType="com.ruoyi.mes.domain.MesWorkshopDevice" resultMap="MesWorkshopDeviceResult">
        select device_id, device_code, device_name, device_type, workshop_id, workshop_name, device_status, device_model, manufacturer, purchase_date, price, remark, del_flag, create_by, create_time, update_by, update_time 
        from mes_workshop_device d
        where d.del_flag = '0'
        <!-- 设备编号 -->
        <if test="deviceCode != null  and deviceCode != ''">
            and d.device_code like concat('%', #{deviceCode}, '%')
        </if>
        <!-- 设备名称 -->
        <if test="deviceName != null  and deviceName != ''">
            and d.device_name like concat('%', #{deviceName}, '%')
        </if>
        <!-- 设备类型 -->
        <if test="deviceType != null  and deviceType != ''">
            and d.device_type = #{deviceType}
        </if>
        <!-- 所属车间 -->
        <if test="workshopId != null">
            and d.workshop_id = #{workshopId}
        </if>
        <!-- 设备状态 -->
        <if test="deviceStatus != null  and deviceStatus != ''">
            and d.device_status = #{deviceStatus}
        </if>
        <!-- 数据权限:这里的d别名要和@DataScope(deptAlias="d")保持一致 -->
        ${params.dataScope}
    </select>

    <!-- 新增 -->
    <insert id="insertMesWorkshopDevice" parameterType="com.ruoyi.mes.domain.MesWorkshopDevice" useGeneratedKeys="true" keyProperty="deviceId">
        insert into mes_workshop_device
        <trim prefix="(" suffix=")" suffixOverrides=",">
            <if test="deviceCode != null">device_code,</if>
            <if test="deviceName != null">device_name,</if>
            <if test="deviceType != null">device_type,</if>
            <if test="workshopId != null">workshop_id,</if>
            <if test="workshopName != null">workshop_name,</if>
            <if test="deviceStatus != null">device_status,</if>
            <if test="deviceModel != null">device_model,</if>
            <if test="manufacturer != null">manufacturer,</if>
            <if test="purchaseDate != null">purchase_date,</if>
            <if test="price != null">price,</if>
            <if test="remark != null">remark,</if>
            <if test="delFlag != null">del_flag,</if>
            <if test="createBy != null">create_by,</if>
            <if test="createTime != null">create_time,</if>
        </trim>
        <trim prefix="values (" suffix=")" suffixOverrides=",">
            <if test="deviceCode != null">#{deviceCode},</if>
            <if test="deviceName != null">#{deviceName},</if>
            <if test="deviceType != null">#{deviceType},</if>
            <if test="workshopId != null">#{workshopId},</if>
            <if test="workshopName != null">#{workshopName},</if>
            <if test="deviceStatus != null">#{deviceStatus},</if>
            <if test="deviceModel != null">#{deviceModel},</if>
            <if test="manufacturer != null">#{manufacturer},</if>
            <if test="purchaseDate != null">#{purchaseDate},</if>
            <if test="price != null">#{price},</if>
            <if test="remark != null">#{remark},</if>
            <if test="delFlag != null">#{delFlag},</if>
            <if test="createBy != null">#{createBy},</if>
            <if test="createTime != null">#{createTime},</if>
        </trim>
    </insert>

    <!-- 修改 -->
    <update id="updateMesWorkshopDevice" parameterType="com.ruoyi.mes.domain.MesWorkshopDevice">
        update mes_workshop_device
        <trim prefix="SET" suffixOverrides=",">
            <if test="deviceCode != null">device_code = #{deviceCode},</if>
            <if test="deviceName != null">device_name = #{deviceName},</if>
            <if test="deviceType != null">device_type = #{deviceType},</if>
            <if test="workshopId != null">workshop_id = #{workshopId},</if>
            <if test="workshopName != null">workshop_name = #{workshopName},</if>
            <if test="deviceStatus != null">device_status = #{deviceStatus},</if>
            <if test="deviceModel != null">device_model = #{deviceModel},</if>
            <if test="manufacturer != null">manufacturer = #{manufacturer},</if>
            <if test="purchaseDate != null">purchase_date = #{purchaseDate},</if>
            <if test="price != null">price = #{price},</if>
            <if test="remark != null">remark = #{remark},</if>
            <if test="delFlag != null">del_flag = #{delFlag},</if>
            <if test="updateBy != null">update_by = #{updateBy},</if>
            <if test="updateTime != null">update_time = #{updateTime},</if>
        </trim>
        where device_id = #{deviceId}
    </update>

    <!-- 删除(逻辑删除) -->
    <delete id="deleteMesWorkshopDeviceByDeviceId" parameterType="Long">
        update mes_workshop_device set del_flag = '2' where device_id = #{deviceId}
    </delete>

    <!-- 批量删除 -->
    <delete id="deleteMesWorkshopDeviceByDeviceIds" parameterType="Long">
        update mes_workshop_device set del_flag = '2' where device_id in
        <foreach collection="array" item="deviceId" open="(" separator="," close=")">
            #{deviceId}
        </foreach>
    </delete>

    <!-- 检查设备编号是否唯一 -->
    <select id="checkDeviceCodeUnique" resultType="int">
        select count(*) from mes_workshop_device where device_code = #{deviceCode} and del_flag = '0' limit 1
    </select>
</mapper>
要点:
  • d别名:要和后面Controller的@DataScope(deptAlias = "d")保持一致
  • ${params.dataScope}:数据权限SQL插入口,AOP就是往这塞SQL
  • 逻辑删除:update set del_flag = '2',不是真删

Service接口:IMesWorkshopDeviceService.java

路径:com.ruoyi.mes.service.IMesWorkshopDeviceService
代码
点击查看代码
public interface IMesWorkshopDeviceService
{
    /**
     * 查询车间设备管理
     * @param deviceId 车间设备管理主键
     * @return 车间设备管理
     */
    public MesWorkshopDevice selectMesWorkshopDeviceByDeviceId(Long deviceId);

    /**
     * 查询车间设备管理列表
     * @param mesWorkshopDevice 车间设备管理
     * @return 车间设备管理集合
     */
    public List<MesWorkshopDevice> selectMesWorkshopDeviceList(MesWorkshopDevice mesWorkshopDevice);

    /**
     * 新增车间设备管理
     * @param mesWorkshopDevice 车间设备管理
     * @return 结果
     */
    public int insertMesWorkshopDevice(MesWorkshopDevice mesWorkshopDevice);

    /**
     * 修改车间设备管理
     * @param mesWorkshopDevice 车间设备管理
     * @return 结果
     */
    public int updateMesWorkshopDevice(MesWorkshopDevice mesWorkshopDevice);

    /**
     * 批量删除车间设备管理
     * @param deviceIds 需要删除的车间设备管理主键集合
     * @return 结果
     */
    public int deleteMesWorkshopDeviceByDeviceIds(Long[] deviceIds);

    /**
     * 删除车间设备管理信息
     * @param deviceId 车间设备管理主键
     * @return 结果
     */
    public int deleteMesWorkshopDeviceByDeviceId(Long deviceId);
    /**
     * 检查设备编号唯一性
     */
    public String checkDeviceCodeUnique(MesWorkshopDevice mesWorkshopDevice);
}

Service实现类:MesWorkshopDeviceServiceImpl.java

路径:com.ruoyi.mes.service.impl.MesWorkshopDeviceServiceImpl
代码
点击查看代码
@Service
public class MesWorkshopDeviceServiceImpl implements IMesWorkshopDeviceService
{
    @Autowired
    private MesWorkshopDeviceMapper mesWorkshopDeviceMapper;

    /**
     * 查询车间设备管理
     *
     * @param deviceId 车间设备管理主键
     * @return 车间设备管理
     */
    @Override
    public MesWorkshopDevice selectMesWorkshopDeviceByDeviceId(Long deviceId)
    {
        return mesWorkshopDeviceMapper.selectMesWorkshopDeviceByDeviceId(deviceId);
    }

    /**
     * 查询车间设备管理列表
     *
     * @param mesWorkshopDevice 车间设备管理
     * @return 车间设备管理
     */
    @Override
    public List<MesWorkshopDevice> selectMesWorkshopDeviceList(MesWorkshopDevice mesWorkshopDevice)
    {
        return mesWorkshopDeviceMapper.selectMesWorkshopDeviceList(mesWorkshopDevice);
    }

    /**
     * 新增车间设备管理
     *
     * @param mesWorkshopDevice 车间设备管理
     * @return 结果
     */
    @Override
    public int insertMesWorkshopDevice(MesWorkshopDevice mesWorkshopDevice)
    {
        return mesWorkshopDeviceMapper.insertMesWorkshopDevice(mesWorkshopDevice);
    }

    /**
     * 修改车间设备管理
     *
     * @param mesWorkshopDevice 车间设备管理
     * @return 结果
     */
    @Override
    public int updateMesWorkshopDevice(MesWorkshopDevice mesWorkshopDevice)
    {
        return mesWorkshopDeviceMapper.updateMesWorkshopDevice(mesWorkshopDevice);
    }

    /**
     * 批量删除车间设备管理
     *
     * @param deviceIds 需要删除的车间设备管理主键
     * @return 结果
     */
    @Override
    public int deleteMesWorkshopDeviceByDeviceIds(Long[] deviceIds)
    {
        return mesWorkshopDeviceMapper.deleteMesWorkshopDeviceByDeviceIds(deviceIds);
    }

    /**
     * 删除车间设备管理信息
     *
     * @param deviceId 车间设备管理主键
     * @return 结果
     */
    @Override
    public int deleteMesWorkshopDeviceByDeviceId(Long deviceId)
    {
        return mesWorkshopDeviceMapper.deleteMesWorkshopDeviceByDeviceId(deviceId);
    }

    /**
     * 检查设备编号是否唯一
     */
    @Override
    public boolean checkDeviceCodeUnique(MesWorkshopDevice mesWorkshopDevice) {
        Long deviceId = StringUtils.isNull(mesWorkshopDevice.getDeviceId()) ? -1L : mesWorkshopDevice.getDeviceId();
        MesWorkshopDevice info = mesWorkshopDeviceMapper.selectMesWorkshopDeviceByDeviceCode(mesWorkshopDevice.getDeviceCode());
        if (StringUtils.isNotNull(info) && info.getDeviceId().longValue() != deviceId.longValue()) {
            return UserConstants.NOT_UNIQUE;
        }
        return UserConstants.UNIQUE;
    }
}

Controller:MesWorkshopDeviceController.java

路径:com.ruoyi.mes.controller.MesWorkshopDeviceController
代码
点击查看代码
@RestController
@RequestMapping("/mes/device")
public class MesWorkshopDeviceController extends BaseController
{
    @Autowired
    private IMesWorkshopDeviceService mesWorkshopDeviceService;

    /**
     * 查询车间设备管理列表
     *
     * 数据权限说明:
     * - 超级管理员:所有设备
     * - 车间主任:本车间及子车间
     * - 普通员工:仅本人
     */
    @PreAuthorize("@ss.hasPermi('mes:device:list')")
    @GetMapping("/list")
    @DataScope(deptAlias = "d")
    public TableDataInfo list(MesWorkshopDevice mesWorkshopDevice)
    {
        startPage();
        List<MesWorkshopDevice> list = mesWorkshopDeviceService.selectMesWorkshopDeviceList(mesWorkshopDevice);
        return getDataTable(list);
    }

    /**
     * 导出车间设备管理列表
     */
    @PreAuthorize("@ss.hasPermi('mes:device:export')")
    @Log(title = "车间设备管理", businessType = BusinessType.EXPORT)
    @PostMapping("/export")
    public void export(HttpServletResponse response, MesWorkshopDevice mesWorkshopDevice)
    {
        List<MesWorkshopDevice> list = mesWorkshopDeviceService.selectMesWorkshopDeviceList(mesWorkshopDevice);
        ExcelUtil<MesWorkshopDevice> util = new ExcelUtil<MesWorkshopDevice>(MesWorkshopDevice.class);
        util.exportExcel(response, list, "车间设备管理数据");
    }

    /**
     * 获取车间设备管理详细信息
     */
    @PreAuthorize("@ss.hasPermi('mes:device:query')")
    @GetMapping(value = "/{deviceId}")
    public AjaxResult getInfo(@PathVariable("deviceId") Long deviceId)
    {
        return success(mesWorkshopDeviceService.selectMesWorkshopDeviceByDeviceId(deviceId));
    }

    /**
     * 新增车间设备管理
     */
    @PreAuthorize("@ss.hasPermi('mes:device:add')")
    @Log(title = "车间设备管理", businessType = BusinessType.INSERT)
    @PostMapping
    public AjaxResult add(@RequestBody MesWorkshopDevice mesWorkshopDevice)
    {
        // 校验设备编号唯一性
        if (!mesWorkshopDeviceService.checkDeviceCodeUnique(mesWorkshopDevice)){
            return error("新增设备失败,设备编号'" + mesWorkshopDevice.getDeviceCode() + "'已存在");
        }
        mesWorkshopDevice.setCreateBy(getUsername());
        return toAjax(mesWorkshopDeviceService.insertMesWorkshopDevice(mesWorkshopDevice));
    }

    /**
     * 修改车间设备管理
     */
    @PreAuthorize("@ss.hasPermi('mes:device:edit')")
    @Log(title = "车间设备管理", businessType = BusinessType.UPDATE)
    @PutMapping
    public AjaxResult edit(@RequestBody MesWorkshopDevice mesWorkshopDevice)
    {
        // 校验设备编号唯一性(排除自己)
        if (!mesWorkshopDeviceService.checkDeviceCodeUnique(mesWorkshopDevice)){
            return error("修改设备失败,设备编号'" + mesWorkshopDevice.getDeviceCode() + "'已存在");
        }
        mesWorkshopDevice.setUpdateBy(getUsername());
        return toAjax(mesWorkshopDeviceService.updateMesWorkshopDevice(mesWorkshopDevice));
    }

    /**
     * 删除车间设备管理
     */
    @PreAuthorize("@ss.hasPermi('mes:device:remove')")
    @Log(title = "车间设备管理", businessType = BusinessType.DELETE)
    @DeleteMapping("/{deviceIds}")
    public AjaxResult remove(@PathVariable Long[] deviceIds)
    {
        return toAjax(mesWorkshopDeviceService.deleteMesWorkshopDeviceByDeviceIds(deviceIds));
    }
}

手写代码——后台前端

创建API文件

路径:ruoyi-ui\src\api\mes\device.js
代码
点击查看代码
import request from '@/utils/request'

// 基础URL,对应你的Controller的@RequestMapping("/mes/device")
const baseURL = '/mes/device'

// 查询设备列表
export function listDevice(query) {
  return request({
    url: `${baseURL}/list`,
    method: 'get',
    params: query
  })
}

// 查询设备详情
export function getDevice(deviceId) {
  return request({
    url: `${baseURL}/${deviceId}`,
    method: 'get'
  })
}

// 新增设备
export function addDevice(data) {
  return request({
    url: baseURL,
    method: 'post',
    data: data
  })
}

// 修改设备
export function updateDevice(data) {
  return request({
    url: baseURL,
    method: 'put',
    data: data
  })
}

// 删除设备
export function delDevice(deviceIds) {
  return request({
    url: `${baseURL}/${deviceIds}`,
    method: 'delete'
  })
}

// 导出设备列表
export function exportDevice(query) {
  return request({
    url: `${baseURL}/export`,
    method: 'post',
    data: query,
    responseType: 'blob'  // 重要!导出用blob类型
  })
}

前端Vue页面

路径:ruoyi-ui/src/views/mes/device/index.vue
代码
点击查看代码
<template>
  <div class="app-container">
    <!-- 搜索栏 -->
    <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
      <el-form-item label="设备编号" prop="deviceCode">
        <el-input
          v-model="queryParams.deviceCode"
          placeholder="请输入设备编号"
          clearable
          @keyup.enter.native="handleQuery"
        />
      </el-form-item>
      <el-form-item label="设备名称" prop="deviceName">
        <el-input
          v-model="queryParams.deviceName"
          placeholder="请输入设备名称"
          clearable
          @keyup.enter.native="handleQuery"
        />
      </el-form-item>
      <el-form-item label="设备状态" prop="deviceStatus">
        <el-select v-model="queryParams.deviceStatus" placeholder="请选择设备状态" clearable>
          <el-option label="正常" value="0" />
          <el-option label="停机" value="1" />
          <el-option label="维修" value="2" />
          <el-option label="报废" value="3" />
        </el-select>
      </el-form-item>
      <el-form-item>
        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
      </el-form-item>
    </el-form>

    <!-- 按钮栏 -->
    <el-row :gutter="10" class="mb8">
      <el-col :span="1.5">
        <el-button
          type="primary"
          plain
          icon="el-icon-plus"
          size="mini"
          @click="handleAdd"
          v-hasPermi="['mes:device:add']"
        >新增</el-button>
      </el-col>
      <el-col :span="1.5">
        <el-button
          type="success"
          plain
          icon="el-icon-edit"
          size="mini"
          :disabled="single"
          @click="handleUpdate"
          v-hasPermi="['mes:device:edit']"
        >修改</el-button>
      </el-col>
      <el-col :span="1.5">
        <el-button
          type="danger"
          plain
          icon="el-icon-delete"
          size="mini"
          :disabled="multiple"
          @click="handleDelete"
          v-hasPermi="['mes:device:remove']"
        >删除</el-button>
      </el-col>
      <el-col :span="1.5">
        <el-button
          type="warning"
          plain
          icon="el-icon-download"
          size="mini"
          @click="handleExport"
          v-hasPermi="['mes:device:export']"
        >导出</el-button>
      </el-col>
      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
    </el-row>

    <!-- 表格 -->
    <el-table v-loading="loading" :data="deviceList" @selection-change="handleSelectionChange">
      <el-table-column type="selection" width="55" align="center" />
      <el-table-column label="设备ID" align="center" prop="deviceId" />
      <el-table-column label="设备编号" align="center" prop="deviceCode" />
      <el-table-column label="设备名称" align="center" prop="deviceName" />
      <el-table-column label="设备类型" align="center" prop="deviceType" />
      <el-table-column label="所属车间" align="center" prop="workshopName" />
      <el-table-column label="设备状态" align="center" prop="deviceStatus">
        <template slot-scope="scope">
          <dict-tag :options="dict.type.mes_device_status" :value="scope.row.deviceStatus"/>
        </template>
      </el-table-column>
      <el-table-column label="设备型号" align="center" prop="deviceModel" />
      <el-table-column label="生产厂家" align="center" prop="manufacturer" />
      <el-table-column label="购买日期" align="center" prop="purchaseDate" width="180">
        <template slot-scope="scope">
          <span>{{ parseTime(scope.row.purchaseDate, '{y}-{m}-{d}') }}</span>
        </template>
      </el-table-column>
      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
        <template slot-scope="scope">
          <el-button
            size="mini"
            type="text"
            icon="el-icon-edit"
            @click="handleUpdate(scope.row)"
            v-hasPermi="['mes:device:edit']"
          >修改</el-button>
          <el-button
            size="mini"
            type="text"
            icon="el-icon-delete"
            @click="handleDelete(scope.row)"
            v-hasPermi="['mes:device:remove']"
          >删除</el-button>
        </template>
      </el-table-column>
    </el-table>

    <!-- 分页 -->
    <pagination
      v-show="total>0"
      :total="total"
      :page.sync="queryParams.pageNum"
      :limit.sync="queryParams.pageSize"
      @pagination="getList"
    />

    <!-- 添加或修改对话框 -->
    <el-dialog :title="title" :visible.sync="open" width="800px" append-to-body>
      <el-form ref="form" :model="form" :rules="rules" label-width="100px">
        <el-row>
          <el-col :span="12">
            <el-form-item label="设备编号" prop="deviceCode">
              <el-input v-model="form.deviceCode" placeholder="请输入设备编号,如:LiuYi_001" />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="设备名称" prop="deviceName">
              <el-input v-model="form.deviceName" placeholder="请输入设备名称" />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row>
          <el-col :span="12">
            <el-form-item label="设备类型" prop="deviceType">
              <el-select v-model="form.deviceType" placeholder="请选择设备类型" style="width: 100%">
                <el-option label="加工设备" value="加工设备" />
                <el-option label="检测设备" value="检测设备" />
                <el-option label="辅助设备" value="辅助设备" />
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="所属车间" prop="workshopId">
              <treeselect v-model="form.workshopId" :options="workshopOptions" :normalizer="normalizer" placeholder="请选择所属车间" />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row>
          <el-col :span="12">
            <el-form-item label="设备状态" prop="deviceStatus">
              <el-select v-model="form.deviceStatus" placeholder="请选择设备状态" style="width: 100%">
                <el-option label="正常" value="0" />
                <el-option label="停机" value="1" />
                <el-option label="维修" value="2" />
                <el-option label="报废" value="3" />
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="设备型号" prop="deviceModel">
              <el-input v-model="form.deviceModel" placeholder="请输入设备型号" />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row>
          <el-col :span="12">
            <el-form-item label="生产厂家" prop="manufacturer">
              <el-input v-model="form.manufacturer" placeholder="请输入生产厂家" />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="购买日期" prop="purchaseDate">
              <el-date-picker clearable
                              v-model="form.purchaseDate"
                              type="date"
                              value-format="yyyy-MM-dd"
                              placeholder="请选择购买日期"
                              style="width: 100%">
              </el-date-picker>
            </el-form-item>
          </el-col>
        </el-row>
        <el-row>
          <el-col :span="12">
            <el-form-item label="设备价格" prop="price">
              <el-input-number v-model="form.price" controls-position="right" :precision="2" :min="0" style="width: 100%"/>
            </el-form-item>
          </el-col>
        </el-row>
        <el-row>
          <el-col :span="24">
            <el-form-item label="备注" prop="remark">
              <el-input v-model="form.remark" type="textarea" placeholder="请输入备注" />
            </el-form-item>
          </el-col>
        </el-row>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button type="primary" @click="submitForm">确 定</el-button>
        <el-button @click="cancel">取 消</el-button>
      </div>
    </el-dialog>
  </div>
</template>

<script>
import { listDevice, getDevice, delDevice, addDevice, updateDevice } from "@/api/mes/device";
import { treeselect } from "@/api/system/dept";
import Treeselect from "@riophae/vue-treeselect";
import "@riophae/vue-treeselect/dist/vue-treeselect.css";

export default {
  name: "Device",
  components: { Treeselect },
  dicts: ['mes_device_status'],
  data() {
    return {
      // 遮罩层
      loading: true,
      // 选中数组
      ids: [],
      // 非单个禁用
      single: true,
      // 非多个禁用
      multiple: true,
      // 显示搜索条件
      showSearch: true,
      // 总条数
      total: 0,
      // 车间设备管理表格数据
      deviceList: [],
      // 部门树选项
      workshopOptions: [],
      // 弹出层标题
      title: "",
      // 是否显示弹出层
      open: false,
      // 查询参数
      queryParams: {
        pageNum: 1,
        pageSize: 10,
        deviceCode: null,
        deviceName: null,
        deviceStatus: null,
        workshopId: null
      },
      // 表单参数
      form: {},
      // 表单校验
      rules: {
        deviceCode: [
          { required: true, message: "设备编号不能为空", trigger: "blur" },
          { pattern: /^[A-Z][a-zA-Z]*_\d{3}$/, message: "格式必须为:英文名_三位序号,如LiuYi_001", trigger: "blur" }
        ],
        deviceName: [
          { required: true, message: "设备名称不能为空", trigger: "blur" }
        ],
        workshopId: [
          { required: true, message: "请选择所属车间", trigger: "blur" }
        ],
        deviceStatus: [
          { required: true, message: "请选择设备状态", trigger: "blur" }
        ]
      }
    };
  },
  created() {
    this.getList();
    this.getTreeselect();
  },
  methods: {
    /** 查询车间设备管理列表 */
    getList() {
      this.loading = true;
      listDevice(this.queryParams).then(response => {
        this.deviceList = response.rows;
        this.total = response.total;
        this.loading = false;
      });
    },
    /** 查询部门下拉树结构 */
    getTreeselect() {
      treeselect().then(response => {
        this.workshopOptions = response.data;
      });
    },
    /** 转换菜单数据结构 */
    normalizer(node) {
      if (node.children && !node.children.length) {
        delete node.children;
      }
      return {
        id: node.id,
        label: node.label,
        children: node.children
      };
    },
    // 取消按钮
    cancel() {
      this.open = false;
      this.reset();
    },
    // 表单重置
    reset() {
      this.form = {
        deviceId: null,
        deviceCode: null,
        deviceName: null,
        deviceType: null,
        workshopId: null,
        workshopName: null,
        deviceStatus: "0",
        deviceModel: null,
        manufacturer: null,
        purchaseDate: null,
        price: null,
        remark: null
      };
      this.resetForm("form");
    },
    /** 搜索按钮操作 */
    handleQuery() {
      this.queryParams.pageNum = 1;
      this.getList();
    },
    /** 重置按钮操作 */
    resetQuery() {
      this.resetForm("queryForm");
      this.handleQuery();
    },
    // 多选框选中数据
    handleSelectionChange(selection) {
      this.ids = selection.map(item => item.deviceId);
      this.single = selection.length !== 1;
      this.multiple = !selection.length;
    },
    /** 新增按钮操作 */
    handleAdd() {
      this.reset();
      this.open = true;
      this.title = "添加车间设备";
    },
    /** 修改按钮操作 */
    handleUpdate(row) {
      this.reset();
      const deviceId = row.deviceId || this.ids[0];
      getDevice(deviceId).then(response => {
        this.form = response.data;
        this.open = true;
        this.title = "修改车间设备";
      });
    },
    /** 提交按钮 */
    submitForm() {
      this.$refs["form"].validate(valid => {
        if (valid) {
          // 根据车间ID填充车间名称
          const selectedDept = this.workshopOptions.find(dept => dept.id === this.form.workshopId);
          if (selectedDept) {
            this.form.workshopName = selectedDept.label;
          }
          if (this.form.deviceId != null) {
            updateDevice(this.form).then(response => {
              this.$modal.msgSuccess("修改成功");
              this.open = false;
              this.getList();
            });
          } else {
            addDevice(this.form).then(response => {
              this.$modal.msgSuccess("新增成功");
              this.open = false;
              this.getList();
            });
          }
        }
      });
    },
    /** 删除按钮操作 */
    handleDelete(row) {
      const deviceIds = row.deviceId || this.ids;
      this.$modal.confirm('是否确认删除设备编号为"' + row.deviceCode + '"的数据项?').then(function() {
        return delDevice(deviceIds);
      }).then(() => {
        this.getList();
        this.$modal.msgSuccess("删除成功");
      }).catch(() => {});
    },
    /** 导出按钮操作 */
    handleExport() {
      const queryParams = this.queryParams;
      this.$modal.confirm('是否确认导出所有设备数据项?').then(() => {
        this.exportLoading = true;
        return exportDevice(queryParams);
      }).then(response => {
        this.$download.name(response.msg);
        this.exportLoading = false;
      }).catch(() => {});
    }
  }
};
</script>

前端要点:

  • dicts: ['mes_device_status']:字典数据,在系统管理-字典管理里加mes_device_status字典
  • 校验规则:deviceCode用正则/[1][a-zA-Z]*_\d{3}$/强制格式为"英文名_三位序号"
  • @DataScope在后端的魔法 :前端无感知,后端自动过滤数据
  • v-hasPermi:按钮级权限控制,没权限的人看不到按钮

后台操作

添加字典

位置 系统管理-字典管理

字典类型:mes_device_status
字典名称:设备状态
字典数据:
键值:0-标签:正常
键值:1-标签:停机
键值:2-标签:维修
键值:3-标签:报废

  • 使用了 <dict-tag :options="dict.type.mes_device_status" ...>
  • 需要在系统管理-字典管理里添加 mes_device_status 字典:

添加菜单

位置 系统管理-菜单管理
字段 说明
菜单名称 车间管理 一级菜单名称
父菜单 主目录 根级别
菜单类型 目录 用来放子菜单的文件夹
路由地址 mes /mes开头的都归它管
显示排序 5 数字越小越靠前

添加子菜单"设备管理"

位置 系统管理-菜单管理
字段 说明
菜单名称 设备管理 页面标题
父菜单 车间管理 上一步创建的目录
菜单类型 菜单 真正的页面
路由地址 device 完整路径将是 /mes/device
组件路径 mes/device/index 对应 views/mes/device/index.vue
权限字符 mes:device:list 和Controller的@PreAuthorize对应
显示状态 显示
显示排序 1 在同级菜单中排第一
菜单图标 fa fa-cogel-icon-monitor 随便选个设备相关的

添加按钮

位置 系统管理-菜单管理
字段
菜单名称 查询
父菜单 设备管理
菜单类型 按钮
权限字符 mes:device:query
字段
菜单名称 新增
父菜单 设备管理
菜单类型 按钮
权限字符 mes:device:add
字段
菜单名称 修改
父菜单 设备管理
菜单类型 按钮
权限字符 mes:device:edit
字段
菜单名称 删除
父菜单 设备管理
菜单类型 按钮
权限字符 mes:device:remove
字段
菜单名称 导出
父菜单 设备管理
菜单类型 按钮
权限字符 mes:device:export
菜单添加成功

手写了之后已经彻底忘记,作业是权限分配

权限添加

抄自:https://blog.csdn.net/2301_80194233/article/details/155482968?spm=1011.2415.3001.5331
image
抄自:https://blog.csdn.net/2301_80194233/article/details/155482968?spm=1011.2415.3001.5331
image

结束

感觉在自己给自己找罪受,写了5个多小时,现在存在一个问题,时间好像不够?
一个小作业可能需要半天一天来写
一周会增加3-6个小作业,要花掉2-3天的时间
大作业简单的一天,难的一个星期起步
最后的3周,目前出现4个大作业,预计还会增加3个大作业


  1. A-Z ↩︎

posted @ 2025-12-04 22:15  The_Fool_l  阅读(11)  评论(0)    收藏  举报