New file |
| | |
| | | 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); |
| | | } |
| | | } |
New file |
| | |
| | | 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; |
| | | } |
New file |
| | |
| | | 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> { |
| | | } |
New file |
| | |
| | | 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); |
| | | } |
New file |
| | |
| | | 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()); |
| | | } |
| | | } |
| | | } |
| | | } |
New file |
| | |
| | | <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> |
| | |
| | | <!-- 空白页 --> |
| | | |
| | | |
| | | |
| | | |
| | | <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 { |
| | |
| | | 100, 122, 101] |
| | | } |
| | | ] |
| | | |
| | | |
| | | } |
| | | this.drawDay('drawLineChart_day11',OptionDay, 1); |
| | | // this.drawLineChart('drawLineChart_day11', 1); |
| | |
| | | //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)); |
| | |
| | | } |
| | | } |
| | | ] |
| | | |
| | | |
| | | |
| | | |
| | | }); |
| | | } |
| | | } |
| | | } |
| | | </script> |
| | | |
| | | |
| | | <template> |
| | | <div> |
| | | <div style="font-size: 30px;height: 70px;line-height: 70px;border: 1px solid #ccc;text-align: center;"> |
| | |
| | | <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> |