l3能源成本分摊(部分完成留存)

This commit is contained in:
2025-12-07 17:23:47 +08:00
parent b6328a94da
commit 59951b77c3
100 changed files with 14350 additions and 847 deletions

View File

@@ -2,6 +2,7 @@ package com.klp.ems.controller;
import java.util.List;
import java.util.Arrays;
import java.util.Map;
import com.klp.ems.domain.bo.EmsEnergyConsumptionQueryBo;
import com.klp.ems.domain.vo.*;
@@ -80,6 +81,14 @@ public class EmsEnergyConsumptionController extends BaseController {
return R.ok(iEmsEnergyConsumptionService.getChainAnalysis(queryBo));
}
/**
* 获取能耗统计信息
*/
@GetMapping("/statistics")
public R<Map<String, Object>> getStatistics(EmsEnergyConsumptionBo bo) {
return R.ok(iEmsEnergyConsumptionService.getStatistics(bo));
}
/**
* 查询能耗记录列表
*/
@@ -109,6 +118,31 @@ public class EmsEnergyConsumptionController extends BaseController {
return R.ok(iEmsEnergyConsumptionService.queryById(energyConsumptionId));
}
/**
* 获取设备的上次抄表记录(用于自动填充起始数据)
* 如果是首次抄表返回null否则返回上次抄表的结束读数作为本次的起始读数
*
* @param meterId 设备ID
*/
@GetMapping("/lastReading/{meterId}")
public R<EmsEnergyConsumptionVo> getLastReading(@NotNull(message = "设备ID不能为空")
@PathVariable Long meterId) {
EmsEnergyConsumptionVo lastReading = iEmsEnergyConsumptionService.getLastReadingForMeter(meterId);
return R.ok(lastReading);
}
/**
* 获取设备本月的累计消耗量
*
* @param meterId 设备ID
*/
@GetMapping("/monthlyConsumption/{meterId}")
public R<Double> getMonthlyConsumption(@NotNull(message = "设备ID不能为空")
@PathVariable Long meterId) {
Double monthlyConsumption = iEmsEnergyConsumptionService.getMonthlyConsumption(meterId);
return R.ok(monthlyConsumption);
}
/**
* 新增能耗记录
*/

View File

@@ -18,12 +18,18 @@ import com.klp.common.core.validate.EditGroup;
import com.klp.common.enums.BusinessType;
import com.klp.common.utils.poi.ExcelUtil;
import com.klp.ems.domain.vo.EmsEnergyRateVo;
import com.klp.ems.domain.vo.EmsRateTierVo;
import com.klp.ems.domain.vo.EmsRateTimePeriodLinkVo;
import com.klp.ems.domain.bo.EmsEnergyRateBo;
import com.klp.ems.domain.bo.EmsRateTierBo;
import com.klp.ems.domain.bo.EmsRateTimePeriodLinkBo;
import com.klp.ems.domain.bo.EmsRateTierPeriodLinkBo;
import com.klp.ems.service.IEmsEnergyRateService;
import com.klp.common.core.page.TableDataInfo;
/**
* 能源费率currency 为 INT0=CNY,1=USD,2=EUR
* 能源费率
* 支持:固定费率、峰谷分时、阶梯电价、峰谷+阶梯组合
*
* @author Joshi
* @date 2025-09-28
@@ -86,14 +92,73 @@ public class EmsEnergyRateController extends BaseController {
}
/**
* 删除能源费率(currency 为 INT0=CNY,1=USD,2=EUR
* 删除能源费率(级联删除梯度和时段费率
*
* @param energyRateIds 主键串
*/
@Log(title = "能源费率currency 为 INT0=CNY,1=USD,2=EUR", businessType = BusinessType.DELETE)
@Log(title = "能源费率", businessType = BusinessType.DELETE)
@DeleteMapping("/{energyRateIds}")
public R<Void> remove(@NotEmpty(message = "主键不能为空")
@PathVariable Long[] energyRateIds) {
return toAjax(iEmsEnergyRateService.deleteWithValidByIds(Arrays.asList(energyRateIds), true));
}
/**
* 获取费率的梯度费率列表
*/
@GetMapping("/{energyRateId}/tiers")
public R<List<EmsRateTierVo>> getRateTiers(@NotNull(message = "费率ID不能为空")
@PathVariable Long energyRateId) {
return R.ok(iEmsEnergyRateService.getRateTiers(energyRateId));
}
/**
* 获取费率的时段费率列表
*/
@GetMapping("/{energyRateId}/timePeriods")
public R<List<EmsRateTimePeriodLinkVo>> getRateTimePeriods(@NotNull(message = "费率ID不能为空")
@PathVariable Long energyRateId) {
return R.ok(iEmsEnergyRateService.getRateTimePeriods(energyRateId));
}
/**
* 保存梯度费率返回保存后的梯度列表包含tierId
*/
@Log(title = "能源费率梯度", businessType = BusinessType.UPDATE)
@PostMapping("/{energyRateId}/tiers")
public R<List<EmsRateTierVo>> saveTiers(@NotNull(message = "费率ID不能为空") @PathVariable Long energyRateId,
@RequestBody List<EmsRateTierBo> tiers) {
return R.ok(iEmsEnergyRateService.saveTiers(energyRateId, tiers));
}
/**
* 保存时段费率
*/
@Log(title = "能源费率时段", businessType = BusinessType.UPDATE)
@PostMapping("/{energyRateId}/timePeriods")
public R<Void> saveTimePeriods(@NotNull(message = "费率ID不能为空") @PathVariable Long energyRateId,
@RequestBody List<EmsRateTimePeriodLinkBo> timePeriods) {
return toAjax(iEmsEnergyRateService.saveTimePeriods(energyRateId, timePeriods));
}
/**
* 获取梯度的峰谷时段费率(用于梯度+峰谷组合模式)
*/
@GetMapping("/{energyRateId}/tier/{tierId}/periods")
public R<List<EmsRateTierPeriodLinkBo>> getTierPeriodLinks(@NotNull(message = "费率ID不能为空") @PathVariable Long energyRateId,
@NotNull(message = "梯度ID不能为空") @PathVariable Long tierId) {
// 返回该梯度对应的所有时段费率
return R.ok(iEmsEnergyRateService.getTierPeriodLinks(tierId));
}
/**
* 保存梯度-时段关联费率(用于梯度+峰谷组合模式)
*/
@Log(title = "梯度-时段关联费率", businessType = BusinessType.UPDATE)
@PostMapping("/{energyRateId}/tier/{tierId}/periods")
public R<Void> saveTierPeriodLinks(@NotNull(message = "费率ID不能为空") @PathVariable Long energyRateId,
@NotNull(message = "梯度ID不能为空") @PathVariable Long tierId,
@RequestBody List<EmsRateTierPeriodLinkBo> tierPeriodLinks) {
return toAjax(iEmsEnergyRateService.saveTierPeriodLinks(tierId, tierPeriodLinks));
}
}

View File

@@ -2,11 +2,13 @@ package com.klp.ems.controller;
import java.util.List;
import java.util.Arrays;
import java.io.IOException;
import lombok.RequiredArgsConstructor;
import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.*;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.validation.annotation.Validated;
import com.klp.common.annotation.RepeatSubmit;
import com.klp.common.annotation.Log;
@@ -96,4 +98,21 @@ public class EmsMeterController extends BaseController {
@PathVariable Long[] meterIds) {
return toAjax(iEmsMeterService.deleteWithValidByIds(Arrays.asList(meterIds), true));
}
/**
* 下载设备导入模板
*/
@GetMapping("/template")
public void downloadTemplate(HttpServletResponse response) {
iEmsMeterService.downloadTemplate(response);
}
/**
* 导入设备
*/
@Log(title = "计量设备(阈值移至此处)", businessType = BusinessType.IMPORT)
@PostMapping("/import")
public R<Void> importMeters(@RequestParam("file") MultipartFile file) {
return toAjax(iEmsMeterService.importMeters(file));
}
}

View File

