yuan
3 天以前 7fc5bc0c6f92d65099397690128cbf218935972d
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
package com.ruoyi.http.service.impl;
 
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ruoyi.common.utils.http.HttpUtils;
import com.ruoyi.http.config.TqdianbiaoConfig;
import com.ruoyi.http.mapper.TqdianbiaoEleRecordMapper;
import com.ruoyi.http.mapper.TqdianbiaoMeterMapper;
import com.ruoyi.http.pojo.TqdianbiaoEleRecord;
import com.ruoyi.http.pojo.TqdianbiaoMeter;
import com.ruoyi.http.service.TqdianbiaoEleSyncService;
import com.ruoyi.http.service.TqdianbiaoSyncLogService;
import com.ruoyi.http.util.StatisticEleParseUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
 
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
 
@Service
@Slf4j
@RequiredArgsConstructor
public class TqdianbiaoEleSyncServiceImpl implements TqdianbiaoEleSyncService {
 
    private static final DateTimeFormatter HOUR_FMT = DateTimeFormatter.ofPattern("yyyyMMddHH");
    private static final DateTimeFormatter DAY_FMT = DateTimeFormatter.ofPattern("yyyyMMdd");
    private static final DateTimeFormatter MONTH_FMT = DateTimeFormatter.ofPattern("yyyyMM");
    private static final DateTimeFormatter YEAR_FMT = DateTimeFormatter.ofPattern("yyyy");
 
    private final TqdianbiaoConfig config;
    private final TqdianbiaoEleRecordMapper eleRecordMapper;
    private final TqdianbiaoMeterMapper meterMapper;
    private final TqdianbiaoSyncLogService syncLogService;
 
    @Override
    public int syncHourData() {
        int window = config.getSync().getHourWindow() != null ? config.getSync().getHourWindow() : 1;
        if (window < 1) {
            window = 1;
        }
        // 结束于上一完整小时,不包含当前未结束的小时
        LocalDateTime currentHourStart = LocalDateTime.now().withMinute(0).withSecond(0).withNano(0);
        LocalDateTime end = currentHourStart.minusHours(1);
        LocalDateTime start = end.minusHours(window - 1L);
        String startTime = start.format(HOUR_FMT);
        String endTime = end.format(HOUR_FMT);
        return syncDimension("hour", startTime, endTime);
    }
 
    @Override
    public int syncLast3DaysHourData() {
        LocalDateTime start = LocalDate.now().minusDays(3).atStartOfDay();
        LocalDateTime end = LocalDateTime.now().withMinute(0).withSecond(0).withNano(0);
        return syncHourRangeInChunks(start, end);
    }
 
    /** 按最多 24 小时一段分批拉取(平台接口限制) */
    private int syncHourRangeInChunks(LocalDateTime start, LocalDateTime end) {
        int total = 0;
        LocalDateTime windowStart = start;
        while (!windowStart.isAfter(end)) {
            LocalDateTime windowEnd = windowStart.plusHours(23);
            if (windowEnd.isAfter(end)) {
                windowEnd = end;
            }
            total += syncDimension("hour", windowStart.format(HOUR_FMT), windowEnd.format(HOUR_FMT));
            windowStart = windowEnd.plusHours(1);
        }
        return total;
    }
 
    @Override
    public int syncDayData() {
        LocalDate yesterday = LocalDate.now().minusDays(1);
        String day = yesterday.format(DAY_FMT);
        return syncDimension("day", day, day);
    }
 
    @Override
    public int syncMonthData() {
        LocalDate now = LocalDate.now();
        String month = now.format(MONTH_FMT);
        return syncDimension("month", month, month);
    }
 
    @Override
    public int syncYearData() {
        LocalDate now = LocalDate.now();
        String year = now.format(YEAR_FMT);
        return syncDimension("year", year, year);
    }
 
    private int syncDimension(String dimension, String startTime, String endTime) {
        return syncDimension(dimension, startTime, endTime, config.getIgnoreRadio());
    }
 
    private int syncDimension(String dimension, String startTime, String endTime, int ignoreRadio) {
        try {
            String url = config.getBaseUrl() + "/Api/StatisticEle/" + dimension;
            String param = String.format(
                    "auth=%s&start_time=%s&end_time=%s&ignore_radio=%d",
                    config.getAuth(), startTime, endTime, ignoreRadio
            );
            log.info("同步电量数据: {} {}-{} ignore_radio={}", dimension, startTime, endTime, ignoreRadio);
            String raw = HttpUtils.sendGet(url, param);
            List<TqdianbiaoEleRecord> records = StatisticEleParseUtil.parseToEntities(raw, dimension);
            enrichMeterInfo(records);
            int count = upsertRecords(records);
            syncLogService.logSuccess(dimension, startTime, endTime, count);
            return count;
        } catch (Exception e) {
            log.error("电量同步失败 dimension={} {}-{}", dimension, startTime, endTime, e);
            syncLogService.logFailure(dimension, startTime, endTime, e.getMessage());
            throw e;
        }
    }
 
    private void enrichMeterInfo(List<TqdianbiaoEleRecord> records) {
        for (TqdianbiaoEleRecord record : records) {
            if (record.getMeterId() == null) {
                continue;
            }
            TqdianbiaoMeter meter = meterMapper.selectOne(
                    Wrappers.<TqdianbiaoMeter>lambdaQuery()
                            .eq(TqdianbiaoMeter::getMeterId, record.getMeterId())
                            .last("LIMIT 1"));
            if (meter != null && StringUtils.hasText(meter.getMeterName())) {
                record.setMeterName(meter.getMeterName());
            }
        }
    }
 
    private int upsertRecords(List<TqdianbiaoEleRecord> records) {
        int count = 0;
        for (TqdianbiaoEleRecord record : records) {
            TqdianbiaoEleRecord existing = eleRecordMapper.selectOne(
                    Wrappers.<TqdianbiaoEleRecord>lambdaQuery()
                            .eq(TqdianbiaoEleRecord::getMeterId, record.getMeterId())
                            .eq(TqdianbiaoEleRecord::getDimension, record.getDimension())
                            .eq(TqdianbiaoEleRecord::getTimeKey, record.getTimeKey())
                            .last("LIMIT 1"));
            if (existing == null) {
                eleRecordMapper.insert(record);
            } else {
                record.setId(existing.getId());
                eleRecordMapper.updateById(record);
            }
            count++;
        }
        return count;
    }
}