letsgocoding
2025-02-14 9ecc36c0694f6f0495f51b1c32cb3d22c9371208
!77 !76 修改swagger信息
Merge pull request !77 from letsgocoding/develop1.0
已添加23个文件
已修改31个文件
5168 ■■■■■ 文件已修改
.gitignore 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zhitan-admin/src/main/java/com/zhitan/web/controller/comprehensivestatistics/ComprehensiveStatisticsController.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zhitan-admin/src/main/java/com/zhitan/web/controller/consumptionanalysis/ConsumptionAnalysisController.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zhitan-admin/src/main/java/com/zhitan/web/controller/energyMonitor/ElectricThreePhaseController.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zhitan-admin/src/main/java/com/zhitan/web/controller/history/HistoryDataTrendController.java 97 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zhitan-admin/src/main/java/com/zhitan/web/controller/meter/MeterController.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zhitan-admin/src/main/java/com/zhitan/web/controller/model/ModelInfoController.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zhitan-admin/src/main/java/com/zhitan/web/controller/saving/EnergySavingProgramController.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zhitan-admin/src/main/java/com/zhitan/web/controller/statisticalAnalysis/EnergyConsumeDataController.java 69 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zhitan-admin/src/main/java/com/zhitan/web/controller/statisticalAnalysis/EnergyDataItemController.java 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zhitan-admin/src/main/java/com/zhitan/web/controller/statisticalAnalysis/StatisticalAnalysisController.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zhitan-admin/src/main/java/com/zhitan/web/core/config/SwaggerConfig.java 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zhitan-common/src/main/java/com/zhitan/common/constant/CommonConst.java 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zhitan-common/src/main/java/com/zhitan/common/enums/RetrievalModes.java 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zhitan-common/src/main/java/com/zhitan/common/utils/ChartUtils.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zhitan-system/src/main/java/com/zhitan/dataitem/mapper/DataItemMapper.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zhitan-system/src/main/java/com/zhitan/energyMonitor/service/impl/ElectricThreePhaseServiceImpl.java 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zhitan-system/src/main/java/com/zhitan/model/service/impl/EnergyIndexServiceImpl.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zhitan-system/src/main/java/com/zhitan/peakvalley/mapper/PeakValleyMapper.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zhitan-system/src/main/java/com/zhitan/realtimedata/service/impl/RealtimeDatabaseServiceImpl.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zhitan-system/src/main/java/com/zhitan/statisticalAnalysis/common/DateTimeUtil.java 750 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zhitan-system/src/main/java/com/zhitan/statisticalAnalysis/domain/vo/CostTrendEnergyTypeItem.java 47 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zhitan-system/src/main/java/com/zhitan/statisticalAnalysis/domain/vo/EnergyConsumeTrendDetailItem.java 83 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zhitan-system/src/main/java/com/zhitan/statisticalAnalysis/domain/vo/EnergyConsumeVO.java 43 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zhitan-system/src/main/java/com/zhitan/statisticalAnalysis/domain/vo/EnergyCostTrendItem.java 51 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zhitan-system/src/main/java/com/zhitan/statisticalAnalysis/domain/vo/EnergyCostTrendPage.java 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zhitan-system/src/main/java/com/zhitan/statisticalAnalysis/domain/vo/EnergyTypeValueContrastedVO.java 62 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zhitan-system/src/main/java/com/zhitan/statisticalAnalysis/domain/vo/QueryCompareRequest.java 49 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zhitan-system/src/main/java/com/zhitan/statisticalAnalysis/service/IEnergyConsumeDataService.java 44 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zhitan-system/src/main/java/com/zhitan/statisticalAnalysis/service/impl/EnergyConsumeDataServiceImpl.java 498 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zhitan-system/src/main/resources/mapper/dataitem/DataItemMapper.xml 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zhitan-system/src/main/resources/mapper/peakvalley/ElectricityDataItemMapper.xml 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zhitan-vue/src/api/cost/api.js 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zhitan-vue/src/api/powerquality/electric-power-factor/api.js 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zhitan-vue/src/api/powerquality/electricThreePhase/api.js 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zhitan-vue/src/api/powerquality/load-analysis/api.js 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zhitan-vue/src/api/realTimeMonitor/historyDataTrend.js 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zhitan-vue/src/assets/styles/ruoyi.scss 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zhitan-vue/src/components/Echarts/LineChart.vue 182 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zhitan-vue/src/views/businessconfiguration/gatewayledger/gatewayLedger.vue 199 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zhitan-vue/src/views/comprehensive/comps/LineChart.vue 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zhitan-vue/src/views/comprehensive/monthlyComprehensive/index.vue 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zhitan-vue/src/views/comprehensive/yearComprehensive/index.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
zhitan-vue/src/views/costAnalysis/cost-trend-analysis.vue 316 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zhitan-vue/src/views/costAnalysis/energy-trend-analysis.vue 295 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zhitan-vue/src/views/dataMonitoring/historyDataTrend/index.vue 337 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zhitan-vue/src/views/energyefficiency/benchmarkmanage/benchmarkmanage.vue 198 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zhitan-vue/src/views/index.vue 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zhitan-vue/src/views/modelconfiguration/indexwarehouse/indexWarehouse.vue 161 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zhitan-vue/src/views/peakvalley/period/period.vue 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zhitan-vue/src/views/powerquality/load/index.vue 402 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zhitan-vue/src/views/powerquality/power/index.vue 331 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zhitan-vue/src/views/powerquality/threephase/index.vue 503 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zhitan-vue/src/views/realtimemonitor/realtimemonitor/realtimemonitor.vue 126 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.gitignore
@@ -10,6 +10,7 @@
######################################################################
# IDE
.DS_Store
### STS ###
.apt_generated
zhitan-admin/src/main/java/com/zhitan/web/controller/comprehensivestatistics/ComprehensiveStatisticsController.java
@@ -9,6 +9,7 @@
import com.zhitan.keyequipment.service.IDailyKeyEquipmentService;
import com.zhitan.model.domain.EnergyIndex;
import com.zhitan.model.service.IModelNodeService;
import io.swagger.annotations.Api;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
zhitan-admin/src/main/java/com/zhitan/web/controller/consumptionanalysis/ConsumptionAnalysisController.java
@@ -10,6 +10,7 @@
import com.zhitan.consumptionanalysis.domain.vo.RankingDataVO;
import com.zhitan.consumptionanalysis.domain.vo.RankingEnergyData;
import com.zhitan.consumptionanalysis.service.IConsumptionAnalysisService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
@@ -35,6 +36,7 @@
 * @Author: Zhujw
 * @Date: 2023/3/1
 */