@@ -0,0 +1,105 @@
package com.klp.ems.controller;
import java.util.List;
import java.util.Arrays;
import lombok.RequiredArgsConstructor;
import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.*;
import org.springframework.web.bind.annotation.*;
import org.springframework.validation.annotation.Validated;
import com.klp.common.annotation.RepeatSubmit;
import com.klp.common.annotation.Log;
import com.klp.common.core.controller.BaseController;
import com.klp.common.core.domain.PageQuery;
import com.klp.common.core.domain.R;
import com.klp.common.core.validate.AddGroup;
import com.klp.common.core.validate.EditGroup;
import com.klp.common.enums.BusinessType;
import com.klp.common.utils.poi.ExcelUtil;
import com.klp.ems.domain.bo.EmsRateTierBo;
import com.klp.ems.domain.vo.EmsRateTierVo;
import com.klp.ems.service.IEmsRateTierService;
import com.klp.common.core.page.TableDataInfo;
/**
* 梯度费率
*
* @author Joshi
* @date 2025-12-05
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/ems/rateTier")
public class EmsRateTierController extends BaseController {
private final IEmsRateTierService iEmsRateTierService;
/**
* 查询梯度费率列表
*/
@GetMapping("/list")
public TableDataInfo<EmsRateTierVo> list(EmsRateTierBo bo, PageQuery pageQuery) {
return iEmsRateTierService.queryPageList(bo, pageQuery);
}
/**
* 根据费率ID查询梯度费率列表
*/
@GetMapping("/listByRate/{energyRateId}")
public R<List<EmsRateTierVo>> listByRate(@NotNull(message = "费率ID不能为空")
@PathVariable Long energyRateId) {
return R.ok(iEmsRateTierService.queryByRateId(energyRateId));
}
/**
* 导出梯度费率列表
*/
@Log(title = "梯度费率", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(EmsRateTierBo bo, HttpServletResponse response) {
List<EmsRateTierVo> list = iEmsRateTierService.queryList(bo);
ExcelUtil.exportExcel(list, "梯度费率", EmsRateTierVo.class, response);
}
/**
* 获取梯度费率详细信息
*/
@GetMapping("/{tierId}")
public R<EmsRateTierVo> getInfo(@NotNull(message = "主键不能为空")
@PathVariable Long tierId) {
return R.ok(iEmsRateTierService.queryById(tierId));
}
/**
* 新增梯度费率
*/
@Log(title = "梯度费率", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping()
public R<Void> add(@Validated(AddGroup.class) @RequestBody EmsRateTierBo bo) {
return toAjax(iEmsRateTierService.insertByBo(bo));
}
/**
* 修改梯度费率
*/
@Log(title = "梯度费率", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping()
public R<Void> edit(@Validated(EditGroup.class) @RequestBody EmsRateTierBo bo) {
return toAjax(iEmsRateTierService.updateByBo(bo));
}
/**
* 删除梯度费率
*/
@Log(title = "梯度费率", businessType = BusinessType.DELETE)
@DeleteMapping("/{tierIds}")
public R<Void> remove(@NotEmpty(message = "主键不能为空")
@PathVariable Long[] tierIds) {
return toAjax(iEmsRateTierService.deleteWithValidByIds(Arrays.asList(tierIds), true));
}
}

View File

@@ -0,0 +1,86 @@
package com.klp.ems.controller;
import com.klp.common.core.controller.BaseController;
import com.klp.common.core.domain.R;
import com.klp.ems.domain.bo.EmsRateTierPeriodLinkBo;
import com.klp.ems.domain.vo.EmsRateTierPeriodLinkVo;
import com.klp.ems.service.IEmsRateTierPeriodLinkService;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.validation.constraints.NotNull;
import java.util.List;
import java.util.stream.Collectors;
/**
* 梯度与时段关联 Controller
*
* @author Joshi
* @date 2025-12-05
*/
@RestController
@RequestMapping("/ems/rateTierPeriodLink")
@RequiredArgsConstructor
@Validated
public class EmsRateTierPeriodLinkController extends BaseController {
private final IEmsRateTierPeriodLinkService iEmsRateTierPeriodLinkService;
/**
* 根据梯度ID查询所有关联的时段费率
*
* @param tierId 梯度ID
* @return 梯度-时段关联列表
*/
@GetMapping("/tier/{tierId}")
public R<List<EmsRateTierPeriodLinkVo>> getByTierId(@NotNull @PathVariable Long tierId) {
// 这里返回的是该梯度对应的所有时段费率
// 前端需要调用此接口获取梯度的峰谷费率配置
return R.ok(iEmsRateTierPeriodLinkService.getByTierId(tierId).stream()
.map(link -> {
EmsRateTierPeriodLinkVo vo = new EmsRateTierPeriodLinkVo();
vo.setLinkId(link.getLinkId());
vo.setTierId(link.getTierId());
vo.setPeriodId(link.getPeriodId());
vo.setRate(link.getRate());
return vo;
})
.collect(Collectors.toList()));
}
/**
* 根据费率ID查询梯度-时段关联的完整信息
*
* @param energyRateId 费率ID
* @return 梯度-时段关联VO列表
*/
@GetMapping("/rate/{energyRateId}")
public R<List<EmsRateTierPeriodLinkVo>> getByEnergyRateId(@NotNull @PathVariable Long energyRateId) {
return R.ok(iEmsRateTierPeriodLinkService.getVoByEnergyRateId(energyRateId));
}
/**
* 保存梯度的时段费率关联
*
* @param tierId 梯度ID
* @param tierPeriodLinks 梯度-时段关联列表
* @return 保存结果
*/
@PostMapping("/tier/{tierId}")
public R<Void> saveTierPeriodLinks(@NotNull @PathVariable Long tierId,
@RequestBody List<EmsRateTierPeriodLinkBo> tierPeriodLinks) {
return toAjax(iEmsRateTierPeriodLinkService.saveTierPeriodLinks(tierId, tierPeriodLinks));
}
/**
* 删除梯度的时段费率关联
*
* @param tierId 梯度ID
* @return 删除结果
*/
@DeleteMapping("/tier/{tierId}")
public R<Void> deleteByTierId(@NotNull @PathVariable Long tierId) {
return toAjax(iEmsRateTierPeriodLinkService.deleteByTierId(tierId));
}
}

View File

@@ -0,0 +1,105 @@
package com.klp.ems.controller;
import java.util.List;
import java.util.Arrays;
import lombok.RequiredArgsConstructor;
import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.*;
import org.springframework.web.bind.annotation.*;
import org.springframework.validation.annotation.Validated;
import com.klp.common.annotation.RepeatSubmit;
import com.klp.common.annotation.Log;
import com.klp.common.core.controller.BaseController;
import com.klp.common.core.domain.PageQuery;
import com.klp.common.core.domain.R;
import com.klp.common.core.validate.AddGroup;
import com.klp.common.core.validate.EditGroup;
import com.klp.common.enums.BusinessType;
import com.klp.common.utils.poi.ExcelUtil;
import com.klp.ems.domain.bo.EmsRateTimePeriodLinkBo;
import com.klp.ems.domain.vo.EmsRateTimePeriodLinkVo;
import com.klp.ems.service.IEmsRateTimePeriodLinkService;
import com.klp.common.core.page.TableDataInfo;
/**
* 费率与时间段关联
*
* @author Joshi
* @date 2025-12-05
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/ems/rateTimePeriodLink")
public class EmsRateTimePeriodLinkController extends BaseController {
private final IEmsRateTimePeriodLinkService iEmsRateTimePeriodLinkService;
/**
* 查询费率与时间段关联列表
*/
@GetMapping("/list")
public TableDataInfo<EmsRateTimePeriodLinkVo> list(EmsRateTimePeriodLinkBo bo, PageQuery pageQuery) {
return iEmsRateTimePeriodLinkService.queryPageList(bo, pageQuery);
}
/**
* 根据费率ID查询峰谷时段费率列表
*/
@GetMapping("/listByRate/{energyRateId}")
public R<List<EmsRateTimePeriodLinkVo>> listByRate(@NotNull(message = "费率ID不能为空")
@PathVariable Long energyRateId) {
return R.ok(iEmsRateTimePeriodLinkService.queryByRateId(energyRateId));
}
/**
* 导出费率与时间段关联列表
*/
@Log(title = "费率与时间段关联", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(EmsRateTimePeriodLinkBo bo, HttpServletResponse response) {
List<EmsRateTimePeriodLinkVo> list = iEmsRateTimePeriodLinkService.queryList(bo);
ExcelUtil.exportExcel(list, "费率与时间段关联", EmsRateTimePeriodLinkVo.class, response);
}
/**
* 获取费率与时间段关联详细信息
*/
@GetMapping("/{linkId}")
public R<EmsRateTimePeriodLinkVo> getInfo(@NotNull(message = "主键不能为空")
@PathVariable Long linkId) {
return R.ok(iEmsRateTimePeriodLinkService.queryById(linkId));
}
/**
* 新增费率与时间段关联
*/
@Log(title = "费率与时间段关联", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping()
public R<Void> add(@Validated(AddGroup.class) @RequestBody EmsRateTimePeriodLinkBo bo) {
return toAjax(iEmsRateTimePeriodLinkService.insertByBo(bo));
}
/**
* 修改费率与时间段关联
*/
@Log(title = "费率与时间段关联", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping()
public R<Void> edit(@Validated(EditGroup.class) @RequestBody EmsRateTimePeriodLinkBo bo) {
return toAjax(iEmsRateTimePeriodLinkService.updateByBo(bo));
}
/**
* 删除费率与时间段关联
*/
@Log(title = "费率与时间段关联", businessType = BusinessType.DELETE)
@DeleteMapping("/{linkIds}")
public R<Void> remove(@NotEmpty(message = "主键不能为空")
@PathVariable Long[] linkIds) {
return toAjax(iEmsRateTimePeriodLinkService.deleteWithValidByIds(Arrays.asList(linkIds), true));
}
}

View File

@@ -0,0 +1,50 @@
package com.klp.ems.controller;
import com.klp.common.annotation.Log;
import com.klp.common.core.controller.BaseController;
import com.klp.common.core.domain.PageQuery;
import com.klp.common.core.domain.R;
import com.klp.common.core.page.TableDataInfo;
import com.klp.common.enums.BusinessType;
import com.klp.ems.domain.bo.EnergyCostReportBo;
import com.klp.ems.domain.vo.EnergyCostSummaryVo;
import com.klp.ems.domain.vo.WmsEnergyCoilDailyVo;
import com.klp.ems.service.IEnergyCostReportService;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
import java.util.Map;
/**
* 能源成本报表 Controller
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/ems/energy/report")
public class EnergyCostReportController extends BaseController {
private final IEnergyCostReportService reportService;
@Log(title = "能源成本报表", businessType = BusinessType.OTHER)
@GetMapping("/overview")
public R<Map<String, Object>> overview(EnergyCostReportBo bo) {
return R.ok(reportService.overview(bo));
}
@Log(title = "能源成本报表", businessType = BusinessType.OTHER)
@GetMapping("/summary")
public R<List<EnergyCostSummaryVo>> summary(EnergyCostReportBo bo) {
return R.ok(reportService.summary(bo));
}
@Log(title = "能源成本报表", businessType = BusinessType.OTHER)
@GetMapping("/detail")
public TableDataInfo<WmsEnergyCoilDailyVo> detail(EnergyCostReportBo bo, PageQuery pageQuery) {
return reportService.detail(bo, pageQuery);
}
}

View File

@@ -0,0 +1,99 @@
package com.klp.ems.controller;
import com.klp.common.annotation.Log;
import com.klp.common.annotation.RepeatSubmit;
import com.klp.common.core.controller.BaseController;
import com.klp.common.core.domain.PageQuery;
import com.klp.common.core.domain.R;
import com.klp.common.core.page.TableDataInfo;
import com.klp.common.core.validate.AddGroup;
import com.klp.common.core.validate.EditGroup;
import com.klp.common.enums.BusinessType;
import com.klp.common.utils.poi.ExcelUtil;
import com.klp.ems.domain.bo.WmsEnergyCoilDailyBo;
import com.klp.ems.domain.vo.WmsEnergyCoilDailyVo;
import com.klp.ems.domain.vo.WmsEnergyCoilDailyStatisticsVo;
import com.klp.ems.service.IWmsEnergyCoilDailyService;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.List;
/**
* 钢卷日能源成本分摊结果 Controller
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/ems/energy/coilDaily")
public class WmsEnergyCoilDailyController extends BaseController {
private final IWmsEnergyCoilDailyService coilDailyService;
@GetMapping("/list")
public TableDataInfo<WmsEnergyCoilDailyVo> list(WmsEnergyCoilDailyBo bo, PageQuery pageQuery) {
return coilDailyService.queryPageList(bo, pageQuery);
}
/**
* 查询待操作钢卷的能源成本(基于待操作时间范围计算)
*/
@GetMapping("/pendingAction")
public TableDataInfo<WmsEnergyCoilDailyVo> pendingAction(WmsEnergyCoilDailyBo bo, PageQuery pageQuery) {
// 调用Service方法计算待操作钢卷的成本
return coilDailyService.queryPendingActionCoilCost(bo, pageQuery);
}
/**
* 查询待操作钢卷的能源成本统计
*/
@GetMapping("/pendingAction/statistics")
public R<WmsEnergyCoilDailyStatisticsVo> pendingActionStatistics(
@RequestParam(required = false) String enterCoilNo,
@RequestParam(required = false) String currentCoilNo,
@RequestParam(required = false) Long warehouseId
) {
WmsEnergyCoilDailyStatisticsVo statistics = coilDailyService.queryPendingActionCoilCostStatistics(enterCoilNo, currentCoilNo, warehouseId);
return R.ok(statistics);
}
@Log(title = "钢卷能源分摊", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(WmsEnergyCoilDailyBo bo, HttpServletResponse response) {
List<WmsEnergyCoilDailyVo> list = coilDailyService.queryList(bo);
ExcelUtil.exportExcel(list, "钢卷能源分摊", WmsEnergyCoilDailyVo.class, response);
}
@GetMapping("/{energyCostId}")
public R<WmsEnergyCoilDailyVo> getInfo(@NotNull @PathVariable Long energyCostId) {
return R.ok(coilDailyService.queryById(energyCostId));
}
@Log(title = "钢卷能源分摊", businessType = BusinessType.INSERT)
@RepeatSubmit
@PostMapping
public R<Void> add(@Validated(AddGroup.class) @RequestBody WmsEnergyCoilDailyBo bo) {
return toAjax(coilDailyService.insertByBo(bo));
}
@Log(title = "钢卷能源分摊", businessType = BusinessType.UPDATE)
@RepeatSubmit
@PutMapping
public R<Void> edit(@Validated(EditGroup.class) @RequestBody WmsEnergyCoilDailyBo bo) {
return toAjax(coilDailyService.updateByBo(bo));
}
@Log(title = "钢卷能源分摊", businessType = BusinessType.DELETE)
@DeleteMapping("/{energyCostIds}")
public R<Void> remove(@NotEmpty @PathVariable Long[] energyCostIds) {
return toAjax(coilDailyService.deleteWithValidByIds(Arrays.asList(energyCostIds), true));
}
}

View File

@@ -0,0 +1,22 @@
package com.klp.ems.domain;
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDate;
/**
* 成本日表仅更新能源成本字段所需的参数。
*/
@Data
public class CostCoilDailyEnergy {
private Long coilId;
private LocalDate calcDate;
private BigDecimal energyCostAmount;
/** JSON 字符串(数组) */
private String energyCostBreakdown;
}

View File

@@ -47,11 +47,23 @@ public class EmsEnergyRate extends BaseEntity {
* 失效日期NULL表示长期有效
*/
private Date expiryDate;
/**
* 是否使用峰谷时段0=否1=是
*/
private Integer usePeakValley;
/**
* 是否使用梯度收费0=否1=是
*/
private Integer useTieredPricing;
/**
* 删除标志0=存在 2=删除)
*/
@TableLogic
private String delFlag;
/**
* 备注
*/

View File

@@ -0,0 +1,65 @@
package com.klp.ems.domain;
import com.baomidou.mybatisplus.annotation.*;
import com.klp.common.core.domain.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.math.BigDecimal;
/**
* 梯度费率对象 ems_rate_tier
* 用于支持用量梯度收费0-100度1元/度100-200度1.5元/度
*
* @author Joshi
* @date 2025-12-05
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("ems_rate_tier")
public class EmsRateTier extends BaseEntity {
private static final long serialVersionUID = 1L;
/**
* 梯度费率ID
*/
@TableId(value = "tier_id")
private Long tierId;
/**
* 关联费率ID
*/
private Long energyRateId;
/**
* 梯度等级1、2、3...
*/
private Integer tierLevel;
/**
* 最小用量(包含)
*/
private BigDecimal minUsage;
/**
* 最大用量不包含NULL表示无上限
*/
private BigDecimal maxUsage;
/**
* 该梯度的费率
*/
private BigDecimal rate;
/**
* 删除标志0=存在 2=删除)
*/
@TableLogic
private String delFlag;
/**
* 备注
*/
private String remark;
}

View File

@@ -0,0 +1,58 @@
package com.klp.ems.domain;
import com.baomidou.mybatisplus.annotation.*;
import com.klp.common.core.domain.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.math.BigDecimal;
/**
* 梯度与时段关联对象 ems_tier_period_link
* 用于支持梯度+峰谷组合计费,如:
* 第1梯度(0-100度) 的峰时段 1.5元/度
* 第1梯度(0-100度) 的谷时段 0.5元/度
* 第2梯度(100-200度) 的峰时段 1.8元/度
*
* @author Joshi
* @date 2025-12-05
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("ems_tier_period_link")
public class EmsRateTierPeriodLink extends BaseEntity {
private static final long serialVersionUID = 1L;
/**
* 关联ID
*/
@TableId(value = "link_id")
private Long linkId;
/**
* 梯度ID
*/
private Long tierId;
/**
* 时间段ID
*/
private Long periodId;
/**
* 该梯度+时段的费率
*/
private BigDecimal rate;
/**
* 删除标志0=存在 2=删除)
*/
@TableLogic
private String delFlag;
/**
* 备注
*/
private String remark;
}

View File

@@ -0,0 +1,55 @@
package com.klp.ems.domain;
import com.baomidou.mybatisplus.annotation.*;
import com.klp.common.core.domain.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.math.BigDecimal;
/**
* 费率与时间段关联对象 ems_rate_time_period_link
* 用于支持峰谷时段的不同费率峰时段费率1.5元/度谷时段费率0.8元/度
*
* @author Joshi
* @date 2025-12-05
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("ems_rate_time_period_link")
public class EmsRateTimePeriodLink extends BaseEntity {
private static final long serialVersionUID = 1L;
/**
* 关联ID
*/
@TableId(value = "link_id")
private Long linkId;
/**
* 费率ID
*/
private Long energyRateId;
/**
* 时间段ID
*/
private Long periodId;
/**
* 该时间段的费率
*/
private BigDecimal rate;
/**
* 删除标志0=存在 2=删除)
*/
@TableLogic
private String delFlag;
/**
* 备注
*/
private String remark;
}

View File

@@ -0,0 +1,62 @@
package com.klp.ems.domain;
import com.baomidou.mybatisplus.annotation.*;
import com.klp.common.core.domain.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 时间段(峰谷平)对象 ems_time_period
*
* @author Joshi
* @date 2025-12-05
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("ems_time_period")
public class EmsTimePeriod extends BaseEntity {
private static final long serialVersionUID = 1L;
/**
* 时间段ID
*/
@TableId(value = "period_id")
private Long periodId;
/**
* 时间段名称(峰、谷、平)
*/
private String periodName;
/**
* 时间段类型0=峰1=谷2=平
*/
private Integer periodType;
/**
* 开始时间HH:mm格式
*/
private String startTime;
/**
* 结束时间HH:mm格式
*/
private String endTime;
/**
* 是否跨天0=否1=是
*/
private Integer crossDay;
/**
* 删除标志0=存在 2=删除)
*/
@TableLogic
private String delFlag;
/**
* 备注
*/
private String remark;
}

View File

@@ -0,0 +1,51 @@
package com.klp.ems.domain;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDate;
/**
* 钢卷日能源成本分摊结果
*/
@Data
@TableName("wms_energy_coil_daily")
public class WmsEnergyCoilDaily {
private static final long serialVersionUID = 1L;
@TableId(value = "energy_cost_id")
private Long energyCostId;
private Long taskId;
private LocalDate calcDate;
private Long coilId;
private String enterCoilNo;
private String currentCoilNo;
private Long warehouseId;
private Long actualWarehouseId;
private Long energyTypeId;
private Long meterId;
private BigDecimal consumptionQty;
private BigDecimal costAmount;
private BigDecimal allocationBasisWeight;
private BigDecimal allocationBasisDays;
private BigDecimal allocationFactor;
private String remark;
}

View File

@@ -30,6 +30,11 @@ public class EmsEnergyConsumptionBo extends BaseEntity {
*/
private Long meterId;
/**
* 能源类型ID用于查询统计
*/
private Long energyTypeId;
/**
* 起始读数
*/

View File

@@ -50,6 +50,16 @@ public class EmsEnergyRateBo extends BaseEntity {
*/
private Date expiryDate;
/**
* 是否使用峰谷时段0=否1=是
*/
private Integer usePeakValley;
/**
* 是否使用梯度收费0=否1=是
*/
private Integer useTieredPricing;
/**
* 备注
*/

View File

@@ -0,0 +1,53 @@
package com.klp.ems.domain.bo;
import com.klp.common.core.domain.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.math.BigDecimal;
/**
* 梯度费率业务对象 ems_rate_tier
*
* @author Joshi
* @date 2025-12-05
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class EmsRateTierBo extends BaseEntity {
/**
* 梯度费率ID
*/
private Long tierId;
/**
* 关联费率ID
*/
private Long energyRateId;
/**
* 梯度等级1、2、3...
*/
private Integer tierLevel;
/**
* 最小用量(包含)
*/
private BigDecimal minUsage;
/**
* 最大用量不包含NULL表示无上限
*/
private BigDecimal maxUsage;
/**
* 该梯度的费率
*/
private BigDecimal rate;
/**
* 备注
*/
private String remark;
}

View File

@@ -0,0 +1,40 @@
package com.klp.ems.domain.bo;
import lombok.Data;
import java.math.BigDecimal;
/**
* 梯度与时段关联业务对象
*
* @author Joshi
* @date 2025-12-05
*/
@Data
public class EmsRateTierPeriodLinkBo {
/**
* 关联ID
*/
private Long linkId;
/**
* 梯度ID
*/
private Long tierId;
/**
* 时间段ID
*/
private Long periodId;
/**
* 该梯度+时段的费率
*/
private BigDecimal rate;
/**
* 备注
*/
private String remark;
}

View File

@@ -0,0 +1,68 @@
package com.klp.ems.domain.bo;
import com.klp.common.core.domain.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.math.BigDecimal;
/**
* 费率与时间段关联业务对象 ems_rate_time_period_link
*
* @author Joshi
* @date 2025-12-05
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class EmsRateTimePeriodLinkBo extends BaseEntity {
/**
* 关联ID
*/
private Long linkId;
/**
* 费率ID
*/
private Long energyRateId;
/**
* 时间段ID
*/
private Long periodId;
/**
* 时间段类型0=峰1=谷2=平
*/
private Integer periodType;
/**
* 时间段名称(峰、谷、平)
*/
private String periodName;
/**
* 开始时间HH:mm格式
*/
private String startTime;
/**
* 结束时间HH:mm格式
*/
private String endTime;
/**
* 是否跨天0=否1=是
*/
private Integer crossDay;
/**
* 该时间段的费率
*/
private BigDecimal rate;
/**
* 备注
*/
private String remark;
}

View File

@@ -0,0 +1,51 @@
package com.klp.ems.domain.bo;
import com.klp.common.core.domain.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 时间段业务对象 ems_time_period
*
* @author Joshi
* @date 2025-12-05
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class EmsTimePeriodBo extends BaseEntity {
/**
* 时间段ID
*/
private Long periodId;
/**
* 时间段名称(峰、谷、平)
*/
private String periodName;
/**
* 时间段类型0=峰1=谷2=平
*/
private Integer periodType;
/**
* 开始时间HH:mm格式
*/
private String startTime;
/**
* 结束时间HH:mm格式
*/
private String endTime;
/**
* 是否跨天0=否1=是
*/
private Integer crossDay;
/**
* 备注
*/
private String remark;
}

View File

@@ -0,0 +1,54 @@
package com.klp.ems.domain.bo;
import com.klp.common.core.domain.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.time.LocalDate;
/**
* 能源成本报表查询参数
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class EnergyCostReportBo extends BaseEntity {
/** 开始日期 */
private LocalDate startDate;
/** 结束日期 */
private LocalDate endDate;
/** 分摊任务 */
private Long taskId;
/** 能源类型 */
private Long energyTypeId;
/** 计量仪表 */
private Long meterId;
/** 逻辑库区 */
private Long warehouseId;
/** 实际库区 */
private Long actualWarehouseId;
/** 入场钢卷号 */
private String enterCoilNo;
/** 当前钢卷号 */
private String currentCoilNo;
/** 汇总维度energyType/warehouse/meter/task */
private String groupBy;
/** 是否返回明细 */
private Boolean includeDetail;
/** 页码 */
private Integer pageNum;
/** 每页大小 */
private Integer pageSize;
}

View File

@@ -0,0 +1,51 @@
package com.klp.ems.domain.bo;
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDate;
/**
* 钢卷日能源成本分摊结果 BO
*/
@Data
public class WmsEnergyCoilDailyBo {
private Long energyCostId;
private Long taskId;
private LocalDate calcDate;
private Long coilId;
private String enterCoilNo;
private String currentCoilNo;
private Long warehouseId;
private Long actualWarehouseId;
private Long energyTypeId;
private Long meterId;
private BigDecimal consumptionQty;
private BigDecimal costAmount;
private BigDecimal allocationBasisWeight;
private BigDecimal allocationBasisDays;
private BigDecimal allocationFactor;
private String remark;
/** 起始日期(查询用) */
private LocalDate startDate;
/** 结束日期(查询用) */
private LocalDate endDate;
}

View File

@@ -0,0 +1,37 @@
package com.klp.ems.domain.dto;
import lombok.Data;
import java.math.BigDecimal;
/**
* 轻量化钢卷信息(仅供能源分摊引擎使用)
*/
@Data
public class AllocationCoilDto {
private Long coilId;
private String enterCoilNo;
private String currentCoilNo;
private Long warehouseId;
private Long actualWarehouseId;
/** 净重kg */
private BigDecimal netWeight;
/** 毛重kg */
private BigDecimal grossWeight;
/** 待操作累计分钟数(基于 pending action 计算) */
private BigDecimal pendingMinutes;
/** 物品类型 */
private String itemType;
/** 材料类型 */
private String materialType;
}

View File

@@ -0,0 +1,48 @@
package com.klp.ems.domain.dto;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;
import java.util.Date;
/**
* 设备导入模板 DTO
*
* @author Joshi
* @date 2025-12-05
*/
@Data
@ExcelIgnoreUnannotated
public class MeterTemplateDto {
/**
* 设备编号
*/
@ExcelProperty(value = "设备编号")
private String meterCode;
/**
* 能源类型(水、电、天然气)
*/
@ExcelProperty(value = "能源类型")
private String energyType;
/**
* 设备型号
*/
@ExcelProperty(value = "设备型号")
private String model;
/**
* 制造商
*/
@ExcelProperty(value = "制造商")
private String manufacturer;
/**
* 安装日期
*/
@ExcelProperty(value = "安装日期")
private Date installDate;
}

View File

@@ -71,6 +71,21 @@ public class EmsEnergyConsumptionVo {
@ExcelDictFormat(readConverterExp = "不=设外键")
private Long recordedBy;
/**
* 记录人名称
*/
private String recordedByName;
/**
* 设备编号
*/
private String meterCode;
/**
* 能源类型名称
*/
private String energyTypeName;
/**
* 备注
*/

View File

@@ -2,6 +2,7 @@ package com.klp.ems.domain.vo;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
@@ -58,11 +59,27 @@ public class EmsEnergyRateVo {
@ExcelProperty(value = "失效日期NULL表示长期有效")
private Date expiryDate;
/**
* 是否使用峰谷时段0=否1=是
*/
@ExcelProperty(value = "是否使用峰谷时段")
private Integer usePeakValley;
/**
* 是否使用梯度收费0=否1=是
*/
@ExcelProperty(value = "是否使用梯度收费")
private Integer useTieredPricing;
/**
* 备注
*/
@ExcelProperty(value = "备注")
private String remark;
/**
* 梯度费率列表(非数据库字段,用于前端展示)
*/
private List<EmsRateTierVo> tiers;
}

View File

@@ -5,6 +5,7 @@ import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.ExcelIgnore;
import com.klp.common.annotation.ExcelDictFormat;
import com.klp.common.convert.ExcelDictConvert;
import lombok.Data;
@@ -43,7 +44,7 @@ public class EmsMeterVo {
/**
* 安装位置
*/
@ExcelProperty(value = "安装位置")
@ExcelIgnore
private Long locationId;
/**
@@ -73,14 +74,13 @@ public class EmsMeterVo {
/**
* 上次校准日期
*/
@ExcelProperty(value = "上次校准日期")
@ExcelIgnore
private Date lastCalibrationDate;
/**
* 阈值(按设备设置)
*/
@ExcelProperty(value = "阈值", converter = ExcelDictConvert.class)
@ExcelDictFormat(readConverterExp = "按=设备设置")
@ExcelIgnore
private BigDecimal thresholdValue;
/**
@@ -89,5 +89,16 @@ public class EmsMeterVo {
@ExcelProperty(value = "备注")
private String remark;
/**
* 库区ID
*/
@ExcelIgnore
private Long warehouseId;
/**
* 库区名称
*/
@ExcelIgnore
private String warehouseName;
}

View File

@@ -0,0 +1,96 @@
package com.klp.ems.domain.vo;
import com.alibaba.excel.annotation.ExcelIgnore;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;
/**
* 梯度与时段关联视图对象
*
* @author Joshi
* @date 2025-12-05
*/
@Data
public class EmsRateTierPeriodLinkVo {
/**
* 关联ID
*/
@ExcelProperty(value = "关联ID", index = 0)
private Long linkId;
/**
* 梯度ID
*/
@ExcelIgnore
private Long tierId;
/**
* 梯度等级
*/
@ExcelProperty(value = "梯度等级", index = 1)
private Integer tierLevel;
/**
* 最小用量
*/
@ExcelProperty(value = "最小用量", index = 2)
private BigDecimal minUsage;
/**
* 最大用量
*/
@ExcelProperty(value = "最大用量", index = 3)
private BigDecimal maxUsage;
/**
* 时间段ID
*/
@ExcelIgnore
private Long periodId;
/**
* 时间段名称
*/
@ExcelProperty(value = "时段名称", index = 4)
private String periodName;
/**
* 时间段类型0=峰1=谷2=平
*/
@ExcelIgnore
private Integer periodType;
/**
* 开始时间HH:mm格式
*/
@ExcelProperty(value = "开始时间", index = 5)
private String startTime;
/**
* 结束时间HH:mm格式
*/
@ExcelProperty(value = "结束时间", index = 6)
private String endTime;
/**
* 该梯度+时段的费率
*/
@ExcelProperty(value = "费率", index = 7)
private BigDecimal rate;
/**
* 创建时间
*/
@ExcelProperty(value = "创建时间", index = 8)
private Date createTime;
/**
* 备注
*/
@ExcelProperty(value = "备注", index = 9)
private String remark;
}

View File

@@ -0,0 +1,69 @@
package com.klp.ems.domain.vo;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Map;
/**
* 梯度费率视图对象 ems_rate_tier
*
* @author Joshi
* @date 2025-12-05
*/
@Data
@ExcelIgnoreUnannotated
public class EmsRateTierVo {
private static final long serialVersionUID = 1L;
/**
* 梯度费率ID
*/
@ExcelProperty(value = "梯度费率ID")
private Long tierId;
/**
* 关联费率ID
*/
@ExcelProperty(value = "费率ID")
private Long energyRateId;
/**
* 梯度等级1、2、3...
*/
@ExcelProperty(value = "梯度等级")
private Integer tierLevel;
/**
* 最小用量(包含)
*/
@ExcelProperty(value = "最小用量")
private BigDecimal minUsage;
/**
* 最大用量不包含NULL表示无上限
*/
@ExcelProperty(value = "最大用量")
private BigDecimal maxUsage;
/**
* 该梯度的费率
*/
@ExcelProperty(value = "梯度费率")
private BigDecimal rate;
/**
* 备注
*/
@ExcelProperty(value = "备注")
private String remark;
/**
* 梯度-时段费率关联(非数据库字段,用于梯度+峰谷组合模式)
* key: periodId, value: rate
*/
private Map<Long, BigDecimal> tierPeriodRates;
}

View File

@@ -0,0 +1,75 @@
package com.klp.ems.domain.vo;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelIgnore;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;
import java.math.BigDecimal;
/**
* 费率与时间段关联视图对象 ems_rate_time_period_link
*
* @author Joshi
* @date 2025-12-05
*/
@Data
@ExcelIgnoreUnannotated
public class EmsRateTimePeriodLinkVo {
private static final long serialVersionUID = 1L;
/**
* 关联ID
*/
@ExcelProperty(value = "关联ID")
private Long linkId;
/**
* 费率ID
*/
@ExcelProperty(value = "费率ID")
private Long energyRateId;
/**
* 时间段ID
*/
@ExcelProperty(value = "时间段ID")
private Long periodId;
/**
* 时间段名称(峰、谷、平)
*/
@ExcelIgnore
private String periodName;
/**
* 时间段类型0=峰1=谷2=平
*/
@ExcelIgnore
private Integer periodType;
/**
* 开始时间HH:mm格式
*/
@ExcelIgnore
private String startTime;
/**
* 结束时间HH:mm格式
*/
@ExcelIgnore
private String endTime;
/**
* 该时间段的费率
*/
@ExcelProperty(value = "时段费率")
private BigDecimal rate;
/**
* 备注
*/
@ExcelProperty(value = "备注")
private String remark;
}

View File

@@ -0,0 +1,60 @@
package com.klp.ems.domain.vo;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;
/**
* 时间段视图对象 ems_time_period
*
* @author Joshi
* @date 2025-12-05
*/
@Data
@ExcelIgnoreUnannotated
public class EmsTimePeriodVo {
private static final long serialVersionUID = 1L;
/**
* 时间段ID
*/
@ExcelProperty(value = "时间段ID")
private Long periodId;
/**
* 时间段名称(峰、谷、平)
*/
@ExcelProperty(value = "时间段名称")
private String periodName;
/**
* 时间段类型0=峰1=谷2=平
*/
@ExcelProperty(value = "时间段类型")
private Integer periodType;
/**
* 开始时间HH:mm格式
*/
@ExcelProperty(value = "开始时间")
private String startTime;
/**
* 结束时间HH:mm格式
*/
@ExcelProperty(value = "结束时间")
private String endTime;
/**
* 是否跨天0=否1=是
*/
@ExcelProperty(value = "是否跨天")
private Integer crossDay;
/**
* 备注
*/
@ExcelProperty(value = "备注")
private String remark;
}

View File

@@ -0,0 +1,42 @@
package com.klp.ems.domain.vo;
import lombok.Data;
import java.math.BigDecimal;
/**
* 能源成本汇总视图
*/
@Data
public class EnergyCostSummaryVo {
/** 分组键ID 或名称) */
private String groupKey;
/** 展示名称 */
private String groupName;
/** 能源类型 ID可选 */
private Long energyTypeId;
/** 仓库 ID可选 */
private Long warehouseId;
/** 实际仓库 ID可选 */
private Long actualWarehouseId;
/** 计量表 ID可选 */
private Long meterId;
/** 任务 ID可选 */
private Long taskId;
/** 分摊能耗合计 */
private BigDecimal totalConsumption;
/** 分摊费用合计 */
private BigDecimal totalCost;
/** 钢卷数量 */
private Long coilCount;
}

View File

@@ -0,0 +1,39 @@
package com.klp.ems.domain.vo;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import lombok.Data;
import java.math.BigDecimal;
/**
* 钢卷能源成本统计 VO
*/
@Data
@ExcelIgnoreUnannotated
public class WmsEnergyCoilDailyStatisticsVo {
/**
* 钢卷总数
*/
private Long totalCoils;
/**
* 总消耗量
*/
private BigDecimal totalConsumption;
/**
* 总成本
*/
private BigDecimal totalCost;
/**
* 平均单位成本(¥/小时)
*/
private BigDecimal avgUnitCost;
/**
* 总生产时长(分钟)
*/
private Long totalProductionDuration;
}

View File

@@ -0,0 +1,84 @@
package com.klp.ems.domain.vo;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
/**
* 钢卷日能源成本分摊结果 VO
*/
@Data
@ExcelIgnoreUnannotated
public class WmsEnergyCoilDailyVo {
@ExcelProperty("记录ID")
private Long energyCostId;
@ExcelProperty("任务ID")
private Long taskId;
@ExcelProperty("日期")
private LocalDate calcDate;
@ExcelProperty("钢卷ID")
private Long coilId;
@ExcelProperty("入场卷号")
private String enterCoilNo;
@ExcelProperty("当前卷号")
private String currentCoilNo;
@ExcelProperty("逻辑库区")
private Long warehouseId;
@ExcelProperty("实际库区")
private Long actualWarehouseId;
@ExcelProperty("能源类型")
private Long energyTypeId;
@ExcelProperty("仪表")
private Long meterId;
@ExcelProperty("分摊能耗")
private BigDecimal consumptionQty;
@ExcelProperty("分摊费用")
private BigDecimal costAmount;
@ExcelProperty("基数-重量")
private BigDecimal allocationBasisWeight;
@ExcelProperty("基数-生产时长")
private BigDecimal allocationBasisDays;
@ExcelProperty("分摊系数")
private BigDecimal allocationFactor;
@ExcelProperty("备注")
private String remark;
// 待操作相关字段
@ExcelProperty("开始时间")
private LocalDateTime scanTime;
@ExcelProperty("结束时间")
private LocalDateTime completeTime;
@ExcelProperty("生产时长(分钟)")
private Long productionDuration;
@ExcelProperty("能源费率")
private BigDecimal energyRate;
@ExcelProperty("区域名称")
private String warehouseName;
@ExcelProperty("能源类型名称")
private String energyTypeName;
}

View File

@@ -0,0 +1,21 @@
package com.klp.ems.mapper;
import com.klp.ems.domain.CostCoilDailyEnergy;
import org.apache.ibatis.annotations.Mapper;
/**
* 访问 wms_cost_coil_daily仅更新能源成本字段
*/
@Mapper
public interface CostCoilDailyMapper {
/**
* 更新成本日表中的能源成本与拆分信息,按 coil_id + calc_date 命中。
*/
int updateEnergyCost(CostCoilDailyEnergy energyCost);
/**
* 查询成本日表现有的能源成本信息energy_cost_amount、energy_cost_breakdown
*/
CostCoilDailyEnergy selectEnergyCost(CostCoilDailyEnergy energyCost);
}

View File

@@ -2,6 +2,7 @@ package com.klp.ems.mapper;
import com.klp.ems.domain.EmsEnergyConsumption;
import com.klp.ems.domain.bo.TimeRangeWithMetersBo;
import com.klp.ems.domain.bo.EmsEnergyConsumptionBo;
import com.klp.ems.domain.vo.EmsEnergyConsumptionVo;
import com.klp.common.core.mapper.BaseMapperPlus;
import com.klp.ems.domain.vo.SummaryDailyVo;
@@ -9,6 +10,7 @@ import com.klp.ems.domain.vo.SummaryMonthlyVo;
import org.apache.ibatis.annotations.Param;
import java.util.List;
import java.util.Map;
/**
* 能耗记录Mapper接口
@@ -35,4 +37,24 @@ public interface EmsEnergyConsumptionMapper extends BaseMapperPlus<EmsEnergyCons
List<SummaryDailyVo> selectDailySummaryWithMeters(TimeRangeWithMetersBo range);
List<SummaryMonthlyVo> selectMonthlySummaryWithMeters(TimeRangeWithMetersBo range);
EmsEnergyConsumption selectLatestBefore(@Param("meterId") Long meterId, @Param("endTime") String endTime);
List<EmsEnergyConsumption> selectOverlapRange(@Param("meterId") Long meterId,
@Param("startTime") String startTime,
@Param("endTime") String endTime);
EmsEnergyConsumption selectCoveringRange(@Param("meterId") Long meterId,
@Param("startTime") String startTime,
@Param("endTime") String endTime);
/**
* 查询指定计量表最近的两条抄表记录按endTime倒序
*/
List<EmsEnergyConsumption> selectLatestTwoReadings(@Param("meterId") Long meterId);
/**
* 获取能耗统计信息用SQL聚合函数计算
*/
Map<String, Object> getStatistics(EmsEnergyConsumptionBo bo);
}

View File

@@ -3,6 +3,9 @@ package com.klp.ems.mapper;
import com.klp.ems.domain.EmsEnergyRate;
import com.klp.ems.domain.vo.EmsEnergyRateVo;
import com.klp.common.core.mapper.BaseMapperPlus;
import org.apache.ibatis.annotations.Param;
import java.time.LocalDate;
/**
* 能源费率currency 为 INT0=CNY,1=USD,2=EURMapper接口
@@ -12,4 +15,9 @@ import com.klp.common.core.mapper.BaseMapperPlus;
*/
public interface EmsEnergyRateMapper extends BaseMapperPlus<EmsEnergyRateMapper, EmsEnergyRate, EmsEnergyRateVo> {
/**
* 按能源类型与日期获取生效费率。
*/
EmsEnergyRate selectEffectiveRate(@Param("energyTypeId") Long energyTypeId,
@Param("calcDate") LocalDate calcDate);
}

View File

@@ -0,0 +1,26 @@
package com.klp.ems.mapper;
import com.klp.ems.domain.EmsRateTier;
import com.klp.ems.domain.vo.EmsRateTierVo;
import com.klp.common.core.mapper.BaseMapperPlus;
import java.util.List;
/**
* 梯度费率Mapper接口
*
* @author Joshi
* @date 2025-12-05
*/
public interface EmsRateTierMapper extends BaseMapperPlus<EmsRateTierMapper, EmsRateTier, EmsRateTierVo> {
/**
* 根据费率ID查询梯度费率列表
*/
List<EmsRateTierVo> selectByRateId(Long energyRateId);
/**
* 物理删除指定费率的所有梯度
*/
int deleteByRateIdPhysical(Long energyRateId);
}

View File

@@ -0,0 +1,65 @@
package com.klp.ems.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.klp.ems.domain.EmsRateTierPeriodLink;
import com.klp.ems.domain.vo.EmsRateTierPeriodLinkVo;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* 梯度与时段关联 Mapper 接口
*
* @author Joshi
* @date 2025-12-05
*/
public interface EmsRateTierPeriodLinkMapper extends BaseMapper<EmsRateTierPeriodLink> {
/**
* 根据梯度ID查询所有关联的时段费率
*
* @param tierId 梯度ID
* @return 梯度-时段关联列表
*/
List<EmsRateTierPeriodLink> selectByTierId(@Param("tierId") Long tierId);
/**
* 根据梯度ID删除所有关联的时段费率逻辑删除
*
* @param tierId 梯度ID
* @return 删除数量
*/
int deleteByTierId(@Param("tierId") Long tierId);
/**
* 根据梯度ID物理删除所有关联的时段费率
*
* @param tierId 梯度ID
* @return 删除数量
*/
int deleteByTierIdPhysical(@Param("tierId") Long tierId);
/**
* 根据费率ID删除所有关联的梯度-时段费率(逻辑删除)
*
* @param energyRateId 费率ID
* @return 删除数量
*/
int deleteByEnergyRateId(@Param("energyRateId") Long energyRateId);
/**
* 根据费率ID物理删除所有关联的梯度-时段费率
*
* @param energyRateId 费率ID
* @return 删除数量
*/
int deleteByEnergyRateIdPhysical(@Param("energyRateId") Long energyRateId);
/**
* 查询梯度-时段关联的完整信息(包含梯度和时段详情)
*
* @param energyRateId 费率ID
* @return 梯度-时段关联VO列表
*/
List<EmsRateTierPeriodLinkVo> selectVoByEnergyRateId(@Param("energyRateId") Long energyRateId);
}

View File

@@ -0,0 +1,21 @@
package com.klp.ems.mapper;
import com.klp.ems.domain.EmsRateTimePeriodLink;
import com.klp.ems.domain.vo.EmsRateTimePeriodLinkVo;
import com.klp.common.core.mapper.BaseMapperPlus;
import java.util.List;
/**
* 费率与时间段关联Mapper接口
*
* @author Joshi
* @date 2025-12-05
*/
public interface EmsRateTimePeriodLinkMapper extends BaseMapperPlus<EmsRateTimePeriodLinkMapper, EmsRateTimePeriodLink, EmsRateTimePeriodLinkVo> {
/**
* 根据费率ID查询峰谷时段费率列表
*/
List<EmsRateTimePeriodLinkVo> selectByRateId(Long energyRateId);
}

View File

@@ -0,0 +1,14 @@
package com.klp.ems.mapper;
import com.klp.ems.domain.EmsTimePeriod;
import com.klp.ems.domain.vo.EmsTimePeriodVo;
import com.klp.common.core.mapper.BaseMapperPlus;
/**
* 时间段Mapper接口
*
* @author Joshi
* @date 2025-12-05
*/
public interface EmsTimePeriodMapper extends BaseMapperPlus<EmsTimePeriodMapper, EmsTimePeriod, EmsTimePeriodVo> {
}

View File

@@ -0,0 +1,53 @@
package com.klp.ems.mapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.klp.common.core.mapper.BaseMapperPlus;
import com.klp.ems.domain.WmsEnergyCoilDaily;
import com.klp.ems.domain.bo.EnergyCostReportBo;
import com.klp.ems.domain.vo.EnergyCostSummaryVo;
import com.klp.ems.domain.vo.WmsEnergyCoilDailyStatisticsVo;
import com.klp.ems.domain.vo.WmsEnergyCoilDailyVo;
import org.apache.ibatis.annotations.Param;
import java.util.List;
import java.util.Map;
/**
* 钢卷日能源成本分摊结果 Mapper
*/
public interface WmsEnergyCoilDailyMapper extends BaseMapperPlus<WmsEnergyCoilDailyMapper, WmsEnergyCoilDaily, WmsEnergyCoilDailyVo> {
/** 物理清理指定任务的明细 */
int deleteByTaskId(Long taskId);
/** 查询指定任务的所有分摊记录 */
List<WmsEnergyCoilDaily> selectListByTask(Long taskId);
/** 按能源类型汇总 */
List<EnergyCostSummaryVo> summaryByEnergyType(@Param("bo") EnergyCostReportBo bo);
/** 按逻辑库区汇总 */
List<EnergyCostSummaryVo> summaryByWarehouse(@Param("bo") EnergyCostReportBo bo);
/** 按计量设备汇总 */
List<EnergyCostSummaryVo> summaryByMeter(@Param("bo") EnergyCostReportBo bo);
/** 按任务汇总 */
List<EnergyCostSummaryVo> summaryByTask(@Param("bo") EnergyCostReportBo bo);
/** 概览统计 */
Map<String, Object> selectEnergyOverview(@Param("bo") EnergyCostReportBo bo);
/** 明细分页 */
Page<WmsEnergyCoilDailyVo> selectReportDetail(Page<WmsEnergyCoilDailyVo> page, @Param("bo") EnergyCostReportBo bo);
/** 查询待操作钢卷的能源成本一次性SQL查询 */
List<WmsEnergyCoilDailyVo> selectPendingActionCoilCost();
/** 查询待操作钢卷的能源成本统计 */
WmsEnergyCoilDailyStatisticsVo selectPendingActionCoilCostStatistics(
@Param("enterCoilNo") String enterCoilNo,
@Param("currentCoilNo") String currentCoilNo,
@Param("warehouseId") Long warehouseId
);
}

View File

@@ -13,6 +13,7 @@ import com.klp.ems.domain.vo.ChainAnalysisVo;
import java.util.Collection;
import java.util.List;
import java.util.Map;
/**
* 能耗记录Service接口
@@ -73,4 +74,25 @@ public interface IEmsEnergyConsumptionService {
/** 环比分析periodType=day/week/month/year + dateKey可过滤 */
ChainAnalysisVo getChainAnalysis(EmsEnergyConsumptionQueryBo queryBo);
/**
* 获取设备的上次抄表记录(用于自动填充起始数据)
* @param meterId 设备ID
* @return 上次抄表记录如果没有则返回null
*/
EmsEnergyConsumptionVo getLastReadingForMeter(Long meterId);
/**
* 获取设备本月的累计消耗量
* @param meterId 设备ID
* @return 本月累计消耗量如果没有则返回0
*/
Double getMonthlyConsumption(Long meterId);
/**
* 获取能耗统计信息
* @param bo 查询条件
* @return 统计信息(总记录数、总消耗量、平均消耗量、最大消耗量等)
*/
Map<String, Object> getStatistics(EmsEnergyConsumptionBo bo);
}

