企业设备运行管理平台——如何计算设备当天使用效率

该项目为前后端分离的基础项目,业务重点围绕设备管理、故障管理、保养管理、关注管理、设备运行数据管理等模块,而我主要负责故障管理、设备运行数据管理模块,下面我细讲一下设备运行数据管理中使用效率管理是怎么实现的。

一.系统需求分析

根据他的需求分析,补充如何计算设备当天使用效率

5.2使用效率管理

    展示所有设备使用平均,使用效率计算方法:绿灯使用时间/(绿灯+黄灯+红灯时间)列表包含:日期、设备编号、设备名称、当天使用效率(绿灯/24)、累计使用效率(每天凌晨累加当天的使用效率)

二、系统开发的配置

1.开发环境版本:JDK 8
2.开发计算机系统:windows
3.开发工具:后端----------IDEA

                     前端----------Visual Studio Code

                     数据库-------Navicat 15 for MySQL

4.框架使用:前端-----------vue+element ui等

                     后端-----------springboot+mybatis/mybatis-plus+springmvc等

三、项目部分模块的架构

1.数据库

计算设备当天使用效率,需要两张表分别为设备表、设备状态记录表。

设备表的设计如下:

设备表

设备状态记录表的设计如下:

设备状态记录表

2.后端包层

3.mapper的xml

4.前端的页面

在后端把计算出来,并赋给设备表中day_efficiency字段,然后在前端展示。

四、具体实现

1.实体类
DevicesEntity设备实体
package com.wedu.modules.xxx_supervise.entity;

import cn.hutool.core.annotation.Alias;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;

import java.io.Serializable;
import java.util.Date;

//@TableName
@Data
@TableName("devices")
public class DevicesEntity implements Serializable {
    private static final long serialVersionUID = 1L;

    //车间
    @Alias("车间")
    private String workshopName;
    // 设备类型 0:其他设备   1:生产设备
    @Alias("设备型号")
    private Integer deviceType;
    //设备编号(主键)
    @TableId(type = IdType.AUTO)
    @Alias("设备ID")
    private Long deviceId;
    //设备名
    @Alias("设备名称")
    private String deviceName;
    @Alias("设备型号")
    //设备型号
    private String deviceModel;
    //制造厂
    @Alias("制造厂")
    private String manufacturer;
    //生产日期
    @Alias("生产日期")
    private Date productionTime;
    //开始使用日期
    @Alias("开始使用时间")
    private Date useTime;
    //维保到期
    @Alias("保养到期时间")
    private Date maintenanceTime;
    //保养周期
    @Alias("保养周期(天)")
    private Integer maintenancePeriod;
    //备注
    @Alias("备注")
    private String remark;
    //当日的效率
    @Alias("当日的效率 ")
    private double dayEfficiency;
    //累计的效率
    @Alias("累计的效率 ")
    private double totalEfficiency;
    //传感器ID
    @Alias("传感器ID")
    private String sensorId;
    //预警周期
    @Alias("预警周期(天)")
    private Integer forewarningPeriod;
    //预警状态
    @Alias("预警状态(0未预警 1预警 2预警过期)")
    private Integer forewarningStatus;
    //设备状态 0:正常  1:保养 2:故障 3:维修中 4:保养中
    private Integer status;
    //逻辑删除 当使用该注解时,MP会自动将删除逻辑改为更新逻辑
    @TableLogic(value = "0", delval = "1")
    private Integer isDeleted;
    //创建时间
    @Alias("创建时间")
    private Date createTime;
    //创建者id
    @Alias("创建者id")
    private Long createUserId;
    //更新时间
    @Alias("更新时间")
    private Date updateTime;
    //更新者id
    @Alias("更新者id")
    private Long updateUserId;
    //红灯开始时间
    @Alias("红灯开始时间")
    private Date redFistTime;
    //故障开始时间
    public Integer setStatus(Integer status) {
        this.status = status;
        if (status !=null && status==2){
            this.setRedFistTime(new Date());
        }
        return status;
    }
    //当前用户是否关注此设备
    @TableField(exist = false)
    private Integer attentionStatus;//设备实体类新增属性
    //数量
    @TableField(exist = false)
   private long dataCount;

}
DevicesStateEntity设备状态记录
package com.wedu.modules.xxx_supervise.entity;

import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;

import java.io.Serializable;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Date;