@Api(tags = "综合能耗分析")
@RestController
@RequestMapping("/consumptionanalysis")
public class ConsumptionAnalysisController extends BaseController {
zhitan-admin/src/main/java/com/zhitan/web/controller/energyMonitor/ElectricThreePhaseController.java
@@ -56,6 +56,7 @@
        if (ObjectUtils.isEmpty(meterId)){
            return AjaxResult.error("电表id不能为空");
        }
        List<EnergyIndex> energyIndexList = energyIndexService.listDeviceIndex(nodeId, meterId);
        return AjaxResult.success(electricThreePhaseService.list(timeType, timeCode, energyIndexList, requestType, meterId));
zhitan-admin/src/main/java/com/zhitan/web/controller/history/HistoryDataTrendController.java
@@ -4,10 +4,15 @@
import com.zhitan.basicdata.domain.MeterImplement;
import com.zhitan.basicdata.services.IMeterImplementService;
import com.zhitan.common.annotation.Log;
import com.zhitan.common.constant.CommonConst;
import com.zhitan.common.constant.TimeTypeConst;
import com.zhitan.common.core.controller.BaseController;
import com.zhitan.common.core.domain.AjaxResult;
import com.zhitan.common.enums.BusinessType;
import com.zhitan.common.enums.RetrievalModes;
import com.zhitan.common.enums.TimeType;
import com.zhitan.common.utils.ChartUtils;
import com.zhitan.common.utils.DateTimeUtil;
import com.zhitan.common.utils.poi.ExcelUtil;
import com.zhitan.history.domain.dto.HistoricalDataDTO;
import com.zhitan.history.domain.vo.HistoricalDataExcel;
@@ -16,7 +21,9 @@
import com.zhitan.model.service.IEnergyIndexService;
import com.zhitan.realtimedata.domain.TagValue;
import com.zhitan.realtimedata.service.RealtimeDatabaseService;
import io.swagger.annotations.Api;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
@@ -29,11 +36,12 @@
import java.util.List;
/**
 * è®¾å¤‡å¯åœå®žæ—¶ç›‘测Controller
 * åŽ†å²æ•°æ®è¶‹åŠ¿Controller
 *
 * @author sys
 * @date 2020-03-30
 */
@Api(tags = "历史数据趋势")
@RestController
@RequestMapping("/dataMonitoring/historyDataTrend")
public class HistoryDataTrendController extends BaseController {
@@ -61,9 +69,6 @@
    public AjaxResult getSettingIndex(EnergyIndex energyIndex) {
        try {
            List<EnergyIndex> infoList = energyIndexService.selectEnergyIndexList(energyIndex);
//            List<String> codeList= infoList.stream().map(EnergyIndex::getCode).collect(Collectors.toList());
//            List<TagValue> valList = realtimeDatabaseService.retrieve(codeList);
//            List resultList = new ArrayList();
            return AjaxResult.success(infoList);
        } catch (Exception ex) {
            logger.error("获取关联采集指标出错!", ex);
@@ -80,68 +85,44 @@
            if (ObjectUtils.isEmpty(energyIndex)) {
                return AjaxResult.error("未找到点位信息");
            }
            Date beginTime = dto.getDataTime();
            Date endTime;
            // æŸ¥è¯¢æ¡æ•°
            int count = 1440;
            if ("DAY".equals(dto.getTimeType())) {
                endTime = DateUtil.endOfDay(beginTime);
            List<Date> dateList = new ArrayList<>();
            if (TimeType.DAY.name().equals(dto.getTimeType())) {
                String timeCode = DateTimeUtil.getDateTime(dto.getDataTime(), DateTimeUtil.COMMON_PATTERN_TO_DAY);
                ChartUtils.generateDateList(TimeTypeConst.TIME_TYPE_DAY, timeCode, dateList);
            } else if (TimeType.HOUR.name().equals(dto.getTimeType())) {
                String timeCode = DateTimeUtil.getDateTime(dto.getDataTime(), DateTimeUtil.COMMON_PATTERN_TO_HOUR);
                ChartUtils.generateDateList(TimeTypeConst.TIME_TYPE_HOUR, timeCode, dateList);
            } else {
                count = 3600;
                endTime = DateUtil.offsetSecond(DateUtil.offsetHour(beginTime, 1), -1);
                return AjaxResult.error("时间间隔类型不正确");
            }
            // æŸ¥è¯¢è®¡é‡å™¨å…·
            MeterImplement info = meterImplementService.selectMeterImplementById(energyIndex.getMeterId());
            List<TagValue> tagValueList = realtimeDatabaseService.retrieve(energyIndex.getCode(), beginTime, endTime,
                    RetrievalModes.BestFit, count);
            MeterImplement meterInfo = meterImplementService.selectMeterImplementById(energyIndex.getMeterId());
            if (ObjectUtils.isEmpty(meterInfo)) {
                return AjaxResult.error("未找到计量器具信息");
            }
            List<HistoricalDataVO> voList = new ArrayList<>();
            Date date = DateUtil.date();
            for (int i = 0; i < count + 1; i++) {
            for (Date date : dateList) {
                List<TagValue> tagValues = new ArrayList<>();
                if(TimeType.DAY.name().equals(dto.getTimeType())){
                    Date beginTime = date;
                    Date endTime = DateUtil.offsetHour(DateUtil.offsetMinute(date, CommonConst.DIGIT_MINUS_1), CommonConst.DIGIT_1);
                    tagValues = realtimeDatabaseService.retrieve(energyIndex.getCode(), beginTime,endTime,CommonConst.DIGIT_1);
                }
                if(TimeType.HOUR.name().equals(dto.getTimeType())){
                    Date beginTime = date;
                    Date endTime = DateUtil.offsetMinute(DateUtil.offsetSecond(date, CommonConst.DIGIT_MINUS_1), CommonConst.DIGIT_1);
                    tagValues = realtimeDatabaseService.retrieve(energyIndex.getCode(), beginTime,endTime,CommonConst.DIGIT_1);
                }
                HistoricalDataVO vo = new HistoricalDataVO();
                vo.setDataTime(DateUtil.formatDateTime(date));
                vo.setIndexId(energyIndex.getIndexId());
                String indexName = energyIndex.getName();
                if (ObjectUtils.isNotEmpty(info)) {
                    indexName = info.getInstallactionLocation() + "_" + info.getMeterName() + "_" + indexName;
                vo.setIndexName(meterInfo.getInstallactionLocation() + "_" + meterInfo.getMeterName() + "_" + energyIndex.getName());
                vo.setValue(CommonConst.DOUBLE_MINUS_SIGN);
                if(ObjectUtils.isNotEmpty(tagValues)){
                    vo.setValue(tagValues.get(0).getValue().toString());
                }
                vo.setIndexName(indexName);
                // å–值
                String value = "--";
                String usedValue = "--";
                if (beginTime.getTime() <= date.getTime()) {
                    try {
                        TagValue tagValue = tagValueList.get(i);
                        BigDecimal cumulative = BigDecimal.valueOf(tagValue.getValue());
                        if ("SWWSDJ_SD".equals(energyIndex.getCode()) || "SWWSDJ_WD".equals(energyIndex.getCode())) {
                            cumulative = cumulative.multiply(BigDecimal.valueOf(0.1));
                        }
                        if (i > 0) {
                            TagValue previousTagValue = tagValueList.get(i - 1);
                            BigDecimal previousValue = BigDecimal.ZERO;
                            if (ObjectUtils.isNotEmpty(previousTagValue.getValue())) {
                                previousValue = BigDecimal.valueOf(previousTagValue.getValue());
                            }
                            if ("SWWSDJ_SD".equals(energyIndex.getCode()) || "SWWSDJ_WD".equals(energyIndex.getCode())) {
                                previousValue = previousValue.multiply(BigDecimal.valueOf(0.1));
                            }
                            usedValue = String.valueOf(cumulative.subtract(previousValue).setScale(2, RoundingMode.HALF_UP));
                        }
                        value = String.valueOf(cumulative.setScale(2, RoundingMode.HALF_UP));
                    } catch (Exception ignored) {
                    }
                }
                // æ—¶é—´
                String timeName = DateUtil.formatDateTime(beginTime);
                vo.setDataTime(timeName);
                if ("DAY".equals(dto.getTimeType())) {
                    beginTime = DateUtil.offsetMinute(beginTime, 1);
                } else {
                    beginTime = DateUtil.offsetSecond(beginTime, 1);
                }
                vo.setUsedValue(String.valueOf(usedValue));
                vo.setValue(String.valueOf(value));
                voList.add(vo);
            }
            return AjaxResult.success(voList);
zhitan-admin/src/main/java/com/zhitan/web/controller/meter/MeterController.java
@@ -26,9 +26,8 @@
 * @Version: 1.0
 * @Since: JDK1.8
 */
@Slf4j
@Api("采集计量表数据管理")
@Slf4j
@RestController
@RequestMapping("/meters")
public class MeterController extends BaseController {
zhitan-admin/src/main/java/com/zhitan/web/controller/model/ModelInfoController.java
@@ -10,6 +10,7 @@
import com.zhitan.model.domain.vo.PointDataVO;
import com.zhitan.model.service.IEnergyIndexService;
import com.zhitan.model.service.IModelInfoService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
@@ -23,6 +24,7 @@
 * @author fanxinfu
 * @date 2020-02-17
 */
@Api(tags = "模型相关")
@RestController
@RequestMapping("/basicsetting/model")
public class ModelInfoController extends BaseController {
zhitan-admin/src/main/java/com/zhitan/web/controller/saving/EnergySavingProgramController.java
@@ -36,7 +36,7 @@
     * åˆ—表
     */
    @GetMapping("/page")
    @PreAuthorize("@ss.hasPermi('energySavingProject:list')")
    @PreAuthorize("@ss.hasPermi('energySavingProject:Project:list')")
    @ApiOperation(value = "分页列表")
    public TableDataInfo list(EnergySavingProgram energySavingProgram) {
        Page<EnergySavingProgramVO> list = energySavingProgramService.selectEnergySavingProgramList(energySavingProgram);
@@ -50,7 +50,6 @@
     * è¯¦ç»†ä¿¡æ¯
     */
    @ApiOperation(value = "查询详情")
    @PreAuthorize("@ss.hasPermi('energySavingProject')")
    @GetMapping(value = "getById")
    public AjaxResult getInfo(@RequestParam("id") Long id) {
        return success(energySavingProgramService.selectEnergySavingProgramById(id));
@@ -61,6 +60,7 @@
     * èŠ‚èƒ½é¡¹ç›®ç®¡ç†
     */
    @ApiOperation(value = "新增")
    @PreAuthorize("@ss.hasPermi('energySavingProject:Project:add')")
    @PostMapping("add")
    public AjaxResult add(  @RequestBody EnergySavingProgramDTO dto) {
        return energySavingProgramService.insertEnergySavingProgram(dto);
@@ -71,6 +71,7 @@
     * èŠ‚èƒ½é¡¹ç›®ç®¡ç†
     */
    @ApiOperation(value = "更新")
    @PreAuthorize("@ss.hasPermi('energySavingProject:Project:edit')")
    @PostMapping("edit")
    public AjaxResult edit(@RequestBody EnergySavingProgramDTO dto) {
        return energySavingProgramService.updateEnergySavingProgram(dto);
@@ -81,6 +82,7 @@
     * èŠ‚èƒ½é¡¹ç›®ç®¡ç†
     */
    @DeleteMapping("del/{id}")
    @PreAuthorize("@ss.hasPermi('energySavingProject:Project:del')")
    @ApiOperation(value = "删除")
    public AjaxResult remove(@PathVariable  Long id) {
        return energySavingProgramService.deleteEnergySavingProgramById(id);
zhitan-admin/src/main/java/com/zhitan/web/controller/statisticalAnalysis/EnergyConsumeDataController.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,69 @@
package com.zhitan.web.controller.statisticalAnalysis;
import com.zhitan.common.annotation.Log;
import com.zhitan.common.core.domain.AjaxResult;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import com.zhitan.statisticalAnalysis.service.IEnergyConsumeDataService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
/**
 * @Description: èƒ½æºæ¶ˆè€—统计分析
 * @author: yxw
 * @date: 2022å¹´04月12日 14:11
 */
@Api(tags = "能耗统计分析")
@RestController
@RequestMapping("/energyTypeAnalysis")
@Slf4j
public class EnergyConsumeDataController {
    @Autowired
    private IEnergyConsumeDataService energyConsumeDataService;
    /**
     * æˆæœ¬è¶‹åŠ¿åˆ†æžï¼ˆèƒ½æºæ¶ˆè€—æˆæœ¬ï¼‰- èŽ·å–è¡¨æ ¼åˆ—è¡¨æ•°æ®
     *
     * @param pageNo   é¡µç æ•°
     * @param pageSize æ¯é¡µæ•°æ®å¤šå°‘
     * @param timeCode æ—¶é—´å€¼   ä¸Žæ—¶é—´ç±»åž‹å¯¹åº”:2022-03-21/2022-03/2022
     * @param timeType æ—¶é—´ç±»åž‹ DAY/MONTH/YEAR
     * @param energyType èƒ½æºç±»åž‹
     * @param modelCode æ¨¡åž‹Code
     * @return
     */
    @Log(title = "能耗统计分析-成本趋势分析(能源消耗成本)- èŽ·å–è¡¨æ ¼åˆ—è¡¨æ•°æ®")
    @ApiOperation(value = "能耗统计分析-成本趋势分析(能源消耗成本)- èŽ·å–è¡¨æ ¼åˆ—è¡¨æ•°æ®", notes = "能耗统计分析-成本趋势分析(能源消耗成本)- èŽ·å–è¡¨æ ¼åˆ—è¡¨æ•°æ®")
    @GetMapping(value = "/listEnergyCostTrend")
    public AjaxResult listEnergyCostTrend(@RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
                                          @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
                                          @RequestParam(name = "timeCode") String timeCode,
                                          @RequestParam(name = "timeType") String timeType,
                                          @RequestParam(name = "energyType",required = false) String energyType,
                                          @RequestParam(name = "modelCode") String modelCode) {
        return AjaxResult.success(energyConsumeDataService.listEnergyCostTrend(pageNo, pageSize, timeCode, timeType,energyType,
                modelCode));
    }
    /**
     * æˆæœ¬è¶‹åŠ¿åˆ†æžï¼ˆèƒ½æºæ¶ˆè€—æˆæœ¬ï¼‰
     *
     * @param timeCode æ—¶é—´å€¼   ä¸Žæ—¶é—´ç±»åž‹å¯¹åº”:2022-03-21/2022-03/2022
     * @param timeType æ—¶é—´ç±»åž‹ DAY/MONTH/YEAR
     * @param modelCode   æ¨¡åž‹Code
     * @param energyType èƒ½æºç±»åž‹
     * @return
     */
    @Log(title = "能耗统计分析-成本趋势分析(能源消耗成本)")
    @ApiOperation(value = "能耗统计分析-成本趋势分析(能源消耗成本)", notes = "能耗统计分析-成本趋势分析(能源消耗成本)")
    @GetMapping(value = "/listEnergyCostTrendDetail")
    public AjaxResult listEnergyCostTrendDetail(@RequestParam(name = "timeCode") String timeCode,
                                                                                @RequestParam(name = "timeType") String timeType,
                                                                                @RequestParam(name = "modelCode") String modelCode,
                                                                                @RequestParam(name = "energyType",required = false) String energyType) {
        return AjaxResult.success(energyConsumeDataService.listEnergyCostTrendDetail(timeCode, timeType, modelCode, energyType));
    }
}
zhitan-admin/src/main/java/com/zhitan/web/controller/statisticalAnalysis/EnergyDataItemController.java
@@ -1,9 +1,12 @@
package com.zhitan.web.controller.statisticalAnalysis;
import com.zhitan.common.annotation.Log;
import com.zhitan.common.constant.CommonConst;
import com.zhitan.common.core.domain.AjaxResult;
import com.zhitan.dataitem.service.IDataItemService;
import com.zhitan.statisticalAnalysis.domain.dto.FlowChartsDTO;
import com.zhitan.statisticalAnalysis.domain.vo.QueryCompareRequest;
import com.zhitan.statisticalAnalysis.service.IEnergyConsumeDataService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
@@ -24,6 +27,9 @@
    @Autowired
    private IDataItemService dataItemService;
    @Autowired
    private IEnergyConsumeDataService energyConsumeDataService;
    /**
     * èŽ·å–èƒ½æµå›¾å½¢åˆ†æž
     *
@@ -36,4 +42,28 @@
    public AjaxResult getFlowCharts(@Validated FlowChartsDTO dto) {
        return AjaxResult.success(dataItemService.getFlowCharts(dto));
    }
    @Log(title = "能耗统计分析-获取同比分析列表数据")
    @ApiOperation(value = "能耗统计分析-获取同比分析列表数据", notes = "能耗统计分析-获取同比分析列表数据")
    @GetMapping(value = "/querySameCompareList")
    public AjaxResult querySameCompareList(@Validated QueryCompareRequest queryCompareRequest) {
        return AjaxResult.success(energyConsumeDataService.listEnergyTypeYoyInfo(queryCompareRequest, CommonConst.ENERGY_COMPARISON_YOY));
    }
    /**
     * èŽ·å–çŽ¯æ¯”åˆ†æžæ•°æ®
     * <p>
     * é€šè¿‡è‡ªå·±çš„æœåŠ¡è®¿é—®åœ°å€ï¼šhttp://localhost:7005/fengniao/energyDataItem/queryLoopCompare?timeType=1
     * é€šè¿‡ç½‘关访问地址:http://localhost:9999/jeecg-fengniao/fengniao/energyDataItem/queryLoopCompare?timeType=1
     *
     * @param queryCompareRequest
     * @return
     */
    @Log(title = "能耗统计分析-获取环比分析列表数据")
    @ApiOperation(value = "能耗统计分析-获取环比分析列表数据", notes = "能耗统计分析-获取环比分析列表数据")
    @GetMapping(value = "/queryLoopCompareList")
    public AjaxResult queryLoopCompareList(@Validated QueryCompareRequest queryCompareRequest) {
        return AjaxResult.success(energyConsumeDataService.listEnergyTypeYoyInfo(queryCompareRequest, CommonConst.ENERGY_COMPARISON_MOM));
    }
}
zhitan-admin/src/main/java/com/zhitan/web/controller/statisticalAnalysis/StatisticalAnalysisController.java
@@ -9,6 +9,7 @@
import com.zhitan.statisticalAnalysis.domain.vo.DataAnalysisYoYExcel;
import com.zhitan.statisticalAnalysis.domain.vo.DataAnalysisYoYVO;
import com.zhitan.statisticalAnalysis.service.IStatisticalAnalysisService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.BeanUtils;
@@ -26,6 +27,7 @@
/**
 * ç»Ÿè®¡åˆ†æž æŽ§åˆ¶å±‚
 */
@Api(tags = "统计分析")
@RestController
@RequestMapping("/statisticalAnalysis")
public class StatisticalAnalysisController extends BaseController {
zhitan-admin/src/main/java/com/zhitan/web/core/config/SwaggerConfig.java
@@ -115,11 +115,11 @@
        // ç”¨ApiInfoBuilder进行定制
        return new ApiInfoBuilder()
                // è®¾ç½®æ ‡é¢˜
                .title("标题:后台管理系统_接口文档")
                .title("智碳_能源管理系统_接口文档")
                // æè¿°
                .description("描述:接口文档")
                .description("采集企业水、电、气、热等能耗数据;帮助企业建立能源管理体系,找到跑冒滴漏,为企业节能提供数据支撑;为企业实现碳跟踪、碳盘查、碳交易、碳汇报的全生命过程;为中国碳达峰-碳中和做出贡献!")
                // ä½œè€…信息
                .contact(new Contact(baseConfig.getName(), null, null))
                .contact(new Contact(baseConfig.getName(), "https://www.zhitancloud.com", "yin.cun@qq.com"))
                // ç‰ˆæœ¬
                .version("版本号:" + baseConfig.getVersion())
                .build();
zhitan-common/src/main/java/com/zhitan/common/constant/CommonConst.java
@@ -891,15 +891,15 @@
    /**
     * ç”µæµ
     */
    public static final String TAG_CODE_CURRENT = "Current_";
    public static final String TAG_CODE_CURRENT = "Current";
    /**
     * ç”µåŽ‹
     */
    public static final String TAG_CODE_VOLTAGE = "Voltage_";
    public static final String TAG_CODE_VOLTAGE = "Voltage";
    /**
     * åŠŸçŽ‡å› æ•°
     */
    public static final String TAG_CODE_FACTOR = "PowerFactor_";
    public static final String TAG_CODE_FACTOR = "PowerFactor";
    /**
     * åŠŸçŽ‡å› æ•°
     */
zhitan-common/src/main/java/com/zhitan/common/enums/RetrievalModes.java
@@ -6,5 +6,8 @@
 *     èŽ·å–å®žæ—¶æ•°æ®æ–¹å¼.
 */
public enum RetrievalModes {
  Full, BestFit
  Full,
  BestFit
}
zhitan-common/src/main/java/com/zhitan/common/utils/ChartUtils.java
@@ -24,6 +24,20 @@
    public static void generateDateList(String timeType, String timeCode, List<Date> dateList) {
        Date now = new Date();
        switch (timeType) {
            case TimeTypeConst.TIME_TYPE_HOUR:
                if (!timeCode.contains(CommonConst.SINGLE_MINUS_SIGN)) {
                    timeCode = DateTimeUtil.toDateTimeStr(timeCode, DateTimeUtil.COMMON_PATTERN_HOUR, DateTimeUtil.COMMON_PATTERN_TO_HOUR);
                }
                int minute = 59;
                for (int i =  CommonConst.DIGIT_0; i <= minute; i++) {
                    String tempCode = timeCode + ":0" + i;
                    if(i>9){
                        tempCode = timeCode + ":" + i;
                    }
                    Date tempD = DateTimeUtil.toDateTime(tempCode, DateTimeUtil.COMMON_PATTERN_END_WITH_MINUTE);
                    dateList.add(tempD);
                }
                break;
            case TimeTypeConst.TIME_TYPE_DAY:
                if (!timeCode.contains(CommonConst.SINGLE_MINUS_SIGN)) {
                    timeCode = DateTimeUtil.toDateTimeStr(timeCode, DateTimeUtil.COMMON_PATTERN_DAY, DateTimeUtil.COMMON_PATTERN_TO_DAY);
zhitan-system/src/main/java/com/zhitan/dataitem/mapper/DataItemMapper.java
@@ -123,4 +123,16 @@
     */
    List<DataItem> getDataItemHourInforByIndexIds(@Param("beginTime") Date beginTime, @Param("endTime") Date endTime,
                                                  @Param("timeType") String timeType, @Param("indexIds") List<String> indexIds);
    /**
     * æŸ¥è¯¢èƒ½æºç±»åž‹éžç”µçš„用量
     * @param beginTime
     * @param endTime
     * @param timeType æ—¶é—´ç±»åž‹
     * @param nodeId èŠ‚ç‚¹Id
     * @param energyType èƒ½æºç±»åž‹
     * @return
     */
    BigDecimal getDataItemTimeRangeValueByNodeId(@Param("beginTime") Date beginTime, @Param("endTime") Date endTime,
                                            @Param("timeType") String timeType, @Param("nodeId") String nodeId, @Param("energyType") String energyType);
}
zhitan-system/src/main/java/com/zhitan/energyMonitor/service/impl/ElectricThreePhaseServiceImpl.java
@@ -54,9 +54,7 @@
    @Override
    public ElectricThreePhaseVO list(String timeType, String timeCode, List<EnergyIndex> energyIndexList, String requestType, String meterId) {
        ElectricThreePhaseVO vo = new ElectricThreePhaseVO();
        if (ObjectUtil.isEmpty(energyIndexList)) {
            return vo;
        }
        // èŽ·å–ç”µåŽ‹ä¸å¹³è¡¡æ•°æ®
        if (CommonConst.STR_NUMBER_0.equals(requestType)) {
            energyIndexList = energyIndexList.stream()
@@ -70,9 +68,13 @@
                            || StringUtil.ifEmptyOrNullReturnValue(x.getCode()).trim().endsWith(CommonConst.TAG_CODE_CURRENT_C))
                    .collect(Collectors.toList());
        }
        if (ObjectUtil.isEmpty(energyIndexList)) {
            return vo;
        }
        List<String> tagCodeList = energyIndexList.stream().map(EnergyIndex::getCode).collect(Collectors.toList());
        tagCodeList.add(CommonConst.STR_NUMBER_MINUS_ONE);
        String tagCodes = String.join(StrUtil.COMMA, tagCodeList);
        if(ObjectUtil.isEmpty(tagCodeList)){
            tagCodeList.add(CommonConst.STR_NUMBER_MINUS_ONE);
        }
        Date start = ChartUtils.getDateTime(timeType, timeCode);
        Date end = getEndTime(timeType, start);
@@ -82,7 +84,7 @@
        long millis = new Duration(begin, finish).getMillis();
        int pointCount = IntegerUtil.toInt(millis / CommonConst.DIGIT_3600 / CommonConst.DIGIT_1000);
        List<TagValue> tagValueList = realtimeDatabaseService.retrieve(tagCodes, start, end, pointCount);
        List<TagValue> tagValueList = realtimeDatabaseService.retrieve(tagCodeList, start, end, pointCount);
        List<ElectricThreePhaseItem> itemList = new ArrayList<>();
        List<Date> dateList = new ArrayList<>();
        ChartUtils.generateDateList(timeType, timeCode, dateList);
@@ -281,10 +283,14 @@
     */
    private void listDayData(Date date, List<TagValue> tagValueList, ElectricThreePhaseItem temp, ElectricThreePhaseTempModel tempModel) {
        Date endTime = DateTimeUtil.addHours(date, CommonConst.DIGIT_1);
        List<TagValue> currentTagValueList = tagValueList.stream().filter(x -> DateTimeUtil.compareDateDiff(date, x.getDataTime()) <= 0 && DateTimeUtil.compareDateDiff(endTime, x.getDataTime()) > 0).collect(Collectors.toList());
        List<TagValue> currentATagValueList = currentTagValueList.stream().filter(x -> StringUtil.ifEmptyOrNullReturnValue(x.getTagCode()).trim().endsWith("_A")).collect(Collectors.toList());
        List<TagValue> currentBTagValueList = currentTagValueList.stream().filter(x -> StringUtil.ifEmptyOrNullReturnValue(x.getTagCode()).trim().endsWith("_B")).collect(Collectors.toList());
        List<TagValue> currentCTagValueList = currentTagValueList.stream().filter(x -> StringUtil.ifEmptyOrNullReturnValue(x.getTagCode()).trim().endsWith("_C")).collect(Collectors.toList());
        List<TagValue> currentTagValueList = tagValueList.stream()
                .filter(x -> DateTimeUtil.compareDateDiff(date, x.getDataTime()) <= 0 && DateTimeUtil.compareDateDiff(endTime, x.getDataTime()) > 0).collect(Collectors.toList());
        List<TagValue> currentATagValueList = currentTagValueList.stream()
                .filter(x -> StringUtil.ifEmptyOrNullReturnValue(x.getTagCode()).trim().endsWith(CommonConst.A_PHASE)).collect(Collectors.toList());
        List<TagValue> currentBTagValueList = currentTagValueList.stream()
                .filter(x -> StringUtil.ifEmptyOrNullReturnValue(x.getTagCode()).trim().endsWith(CommonConst.B_PHASE)).collect(Collectors.toList());
        List<TagValue> currentCTagValueList = currentTagValueList.stream()
                .filter(x -> StringUtil.ifEmptyOrNullReturnValue(x.getTagCode()).trim().endsWith(CommonConst.C_PHASE)).collect(Collectors.toList());
        TagValue tagValueA = currentATagValueList.stream().filter(x -> DateTimeUtil.compareDateDiff(date, x.getDataTime()) == 0).findAny().orElse(null);
        TagValue tagValueB = currentBTagValueList.stream().filter(x -> DateTimeUtil.compareDateDiff(date, x.getDataTime()) == 0).findAny().orElse(null);
        TagValue tagValueC = currentCTagValueList.stream().filter(x -> DateTimeUtil.compareDateDiff(date, x.getDataTime()) == 0).findAny().orElse(null);
zhitan-system/src/main/java/com/zhitan/model/service/impl/EnergyIndexServiceImpl.java
@@ -358,8 +358,7 @@
     */
    @Override
    public List<EnergyIndex> listDeviceIndex(String nodeId, String meterId) {
        return energyIndexMapper.selectList(Wrappers.<EnergyIndex>lambdaQuery()
                .eq(EnergyIndex::getNodeId, nodeId)
                .eq(EnergyIndex::getMeterId, meterId));
        List<EnergyIndex> energyIndexList = energyIndexMapper.getIndexByMeterIdIndexCode(meterId,null,nodeId);
        return energyIndexList;
    }
}
zhitan-system/src/main/java/com/zhitan/peakvalley/mapper/PeakValleyMapper.java
@@ -38,4 +38,16 @@
    List<ElectricityDataItem> getDataStatisticsDeviationAnalysis(@Param("indexIdSet") Set<String> indexIdSet,
                                                 @Param("timeType") String timeType);
    /**
     * æŸ¥è¯¢æˆæœ¬è¶‹åŠ¿
     * @param beginTime
     * @param endTime
     * @param timeType æ—¶é—´ç±»åž‹
     * @param nodeId èŠ‚ç‚¹Id
     * @param energyType èƒ½æºç±»åž‹
     * @return
     */
    List<ElectricityDataItem> getCostTrends(@Param("beginTime") Date beginTime, @Param("endTime") Date endTime,
                                                 @Param("timeType") String timeType, @Param("nodeId") String nodeId,@Param("energyType") String energyType);
}
zhitan-system/src/main/java/com/zhitan/realtimedata/service/impl/RealtimeDatabaseServiceImpl.java
@@ -178,6 +178,5 @@
        tagCodes.add(tagCode);
        List<TagValue> historyData = repository.getHistoryData(tagCodes, beginTime, endTime, interval);
        return historyData;
//        return realtimeDatabaseManager.retrieve(tagCode, beginTime, endTime, retrievalModes, pointCount);
    }
}
zhitan-system/src/main/java/com/zhitan/statisticalAnalysis/common/DateTimeUtil.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,750 @@
package com.zhitan.statisticalAnalysis.common;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.zhitan.common.constant.CommonConst;
import com.zhitan.common.constant.TimeTypeConst;
import com.zhitan.common.utils.IntegerUtil;
import com.zhitan.common.utils.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.DateUtils;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
/**
 * @Description: æ—¶é—´å·¥å…·ç±»
 * @author: yxw
 * @date: 2022å¹´02月02日 12:23
 */
@Slf4j
public class DateTimeUtil {
    /**
     * æ—¥æœŸå¸¸ç”¨æ ¼å¼
     */
    public static final String COMMON_PATTERN = "yyyy-MM-dd HH:mm:ss";
    /**
     * æ ¼å¼åŒ–日期到分钟
     */
    public static final String COMMON_PATTERN_END_WITH_MINUTE = "yyyy-MM-dd HH:mm";
    /**
     * æ—¥æœŸæ ¼å¼ - å°æ—¶:分钟
     */
    public static final String COMMON_PATTERN_HOUR_MINUTE = "HH:mm";
    /**
     * æ—¥æœŸå¸¸ç”¨æ ¼å¼ - å¹´ä»½
     */
    public static final String COMMON_PATTERN_YEAR = "yyyy";
    /**
     * æ—¥æœŸå¸¸ç”¨æ ¼å¼ - æŸä¸€å¹´,
     */
    public static final String COMMON_PATTERN_CERTAIN_YEAR = "yy";
    /**
     * æ—¥æœŸå¸¸ç”¨æ ¼å¼ - æœˆä»½
     */
    public static final String COMMON_PATTERN_MONTH = "yyyyMM";
    /**
     * æ—¥æœŸå¸¸ç”¨æ ¼å¼ - æœˆä»½
     */
    public static final String COMMON_PATTERN_TO_MONTH = "yyyy-MM";
    /**
     * æ—¥æœŸå¸¸ç”¨æ ¼å¼ - æœˆä»½
     */
    public static final String COMMON_PATTERN_TO_MONTH_WORD = "yyyy-MM月";
    /**
     * æ—¥æœŸå¸¸ç”¨æ ¼å¼ - æœˆä»½
     */
    public static final String COMMON_PATTERN_TO_MONTH_ZH = "yyyyå¹´MM月";
    /**
     * æ—¥æœŸå¸¸ç”¨æ ¼å¼ - å¤©
     */
    public static final String COMMON_PATTERN_DAY = "yyyyMMdd";
    /**
     * æ—¥æœŸå¸¸ç”¨æ ¼å¼ - å¤©
     */
    public static final String COMMON_PATTERN_TO_DAY = "yyyy-MM-dd";
    /**
     * æ—¥æœŸå¸¸ç”¨æ ¼å¼ - å¤©
     */
    public static final String COMMON_PATTERN_TO_DAY_WORD = "yyyy-MM-dd日";
    /**
     * æ—¥æœŸå¸¸ç”¨æ ¼å¼ - æœˆæ—¥
     */
    public static final String COMMON_PATTERN_MONTH_DAY = "MM-dd";
    /**
     * æ—¥æœŸå¸¸ç”¨æ ¼å¼ - å¤©æŸä¸€å¤©,
     */
    public static final String COMMON_PATTERN_DAY_OF_MONTH = "dd";
    /**
     * æ—¥æœŸå¸¸ç”¨æ ¼å¼ - å°æ—¶
     */
    public static final String COMMON_PATTERN_HOUR = "yyyyMMddHH";
    /**
     * æ—¥æœŸå¸¸ç”¨æ ¼å¼ - å°æ—¶
     */
    public static final String COMMON_PATTERN_TO_HOUR = "yyyy-MM-dd HH";
    /**
     * æ—¥æœŸå¸¸ç”¨æ ¼å¼ - å°æ—¶
     */
    public static final String COMMON_PATTERN_TO_HOUR_WORD = "yyyy-MM-dd HH时";
    /**
     * æ—¥æœŸå¸¸ç”¨æ ¼å¼ - å°æ—¶
     */
    public static final String COMMON_PATTERN_TO_HOUR_TEXT = "yyyyå¹´MM月dd日 HH时";
    /**
     * èŽ·å–å½“å‰æ—¶é—´,时间格式:yyyy-MM-dd HH:mm:ss
     *
     * @return
     */
    public static String getNowDateTime() {
        return getNowDateTime(COMMON_PATTERN);
    }
    /**
     * èŽ·å–å½“å‰æ—¶é—´
     *
     * @param pattern æ—¶é—´æ ¼å¼
     * @return
     */
    public static String getNowDateTime(String pattern) {
        //设置日期格式
        SimpleDateFormat df = new SimpleDateFormat(pattern);
        String dateTime = df.format(new Date());
        return dateTime;
    }
    /**
     * èŽ·å–ä»Šå¹´çš„å¹´ä»½å€¼
     *
     * @return
     */
    public static String getNowYear() {
        return getNowDateTime(COMMON_PATTERN_YEAR);
    }
    /**
     * èŽ·å–ä»Šå¹´çš„æœˆä»½å€¼
     *
     * @return
     */
    public static String getNowMonth() {
        return getNowDateTime(COMMON_PATTERN_MONTH);
    }
    /**
     * å­—符串转成时间类型,默认格式:yyyy-MM-dd HH:mm:ss
     *
     * @param dateTimeStr
     * @return
     */
    public static Date toDateTime(String dateTimeStr) {
        DateTime dt = null;
        try {
            dt = DateTime.of(dateTimeStr, COMMON_PATTERN);
        } catch (Exception e) {
        }
        return dt;
    }
    /**
     * å­—符串转成时间类型
     *
     * @param dateTimeStr
     * @return
     */
    public static Date toDateTime(String dateTimeStr, String pattern) {
        DateTime dt = null;
        try {
            dt = DateTime.of(dateTimeStr, pattern);
        } catch (Exception e) {
        }
        return dt;
    }
    /**
     * å­—符串转成特定格式的时间字符串类型
     *
     * @param dateTimeStr   æ—¶é—´å­—符串
     * @param sourcePattern å­—符串时间格式
     * @param toPattern     è¦è½¬æˆä»€ä¹ˆæ ¼å¼çš„æ—¶é—´
     * @return
     */
    public static String toDateTimeStr(String dateTimeStr, String sourcePattern, String toPattern) {
        String str = CommonConst.EMPTY;
        try {
            DateTime dt = DateTime.of(dateTimeStr, sourcePattern);
            str = getDateTime(dt, toPattern);
        } catch (Exception e) {
        }
        return str;
    }
    /**
     * æ—¶é—´è½¬æˆæŒ‡å®šçš„æ ¼å¼
     *
     * @param pattern æ—¶é—´æ ¼å¼
     * @return
     */
    public static String getDateTime(Date dt, String pattern) {
        //设置日期格式
        SimpleDateFormat df = new SimpleDateFormat(pattern);
        return df.format(dt);
    }
    /**
     * æ—¶é—´è½¬æˆyyyy-MM-dd HH:mm:ss格式
     *
     * @return
     */
    public static String getDateTime(Date dt) {
        if (ObjectUtil.isEmpty(dt)) {
            return CommonConst.EMPTY;
        }
        return getDateTime(dt, COMMON_PATTERN);
    }
    /**
     * èŽ·å–å½“å‰æ—¶é—´æ‰€å±žæœˆä»½çš„æœ€åŽä¸€å¤©
     *
     * @return
     */
    public static int getDateTimeLastDay(Date dt) {
        String month = getMonth(dt);
        String firstDate = month + "01";
        Date nextMonthFirstDate = addMonths(toDateTime(firstDate, COMMON_PATTERN_DAY), CommonConst.DIGIT_1);
        Date currentMonthLastDate = addDays(nextMonthFirstDate, CommonConst.DIGIT_MINUS_1);
        int day = IntegerUtil.toInt(getDateTime(currentMonthLastDate, COMMON_PATTERN_DAY_OF_MONTH));
        return day;
    }
    /**
     * èŽ·å–å¹´ä»½å€¼
     *
     * @return
     */
    public static String getYear(Date dt) {
        return getDateTime(dt, COMMON_PATTERN_YEAR);
    }
    /**
     * èŽ·å–æœˆä»½å€¼ 202202
     *
     * @return
     */
    public static String getMonth(Date dt) {
        return getDateTime(dt, COMMON_PATTERN_MONTH);
    }
    /**
     * èŽ·å–å¤©,格式:yyyyMMdd
     *
     * @return
     */
    public static String toDay(Date dt) {
        return getDateTime(dt, COMMON_PATTERN_DAY);
    }
    /**
     * èŽ·å–å°æ—¶:yyyyMMddHH
     *
     * @return
     */
    public static String toHour(Date dt) {
        return getDateTime(dt, COMMON_PATTERN_HOUR);
    }
    /**
     * è½¬æˆå­—符串类型值
     *
     * @return
     */
    public static String toString(Date dt) {
        return getDateTime(dt, COMMON_PATTERN);
    }
    /**
     * æ—¶é—´å¢žåŠ å¯¹åº”çš„å¹´æ•°
     *
     * @param dateTime
     * @param years
     * @return
     */
    public static Date addYears(Date dateTime, int years) {
        return calcDate(dateTime, years, Calendar.YEAR);
    }
    /**
     * æ—¶é—´å¢žåŠ å¯¹åº”çš„æœˆæ•°
     *
     * @param dateTime
     * @param months
     * @return
     */
    public static Date addMonths(Date dateTime, int months) {
        return calcDate(dateTime, months, Calendar.MONTH);
    }
    /**
     * æ—¶é—´å¢žåŠ å¯¹åº”çš„å¤©æ•°
     *
     * @param dateTime
     * @param days
     * @return
     */
    public static Date addDays(Date dateTime, int days) {
        return calcDate(dateTime, days, Calendar.DATE);
    }
    /**
     * æ—¶é—´å¢žåŠ å¯¹åº”çš„å°æ—¶æ•°
     *
     * @param dateTime
     * @param hours
     * @return
     */
    public static Date addHours(Date dateTime, int hours) {
        return calcDate(dateTime, hours, Calendar.HOUR);
    }
    /**
     * æ—¶é—´å¢žåŠ å¯¹åº”çš„åˆ†é’Ÿæ•°
     *
     * @param dateTime
     * @param minutes
     * @return
     */
    public static Date addMinutes(Date dateTime, int minutes) {
        return calcDate(dateTime, minutes, Calendar.MINUTE);
    }
    /**
     * æ—¶é—´å¢žåŠ å¯¹åº”çš„å°æ—¶æ•°
     *
     * @param dateTime
     * @param seconds
     * @return
     */
    public static Date addSeconds(Date dateTime, int seconds) {
        return calcDate(dateTime, seconds, Calendar.SECOND);
    }
    /**
     * è®¡ç®—日期通用方法
     *
     * @param dateTime
     * @param addValue
     * @param calendarType è®¡ç®—类型:Calendar.YEAR,Calendar.MONTH,Calendar.DAY
     * @return
     */
    private static Date calcDate(Date dateTime, int addValue, int calendarType) {
        Date dt = null;
        try {
            Calendar calendar = new GregorianCalendar();
            calendar.setTime(dateTime);
            //把日期往后增加一年,整数往后推,负数往前移
            calendar.add(calendarType, addValue);
            // èŽ·å–ç›¸åŠ æˆ–è€…ç›¸å‡ä¹‹åŽçš„æ—¶é—´å€¼
            Date tempDt = calendar.getTime();
            // æŠŠæ—¶é—´è½¬æˆæ‰€éœ€è¦çš„æ ¼å¼
            String temp = getDateTime(tempDt, COMMON_PATTERN);
            dt = toDateTime(temp);
        } catch (Exception e) {
        }
        return dt;
    }
    /**
     * èŽ·å–è¯¥æ—¶é—´å±žäºŽå½“å¤©çš„ç¬¬å‡ ä¸ªå°æ—¶
     *
     * @param dateTime
     * @return
     */
    public static int getHourOfDay(Date dateTime) {
        return getDateValue(dateTime, Calendar.HOUR_OF_DAY);
    }
    /**
     * èŽ·å–è¯¥æ—¶é—´å±žäºŽå½“æœˆçš„ç¬¬å‡ å¤©
     *
     * @param dateTime
     * @return
     */
    public static int getDayOfMonth(Date dateTime) {
        return getDateValue(dateTime, Calendar.DAY_OF_MONTH);
    }
    /**
     * èŽ·å–è¯¥æ—¶é—´å±žäºŽå½“å‘¨çš„ç¬¬å‡ å¤©
     * ä¸€å‘¨çš„第一天是周日
     *
     * @param dateTime
     * @return
     */
    public static int getDayOfWeek(Date dateTime) {
        return getDateValue(dateTime, Calendar.DAY_OF_WEEK);
    }
    /**
     * èŽ·å–è¯¥æ—¶é—´å±žäºŽå¹´çš„ç¬¬å‡ ä¸ªæœˆ
     * æœˆä»½å€¼+1是真实的当前月
     *
     * @param dateTime
     * @return å·²ç»åœ¨ç³»ç»Ÿä¸­èŽ·å–å€¼çš„åŸºç¡€ä¸ŠåŠ 1了,现在是真实的当前月份值
     */
    public static int getMonthOfYear(Date dateTime) {
        return getDateValue(dateTime, Calendar.MONTH) + 1;
    }
    /**
     * èŽ·å–å½“å¤©çš„ç¬¬å‡ ä¸ªå°æ—¶/当月的第几天/当年的第几个月
     *
     * @param dateTime     å¦‚果时间值为空,默认当前时间
     * @param calendarType
     * @return
     */
    private static int getDateValue(Date dateTime, int calendarType) {
        int value = 0;
        try {
            if (ObjectUtil.isEmpty(dateTime)) {
                dateTime = new Date();
            }
            Calendar calendar = new GregorianCalendar();
            calendar.setTime(dateTime);
            value = calendar.get(calendarType);
        } catch (Exception e) {
        }
        return value;
    }
    /**
     * å¯¹æ¯”time1 å’Œ time2 çš„大小
     *
     * @param time1
     * @param time2
     * @return -1:time1小于time2;0:time1等于time2;1:time1大于time2;
     */
    public static int compareDateDiff(Date time1, Date time2) {
        long diff = time1.getTime() - time2.getTime();
        int res = 0;
        if (diff > 0) {
            res = 1;
        } else if (diff < 0) {
            res = -1;
        }
        return res;
    }
    /**
     * èŽ·å–æŸ¥è¯¢data_item所需要的timecode值
     *
     * @param timeType æ—¥æœŸç±»åž‹
     * @param date     æ—¶é—´
     * @return
     */
    public static String getTimeCode(String timeType, Date date) {
        String timeCode = CommonConst.EMPTY;
        if (ObjectUtil.isEmpty(date)) {
            date = new Date();
        }
        timeType = StringUtil.ifEmptyOrNullReturnValue(timeType).toUpperCase();
        switch (timeType) {
            case TimeTypeConst.TIME_TYPE_HOUR:
                timeCode = CommonConst.WORD_H + getDateTime(date, COMMON_PATTERN_HOUR);
                break;
            case TimeTypeConst.TIME_TYPE_DAY:
                timeCode = CommonConst.WORD_D + getDateTime(date, COMMON_PATTERN_DAY);
                break;
            case TimeTypeConst.TIME_TYPE_MONTH:
                timeCode = CommonConst.WORD_M + getDateTime(date, COMMON_PATTERN_MONTH);
                break;
            case TimeTypeConst.TIME_TYPE_YEAR:
                timeCode = CommonConst.WORD_Y + getDateTime(date, COMMON_PATTERN_YEAR);
                break;
            default:
                break;
        }
        return timeCode;
    }
    /**
     * èŽ·å–æŸ¥è¯¢æ—¥æœˆå¹´æŠ¥è¡¨æ‰€éœ€è¦çš„timecode值
     *
     * @param timeType æ—¥æœŸç±»åž‹
     * @param date     æ—¶é—´
     * @return
     */
    public static String getReportTimeCode(String timeType, Date date) {
        String timeCode = CommonConst.EMPTY;
        if (ObjectUtil.isEmpty(date)) {
            date = new Date();
        }
        timeType = StringUtil.ifEmptyOrNullReturnValue(timeType).toUpperCase();
        switch (timeType) {
            case TimeTypeConst.TIME_TYPE_HOUR:
                timeCode = getDateTime(date, COMMON_PATTERN_TO_HOUR);
                break;
            case TimeTypeConst.TIME_TYPE_DAY:
                timeCode = getDateTime(date, COMMON_PATTERN_TO_DAY);
                break;
            case TimeTypeConst.TIME_TYPE_MONTH:
                timeCode = getDateTime(date, COMMON_PATTERN_TO_MONTH);
                break;
            case TimeTypeConst.TIME_TYPE_YEAR:
                timeCode = getDateTime(date, COMMON_PATTERN_YEAR);
                break;
            default:
                break;
        }
        return timeCode;
    }
    /**
     * èŽ·å–æ—¶é—´å¯¹åº”çš„çŽ¯æ¯”æ—¶é—´
     *
     * @param timeType HOUR/DAY/MONTH/YEAR
     * @param date     æ—¶é—´å€¼
     * @return
     */
    public static Date getLoopTime(String timeType, Date date) {
        Date dt = null;
        if (ObjectUtil.isEmpty(date)) {
            date = new Date();
        }
        timeType = StringUtil.ifEmptyOrNullReturnValue(timeType).toUpperCase();
        switch (timeType) {
            case TimeTypeConst.TIME_TYPE_HOUR:
                dt = addHours(date, CommonConst.DIGIT_MINUS_1);
                break;
            case TimeTypeConst.TIME_TYPE_DAY:
                dt = addDays(date, CommonConst.DIGIT_MINUS_1);
                break;
            case TimeTypeConst.TIME_TYPE_MONTH:
                dt = addMonths(date, CommonConst.DIGIT_MINUS_1);
                break;
            case TimeTypeConst.TIME_TYPE_YEAR:
                dt = addYears(date, CommonConst.DIGIT_MINUS_1);
                break;
            default:
                break;
        }
        return dt;
    }
    /**
     * èŽ·å–æ•´ç‚¹æ—¶é—´
     *
     * @param timeType HOUR/DAY/MONTH/YEAR
     * @param date     æ—¶é—´å€¼
     * @return
     */
    public static Date getHourTime(String timeType, Date date) {
        Date dt = null;
        if (ObjectUtil.isEmpty(date)) {
            date = new Date();
        }
        String tempStr = null;
        timeType = StringUtil.ifEmptyOrNullReturnValue(timeType).toUpperCase();
        switch (timeType) {
            case TimeTypeConst.TIME_TYPE_HOUR:
                tempStr = getDateTime(date, COMMON_PATTERN_TO_HOUR);
                dt = toDateTime(tempStr, COMMON_PATTERN_TO_HOUR);
                break;
            case TimeTypeConst.TIME_TYPE_DAY:
                tempStr = getDateTime(date, COMMON_PATTERN_TO_DAY);
                dt = toDateTime(tempStr, COMMON_PATTERN_TO_DAY);
                break;
            case TimeTypeConst.TIME_TYPE_MONTH:
                tempStr = getDateTime(date, COMMON_PATTERN_TO_MONTH);
                dt = toDateTime(tempStr, COMMON_PATTERN_TO_MONTH);
                break;
            case TimeTypeConst.TIME_TYPE_YEAR:
                tempStr = getDateTime(date, COMMON_PATTERN_YEAR);
                dt = toDateTime(tempStr, COMMON_PATTERN_YEAR);
                break;
            default:
                break;
        }
        return dt;
    }
    /**
     * è®¡ç®—两个时间间隔天数(日期格式比较)
     *
     * @param beginTime
     * @param endTime
     * @return
     */
    public static int daysBetween(Date beginTime, Date endTime) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(beginTime);
        long beginStamp = calendar.getTimeInMillis();
        calendar.setTime(endTime);
        long endStamp = calendar.getTimeInMillis();
        long betweenDays = (endStamp - beginStamp) / (1000 * 3600 * 24);
        return Integer.parseInt(String.valueOf(betweenDays));
    }
    /**
     * è®¡ç®—两个时间间隔天数(字符串格式比较)
     *
     * @param beginTime
     * @param endTime
     * @return
     */
    public static int daysBetween(String beginTime, String endTime) {
        try {
            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
            Date begin = format.parse(beginTime);
            Date end = format.parse(endTime);
            return daysBetween(begin, end);
        } catch (ParseException exception) {
            log.error("计算两个时间间隔天数" + exception.getMessage());
            return 0;
        }
    }
    /**
     * æ ¹æ®æ—¶é—´ç±»åž‹æŠŠå­—符串转成对应的时间
     *
     * @param timeType æ—¶é—´ç±»åž‹
     * @param time     æ—¶é—´å­—符串
     * @return
     */
    public static Date getTime(String timeType, String time) {
        Date dt = null;
        timeType = StringUtil.ifEmptyOrNullReturnValue(timeType).toUpperCase();
        switch (timeType) {
            case TimeTypeConst.TIME_TYPE_HOUR:
                dt = toDateTime(time, COMMON_PATTERN_TO_HOUR);
                break;
            case TimeTypeConst.TIME_TYPE_DAY:
                dt = toDateTime(time, COMMON_PATTERN_TO_DAY);
                break;
            case TimeTypeConst.TIME_TYPE_MONTH:
                dt = toDateTime(time, COMMON_PATTERN_TO_MONTH);
                break;
            case TimeTypeConst.TIME_TYPE_YEAR:
                dt = toDateTime(time, COMMON_PATTERN_YEAR);
                break;
            default:
                break;
        }
        return dt;
    }
    /**
     * æ ¹æ®æ—¶é—´ç±»åž‹æŠŠè¿žç»­çš„æ—¥æœŸå­—符串转成对应的时间 ï¼ˆ202303、20230303、2023030301、202303030101)
     *
     * @param timeType æ—¶é—´ç±»åž‹
     * @param time     æ—¶é—´å­—符串
     * @return
     */
    public static Date getTimeByContinuousTimeCode(String timeType, String time) {
        Date dt = null;
        timeType = StringUtil.ifEmptyOrNullReturnValue(timeType).toUpperCase();
        switch (timeType) {
            case TimeTypeConst.TIME_TYPE_HOUR:
                dt = toDateTime(time, COMMON_PATTERN_HOUR);
                break;
            case TimeTypeConst.TIME_TYPE_DAY:
                dt = toDateTime(time, COMMON_PATTERN_DAY);
                break;
            case TimeTypeConst.TIME_TYPE_MONTH:
                dt = toDateTime(time, COMMON_PATTERN_MONTH);
                break;
            case TimeTypeConst.TIME_TYPE_YEAR:
                dt = toDateTime(time, COMMON_PATTERN_YEAR);
                break;
            default:
                break;
        }
        return dt;
    }
    /**
     * æ ¹æ®æ—¶é—´ç±»åž‹è¿”回天、月、年最后的时间
     *
     * @param timeType æ—¶é—´ç±»åž‹
     * @param time     æ—¶é—´
     * @return
     */
    public static Date getEndTimeByType(String timeType, Date time) {
        Date dt = null;
        switch (timeType) {
            case TimeTypeConst.TIME_TYPE_DAY:
                dt = DateUtil.endOfDay(time);
                break;
            case TimeTypeConst.TIME_TYPE_MONTH:
                dt = DateUtil.endOfMonth(time);
                break;
            case TimeTypeConst.TIME_TYPE_YEAR:
                dt = DateUtil.endOfYear(time);
                break;
            default:
                break;
        }
        return dt;
    }
    /**
     * æ ¹æ®å‘¨æœŸç±»åž‹å¯¹ç”Ÿäº§å‘¨æœŸè¿›è¡ŒåŠ å‡è®¡ç®—
     * å¡«æŠ¥å‘¨æœŸç±»åž‹ï¼ˆHOUR小时、DAY天、MONTH月、YEAR年)
     *
     * @param date      ç”Ÿäº§å‘¨æœŸ
     * @param cycleType ç”Ÿäº§å‘¨æœŸç±»åž‹
     * @param cycleType ç”Ÿäº§å‘¨æœŸç±»åž‹
     * @param val è®¡ç®—值
     * @return
     */
    public static Date productionCycleCal(Date date, String cycleType,int val) {
        Date momDate = date;
        switch (cycleType) {
            case TimeTypeConst.TIME_TYPE_HOUR:
                momDate = DateUtils.addHours(date, val);
                break;
            case TimeTypeConst.TIME_TYPE_DAY:
                momDate = DateUtils.addDays(date, val);
                break;
            case TimeTypeConst.TIME_TYPE_MONTH:
                momDate = DateUtils.addMonths(date, val);
                break;
        }
        return momDate;
    }
    /**
     * æ ¹æ®å‘¨æœŸç±»åž‹å¯¹ç”Ÿäº§å‘¨æœŸè¿›è¡ŒåŠ å‡è®¡ç®— å¹¶ä¸”进位  ä¾‹å¦‚: HOUR +1进位就是 åР䏀天
     * å¡«æŠ¥å‘¨æœŸç±»åž‹ï¼ˆHOUR小时、DAY天、MONTH月、YEAR年)
     *
     * @param date      ç”Ÿäº§å‘¨æœŸ
     * @param cycleType ç”Ÿäº§å‘¨æœŸç±»åž‹
     * @param val è®¡ç®—值
     * @return
     */
    public static Date productionCycleCalCarry(Date date, String cycleType,int val) {
        Date momDate = date;
        switch (cycleType) {
            case TimeTypeConst.TIME_TYPE_HOUR:
                momDate = DateUtils.addDays(date, val);
                break;
            case TimeTypeConst.TIME_TYPE_DAY:
                momDate = DateUtils.addMonths(date, val);
                break;
            case TimeTypeConst.TIME_TYPE_MONTH:
                momDate = DateUtils.addYears(date, val);
                break;
        }
        return momDate;
    }
}
zhitan-system/src/main/java/com/zhitan/statisticalAnalysis/domain/vo/CostTrendEnergyTypeItem.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,47 @@
package com.zhitan.statisticalAnalysis.domain.vo;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
import java.math.BigDecimal;
/**
 * æˆæœ¬è¶‹åŠ¿-能源类型
 *
 * @Author: Zhujw
 * @Date: 2023/2/14
 */
@Data
@ApiModel(value = "成本趋势-能源类型", description = "成本趋势-能源类型")
public class CostTrendEnergyTypeItem implements Serializable {
    /**
     * èƒ½æºç±»åž‹
     */
    @ApiModelProperty(value = "能源类型")
    private String energyType;
    /**
     * èƒ½æºåç§°
     */
    @ApiModelProperty(value = "能源名称")
    private String energyName;
    /**
     * ç´¯ç§¯é‡
     */
    @ApiModelProperty(value = "累积量")
    @JsonFormat(shape = JsonFormat.Shape.STRING)
    private BigDecimal accumulation;
    /**
     * è´¹ç”¨
     */
    @ApiModelProperty(value = "费用")
    @JsonFormat(shape = JsonFormat.Shape.STRING)
    private BigDecimal cost;
}
zhitan-system/src/main/java/com/zhitan/statisticalAnalysis/domain/vo/EnergyConsumeTrendDetailItem.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,83 @@
package com.zhitan.statisticalAnalysis.domain.vo;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
import java.util.List;
/**
 * è´¹ç”¨åˆ†æž-成本趋势分析统计图返回值信息
 *
 * @Author: Zhujw
 * @Date: 2023/2/14
*/
@Data
@ApiModel(value = "费用分析-成本趋势分析统计图返回值信息", description = "费用分析-成本趋势分析统计图返回值信息")
public class EnergyConsumeTrendDetailItem {
    /**
     *  èƒ½æºç±»åž‹
     */
    @ApiModelProperty(value = "能源类型")
    private String energyType;
    /**
     *  èƒ½æºå•位
     */
    @ApiModelProperty(value = "能源单位")
    private String energyUnit;
    /**
     *  ç´¯ç§¯é‡æ ‡ç­¾
     */
    @ApiModelProperty(value = "累积量标签")
    private String accumulationLabel;
    /**
     *  è´¹ç”¨æ ‡ç­¾
     */
    @ApiModelProperty(value = "费用标签")
    private String costLabel;
    /**
     * ç´¯ç§¯é‡
     */
    @ApiModelProperty(value = "累积量")
    @JsonFormat(shape = JsonFormat.Shape.STRING)
    private BigDecimal accumulation;
    /**
     * è´¹ç”¨
     */
    @ApiModelProperty(value = "费用")
    @JsonFormat(shape = JsonFormat.Shape.STRING)
    private BigDecimal cost;
    /**
     * ç´¯ç§¯é‡key集合
     */
    @ApiModelProperty(value = "累积量key集合")
    private List<String> accumulationKeyList;
    /**
     * ç´¯ç§¯é‡value集合
     */
    @ApiModelProperty(value = "累积量value集合")
    private List<BigDecimal> accumulationValueList;
    /**
     * è´¹ç”¨key集合
     */
    @ApiModelProperty(value = "费用key集合")
    private List<String> costKeyList;
    /**
     * è´¹ç”¨value集合
     */
    @ApiModelProperty(value = "费用value集合")
    private List<BigDecimal> costValueList;
}
zhitan-system/src/main/java/com/zhitan/statisticalAnalysis/domain/vo/EnergyConsumeVO.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,43 @@
package com.zhitan.statisticalAnalysis.domain.vo;
import lombok.Data;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
/**
 * èƒ½è€—实体类
 *
 * @Author: Zhujw
 * @Date: 2023/1/28
 */
@Data
public class EnergyConsumeVO implements Serializable {
    /**
     * è®¡é‡å™¨å…·id
     */
    private String deviceId;
    /**
     * èƒ½æºç±»åž‹
     */
    private String energyType;
    /**
     * æ—¶é—´ç¼–码
     */
    private Date dataTime;
    /**
     * è´¹ç”¨
     */
    private BigDecimal costValue;
    /**
     * ç´¯è®¡é‡
     */
    private BigDecimal accumulationValue;
}
zhitan-system/src/main/java/com/zhitan/statisticalAnalysis/domain/vo/EnergyCostTrendItem.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,51 @@
package com.zhitan.statisticalAnalysis.domain.vo;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
import java.util.List;
/**
 * æˆæœ¬è¶‹åŠ¿åˆ†æž-表格信息
 *
 * @Author: Zhujw
 * @Date: 2023/2/14
 */
@Data
@ApiModel(value = "成本趋势分析-表格信息", description = "成本趋势分析-表格信息")
public class EnergyCostTrendItem {
    /**
     * ç”¨èƒ½å•å…ƒid
     */
    @ApiModelProperty(value = "用能单元id")
    private String energyUnitId;
    /**
     * ç”¨èƒ½å•元名称
     */
    @ApiModelProperty(value = "用能单元名称")
    private String energyUnitName;
    /**
     * æ€»è´¹ç”¨
     */
    @ApiModelProperty(value = "总费用")
    @JsonFormat(shape = JsonFormat.Shape.STRING)
    private BigDecimal total;
    /**
     * æ—¶é—´
     */
    @ApiModelProperty(value = "时间")
    private String dateCode;
    /**
     * èƒ½æºç±»åž‹
     */
    @ApiModelProperty(value = "能源类型")
    private List<CostTrendEnergyTypeItem> itemList;
}
zhitan-system/src/main/java/com/zhitan/statisticalAnalysis/domain/vo/EnergyCostTrendPage.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,22 @@
package com.zhitan.statisticalAnalysis.domain.vo;
import lombok.Data;
import java.util.List;
/**
 * @Description: TODO
 * @author: yxw
 * @date: 2022å¹´04月15日 10:07
 */
@Data
public class EnergyCostTrendPage {
    /**
     * æ•°æ®åˆ—表
     */
    private List<EnergyCostTrendItem> itemList;
    /**
     * è®°å½•总数量
     */
    private long total;
}
zhitan-system/src/main/java/com/zhitan/statisticalAnalysis/domain/vo/EnergyTypeValueContrastedVO.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,62 @@
package com.zhitan.statisticalAnalysis.domain.vo;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
/**
 * å„能源类型值同比、环比VO
 *
 * @Author: Zhujw
 * @Date: 2023/2/8
 */
@Data
public class EnergyTypeValueContrastedVO {
    /**
     * ç”¨èƒ½å•元名称
     */
    @ApiModelProperty(value = "用能单元名称")
    private String energyUnitName;
    /**
     * èƒ½æºç±»åž‹
     */
    @ApiModelProperty(value = "能源类型")
    private String energyType;
    /**
     * æœ¬æœŸæ—¶é—´
     */
    @ApiModelProperty(value = "本期时间")
    private String currentTime;
    /**
     * æœ¬æœŸå€¼
     */
    @ApiModelProperty(value = "本期值")
    private BigDecimal currentValue;
    /**
     * å¯¹æ¯”æ—¶é—´
     */
    @ApiModelProperty(value = "对比时间")
    private String compareTime;
    /**
     * å¯¹æ¯”值
     */
    @ApiModelProperty(value = "对比值")
    private BigDecimal contrastValues;
    /**
     * åŒæ¯”值
     * åŒæ¯”增长率=(本期值-去年同期值)/去年同期值×100%
     * çŽ¯æ¯”å€¼
     * çŽ¯æ¯”å¢žé•¿çŽ‡=(本期值-上期值)/上期值×100%
     */
    @ApiModelProperty(value = "同比增长率/环比增长率")
    private BigDecimal ratio;
}
zhitan-system/src/main/java/com/zhitan/statisticalAnalysis/domain/vo/QueryCompareRequest.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,49 @@
package com.zhitan.statisticalAnalysis.domain.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import javax.validation.constraints.NotBlank;
/**
 * @Description: æ•°æ®æŸ¥è¯¢æ¡ä»¶å®žä½“
 * @author: yxw
 * @date: 2022å¹´01月28日 14:49
 */
@Data
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = false)
@ApiModel(value="QueryCompareRequest", description="获取数据的参数实体")
public class QueryCompareRequest {
    /**
     * æŸ¥è¯¢æ—¶é—´ç±»åž‹,对应常量类:TimeTypeConst
     */
    @NotBlank(message = "时间类型不能为空")
    @ApiModelProperty(value = "查询时间类型,对应常量:DAY/MONTH/SEASON/YEAR,默认MONTH")
    private String timeType;
    /**
     * æ—¥æœŸå€¼ï¼Œæœˆä»½(202201-202212)、年份(2022-~)
     */
    @NotBlank(message = "时间编码不能为空")
    @ApiModelProperty(value = "日期值,月份(202201-202212)、年份(2022-~)")
    private String timeCode;
    /**
     * èŠ‚ç‚¹Id
     */
    @NotBlank(message = "节点Id")
    @ApiModelProperty(value = "节点Id")
    private String nodeId;
    /**
     * èƒ½æºç±»åž‹ï¼Œé€šè¿‡/隔开,water/gas
     */
    @ApiModelProperty(value = "能源类型,通过/隔开,water/gas")
    private String energyType;
}
zhitan-system/src/main/java/com/zhitan/statisticalAnalysis/service/IEnergyConsumeDataService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,44 @@
package com.zhitan.statisticalAnalysis.service;
import com.zhitan.statisticalAnalysis.domain.vo.*;
import java.util.List;
/**
 * èƒ½æºæ¶ˆè€—统计相关查询
 */
public interface IEnergyConsumeDataService {
    /**
     * æˆæœ¬è¶‹åŠ¿åˆ†æžï¼ˆèƒ½æºæ¶ˆè€—æˆæœ¬ï¼‰- èŽ·å–è¡¨æ ¼åˆ—è¡¨æ•°æ®
     *
     * @param pageNo   é¡µç æ•°
     * @param pageSize æ¯é¡µæ•°æ®å¤šå°‘
     * @param timeCode æ—¶é—´å€¼   ä¸Žæ—¶é—´ç±»åž‹å¯¹åº”:2022-03-21/2022-03/2022
     * @param timeType æ—¶é—´ç±»åž‹ DAY/MONTH/YEAR
     * @param energyType èƒ½æºç±»åž‹
     * @param modelCode æ¨¡åž‹Code
     * @return
     */
    EnergyCostTrendPage listEnergyCostTrend(int pageNo, int pageSize, String timeCode, String timeType,String energyType, String modelCode);
    /**
     * æˆæœ¬è¶‹åŠ¿åˆ†æžï¼ˆèƒ½æºæ¶ˆè€—æˆæœ¬ï¼‰
     *
     * @param timeCode æ—¶é—´å€¼   ä¸Žæ—¶é—´ç±»åž‹å¯¹åº”:2022-03-21/2022-03/2022
     * @param timeType æ—¶é—´ç±»åž‹ DAY/MONTH/YEAR
     * @param modelCode   æ¨¡åž‹Code
     * @param energyType èƒ½æºç±»åž‹
     * @return
     */
    List<EnergyConsumeTrendDetailItem> listEnergyCostTrendDetail(String timeCode, String timeType, String modelCode, String energyType);
    /**
     * åŒæ¯”环比分析
     *
     * @param req            è¯·æ±‚参数
     * @param comparisonType å¯¹æ¯”类型
     * @return
     */
    public List<EnergyTypeValueContrastedVO> listEnergyTypeYoyInfo(QueryCompareRequest req, String comparisonType);
}
zhitan-system/src/main/java/com/zhitan/statisticalAnalysis/service/impl/EnergyConsumeDataServiceImpl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,498 @@
package com.zhitan.statisticalAnalysis.service.impl;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.zhitan.basicdata.domain.SysEnergy;
import com.zhitan.basicdata.mapper.SysEnergyMapper;
import com.zhitan.carbonemission.domain.CarbonEmission;
import com.zhitan.common.constant.CommonConst;
import com.zhitan.common.constant.TimeTypeConst;
import com.zhitan.common.utils.StringUtils;
import com.zhitan.dataitem.mapper.DataItemMapper;
import com.zhitan.model.domain.ModelNode;
import com.zhitan.model.domain.NodeIndex;
import com.zhitan.model.mapper.ModelNodeMapper;
import com.zhitan.model.mapper.NodeIndexMapper;
import com.zhitan.peakvalley.domain.ElectricityDataItem;
import com.zhitan.peakvalley.mapper.PeakValleyMapper;
import com.zhitan.statisticalAnalysis.common.DateTimeUtil;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.ObjectUtils;
import com.zhitan.statisticalAnalysis.domain.vo.*;
import com.zhitan.statisticalAnalysis.service.IEnergyConsumeDataService;
import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;
/**
 * @Description: TODO
 * @author: yxw
 * @date: 2022å¹´04月12日 14:15
 */
@Service
@AllArgsConstructor
public class EnergyConsumeDataServiceImpl implements IEnergyConsumeDataService {
    private DataItemMapper dataItemMapper;
    private ModelNodeMapper modelNodeMapper;
    private NodeIndexMapper nodeIndexMapper;
    private PeakValleyMapper peakValleyMapper;
    private SysEnergyMapper sysEnergyMapper;
    /**
     * æˆæœ¬è¶‹åŠ¿åˆ†æžï¼ˆèƒ½æºæ¶ˆè€—æˆæœ¬ï¼‰- èŽ·å–è¡¨æ ¼åˆ—è¡¨æ•°æ®
     *
     * @param pageNo     é¡µç æ•°
     * @param pageSize   æ¯é¡µæ•°æ®å¤šå°‘
     * @param timeCode   æ—¶é—´å€¼   ä¸Žæ—¶é—´ç±»åž‹å¯¹åº”:2022-03-21/2022-03/2022
     * @param timeType   æ—¶é—´ç±»åž‹ DAY/MONTH/YEAR
     * @param energyType èƒ½æºç±»åž‹
     * @param modelCode  æ¨¡åž‹Code
     * @return
     */
    @Override
    public EnergyCostTrendPage listEnergyCostTrend(int pageNo, int pageSize, String timeCode, String timeType, String energyType,
                                                   String modelCode) {
        //能源类型信息
        SysEnergy sysEnergy = new SysEnergy();
        if (StringUtils.isNotEmpty(energyType)) {
            sysEnergy.setEnersno(energyType);
        }
        List<SysEnergy> sysEnergies = sysEnergyMapper.selectSysEnergyList(sysEnergy);
        if (sysEnergies.isEmpty()) {
            throw new RuntimeException("未查询到能源信息");
        }
        //节点信息
        List<ModelNode> modelNodes = modelNodeMapper.selectList(Wrappers.<ModelNode>lambdaQuery().eq(ModelNode::getModelCode, modelCode)
                .isNull(ModelNode::getParentId));
        if (ObjectUtils.isEmpty(modelNodes)) {
            throw new RuntimeException("未查询到节点信息");
        }
        ModelNode modelNodeInfo = modelNodes.stream().findFirst().get();
        //点位信息
        List<NodeIndex> nodeIndices = nodeIndexMapper.selectList(Wrappers.<NodeIndex>lambdaQuery()
                .eq(NodeIndex::getNodeId, modelNodeInfo.getNodeId()));
        if (nodeIndices.isEmpty()) {
            throw new RuntimeException("未查询到点位信息");
        }
        // æ€»è´¹ç”¨
        BigDecimal totalCost = BigDecimal.ZERO;
        // éåŽ†èƒ½æºç±»åž‹
        List<CostTrendEnergyTypeItem> itemList = new ArrayList<>();
        for (SysEnergy sysEnergyInfo : sysEnergies) {
            CostTrendEnergyTypeItem item = new CostTrendEnergyTypeItem();
            item.setEnergyType(sysEnergyInfo.getEnersno());
            item.setEnergyName(sysEnergyInfo.getEnername());
            // å¤„理时间
            Date bsTime = DateTimeUtil.getTime(timeType, timeCode);
            Date endTime = DateTimeUtil.getEndTimeByType(timeType, bsTime);
            totalCost = getEnergyUnitCostTrendAnalysisValueInfo(timeType, bsTime, endTime, totalCost, nodeIndices, modelNodeInfo.getNodeId(), sysEnergyInfo, item);
            itemList.add(item);
        }
        // éåŽ†ç”¨èƒ½å•å…ƒèŽ·å–è¡¨æ ¼ä¸­çš„æ•°æ®
        List<EnergyCostTrendItem> trendItemList = new ArrayList<>();
        EnergyCostTrendItem energyCostTrendItem = new EnergyCostTrendItem();
        energyCostTrendItem.setDateCode(timeCode);
        energyCostTrendItem.setTotal(totalCost.setScale(CommonConst.DIGIT_2, RoundingMode.HALF_UP));
        energyCostTrendItem.setItemList(itemList);
        trendItemList.add(energyCostTrendItem);
        EnergyCostTrendPage energyCostTrendPage = new EnergyCostTrendPage();
        energyCostTrendPage.setTotal(1);
        energyCostTrendPage.setItemList(trendItemList);
        return energyCostTrendPage;
    }
    /**
     * èŽ·å–ç”¨èƒ½å•å…ƒæˆæœ¬è¶‹åŠ¿åˆ†æžç´¯ç§¯é‡ã€è´¹ç”¨ä¿¡æ¯
     *
     * @param timeType      æ—¶é—´ç±»åž‹
     * @param bsTime        å¼€å§‹æ—¶é—´
     * @param endTime       ç»“束时间
     * @param totalCost     æ€»è´¹ç”¨
     * @param nodeIndices   èŠ‚ç‚¹ç‚¹ä½é›†åˆ
     * @param nodeId        èŠ‚ç‚¹id
     * @param sysEnergyInfo èƒ½æºç±»åž‹ä¿¡æ¯
     * @param item          è¿”回对象
     * @return
     */
    private BigDecimal getEnergyUnitCostTrendAnalysisValueInfo(String timeType, Date bsTime, Date endTime, BigDecimal totalCost,
                                                               List<NodeIndex> nodeIndices, String nodeId, SysEnergy sysEnergyInfo,
                                                               CostTrendEnergyTypeItem item) {
        BigDecimal costValue = BigDecimal.ZERO;
        BigDecimal accumulationValue = BigDecimal.ZERO;
        //电:只有HOUR数据有效;其他能源类型:HOUR、DAY有数据
        switch (sysEnergyInfo.getEnersno()) {
            case "electric":
                List<ElectricityDataItem> electricityDataItems = peakValleyMapper.getDataStatistics(nodeIndices.stream().map(NodeIndex::getIndexId).collect(Collectors.toSet()), bsTime, endTime, TimeTypeConst.TIME_TYPE_HOUR);
                costValue = electricityDataItems.stream().map(ElectricityDataItem::getCost).reduce(BigDecimal.ZERO, BigDecimal::add);
                accumulationValue = electricityDataItems.stream().map(ElectricityDataItem::getElectricity).reduce(BigDecimal.ZERO, BigDecimal::add);
                break;
            default:
                accumulationValue = dataItemMapper.getDataItemTimeRangeValueByNodeId(bsTime, endTime, TimeTypeConst.TIME_TYPE_DAY, nodeId, sysEnergyInfo.getEnersno());
                costValue = accumulationValue.multiply(sysEnergyInfo.getPrice());
                break;
        }
        costValue = costValue.setScale(CommonConst.DIGIT_2, RoundingMode.HALF_UP);
        totalCost = totalCost.add(costValue);
        item.setCost(costValue);
        item.setAccumulation(accumulationValue.setScale(CommonConst.DIGIT_2, RoundingMode.HALF_UP));
        return totalCost;
    }
    /**
     * æˆæœ¬è¶‹åŠ¿åˆ†æžï¼ˆèƒ½æºæ¶ˆè€—æˆæœ¬ï¼‰
     *
     * @param timeCode   æ—¶é—´å€¼   ä¸Žæ—¶é—´ç±»åž‹å¯¹åº”:2022-03-21/2022-03/2022
     * @param timeType   æ—¶é—´ç±»åž‹ DAY/MONTH/YEAR
     * @param modelCode  æ¨¡åž‹Code
     * @param energyType èƒ½æºç±»åž‹
     * @return
     */
    @Override
    public List<EnergyConsumeTrendDetailItem> listEnergyCostTrendDetail(String timeCode, String timeType, String modelCode, String energyType) {
        //能源类型信息
        SysEnergy sysEnergy = new SysEnergy();
        if (StringUtils.isNotEmpty(energyType)) {
            sysEnergy.setEnersno(energyType);
        }
        List<SysEnergy> sysEnergies = sysEnergyMapper.selectSysEnergyList(sysEnergy);
        if (sysEnergies.isEmpty()) {
            throw new RuntimeException("未查询到能源信息");
        }
        //节点信息
        List<ModelNode> modelNodes = modelNodeMapper.selectList(Wrappers.<ModelNode>lambdaQuery().eq(ModelNode::getModelCode, modelCode)
                .isNull(ModelNode::getParentId));
        if (modelNodes.isEmpty()) {
            throw new RuntimeException("未查询到节点信息");
        }
        String nodeId = modelNodes.stream().findFirst().get().getNodeId();
        // èƒ½è€—信息
        List<EnergyConsumeTrendDetailItem> itemList = new ArrayList<>();
        Date startTime = DateTimeUtil.getTime(timeType, timeCode);
        Date endTime = DateTimeUtil.getEndTimeByType(timeType, startTime);
        //电:只有HOUR数据有效;其他能源类型:HOUR、DAY有数据
        String queryTimeType = TimeTypeConst.TIME_TYPE_HOUR;
        for (SysEnergy sysEnergyInfo : sysEnergies) {
            List<EnergyConsumeVO> energyConsumeVOList = new ArrayList<>();
            switch (sysEnergyInfo.getEnersno()) {
                case "electric":
                    List<ElectricityDataItem> electricityDataItems = peakValleyMapper.getCostTrends(startTime, endTime, queryTimeType, nodeId, sysEnergyInfo.getEnersno());
                    if (!electricityDataItems.isEmpty()) {
                        electricityDataItems.forEach(electricityDataItem -> {
                            EnergyConsumeVO temp = new EnergyConsumeVO();
                            temp.setDataTime(electricityDataItem.getDataTime());
                            temp.setCostValue(electricityDataItem.getCost());
                            temp.setAccumulationValue(electricityDataItem.getElectricity());
                            energyConsumeVOList.add(temp);
                        });
                    }
                    break;
                default:
                    if (timeType.equals(TimeTypeConst.TIME_TYPE_MONTH) || timeType.equals(TimeTypeConst.TIME_TYPE_YEAR)) {
                        queryTimeType = TimeTypeConst.TIME_TYPE_DAY;
                    }
                    List<CarbonEmission> dataItems = dataItemMapper.getMiddleCarbonEmission(startTime, endTime, queryTimeType, nodeId, sysEnergyInfo.getEnersno());
                    if (!dataItems.isEmpty()) {
                        dataItems.forEach(electricityDataItem -> {
                            EnergyConsumeVO temp = new EnergyConsumeVO();
                            temp.setDataTime(electricityDataItem.getDataTime());
                            temp.setCostValue(new BigDecimal(electricityDataItem.getValue()));
                            temp.setAccumulationValue(new BigDecimal(electricityDataItem.getValue()).multiply(sysEnergyInfo.getPrice()));
                            energyConsumeVOList.add(temp);
                        });
                    }
                    break;
            }
            BigDecimal cost = energyConsumeVOList.stream().map(EnergyConsumeVO::getCostValue)
                    .reduce(BigDecimal.ZERO, BigDecimal::add).setScale(CommonConst.DIGIT_2, RoundingMode.HALF_UP);
            BigDecimal accumulation = energyConsumeVOList.stream().map(EnergyConsumeVO::getAccumulationValue)
                    .reduce(BigDecimal.ZERO, BigDecimal::add).setScale(CommonConst.DIGIT_2, RoundingMode.HALF_UP);
            // ç»„装统计图信息
            EnergyConsumeTrendDetailItem item = new EnergyConsumeTrendDetailItem();
            item.setEnergyType(sysEnergyInfo.getEnersno());
            item.setEnergyUnit(sysEnergyInfo.getMuid());
            item.setCostLabel(sysEnergyInfo.getEnername() + "è´¹");
            item.setAccumulationLabel(sysEnergyInfo.getEnername() + "用量");
            item.setCost(cost);
            item.setAccumulation(accumulation);
            // ç»„装图表信息
            getTrendAnalysisCharInfoByEnergyType(startTime, timeType, energyConsumeVOList, item);
            itemList.add(item);
        }
        return itemList;
    }
    /**
     * ç»„装成本趋势分析-统计图信息
     *
     * @param bsTime    æ—¶é—´
     * @param timeType  æ—¶é—´ç±»åž‹
     * @param dataItems èƒ½è€—
     * @param item      è¿”回对象
     */
    private void getTrendAnalysisCharInfoByEnergyType(Date bsTime, String timeType,
                                                      List<EnergyConsumeVO> dataItems, EnergyConsumeTrendDetailItem item) {
        List<String> costKeyList = new ArrayList<>();
        List<String> accumulationKeyList = new ArrayList<>();
        List<BigDecimal> costValueList = new ArrayList<>();
        List<BigDecimal> accumulationValueList = new ArrayList<>();
        Map<String, List<EnergyConsumeVO>> energyConsumeVOMap;
        //按时间类型组织返回数据
        switch (timeType) {
            case TimeTypeConst.TIME_TYPE_DAY:
                energyConsumeVOMap = dataItems.stream().collect(Collectors.groupingBy(li -> DateUtil.formatDateTime(li.getDataTime())));
                for (int i = 0; i < CommonConst.DIGIT_24; i++) {
                    String formatDate = i + CommonConst.TIME_UNIT_SHOW_HOUR;
                    costKeyList.add(formatDate);
                    accumulationKeyList.add(formatDate);
                    String key = DateUtil.formatDateTime(DateUtil.offsetHour(bsTime, i));
                    calculateCostAndAccumulation(energyConsumeVOMap, key, costValueList, accumulationValueList);
                }
                break;
            case TimeTypeConst.TIME_TYPE_MONTH:
                energyConsumeVOMap = dataItems.stream().collect(Collectors.groupingBy(li -> DateUtil.formatDate(li.getDataTime())));
                Date endTime = DateTimeUtil.getEndTimeByType(timeType, bsTime);
                while (bsTime.before(endTime)) {
                    String formatDate = DateUtil.formatDate(bsTime);
                    costKeyList.add(formatDate);
                    accumulationKeyList.add(formatDate);
                    calculateCostAndAccumulation(energyConsumeVOMap, formatDate, costValueList, accumulationValueList);
                    bsTime = DateUtil.offsetDay(bsTime, CommonConst.DIGIT_1);
                }
                break;
            case TimeTypeConst.TIME_TYPE_YEAR:
                SimpleDateFormat formatter = new SimpleDateFormat(DateTimeUtil.COMMON_PATTERN_TO_MONTH_ZH);
                energyConsumeVOMap = dataItems.stream().collect(Collectors.groupingBy(li -> formatter.format(li.getDataTime())));
                for (int i = 0; i < CommonConst.DIGIT_12; i++) {
                    Date newDate = DateUtil.offsetMonth(bsTime, i);
                    String formatDate = DateUtil.format(newDate, DateTimeUtil.COMMON_PATTERN_TO_MONTH_ZH);
                    costKeyList.add(formatDate);
                    accumulationKeyList.add(formatDate);
                    calculateCostAndAccumulation(energyConsumeVOMap, formatDate, costValueList, accumulationValueList);
                }
                break;
            default:
                break;
        }
        item.setCostKeyList(costKeyList);
        item.setCostValueList(costValueList);
        item.setAccumulationKeyList(accumulationKeyList);
        item.setAccumulationValueList(accumulationValueList);
    }
    /**
     * è®¡ç®—费用和用量
     *
     * @param energyConsumeVOMap
     * @param formatDate
     * @param costValueList
     * @param accumulationValueList
     */
    private static void calculateCostAndAccumulation(Map<String, List<EnergyConsumeVO>> energyConsumeVOMap, String formatDate, List<BigDecimal> costValueList, List<BigDecimal> accumulationValueList) {
        List<EnergyConsumeVO> energyConsumeList = Optional.ofNullable(energyConsumeVOMap.get(formatDate))
                .orElse(Collections.emptyList());
        BigDecimal totalCost = energyConsumeList.stream()
                .map(EnergyConsumeVO::getCostValue)
                .reduce(BigDecimal.ZERO, BigDecimal::add)
                .setScale(CommonConst.DIGIT_2, RoundingMode.HALF_UP);
        BigDecimal totalAccumulation = energyConsumeList.stream()
                .map(EnergyConsumeVO::getAccumulationValue)
                .reduce(BigDecimal.ZERO, BigDecimal::add)
                .setScale(CommonConst.DIGIT_2, RoundingMode.HALF_UP);
        costValueList.add(totalCost);
        accumulationValueList.add(totalAccumulation);
    }
    /**
     * åŒæ­¥çŽ¯æ¯”åˆ†æž
     *
     * @param req            è¯·æ±‚参数
     * @param comparisonType å¯¹æ¯”类型
     * @return
     */
    @Override
    public List<EnergyTypeValueContrastedVO> listEnergyTypeYoyInfo(QueryCompareRequest req, String comparisonType) {
        String energyType = req.getEnergyType();
        String timeType = req.getTimeType();
        String timeCode = req.getTimeCode();
        String nodeId = req.getNodeId();
        //能源类型信息
        SysEnergy sysEnergy = new SysEnergy();
        sysEnergy.setEnersno(energyType);
        List<SysEnergy> sysEnergies = sysEnergyMapper.selectSysEnergyList(sysEnergy);
        if (sysEnergies.isEmpty()) {
            throw new RuntimeException("未查询到能源信息");
        }
        SysEnergy sysEnergyInfo = sysEnergies.get(0);
        // èƒ½è€—信息
        Date startTime = DateTimeUtil.getTime(timeType, timeCode);
        Date endTime = DateTimeUtil.getEndTimeByType(timeType, startTime);
        //是否同比
        boolean isYoy = comparisonType.equals(CommonConst.ENERGY_COMPARISON_YOY);
        // è®¡ç®—上一年的同期时间
        Date lastBeginTime = DateUtil.offset(startTime, DateField.YEAR, CommonConst.DIGIT_MINUS_1);
        Date lastEndTime = DateUtil.offset(endTime, DateField.YEAR, CommonConst.DIGIT_MINUS_1);
        if (!isYoy) {
            switch (timeType) {
                case TimeTypeConst.TIME_TYPE_DAY:
                    lastBeginTime = DateUtil.offsetDay(startTime, CommonConst.DIGIT_MINUS_1);
                    lastEndTime = DateUtil.offsetDay(endTime, CommonConst.DIGIT_MINUS_1);
                    break;
                case TimeTypeConst.TIME_TYPE_MONTH:
                    lastBeginTime = DateUtil.offsetMonth(startTime, CommonConst.DIGIT_MINUS_1);
                    lastEndTime = DateUtil.offsetMonth(endTime, CommonConst.DIGIT_MINUS_1);
                    break;
            }
        }
        //电:只有HOUR数据有效;其他能源类型:HOUR、DAY有数据
        String queryTimeType = TimeTypeConst.TIME_TYPE_HOUR;
        List<EnergyConsumeVO> energyConsumeVOList = new ArrayList<>();
        switch (sysEnergyInfo.getEnersno()) {
            case "electric":
                List<ElectricityDataItem> electricityDataItems = peakValleyMapper.getCostTrends(startTime, endTime, queryTimeType, nodeId, sysEnergyInfo.getEnersno());
                List<ElectricityDataItem> lastDataItemList = peakValleyMapper.getCostTrends(lastBeginTime, lastEndTime, queryTimeType, nodeId, sysEnergyInfo.getEnersno());
                if (!lastDataItemList.isEmpty()) {
                    electricityDataItems.addAll(lastDataItemList);
                }
                if (!electricityDataItems.isEmpty()) {
                    electricityDataItems.forEach(electricityDataItem -> {
                        EnergyConsumeVO temp = new EnergyConsumeVO();
                        temp.setDataTime(electricityDataItem.getDataTime());
                        temp.setAccumulationValue(electricityDataItem.getElectricity());
                        energyConsumeVOList.add(temp);
                    });
                }
                break;
            default:
                if (timeType.equals(TimeTypeConst.TIME_TYPE_MONTH) || timeType.equals(TimeTypeConst.TIME_TYPE_YEAR)) {
                    queryTimeType = TimeTypeConst.TIME_TYPE_DAY;
                }
                List<CarbonEmission> dataItems = dataItemMapper.getMiddleCarbonEmission(startTime, endTime, queryTimeType, nodeId, sysEnergyInfo.getEnersno());
                List<CarbonEmission> lastDataItems = dataItemMapper.getMiddleCarbonEmission(lastBeginTime, lastEndTime, queryTimeType, nodeId, sysEnergyInfo.getEnersno());
                if (!lastDataItems.isEmpty()) {
                    dataItems.addAll(lastDataItems);
                }
                dataItems.addAll(lastDataItems);
                if (!dataItems.isEmpty()) {
                    dataItems.forEach(dataItem -> {
                        EnergyConsumeVO temp = new EnergyConsumeVO();
                        temp.setDataTime(dataItem.getDataTime());
                        temp.setAccumulationValue(new BigDecimal(dataItem.getValue()));
                        energyConsumeVOList.add(temp);
                    });
                }
                break;
        }
        // ç»„装统计图信息
        return getEnergyTypeValueContrastedVOList(startTime, timeType, energyConsumeVOList, sysEnergyInfo.getEnersno(), isYoy);
    }
    /**
     * ç»„装成本趋势分析-统计图信息
     *
     * @param bsTime     æ—¶é—´
     * @param timeType   æ—¶é—´ç±»åž‹
     * @param dataItems  èƒ½è€—
     * @param energyType èƒ½æºç±»åž‹
     * @param isYoy      æ˜¯å¦åŒæ¯”
     */
    private List<EnergyTypeValueContrastedVO> getEnergyTypeValueContrastedVOList(Date bsTime, String timeType,
                                                                                 List<EnergyConsumeVO> dataItems, String energyType, boolean isYoy) {
        Map<String, List<EnergyConsumeVO>> energyConsumeVOMap;
        Map<String, List<EnergyConsumeVO>> lastEnergyConsumeVOMap;
        List<EnergyTypeValueContrastedVO> itemList = new ArrayList<>();
        //按时间类型组织返回数据
        switch (timeType) {
            case TimeTypeConst.TIME_TYPE_DAY:
                energyConsumeVOMap = dataItems.stream().collect(Collectors.groupingBy(li -> DateUtil.formatDateTime(li.getDataTime())));
                for (int i = 0; i < CommonConst.DIGIT_24; i++) {
                    Date currentTime = DateUtil.offsetHour(bsTime, i);
                    Date compareTime = isYoy ? DateUtil.offset(currentTime, DateField.YEAR, CommonConst.DIGIT_MINUS_1) : DateUtil.offsetDay(currentTime, CommonConst.DIGIT_MINUS_1);
                    String keyCurrentTime = DateUtil.formatDateTime(currentTime);
                    String keyCompareTime = DateUtil.formatDateTime(compareTime);
                    EnergyTypeValueContrastedVO item = getEnergyTypeValueContrastedVO(energyType, energyConsumeVOMap, keyCurrentTime, keyCompareTime, currentTime, compareTime);
                    itemList.add(item);
                }
                break;
            case TimeTypeConst.TIME_TYPE_MONTH:
                energyConsumeVOMap = dataItems.stream().collect(Collectors.groupingBy(li -> DateUtil.formatDate(li.getDataTime())));
                Date endTime = DateTimeUtil.getEndTimeByType(timeType, bsTime);
                while (bsTime.before(endTime)) {
                    Date currentTime = bsTime;
                    Date compareTime = isYoy ? DateUtil.offset(currentTime, DateField.YEAR, CommonConst.DIGIT_MINUS_1) : DateUtil.offsetMonth(currentTime, CommonConst.DIGIT_MINUS_1);
                    String keyCurrentTime = DateUtil.formatDate(currentTime);
                    String keyCompareTime = DateUtil.formatDate(compareTime);
                    EnergyTypeValueContrastedVO item = getEnergyTypeValueContrastedVO(energyType, energyConsumeVOMap, keyCurrentTime, keyCompareTime, currentTime, compareTime);
                    itemList.add(item);
                    bsTime = DateUtil.offsetDay(bsTime, CommonConst.DIGIT_1);
                }
                break;
            case TimeTypeConst.TIME_TYPE_YEAR:
                SimpleDateFormat formatter = new SimpleDateFormat(DateTimeUtil.COMMON_PATTERN_TO_MONTH_ZH);
                energyConsumeVOMap = dataItems.stream().collect(Collectors.groupingBy(li -> formatter.format(li.getDataTime())));
                for (int i = 0; i < CommonConst.DIGIT_12; i++) {
                    Date currentTime = DateUtil.offsetMonth(bsTime, i);
                    Date compareTime = DateUtil.offset(currentTime, DateField.YEAR, CommonConst.DIGIT_MINUS_1);
                    String keyCurrentTime = formatter.format(currentTime);
                    String keyCompareTime = formatter.format(compareTime);
                    EnergyTypeValueContrastedVO item = getEnergyTypeValueContrastedVO(energyType, energyConsumeVOMap, keyCurrentTime, keyCompareTime, currentTime, compareTime);
                    itemList.add(item);
                }
                break;
            default:
                break;
        }
        return itemList;
    }
    private @NotNull EnergyTypeValueContrastedVO getEnergyTypeValueContrastedVO(String energyType, Map<String, List<EnergyConsumeVO>> energyConsumeVOMap,
                                                                                String keyCurrentTime, String keyCompareTime, Date currentTime, Date compareTime) {
        List<EnergyConsumeVO> energyConsumeList = Optional.ofNullable(energyConsumeVOMap.get(keyCurrentTime))
                .orElse(Collections.emptyList());
        BigDecimal currentValue = calculateSum(energyConsumeList);
        List<EnergyConsumeVO> lastEnergyConsumeList = Optional.ofNullable(energyConsumeVOMap.get(keyCompareTime))
                .orElse(Collections.emptyList());
        BigDecimal contrastValues = calculateSum(lastEnergyConsumeList);
        BigDecimal multiple = BigDecimal.valueOf(CommonConst.DIGIT_100);
        BigDecimal ratio = calculateRatio(currentValue, contrastValues, multiple);
        EnergyTypeValueContrastedVO item = new EnergyTypeValueContrastedVO();
        item.setEnergyType(energyType);
        item.setCurrentTime(DateUtil.formatDateTime(currentTime));
        item.setCompareTime(DateUtil.formatDateTime(compareTime));
        item.setCurrentValue(currentValue);
        item.setContrastValues(contrastValues);
        item.setRatio(ratio);
        return item;
    }
    private BigDecimal calculateSum(List<EnergyConsumeVO> dataItemList) {
        return dataItemList.stream()
                .map(EnergyConsumeVO::getAccumulationValue)
                .reduce(BigDecimal.ZERO, BigDecimal::add)
                .setScale(CommonConst.DIGIT_2, RoundingMode.HALF_UP);
    }
    private BigDecimal calculateRatio(BigDecimal currentSum, BigDecimal lastSum, BigDecimal multiple) {
        if (lastSum.compareTo(BigDecimal.ZERO) == 0) {
            return BigDecimal.ZERO;
        }
        return currentSum.subtract(lastSum)
                .divide(lastSum, CommonConst.DIGIT_2, RoundingMode.HALF_UP)
                .multiply(multiple)
                .setScale(CommonConst.DIGIT_2, RoundingMode.HALF_UP);
    }
}
zhitan-system/src/main/resources/mapper/dataitem/DataItemMapper.xml
@@ -215,4 +215,22 @@
        AND ( begin_time BETWEEN #{beginTime} AND #{endTime} )
        AND time_type = #{timeType}
    </select>
    <select id="getDataItemTimeRangeValueByNodeId" resultType="java.math.BigDecimal">
        SELECT
        COALESCE (SUM ( "value" ), 0)
        FROM
        "data_item" di
        JOIN energy_index ei  ON di.index_id = ei.index_id
        WHERE
        di.index_id IN ( SELECT index_id FROM node_index WHERE node_id = #{nodeId})
        <if test="energyType !='' and energyType !=null  and energyType =='allType'">
            AND ei.energy_id != ''
        </if>
        <if test="energyType !='' and energyType !=null  and energyType !='allType'">
            AND  ei.energy_id = #{energyType}
        </if>
        AND (di.data_time BETWEEN #{beginTime} AND #{endTime})
        AND di.time_type = #{timeType}
    </select>
</mapper>
zhitan-system/src/main/resources/mapper/peakvalley/ElectricityDataItemMapper.xml
@@ -49,4 +49,30 @@
        AND time_type = #{timeType}
    </select>
    <select id="getCostTrends"
            resultType="com.zhitan.peakvalley.domain.ElectricityDataItem">
        SELECT
        di.index_code,
        di.time_code,
        di.electricity_type,
        di.data_time,
        di.electricity,
        di.cost,
        di.time_type,
        di.price,
        di.remark
        FROM
        "electricity_data_item" di
        JOIN energy_index ei  ON di.index_id = ei.index_id
        WHERE
        di.index_id IN ( SELECT index_id FROM node_index WHERE node_id = #{nodeId})
        <if test="energyType !='' and energyType !=null  and energyType =='allType'">
            AND ei.energy_id != ''
        </if>
        <if test="energyType !='' and energyType !=null  and energyType !='allType'">
            AND  ei.energy_id = #{energyType}
        </if>
        AND (di.data_time BETWEEN #{beginTime} AND #{endTime})
        AND di.time_type = #{timeType}
    </select>
</mapper>
zhitan-vue/src/api/cost/api.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,16 @@
import request from "@/utils/request"
export function listEnergyCostTrend(query) {
  return request({
    url: "/energyTypeAnalysis/listEnergyCostTrend",
    method: "get",
    params: query,
  })
}
export function listEnergyCostTrendDetail(query) {
  return request({
    url: "/energyTypeAnalysis/listEnergyCostTrendDetail",
    method: "get",
    params: query,
  })
}
zhitan-vue/src/api/powerquality/electric-power-factor/api.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,9 @@
import request from "@/utils/request"
// èŽ·å–ç”¨èƒ½å•å…ƒä¸‹çš„æŸä¸ªç”µè¡¨çš„åŠŸçŽ‡å› æ•°æ•°æ®
export function powerFactorAnalysisDetail(params) {
  return request({
    url: "/powerFactorAnalysis/detail",
    method: "get",
    params,
  })
}
zhitan-vue/src/api/powerquality/electricThreePhase/api.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,10 @@
import request from "@/utils/request"
// èŽ·å–ä¸‰ç›¸ä¸å¹³è¡¡åˆ†æžæ•°æ®
export function threePhaseUnbalanceAnalysisDetail(params) {
  return request({
    url: "/threePhaseUnbalanceAnalysis/detail",
    method: "get",
    params,
  })
}
zhitan-vue/src/api/powerquality/load-analysis/api.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,28 @@
import request from "@/utils/request"
// èŽ·å–ç”¨èƒ½å•å…ƒä¸‹çš„ç”µè¡¨åˆ—è¡¨
export function listElectricityMeter(params) {
  return request({
    url: "/meter/listElectricityMeter",
    method: "get",
    params,
  })
}
// èŽ·å–ç”¨èƒ½å•å…ƒä¸‹çš„æŸä¸ªç”µè¡¨çš„è´Ÿè·åˆ†æžæ•°æ®
export function loadAnalysisDetail(params) {
  return request({
    url: "/loadAnalysis/detail",
    method: "get",
    params,
  })
}
// èŽ·å–ç”¨èƒ½å•å…ƒä¸‹çš„ç”µè¡¨åˆ—è¡¨-实体表
export function listElectricityDeviceMeter(params) {
  return request({
    url: "/loadAnalysis/listElectricMeter",
    method: "get",
    params,
  })
}
zhitan-vue/src/api/realTimeMonitor/historyDataTrend.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,16 @@
import request from "@/utils/request"
export function getHistoricalDataByIndexId(query) {
  return request({
    url: "/dataMonitoring/historyDataTrend/getHistoricalDataByIndexId",
    method: "get",
    params: query,
  })
}
export function getEnergyIndexByModelId(query) {
  return request({
    url: "/basicsetting/model/getEnergyIndexByModelId",
    method: "get",
    params: query,
  })
}
zhitan-vue/src/assets/styles/ruoyi.scss
@@ -569,6 +569,19 @@
  .el-tabs__item.is-active {
    color: #409EFF;
  }
  .el-descriptions__cell {
    background: transparent;
    color: #fff !important;
  }
  .el-descriptions__body {
    background-color: transparent;
    color: #fff;
  }
  .el-descriptions__label {
    color: #fff !important;
    background-color: #1a235d !important;
  }
}
zhitan-vue/src/components/Echarts/LineChart.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,182 @@
<template>
  <div class="chart-item">
    <div :id="domId" style="width: 100%; height: 100%"></div>
  </div>
</template>
<script setup>
import * as echarts from "echarts"
const { proxy } = getCurrentInstance()
import useSettingsStore from "@/store/modules/settings"
const settingsStore = useSettingsStore()
const emit = defineEmits()
const props = defineProps({
  chartData: {
    type: Object,
    default: () => {},
  },
  chartType: {
    type: String,
    default: "line", // bar
  },
  domId: {
    type: String,
    default: "ChartDom",
  },
})
watch(
  () => props.chartData,
  (val) => {
    console.log("watch", val)
    initChart()
  }
)
watch(
  () => settingsStore.sideTheme,
  (val) => {
    initChart()
  }
)
onMounted(() => {
  initChart()
})
function initChart(value) {
  console.log("initChart", props.chartData)
  if (!props.chartData.xAxis) {
    return
  }
  const chartDom = document.getElementById(props.domId)
  if (echarts.getInstanceByDom(chartDom)) {
    echarts.dispose(chartDom)
  }
  const myChart = echarts.init(chartDom)
  // å¤„理多系列数据
  const series = props.chartData.series.map((item) => ({
    ...item,
    name: item.name,
    type: props.chartType, // æ ¹æ®ä¼ å…¥ç±»åž‹æ¸²æŸ“
    data: item.data,
    barWidth: "16",
    itemStyle: {
      borderRadius: [15, 15, 0, 0],
    },
    smooth: true, // å¯ç”¨å¹³æ»‘曲线
  }))
  console.log("initChart", series)
  let option = {
    title: {
      // text: props.chartData.title,
      left: "40",
      textStyle: {
        color: "#2979ff",
      },
    },
    color: ["#2979ff", "#19be6b", "#ff9900", "#fa3534"],
    tooltip: {
      trigger: "axis",
      axisPointer: {
        type: "shadow",
      },
    },
    legend: {
      data: props.chartData.series.map((item) => item.name), // å›¾ä¾‹æ•°æ®
      icon: "rect",
      right: 40,
      itemWidth: 14,
      itemHeight: 10,
      textStyle: {
        color: settingsStore.sideTheme == "theme-dark" ? "#FFFFFF" : "#222222",
      },
    },
    grid: {
      top: "40",
      left: "40",
      right: "40",
      bottom: "20",
      containLabel: true,
    },
    xAxis: {
      type: "category",
      axisPointer: {
        type: "shadow",
      },
      axisLine: {
        show: true,
        lineStyle: {
          color: settingsStore.sideTheme == "theme-dark" ? "#FFFFFF" : "#222222",
        },
      },
      axisTick: {
        show: false,
      },
      splitArea: {
        show: false,
      },
      splitLine: {
        show: false,
      },
      axisLabel: {
        color: settingsStore.sideTheme == "theme-dark" ? "#FFFFFF" : "#222222",
        fontSize: 14,
        padding: [5, 0, 0, 0],
        //   formatter: '{value} ml'
      },
      data: props.chartData.xAxis,
    },
    yAxis: [
      {
        type: "value",
        nameTextStyle: {
          color: settingsStore.sideTheme == "theme-dark" ? "#FFFFFF" : "#222222",
          fontSize: 14,
          padding: [0, 0, 5, 0],
        },
        axisLine: {
          show: false,
        },
        splitLine: {
          show: true,
          lineStyle: {
            type: "dashed",
            color: settingsStore.sideTheme == "theme-dark" ? "#FFFFFF" : "#222222",
          },
        },
        axisTick: {
          show: false,
        },
        splitArea: {
          show: false,
        },
        axisLabel: {
          color: settingsStore.sideTheme == "theme-dark" ? "#FFFFFF" : "#222222",
          fontSize: 14,
        },
      },
    ],
    series: series,
  }
  setTimeout(() => {
    myChart.setOption(option)
  }, 200)
  window.addEventListener(
    "resize",
    () => {
      myChart.resize()
    },
    { passive: true }
  )
}
</script>
<style lang="scss" scoped>
.chart-item {
  width: 100%;
  height: 360px !important;
  margin-top: 0px;
  padding-top: 20px;
}
</style>
zhitan-vue/src/views/businessconfiguration/gatewayledger/gatewayLedger.vue
@@ -1,131 +1,140 @@
<template>
    <div class="page">
        <div class="form-card">
            <el-form :inline="true">
                <el-form-item label="网关数量:" class="header-box">
                    {{ total }}
                </el-form-item>
                <el-form-item label="计量器具数量:" class="header-box">
                    {{ statistics.deviceNum }}
                </el-form-item>
                <el-form-item label="测点数量:" class="header-box">
                    {{ statistics.ptNum }}
                </el-form-item>
            </el-form>
        </div>
        <div class="table-box">
            <div class="mt20 mb20">
                <el-button type="primary" icon="plus" @click="handleAdd">新增</el-button>
                <el-button type="primary" icon="Download" @click="handleExport">导出</el-button>
            </div>
            <el-table :data="tableData" v-loading="loading">
                <el-table-column prop="gatewayNum" label="网关编号" show-overflow-tooltip align="center" />
                <el-table-column prop="gatewayName" label="网关名称" show-overflow-tooltip align="center" />
                <el-table-column prop="specsModel" label="规格型号" show-overflow-tooltip align="center" />
                <el-table-column prop="installLocation" label="安装位置" show-overflow-tooltip align="center" />
                <el-table-column prop="ipAdd" label="IP地址" show-overflow-tooltip align="center" />
                <el-table-column prop="runStatus" label="运行状态" show-overflow-tooltip align="center" />
                <el-table-column prop="deviceNum" label="计量器具数量" show-overflow-tooltip align="center" />
                <el-table-column prop="ptNum" label="采集测点数量" show-overflow-tooltip align="center" />
                <el-table-column label="操作" width="300" align="center">
                    <template #default="scope">
                        <el-button link type="primary" icon="Edit" @click="handleAdd(scope.row)">
                            ä¿®æ”¹
                        </el-button>
                        <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)">
                            åˆ é™¤
                        </el-button>
                    </template>
                </el-table-column>
            </el-table>
            <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum"
                v-model:limit="queryParams.pageSize" @pagination="getList" />
        </div>
        <edit-modal ref="EditModalRef" @getList="getList(1)" />
  <div class="page">
    <div class="form-card">
      <el-form :inline="true">
        <el-form-item label="网关数量:" class="header-box">
          <span class="count">{{ total || 0 }}</span>
        </el-form-item>
        <el-form-item label="计量器具数量:" class="header-box">
          <span class="count">{{ deviceNum || 0 }}</span>
        </el-form-item>
        <el-form-item label="测点数量:" class="header-box">
          <span class="count">{{ ptNum || 0 }}</span>
        </el-form-item>
      </el-form>
    </div>
    <div class="table-bg-style">
      <div class="theme-dark-mt20 mb20 ml20">
        <el-button type="primary" icon="plus" @click="handleAdd">新增</el-button>
        <el-button type="primary" icon="Download" @click="handleExport">导出</el-button>
      </div>
      <div class="table-box">
        <el-table :data="tableData" v-loading="loading">
          <el-table-column prop="gatewayNum" label="网关编号" show-overflow-tooltip align="center" />
          <el-table-column prop="gatewayName" label="网关名称" show-overflow-tooltip align="center" />
          <el-table-column prop="specsModel" label="规格型号" show-overflow-tooltip align="center" />
          <el-table-column prop="installLocation" label="安装位置" show-overflow-tooltip align="center" />
          <el-table-column prop="ipAdd" label="IP地址" show-overflow-tooltip align="center" />
          <el-table-column prop="runStatus" label="运行状态" show-overflow-tooltip align="center" />
          <el-table-column prop="deviceNum" label="计量器具数量" show-overflow-tooltip align="center" />
          <el-table-column prop="ptNum" label="采集测点数量" show-overflow-tooltip align="center" />
          <el-table-column label="操作" width="300" align="center">
            <template #default="scope">
              <el-button link type="primary" icon="Edit" @click="handleAdd(scope.row)"> ä¿®æ”¹ </el-button>
              <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)"> åˆ é™¤ </el-button>
            </template>
          </el-table-column>
        </el-table>
        <pagination
          v-show="total > 0"
          :total="total"
          v-model:page="queryParams.pageNum"
          v-model:limit="queryParams.pageSize"
          @pagination="getList"
        />
      </div>
    </div>
    <edit-modal ref="EditModalRef" @getList="getList(1)" />
  </div>
</template>
<script setup>
import EditModal from './components/EditModal.vue'
import { gatewayStatistics, gatewayList, gatewayDel } from "@/api/businessConfiguration/gatewayLedger";
import EditModal from "./components/EditModal.vue"
import { gatewayStatistics, gatewayList, gatewayDel } from "@/api/businessConfiguration/gatewayLedger"
let { proxy } = getCurrentInstance()
let statistics = ref({
    deviceNum: 0,
    ptNum: 0
  deviceNum: 0,
  ptNum: 0,
})
function getGatewayStatisticsFun() {
    gatewayStatistics().then(res => {
        if (res.code == 200) {
            if (res.data) {
                statistics.value = res.data
            }
        }
    })
  gatewayStatistics().then((res) => {
    if (res.code == 200) {
      if (res.data) {
        statistics.value = res.data
      }
    }
  })
}
getGatewayStatisticsFun()
let loading = ref(false);
let total = ref(0);
let loading = ref(false)
let total = ref(0)
let tableData = ref([])
let queryParams = ref({
    pageNum: 1,
    pageSize: 10,
  pageNum: 1,
  pageSize: 10,
})
function getList(arg) {
    if (arg == 1) {
        queryParams.value.pageNum = 1
    }
    loading.value = true
    gatewayList(queryParams.value).then(res => {
        tableData.value = res.rows
        total.value = res.total
        loading.value = false
    })
  if (arg == 1) {
    queryParams.value.pageNum = 1
  }
  loading.value = true
  gatewayList(queryParams.value).then((res) => {
    tableData.value = res.rows
    total.value = res.total
    loading.value = false
  })
}
getList()
function handleExport() {
    proxy.download(
        "gatewaySetting/export",
        queryParams.value,
        `网关台账${new Date().getTime()}.xlsx`
    );
  proxy.download("gatewaySetting/export", queryParams.value, `网关台账${new Date().getTime()}.xlsx`)
}
let EditModalRef = ref('')
let EditModalRef = ref("")
function handleAdd(row) {
    if (EditModalRef.value) {
        EditModalRef.value.handleOpen(row)
    }
  if (EditModalRef.value) {
    EditModalRef.value.handleOpen(row)
  }
}
function handleDelete(row) {
    proxy.$modal
        .confirm('是否确认删除网关为"' + row.gatewayName + '"的数据项?')
        .then(function () {
            return gatewayDel(row.id);
        })
        .then(() => {
            getList(1);
            proxy.$modal.msgSuccess("删除成功");
        })
        .catch(() => { });
  proxy.$modal
    .confirm('是否确认删除网关为"' + row.gatewayName + '"的数据项?')
    .then(function () {
      return gatewayDel(row.id)
    })
    .then(() => {
      getList(1)
      proxy.$modal.msgSuccess("删除成功")
    })
    .catch(() => {})
}
</script>
<style lang="scss" scoped>
@import "@/assets/styles/page.scss";
.header-box {
    :deep .el-form-item__content {
        color: #fff;
        font-size: 16px;
    }
  :deep .el-form-item__content {
    color: #fff;
    font-size: 16px;
  }
}
</style>
.themeDark {
  .count {
    color: #fff;
  }
}
.themeLight {
  .count {
    color: #333;
  }
}
</style>
zhitan-vue/src/views/comprehensive/comps/LineChart.vue
@@ -31,6 +31,10 @@
  }
)
onMounted(() => {
  initChart()
})
function initChart(value) {
  const chartDom = document.getElementById("ChartDom")
  if (echarts.getInstanceByDom(chartDom)) {
zhitan-vue/src/views/comprehensive/monthlyComprehensive/index.vue
@@ -69,10 +69,9 @@
            </template>
          </el-table-column>
          <el-table-column v-for="index in 31" :key="index" :label="index + '日'" align="center" min-width="100">
            <template #default="scope">{{ numFilter(scope.row[`value${index - 1}`]) }}</template>
            <template #default="scope">{{ numFilter(scope.row[`value${index}`]) }}</template>
          </el-table-column>
        </el-table>
        <div>
          <line-chart ref="LineChartRef" :chartData="lineChartData" />
        </div>
zhitan-vue/src/views/comprehensive/yearComprehensive/index.vue
@@ -69,7 +69,7 @@
            </template>
          </el-table-column>
          <el-table-column v-for="index in 12" :key="index" :label="index + '月'" align="center" min-width="100">
            <template #default="scope">{{ numFilter(scope.row[`value${index - 1}`]) }}</template>
            <template #default="scope">{{ numFilter(scope.row[`value${index}`]) }}</template>
          </el-table-column>
        </el-table>
zhitan-vue/src/views/costAnalysis/cost-trend-analysis.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,316 @@
<template>
  <div class="page">
    <div>
      <div class="form-card">
        <el-form :model="queryParams" ref="queryRef" :inline="true">
          <el-form-item label="期间" prop="timeType">
            <el-select
              v-model="queryParams.timeType"
              placeholder="期间"
              clearable
              style="width: 120px"
              @change="handleTimeType"
            >
              <el-option v-for="dict in period" :key="dict.value" :label="dict.label" :value="dict.value" />
            </el-select>
          </el-form-item>
          <el-form-item label="时间" prop="dataTime">
            <el-date-picker
              v-model="queryParams.dataTime"
              :type="queryParams.timeType == 'YEAR' ? 'year' : queryParams.timeType == 'MONTH' ? 'month' : 'date'"
              :format="
                queryParams.timeType == 'YEAR' ? 'YYYY' : queryParams.timeType == 'MONTH' ? 'YYYY-MM' : 'YYYY-MM-DD'
              "
              value-format="YYYY-MM-DD"
              placeholder="时间"
              style="width: 100%"
            />
          </el-form-item>
          <el-form-item>
            <el-button type="primary" icon="Search" @click="handleQuery"> æœç´¢ </el-button>
          </el-form-item>
          <!-- <el-form-item>
              <el-button type="primary" icon="Download" @click="handleExport"> å¯¼å‡º </el-button>
            </el-form-item> -->
        </el-form>
      </div>
      <div class="table-bg-style">
        <div class="table-box theme-dark-mt20" style="">
          <el-table :data="tableData" v-loading="loading">
            <el-table-column label="时间" prop="dateCode" align="center" width="160" />
            <el-table-column label="总费用(元)" prop="total" align="center" width="120" />
            <el-table-column :label="col.energyName" v-for="(col, index) in columns" :key="index" align="center">
              <el-table-column :prop="'energyTotal' + col.energyType" label="消耗量" min-width="120" align="center" />
              <el-table-column :prop="'costTotal' + col.energyType" label="费用(元)" min-width="120" align="center" />
            </el-table-column>
          </el-table>
        </div>
      </div>
      <div class="charts-view" v-loading="loading">
        <el-row :gutter="2" class="" v-for="item in chartDataList" :key="item.energyType">
          <el-col :span="12">
            <BaseCard :title="item.costLabel + '(元)'">
              <div class="">
                <LineChart
                  :ref="'LineChartCostRef' + item.energyType"
                  :domId="'costDom_' + item.energyType"
                  :chartData="{
                    title: item.costLabel,
                    chartType: 'line',
                    xAxis: item.costKeyList,
                    series: [
                      {
                        name: item.costLabel,
                        data: item.costValueList,
                        markPoint: {
                          data: [
                            { type: 'max', name: 'Max' },
                            { type: 'min', name: 'Min' },
                          ],
                        },
                      },
                    ],
                  }"
                />
              </div>
            </BaseCard>
          </el-col>
          <el-col :span="12">
            <BaseCard :title="item.accumulationLabel + '(' + item.energyUnit + ')'">
              <div class="">
                <LineChart
                  :ref="'LineChartaccumulationRef' + item.energyType"
                  :domId="'accumulationDom_' + item.energyType"
                  :chartType="'bar'"
                  :chartData="{
                    title: item.accumulationLabel,
                    chartType: 'bar',
                    xAxis: item.accumulationKeyList,
                    series: [
                      {
                        name: item.accumulationLabel,
                        color: '#19be6b',
                        data: item.accumulationValueList,
                        markPoint: {
                          data: [
                            { type: 'max', name: 'Max' },
                            { type: 'min', name: 'Min' },
                          ],
                        },
                      },
                    ],
                  }"
                />
              </div>
            </BaseCard>
          </el-col>
        </el-row>
      </div>
    </div>
  </div>
</template>
<script setup name="loadAnalysis">
import { listEnergyCostTrend, listEnergyCostTrendDetail } from "@/api/cost/api.js"
import LineChart from "@/components/Echarts/LineChart.vue"
import { deepClone } from "@/utils/index.js"
const { proxy } = getCurrentInstance()
import { useRoute } from "vue-router"
const { period } = proxy.useDict("period")
import useSettingsStore from "@/store/modules/settings"
const settingsStore = useSettingsStore()
watch(
  () => settingsStore.sideTheme,
  (val) => {
    getList()
  }
)
const activeKey = ref(1)
const loading = ref(false)
const tableData = ref([])
const columns = ref([])
const detailData = ref({})
const lineChartData = ref({})
const chartDataList = ref([])
const data = reactive({
  queryParams: {
    nodeId: null,
    nodeName: null,
    timeType: null,
    dataTime: null,
    meterId: "",
    modelCode: useRoute().query.modelCode,
  },
  query: { ...useRoute().query },
})
const { queryParams, query } = toRefs(data)
function handleTimeType(e) {
  queryParams.value.timeType = e
  queryParams.value.dataTime = proxy.dayjs(new Date()).format("YYYY-MM-DD")
  getTableData()
  getList()
}
function getTableData() {
  let params = {
    ...queryParams.value,
    nodeId: queryParams.value.nodeId,
    timeType: queryParams.value.timeType,
    timeCode: queryParams.value.dataTime,
    meterId: queryParams.value.meterId,
  }
  if (queryParams.value.timeType == "DAY") {
    params.timeCode = proxy.dayjs(new Date(queryParams.value.dataTime)).format("YYYY-MM-DD")
  } else if (queryParams.value.timeType == "MONTH") {
    params.timeCode = proxy.dayjs(new Date(queryParams.value.dataTime)).format("YYYY-MM")
  } else if (queryParams.value.timeType == "YEAR") {
    params.timeCode = proxy.dayjs(new Date(queryParams.value.dataTime)).format("YYYY")
  }
  listEnergyCostTrend(params).then((res) => {
    if (res.code === 200) {
      let data = deepClone(res.data.itemList || [])
      // è¡¨å¤´çš„æ•°æ®
      if (data.length > 0 && data[0].itemList.length > 0) {
        let energyList = data[0].itemList
        columns.value = energyList.map((item) => {
          return {
            energyName: item.energyName,
            energyType: item.energyType,
          }
        })
      }
      tableData.value = data.map((item) => {
        let tempObj = {}
        item.itemList.forEach((element) => {
          tempObj["energyTotal" + element.energyType] = element.accumulation
          tempObj["costTotal" + element.energyType] = element.cost
        })
        return {
          ...item,
          ...tempObj,
        }
      })
    }
  })
}
const LineChartRef = ref()
function getList() {
  loading.value = true
  let params = {
    ...queryParams.value,
    nodeId: queryParams.value.nodeId,
    timeType: queryParams.value.timeType,
    timeCode: queryParams.value.dataTime,
    meterId: queryParams.value.meterId,
  }
  if (queryParams.value.timeType == "DAY") {
    params.timeCode = proxy.dayjs(new Date(queryParams.value.dataTime)).format("YYYY-MM-DD")
  } else if (queryParams.value.timeType == "MONTH") {
    params.timeCode = proxy.dayjs(new Date(queryParams.value.dataTime)).format("YYYY-MM")
  } else if (queryParams.value.timeType == "YEAR") {
    params.timeCode = proxy.dayjs(new Date(queryParams.value.dataTime)).format("YYYY")
  }
  listEnergyCostTrendDetail(params)
    .then((res) => {
      if (res.code == 200) {
        loading.value = false
        chartDataList.value = res.data
      }
    })
    .catch(() => {
      loading.value = false
    })
}
// ç¢³æŽ’放管理-碳排放量核算-搜索
function handleQuery() {
  getTableData()
  getList()
}
// ç¢³æŽ’放管理-碳排放量核算-重置
function resetQuery() {
  proxy.resetForm("queryRef")
  queryParams.value.timeType = null
  queryParams.value.dataTime = null
  handleTimeType(period.value[0].value)
  handleQuery()
}
// ç¢³æŽ’放管理-碳排放量核算-导出
function handleExport() {
  proxy.download(
    "carbonEmission/export",
    {
      emissionType: "allType",
      ...queryParams.value,
      ...query.value,
    },
    `${queryParams.value.nodeName}-碳排放量核算_${new Date().getTime()}.xlsx`
  )
}
onMounted(() => {
  setTimeout(() => {
    handleTimeType(period.value[0].value)
  }, 200)
})
</script>
<style scoped lang="scss">
@import "@/assets/styles/page.scss";
.table-box {
  margin-top: 0;
  :deep .el-table--border .el-table__inner-wrapper:after {
    height: 0;
  }
  :deep .el-table--border:after {
    width: 0;
  }
  :deep .el-table--border:before {
    width: 0;
  }
  :deep .el-table__border-left-patch {
    background: transparent;
  }
  :deep .el-table--border .el-table__cell {
    border-right: none;
  }
}
.charts-view {
  width: 100%;
  margin-top: 20px;
  // padding: 0 30px;
}
.display-buttons {
  display: flex;
  justify-content: flex-end;
  align-items: center;
  margin-top: 16px;
  margin-right: 16px;
  .display-btn,
  .active-display-btn {
    width: 78px;
    height: 34px;
    background: #fff;
    color: #409eff;
    border: 2px solid #409eff;
    border-radius: 4px;
    margin-left: 10px;
    text-align: center;
    line-height: 31px;
    font-size: 14px;
    font-weight: 400;
    cursor: pointer;
    &:hover {
      opacity: 0.9;
    }
  }
  .active-display-btn {
    background: #409eff;
    color: #fff;
  }
}
</style>
zhitan-vue/src/views/costAnalysis/energy-trend-analysis.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,295 @@
<template>
  <div class="page"></div>
</template>
<script setup name="loadAnalysis">
import { loadAnalysisDetail, listElectricityDeviceMeter } from "@/api/powerquality/load-analysis/api.js"
import LineChart from "@/components/Echarts/LineChart.vue"
const { proxy } = getCurrentInstance()
import { useRoute } from "vue-router"
const { period } = proxy.useDict("period")
import useSettingsStore from "@/store/modules/settings"
const settingsStore = useSettingsStore()
watch(
  () => settingsStore.sideTheme,
  (val) => {
    getList()
  }
)
const activeKey = ref(1)
const loading = ref(false)
const tableData = ref([])
const detailData = ref({})
const lineChartData = ref({})
const electricityMeter = ref([])
const data = reactive({
  queryParams: {
    nodeId: null,
    nodeName: null,
    timeType: null,
    dataTime: null,
    meterId: "",
    modelCode: useRoute().query.modelCode,
  },
  query: { ...useRoute().query },
})
const { queryParams, query } = toRefs(data)
function getElectricityMeter(params) {
  listElectricityDeviceMeter(params).then((res) => {
    if (res.code === 200) {
      electricityMeter.value = res.data.map((item) => {
        return {
          ...item,
          value: item.code,
        }
      })
      queryParams.value.meterId = res.data.length > 0 ? res.data[0].code : ""
      getList()
    }
  })
}
/** èŠ‚ç‚¹å•å‡»äº‹ä»¶ */
function handleNodeClick(data) {
  queryParams.value.nodeId = data.id
  queryParams.value.nodeName = data.label
  setTimeout(() => {
    handleTimeType(period.value[0].value)
  }, 200)
}
function handleTimeType(e) {
  queryParams.value.timeType = e
  queryParams.value.dataTime = proxy.dayjs(new Date()).format("YYYY-MM-DD")
  getElectricityMeter({ nodeId: queryParams.value.nodeId })
}
const LineChartRef = ref()
function getList() {
  return
  loading.value = true
  let params = {
    nodeId: queryParams.value.nodeId,
    timeType: queryParams.value.timeType,
    timeCode: queryParams.value.dataTime,
    meterId: queryParams.value.meterId,
  }
  if (queryParams.value.timeType == "DAY") {
    params.timeCode = proxy.dayjs(new Date(queryParams.value.dataTime)).format("YYYY-MM-DD")
  } else if (queryParams.value.timeType == "MONTH") {
    params.timeCode = proxy.dayjs(new Date(queryParams.value.dataTime)).format("YYYY-MM")
  } else if (queryParams.value.timeType == "YEAR") {
    params.timeCode = proxy.dayjs(new Date(queryParams.value.dataTime)).format("YYYY")
  }
  loadAnalysisDetail(params)
    .then((res) => {
      if (res.code == 200) {
        loading.value = false
        tableData.value = res.data.itemList
        detailData.value = res.data.detail
        let itemList = res.data.itemList
        if (queryParams.value.timeType == "DAY") {
          lineChartData.value = {
            title: "负荷分析",
            xAxis: itemList.map((item) => {
              return item.timeCode.slice(item.timeCode.length - 2, item.timeCode.length) + "时"
            }),
            series: [
              {
                name: "负荷值",
                data: itemList.map((item) => {
                  return item.value
                }),
              },
            ],
          }
        } else {
          lineChartData.value = {
            title: "负荷分析",
            xAxis: itemList.map((item) => {
              return item.timeCodeChart
            }),
            series: [
              {
                name: "平均负荷",
                data: itemList.map((item) => {
                  return item.avg
                }),
              },
              {
                name: "最大负荷",
                data: itemList.map((item) => {
                  return item.max
                }),
              },
              {
                name: "最小负荷",
                data: itemList.map((item) => {
                  return item.min
                }),
              },
            ],
          }
        }
      }
    })
    .catch(() => {
      loading.value = false
    })
}
// ç¢³æŽ’放管理-碳排放量核算-搜索
function handleQuery() {
  getList()
}
// ç¢³æŽ’放管理-碳排放量核算-重置
function resetQuery() {
  proxy.resetForm("queryRef")
  queryParams.value.timeType = null
  queryParams.value.dataTime = null
  handleTimeType(period.value[0].value)
  handleQuery()
}
// ç¢³æŽ’放管理-碳排放量核算-导出
function handleExport() {
  proxy.download(
    "carbonEmission/export",
    {
      emissionType: "allType",
      ...queryParams.value,
      ...query.value,
    },
    `${queryParams.value.nodeName}-碳排放量核算_${new Date().getTime()}.xlsx`
  )
}
</script>
<style scoped lang="scss">
@import "@/assets/styles/page.scss";
.themeDark {
  .card-list {
    width: 100%;
    display: flex;
    flex-wrap: wrap;
    padding: 18px;
    color: #fff;
    .card-list-item {
      width: 19%;
      margin-right: 1%;
      height: 157px;
      background: #223386;
      border-radius: 5px 5px 5px 5px;
      border: 1px solid #4868b7;
      background-size: 100% 100%;
      box-sizing: border-box;
      padding: 25px 18px 12px 16px;
      .item-top {
        display: flex;
        align-items: center;
        .top-icon {
          width: 40px;
          height: 40px;
          background-size: 100% 100%;
        }
        .top-right {
          margin-left: 16px;
          font-weight: bold;
          font-size: 16px;
          font-family: OPPOSans-Bold;
        }
      }
      .item-bottom {
        display: flex;
        justify-content: space-between;
        margin-top: 18px;
        font-family: OPPOSans, OPPOSans;
        font-weight: bold;
        font-size: 14px;
      }
    }
  }
}
.themeLight {
  .card-list {
    width: 100%;
    display: flex;
    flex-wrap: wrap;
    padding: 18px;
    .card-list-item {
      width: 19%;
      margin-right: 1%;
      height: 157px;
      background: #fff;
      border-radius: 5px 5px 5px 5px;
      border: 1px solid #e8e8e8;
      background-size: 100% 100%;
      box-sizing: border-box;
      padding: 25px 18px 12px 16px;
      .item-top {
        display: flex;
        align-items: center;
        .top-icon {
          width: 40px;
          height: 40px;
          background-size: 100% 100%;
        }
        .top-right {
          margin-left: 16px;
          font-weight: bold;
          font-size: 16px;
          color: #000;
          font-family: OPPOSans-Bold;
        }
      }
      .item-bottom {
        display: flex;
        justify-content: space-between;
        margin-top: 18px;
        font-family: OPPOSans, OPPOSans;
        font-weight: bold;
        font-size: 14px;
      }
    }
  }
}
.chart-box {
  width: 100%;
  height: 100% !important;
}
.display-buttons {
  display: flex;
  justify-content: flex-end;
  align-items: center;
  margin-top: 16px;
  margin-right: 16px;
  .display-btn,
  .active-display-btn {
    width: 78px;
    height: 34px;
    background: #fff;
    color: #409eff;
    border: 2px solid #409eff;
    border-radius: 4px;
    margin-left: 10px;
    text-align: center;
    line-height: 31px;
    font-size: 14px;
    font-weight: 400;
    cursor: pointer;
    &:hover {
      opacity: 0.9;
    }
  }
  .active-display-btn {
    background: #409eff;
    color: #fff;
  }
}
</style>
zhitan-vue/src/views/dataMonitoring/historyDataTrend/index.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,337 @@
<template>
  <div class="page">
    <div class="page-container">
      <div class="page-container-left">
        <LeftTree ref="leftTreeRef" @handleNodeClick="handleNodeClick" />
      </div>
      <div class="page-container-right">
        <div>
          <BaseCard :title="queryParams.nodeName">
            <div class="form-card">
              <el-form :model="queryParams" ref="queryRef" :inline="true" label-width="40px">
                <el-form-item label=" " prop="timeType" label-width="0">
                  <el-radio-group v-model="queryParams.timeType" @change="changeTimeType">
                    <el-radio-button label="DAY">日</el-radio-button>
                    <el-radio-button label="HOUR">小时</el-radio-button>
                  </el-radio-group>
                </el-form-item>
                <el-form-item label="时间" prop="dataTime">
                  <el-date-picker
                    v-model="queryParams.dataTime"
                    :type="queryParams.timeType == 'DAY' ? 'date' : 'datetime'"
                    :format="queryParams.timeType == 'DAY' ? 'YYYY-MM-DD' : 'YYYY-MM-DD HH:00:00'"
                    :value-format="queryParams.timeType == 'DAY' ? 'YYYY-MM-DD' : 'YYYY-MM-DD HH:00:00'"
                    placeholder="时间"
                    style="width: 100%"
                  />
                </el-form-item>
                <el-form-item label="点位" prop="meterId">
                  <el-select v-model="queryParams.meterId" placeholder="选择点位" clearable style="width: 220px">
                    <el-option
                      v-for="dict in electricityMeter"
                      :key="dict.value"
                      :label="dict.label"
                      :value="dict.value"
                    />
                  </el-select>
                </el-form-item>
                <el-form-item>
                  <el-button type="primary" icon="Search" @click="handleQuery"> æœç´¢ </el-button>
                </el-form-item>
                <!-- <el-form-item>
              <el-button type="primary" icon="Download" @click="handleExport"> å¯¼å‡º </el-button>
            </el-form-item> -->
              </el-form>
            </div>
            <div class="display-buttons">
              <div class="display-btn" @click="activeKey = 1" :class="{ 'active-display-btn': activeKey === 1 }">
                å›¾å½¢
              </div>
              <div class="display-btn" @click="activeKey = 2" :class="{ 'active-display-btn': activeKey === 2 }">
                æ•°æ®
              </div>
            </div>
            <div class="chart-box" v-loading="loading" v-show="activeKey === 1">
              <LineChart ref="LineChartRef" :chartData="lineChartData" />
            </div>
            <div style="margin-top: 16px" v-show="activeKey === 2">
              <div class="" style="padding: 0 16px">
                <el-table :data="tableData" v-loading="loading" height="calc(100vh - 350px)">
                  <el-table-column label="点位名称" prop="indexName" align="center" />
                  <el-table-column label="点位值" prop="value" align="center" />
                  <el-table-column label="时间" prop="dataTime" align="center" />
                </el-table>
              </div>
            </div>
          </BaseCard>
        </div>
      </div>
    </div>
  </div>
</template>
<script setup name="loadAnalysis">
import { getHistoricalDataByIndexId, getEnergyIndexByModelId } from "@/api/realTimeMonitor/historyDataTrend.js"
import LineChart from "@/components/Echarts/LineChart.vue"
const { proxy } = getCurrentInstance()
import { useRoute } from "vue-router"
import useSettingsStore from "@/store/modules/settings"
const settingsStore = useSettingsStore()
watch(
  () => settingsStore.sideTheme,
  (val) => {
    getList()
  }
)
const activeKey = ref(1)
const loading = ref(false)
const tableData = ref([])
const lineChartData = ref({})
const electricityMeter = ref([])
const data = reactive({
  queryParams: {
    nodeId: null,
    nodeName: null,
    timeType: "DAY",
    dataTime: null,
    meterId: "",
  },
  query: { ...useRoute().query },
})
const { queryParams, query } = toRefs(data)
function getElectricityMeter(params) {
  getEnergyIndexByModelId(params).then((res) => {
    if (res.code === 200) {
      electricityMeter.value = res.data.map((item) => {
        return {
          ...item,
          label: item.indexName,
          value: item.indexId,
        }
      })
      queryParams.value.meterId = res.data.length > 0 ? res.data[0].indexId : ""
      getList()
    }
  })
}
/** èŠ‚ç‚¹å•å‡»äº‹ä»¶ */
function handleNodeClick(data) {
  queryParams.value.nodeId = data.id
  queryParams.value.nodeName = data.label
  setTimeout(() => {
    handleTimeType(queryParams.value.timeType)
  }, 200)
}
function handleTimeType(e) {
  queryParams.value.timeType = e
  queryParams.value.dataTime = proxy.dayjs(new Date()).format("YYYY-MM-DD HH:00:00")
  getElectricityMeter({ modelId: queryParams.value.nodeId })
}
function changeTimeType(e) {
  console.log(e)
  queryParams.value.dataTime = proxy.dayjs(new Date()).format("YYYY-MM-DD HH:00:00")
  getElectricityMeter({ modelId: queryParams.value.nodeId })
}
const LineChartRef = ref()
function getList() {
  loading.value = true
  let params = {
    nodeId: queryParams.value.nodeId,
    timeType: queryParams.value.timeType,
    dataTime: queryParams.value.dataTime,
    indexId: queryParams.value.meterId,
  }
  if (queryParams.value.timeType == "DAY") {
    params.timeCode = proxy.dayjs(new Date(queryParams.value.dataTime)).format("YYYY-MM-DD")
  } else if (queryParams.value.timeType == "MONTH") {
    params.timeCode = proxy.dayjs(new Date(queryParams.value.dataTime)).format("YYYY-MM")
  } else if (queryParams.value.timeType == "YEAR") {
    params.timeCode = proxy.dayjs(new Date(queryParams.value.dataTime)).format("YYYY")
  }
  getHistoricalDataByIndexId(params)
    .then((res) => {
      if (res.code == 200) {
        loading.value = false
        tableData.value = res.data
        let itemList = res.data
        lineChartData.value = {
          title: "",
          xAxis: itemList.map((item) => {
            return queryParams.value.timeType == "DAY"
              ? item.dataTime.slice(11, 13) + "时"
              : item.dataTime.slice(11, 16)
          }),
          series: [
            {
              name: "点位值",
              data: itemList.map((item) => {
                return item.value
              }),
            },
          ],
        }
      }
    })
    .catch(() => {
      loading.value = false
    })
}
// ç¢³æŽ’放管理-碳排放量核算-搜索
function handleQuery() {
  getList()
}
// ç¢³æŽ’放管理-碳排放量核算-重置
function resetQuery() {
  proxy.resetForm("queryRef")
  queryParams.value.timeType = null
  queryParams.value.dataTime = null
  handleQuery()
}
// ç¢³æŽ’放管理-碳排放量核算-导出
function handleExport() {
  proxy.download(
    "carbonEmission/export",
    {
      emissionType: "allType",
      ...queryParams.value,
      ...query.value,
    },
    `${queryParams.value.nodeName}-碳排放量核算_${new Date().getTime()}.xlsx`
  )
}
</script>
<style scoped lang="scss">
@import "@/assets/styles/page.scss";
.themeDark {
  .card-list {
    width: 100%;
    display: flex;
    flex-wrap: wrap;
    padding: 18px;
    color: #fff;
    .card-list-item {
      width: 19%;
      margin-right: 1%;
      height: 157px;
      background: #223386;
      border-radius: 5px 5px 5px 5px;
      border: 1px solid #4868b7;
      background-size: 100% 100%;
      box-sizing: border-box;
      padding: 25px 18px 12px 16px;
      .item-top {
        display: flex;
        align-items: center;
        .top-icon {
          width: 40px;
          height: 40px;
          background-size: 100% 100%;
        }
        .top-right {
          margin-left: 16px;
          font-weight: bold;
          font-size: 16px;
          font-family: OPPOSans-Bold;
        }
      }
      .item-bottom {
        display: flex;
        justify-content: space-between;
        margin-top: 18px;
        font-family: OPPOSans, OPPOSans;
        font-weight: bold;
        font-size: 14px;
      }
    }
  }
}
.themeLight {
  .card-list {
    width: 100%;
    display: flex;
    flex-wrap: wrap;
    padding: 18px;
    .card-list-item {
      width: 19%;
      margin-right: 1%;
      height: 157px;
      background: #fff;
      border-radius: 5px 5px 5px 5px;
      border: 1px solid #e8e8e8;
      background-size: 100% 100%;
      box-sizing: border-box;
      padding: 25px 18px 12px 16px;
      .item-top {
        display: flex;
        align-items: center;
        .top-icon {
          width: 40px;
          height: 40px;
          background-size: 100% 100%;
        }
        .top-right {
          margin-left: 16px;
          font-weight: bold;
          font-size: 16px;
          color: #000;
          font-family: OPPOSans-Bold;
        }
      }
      .item-bottom {
        display: flex;
        justify-content: space-between;
        margin-top: 18px;
        font-family: OPPOSans, OPPOSans;
        font-weight: bold;
        font-size: 14px;
      }
    }
  }
}
.chart-box {
  width: 100%;
  height: 100% !important;
}
.display-buttons {
  display: flex;
  justify-content: flex-end;
  align-items: center;
  margin-top: 16px;
  margin-right: 16px;
  .display-btn,
  .active-display-btn {
    width: 78px;
    height: 34px;
    background: #fff;
    color: #409eff;
    border: 2px solid #409eff;
    border-radius: 4px;
    margin-left: 10px;
    text-align: center;
    line-height: 31px;
    font-size: 14px;
    font-weight: 400;
    cursor: pointer;
    &:hover {
      opacity: 0.9;
    }
  }
  .active-display-btn {
    background: #409eff;
    color: #fff;
  }
}
</style>
zhitan-vue/src/views/energyefficiency/benchmarkmanage/benchmarkmanage.vue
@@ -1,122 +1,136 @@
<template>
    <div class="page">
        <div class="form-card">
            <el-form :model="form" ref="queryRef" :inline="true" label-width="85px">
                <el-form-item label="标杆编号" prop="code">
                    <el-input v-model="form.code" placeholder="请输入标杆编号" />
                </el-form-item>
                <el-form-item label="标杆类型" prop="type">
                    <el-select v-model="form.type" clearable>
                        <el-option v-for="dict in benchmark_type" :key="dict.value" :label="dict.label"
                            :value="dict.value" />
                    </el-select>
                </el-form-item>
                <el-form-item label="标杆等级" prop="grade">
                    <el-select v-model="form.grade" clearable>
                        <el-option v-for="dict in benchmark_grade" :key="dict.value" :label="dict.label"
                            :value="dict.value" />
                    </el-select>
                </el-form-item>
                <el-form-item>
                    <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
                    <el-button icon="Refresh" @click="resetQuery">重置</el-button>
                </el-form-item>
            </el-form>
        </div>
        <div class="table-box">
            <div class=" mt20 mb20">
                <el-button type="primary" icon="Plus" @click="handleAdd">新增</el-button>
            </div>
            <el-table :data="tableData" v-loading="loading">
                <el-table-column prop="code" label="标杆编号" show-overflow-tooltip align="center" />
                <el-table-column prop="type" label="标杆类型" show-overflow-tooltip align="center"
                    :formatter="(row, c) => proxy.selectDictLabel(benchmark_type, row.type)" />
                <el-table-column prop="grade" label="标杆等级" show-overflow-tooltip align="center"
                    :formatter="(row, c) => proxy.selectDictLabel(benchmark_grade, row.grade)" />
                <el-table-column prop="value" label="标杆值" show-overflow-tooltip align="center" />
                <el-table-column prop="nationalNum" label="国标编号" show-overflow-tooltip align="center" />
                <el-table-column prop="createBy" label="录入人" show-overflow-tooltip align="center" />
                <el-table-column prop="createTime" label="录入时间" show-overflow-tooltip align="center" />
                <el-table-column prop="remark" label="备注" show-overflow-tooltip align="center" />
                <el-table-column prop="active" label="操作" width="150" align="center">
                    <template #default="scope">
                        <el-button link type="primary" icon="Edit" @click="handleAdd(scope.row)">
                            ä¿®æ”¹
                        </el-button>
                        <el-button link type="primary" icon="Delete" @click="handleDel(scope.row)">
                            åˆ é™¤
                        </el-button>
                    </template>
                </el-table-column>
            </el-table>
            <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum"
                v-model:limit="queryParams.pageSize" @pagination="getList" />
        </div>
        <EditModal ref="EditModalRef" :benchmark_grade="benchmark_grade" :benchmark_type="benchmark_type"
            @getList="getList" />
  <div class="page">
    <div class="form-card">
      <el-form :model="form" ref="queryRef" :inline="true" label-width="85px">
        <el-form-item label="标杆编号" prop="code">
          <el-input v-model="form.code" placeholder="请输入标杆编号" />
        </el-form-item>
        <el-form-item label="标杆类型" prop="type">
          <el-select v-model="form.type" clearable>
            <el-option v-for="dict in benchmark_type" :key="dict.value" :label="dict.label" :value="dict.value" />
          </el-select>
        </el-form-item>
        <el-form-item label="标杆等级" prop="grade">
          <el-select v-model="form.grade" clearable>
            <el-option v-for="dict in benchmark_grade" :key="dict.value" :label="dict.label" :value="dict.value" />
          </el-select>
        </el-form-item>
        <el-form-item>
          <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
          <el-button icon="Refresh" @click="resetQuery">重置</el-button>
        </el-form-item>
      </el-form>
    </div>
    <div class="table-bg-style">
      <div class="theme-dark-mt20 mb20 ml20">
        <el-button type="primary" icon="Plus" @click="handleAdd">新增</el-button>
      </div>
      <div class="table-box">
        <el-table :data="tableData" v-loading="loading">
          <el-table-column prop="code" label="标杆编号" show-overflow-tooltip align="center" />
          <el-table-column
            prop="type"
            label="标杆类型"
            show-overflow-tooltip
            align="center"
            :formatter="(row, c) => proxy.selectDictLabel(benchmark_type, row.type)"
          />
          <el-table-column
            prop="grade"
            label="标杆等级"
            show-overflow-tooltip
            align="center"
            :formatter="(row, c) => proxy.selectDictLabel(benchmark_grade, row.grade)"
          />
          <el-table-column prop="value" label="标杆值" show-overflow-tooltip align="center" />
          <el-table-column prop="nationalNum" label="国标编号" show-overflow-tooltip align="center" />
          <el-table-column prop="createBy" label="录入人" show-overflow-tooltip align="center" />
          <el-table-column prop="createTime" label="录入时间" show-overflow-tooltip align="center" />
          <el-table-column prop="remark" label="备注" show-overflow-tooltip align="center" />
          <el-table-column prop="active" label="操作" width="150" align="center">
            <template #default="scope">
              <el-button link type="primary" icon="Edit" @click="handleAdd(scope.row)"> ä¿®æ”¹ </el-button>
              <el-button link type="primary" icon="Delete" @click="handleDel(scope.row)"> åˆ é™¤ </el-button>
            </template>
          </el-table-column>
        </el-table>
        <pagination
          v-show="total > 0"
          :total="total"
          v-model:page="queryParams.pageNum"
          v-model:limit="queryParams.pageSize"
          @pagination="getList"
        />
      </div>
    </div>
    <EditModal
      ref="EditModalRef"
      :benchmark_grade="benchmark_grade"
      :benchmark_type="benchmark_type"
      @getList="getList"
    />
  </div>
</template>
<script setup>
import EditModal from './components/EditModal.vue'
import { valueManageList, valueManageDel } from '@/api/benchmarkManage'
import EditModal from "./components/EditModal.vue"
import { valueManageList, valueManageDel } from "@/api/benchmarkManage"
let proxy = getCurrentInstance().proxy
let { benchmark_grade, benchmark_type } = proxy.useDict("benchmark_grade", 'benchmark_type')
let { benchmark_grade, benchmark_type } = proxy.useDict("benchmark_grade", "benchmark_type")
let form = ref({
    code: null,
    type: null,
    grade: null,
  code: null,
  type: null,
  grade: null,
})
function handleQuery() {
    queryParams.value.pageNum = 1
    getList()
  queryParams.value.pageNum = 1
  getList()
}
function resetQuery() {
    queryParams.value.pageNum = 1
    form.value = {}
    handleQuery();
  queryParams.value.pageNum = 1
  form.value = {}
  handleQuery()
}
let loading = ref(false);
let total = ref(0);
let loading = ref(false)
let total = ref(0)
let tableData = ref([])
let queryParams = ref({
    pageNum: 1,
    pageSize: 10,
  pageNum: 1,
  pageSize: 10,
})
function getList(flag) {
    loading.value = true
    valueManageList({ ...queryParams.value, ...form.value }).then(res => {
        tableData.value = res.rows
        total.value = res.total
        loading.value = false
    })
  loading.value = true
  valueManageList({ ...queryParams.value, ...form.value }).then((res) => {
    tableData.value = res.rows
    total.value = res.total
    loading.value = false
  })
}
getList()
let EditModalRef = ref('')
let EditModalRef = ref("")
function handleAdd(row) {
    if (EditModalRef.value) {
        EditModalRef.value.handleOpen(row)
    }
  if (EditModalRef.value) {
    EditModalRef.value.handleOpen(row)
  }
}
function handleDel(row) {
    proxy.$modal.confirm('是否确认删除数据项?').then(function () {
        return valueManageDel(row.id);
    }).then(() => {
        getList();
        proxy.$modal.msgSuccess("删除成功");
    }).catch(() => { });
  proxy.$modal
    .confirm("是否确认删除数据项?")
    .then(function () {
      return valueManageDel(row.id)
    })
    .then(() => {
      getList()
      proxy.$modal.msgSuccess("删除成功")
    })
    .catch(() => {})
}
</script>
<style lang="scss" scoped>
@import "@/assets/styles/page.scss";
zhitan-vue/src/views/index.vue
@@ -20,10 +20,11 @@
              <div class="top-right">
                <div class="right-name">
                  {{ item.energyName }}
                  <span v-if="item.energyUnit" class="unit">({{ item.energyUnit }})</span>
                </div>
                <div class="right-value">
                  <span> {{ item.count }}</span>
                  <span class="unit">{{ item.energyUnit }}</span>
                  <!-- <span class="unit">{{ item.energyUnit }}</span> -->
                </div>
              </div>
            </div>
@@ -889,18 +890,23 @@
          display: flex;
          .top-icon {
            width: 69px;
            height: 69px;
            width: 50px;
            height: 50px;
            background-size: 100% 100%;
          }
          .top-right {
            margin-left: 16px;
            margin-left: 12px;
            .right-name {
              font-weight: bold;
              font-size: 16px;
              font-family: OPPOSans-Bold;
              .unit {
                margin-left: 2px;
                font-size: 16px;
                font-weight: normal;
              }
            }
            .right-value {
zhitan-vue/src/views/modelconfiguration/indexwarehouse/indexWarehouse.vue
@@ -5,38 +5,44 @@
        <div class="tree page-box">
          <!-- <CardHeader class="mb20">用能单元结构</CardHeader> -->
          <!-- <el-input v-model="filterText" style="width: 240px" placeholder="输入关键字进行过滤" class="mb10" /> -->
          <el-tree ref="treeRef" :props="defaultProps" :data="treeData" node-key="id" highlight-current
            :filter-node-method="filterNode" :default-expanded-keys="treeExpandData" :expand-on-click-node="false"
            @node-click="changeNode" accordion>
          <el-tree
            ref="treeRef"
            :props="defaultProps"
            :data="treeData"
            node-key="id"
            highlight-current
            :filter-node-method="filterNode"
            :default-expanded-keys="treeExpandData"
            :expand-on-click-node="false"
            @node-click="changeNode"
            accordion
          >
            <template #default="{ node, data }">
              <span>
                <el-tooltip v-if="node.label.length > 6" class="item" effect="dark" :content="node.label"
                  placement="top-end">
                <el-tooltip
                  v-if="node.label.length > 6"
                  class="item"
                  effect="dark"
                  :content="node.label"
                  placement="top-end"
                >
                  <span>{{ node.label.slice(0, 6) + "..." }}</span>
                </el-tooltip>
                <span v-else id="b">{{ node.label }}</span>
              </span>
              <span class="node-opt">
                <el-link title="新增下级节点" icon="Plus" @click="() => addNode(node, data)">
                </el-link>
                <el-link title="修改节点" icon="EditPen" @click="() => editNode(node, data)">
                </el-link>
                <el-link title="删除节点" icon="Delete" @click="() => delNode(node, data)">
                </el-link>
                <el-link title="新增下级节点" icon="Plus" @click="() => addNode(node, data)"> </el-link>
                <el-link title="修改节点" icon="EditPen" @click="() => editNode(node, data)"> </el-link>
                <el-link title="删除节点" icon="Delete" @click="() => delNode(node, data)"> </el-link>
              </span>
            </template>
          </el-tree>
        </div>
      </div>
      <div class="page-container-right">
        <div class="mb20 mt20 ml20 tab-box">
          <div class="tab-li" :class="tab == 1 ? 'is-tab' : ''" @click="handleTab('1')">
            è®¡é‡å™¨å…·é…ç½®ä¿¡æ¯
          </div>
          <div class="tab-li" :class="tab == 2 ? 'is-tab' : ''" @click="handleTab('2')">
            ç»Ÿè®¡æŒ‡æ ‡
          </div>
          <div class="tab-li" :class="tab == 1 ? 'is-tab' : ''" @click="handleTab('1')">计量器具配置信息</div>
          <div class="tab-li" :class="tab == 2 ? 'is-tab' : ''" @click="handleTab('2')">统计指标</div>
          <!-- <el-radio-group v-model="tab">
                                <el-radio-button label="1" @click="handleTab('1')"> è®¾å¤‡é…ç½®</el-radio-button>
                                <el-radio-button label="2" @click="handleTab('2')"> é‡‡é›†æŒ‡æ ‡</el-radio-button>
@@ -45,10 +51,10 @@
        <BaseCard :title="currentNode ? currentNode.label + '--节点配置' : '暂无节点配置'">
          <div>
            <div class="content-box" v-if="tab == '1'">
              <deviceConfig ref='deviceConfigRef' />
              <deviceConfig ref="deviceConfigRef" />
            </div>
            <div class="content-box1" v-if="tab == '2'">
              <statisticalIndicatorManagement ref='statisticalIndicatorManagementRef' :indexType='"STATISTIC"' />
              <statisticalIndicatorManagement ref="statisticalIndicatorManagementRef" :indexType="'STATISTIC'" />
            </div>
          </div>
        </BaseCard>
@@ -56,18 +62,22 @@
        <!-- <statisticalIndicatorManagement ref="statisticalIndicatorManagementRef" :indexType='"STATISTIC"' /> -->
      </div>
    </div>
    <treeNodeModal ref="treeNodeModalRef" @getList="getTreeList" modelCode="JCZBK_CODE" @addTreeList="addTreeList"
      @addTreeSelectList="addTreeSelectList" />
    <treeNodeModal
      ref="treeNodeModalRef"
      @getList="getTreeList"
      modelCode="JCZBK_CODE"
      @addTreeList="addTreeList"
      @addTreeSelectList="addTreeSelectList"
    />
  </div>
</template>
<script setup>
import treeNodeModal from './components/TreeNodeModal.vue'
import deviceConfig from './components/deviceConfig/DeviceConfig.vue'
import statisticalIndicatorManagement from './components/statisticalIndicatorManagement/statisticalIndicatorManagement.vue';
import { treeList, delModelNode, hasEnergyIndex, } from '@/api/modelConfiguration/indexWarehouse'
const { proxy } = getCurrentInstance();
import treeNodeModal from "./components/TreeNodeModal.vue"
import deviceConfig from "./components/deviceConfig/DeviceConfig.vue"
import statisticalIndicatorManagement from "./components/statisticalIndicatorManagement/statisticalIndicatorManagement.vue"
import { treeList, delModelNode, hasEnergyIndex } from "@/api/modelConfiguration/indexWarehouse"
const { proxy } = getCurrentInstance()
let currentNode = ref()
let treeRef = ref()
@@ -75,12 +85,12 @@
let treeData = ref([])
const defaultProps = ref({
  children: 'children',
  label: 'label',
  children: "children",
  label: "label",
})
//检索树
let filterText = ref('')
let filterText = ref("")
const filterNode = (value, data) => {
  if (!value) return true
@@ -88,14 +98,14 @@
}
watch(filterText, (val) => {
  // æ£€æŸ¥treeRef.value是否是一个有效的ElTree实例
  if (treeRef.value && typeof treeRef.value.filter === 'function') {
  if (treeRef.value && typeof treeRef.value.filter === "function") {
    // è°ƒç”¨filter方法
    treeRef.value.filter(val);
    treeRef.value.filter(val)
  } else {
    // treeRef.value无效,处理错误
    console.error('error');
    console.error("error")
  }
});
})
let treeExpandData = ref([])
let isFirstLeafNode = ref(false)
@@ -103,32 +113,31 @@
let statisticalIndicatorManagementRef = ref(null)
//获取树列表
function getTreeList() {
  treeList({ modelCode: 'JCZBK_CODE' }).then(res => {
  treeList({ modelCode: "JCZBK_CODE" }).then((res) => {
    let { data } = res
    treeData.value = data;
    let chooseNode = null;
    treeData.value = data
    let chooseNode = null
    if (data.length > 0) {
      if (data[0].children && data[0].children.length !== 0 && isFirstLeafNode.value) {
        if (data[0].children[0].children && data[0].children[0].children.length !== 0) {
          chooseNode = data[0].children[0].children[0];
          chooseNode = data[0].children[0].children[0]
        } else {
          chooseNode = data[0].children[0];
          chooseNode = data[0].children[0]
        }
      } else {
        chooseNode = data[0];
        chooseNode = data[0]
      }
      currentNode.value = chooseNode;
      treeExpandData.value.push(chooseNode.id);
      currentNode.value = chooseNode
      treeExpandData.value.push(chooseNode.id)
      nextTick(() => {
        treeRef.value.setCurrentKey(chooseNode.id);
        treeRef.value.setCurrentKey(chooseNode.id)
        if (tab.value == 1 && deviceConfigRef.value) {
          deviceConfigRef.value.getList(chooseNode)
        }
        if (tab.value == 2 && statisticalIndicatorManagementRef.value) {
          statisticalIndicatorManagementRef.value.getList(chooseNode)
        }
      });
      })
    }
  })
}
@@ -143,7 +152,7 @@
  treeExpandData.value.push(addedNode.nodeId)
  nextTick(() => {
    treeRef.value.setCurrentNode(newChild)
    currentNode.value = newChild;
    currentNode.value = newChild
    if (tab.value == 1) {
      if (deviceConfigRef.value) {
        deviceConfigRef.value.getList(newChild)
@@ -155,11 +164,10 @@
      }
    }
  })
}
//树点击
function changeNode(data, node, ev) {
  currentNode.value = data;
  currentNode.value = data
  if (tab.value == 1) {
    if (deviceConfigRef.value) {
      deviceConfigRef.value.getList(data)
@@ -171,7 +179,6 @@
    }
  }
}
let treeNodeModalRef = ref(null)
@@ -188,26 +195,27 @@
function delNode(node, data) {
  if (data.children && data.children.length > 0) {
    proxy.$modal.msgWarning('包含子节点,不能进行删除!')
    proxy.$modal.msgWarning("包含子节点,不能进行删除!")
    return
  }
  hasEnergyIndex(data.id).then(response => {
  hasEnergyIndex(data.id).then((response) => {
    if (response.data) {
      proxy.$modal.msgWarning('当前节点下存在指标,不能进行删除!')
      proxy.$modal.msgWarning("当前节点下存在指标,不能进行删除!")
    } else {
      proxy.$modal.confirm('是否确认删除名为"' + data.label + '"的节点?', '警告', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      })
      proxy.$modal
        .confirm('是否确认删除名为"' + data.label + '"的节点?', "警告", {
          confirmButtonText: "确定",
          cancelButtonText: "取消",
          type: "warning",
        })
        .then(function () {
          return delModelNode(data.id)
        })
        .then(() => {
          let parent = node.parent
          let children = parent.data.children || parent.data
          let index = children.findIndex(d => d.id === data.id)
          let index = children.findIndex((d) => d.id === data.id)
          children.splice(index, 1)
          nextTick(() => {
@@ -217,10 +225,9 @@
              changeNode(null)
            }
          })
          proxy.$modal.msgSuccess('删除成功')
          proxy.$modal.msgSuccess("删除成功")
        })
        .catch(function () {
        })
        .catch(function () {})
    }
  })
}
@@ -234,15 +241,12 @@
    if (value == 2 && statisticalIndicatorManagementRef.value) {
      statisticalIndicatorManagementRef.value.getList(currentNode.value)
    }
  });
  })
}
</script>
<style lang="scss" scoped>
@import "@/assets/styles/page.scss";
.page-box {
  height: calc(100vh - 145px);
@@ -276,8 +280,6 @@
      margin-right: 5px;
    }
  }
}
:deep .el-tabs__nav-wrap:after {
@@ -298,29 +300,40 @@
.tab-box {
  display: flex;
  align-items: center;
  color: #fff;
  border-bottom: 1px solid #3371EB;
  color: #333;
  border-bottom: 1px solid #3371eb;
  margin-right: 20px;
  .tab-li {
    cursor: pointer;
    border: 1px solid #3371EB;
    border: 1px solid #3371eb;
    padding: 10px 25px;
    border-radius: 5px 5px 0 0;
  }
  .is-tab {
    background: #3371EB;
    background: #3371eb;
    color: #fff;
  }
}
.themeDark {
  .tab-box {
    color: #fff;
  }
}
.themeLight {
  .tab-box {
    color: #333;
  }
}
.content-box {
  height: calc(100vh - 310px) !important;
}
.content-box1 {
  height: calc(100vh - 290px) !important;
}
</style>
zhitan-vue/src/views/peakvalley/period/period.vue
@@ -555,16 +555,21 @@
    display: flex;
    justify-content: space-between;
    padding: 18px;
    width: 100%;
    overflow: hidden;
    overflow-x: auto;
    .card-list-item {
      width: 19%;
      height: 187px;
      flex-shrink: 0;
      width: 230px;
      height: 188px;
      background: #223386;
      border-radius: 5px 5px 5px 5px;
      border: 1px solid #4868b7;
      background-size: 100% 100%;
      box-sizing: border-box;
      padding: 10px 18px 13px 16px;
      margin-right: 12px;
      .item-top {
        display: flex;
zhitan-vue/src/views/powerquality/load/index.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,402 @@
<template>
  <div class="page">
    <div class="page-container">
      <div class="page-container-left">
        <LeftTree ref="leftTreeRef" @handleNodeClick="handleNodeClick" />
      </div>
      <div class="page-container-right">
        <div
          style="height: calc(100vh - 150px) !important; max-height: calc(100vh - 150px) !important; overflow-y: auto"
        >
          <BaseCard :title="queryParams.nodeName + '-负荷分析'">
            <div class="form-card">
              <el-form :model="queryParams" ref="queryRef" :inline="true">
                <el-form-item label="期间" prop="timeType">
                  <el-select
                    v-model="queryParams.timeType"
                    placeholder="期间"
                    clearable
                    style="width: 120px"
                    @change="handleTimeType"
                  >
                    <el-option v-for="dict in period" :key="dict.value" :label="dict.label" :value="dict.value" />
                  </el-select>
                </el-form-item>
                <el-form-item label="时间" prop="dataTime">
                  <el-date-picker
                    v-model="queryParams.dataTime"
                    :type="queryParams.timeType == 'YEAR' ? 'year' : queryParams.timeType == 'MONTH' ? 'month' : 'date'"
                    :format="
                      queryParams.timeType == 'YEAR'
                        ? 'YYYY'
                        : queryParams.timeType == 'MONTH'
                        ? 'YYYY-MM'
                        : 'YYYY-MM-DD'
                    "
                    value-format="YYYY-MM-DD"
                    placeholder="时间"
                    style="width: 100%"
                  />
                </el-form-item>
                <el-form-item label="选择电表" prop="meterId">
                  <el-select v-model="queryParams.meterId" placeholder="选择电表" clearable style="width: 200px">
                    <el-option
                      v-for="dict in electricityMeter"
                      :key="dict.value"
                      :label="dict.label"
                      :value="dict.value"
                    />
                  </el-select>
                </el-form-item>
                <el-form-item>
                  <el-button type="primary" icon="Search" @click="handleQuery"> æœç´¢ </el-button>
                </el-form-item>
                <!-- <el-form-item>
              <el-button type="primary" icon="Download" @click="handleExport"> å¯¼å‡º </el-button>
            </el-form-item> -->
              </el-form>
            </div>
            <div class="display-buttons">
              <div class="display-btn" @click="activeKey = 1" :class="{ 'active-display-btn': activeKey === 1 }">
                å›¾å½¢
              </div>
              <div class="display-btn" @click="activeKey = 2" :class="{ 'active-display-btn': activeKey === 2 }">
                æ•°æ®
              </div>
            </div>
            <div class="chart-box" v-loading="loading" v-show="activeKey === 1">
              <LineChart ref="LineChartRef" :chartData="lineChartData" />
              <div style="padding: 16px">
                <el-descriptions title="" size="large" border :column="2">
                  <el-descriptions-item label="最大负荷">
                    {{ detailData.max || "--" }}
                  </el-descriptions-item>
                  <el-descriptions-item label="发生时间">
                    {{ detailData.maxTime || "" }}
                  </el-descriptions-item>
                  <el-descriptions-item label="最小负荷">
                    {{ detailData.min || "--" }}
                  </el-descriptions-item>
                  <el-descriptions-item label="发生时间">
                    {{ detailData.minTime || "--" }}
                  </el-descriptions-item>
                  <el-descriptions-item label="平均负荷">
                    {{ detailData.avg || "--" }}
                  </el-descriptions-item>
                  <el-descriptions-item label="负荷率">
                    {{ detailData.rate || "" }}
                  </el-descriptions-item>
                </el-descriptions>
              </div>
            </div>
            <div style="margin-top: 16px" v-show="activeKey === 2">
              <div class="" style="padding: 0 16px">
                <el-table :data="tableData" v-loading="loading" height="calc(100vh - 400px)">
                  <el-table-column label="时间" prop="timeCode" align="center" />
                  <el-table-column label="电表名称" prop="name" align="center" />
                  <el-table-column v-if="queryParams.timeType == 'DAY'" label="负荷" prop="value" align="center" />
                  <el-table-column v-if="queryParams.timeType != 'DAY'" label="最大负荷" prop="max" align="center" />
                  <el-table-column v-if="queryParams.timeType != 'DAY'" label="最小负荷" prop="min" align="center" />
                  <el-table-column v-if="queryParams.timeType != 'DAY'" label="平均负荷" prop="avg" align="center" />
                  <el-table-column v-if="queryParams.timeType != 'DAY'" label="负荷率(%)" prop="rate" align="center" />
                </el-table>
              </div>
            </div>
          </BaseCard>
        </div>
      </div>
    </div>
  </div>
</template>
<script setup name="loadAnalysis">
import { loadAnalysisDetail, listElectricityDeviceMeter } from "@/api/powerquality/load-analysis/api.js"
import LineChart from "@/components/Echarts/LineChart.vue"
const { proxy } = getCurrentInstance()
import { useRoute } from "vue-router"
const { period } = proxy.useDict("period")
import useSettingsStore from "@/store/modules/settings"
const settingsStore = useSettingsStore()
watch(
  () => settingsStore.sideTheme,
  (val) => {
    getList()
  }
)
const activeKey = ref(1)
const loading = ref(false)
const tableData = ref([])
const detailData = ref({})
const lineChartData = ref({})
const electricityMeter = ref([])
const data = reactive({
  queryParams: {
    nodeId: null,
    nodeName: null,
    timeType: null,
    dataTime: null,
    meterId: "",
  },
  query: { ...useRoute().query },
})
const { queryParams, query } = toRefs(data)
function getElectricityMeter(params) {
  listElectricityDeviceMeter(params).then((res) => {
    if (res.code === 200) {
      electricityMeter.value = res.data.map((item) => {
        return {
          ...item,
          value: item.code,
        }
      })
      queryParams.value.meterId = res.data.length > 0 ? res.data[0].code : ""
      getList()
    }
  })
}
/** èŠ‚ç‚¹å•å‡»äº‹ä»¶ */
function handleNodeClick(data) {
  queryParams.value.nodeId = data.id
  queryParams.value.nodeName = data.label
  setTimeout(() => {
    handleTimeType(period.value[0].value)
  }, 200)
}
function handleTimeType(e) {
  queryParams.value.timeType = e
  queryParams.value.dataTime = proxy.dayjs(new Date()).format("YYYY-MM-DD")
  getElectricityMeter({ nodeId: queryParams.value.nodeId })
}
const LineChartRef = ref()
function getList() {
  loading.value = true
  let params = {
    nodeId: queryParams.value.nodeId,
    timeType: queryParams.value.timeType,
    timeCode: queryParams.value.dataTime,
    meterId: queryParams.value.meterId,
  }
  if (queryParams.value.timeType == "DAY") {
    params.timeCode = proxy.dayjs(new Date(queryParams.value.dataTime)).format("YYYY-MM-DD")
  } else if (queryParams.value.timeType == "MONTH") {
    params.timeCode = proxy.dayjs(new Date(queryParams.value.dataTime)).format("YYYY-MM")
  } else if (queryParams.value.timeType == "YEAR") {
    params.timeCode = proxy.dayjs(new Date(queryParams.value.dataTime)).format("YYYY")
  }
  loadAnalysisDetail(params)
    .then((res) => {
      if (res.code == 200) {
        loading.value = false
        tableData.value = res.data.itemList
        detailData.value = res.data.detail
        let itemList = res.data.itemList
        if (queryParams.value.timeType == "DAY") {
          lineChartData.value = {
            title: "负荷分析",
            xAxis: itemList.map((item) => {
              return item.timeCode.slice(item.timeCode.length - 2, item.timeCode.length) + "时"
            }),
            series: [
              {
                name: "负荷值",
                data: itemList.map((item) => {
                  return item.value
                }),
              },
            ],
          }
        } else {
          lineChartData.value = {
            title: "负荷分析",
            xAxis: itemList.map((item) => {
              return item.timeCodeChart
            }),
            series: [
              {
                name: "平均负荷",
                data: itemList.map((item) => {
                  return item.avg
                }),
              },
              {
                name: "最大负荷",
                data: itemList.map((item) => {
                  return item.max
                }),
              },
              {
                name: "最小负荷",
                data: itemList.map((item) => {
                  return item.min
                }),
              },
            ],
          }
        }
      }
    })
    .catch(() => {
      loading.value = false
    })
}
// ç¢³æŽ’放管理-碳排放量核算-搜索
function handleQuery() {
  getList()
}
// ç¢³æŽ’放管理-碳排放量核算-重置
function resetQuery() {
  proxy.resetForm("queryRef")
  queryParams.value.timeType = null
  queryParams.value.dataTime = null
  handleTimeType(period.value[0].value)
  handleQuery()
}
// ç¢³æŽ’放管理-碳排放量核算-导出
function handleExport() {
  proxy.download(
    "carbonEmission/export",
    {
      emissionType: "allType",
      ...queryParams.value,
      ...query.value,
    },
    `${queryParams.value.nodeName}-碳排放量核算_${new Date().getTime()}.xlsx`
  )
}
</script>
<style scoped lang="scss">
@import "@/assets/styles/page.scss";
.themeDark {
  .card-list {
    width: 100%;
    display: flex;
    flex-wrap: wrap;
    padding: 18px;
    color: #fff;
    .card-list-item {
      width: 19%;
      margin-right: 1%;
      height: 157px;
      background: #223386;
      border-radius: 5px 5px 5px 5px;
      border: 1px solid #4868b7;
      background-size: 100% 100%;
      box-sizing: border-box;
      padding: 25px 18px 12px 16px;
      .item-top {
        display: flex;
        align-items: center;
        .top-icon {
          width: 40px;
          height: 40px;
          background-size: 100% 100%;
        }
        .top-right {
          margin-left: 16px;
          font-weight: bold;
          font-size: 16px;
          font-family: OPPOSans-Bold;
        }
      }
      .item-bottom {
        display: flex;
        justify-content: space-between;
        margin-top: 18px;
        font-family: OPPOSans, OPPOSans;
        font-weight: bold;
        font-size: 14px;
      }
    }
  }
}
.themeLight {
  .card-list {
    width: 100%;
    display: flex;
    flex-wrap: wrap;
    padding: 18px;
    .card-list-item {
      width: 19%;
      margin-right: 1%;
      height: 157px;
      background: #fff;
      border-radius: 5px 5px 5px 5px;
      border: 1px solid #e8e8e8;
      background-size: 100% 100%;
      box-sizing: border-box;
      padding: 25px 18px 12px 16px;
      .item-top {
        display: flex;
        align-items: center;
        .top-icon {
          width: 40px;
          height: 40px;
          background-size: 100% 100%;
        }
        .top-right {
          margin-left: 16px;
          font-weight: bold;
          font-size: 16px;
          color: #000;
          font-family: OPPOSans-Bold;
        }
      }
      .item-bottom {
        display: flex;
        justify-content: space-between;
        margin-top: 18px;
        font-family: OPPOSans, OPPOSans;
        font-weight: bold;
        font-size: 14px;
      }
    }
  }
}
.chart-box {
  width: 100%;
  height: 100% !important;
}
.display-buttons {
  display: flex;
  justify-content: flex-end;
  align-items: center;
  margin-top: 16px;
  margin-right: 16px;
  .display-btn,
  .active-display-btn {
    width: 78px;
    height: 34px;
    background: #fff;
    color: #409eff;
    border: 2px solid #409eff;
    border-radius: 4px;
    margin-left: 10px;
    text-align: center;
    line-height: 31px;
    font-size: 14px;
    font-weight: 400;
    cursor: pointer;
    &:hover {
      opacity: 0.9;
    }
  }
  .active-display-btn {
    background: #409eff;
    color: #fff;
  }
}
</style>
zhitan-vue/src/views/powerquality/power/index.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,331 @@
<template>
  <div class="page">
    <div class="page-container">
      <div class="page-container-left">
        <LeftTree ref="leftTreeRef" @handleNodeClick="handleNodeClick" />
      </div>
      <div class="page-container-right">
        <div
          style="height: calc(100vh - 150px) !important; max-height: calc(100vh - 150px) !important; overflow-y: auto"
        >
          <BaseCard :title="queryParams.nodeName + '-功率因数分析'">
            <div class="form-card">
              <el-form :model="queryParams" ref="queryRef" :inline="true">
                <el-form-item label="时间" prop="dataTime">
                  <el-date-picker
                    v-model="queryParams.dataTime"
                    :type="queryParams.timeType == 'YEAR' ? 'year' : queryParams.timeType == 'MONTH' ? 'month' : 'date'"
                    :format="
                      queryParams.timeType == 'YEAR'
                        ? 'YYYY'
                        : queryParams.timeType == 'MONTH'
                        ? 'YYYY-MM'
                        : 'YYYY-MM-DD'
                    "
                    value-format="YYYY-MM-DD"
                    placeholder="时间"
                    style="width: 100%"
                  />
                </el-form-item>
                <el-form-item label="选择电表" prop="meterId">
                  <el-select v-model="queryParams.meterId" placeholder="选择电表" clearable style="width: 200px">
                    <el-option
                      v-for="dict in electricityMeter"
                      :key="dict.value"
                      :label="dict.label"
                      :value="dict.value"
                    />
                  </el-select>
                </el-form-item>
                <el-form-item>
                  <el-button type="primary" icon="Search" @click="handleQuery"> æœç´¢ </el-button>
                </el-form-item>
                <!-- <el-form-item>
              <el-button type="primary" icon="Download" @click="handleExport"> å¯¼å‡º </el-button>
            </el-form-item> -->
              </el-form>
            </div>
            <div class="chart-box" v-loading="loading">
              <LineChart ref="LineChartRef" :chartData="lineChartData" />
              <div style="padding: 16px">
                <el-table :data="tableData" v-loading="loading">
                  <el-table-column label="功率因数" prop="title" align="center" />
                  <el-table-column label="最大值" prop="max" align="center" />
                  <el-table-column label="最小值" prop="min" align="center" />
                  <el-table-column label="平均值" prop="avg" align="center" />
                </el-table>
              </div>
            </div>
          </BaseCard>
        </div>
      </div>
    </div>
  </div>
</template>
<script setup name="loadAnalysis">
import { powerFactorAnalysisDetail } from "@/api/powerquality/electric-power-factor/api.js"
import { listElectricityDeviceMeter } from "@/api/powerquality/load-analysis/api.js"
import LineChart from "@/components/Echarts/LineChart.vue"
const { proxy } = getCurrentInstance()
import { useRoute } from "vue-router"
import useSettingsStore from "@/store/modules/settings"
const settingsStore = useSettingsStore()
watch(
  () => settingsStore.sideTheme,
  (val) => {
    getList()
  }
)
const loading = ref(false)
const tableData = ref([])
const lineChartData = ref({})
const electricityMeter = ref([])
const data = reactive({
  queryParams: {
    nodeId: null,
    nodeName: null,
    timeType: "DAY",
    dataTime: proxy.dayjs(new Date()).format("YYYY-MM-DD"),
    meterId: "",
  },
  query: { ...useRoute().query },
})
const { queryParams, query } = toRefs(data)
function getElectricityMeter(params) {
  listElectricityDeviceMeter(params).then((res) => {
    if (res.code === 200) {
      electricityMeter.value = res.data.map((item) => {
        return {
          ...item,
          value: item.code,
        }
      })
      queryParams.value.meterId = res.data.length > 0 ? res.data[0].code : ""
      getList()
    }
  })
}
/** èŠ‚ç‚¹å•å‡»äº‹ä»¶ */
function handleNodeClick(data) {
  queryParams.value.nodeId = data.id
  queryParams.value.nodeName = data.label
  getElectricityMeter({ nodeId: queryParams.value.nodeId })
}
const LineChartRef = ref()
function getList() {
  loading.value = true
  let params = {
    nodeId: queryParams.value.nodeId,
    timeType: queryParams.value.timeType,
    timeCode: queryParams.value.dataTime,
    meterId: queryParams.value.meterId,
  }
  if (queryParams.value.timeType == "DAY") {
    params.timeCode = proxy.dayjs(new Date(queryParams.value.dataTime)).format("YYYY-MM-DD")
  } else if (queryParams.value.timeType == "MONTH") {
    params.timeCode = proxy.dayjs(new Date(queryParams.value.dataTime)).format("YYYY-MM")
  } else if (queryParams.value.timeType == "YEAR") {
    params.timeCode = proxy.dayjs(new Date(queryParams.value.dataTime)).format("YYYY")
  }
  powerFactorAnalysisDetail(params)
    .then((res) => {
      if (res.code == 200) {
        loading.value = false
        let detailData = res.data.detail
        tableData.value = [
          {
            title: "发生值",
            max: detailData.max,
            min: detailData.min,
            avg: detailData.avg,
          },
          {
            title: "发生时间",
            max: detailData.maxTime,
            min: detailData.minTime,
            avg: "--",
          },
        ]
        detailData.value = res.data.detail
        let itemList = res.data.itemList
        lineChartData.value = {
          title: "功率因数分析",
          xAxis: itemList.map((item) => {
            return item.timeCode.slice(0, 2) + "时"
          }),
          series: [
            {
              name: "功率因数",
              data: itemList.map((item) => {
                return item.value
              }),
            },
          ],
        }
      }
    })
    .catch(() => {
      loading.value = false
    })
}
// ç¢³æŽ’放管理-碳排放量核算-搜索
function handleQuery() {
  getList()
}
// ç¢³æŽ’放管理-碳排放量核算-重置
function resetQuery() {
  proxy.resetForm("queryRef")
  queryParams.value.timeType = null
  queryParams.value.dataTime = null
  handleQuery()
}
// ç¢³æŽ’放管理-碳排放量核算-导出
function handleExport() {
  proxy.download(
    "carbonEmission/export",
    {
      emissionType: "allType",
      ...queryParams.value,
      ...query.value,
    },
    `${queryParams.value.nodeName}-碳排放量核算_${new Date().getTime()}.xlsx`
  )
}
</script>
<style scoped lang="scss">
@import "@/assets/styles/page.scss";
.themeDark {
  .card-list {
    width: 100%;
    display: flex;
    flex-wrap: wrap;
    padding: 18px;
    color: #fff;
    .card-list-item {
      width: 19%;
      margin-right: 1%;
      height: 157px;
      background: #223386;
      border-radius: 5px 5px 5px 5px;
      border: 1px solid #4868b7;
      background-size: 100% 100%;
      box-sizing: border-box;
      padding: 25px 18px 12px 16px;
      .item-top {
        display: flex;
        align-items: center;
        .top-icon {
          width: 40px;
          height: 40px;
          background-size: 100% 100%;
        }
        .top-right {
          margin-left: 16px;
          font-weight: bold;
          font-size: 16px;
          font-family: OPPOSans-Bold;
        }
      }
      .item-bottom {
        display: flex;
        justify-content: space-between;
        margin-top: 18px;
        font-family: OPPOSans, OPPOSans;
        font-weight: bold;
        font-size: 14px;
      }
    }
  }
}
.themeLight {
  .card-list {
    width: 100%;
    display: flex;
    flex-wrap: wrap;
    padding: 18px;
    .card-list-item {
      width: 19%;
      margin-right: 1%;
      height: 157px;
      background: #fff;
      border-radius: 5px 5px 5px 5px;
      border: 1px solid #e8e8e8;
      background-size: 100% 100%;
      box-sizing: border-box;
      padding: 25px 18px 12px 16px;
      .item-top {
        display: flex;
        align-items: center;
        .top-icon {
          width: 40px;
          height: 40px;
          background-size: 100% 100%;
        }
        .top-right {
          margin-left: 16px;
          font-weight: bold;
          font-size: 16px;
          color: #000;
          font-family: OPPOSans-Bold;
        }
      }
      .item-bottom {
        display: flex;
        justify-content: space-between;
        margin-top: 18px;
        font-family: OPPOSans, OPPOSans;
        font-weight: bold;
        font-size: 14px;
      }
    }
  }
}
.chart-box {
  width: 100%;
  height: 100% !important;
}
.display-buttons {
  display: flex;
  justify-content: flex-end;
  align-items: center;
  margin-top: 16px;
  margin-right: 16px;
  .display-btn,
  .active-display-btn {
    width: 78px;
    height: 34px;
    background: #fff;
    color: #409eff;
    border: 2px solid #409eff;
    border-radius: 4px;
    margin-left: 10px;
    text-align: center;
    line-height: 31px;
    font-size: 14px;
    font-weight: 400;
    cursor: pointer;
    &:hover {
      opacity: 0.9;
    }
  }
  .active-display-btn {
    background: #409eff;
    color: #fff;
  }
}
</style>
zhitan-vue/src/views/powerquality/threephase/index.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,503 @@
<template>
  <div class="page">
    <div class="page-container">
      <div class="page-container-left">
        <LeftTree ref="leftTreeRef" @handleNodeClick="handleNodeClick" />
      </div>
      <div class="page-container-right">
        <div
          style="height: calc(100vh - 150px) !important; max-height: calc(100vh - 150px) !important; overflow-y: auto"
        >
          <BaseCard :title="queryParams.nodeName + '-三相不平衡分析'">
            <div class="form-card">
              <el-form :model="queryParams" ref="queryRef" :inline="true">
                <el-form-item label="期间" prop="timeType">
                  <el-select
                    v-model="queryParams.timeType"
                    placeholder="期间"
                    clearable
                    style="width: 120px"
                    @change="handleTimeType"
                  >
                    <el-option v-for="dict in period" :key="dict.value" :label="dict.label" :value="dict.value" />
                  </el-select>
                </el-form-item>
                <el-form-item label="时间">
                  <el-date-picker
                    v-model="queryParams.dataTime"
                    :type="queryParams.timeType == 'YEAR' ? 'year' : queryParams.timeType == 'MONTH' ? 'month' : 'date'"
                    :format="
                      queryParams.timeType == 'YEAR'
                        ? 'YYYY'
                        : queryParams.timeType == 'MONTH'
                        ? 'YYYY-MM'
                        : 'YYYY-MM-DD'
                    "
                    value-format="YYYY-MM-DD"
                    placeholder="时间"
                    style="width: 100%"
                  />
                </el-form-item>
                <el-form-item label="选择电表" prop="meterId">
                  <el-select
                    v-model="queryParams.meterId"
                    placeholder="选择电表"
                    clearable
                    style="width: 200px"
                    @change="handleTimeType"
                  >
                    <el-option
                      v-for="dict in electricityMeter"
                      :key="dict.value"
                      :label="dict.label"
                      :value="dict.value"
                    />
                  </el-select>
                </el-form-item>
                <el-form-item>
                  <el-button type="primary" icon="Search" @click="handleQuery"> æœç´¢ </el-button>
                </el-form-item>
                <!-- <el-form-item>
              <el-button type="primary" icon="Download" @click="handleExport"> å¯¼å‡º </el-button>
            </el-form-item> -->
              </el-form>
            </div>
            <div style="padding: 0 16px">
              <el-tabs v-model="activeTabKey" type="card">
                <el-tab-pane label="电压不平衡" name="1"> </el-tab-pane>
                <el-tab-pane label="电流不平衡" name="2"> </el-tab-pane>
              </el-tabs>
              <div class="display-buttons">
                <div class="display-btn" @click="switchBtnType(1)" :class="{ 'active-display-btn': activeKey === 1 }">
                  å›¾å½¢
                </div>
                <div class="display-btn" @click="switchBtnType(2)" :class="{ 'active-display-btn': activeKey === 2 }">
                  æ•°æ®
                </div>
              </div>
            </div>
            <div class="chart-box" v-loading="loading" v-show="activeKey === 1">
              <LineChart ref="LineChartRef" :chartData="lineChartData" />
              <el-table :data="tableData1" v-loading="loading">
                <el-table-column label="类型" prop="type" align="center" />
                <el-table-column label="三项不平衡极值" prop="value" align="center" />
                <el-table-column label="发生时间" prop="time" align="center" />
                <el-table-column v-if="activeTabKey == 1" label="A项电压(V)" prop="valueA" align="center" />
                <el-table-column v-if="activeTabKey == 1" label="B项电压(V)" prop="valueB" align="center" />
                <el-table-column v-if="activeTabKey == 1" label="C项电压(V)" prop="valueC" align="center" />
                <el-table-column v-if="activeTabKey == 2" label="A项电流(A)" prop="valueA" align="center" />
                <el-table-column v-if="activeTabKey == 2" label="B项电流(A)" prop="valueB" align="center" />
                <el-table-column v-if="activeTabKey == 2" label="C项电流(A)" prop="valueC" align="center" />
              </el-table>
            </div>
            <div style="margin-top: 16px" v-show="activeKey === 2">
              <div class="" style="padding: 0 16px">
                <el-table :data="tableData2" v-loading="loading" height="calc(100vh - 400px)">
                  <el-table-column label="时间" prop="timeCode" align="center" />
                  <el-table-column label="电表名称" prop="name" align="center" />
                  <el-table-column
                    v-if="activeTabKey == 1 && queryParams.timeType == 'DAY'"
                    label="A项电压(V)"
                    prop="valueA"
                    align="center"
                  />
                  <el-table-column
                    v-if="activeTabKey == 1 && queryParams.timeType == 'DAY'"
                    label="B项电压(V)"
                    prop="valueB"
                    align="center"
                  />
                  <el-table-column
                    v-if="activeTabKey == 1 && queryParams.timeType == 'DAY'"
                    label="C项电压(V)"
                    prop="valueC"
                    align="center"
                  />
                  <el-table-column
                    v-if="activeTabKey == 2 && queryParams.timeType == 'DAY'"
                    label="A项电流(A)"
                    prop="valueA"
                    align="center"
                  />
                  <el-table-column
                    v-if="activeTabKey == 2 && queryParams.timeType == 'DAY'"
                    label="B项电流(A)"
                    prop="valueB"
                    align="center"
                  />
                  <el-table-column
                    v-if="activeTabKey == 2 && queryParams.timeType == 'DAY'"
                    label="C项电流(A)"
                    prop="valueC"
                    align="center"
                  />
                  <el-table-column
                    v-if="activeTabKey == 1 && queryParams.timeType !== 'DAY'"
                    label="最大值(V)"
                    prop="max"
                    align="center"
                  />
                  <el-table-column
                    v-if="activeTabKey == 1 && queryParams.timeType !== 'DAY'"
                    label="最小值(V)"
                    prop="min"
                    align="center"
                  />
                  <el-table-column
                    v-if="activeTabKey == 2 && queryParams.timeType !== 'DAY'"
                    label="最大值(A)"
                    prop="max"
                    align="center"
                  />
                  <el-table-column
                    v-if="activeTabKey == 2 && queryParams.timeType !== 'DAY'"
                    label="最小值(A)"
                    prop="min"
                    align="center"
                  />
                </el-table>
              </div>
            </div>
          </BaseCard>
        </div>
      </div>
    </div>
  </div>
</template>
<script setup name="loadAnalysis">
import { threePhaseUnbalanceAnalysisDetail } from "@/api/powerquality/electricThreePhase/api.js"
import { listElectricityDeviceMeter } from "@/api/powerquality/load-analysis/api.js"
import LineChart from "@/components/Echarts/LineChart.vue"
const { proxy } = getCurrentInstance()
import { useRoute } from "vue-router"
const { period } = proxy.useDict("period")
import useSettingsStore from "@/store/modules/settings"
const settingsStore = useSettingsStore()
watch(
  () => settingsStore.sideTheme,
  (val) => {
    getList()
  }
)
const activeTabKey = ref("1")
const activeKey = ref(1)
const activeKeyA = ref(1)
const loading = ref(false)
const tableData1 = ref([])
const tableData2 = ref([])
const detailData = ref({})
const lineChartData = ref({})
const electricityMeter = ref([])
const data = reactive({
  queryParams: {
    nodeId: null,
    nodeName: null,
    timeType: null,
    dataTime: null,
    meterId: "",
  },
  query: { ...useRoute().query },
})
const { queryParams, query } = toRefs(data)
function getElectricityMeter(params) {
  listElectricityDeviceMeter(params).then((res) => {
    if (res.code === 200) {
      electricityMeter.value = res.data.map((item) => {
        return {
          ...item,
          value: item.code,
        }
      })
      queryParams.value.meterId = res.data.length > 0 ? res.data[0].code : ""
      getList()
    }
  })
}
/** èŠ‚ç‚¹å•å‡»äº‹ä»¶ */
function handleNodeClick(data) {
  queryParams.value.nodeId = data.id
  queryParams.value.nodeName = data.label
  handleTimeType(period.value[0].value)
  getElectricityMeter({ nodeId: queryParams.value.nodeId })
}
function handleTimeType(e) {
  queryParams.value.timeType = e
  queryParams.value.dataTime = proxy.dayjs(new Date()).format("YYYY-MM-DD")
}
function switchBtnType(e) {
  activeKey.value = e
  if (e === 1) {
    getList()
  }
}
// åˆ—表
function getList() {
  loading.value = true
  let params = {
    nodeId: queryParams.value.nodeId,
    timeType: queryParams.value.timeType,
    timeCode: queryParams.value.dataTime,
    meterId: queryParams.value.meterId,
    requestType: activeTabKey.value == 1 ? 0 : 1,
  }
  if (queryParams.value.timeType == "DAY") {
    params.timeCode = proxy.dayjs(new Date(queryParams.value.dataTime)).format("YYYY-MM-DD")
  } else if (queryParams.value.timeType == "MONTH") {
    params.timeCode = proxy.dayjs(new Date(queryParams.value.dataTime)).format("YYYY-MM")
  } else if (queryParams.value.timeType == "YEAR") {
    params.timeCode = proxy.dayjs(new Date(queryParams.value.dataTime)).format("YYYY")
  }
  threePhaseUnbalanceAnalysisDetail(params)
    .then((res) => {
      if (!!res.code && res.code == 200) {
        // detailData.value = res.data.detail
        loading.value = false
        let itemList = res.data.itemList || []
        let detail = res.data.detail || {}
        if (detail) {
          tableData1.value = [
            {
              type: "最大值",
              value: detail.max || "--",
              time: detail.maxTime,
              valueA: detail.valueMaxA,
              valueB: detail.valueMaxB,
              valueC: detail.valueMaxC,
            },
            {
              type: "最小值",
              value: detail.min,
              time: detail.minTime,
              valueA: detail.valueMinA,
              valueB: detail.valueMinB,
              valueC: detail.valueMinC,
            },
          ]
        }
        let tableDataWithMeterList = itemList
        tableData2.value =
          tableDataWithMeterList.map((item) => {
            // item.timeCode = this.formatTime(item.timeCode)
            return item
          }) || []
        // chart
        let chartData = {}
        if (queryParams.value.timeType !== "DAY") {
          chartData = {
            title: "三相不平衡分析",
            xAxis: itemList.map((item) => {
              return item.timeCodeChart
            }),
            series: [
              {
                name: "最小值",
                data: itemList.map((item) => {
                  return item.min === "--" || !item.min ? null : Number(item.min)
                }),
              },
              {
                name: "最大值",
                data: itemList.map((item) => {
                  return item.max === "--" || !item.max ? null : Number(item.max)
                }),
              },
            ],
          }
        } else {
          chartData = {
            title: "三相不平衡分析",
            xAxis: itemList.map((item) => {
              return item.timeCode.slice(item.timeCode.length - 2, item.timeCode.length) + "时"
            }),
            series: [
              {
                name: "A相" + (activeTabKey.value == 1 ? "电压" : "电流"),
                data: itemList.map((item) => {
                  return item.valueA === "--" || !item.valueA ? null : Number(item.valueA)
                }),
              },
              {
                name: "B相" + (activeTabKey.value == 1 ? "电压" : "电流"),
                data: itemList.map((item) => {
                  return item.valueB === "--" || !item.valueB ? null : Number(item.valueB)
                }),
              },
              {
                name: "C相" + (activeTabKey.value == 1 ? "电压" : "电流"),
                data: itemList.map((item) => {
                  return item.valueC === "--" || !item.valueC ? null : Number(item.valueC)
                }),
              },
            ],
          }
        }
        lineChartData.value = chartData
      }
    })
    .catch(() => {
      loading.value = false
    })
}
// ç¢³æŽ’放管理-碳排放量核算-搜索
function handleQuery() {
  getList()
}
// ç¢³æŽ’放管理-碳排放量核算-重置
function resetQuery() {
  proxy.resetForm("queryRef")
  queryParams.value.timeType = null
  queryParams.value.dataTime = null
  handleTimeType(period.value[0].value)
  handleQuery()
}
// ç¢³æŽ’放管理-碳排放量核算-导出
function handleExport() {
  proxy.download(
    "carbonEmission/export",
    {
      emissionType: "allType",
      ...queryParams.value,
      ...query.value,
    },
    `${queryParams.value.nodeName}-碳排放量核算_${new Date().getTime()}.xlsx`
  )
}
</script>
<style scoped lang="scss">
@import "@/assets/styles/page.scss";
.themeDark {
  .card-list {
    width: 100%;
    display: flex;
    flex-wrap: wrap;
    padding: 18px;
    color: #fff;
    .card-list-item {
      width: 19%;
      margin-right: 1%;
      height: 157px;
      background: #223386;
      border-radius: 5px 5px 5px 5px;
      border: 1px solid #4868b7;
      background-size: 100% 100%;
      box-sizing: border-box;
      padding: 25px 18px 12px 16px;
      .item-top {
        display: flex;
        align-items: center;
        .top-icon {
          width: 40px;
          height: 40px;
          background-size: 100% 100%;
        }
        .top-right {
          margin-left: 16px;
          font-weight: bold;
          font-size: 16px;
          font-family: OPPOSans-Bold;
        }
      }
      .item-bottom {
        display: flex;
        justify-content: space-between;
        margin-top: 18px;
        font-family: OPPOSans, OPPOSans;
        font-weight: bold;
        font-size: 14px;
      }
    }
  }
}
.themeLight {
  .card-list {
    width: 100%;
    display: flex;
    flex-wrap: wrap;
    padding: 18px;
    .card-list-item {
      width: 19%;
      margin-right: 1%;
      height: 157px;
      background: #fff;
      border-radius: 5px 5px 5px 5px;
      border: 1px solid #e8e8e8;
      background-size: 100% 100%;
      box-sizing: border-box;
      padding: 25px 18px 12px 16px;
      .item-top {
        display: flex;
        align-items: center;
        .top-icon {
          width: 40px;
          height: 40px;
          background-size: 100% 100%;
        }
        .top-right {
          margin-left: 16px;
          font-weight: bold;
          font-size: 16px;
          color: #000;
          font-family: OPPOSans-Bold;
        }
      }
      .item-bottom {
        display: flex;
        justify-content: space-between;
        margin-top: 18px;
        font-family: OPPOSans, OPPOSans;
        font-weight: bold;
        font-size: 14px;
      }
    }
  }
}
.chart-box {
  width: 100%;
  height: 100% !important;
}
.display-buttons {
  display: flex;
  justify-content: flex-end;
  align-items: center;
  .display-btn,
  .active-display-btn {
    width: 78px;
    height: 34px;
    background: #fff;
    color: #409eff;
    border: 2px solid #409eff;
    border-radius: 4px;
    margin-left: 10px;
    text-align: center;
    line-height: 31px;
    font-size: 14px;
    font-weight: 400;
    cursor: pointer;
    &:hover {
      opacity: 0.9;
    }
  }
  .active-display-btn {
    background: #409eff;
    color: #fff;
  }
}
</style>
zhitan-vue/src/views/realtimemonitor/realtimemonitor/realtimemonitor.vue
@@ -9,13 +9,16 @@
          <el-form :model="queryParams" ref="queryRef" :inline="true">
            <el-form-item label="能源类型" prop="energyType">
              <el-select v-model="queryParams.energyType" placeholder="能源类型" @change="handleQuery">
                <el-option :label="item.enername" :value="item.enersno" v-for="item in energyTypeList" :key="item.enersno" />
                <el-option
                  :label="item.enername"
                  :value="item.enersno"
                  v-for="item in energyTypeList"
                  :key="item.enersno"
                />
              </el-select>
            </el-form-item>
            <el-form-item>
              <el-button type="primary" icon="Search" @click="handleQuery">
                æœç´¢
              </el-button>
              <el-button type="primary" icon="Search" @click="handleQuery"> æœç´¢ </el-button>
              <el-button icon="Refresh" @click="resetQuery"> é‡ç½® </el-button>
            </el-form-item>
            <el-form-item>
@@ -23,20 +26,24 @@
            </el-form-item>
          </el-form>
        </div>
        <div style="
            height: calc(100vh - 220px) !important;
            max-height: calc(100vh - 220px) !important;
            overflow-y: auto;
          " v-loading="loading">
        <div
          style="height: calc(100vh - 220px) !important; max-height: calc(100vh - 220px) !important; overflow-y: auto"
          v-loading="loading"
        >
          <div v-for="(item, index) in energyRealTimeMonitorList" :key="index" v-show="!!item.deviceArray">
            <BaseCard :title="queryParams.nodeName + '-' + item.energyTypeName" v-if="item.deviceArray.length > 0">
              <el-scrollbar>
                <div class="scrollbar-flex-content">
                  <p></p>
                  <div class="scrollbar-demo-item item-tag" @click="handleClick(item, index1)" v-for="item1,index1 in item.deviceArray" :key="index1" :style="{
                    backgroundColor:
                      index1 == item.activeIndex ? '#5EC894' : '#9841FC',
                  }">
                  <div
                    class="scrollbar-demo-item item-tag"
                    @click="handleClick(item, index1)"
                    v-for="(item1, index1) in item.deviceArray"
                    :key="index1"
                    :style="{
                      backgroundColor: index1 == item.activeIndex ? '#5EC894' : '#9841FC',
                    }"
                  >
                    {{ item1.deviceName }}
                  </div>
                </div>
@@ -71,18 +78,18 @@
                  {{ item.deviceArray[item.activeIndex].energyTypeName }}
                </div>
                <div class="card-box-ul">
                  <div class="card-box-li" v-for="(item2, index2) in item.deviceArray[item.activeIndex]
                    .energyIndexArray">
                  <div
                    class="card-box-li"
                    v-for="(item2, index2) in item.deviceArray[item.activeIndex].energyIndexArray"
                  >
                    <el-tooltip class="box-item" effect="dark" content="查看历史数据" placement="top">
                      <dl @click="handleChartModal(item2)">
                        <dd class="title">
                          {{ item2.name }}
                          <template v-if="!!item2.unit">
                            ({{ item2.unit }})
                          </template>
                          <template v-if="!!item2.unit"> ({{ item2.unit }}) </template>
                        </dd>
                        <dd class="num">
                          {{ item2.value!=null ? item2.value.toFixed(2) : '--' }}
                          {{ item2.value != null ? item2.value.toFixed(2) : "--" }}
                        </dd>
                        <dd class="time">
                          <el-icon>
@@ -105,22 +112,22 @@
  </div>
</template>
<script setup name="energy-real-time-monitor">
import chartModal from "./components/chart-modal.vue";
import { listEnergyRealTimeMonitor } from "@/api/realTimeMonitor/realTimeMonitor";
import { listEnergyTypeList } from "@/api/modelConfiguration/energyType";
const { proxy } = getCurrentInstance();
import { useRoute } from "vue-router";
import useSettingsStore from "@/store/modules/settings";
const settingsStore = useSettingsStore();
import chartModal from "./components/chart-modal.vue"
import { listEnergyRealTimeMonitor } from "@/api/realTimeMonitor/realTimeMonitor"
import { listEnergyTypeList } from "@/api/modelConfiguration/energyType"
const { proxy } = getCurrentInstance()
import { useRoute } from "vue-router"
import useSettingsStore from "@/store/modules/settings"
const settingsStore = useSettingsStore()
watch(
  () => settingsStore.sideTheme,
  (val) => {
    getList();
    getList()
  }
);
const energyTypeList = ref(undefined);
let energyRealTimeMonitorList = ref([]);
const loading = ref(false);
)
const energyTypeList = ref(undefined)
let energyRealTimeMonitorList = ref([])
const loading = ref(false)
const data = reactive({
  queryParams: {
    nodeId: null,
@@ -128,24 +135,24 @@
    energyType: null,
  },
  query: { ...useRoute().query },
});
const { queryParams, query } = toRefs(data);
})
const { queryParams, query } = toRefs(data)
/** èŠ‚ç‚¹å•å‡»äº‹ä»¶ */
function handleNodeClick(data) {
  queryParams.value.nodeId = data.id;
  queryParams.value.nodeName = data.label;
  queryParams.value.nodeId = data.id
  queryParams.value.nodeName = data.label
  listEnergyTypeList().then((res) => {
    energyTypeList.value = res.data;
    queryParams.value.energyType = energyTypeList.value[0].enersno;
    handleQuery();
  });
    energyTypeList.value = res.data
    queryParams.value.energyType = energyTypeList.value[0].enersno
    handleQuery()
  })
}
function handleClick(item, index) {
  item.activeIndex = index;
  item.activeIndex = index
}
// èƒ½æºå®žæ—¶ç›‘控-能源实时监控-列表
function getList() {
  loading.value = true;
  loading.value = true
  listEnergyRealTimeMonitor(
    proxy.addDateRange({
      ...queryParams.value,
@@ -154,31 +161,31 @@
  ).then((res) => {
    if (!!res.code && res.code == 200) {
      res.data.map((item) => {
        item.activeIndex = 0;
      });
      loading.value = false;
      energyRealTimeMonitorList.value = res.data;
        item.activeIndex = 0
      })
      loading.value = false
      energyRealTimeMonitorList.value = res.data
    }
  });
  })
}
// èƒ½æºå®žæ—¶ç›‘控-能源实时监控-搜索
function handleQuery() {
  energyRealTimeMonitorList.value = [];
  getList();
  energyRealTimeMonitorList.value = []
  getList()
}
// èƒ½æºå®žæ—¶ç›‘控-能源实时监控-重置
function resetQuery() {
  proxy.resetForm("queryRef");
  queryParams.value.energyType = null;
  energyRealTimeMonitorList.value = [];
  handleQuery();
  proxy.resetForm("queryRef")
  queryParams.value.energyType = null
  energyRealTimeMonitorList.value = []
  handleQuery()
}
let chartRef = ref();
let chartRef = ref()
function handleChartModal(row) {
  if (chartRef.value) {
    row.nodeName = queryParams.value.nodeName
    chartRef.value.handleOpen(row);
    chartRef.value.handleOpen(row)
  }
}
</script>
@@ -213,6 +220,7 @@
    &-li {
      width: 18%;
      min-width: 190px;
      margin: 1%;
      border-radius: 5px;
      border: 1px solid #22408c;
@@ -235,11 +243,10 @@
      }
      .num {
        font-size: 22px;
        font-size: 24px;
        color: #36d3ff;
        font-family: OPPOSans, OPPOSans;
        font-weight: 800;
        font-size: 32px;
        text-align: left;
        font-style: normal;
        text-transform: none;
@@ -252,6 +259,7 @@
        text-align: left;
        font-style: normal;
        text-transform: none;
        font-size: 14px;
      }
    }
@@ -423,12 +431,12 @@
.item-tag {
  // width: 13%;
  text-align: center;
  margin: 5px 8px;
  margin: 2px 6px;
  border-radius: 8px;
  padding: 7px 10px;
  padding: 5px 10px;
  font-family: OPPOSans, OPPOSans;
  font-weight: 500;
  font-size: 16px;
  font-size: 14px;
  color: #ffffff;
  cursor: pointer;
}