View File

@@ -2,7 +2,12 @@ package com.klp.ems.service;
import com.klp.ems.domain.EmsEnergyRate;
import com.klp.ems.domain.vo.EmsEnergyRateVo;
import com.klp.ems.domain.vo.EmsRateTierVo;
import com.klp.ems.domain.vo.EmsRateTimePeriodLinkVo;
import com.klp.ems.domain.bo.EmsEnergyRateBo;
import com.klp.ems.domain.bo.EmsRateTierBo;
import com.klp.ems.domain.bo.EmsRateTimePeriodLinkBo;
import com.klp.ems.domain.bo.EmsRateTierPeriodLinkBo;
import com.klp.common.core.page.TableDataInfo;
import com.klp.common.core.domain.PageQuery;
@@ -10,7 +15,8 @@ import java.util.Collection;
import java.util.List;
/**
* 能源费率currency 为 INT0=CNY,1=USD,2=EURService接口
* 能源费率Service接口
* 支持:固定费率、峰谷分时、阶梯电价、峰谷+阶梯组合
*
* @author Joshi
* @date 2025-09-28
@@ -18,32 +24,62 @@ import java.util.List;
public interface IEmsEnergyRateService {
/**
* 查询能源费率currency 为 INT0=CNY,1=USD,2=EUR
* 查询能源费率
*/
EmsEnergyRateVo queryById(Long energyRateId);
/**
* 查询能源费率currency 为 INT0=CNY,1=USD,2=EUR列表
* 查询能源费率列表
*/
TableDataInfo<EmsEnergyRateVo> queryPageList(EmsEnergyRateBo bo, PageQuery pageQuery);
/**
* 查询能源费率currency 为 INT0=CNY,1=USD,2=EUR列表
* 查询能源费率列表
*/
List<EmsEnergyRateVo> queryList(EmsEnergyRateBo bo);
/**
* 新增能源费率(currency 为 INT0=CNY,1=USD,2=EUR
* 新增能源费率(包括梯度和时段费率
*/
Boolean insertByBo(EmsEnergyRateBo bo);
/**
* 修改能源费率(currency 为 INT0=CNY,1=USD,2=EUR
* 修改能源费率(包括梯度和时段费率
*/
Boolean updateByBo(EmsEnergyRateBo bo);
/**
* 校验并批量删除能源费率(currency 为 INT0=CNY,1=USD,2=EUR信息
* 删除能源费率(级联删除梯度和时段费率)
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
/**
* 获取费率的梯度费率列表
*/
List<EmsRateTierVo> getRateTiers(Long energyRateId);
/**
* 获取费率的时段费率列表
*/
List<EmsRateTimePeriodLinkVo> getRateTimePeriods(Long energyRateId);
/**
* 保存梯度费率返回保存后的梯度列表包含tierId
*/
List<EmsRateTierVo> saveTiers(Long energyRateId, List<EmsRateTierBo> tiers);
/**
* 保存时段费率
*/
Boolean saveTimePeriods(Long energyRateId, List<EmsRateTimePeriodLinkBo> timePeriods);
/**
* 获取梯度的峰谷时段费率(用于梯度+峰谷组合模式)
*/
List<EmsRateTierPeriodLinkBo> getTierPeriodLinks(Long tierId);
/**
* 保存梯度-时段关联费率(用于梯度+峰谷组合模式)
*/
Boolean saveTierPeriodLinks(Long tierId, List<EmsRateTierPeriodLinkBo> tierPeriodLinks);
}