//@TableName
@Data
@TableName("devices_state")
public class DevicesStateEntity implements Serializable {
    private static final long serialVersionUID = 1L;
    //设备状态记录id
    @TableId(type = IdType.AUTO)
    private Long id;
    //设备编号
    private Long deviceId;
    //灯开始时间
    private Date lightFistTime;
    //灯结束时间
    private Date lightEndTime;
    //灯的状态
    private Integer status;
    //红灯时长
    private String redMaintainTime;
    //红灯时长标准为秒
    private Long redMaintainTimeS;
    //黄灯时长
    private String yMaintainTime;
    //黄灯时长标准为秒
    private Long yMaintainTimeS;
    //逻辑删除 当使用该注解时,MP会自动将删除逻辑改为更新逻辑
    @TableLogic(value = "0", delval = "1")
    private Integer isDelete;
    //创建时间
    private Date createTime;
    //创建者id
    private Long createBy;
    //更新时间
    private Date updateTime;
    //更新者id
    private Long updateBy;
    //总绿灯时长
    @TableField(exist = false)
    private String greenLightTime;
    //总红灯时长
    @TableField(exist = false)
    private String redLightTime;
    //总黄灯时长
    @TableField(exist = false)
    private String yellowLightTime;
    //设备表的id
    @TableField(exist = false)
    private Long dId;
    //设备名
    @TableField(exist = false)
    private String deviceName;

    @TableField(exist = false)
    private Integer dataNum;

    @TableField(exist = false)
    private Long  d1Id;


}
2.在业务逻辑层的RuningDataServiceImpl中计算当天绿灯的效率

(一)在DevicesService接口中创建queryPageAllStateRecord()方法和RuningDataService接口中创建DeviceDayEfficiency()方法

/**
     * 所有设备当天的使用效率
     * @param params
     * @return
     */
 PageUtils queryEfficiencyPage(Map<String, Object> params);
 /**
     * 设备当天的使用效率
     * @param
     */
    void DeviceDayEfficiency();

(二)在RuningDataServiceImpl类中创建DeviceDayEfficiency()方法计算绿灯的效率

