huang
2025-03-18 67c9118cffb7d7407668bbbad4c64f9aaf21ba0d
看板能耗管理
1个文件已修改
6个文件已添加
550 ■■■■■ 已修改文件
JiuMuMesParent/moduleService/DeviceInteractionModule/src/main/java/com/mes/energy/controller/EnergyConsumptionController.java 89 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
JiuMuMesParent/moduleService/DeviceInteractionModule/src/main/java/com/mes/energy/entity/EnergyConsumption.java 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
JiuMuMesParent/moduleService/DeviceInteractionModule/src/main/java/com/mes/energy/mapper/EnergyConsumptionMapper.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
JiuMuMesParent/moduleService/DeviceInteractionModule/src/main/java/com/mes/energy/service/EnergyConsumptionService.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
JiuMuMesParent/moduleService/DeviceInteractionModule/src/main/java/com/mes/energy/service/impl/EnergyConsumptionServiceImpl.java 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
UI-Project/src/views/Energy/energyConsumption.vue 254 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
UI-Project/src/views/KanbanDisplay/kanbanDisplay.vue 129 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
JiuMuMesParent/moduleService/DeviceInteractionModule/src/main/java/com/mes/energy/controller/EnergyConsumptionController.java
New file
@@ -0,0 +1,89 @@
package com.mes.energy.controller;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.mes.energy.entity.EnergyConsumption;
import com.mes.energy.service.EnergyConsumptionService;
import com.mes.utils.Result;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Api(tags = "能源管理")
@RestController
@RequestMapping("/energy/consumption")
public class EnergyConsumptionController {
    @Autowired
    private EnergyConsumptionService energyService;
    @ApiOperation("获取能耗数据列表")
    @PostMapping("/listEnergy")
    @ResponseBody
    public Result list(@RequestBody Map<String, Object> params) {
        Integer page = params.get("page") == null ? 1 : (Integer) params.get("page");
        Integer pageSize = params.get("pageSize") == null ? 10 : (Integer) params.get("pageSize");
        Page<EnergyConsumption> pageData = energyService.page(
            new Page<>(page, pageSize),
            new QueryWrapper<EnergyConsumption>().orderByDesc("record_date")
        );
        return Result.build(200, "查询成功", pageData);
    }
    @ApiOperation("添加能耗数据")
    @PostMapping("/addEnergy")
    @ResponseBody
    public Result add(@RequestBody EnergyConsumption consumption) {
        consumption.setCreatedAt(new Date());
        consumption.setUpdatedAt(new Date());
        int count = energyService.save(consumption) ? 1 : 0;
        String message = count > 0 ? "添加成功:" + count : "添加失败!";
        return Result.build(200, message, count);
    }
    @ApiOperation("修改能耗数据")
    @PostMapping("/updateEnergy")
    @ResponseBody
    public Result update(@RequestBody EnergyConsumption consumption) {
        consumption.setUpdatedAt(new Date());
        int count = energyService.updateById(consumption) ? 1 : 0;
        String message = count > 0 ? "修改成功:" + count : "修改失败!";
        energyService.notifyEnergyUpdate(consumption);
        return Result.build(200, message, count);
    }
    @ApiOperation("删除能耗数据")
    @PostMapping("/deleteEnergy")
    @ResponseBody
    public Result delete(@RequestBody EnergyConsumption consumption) {
        int count = energyService.removeById(consumption.getId()) ? 1 : 0;
        String message = count > 0 ? "删除成功:" + count : "删除失败!";
        return Result.build(200, message, count);
    }
    @ApiOperation("获取图表数据")
    @PostMapping("/chartEnergy")
    @ResponseBody
    public Result getChartData() {
        List<EnergyConsumption> data = energyService.list(
            new QueryWrapper<EnergyConsumption>()
                .orderByAsc("record_date")
                .last("limit 30")
        );
        Map<String, Object> result = new HashMap<>();
        result.put("actual", data);
        result.put("planned", null);
        return Result.build(200, "查询成功", result);
    }
}
JiuMuMesParent/moduleService/DeviceInteractionModule/src/main/java/com/mes/energy/entity/EnergyConsumption.java
New file
@@ -0,0 +1,32 @@
package com.mes.energy.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Date;
@Data
@TableName("energy_consumption")
public class EnergyConsumption {
    @TableId(type = IdType.AUTO)
    private Integer id;
    @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
    private Date recordDate;
    private Double energyValue;
    private Integer userId;
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private Date createdAt;
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private Date updatedAt;
}
JiuMuMesParent/moduleService/DeviceInteractionModule/src/main/java/com/mes/energy/mapper/EnergyConsumptionMapper.java
New file
@@ -0,0 +1,9 @@
package com.mes.energy.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.mes.energy.entity.EnergyConsumption;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface EnergyConsumptionMapper extends BaseMapper<EnergyConsumption> {
}
JiuMuMesParent/moduleService/DeviceInteractionModule/src/main/java/com/mes/energy/service/EnergyConsumptionService.java
New file
@@ -0,0 +1,8 @@
package com.mes.energy.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.mes.energy.entity.EnergyConsumption;
public interface EnergyConsumptionService extends IService<EnergyConsumption> {
    void notifyEnergyUpdate(EnergyConsumption consumption);
}
JiuMuMesParent/moduleService/DeviceInteractionModule/src/main/java/com/mes/energy/service/impl/EnergyConsumptionServiceImpl.java
New file
@@ -0,0 +1,29 @@
package com.mes.energy.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.mes.energy.entity.EnergyConsumption;
import com.mes.energy.mapper.EnergyConsumptionMapper;
import com.mes.energy.service.EnergyConsumptionService;
import com.mes.tools.WebSocketServer;
import cn.hutool.json.JSONObject;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
@Service
public class EnergyConsumptionServiceImpl extends ServiceImpl<EnergyConsumptionMapper, EnergyConsumption> implements EnergyConsumptionService {
    @Override
    public void notifyEnergyUpdate(EnergyConsumption consumption) {
        JSONObject message = new JSONObject();
        message.set("type", "energy_update");
        message.set("data", consumption);
        ArrayList<WebSocketServer> servers = WebSocketServer.sessionMap.get("energy");
        if (servers != null) {
            for (WebSocketServer server : servers) {
                server.sendMessage(message.toString());
            }
        }
    }
}
UI-Project/src/views/Energy/energyConsumption.vue
New file
@@ -0,0 +1,254 @@
<script setup>
import { ref } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import request from '@/utils/request'
// 数据定义
const formData = ref({
  recordDate: new Date().toISOString().slice(0, 10),
  energyValue: null
})
const loading = ref(false)
const energyData = ref([])
// 日期格式化
const formatDate = (dateStr) => {
  const date = new Date(dateStr)
  return date.toISOString().slice(0, 10)
}
// 检查日期是否重复
const checkDateExists = (date, excludeId = null) => {
  return energyData.value.some(item =>
    item.recordDate === date && (!excludeId || item.id !== excludeId)
  )
}
// API 请求
const loadDataFromApi = async () => {
  loading.value = true
  try {
    const { data } = await request({
      url: '/deviceInteraction/energy/consumption/listEnergy',
      method: 'post',
      data: { page: 1, pageSize: 10 }
    })
    if (data?.records) {
      energyData.value = data.records.map(item => ({
        ...item,
        editing: false,
        originalData: { ...item }
      }))
    }
  } catch (error) {
    ElMessage.error('数据加载失败')
    console.error(error)
  } finally {
    loading.value = false
  }
}
// 表单操作
const handleSubmit = async () => {
  if (!formData.value.recordDate || formData.value.energyValue === null) {
    ElMessage.error('请填写完整信息')
    return
  }
  if (checkDateExists(formData.value.recordDate)) {
    ElMessage.error('该日期已存在能耗记录')
    return
  }
  try {
    await request({
      url: '/deviceInteraction/energy/consumption/addEnergy',
      method: 'post',
      data: formData.value
    })
    ElMessage.success('添加成功')
    await loadDataFromApi()
    resetForm()
  } catch (error) {
    ElMessage.error('添加失败')
    console.error(error)
  }
}
const resetForm = () => {
  formData.value = {
    recordDate: new Date().toISOString().slice(0, 10),
    energyValue: null
  }
}
// 表格操作
const handleRowEdit = async (index, row) => {
  if (!row.editing) {
    row.editing = true
    return
  }
  if (!row.recordDate || row.energyValue === null) {
    ElMessage.error('请填写完整信息')
    return
  }
  if (checkDateExists(row.recordDate, row.id)) {
    ElMessage.error('该日期已存在能耗记录')
    return
  }
  try {
    await request({
      url: '/deviceInteraction/energy/consumption/updateEnergy',
      method: 'post',
      data: {
        id: row.id,
        recordDate: row.recordDate,
        energyValue: row.energyValue
      }
    })
    row.editing = false
    row.originalData = { ...row }
    ElMessage.success('修改成功')
  } catch (error) {
    ElMessage.error('修改失败')
    console.error(error)
  }
}
const cancelEdit = (index, row) => {
  Object.assign(row, row.originalData)
  row.editing = false
}
const handleDelete = async (index) => {
  try {
    await ElMessageBox.confirm('确认删除该记录?', '警告', {
      type: 'warning'
    })
    const id = energyData.value[index].id
    await request({
      url: '/deviceInteraction/energy/consumption/deleteEnergy',
      method: 'post',
      data: { id }
    })
    energyData.value.splice(index, 1)
    ElMessage.success('删除成功')
  } catch (error) {
    if (error !== 'cancel') {
      ElMessage.error('删除失败')
      console.error(error)
    }
  }
}
// 初始化
loadDataFromApi()
</script>
<template>
  <el-container>
    <el-header class="header" style="height: auto; margin:20px 0 -10px ; ">
      <el-form :inline="true" :model="formData" label-width="80px" class="form-container">
        <el-form-item label="日期" prop="recordDate">
          <el-date-picker
            v-model="formData.recordDate"
            type="date"
            value-format="YYYY-MM-DD"
            placeholder="选择日期"
            :default-value="new Date()"
            style="width: 200px"
          />
        </el-form-item>
        <el-form-item label="能耗值" prop="energyValue">
          <el-input-number
            v-model="formData.energyValue"
            :precision="2"
            :step="0.1"
            :min="0"
            controls-position="right"
            style="width: 200px"
          />
        </el-form-item>
        <el-form-item>
          <el-button type="primary" @click="handleSubmit">提交</el-button>
          <el-button @click="resetForm">重置</el-button>
        </el-form-item>
      </el-form>
    </el-header>
    <el-main class="main">
      <div class="table-container">
        <el-table
          :data="energyData"
          border
          style="width: 100%"
          height="500"
          v-loading="loading"
        >
          <el-table-column prop="recordDate" label="日期" width="180">
            <template #default="scope">
              <el-date-picker
                v-if="scope.row.editing"
                v-model="scope.row.recordDate"
                type="date"
                value-format="YYYY-MM-DD"
                placeholder="选择日期"
                style="width: 140px"
              />
              <span v-else>{{ formatDate(scope.row.recordDate) }}</span>
            </template>
          </el-table-column>
          <el-table-column prop="energyValue" label="能耗值" width="180">
            <template #default="scope">
              <el-input-number
                v-if="scope.row.editing"
                v-model="scope.row.energyValue"
                :precision="2"
                :step="0.1"
                :min="0"
                controls-position="right"
                style="width: 140px"
              />
              <span v-else>{{ scope.row.energyValue }}</span>
            </template>
          </el-table-column>
          <el-table-column label="操作" width="200" fixed="right">
            <template #default="scope">
              <el-button-group>
                <el-button
                  size="small"
                  :type="scope.row.editing ? 'success' : 'primary'"
                  @click="handleRowEdit(scope.$index, scope.row)"
                >
                  {{ scope.row.editing ? '保存' : '编辑' }}
                </el-button>
                <el-button
                  v-if="scope.row.editing"
                  size="small"
                  @click="cancelEdit(scope.$index, scope.row)"
                >
                  取消
                </el-button>
                <el-button
                  v-else
                  size="small"
                  type="danger"
                  @click="handleDelete(scope.$index)"
                >
                  删除
                </el-button>
              </el-button-group>
            </template>
          </el-table-column>
        </el-table>
      </div>
    </el-main>
  </el-container>