View File

@@ -5,6 +5,8 @@ import com.klp.ems.domain.vo.EmsMeterVo;
import com.klp.ems.domain.bo.EmsMeterBo;
import com.klp.common.core.page.TableDataInfo;
import com.klp.common.core.domain.PageQuery;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.util.Collection;
import java.util.List;
@@ -46,4 +48,14 @@ public interface IEmsMeterService {
* 校验并批量删除计量设备(阈值移至此处)信息
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
/**
* 下载设备导入模板
*/
void downloadTemplate(HttpServletResponse response);
/**
* 导入设备
*/
Boolean importMeters(MultipartFile file);
}

View File

@@ -0,0 +1,58 @@
package com.klp.ems.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.klp.ems.domain.EmsRateTierPeriodLink;
import com.klp.ems.domain.bo.EmsRateTierPeriodLinkBo;
import com.klp.ems.domain.vo.EmsRateTierPeriodLinkVo;
import java.util.List;
/**
* 梯度与时段关联 Service 接口
*
* @author Joshi
* @date 2025-12-05
*/
public interface IEmsRateTierPeriodLinkService extends IService<EmsRateTierPeriodLink> {
/**
* 根据梯度ID查询所有关联的时段费率
*
* @param tierId 梯度ID
* @return 梯度-时段关联列表
*/
List<EmsRateTierPeriodLink> getByTierId(Long tierId);
/**
* 根据梯度ID删除所有关联的时段费率
*
* @param tierId 梯度ID
* @return 是否删除成功
*/
Boolean deleteByTierId(Long tierId);
/**
* 根据费率ID删除所有关联的梯度-时段费率
*
* @param energyRateId 费率ID
* @return 是否删除成功
*/
Boolean deleteByEnergyRateId(Long energyRateId);
/**
* 查询梯度-时段关联的完整信息(包含梯度和时段详情)
*
* @param energyRateId 费率ID
* @return 梯度-时段关联VO列表
*/
List<EmsRateTierPeriodLinkVo> getVoByEnergyRateId(Long energyRateId);
/**
* 批量保存梯度-时段关联费率
*
* @param tierId 梯度ID
* @param tierPeriodLinks 梯度-时段关联列表
* @return 是否保存成功
*/
Boolean saveTierPeriodLinks(Long tierId, List<EmsRateTierPeriodLinkBo> tierPeriodLinks);
}

View File

@@ -0,0 +1,58 @@
package com.klp.ems.service;
import com.klp.ems.domain.vo.EmsRateTierVo;
import com.klp.ems.domain.bo.EmsRateTierBo;
import com.klp.common.core.page.TableDataInfo;
import com.klp.common.core.domain.PageQuery;
import java.util.Collection;
import java.util.List;
/**
* 梯度费率Service接口
*
* @author Joshi
* @date 2025-12-05
*/
public interface IEmsRateTierService {
/**
* 查询梯度费率
*/
EmsRateTierVo queryById(Long tierId);
/**
* 查询梯度费率列表
*/
TableDataInfo<EmsRateTierVo> queryPageList(EmsRateTierBo bo, PageQuery pageQuery);
/**
* 查询梯度费率列表
*/
List<EmsRateTierVo> queryList(EmsRateTierBo bo);
/**
* 根据费率ID查询梯度费率列表
*/
List<EmsRateTierVo> queryByRateId(Long energyRateId);
/**
* 新增梯度费率
*/
Boolean insertByBo(EmsRateTierBo bo);
/**
* 修改梯度费率
*/
Boolean updateByBo(EmsRateTierBo bo);
/**
* 删除梯度费率
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
/**
* 根据费率ID删除所有梯度费率
*/
Boolean deleteByRateId(Long energyRateId);
}

View File

@@ -0,0 +1,58 @@
package com.klp.ems.service;
import com.klp.ems.domain.vo.EmsRateTimePeriodLinkVo;
import com.klp.ems.domain.bo.EmsRateTimePeriodLinkBo;
import com.klp.common.core.page.TableDataInfo;
import com.klp.common.core.domain.PageQuery;
import java.util.Collection;
import java.util.List;
/**
* 费率与时间段关联Service接口
*
* @author Joshi
* @date 2025-12-05
*/
public interface IEmsRateTimePeriodLinkService {
/**
* 查询费率与时间段关联
*/
EmsRateTimePeriodLinkVo queryById(Long linkId);
/**
* 查询费率与时间段关联列表
*/
TableDataInfo<EmsRateTimePeriodLinkVo> queryPageList(EmsRateTimePeriodLinkBo bo, PageQuery pageQuery);
/**
* 查询费率与时间段关联列表
*/
List<EmsRateTimePeriodLinkVo> queryList(EmsRateTimePeriodLinkBo bo);
/**
* 根据费率ID查询峰谷时段费率列表
*/
List<EmsRateTimePeriodLinkVo> queryByRateId(Long energyRateId);
/**
* 新增费率与时间段关联
*/
Boolean insertByBo(EmsRateTimePeriodLinkBo bo);
/**
* 修改费率与时间段关联
*/
Boolean updateByBo(EmsRateTimePeriodLinkBo bo);
/**
* 删除费率与时间段关联
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
/**
* 根据费率ID删除所有关联
*/
Boolean deleteByRateId(Long energyRateId);
}

View File