/**
     * 计算设备当天的使用效率
     * @param
     */
    @Override
    public void DeviceDayEfficiency() {

(三)在DevicesStateDao.xml中创建两个查询

        查询设备表中的所有设备在设备状态记录有多少条数据

  <!--查询设备表中的所有设备在设备状态记录有多少条数据-->
    <select id="countDevicesState" resultType="com.wedu.modules.wzh_supervise.entity.DevicesStateEntity">
        SELECT d.device_id d1_id, COUNT(ds.device_id) AS dataNum
        FROM devices d
                 LEFT JOIN devices_state ds ON ds.device_id = d.device_id
                                                   AND ds.is_delete = 0
                                                   AND DATE(ds.light_fist_time) = CURDATE()
        WHERE d.is_deleted = 0
        GROUP BY d.device_id

    </select>

        根据设备id查询该设备id在设备状态记录表中当天所有记录

<!--根据设备id查询该设备id在设备状态记录表中当天所有记录-->
    <select id="AllDevicesStateBydeviceId" resultType="com.wedu.modules.wzh_supervise.entity.DevicesStateEntity">
        SELECT device_id,light_fist_time , status
        FROM devices_state ds
        where  DATE(ds.light_fist_time) = CURDATE() and ds.device_id=#{deviceId}
        order by device_id , light_fist_time
    </select>

(四)在DevicesStateDao中接收这两个查询,并封装到集合中

    List<DevicesStateEntity> countDevicesState();
    List<DevicesStateEntity> AllDevicesStateBydeviceId(Long deviceId);

(五)在DeviceDayEfficiency()方法中首先调用devicesStateDao类中countDevicesState()方法当天获取设备表的所有设备在设备状态记录表中有多少条数据,然后判断当天获取设备表的哪个设备在设备状态记录表中没有记录,如果没有记录就只有两种情况1.该设备在当天是一致是正常的2.该设备在当天是一致是不正常的,那么一致正常其效率为1,一致不正常其效率为0;


        /*当天获取设备表的所有设备在设备状态记录表中有多少条数据*/
        //用sql语句多表联查,获取数据装到一个集合里
        List<DevicesStateEntity> xxx = devicesStateDao.countDevicesState();
        //遍历集合
        for (DevicesStateEntity devicesStateEntity : xxx) {
            /*当天获取设备表的哪个设备在设备状态记录表中没有记录*/
            if (devicesStateEntity.getDataNum() == 0) {
                //那就根据设备id把该设备查出来
                QueryWrapper<DevicesEntity> queryWrapper1 = new QueryWrapper<>();
                queryWrapper1.eq("device_id", devicesStateEntity.getD1Id());
                DevicesEntity devicesEntity1 = devicesDao.selectOne(queryWrapper1);
                //如果该设备的状态为正常
                if (devicesEntity1.getStatus() == 0) {
                    //证明这一天都是正常的,其效率为100%
                    devicesEntity1.setDayEfficiency(1);
                    //如果该设备的状态不是正常的
                } else {
                    //证明这一天的效率状态不正常效率为0%
                    devicesEntity1.setDayEfficiency(0);
                }
                //修改该设备
                devicesDao.updateById(devicesEntity1);
                
            }
            

 (六)如果该设备在状态记录表有数据,根据其设备id,把它在设备状态记录中的所有记录获取,然后这些数据放到集合中在调用calculateGreenLightDuration()方法计算其设备在当天的绿灯时长,将绿灯时长/24,最后将其值传到设备表中day_efficiency字段中

else if (devicesStateEntity.getDataNum() != 0) {
                 //根据其设备id,把它在设备状态记录中的所有记录获取
                List<DevicesStateEntity> mys = devicesStateDao.AllDevicesStateBydeviceId(devicesStateEntity.getD1Id());
                System.out.println(mys);
                //  解析数据
                // 创建用于存储DeviceStatusRecord对象的集合
                List<DevicesStateEntity> deviceStatusRecords = new ArrayList<>();
                    // 遍历mys列表
                for (DevicesStateEntity record : mys) {
                    // record.getLinghtFistTime()返回LocalDateTime
                    // 创建DeviceStatusRecord对象并添加到集合中
                            record.getDeviceId();
                           record.getLightFistTime();//直接传递record.getLinghtFistTime()
                            record.getStatus();
                            /*把DevicesStateEntity中的设备id、灯开始时间、设备状态添加到一个集合中*/
                    deviceStatusRecords.add(record);
                    System.out.println(deviceStatusRecords);
                }
                /*计算其设备在当天的效率*/
                //计算其设备在当天绿灯
                long greenLightDuration = calculateGreenLightDuration(deviceStatusRecords);
                double greenLightDurationInHours = greenLightDuration / (60.0 * 60 * 1000); // 转换为小时
                System.out.printf("当天绿灯的时长为:%.2f小时\n", greenLightDurationInHours);
                /*根据设备id把其设备获取*/
                QueryWrapper<DevicesEntity> queryWrapper1 = new QueryWrapper<>();
                queryWrapper1.eq("device_id",devicesStateEntity.getD1Id());
                DevicesEntity devicesEntity1 = devicesDao.selectOne(queryWrapper1);
                //将计算好的效率赋给设备表中效率字段
                // 保留两位小数不进位
                devicesEntity1.setDayEfficiency( Math.floor(greenLightDurationInHours/24 * 100) / 100);
                //更新设备表
                devicesDao.updateById(devicesEntity1);

(七)下面是计算绿灯时长所用的方法

  //返回当天的当天的0点,格式为xxxx-xx-xx 00:00:00
    public static Date getStartOfDay() {
        // 创建一个SimpleDateFormat对象,用于格式化日期为"yyyy-MM-dd HH:mm:ss"的格式
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
// 获取当前时间的Calendar实例
        Calendar calendar = Calendar.getInstance();
        // 将Calendar的小时设置为0,表示午夜
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        // 将Calendar的分钟设置为0
        calendar.set(Calendar.MINUTE, 0);
        // 将Calendar的秒设置为0
        calendar.set(Calendar.SECOND, 0);
        // 将Calendar的毫秒设置为0
        calendar.set(Calendar.MILLISECOND, 0);
        // 获取Calendar对象所表示的时间
        Date start = calendar.getTime();
        // 使用SimpleDateFormat对象将Date对象格式化为字符串,并打印出来
        System.out.println("Start of the day: " + sdf.format(start));
        // 返回当天0点的Date对象
        return start;
    }
    //返回当天的当天的23点,格式为xxxx-xx-xx 23:59:59
    public static Date getEndOfDay() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        calendar.set(Calendar.MILLISECOND, 999);
        Date end = calendar.getTime();
        System.out.println("Start of the day: " + sdf.format(end));
        return end;
    }
    //计算当天绿灯
    private  long calculateGreenLightDuration(List<DevicesStateEntity> trafficDataList) {
        // 初始化变量来存储总绿灯时间
        long greenLightDuration = 0;
        // 获取一天的开始时间
        Date start = getStartOfDay();
        // 获取一天的结束时间
        Date end = getEndOfDay();
        /*如果只有一条数据,其状态为0,那么绿灯时间是从状态为0的时间到一天结束,
        其状态不为0,那么绿灯时间是从一天开始时间到状态不为0的时间*/
        // 检查trafficDataList中是否只有一个数据项
        if (trafficDataList.size() == 1) {
            // 获取数据项
            DevicesStateEntity data = trafficDataList.get(0);
            // 检查状态是否为0(绿灯)
            if (data.getStatus() == 0) {
                // 计算绿灯持续时间直到一天结束
                greenLightDuration = end.getTime() - data.getLightFistTime().getTime();
            } else {
                // 计算绿灯持续时间从一天开始
                greenLightDuration = data.getLightFistTime().getTime() - start.getTime();
            }
            /*如果数据是多条的,其状态2-0-2-0-2-0,
            如果第一个状态为2,证明从0点开始到第一个状态为2,
            其时间是为绿灯时间的。如果最后个状态为0,
            证明从最后状态为0的时间到这一天结束,
            其时间也是绿灯时间的,
            那么绿灯时间是从一天开始到第一个状态2的时间加上期间状态从0变2的时间加上最后状态0的时间到一天结束的时间*/
            /*如果数据是多条的,其状态0-2-0-2,那么绿灯时间是所有状态从0变2的时间相加*/
        } else {
            // 处理trafficDataList中的多个数据项
            // 检查第一个数据项的状态
            if (trafficDataList.get(0).getStatus() == 2 || trafficDataList.get(0).getStatus() == 1) {
                // 计算从一天开始到第一个绿灯的持续时间
                greenLightDuration += trafficDataList.get(0).getLightFistTime().getTime() - start.getTime();
            }
            // 遍历剩下的数据项
            for (int i = 0; i < trafficDataList.size() - 1; i++) {
                DevicesStateEntity current = trafficDataList.get(i);
                DevicesStateEntity next = trafficDataList.get(i + 1);
                // 检查当前状态是否为绿灯并且下一个状态是黄灯或红灯
                if (current.getStatus() == 0 && (next.getStatus() == 2||next.getStatus() == 1)) {
                    // 计算当前状态和下一个状态变化之间的绿灯持续时间
                    greenLightDuration += next.getLightFistTime().getTime() - current.getLightFistTime().getTime();
                }
            }
            // 检查最后一个数据项的状态
            if (trafficDataList.get(trafficDataList.size() - 1).getStatus() == 0) {
                // 计算从最后一个绿灯到一天结束的持续时间
                greenLightDuration += end.getTime() - trafficDataList.get(trafficDataList.size() - 1).getLightFistTime().getTime();
            }
        }
        // 返回总绿灯时间
        return greenLightDuration;
    }

  (八)在数据库添加一事件,实现数据库每天每天凌晨把day_efficiency字段清零,然后把day_efficiency加到total_efficiency中。

-- 创建每天凌晨更新累计效率和清空当日效率
DROP EVENT IF EXISTS evt_reset_daily_efficiency;
CREATE EVENT evt_reset_daily_efficiency
    ON SCHEDULE EVERY 1 DAY
        STARTS TIMESTAMP(CURRENT_DATE, '00:00:00') -- 设置开始时间为今天凌晨
    DO
    BEGIN
        UPDATE devices
        SET day_efficiency = 0,
            total_efficiency = total_efficiency + COALESCE(day_efficiency, 0);
    END;

(九)在DevicesServiceImpl在重写queryEfficiencyPage()展示效率列表。

/**
     * 效率列表
     * 分页和模糊查询
     * @param params 框架自动把url参数或者表单参数封装为map
     * @return
     */
    @Override
    public PageUtils queryEfficiencyPage(Map<String, Object> params) {
        //从请求参数中获取设备名
        String deviceName = (String) params.get("deviceName");
        IPage<DevicesEntity> page = this.page(
                new Query<DevicesEntity>().getPage(params),
                new QueryWrapper<DevicesEntity>()
                        .like(StringUtils.isNotBlank(deviceName), "device_name", deviceName)
                        .orderByDesc("update_time")
        );
        return new PageUtils(page);
    }
3. 在控制层RuningDataController类,调用DeviceDayEfficiency(),queryEfficiencyPage(params)这两个方法。
/**
     * 效率列表
     * 分页和模糊查询
     * @param params 框架自动把url参数或者表单参数封装为map
     * @return
     */
    @GetMapping("/efficiency/Alllist")
    public R queryAllDevicesEfficiency(@RequestParam Map<String, Object> params) {
        //计算当天效率
        runingDataService.DeviceDayEfficiency();
        PageUtils page = devicesService.queryEfficiencyPage(params);
        return R.ok().put("page", page);
    }
4.在前端把该页面展示出来
<template>
  <div class="mod-devices">
<!--  运行状态管理-->
    <!-- 查询表单 -->
    <el-form :inline="true" :model="dataForm" @keyup.enter.native="search()">
      <el-form-item>
        <el-input v-model="dataForm.deviceName" placeholder="请输入设备名" clearable></el-input>
      </el-form-item>
      <el-form-item>
        <el-button @click="search()">查询</el-button>
      </el-form-item>
    </el-form>
    <!-- 数据展示列表 -->
    <el-table :data="dataList" border v-loading="dataListLoading"
      style="width: 100%;">
      <el-table-column prop="deviceId" header-align="center" align="center" label="设备ID"></el-table-column>
      <el-table-column prop="deviceName" header-align="center" align="center" label="设备名"></el-table-column>
      <el-table-column prop="status" header-align="center" align="center" label="运行状态">
        <template slot-scope="scope">
          <el-tag v-if="scope.row.status === 0" size="small">正常</el-tag>
          <el-tag v-else-if="scope.row.status === 1" size="small" type="warning">保养</el-tag>
          <el-tag v-else-if="scope.row.status === 4" size="small" type="warning">保养中</el-tag>
          <el-tag v-else-if="scope.row.status === 3" size="small" style="background-color: #a78ba7; color: #7918a0 ;">维修中</el-tag>
          <el-tag v-else size="small" type="danger">故障</el-tag>
        </template>
      </el-table-column>
      <el-table-column prop="efficiency" header-align="center" align="center" label="当天使用效率">
        <template slot-scope="scope">
          <el-text >{{(scope.row.dayEfficiency)*100}}%</el-text>
        </template>
      </el-table-column>
      <el-table-column header-align="center" align="center" label="积累使用效率">
        <template slot-scope="scope">
          <el-text >{{(scope.row.totalEfficiency)*100}}%</el-text>
        </template>
      </el-table-column>
    </el-table>
    <!-- 分页工具条 -->
    <el-pagination @size-change="sizeChangeHandle" @current-change="currentChangeHandle" :current-page="pageIndex"
      :page-sizes="[10, 20, 30, 40]" :page-size="pageSize" :total="totalPage"
      layout="total, sizes, prev, pager, next, jumper">
    </el-pagination>
  </div>
</template>
<script>
export default {
  // 数据域
  data () {
    return {
      // 查询表单数据模型
      dataForm: {
        faultManifestation: ''
      },
      // 当前页码
      pageIndex: 1,
      // 每页记录数
      pageSize: 10,
      // 总页数
      totalPage: 0,
      // 设备数据列表
      dataList: [],
      // 批量删除数组 数组元素为设备对象
      dataListSelections: [],
      // 是否显示加载动效
      dataListLoading: false
    }
  },
  // 声明组件
  components: {
  },
  // 生命周期函数
  mounted () {
    this.getDataList()
  },
  // 修改状态
  methods: {
    // 每页记录数
    sizeChangeHandle (val) {
      this.pageSize = val
      this.getDataList()
    },
    // 当前页
    currentChangeHandle (val) {
      this.pageIndex = val
      this.getDataList()
    },
    // 查询表单的查询按钮以及回车事件绑定
    search () {
      // this.pageIndex = 1;
      /* alert(this.dataForm.goodsName) */
      this.getDataList()
    },
    getDataList () {
      // 发送查询请求
      this.$http({
        url: this.$http.adornUrl('/xxx/runingData/efficiency/Alllist'),
        method: 'get',
        params: this.$http.adornParams({
          'page': this.pageIndex,
          'limit': this.pageSize,
          'deviceName': this.dataForm.deviceName
          // 'status': this.dataForm.status
        })
      }).then(resp => {
        /* console.log(resp); */
        let code = resp.data.code
        if (!code && resp.data.code === 0) {
          this.dataList = resp.data.page.list
          this.totalPage = resp.data.page.totalCount
        }
      })
    }
  }
}
</script>
5.结果展示

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值