</template>
<style scoped>
</style>
UI-Project/src/views/KanbanDisplay/kanbanDisplay.vue
@@ -1,9 +1,111 @@
<!--  空白页  -->
<script setup>
import { ref, computed } from 'vue'
import * as echarts from 'echarts';
import { ref, onMounted } from 'vue'
import * as echarts from 'echarts'
import request from '@/utils/request'
const energyData = ref([])
// 获取能耗数据
const loadEnergyData = async () => {
  try {
    const res = await request({
      url: '/deviceInteraction/energy/consumption/chartEnergy',
      method: 'post'
    })
    if (res.code === 200) {
      energyData.value = res.data.actual || [];
      updateEnergyChart()
    }
  } catch (error) {
    console.error('获取能耗数据失败:', error)
  }
}
const draw = (name, Option) => {
  var myChart = echarts.init(document.getElementById(name));
  myChart.setOption(Option);
}
const drawDay = (name, Option) => {
  Option.title.text = "能耗管理";
  draw(name, Option);
}
// 更新能耗图表
const updateEnergyChart = () => {
  // 按日期排序并格式化日期
  const sortedData = [...energyData.value].sort((a, b) =>
    new Date(a.recordDate) - new Date(b.recordDate)
  ).map(item => {
    const date = new Date(item.recordDate);
    return {
      ...item,
      recordDate: `${date.getMonth() + 1}-${date.getDate().toString().padStart(2, '0')}`
    };
  });
  const energyoption = {
    title: {
      text: '能耗管理'
    },
    tooltip: {
      trigger: 'axis',
      axisPointer: {
        type: 'cross',
        label: {
              backgroundColor: '#6a7985'
        }
      }
    },
    legend: {
      data: ['能耗值']
    },
    toolbox: {
      feature: {
        saveAsImage: {}
      }
    },
    grid: {
      left: '3%',
      right: '4%',
      bottom: '3%',
      containLabel: true
    },
    xAxis: [
      {
        type: 'category',
        boundaryGap: false,
        data: sortedData.map(item => item.recordDate)
      }
    ],
    yAxis: [
      {
        type: 'value'
      }
    ],
    series: [
      {
        name: '能耗值',
        type: 'line',
        areaStyle: {},
        label: {
          show: true,
          position: 'top'
        },
        data: sortedData.map(item => item.energyValue)
      }
    ]
  }
  drawDay('drawLineChart_day71', energyoption);
}
onMounted(() => {
  loadEnergyData()
})
</script>
<script>
export default {
@@ -81,7 +183,7 @@
              100, 122, 101]
          }
        ]
      }
     this.drawDay('drawLineChart_day11',OptionDay, 1);
    // this.drawLineChart('drawLineChart_day11', 1);