@@ -0,0 +1,48 @@
package com.klp.ems.service;
import com.klp.ems.domain.vo.EmsTimePeriodVo;
import com.klp.ems.domain.bo.EmsTimePeriodBo;
import com.klp.common.core.page.TableDataInfo;
import com.klp.common.core.domain.PageQuery;
import java.util.Collection;
import java.util.List;
/**
* 时间段Service接口
*
* @author Joshi
* @date 2025-12-05
*/
public interface IEmsTimePeriodService {
/**
* 查询时间段
*/
EmsTimePeriodVo queryById(Long periodId);
/**
* 查询时间段列表
*/
TableDataInfo<EmsTimePeriodVo> queryPageList(EmsTimePeriodBo bo, PageQuery pageQuery);
/**
* 查询时间段列表
*/
List<EmsTimePeriodVo> queryList(EmsTimePeriodBo bo);
/**
* 新增时间段
*/
Boolean insertByBo(EmsTimePeriodBo bo);
/**
* 修改时间段
*/
Boolean updateByBo(EmsTimePeriodBo bo);
/**
* 删除时间段
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
}

View File

@@ -0,0 +1,19 @@
package com.klp.ems.service;
import java.time.LocalDate;
/**
* 综合能源分摊调度/执行服务
*/
public interface IEnergyAllocationService {
/**
* 根据日期+能源类型触发一次分摊,若 energyTypeId 为空则针对所有已配置能源类型。
*/
void dispatch(LocalDate calcDate, Long energyTypeId, String allocationScope);
/**
* 将指定任务标记为需要重新计算并立即执行。
*/
void rerunTask(Long taskId);
}

View File

@@ -0,0 +1,25 @@
package com.klp.ems.service;
import com.klp.common.core.domain.PageQuery;
import com.klp.common.core.page.TableDataInfo;
import com.klp.ems.domain.bo.EnergyCostReportBo;
import com.klp.ems.domain.vo.EnergyCostSummaryVo;
import com.klp.ems.domain.vo.WmsEnergyCoilDailyVo;
import java.util.List;
import java.util.Map;
/**
* 能源成本报表 Service
*/
public interface IEnergyCostReportService {
/** 概览统计 */
Map<String, Object> overview(EnergyCostReportBo bo);
/** 汇总数据 */
List<EnergyCostSummaryVo> summary(EnergyCostReportBo bo);
/** 明细分页 */
TableDataInfo<WmsEnergyCoilDailyVo> detail(EnergyCostReportBo bo, PageQuery pageQuery);
}

View File

@@ -0,0 +1,42 @@
package com.klp.ems.service;
import com.klp.common.core.domain.PageQuery;
import com.klp.common.core.page.TableDataInfo;
import com.klp.ems.domain.bo.WmsEnergyCoilDailyBo;
import com.klp.ems.domain.vo.WmsEnergyCoilDailyVo;
import com.klp.ems.domain.vo.WmsEnergyCoilDailyStatisticsVo;
import java.util.Collection;
import java.util.List;
/**
* 钢卷日能源成本分摊结果 Service
*/
public interface IWmsEnergyCoilDailyService {
WmsEnergyCoilDailyVo queryById(Long energyCostId);
TableDataInfo<WmsEnergyCoilDailyVo> queryPageList(WmsEnergyCoilDailyBo bo, PageQuery pageQuery);
List<WmsEnergyCoilDailyVo> queryList(WmsEnergyCoilDailyBo bo);
/**
* 查询待操作钢卷的能源成本(基于待操作时间范围计算)
* 1. 查询所有待操作记录(已操作或等待操作的钢卷)
* 2. 按待操作的时间范围查询抄表记录
* 3. 计算该时间段内的能源消耗和成本
* 4. 按分摊方式分摊到每个钢卷
*/
TableDataInfo<WmsEnergyCoilDailyVo> queryPendingActionCoilCost(WmsEnergyCoilDailyBo bo, PageQuery pageQuery);
/**
* 查询待操作钢卷的能源成本统计
*/
WmsEnergyCoilDailyStatisticsVo queryPendingActionCoilCostStatistics(String enterCoilNo, String currentCoilNo, Long warehouseId);
Boolean insertByBo(WmsEnergyCoilDailyBo bo);
Boolean updateByBo(WmsEnergyCoilDailyBo bo);
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
}

View File

@@ -1,12 +1,16 @@
package com.klp.ems.service.impl;
import cn.hutool.core.bean.BeanUtil;
import com.klp.common.core.domain.entity.SysUser;
import com.klp.common.core.page.TableDataInfo;
import com.klp.common.core.domain.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.klp.common.helper.LoginHelper;
import com.klp.ems.domain.EmsEnergyType;
import com.klp.ems.domain.EmsLocation;
import com.klp.ems.domain.EmsMeter;
import com.klp.ems.domain.bo.EmsEnergyConsumptionQueryBo;
import com.klp.ems.domain.bo.MeterFilterBo;
import com.klp.ems.domain.bo.TimeRangeWithMetersBo;
@@ -15,6 +19,7 @@ import com.klp.ems.domain.vo.SummaryDailyVo;
import com.klp.ems.domain.vo.SummaryMonthlyVo;
import com.klp.ems.domain.vo.YearOnYearVo;
import com.klp.ems.domain.vo.ChainAnalysisVo;
import com.klp.system.mapper.SysUserMapper;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import com.klp.ems.domain.bo.EmsEnergyConsumptionBo;
@@ -23,6 +28,7 @@ import com.klp.ems.domain.EmsEnergyConsumption;
import com.klp.ems.mapper.EmsEnergyConsumptionMapper;
import com.klp.ems.mapper.EmsMeterMapper;
import com.klp.ems.mapper.EmsLocationMapper;
import com.klp.ems.mapper.EmsEnergyTypeMapper;
import com.klp.ems.service.IEmsEnergyConsumptionService;
import java.time.LocalDate;
@@ -30,6 +36,7 @@ import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.WeekFields;
import java.util.*;
import java.math.BigDecimal;
/**
* 能耗记录Service业务层处理
@@ -44,13 +51,22 @@ public class EmsEnergyConsumptionServiceImpl implements IEmsEnergyConsumptionSer
private final EmsEnergyConsumptionMapper baseMapper;
private final EmsMeterMapper meterMapper;
private final EmsLocationMapper locationMapper;
private final SysUserMapper sysUserMapper;
private final EmsEnergyTypeMapper energyTypeMapper;
/**
* 查询能耗记录
*/
@Override
public EmsEnergyConsumptionVo queryById(Long energyConsumptionId){
return baseMapper.selectVoById(energyConsumptionId);
EmsEnergyConsumptionVo vo = baseMapper.selectVoById(energyConsumptionId);
if (vo != null && vo.getRecordedBy() != null) {
SysUser user = sysUserMapper.selectById(vo.getRecordedBy());
if (user != null) {
vo.setRecordedByName(user.getNickName());
}
}
return vo;
}
/**
@@ -60,6 +76,7 @@ public class EmsEnergyConsumptionServiceImpl implements IEmsEnergyConsumptionSer
public TableDataInfo<EmsEnergyConsumptionVo> queryPageList(EmsEnergyConsumptionBo bo, PageQuery pageQuery) {
LambdaQueryWrapper<EmsEnergyConsumption> lqw = buildQueryWrapper(bo);
Page<EmsEnergyConsumptionVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
fillRecordedByName(result.getRecords());
return TableDataInfo.build(result);
}
@@ -69,7 +86,41 @@ public class EmsEnergyConsumptionServiceImpl implements IEmsEnergyConsumptionSer
@Override
public List<EmsEnergyConsumptionVo> queryList(EmsEnergyConsumptionBo bo) {
LambdaQueryWrapper<EmsEnergyConsumption> lqw = buildQueryWrapper(bo);
return baseMapper.selectVoList(lqw);
List<EmsEnergyConsumptionVo> list = baseMapper.selectVoList(lqw);
fillRecordedByName(list);
return list;
}
/**
* 填充记录人名称、设备编号、能源类型名称
*/
private void fillRecordedByName(List<EmsEnergyConsumptionVo> list) {
if (list == null || list.isEmpty()) {
return;
}
for (EmsEnergyConsumptionVo vo : list) {
// 填充记录人名称
if (vo.getRecordedBy() != null) {
SysUser user = sysUserMapper.selectById(vo.getRecordedBy());
if (user != null) {
vo.setRecordedByName(user.getNickName());
}
}
// 填充设备编号和能源类型名称
if (vo.getMeterId() != null) {
EmsMeter meter = meterMapper.selectById(vo.getMeterId());
if (meter != null) {
vo.setMeterCode(meter.getMeterCode());
// 通过energyTypeId查询能源类型名称
if (meter.getEnergyTypeId() != null) {
EmsEnergyType energyType = energyTypeMapper.selectById(meter.getEnergyTypeId());
if (energyType != null) {
vo.setEnergyTypeName(energyType.getName());
}
}
}
}
}
}
private LambdaQueryWrapper<EmsEnergyConsumption> buildQueryWrapper(EmsEnergyConsumptionBo bo) {
@@ -92,6 +143,7 @@ public class EmsEnergyConsumptionServiceImpl implements IEmsEnergyConsumptionSer
public Boolean insertByBo(EmsEnergyConsumptionBo bo) {
EmsEnergyConsumption add = BeanUtil.toBean(bo, EmsEnergyConsumption.class);
validEntityBeforeSave(add);
add.setRecordedBy(LoginHelper.getUserId());
boolean flag = baseMapper.insert(add) > 0;
if (flag) {
bo.setEnergyConsumptionId(add.getEnergyConsumptionId());
@@ -455,4 +507,55 @@ public class EmsEnergyConsumptionServiceImpl implements IEmsEnergyConsumptionSer
filter.setMeterId(null);
return meterMapper.selectMeterIds(filter);
}
/**
* 获取设备的上次抄表记录(用于自动填充起始数据)
*/
@Override
public EmsEnergyConsumptionVo getLastReadingForMeter(Long meterId) {
List<EmsEnergyConsumption> readings = baseMapper.selectLatestTwoReadings(meterId);
if (readings != null && !readings.isEmpty()) {
// 返回最新的一条记录
EmsEnergyConsumption latest = readings.get(0);
return BeanUtil.toBean(latest, EmsEnergyConsumptionVo.class);
}
return null;
}
/**
* 获取设备本月的累计消耗量
*/
@Override
public Double getMonthlyConsumption(Long meterId) {
LocalDateTime now = LocalDateTime.now();
LocalDateTime startOfThisMonth = now.withDayOfMonth(1).toLocalDate().atStartOfDay();
LocalDateTime endOfThisMonth = now.withDayOfMonth(now.toLocalDate().lengthOfMonth())
.withHour(23).withMinute(59).withSecond(59);
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
TimeRangeWithMetersBo range = new TimeRangeWithMetersBo();
range.setMeterIds(Collections.singletonList(meterId));
range.setStart(fmt.format(startOfThisMonth));
range.setEnd(fmt.format(endOfThisMonth));
Double consumption = baseMapper.sumConsumptionBetweenWithMeters(range);
return consumption != null ? consumption : 0D;
}
/**
* 获取能耗统计信息使用SQL聚合函数
*/
@Override
public Map<String, Object> getStatistics(EmsEnergyConsumptionBo bo) {
Map<String, Object> stats = baseMapper.getStatistics(bo);
if (stats == null) {
stats = new HashMap<>();
stats.put("totalCount", 0);
stats.put("totalConsumption", 0.0);
stats.put("avgConsumption", 0.0);
stats.put("maxConsumption", 0.0);
stats.put("minConsumption", 0.0);
}
return stats;
}
}

View File

@@ -6,20 +6,33 @@ import com.klp.common.core.domain.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.klp.ems.domain.bo.*;
import com.klp.ems.domain.vo.EmsRateTierPeriodLinkVo;
import com.klp.ems.mapper.EmsRateTierPeriodLinkMapper;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import com.klp.ems.domain.bo.EmsEnergyRateBo;
import com.klp.ems.domain.vo.EmsEnergyRateVo;
import com.klp.ems.domain.vo.EmsRateTierVo;
import com.klp.ems.domain.vo.EmsRateTimePeriodLinkVo;
import com.klp.ems.domain.EmsEnergyRate;
import com.klp.ems.domain.EmsRateTier;
import com.klp.ems.domain.EmsRateTimePeriodLink;
import com.klp.ems.mapper.EmsEnergyRateMapper;
import com.klp.ems.mapper.EmsRateTierMapper;
import com.klp.ems.mapper.EmsRateTimePeriodLinkMapper;
import com.klp.ems.service.IEmsEnergyRateService;
import com.klp.ems.service.IEmsRateTierService;
import com.klp.ems.service.IEmsRateTimePeriodLinkService;
import com.klp.ems.service.IEmsRateTierPeriodLinkService;
import com.klp.ems.service.IEmsTimePeriodService;
import java.util.List;
import java.util.Map;
import java.util.Collection;
/**
* 能源费率currency 为 INT0=CNY,1=USD,2=EURService业务层处理
* 能源费率Service业务层处理
* 支持:固定费率、峰谷分时、阶梯电价、峰谷+阶梯组合
*
* @author Joshi
* @date 2025-09-28
@@ -29,6 +42,11 @@ import java.util.Collection;
public class EmsEnergyRateServiceImpl implements IEmsEnergyRateService {
private final EmsEnergyRateMapper baseMapper;
private final IEmsRateTierService rateTierService;
private final IEmsRateTimePeriodLinkService rateTimePeriodLinkService;
private final EmsRateTierMapper rateTierMapper;
private final IEmsRateTierPeriodLinkService rateTierPeriodLinkService;
private final IEmsTimePeriodService iEmsTimePeriodService;
/**
* 查询能源费率currency 为 INT0=CNY,1=USD,2=EUR
@@ -45,6 +63,10 @@ public class EmsEnergyRateServiceImpl implements IEmsEnergyRateService {
public TableDataInfo<EmsEnergyRateVo> queryPageList(EmsEnergyRateBo bo, PageQuery pageQuery) {
LambdaQueryWrapper<EmsEnergyRate> lqw = buildQueryWrapper(bo);
Page<EmsEnergyRateVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
// 为每个费率添加梯度信息
result.getRecords().forEach(rate -> {
rate.setTiers(getRateTiers(rate.getEnergyRateId()));
});
return TableDataInfo.build(result);
}
@@ -54,7 +76,12 @@ public class EmsEnergyRateServiceImpl implements IEmsEnergyRateService {
@Override
public List<EmsEnergyRateVo> queryList(EmsEnergyRateBo bo) {
LambdaQueryWrapper<EmsEnergyRate> lqw = buildQueryWrapper(bo);
return baseMapper.selectVoList(lqw);
List<EmsEnergyRateVo> list = baseMapper.selectVoList(lqw);
// 为每个费率添加梯度信息
list.forEach(rate -> {
rate.setTiers(getRateTiers(rate.getEnergyRateId()));
});
return list;
}
private LambdaQueryWrapper<EmsEnergyRate> buildQueryWrapper(EmsEnergyRateBo bo) {
@@ -100,13 +127,225 @@ public class EmsEnergyRateServiceImpl implements IEmsEnergyRateService {
}
/**
* 批量删除能源费率(currency 为 INT0=CNY,1=USD,2=EUR
* 批量删除能源费率(级联删除梯度和时段费率
*/
@Override
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if(isValid){
//TODO 做一些业务上的校验,判断是否需要校验
}
// 级联删除梯度费率和时段费率
for (Long rateId : ids) {
rateTierService.deleteByRateId(rateId);
rateTimePeriodLinkService.deleteByRateId(rateId);
}
return baseMapper.deleteBatchIds(ids) > 0;
}
/**
* 获取费率的梯度费率列表
* 逻辑:
* - 单梯度模式:返回梯度的 rate 字段
* - 单峰谷模式:不返回梯度(梯度为空)
* - 双模式(梯度+峰谷):返回梯度在第一个时段(峰)的费率
*/
@Override
public List<EmsRateTierVo> getRateTiers(Long energyRateId) {
// 先查询费率配置
EmsEnergyRateVo energyRate = queryById(energyRateId);
if (energyRate == null) {
return new java.util.ArrayList<>();
}
List<EmsRateTierVo> tiers = rateTierService.queryByRateId(energyRateId);
// 双模式(梯度+峰谷):需要从关联表中获取费率
if (energyRate.getUseTieredPricing() == 1 && energyRate.getUsePeakValley() == 1) {
// 获取所有梯度-时段关联
List<EmsRateTierPeriodLinkVo> tierPeriodLinks = rateTierPeriodLinkService.getVoByEnergyRateId(energyRateId);
// 为每个梯度设置第一个时段(峰)的费率,并添加所有时段的费率映射
tiers.forEach(tier -> {
// 为该梯度创建时段费率映射
java.util.Map<Long, java.math.BigDecimal> tierPeriodRates = new java.util.HashMap<>();
// 找到该梯度的所有时段费率
tierPeriodLinks.stream()
.filter(link -> link.getTierId().equals(tier.getTierId()))
.forEach(link -> {
tierPeriodRates.put(link.getPeriodId(), link.getRate());
});
// 设置梯度的时段费率映射
tier.setTierPeriodRates(tierPeriodRates);
// 设置梯度的主费率为峰时段的费率
EmsRateTierPeriodLinkVo peakRate = tierPeriodLinks.stream()
.filter(link -> link.getTierId().equals(tier.getTierId()) && link.getPeriodType() == 0)
.findFirst()
.orElse(null);
if (peakRate != null) {
tier.setRate(peakRate.getRate());
}
});
}
System.out.println("getRateTiers返回梯度数量: " + tiers.size() + ", 模式: tiered=" + energyRate.getUseTieredPricing() + ", peakValley=" + energyRate.getUsePeakValley());
tiers.forEach(tier -> System.out.println(" - tierLevel=" + tier.getTierLevel() + ", rate=" + tier.getRate()));
return tiers;
}
/**
* 获取费率的时段费率列表
*/
@Override
public List<EmsRateTimePeriodLinkVo> getRateTimePeriods(Long energyRateId) {
return rateTimePeriodLinkService.queryByRateId(energyRateId);
}
/**
* 保存梯度费率返回保存后的梯度列表包含tierId
*/
@Override
public List<EmsRateTierVo> saveTiers(Long energyRateId, List<EmsRateTierBo> tiers) {
if (tiers == null || tiers.isEmpty()) {
return new java.util.ArrayList<>();
}
try {
// 先物理删除梯度-时段关联(避免外键约束失败)
com.klp.ems.mapper.EmsRateTierPeriodLinkMapper tierPeriodLinkMapper =
(com.klp.ems.mapper.EmsRateTierPeriodLinkMapper) rateTierPeriodLinkService.getBaseMapper();
int deleteLinkCount = tierPeriodLinkMapper.deleteByEnergyRateIdPhysical(energyRateId);
System.out.println("物理删除梯度-时段关联数量: " + deleteLinkCount + ", energyRateId: " + energyRateId);
// 再物理删除旧的梯度费率(使用原生 SQL
int deleteCount = rateTierMapper.deleteByRateIdPhysical(energyRateId);
System.out.println("物理删除梯度数量: " + deleteCount + ", energyRateId: " + energyRateId);
// 再保存新的梯度费率
for (EmsRateTierBo tier : tiers) {
tier.setEnergyRateId(energyRateId);
// 清除 tierId让数据库自动生成
tier.setTierId(null);
System.out.println("插入梯度: tierLevel=" + tier.getTierLevel() +
", minUsage=" + tier.getMinUsage() +
", maxUsage=" + tier.getMaxUsage() +
", rate=" + tier.getRate() +
", energyRateId=" + energyRateId);
rateTierService.insertByBo(tier);
}
// 返回保存后的梯度列表
List<EmsRateTierVo> result = rateTierService.queryByRateId(energyRateId);
System.out.println("保存梯度成功,返回数量: " + result.size());
return result;
} catch (Exception e) {
// 如果插入失败,记录错误并重新抛出
System.err.println("保存梯度失败: " + e.getMessage());
e.printStackTrace();
throw e;
}
}
/**
* 保存时段费率
*/
@Override
public Boolean saveTimePeriods(Long energyRateId, List<EmsRateTimePeriodLinkBo> timePeriods) {
if (timePeriods == null || timePeriods.isEmpty()) {
return true;
}
// 获取现有的时段费率
List<EmsRateTimePeriodLinkVo> existingLinks = rateTimePeriodLinkService.queryByRateId(energyRateId);
// 处理时段费率:新增、更新或删除
for (EmsRateTimePeriodLinkBo period : timePeriods) {
// 如果 periodId 为 null说明是新增时段需要先保存时段定义
if (period.getPeriodId() == null) {
// 创建新的时段定义
EmsTimePeriodBo timePeriodBo = new EmsTimePeriodBo();
timePeriodBo.setPeriodType(period.getPeriodType());
timePeriodBo.setPeriodName(period.getPeriodName());
timePeriodBo.setStartTime(period.getStartTime());
timePeriodBo.setEndTime(period.getEndTime());
timePeriodBo.setCrossDay(period.getCrossDay());
// 保存时段定义并获得 periodId
iEmsTimePeriodService.insertByBo(timePeriodBo);
period.setPeriodId(timePeriodBo.getPeriodId());
}
// 如果 rate 为 null说明是组合模式只保存时段定义不保存时段费率关联
if (period.getRate() == null) {
System.out.println("跳过时段费率关联保存(组合模式): periodId=" + period.getPeriodId());
continue;
}
period.setEnergyRateId(energyRateId);
// 检查是否已存在(通过 linkId
if (period.getLinkId() != null) {
// 已存在,执行更新
rateTimePeriodLinkService.updateByBo(period);
} else {
// linkId 为 null检查是否存在相同的 periodId
EmsRateTimePeriodLinkVo existingLink = existingLinks.stream()
.filter(link -> link.getPeriodId().equals(period.getPeriodId()) &&
link.getEnergyRateId().equals(energyRateId))
.findFirst()
.orElse(null);
if (existingLink != null) {
// 找到已有关联,执行更新
period.setLinkId(existingLink.getLinkId());
rateTimePeriodLinkService.updateByBo(period);
} else {
// 不存在,执行插入
rateTimePeriodLinkService.insertByBo(period);
}
}
}
// 删除不在新列表中的旧时段费率
for (EmsRateTimePeriodLinkVo existingLink : existingLinks) {
boolean stillExists = timePeriods.stream()
.anyMatch(period -> period.getPeriodId().equals(existingLink.getPeriodId()));
if (!stillExists) {
rateTimePeriodLinkService.deleteWithValidByIds(
java.util.Collections.singletonList(existingLink.getLinkId()), false);
}
}
return true;
}
/**
* 获取梯度的峰谷时段费率(用于梯度+峰谷组合模式)
*/
@Override
public List<EmsRateTierPeriodLinkBo> getTierPeriodLinks(Long tierId) {
return rateTierPeriodLinkService.getByTierId(tierId).stream()
.map(link -> {
EmsRateTierPeriodLinkBo bo = new EmsRateTierPeriodLinkBo();
bo.setLinkId(link.getLinkId());
bo.setTierId(link.getTierId());
bo.setPeriodId(link.getPeriodId());
bo.setRate(link.getRate());
return bo;
})
.collect(java.util.stream.Collectors.toList());
}
/**
* 保存梯度-时段关联费率(用于梯度+峰谷组合模式)
*/
@Override
public Boolean saveTierPeriodLinks(Long tierId, List<EmsRateTierPeriodLinkBo> tierPeriodLinks) {
if (tierPeriodLinks == null || tierPeriodLinks.isEmpty()) {
return true;
}
return rateTierPeriodLinkService.saveTierPeriodLinks(tierId, tierPeriodLinks);
}
}

View File

@@ -7,14 +7,21 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.klp.common.utils.StringUtils;
import com.klp.common.utils.poi.ExcelUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import com.klp.ems.domain.bo.EmsMeterBo;
import com.klp.ems.domain.vo.EmsMeterVo;
import com.klp.ems.domain.EmsMeter;
import com.klp.ems.domain.EmsEnergyType;
import com.klp.ems.domain.dto.MeterTemplateDto;
import com.klp.ems.mapper.EmsMeterMapper;
import com.klp.ems.mapper.EmsEnergyTypeMapper;
import com.klp.ems.service.IEmsMeterService;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Collection;
@@ -30,6 +37,7 @@ import java.util.Collection;
public class EmsMeterServiceImpl implements IEmsMeterService {
private final EmsMeterMapper baseMapper;
private final EmsEnergyTypeMapper energyTypeMapper;
/**
* 查询计量设备(阈值移至此处)
@@ -114,4 +122,113 @@ public class EmsMeterServiceImpl implements IEmsMeterService {
}
return baseMapper.deleteBatchIds(ids) > 0;
}
/**
* 下载设备导入模板
*/
@Override
public void downloadTemplate(HttpServletResponse response) {
// 创建示例数据
List<MeterTemplateDto> templateData = new java.util.ArrayList<>();
// 示例1水表
MeterTemplateDto meter1 = new MeterTemplateDto();
meter1.setMeterCode("W-001");
meter1.setEnergyType("");
meter1.setModel("DL-100");
meter1.setManufacturer("厂商A");
meter1.setInstallDate(new Date());
templateData.add(meter1);
// 示例2电表
MeterTemplateDto meter2 = new MeterTemplateDto();
meter2.setMeterCode("E-001");
meter2.setEnergyType("");
meter2.setModel("DL-200");
meter2.setManufacturer("厂商B");
meter2.setInstallDate(new Date());
templateData.add(meter2);
// 示例3气表
MeterTemplateDto meter3 = new MeterTemplateDto();
meter3.setMeterCode("G-001");
meter3.setEnergyType("天然气");
meter3.setModel("DL-300");
meter3.setManufacturer("厂商C");
meter3.setInstallDate(new Date());
templateData.add(meter3);
// 导出为 Excel
ExcelUtil.exportExcel(templateData, "设备导入模板", MeterTemplateDto.class, response);
}
/**
* 导入设备
*/
@Override
public Boolean importMeters(MultipartFile file) {
try {
// 读取 Excel 文件为模板 DTO
List<MeterTemplateDto> templateList = ExcelUtil.importExcel(file.getInputStream(), MeterTemplateDto.class);
if (templateList == null || templateList.isEmpty()) {
return false;
}
// 转换为 EmsMeter 并设置默认值
List<EmsMeter> meterList = new java.util.ArrayList<>();
for (MeterTemplateDto template : templateList) {
EmsMeter meter = new EmsMeter();
meter.setMeterCode(template.getMeterCode());
meter.setModel(template.getModel());
meter.setManufacturer(template.getManufacturer());
// 安装日期为空时默认为当日
if (template.getInstallDate() != null) {
meter.setInstallDate(template.getInstallDate());
} else {
meter.setInstallDate(new Date());
}
// 设备状态默认为启用0
meter.setStatus(0L);
// 根据能源类型名称获取能源类型 ID
Long energyTypeId = getEnergyTypeIdByName(template.getEnergyType());
meter.setEnergyTypeId(energyTypeId);
meterList.add(meter);
}
// 批量插入
for (EmsMeter meter : meterList) {
validEntityBeforeSave(meter);
baseMapper.insert(meter);
}
return true;
} catch (Exception e) {
throw new RuntimeException("导入设备失败: " + e.getMessage(), e);
}
}
/**
* 根据能源类型名称获取能源类型 ID
*/
private Long getEnergyTypeIdByName(String energyTypeName) {
if (energyTypeName == null) {
return null;
}
// 从数据库查询能源类型
LambdaQueryWrapper<EmsEnergyType> queryWrapper = Wrappers.lambdaQuery();
queryWrapper.eq(EmsEnergyType::getName, energyTypeName.trim());
EmsEnergyType energyType = energyTypeMapper.selectOne(queryWrapper);
if (energyType != null) {
return energyType.getEnergyTypeId();
}
return null;
}
}

View File

@@ -0,0 +1,79 @@
package com.klp.ems.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.klp.ems.domain.EmsRateTierPeriodLink;
import com.klp.ems.domain.bo.EmsRateTierPeriodLinkBo;
import com.klp.ems.domain.vo.EmsRateTierPeriodLinkVo;
import com.klp.ems.mapper.EmsRateTierPeriodLinkMapper;
import com.klp.ems.service.IEmsRateTierPeriodLinkService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.stream.Collectors;
/**
* 梯度与时段关联 Service 实现
*
* @author Joshi
* @date 2025-12-05
*/
@Service
@RequiredArgsConstructor
public class EmsRateTierPeriodLinkServiceImpl extends ServiceImpl<EmsRateTierPeriodLinkMapper, EmsRateTierPeriodLink>
implements IEmsRateTierPeriodLinkService {
private final EmsRateTierPeriodLinkMapper emsRateTierPeriodLinkMapper;
@Override
public List<EmsRateTierPeriodLink> getByTierId(Long tierId) {
return emsRateTierPeriodLinkMapper.selectByTierId(tierId);
}
@Override
@Transactional
public Boolean deleteByTierId(Long tierId) {
return emsRateTierPeriodLinkMapper.deleteByTierId(tierId) > 0;
}
@Override
@Transactional
public Boolean deleteByEnergyRateId(Long energyRateId) {
return emsRateTierPeriodLinkMapper.deleteByEnergyRateId(energyRateId) > 0;
}
@Override
public List<EmsRateTierPeriodLinkVo> getVoByEnergyRateId(Long energyRateId) {
return emsRateTierPeriodLinkMapper.selectVoByEnergyRateId(energyRateId);
}
@Override
@Transactional
public Boolean saveTierPeriodLinks(Long tierId, List<EmsRateTierPeriodLinkBo> tierPeriodLinks) {
System.out.println("保存梯度-时段关联: tierId=" + tierId + ", 关联数量=" + tierPeriodLinks.size());
tierPeriodLinks.forEach(bo -> {
System.out.println(" - periodId=" + bo.getPeriodId() + ", rate=" + bo.getRate());
});
// 先物理删除该梯度的所有关联(避免死锁)
int deleteCount = emsRateTierPeriodLinkMapper.deleteByTierIdPhysical(tierId);
System.out.println("物理删除梯度-时段关联数量: " + deleteCount + ", tierId: " + tierId);
// 再批量插入新的关联
List<EmsRateTierPeriodLink> links = tierPeriodLinks.stream()
.map(bo -> {
EmsRateTierPeriodLink link = new EmsRateTierPeriodLink();
link.setTierId(tierId);
link.setPeriodId(bo.getPeriodId());
link.setRate(bo.getRate());
link.setRemark(bo.getRemark());
return link;
})
.collect(Collectors.toList());
boolean result = this.saveBatch(links);
System.out.println("梯度-时段关联保存结果: " + result);
return result;
}
}

View File

@@ -0,0 +1,98 @@
package com.klp.ems.service.impl;
import cn.hutool.core.bean.BeanUtil;
import com.klp.common.core.page.TableDataInfo;
import com.klp.common.core.domain.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import com.klp.ems.domain.bo.EmsRateTierBo;
import com.klp.ems.domain.vo.EmsRateTierVo;
import com.klp.ems.domain.EmsRateTier;
import com.klp.ems.mapper.EmsRateTierMapper;
import com.klp.ems.service.IEmsRateTierService;
import java.util.Collection;
import java.util.List;
/**
* 梯度费率Service业务层处理
*
* @author Joshi
* @date 2025-12-05
*/
@RequiredArgsConstructor
@Service
public class EmsRateTierServiceImpl implements IEmsRateTierService {
private final EmsRateTierMapper baseMapper;
@Override
public EmsRateTierVo queryById(Long tierId) {
return baseMapper.selectVoById(tierId);
}
@Override
public TableDataInfo<EmsRateTierVo> queryPageList(EmsRateTierBo bo, PageQuery pageQuery) {
LambdaQueryWrapper<EmsRateTier> lqw = buildQueryWrapper(bo);
Page<EmsRateTierVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
return TableDataInfo.build(result);
}
@Override
public List<EmsRateTierVo> queryList(EmsRateTierBo bo) {
LambdaQueryWrapper<EmsRateTier> lqw = buildQueryWrapper(bo);
return baseMapper.selectVoList(lqw);
}
@Override
public List<EmsRateTierVo> queryByRateId(Long energyRateId) {
return baseMapper.selectByRateId(energyRateId);
}
private LambdaQueryWrapper<EmsRateTier> buildQueryWrapper(EmsRateTierBo bo) {
LambdaQueryWrapper<EmsRateTier> lqw = Wrappers.lambdaQuery();
lqw.eq(bo.getEnergyRateId() != null, EmsRateTier::getEnergyRateId, bo.getEnergyRateId());
lqw.eq(bo.getTierLevel() != null, EmsRateTier::getTierLevel, bo.getTierLevel());
return lqw;
}
@Override
public Boolean insertByBo(EmsRateTierBo bo) {
EmsRateTier add = BeanUtil.toBean(bo, EmsRateTier.class);
validEntityBeforeSave(add);
boolean flag = baseMapper.insert(add) > 0;
if (flag) {
bo.setTierId(add.getTierId());
}
return flag;
}
@Override
public Boolean updateByBo(EmsRateTierBo bo) {
EmsRateTier update = BeanUtil.toBean(bo, EmsRateTier.class);
validEntityBeforeSave(update);
return baseMapper.updateById(update) > 0;
}
private void validEntityBeforeSave(EmsRateTier entity) {
// TODO 做一些数据校验
}
@Override
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if (isValid) {
// TODO 做一些业务上的校验
}
return baseMapper.deleteBatchIds(ids) > 0;
}
@Override
public Boolean deleteByRateId(Long energyRateId) {
LambdaQueryWrapper<EmsRateTier> lqw = Wrappers.lambdaQuery();
lqw.eq(EmsRateTier::getEnergyRateId, energyRateId);
return baseMapper.delete(lqw) > 0;
}
}

View File

@@ -0,0 +1,98 @@
package com.klp.ems.service.impl;
import cn.hutool.core.bean.BeanUtil;
import com.klp.common.core.page.TableDataInfo;
import com.klp.common.core.domain.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import com.klp.ems.domain.bo.EmsRateTimePeriodLinkBo;
import com.klp.ems.domain.vo.EmsRateTimePeriodLinkVo;
import com.klp.ems.domain.EmsRateTimePeriodLink;
import com.klp.ems.mapper.EmsRateTimePeriodLinkMapper;
import com.klp.ems.service.IEmsRateTimePeriodLinkService;
import java.util.Collection;
import java.util.List;
/**
* 费率与时间段关联Service业务层处理
*
* @author Joshi
* @date 2025-12-05
*/
@RequiredArgsConstructor
@Service
public class EmsRateTimePeriodLinkServiceImpl implements IEmsRateTimePeriodLinkService {
private final EmsRateTimePeriodLinkMapper baseMapper;
@Override
public EmsRateTimePeriodLinkVo queryById(Long linkId) {
return baseMapper.selectVoById(linkId);
}
@Override
public TableDataInfo<EmsRateTimePeriodLinkVo> queryPageList(EmsRateTimePeriodLinkBo bo, PageQuery pageQuery) {
LambdaQueryWrapper<EmsRateTimePeriodLink> lqw = buildQueryWrapper(bo);
Page<EmsRateTimePeriodLinkVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
return TableDataInfo.build(result);
}
@Override
public List<EmsRateTimePeriodLinkVo> queryList(EmsRateTimePeriodLinkBo bo) {
LambdaQueryWrapper<EmsRateTimePeriodLink> lqw = buildQueryWrapper(bo);
return baseMapper.selectVoList(lqw);
}
@Override
public List<EmsRateTimePeriodLinkVo> queryByRateId(Long energyRateId) {
return baseMapper.selectByRateId(energyRateId);
}
private LambdaQueryWrapper<EmsRateTimePeriodLink> buildQueryWrapper(EmsRateTimePeriodLinkBo bo) {
LambdaQueryWrapper<EmsRateTimePeriodLink> lqw = Wrappers.lambdaQuery();
lqw.eq(bo.getEnergyRateId() != null, EmsRateTimePeriodLink::getEnergyRateId, bo.getEnergyRateId());
lqw.eq(bo.getPeriodId() != null, EmsRateTimePeriodLink::getPeriodId, bo.getPeriodId());
return lqw;
}
@Override
public Boolean insertByBo(EmsRateTimePeriodLinkBo bo) {
EmsRateTimePeriodLink add = BeanUtil.toBean(bo, EmsRateTimePeriodLink.class);
validEntityBeforeSave(add);
boolean flag = baseMapper.insert(add) > 0;
if (flag) {
bo.setLinkId(add.getLinkId());
}
return flag;
}
@Override
public Boolean updateByBo(EmsRateTimePeriodLinkBo bo) {
EmsRateTimePeriodLink update = BeanUtil.toBean(bo, EmsRateTimePeriodLink.class);
validEntityBeforeSave(update);
return baseMapper.updateById(update) > 0;
}
private void validEntityBeforeSave(EmsRateTimePeriodLink entity) {
// TODO 做一些数据校验
}
@Override
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if (isValid) {
// TODO 做一些业务上的校验
}
return baseMapper.deleteBatchIds(ids) > 0;
}
@Override
public Boolean deleteByRateId(Long energyRateId) {
LambdaQueryWrapper<EmsRateTimePeriodLink> lqw = Wrappers.lambdaQuery();
lqw.eq(EmsRateTimePeriodLink::getEnergyRateId, energyRateId);
return baseMapper.delete(lqw) > 0;
}
}

View File

@@ -0,0 +1,88 @@
package com.klp.ems.service.impl;
import cn.hutool.core.bean.BeanUtil;
import com.klp.common.core.page.TableDataInfo;
import com.klp.common.core.domain.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import com.klp.ems.domain.bo.EmsTimePeriodBo;
import com.klp.ems.domain.vo.EmsTimePeriodVo;
import com.klp.ems.domain.EmsTimePeriod;
import com.klp.ems.mapper.EmsTimePeriodMapper;
import com.klp.ems.service.IEmsTimePeriodService;
import java.util.Collection;
import java.util.List;
import java.util.Map;
/**
* 时间段Service业务层处理
*
* @author Joshi
* @date 2025-12-05
*/
@RequiredArgsConstructor
@Service
public class EmsTimePeriodServiceImpl implements IEmsTimePeriodService {
private final EmsTimePeriodMapper baseMapper;
@Override
public EmsTimePeriodVo queryById(Long periodId) {
return baseMapper.selectVoById(periodId);
}
@Override
public TableDataInfo<EmsTimePeriodVo> queryPageList(EmsTimePeriodBo bo, PageQuery pageQuery) {
LambdaQueryWrapper<EmsTimePeriod> lqw = buildQueryWrapper(bo);
Page<EmsTimePeriodVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
return TableDataInfo.build(result);
}
@Override
public List<EmsTimePeriodVo> queryList(EmsTimePeriodBo bo) {
LambdaQueryWrapper<EmsTimePeriod> lqw = buildQueryWrapper(bo);
return baseMapper.selectVoList(lqw);
}
private LambdaQueryWrapper<EmsTimePeriod> buildQueryWrapper(EmsTimePeriodBo bo) {
LambdaQueryWrapper<EmsTimePeriod> lqw = Wrappers.lambdaQuery();
lqw.eq(bo.getPeriodId() != null, EmsTimePeriod::getPeriodId, bo.getPeriodId());
lqw.like(bo.getPeriodName() != null, EmsTimePeriod::getPeriodName, bo.getPeriodName());
lqw.eq(bo.getPeriodType() != null, EmsTimePeriod::getPeriodType, bo.getPeriodType());
return lqw;
}
@Override
public Boolean insertByBo(EmsTimePeriodBo bo) {
EmsTimePeriod add = BeanUtil.toBean(bo, EmsTimePeriod.class);
validEntityBeforeSave(add);
boolean flag = baseMapper.insert(add) > 0;
if (flag) {
bo.setPeriodId(add.getPeriodId());
}
return flag;
}
@Override
public Boolean updateByBo(EmsTimePeriodBo bo) {
EmsTimePeriod update = BeanUtil.toBean(bo, EmsTimePeriod.class);
validEntityBeforeSave(update);
return baseMapper.updateById(update) > 0;
}
private void validEntityBeforeSave(EmsTimePeriod entity) {
// TODO 做一些数据校验
}
@Override
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if (isValid) {
// TODO 做一些业务上的校验
}
return baseMapper.deleteBatchIds(ids) > 0;
}
}