@@ -93,17 +195,16 @@
    //this.drawBarchart('drawBarchart', 1);
  },
  methods: {
    //方法
    draw(name, Option,data) {
    draw(name, Option, data) {
      var myChart = echarts.init(document.getElementById(name));
      myChart.setOption(Option);
    },
    drawDay(name, Option,data) {
    drawDay(name, Option, data) {
      Option.title.text="日看板";
      console.log(Option);
      this.draw(name, Option,data);
      this.draw(name, Option, data);
    },
    drawLineChart(name, Option,data) {
    drawLineChart(name, Option, data) {
      console.log(name);
      console.log(data);
      var myChart = echarts.init(document.getElementById(name));
@@ -152,14 +253,14 @@
            }
          }
        ]
      });
    }
  }
}
</script>
<template>
  <div>
    <div style="font-size: 30px;height: 70px;line-height: 70px;border: 1px solid #ccc;text-align: center;">
@@ -184,7 +285,7 @@
        <div id="drawLineChart_day71" style="height: 33.3%;width: 100%;border: 1px solid #ccc;">能耗管理-按天显示(手输)</div>
      </div>
    </div>
    <!-- <div style="width:33% ;height: 880px;border: 1px solid #ccc;">
      <div id="drawLineChart_day1" style="height: 300px;width: 25%;border: 1px solid #ccc;float: left;"></div>
      <div id="drawLineChart_day2" style="height: 300px;width: 25%;border: 1px solid #ccc;float: left;"></div>