View File

@@ -0,0 +1,55 @@
package com.klp.ems.service.impl;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.klp.common.core.domain.PageQuery;
import com.klp.common.core.page.TableDataInfo;
import com.klp.ems.domain.bo.EnergyCostReportBo;
import com.klp.ems.domain.vo.EnergyCostSummaryVo;
import com.klp.ems.domain.vo.WmsEnergyCoilDailyVo;
import com.klp.ems.mapper.WmsEnergyCoilDailyMapper;
import com.klp.ems.service.IEnergyCostReportService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
/**
* 能源成本报表 Service 实现
*/
@Service
@RequiredArgsConstructor
public class EnergyCostReportServiceImpl implements IEnergyCostReportService {
private final WmsEnergyCoilDailyMapper coilDailyMapper;
@Override
public Map<String, Object> overview(EnergyCostReportBo bo) {
return coilDailyMapper.selectEnergyOverview(bo);
}
@Override
public List<EnergyCostSummaryVo> summary(EnergyCostReportBo bo) {
String group = bo.getGroupBy();
Function<EnergyCostReportBo, List<EnergyCostSummaryVo>> function;
if ("warehouse".equalsIgnoreCase(group)) {
function = coilDailyMapper::summaryByWarehouse;
} else if ("meter".equalsIgnoreCase(group)) {
function = coilDailyMapper::summaryByMeter;
} else if ("task".equalsIgnoreCase(group)) {
function = coilDailyMapper::summaryByTask;
} else {
function = coilDailyMapper::summaryByEnergyType;
}
List<EnergyCostSummaryVo> list = function.apply(bo);
return list == null ? Collections.emptyList() : list;
}
@Override
public TableDataInfo<WmsEnergyCoilDailyVo> detail(EnergyCostReportBo bo, PageQuery pageQuery) {
Page<WmsEnergyCoilDailyVo> page = coilDailyMapper.selectReportDetail(pageQuery.build(), bo);
return TableDataInfo.build(page);
}
}

View File

@@ -0,0 +1,126 @@
package com.klp.ems.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.klp.common.core.domain.PageQuery;
import com.klp.common.core.page.TableDataInfo;
import com.klp.common.utils.StringUtils;
import com.klp.ems.domain.*;
import com.klp.ems.domain.bo.WmsEnergyCoilDailyBo;
import com.klp.ems.domain.vo.WmsEnergyCoilDailyStatisticsVo;
import com.klp.ems.domain.vo.WmsEnergyCoilDailyVo;
import com.klp.ems.mapper.*;
import com.klp.ems.service.IWmsEnergyCoilDailyService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.*;
/**
* 钢卷日能源成本分摊结果 Service 实现
*/
@Slf4j
@RequiredArgsConstructor
@Service
public class WmsEnergyCoilDailyServiceImpl implements IWmsEnergyCoilDailyService {
private final WmsEnergyCoilDailyMapper baseMapper;
@Override
public WmsEnergyCoilDailyVo queryById(Long energyCostId) {
return baseMapper.selectVoById(energyCostId);
}
@Override
public TableDataInfo<WmsEnergyCoilDailyVo> queryPageList(WmsEnergyCoilDailyBo bo, PageQuery pageQuery) {
LambdaQueryWrapper<WmsEnergyCoilDaily> lqw = buildQueryWrapper(bo);
Page<WmsEnergyCoilDailyVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
return TableDataInfo.build(result);
}
@Override
public List<WmsEnergyCoilDailyVo> queryList(WmsEnergyCoilDailyBo bo) {
return baseMapper.selectVoList(buildQueryWrapper(bo));
}
@Override
public TableDataInfo<WmsEnergyCoilDailyVo> queryPendingActionCoilCost(WmsEnergyCoilDailyBo bo, PageQuery pageQuery) {
// 使用SQL一次性查询待操作钢卷的能源成本
// 所有的关联、聚合、计算都在SQL中完成性能更高
List<WmsEnergyCoilDailyVo> resultList = baseMapper.selectPendingActionCoilCost();
if (CollUtil.isEmpty(resultList)) {
log.warn("[PendingActionCoilCost] No pending action coils found");
return TableDataInfo.build(new Page<>());
}
// 分页处理
int pageNum = pageQuery.getPageNum();
int pageSize = pageQuery.getPageSize();
int start = (pageNum - 1) * pageSize;
int end = Math.min(start + pageSize, resultList.size());
List<WmsEnergyCoilDailyVo> pageData = resultList.subList(start, end);
Page<WmsEnergyCoilDailyVo> resultPage = new Page<>(pageNum, pageSize);
resultPage.setRecords(pageData);
resultPage.setTotal(resultList.size());
return TableDataInfo.build(resultPage);
}
@Override
public WmsEnergyCoilDailyStatisticsVo queryPendingActionCoilCostStatistics(String enterCoilNo, String currentCoilNo, Long warehouseId) {
return baseMapper.selectPendingActionCoilCostStatistics(enterCoilNo, currentCoilNo, warehouseId);
}
@Override
public Boolean insertByBo(WmsEnergyCoilDailyBo bo) {
WmsEnergyCoilDaily add = BeanUtil.toBean(bo, WmsEnergyCoilDaily.class);
validEntityBeforeSave(add);
boolean flag = baseMapper.insert(add) > 0;
if (flag) {
bo.setEnergyCostId(add.getEnergyCostId());
}
return flag;
}
@Override
public Boolean updateByBo(WmsEnergyCoilDailyBo bo) {
WmsEnergyCoilDaily update = BeanUtil.toBean(bo, WmsEnergyCoilDaily.class);
validEntityBeforeSave(update);
return baseMapper.updateById(update) > 0;
}
@Override
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if (isValid) {
// TODO 判断是否允许删除(例如已用于成本对账)
}
return baseMapper.deleteBatchIds(ids) > 0;
}
private LambdaQueryWrapper<WmsEnergyCoilDaily> buildQueryWrapper(WmsEnergyCoilDailyBo bo) {
LambdaQueryWrapper<WmsEnergyCoilDaily> lqw = Wrappers.lambdaQuery();
lqw.eq(bo.getTaskId() != null, WmsEnergyCoilDaily::getTaskId, bo.getTaskId());
lqw.eq(bo.getCalcDate() != null, WmsEnergyCoilDaily::getCalcDate, bo.getCalcDate());
lqw.eq(bo.getCoilId() != null, WmsEnergyCoilDaily::getCoilId, bo.getCoilId());
lqw.eq(bo.getWarehouseId() != null, WmsEnergyCoilDaily::getWarehouseId, bo.getWarehouseId());
lqw.eq(bo.getActualWarehouseId() != null, WmsEnergyCoilDaily::getActualWarehouseId, bo.getActualWarehouseId());
lqw.eq(bo.getEnergyTypeId() != null, WmsEnergyCoilDaily::getEnergyTypeId, bo.getEnergyTypeId());
lqw.eq(bo.getMeterId() != null, WmsEnergyCoilDaily::getMeterId, bo.getMeterId());
lqw.ge(bo.getStartDate() != null, WmsEnergyCoilDaily::getCalcDate, bo.getStartDate());
lqw.le(bo.getEndDate() != null, WmsEnergyCoilDaily::getCalcDate, bo.getEndDate());
lqw.like(StringUtils.isNotBlank(bo.getEnterCoilNo()), WmsEnergyCoilDaily::getEnterCoilNo, bo.getEnterCoilNo());
lqw.like(StringUtils.isNotBlank(bo.getCurrentCoilNo()), WmsEnergyCoilDaily::getCurrentCoilNo, bo.getCurrentCoilNo());
return lqw;
}
private void validEntityBeforeSave(WmsEnergyCoilDaily entity) {
// TODO 数据校验(如同一 taskId + coilId 不重复)
}
}

View File

@@ -0,0 +1,13 @@
<?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.klp.ems.mapper.CostCoilDailyMapper">
<update id="updateEnergyCost" parameterType="com.klp.ems.domain.CostCoilDailyEnergy">
UPDATE wms_cost_coil_daily
SET energy_cost_amount = #{energyCostAmount},
energy_cost_breakdown = #{energyCostBreakdown}
WHERE coil_id = #{coilId}
AND calc_date = #{calcDate}
</update>
</mapper>

View File

@@ -101,4 +101,66 @@
</if>
</select>
<select id="selectLatestBefore" resultMap="EmsEnergyConsumptionResult">
SELECT *
FROM ems_energy_consumption
WHERE meter_id = #{meterId}
AND end_time &lt;= #{endTime}
ORDER BY end_time DESC
LIMIT 1
</select>
<select id="selectOverlapRange" resultMap="EmsEnergyConsumptionResult">
SELECT *
FROM ems_energy_consumption
WHERE meter_id = #{meterId}
AND end_time &gt;= #{startTime}
AND start_time &lt;= #{endTime}
ORDER BY start_time ASC
</select>
<select id="selectCoveringRange" resultMap="EmsEnergyConsumptionResult">
SELECT *
FROM ems_energy_consumption
WHERE meter_id = #{meterId}
AND start_time &lt;= #{startTime}
AND end_time &gt;= #{endTime}
ORDER BY start_time ASC
LIMIT 1
</select>
<select id="selectLatestTwoReadings" resultMap="EmsEnergyConsumptionResult">
SELECT *
FROM ems_energy_consumption
WHERE meter_id = #{meterId}
ORDER BY end_time DESC
LIMIT 2
</select>
<!-- 统计查询 -->
<select id="getStatistics" parameterType="com.klp.ems.domain.bo.EmsEnergyConsumptionBo" resultType="java.util.Map">
SELECT
COUNT(*) AS totalCount,
IFNULL(SUM(consumption), 0) AS totalConsumption,
IFNULL(AVG(consumption), 0) AS avgConsumption,
IFNULL(MAX(consumption), 0) AS maxConsumption,
IFNULL(MIN(consumption), 0) AS minConsumption
FROM ems_energy_consumption
WHERE 1=1
<if test="meterId != null">
AND meter_id = #{meterId}
</if>
<if test="energyTypeId != null">
AND meter_id IN (
SELECT meter_id FROM ems_meter WHERE energy_type_id = #{energyTypeId}
)
</if>
<if test="startTime != null">
AND start_time &gt;= #{startTime}
</if>
<if test="endTime != null">
AND end_time &lt;= #{endTime}
</if>
</select>
</mapper>

View File

@@ -11,6 +11,8 @@
<result property="currency" column="currency"/>
<result property="effectiveDate" column="effective_date"/>
<result property="expiryDate" column="expiry_date"/>
<result property="usePeakValley" column="use_peak_valley"/>
<result property="useTieredPricing" column="use_tiered_pricing"/>
<result property="createBy" column="create_by"/>
<result property="updateBy" column="update_by"/>
<result property="createTime" column="create_time"/>
@@ -19,5 +21,69 @@
<result property="remark" column="remark"/>
</resultMap>
<resultMap type="com.klp.ems.domain.vo.EmsEnergyRateVo" id="EmsEnergyRateVoResult">
<result property="energyRateId" column="energy_rate_id"/>
<result property="energyTypeId" column="energy_type_id"/>
<result property="rate" column="rate"/>
<result property="currency" column="currency"/>
<result property="effectiveDate" column="effective_date"/>
<result property="expiryDate" column="expiry_date"/>
<result property="usePeakValley" column="use_peak_valley"/>
<result property="useTieredPricing" column="use_tiered_pricing"/>
<result property="createBy" column="create_by"/>
<result property="updateBy" column="update_by"/>
<result property="createTime" column="create_time"/>
<result property="updateTime" column="update_time"/>
<result property="delFlag" column="del_flag"/>
<result property="remark" column="remark"/>
</resultMap>
<select id="selectEffectiveRate" parameterType="map" resultMap="EmsEnergyRateResult">
SELECT *
FROM ems_energy_rate
WHERE energy_type_id = #{energyTypeId}
AND del_flag = '0'
AND effective_date &lt;= #{calcDate}
AND (expiry_date IS NULL OR expiry_date &gt;= #{calcDate})
ORDER BY effective_date DESC
LIMIT 1
</select>
<!-- 查询费率列表(包含梯度和时段信息) -->
<select id="selectVoList" resultMap="EmsEnergyRateVoResult">
SELECT DISTINCT
er.energy_rate_id,
er.energy_type_id,
er.rate,
er.currency,
er.effective_date,
er.expiry_date,
er.use_peak_valley,
er.use_tiered_pricing,
er.create_by,
er.update_by,
er.create_time,
er.update_time,
er.del_flag,
er.remark
FROM ems_energy_rate er
WHERE er.del_flag = '0'
<if test="energyTypeId != null">
AND er.energy_type_id = #{energyTypeId}
</if>
<if test="rate != null">
AND er.rate = #{rate}
</if>
<if test="currency != null">
AND er.currency = #{currency}
</if>
<if test="effectiveDate != null">
AND er.effective_date = #{effectiveDate}
</if>
<if test="expiryDate != null">
AND er.expiry_date = #{expiryDate}
</if>
ORDER BY er.create_time DESC
</select>
</mapper>

View File

@@ -23,6 +23,56 @@
<result property="remark" column="remark"/>
</resultMap>
<resultMap type="com.klp.ems.domain.vo.EmsMeterVo" id="EmsMeterVoResult">
<result property="meterId" column="meter_id"/>
<result property="meterCode" column="meter_code"/>
<result property="energyTypeId" column="energy_type_id"/>
<result property="locationId" column="location_id"/>
<result property="model" column="model"/>
<result property="manufacturer" column="manufacturer"/>
<result property="installDate" column="install_date"/>
<result property="status" column="status"/>
<result property="lastCalibrationDate" column="last_calibration_date"/>
<result property="thresholdValue" column="threshold_value"/>
<result property="remark" column="remark"/>
<result property="warehouseId" column="warehouse_id"/>
<result property="warehouseName" column="warehouse_name"/>
</resultMap>
<!-- 查询设备列表,包含库区信息 -->
<select id="selectVoList" resultMap="EmsMeterVoResult">
SELECT
m.meter_id,
m.meter_code,
m.energy_type_id,
m.location_id,
m.model,
m.manufacturer,
m.install_date,
m.status,
m.last_calibration_date,
m.threshold_value,
m.remark,
COALESCE(w.warehouse_id, 0) as warehouse_id,
COALESCE(w.warehouse_name, '') as warehouse_name
FROM ems_meter m
LEFT JOIN wms_energy_area_link l ON m.meter_id = l.meter_id AND l.is_enabled = 1
LEFT JOIN wms_warehouse w ON l.warehouse_id = w.warehouse_id
WHERE m.del_flag = '0'
<if test="meterId != null">
AND m.meter_id = #{meterId}
</if>
<if test="meterCode != null and meterCode != ''">
AND m.meter_code LIKE CONCAT('%', #{meterCode}, '%')
</if>
<if test="energyTypeId != null">
AND m.energy_type_id = #{energyTypeId}
</if>
<if test="status != null">
AND m.status = #{status}
</if>
</select>
<select id="selectMeterIds" parameterType="com.klp.ems.domain.bo.MeterFilterBo" resultType="java.lang.Long">
SELECT meter_id
FROM ems_meter

View File

@@ -0,0 +1,41 @@
<?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.klp.ems.mapper.EmsRateTierMapper">
<resultMap type="com.klp.ems.domain.EmsRateTier" id="EmsRateTierResult">
<result property="tierId" column="tier_id"/>
<result property="energyRateId" column="energy_rate_id"/>
<result property="tierLevel" column="tier_level"/>
<result property="minUsage" column="min_usage"/>
<result property="maxUsage" column="max_usage"/>
<result property="rate" column="rate"/>
<result property="delFlag" column="del_flag"/>
<result property="remark" column="remark"/>
</resultMap>
<resultMap type="com.klp.ems.domain.vo.EmsRateTierVo" id="EmsRateTierVoResult">
<result property="tierId" column="tier_id"/>
<result property="energyRateId" column="energy_rate_id"/>
<result property="tierLevel" column="tier_level"/>
<result property="minUsage" column="min_usage"/>
<result property="maxUsage" column="max_usage"/>
<result property="rate" column="rate"/>
<result property="remark" column="remark"/>
</resultMap>
<select id="selectByRateId" parameterType="java.lang.Long" resultMap="EmsRateTierVoResult">
SELECT * FROM ems_rate_tier
WHERE energy_rate_id = #{energyRateId}
AND del_flag = '0'
ORDER BY tier_level ASC
</select>
<!-- 物理删除指定费率的所有梯度 -->
<delete id="deleteByRateIdPhysical" parameterType="java.lang.Long">
DELETE FROM ems_rate_tier
WHERE energy_rate_id = #{energyRateId}
</delete>
</mapper>

View File

@@ -0,0 +1,105 @@
<?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.klp.ems.mapper.EmsRateTierPeriodLinkMapper">
<resultMap type="com.klp.ems.domain.EmsRateTierPeriodLink" id="EmsRateTierPeriodLinkResult">
<result property="linkId" column="link_id"/>
<result property="tierId" column="tier_id"/>
<result property="periodId" column="period_id"/>
<result property="rate" column="rate"/>
<result property="createBy" column="create_by"/>
<result property="updateBy" column="update_by"/>
<result property="createTime" column="create_time"/>
<result property="updateTime" column="update_time"/>
<result property="delFlag" column="del_flag"/>
<result property="remark" column="remark"/>
</resultMap>
<resultMap type="com.klp.ems.domain.vo.EmsRateTierPeriodLinkVo" id="EmsRateTierPeriodLinkVoResult">
<result property="linkId" column="link_id"/>
<result property="tierId" column="tier_id"/>
<result property="tierLevel" column="tier_level"/>
<result property="minUsage" column="min_usage"/>
<result property="maxUsage" column="max_usage"/>
<result property="periodId" column="period_id"/>
<result property="periodName" column="period_name"/>
<result property="periodType" column="period_type"/>
<result property="startTime" column="start_time"/>
<result property="endTime" column="end_time"/>
<result property="rate" column="rate"/>
<result property="createTime" column="create_time"/>
<result property="remark" column="remark"/>
</resultMap>
<!-- 根据梯度ID查询所有关联的时段费率 -->
<select id="selectByTierId" parameterType="long" resultMap="EmsRateTierPeriodLinkResult">
SELECT *
FROM ems_tier_period_link
WHERE tier_id = #{tierId}
AND del_flag = '0'
ORDER BY period_id
</select>
<!-- 根据梯度ID删除所有关联的时段费率逻辑删除 -->
<delete id="deleteByTierId" parameterType="long">
UPDATE ems_tier_period_link
SET del_flag = '2'
WHERE tier_id = #{tierId}
</delete>
<!-- 根据梯度ID物理删除所有关联的时段费率 -->
<delete id="deleteByTierIdPhysical" parameterType="long">
DELETE FROM ems_tier_period_link
WHERE tier_id = #{tierId}
</delete>
<!-- 根据费率ID删除所有关联的梯度-时段费率(逻辑删除) -->
<delete id="deleteByEnergyRateId" parameterType="long">
UPDATE ems_tier_period_link tpl
SET tpl.del_flag = '2'
WHERE tpl.tier_id IN (
SELECT tier_id
FROM ems_rate_tier
WHERE energy_rate_id = #{energyRateId}
)
</delete>
<!-- 根据费率ID物理删除所有关联的梯度-时段费率 -->
<delete id="deleteByEnergyRateIdPhysical" parameterType="long">
DELETE FROM ems_tier_period_link
WHERE tier_id IN (
SELECT tier_id
FROM ems_rate_tier
WHERE energy_rate_id = #{energyRateId}
)
</delete>
<!-- 查询梯度-时段关联的完整信息 -->
<select id="selectVoByEnergyRateId" parameterType="long" resultMap="EmsRateTierPeriodLinkVoResult">
SELECT
tpl.link_id,
tpl.tier_id,
rt.tier_level,
rt.min_usage,
rt.max_usage,
tpl.period_id,
tp.period_name,
tp.period_type,
tp.start_time,
tp.end_time,
tpl.rate,
tpl.create_time,
tpl.remark
FROM ems_tier_period_link tpl
JOIN ems_rate_tier rt ON tpl.tier_id = rt.tier_id
JOIN ems_time_period tp ON tpl.period_id = tp.period_id
WHERE rt.energy_rate_id = #{energyRateId}
AND tpl.del_flag = '0'
AND rt.del_flag = '0'
AND tp.del_flag = '0'
ORDER BY rt.tier_level, tp.period_type
</select>
</mapper>

View File

@@ -0,0 +1,46 @@
<?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.klp.ems.mapper.EmsRateTimePeriodLinkMapper">
<resultMap type="com.klp.ems.domain.EmsRateTimePeriodLink" id="EmsRateTimePeriodLinkResult">
<result property="linkId" column="link_id"/>
<result property="energyRateId" column="energy_rate_id"/>
<result property="periodId" column="period_id"/>
<result property="rate" column="rate"/>
<result property="delFlag" column="del_flag"/>
<result property="remark" column="remark"/>
</resultMap>
<resultMap type="com.klp.ems.domain.vo.EmsRateTimePeriodLinkVo" id="EmsRateTimePeriodLinkVoResult">
<result property="linkId" column="link_id"/>
<result property="energyRateId" column="energy_rate_id"/>
<result property="periodId" column="period_id"/>
<result property="periodName" column="period_name"/>
<result property="periodType" column="period_type"/>
<result property="startTime" column="start_time"/>
<result property="endTime" column="end_time"/>
<result property="rate" column="rate"/>
<result property="remark" column="remark"/>
</resultMap>
<select id="selectByRateId" parameterType="java.lang.Long" resultMap="EmsRateTimePeriodLinkVoResult">
SELECT
l.link_id,
l.energy_rate_id,
l.period_id,
p.period_name,
p.period_type,
p.start_time,
p.end_time,
l.rate,
l.remark
FROM ems_rate_time_period_link l
LEFT JOIN ems_time_period p ON l.period_id = p.period_id
WHERE l.energy_rate_id = #{energyRateId}
AND l.del_flag = '0'
ORDER BY p.period_type ASC
</select>
</mapper>

View File

@@ -0,0 +1,18 @@
<?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.klp.ems.mapper.EmsTimePeriodMapper">
<resultMap type="com.klp.ems.domain.EmsTimePeriod" id="EmsTimePeriodResult">
<result property="periodId" column="period_id"/>
<result property="periodName" column="period_name"/>
<result property="periodType" column="period_type"/>
<result property="startTime" column="start_time"/>
<result property="endTime" column="end_time"/>
<result property="crossDay" column="cross_day"/>
<result property="delFlag" column="del_flag"/>
<result property="remark" column="remark"/>
</resultMap>
</mapper>

View File

@@ -0,0 +1,244 @@
<?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.klp.ems.mapper.WmsEnergyCoilDailyMapper">
<resultMap id="WmsEnergyCoilDailyResult" type="com.klp.ems.domain.WmsEnergyCoilDaily">
<result property="energyCostId" column="energy_cost_id"/>
<result property="taskId" column="task_id"/>
<result property="calcDate" column="calc_date"/>
<result property="coilId" column="coil_id"/>
<result property="enterCoilNo" column="enter_coil_no"/>
<result property="currentCoilNo" column="current_coil_no"/>
<result property="warehouseId" column="warehouse_id"/>
<result property="actualWarehouseId" column="actual_warehouse_id"/>
<result property="energyTypeId" column="energy_type_id"/>
<result property="meterId" column="meter_id"/>
<result property="consumptionQty" column="consumption_qty"/>
<result property="costAmount" column="cost_amount"/>
<result property="allocationBasisWeight" column="allocation_basis_weight"/>
<result property="allocationBasisDays" column="allocation_basis_days"/>
<result property="allocationFactor" column="allocation_factor"/>
<result property="remark" column="remark"/>
<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>
<delete id="deleteByTaskId" parameterType="long">
DELETE FROM wms_energy_coil_daily WHERE task_id = #{taskId}
</delete>
<select id="selectListByTask" resultMap="WmsEnergyCoilDailyResult" parameterType="long">
SELECT * FROM wms_energy_coil_daily WHERE task_id = #{taskId}
</select>
<sql id="ReportWhere">
<where>
<if test="bo != null and bo.taskId != null">
AND c.task_id = #{bo.taskId}
</if>
<if test="bo != null and bo.energyTypeId != null">
AND c.energy_type_id = #{bo.energyTypeId}
</if>
<if test="bo != null and bo.meterId != null">
AND c.meter_id = #{bo.meterId}
</if>
<if test="bo != null and bo.warehouseId != null">
AND c.warehouse_id = #{bo.warehouseId}
</if>
<if test="bo != null and bo.actualWarehouseId != null">
AND c.actual_warehouse_id = #{bo.actualWarehouseId}
</if>
<if test="bo != null and bo.startDate != null">
AND c.calc_date <![CDATA[>=]]> #{bo.startDate}
</if>
<if test="bo != null and bo.endDate != null">
AND c.calc_date <![CDATA[<=]]> #{bo.endDate}
</if>
<if test="bo != null and bo.enterCoilNo != null and bo.enterCoilNo != ''">
AND c.enter_coil_no LIKE CONCAT('%', #{bo.enterCoilNo}, '%')
</if>
<if test="bo != null and bo.currentCoilNo != null and bo.currentCoilNo != ''">
AND c.current_coil_no LIKE CONCAT('%', #{bo.currentCoilNo}, '%')
</if>
</where>
</sql>
<select id="summaryByEnergyType" parameterType="com.klp.ems.domain.bo.EnergyCostReportBo"
resultType="com.klp.ems.domain.vo.EnergyCostSummaryVo">
SELECT
CAST(c.energy_type_id AS CHAR) AS groupKey,
COALESCE(et.name, CONCAT('能源-', c.energy_type_id)) AS groupName,
c.energy_type_id,
SUM(c.consumption_qty) AS totalConsumption,
SUM(c.cost_amount) AS totalCost,
COUNT(DISTINCT c.coil_id) AS coilCount
FROM wms_energy_coil_daily c
LEFT JOIN ems_energy_type et ON c.energy_type_id = et.energy_type_id
<include refid="ReportWhere"/>
GROUP BY c.energy_type_id
ORDER BY totalCost DESC
</select>
<select id="summaryByWarehouse" parameterType="com.klp.ems.domain.bo.EnergyCostReportBo"
resultType="com.klp.ems.domain.vo.EnergyCostSummaryVo">
SELECT
CAST(c.warehouse_id AS CHAR) AS groupKey,
COALESCE(wh.warehouse_name, CONCAT('库区-', c.warehouse_id)) AS groupName,
c.warehouse_id,
c.actual_warehouse_id,
SUM(c.consumption_qty) AS totalConsumption,
SUM(c.cost_amount) AS totalCost,
COUNT(DISTINCT c.coil_id) AS coilCount
FROM wms_energy_coil_daily c
LEFT JOIN wms_warehouse wh ON c.warehouse_id = wh.warehouse_id
<include refid="ReportWhere"/>
GROUP BY c.warehouse_id, c.actual_warehouse_id
ORDER BY totalCost DESC
</select>
<select id="summaryByMeter" parameterType="com.klp.ems.domain.bo.EnergyCostReportBo"
resultType="com.klp.ems.domain.vo.EnergyCostSummaryVo">
SELECT
CAST(c.meter_id AS CHAR) AS groupKey,
COALESCE(m.meter_code, CONCAT('计量表-', c.meter_id)) AS groupName,
c.meter_id,
c.energy_type_id,
SUM(c.consumption_qty) AS totalConsumption,
SUM(c.cost_amount) AS totalCost,
COUNT(DISTINCT c.coil_id) AS coilCount
FROM wms_energy_coil_daily c
LEFT JOIN ems_meter m ON c.meter_id = m.meter_id
<include refid="ReportWhere"/>
GROUP BY c.meter_id, c.energy_type_id
ORDER BY totalCost DESC
</select>
<select id="summaryByTask" parameterType="com.klp.ems.domain.bo.EnergyCostReportBo"
resultType="com.klp.ems.domain.vo.EnergyCostSummaryVo">
SELECT
CAST(c.task_id AS CHAR) AS groupKey,
CONCAT('任务-', c.task_id) AS groupName,
c.task_id,
c.energy_type_id,
SUM(c.consumption_qty) AS totalConsumption,
SUM(c.cost_amount) AS totalCost,
COUNT(DISTINCT c.coil_id) AS coilCount
FROM wms_energy_coil_daily c
<include refid="ReportWhere"/>
GROUP BY c.task_id, c.energy_type_id
ORDER BY c.task_id DESC
</select>
<select id="selectEnergyOverview" parameterType="com.klp.ems.domain.bo.EnergyCostReportBo"
resultType="java.util.Map">
SELECT
COUNT(DISTINCT c.coil_id) AS coilCount,
SUM(c.consumption_qty) AS totalConsumption,
SUM(c.cost_amount) AS totalCost
FROM wms_energy_coil_daily c
<include refid="ReportWhere"/>
</select>
<!-- 查询待操作钢卷的能源成本(按钢卷维度聚合,综合所有能源类型) -->
<select id="selectPendingActionCoilCost" resultType="com.klp.ems.domain.vo.WmsEnergyCoilDailyVo">
SELECT
pa.coil_id AS coilId,
pa.current_coil_no AS currentCoilNo,
c.enter_coil_no AS enterCoilNo,
pa.warehouse_id AS warehouseId,
wh.warehouse_name AS warehouseName,
pa.create_time AS scanTime,
COALESCE(pa.complete_time, NOW()) AS completeTime,
TIMESTAMPDIFF(MINUTE, pa.create_time, COALESCE(pa.complete_time, NOW())) AS productionDuration,
SUM(COALESCE(ec.consumption, 0)) AS consumptionQty,
SUM(COALESCE(ec.consumption, 0) * COALESCE(er.rate, 0)) AS costAmount,
CAST(1.0 AS DECIMAL(10, 6)) AS allocationFactor
FROM wms_coil_pending_action pa
LEFT JOIN wms_material_coil c ON pa.coil_id = c.coil_id
LEFT JOIN wms_warehouse wh ON pa.warehouse_id = wh.warehouse_id
LEFT JOIN ems_energy_consumption ec ON ec.end_time BETWEEN pa.create_time AND COALESCE(pa.complete_time, NOW())
LEFT JOIN ems_meter m ON ec.meter_id = m.meter_id
LEFT JOIN ems_energy_type et ON m.energy_type_id = et.energy_type_id
LEFT JOIN ems_energy_rate er ON et.energy_type_id = er.energy_type_id
AND er.effective_date <![CDATA[<=]]> CURDATE()
AND (er.expiry_date IS NULL OR er.expiry_date <![CDATA[>=]]> CURDATE())
WHERE pa.action_status IN (0, 1, 2)
AND pa.warehouse_id IS NOT NULL
GROUP BY pa.coil_id, pa.current_coil_no, c.enter_coil_no, pa.warehouse_id, wh.warehouse_name, pa.create_time, pa.complete_time
ORDER BY pa.warehouse_id, pa.create_time DESC
</select>
<!-- 查询待操作钢卷的能源成本统计 -->
<select id="selectPendingActionCoilCostStatistics" resultType="com.klp.ems.domain.vo.WmsEnergyCoilDailyStatisticsVo">
SELECT
COUNT(DISTINCT t.coil_id) AS totalCoils,
SUM(t.total_consumption) AS totalConsumption,
SUM(t.total_cost) AS totalCost,
SUM(t.production_duration) AS totalProductionDuration,
CASE
WHEN SUM(t.production_duration) > 0
THEN SUM(t.total_cost) / (SUM(t.production_duration) / 60.0)
ELSE 0
END AS avgUnitCost
FROM (
SELECT
pa.coil_id,
pa.current_coil_no,
c.enter_coil_no,
pa.warehouse_id,
wh.warehouse_name,
pa.create_time,
COALESCE(pa.complete_time, NOW()) AS complete_time,
TIMESTAMPDIFF(MINUTE, pa.create_time, COALESCE(pa.complete_time, NOW())) AS production_duration,
SUM(COALESCE(ec.consumption, 0)) AS total_consumption,
SUM(COALESCE(ec.consumption, 0) * COALESCE(er.rate, 0)) AS total_cost
FROM wms_coil_pending_action pa
LEFT JOIN wms_material_coil c ON pa.coil_id = c.coil_id
LEFT JOIN wms_warehouse wh ON pa.warehouse_id = wh.warehouse_id
LEFT JOIN ems_energy_consumption ec ON ec.end_time BETWEEN pa.create_time AND COALESCE(pa.complete_time, NOW())
LEFT JOIN ems_meter m ON ec.meter_id = m.meter_id
LEFT JOIN ems_energy_type et ON m.energy_type_id = et.energy_type_id
LEFT JOIN ems_energy_rate er ON et.energy_type_id = er.energy_type_id
AND er.effective_date <![CDATA[<=]]> CURDATE()
AND (er.expiry_date IS NULL OR er.expiry_date <![CDATA[>=]]> CURDATE())
WHERE pa.action_status IN (0, 1, 2)
AND pa.warehouse_id IS NOT NULL
<if test="enterCoilNo != null and enterCoilNo != ''">
AND c.enter_coil_no LIKE CONCAT('%', #{enterCoilNo}, '%')
</if>
<if test="currentCoilNo != null and currentCoilNo != ''">
AND pa.current_coil_no LIKE CONCAT('%', #{currentCoilNo}, '%')
</if>
<if test="warehouseId != null">
AND pa.warehouse_id = #{warehouseId}
</if>
GROUP BY pa.coil_id, pa.current_coil_no, c.enter_coil_no, pa.warehouse_id, wh.warehouse_name, pa.create_time, pa.complete_time
) t
</select>
<select id="selectReportDetail" resultType="com.klp.ems.domain.vo.WmsEnergyCoilDailyVo">
SELECT
c.energy_cost_id AS energyCostId,
c.task_id AS taskId,
c.calc_date AS calcDate,
c.coil_id AS coilId,
c.enter_coil_no AS enterCoilNo,
c.current_coil_no AS currentCoilNo,
c.warehouse_id AS warehouseId,
c.actual_warehouse_id AS actualWarehouseId,
c.energy_type_id AS energyTypeId,
c.meter_id AS meterId,
c.consumption_qty AS consumptionQty,
c.cost_amount AS costAmount,
c.allocation_basis_weight AS allocationBasisWeight,
c.allocation_basis_days AS allocationBasisDays,
c.allocation_factor AS allocationFactor,
c.remark AS remark
FROM wms_energy_coil_daily c
<include refid="ReportWhere"/>
ORDER BY c.calc_date DESC, c.energy_cost_id DESC
</select>
</mapper>