yeg
2026-09-01 0fcd0642efdff8d4e0584fa991aaea2178bc932b
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
package com.ruoyi.system.service.impl;
 
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.Date;
import java.util.HexFormat;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.ruoyi.device.bts.BtsDevelopmentSimulator;
import com.ruoyi.device.simulator.BtsSimulatorStateStore.BtsHistoryRecord;
import com.ruoyi.system.domain.TTest;
import com.ruoyi.system.domain.TTestBattery;
import com.ruoyi.system.domain.TTestChannelBinding;
import com.ruoyi.system.domain.TTestReceptionInterval;
import com.ruoyi.system.mapper.TTestMapper;
import com.ruoyi.system.service.ITTestService;
import com.ruoyi.system.service.ITestDataReceptionService;
 
/** 接收时确定测试归属,并以现有采样表追加保存检测柜事实。 */
@Service
public class TestDataReceptionServiceImpl implements ITestDataReceptionService
{
    private final TTestMapper mapper;
    private final ITTestService tests;
    private final BtsDevelopmentSimulator simulator;
 
    public TestDataReceptionServiceImpl(TTestMapper mapper, ITTestService tests, BtsDevelopmentSimulator simulator)
    {
        this.mapper = mapper;
        this.tests = tests;
        this.simulator = simulator;
    }
 
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void captureDevelopmentCabinetRecords()
    {
        List<Long> testIds = mapper.selectReceivingTestIds();
        if (testIds == null) return;
        for (Long testId : testIds)
        {
            TTest test = tests.selectTestById(testId);
            if (test == null || !"RECEIVING".equals(test.getReceptionStatus())) continue;
            captureTest(test);
        }
    }
 
    private void captureTest(TTest test)
    {
        for (TTestBattery battery : test.getBatteries() == null ? List.<TTestBattery>of() : test.getBatteries())
        {
            TTestChannelBinding binding = battery.getBinding();
            if (binding == null || binding.getDevid() == null || binding.getChlid() == null) continue;
            Optional<TTestReceptionInterval> open = mapper.selectTestReceptionIntervals(test.getTestId()).stream()
                    .filter(item -> Objects.equals(item.getBindingId(), binding.getBindingId())
                            && "CABINET_CHANNEL".equals(item.getSourceType())
                            && Objects.equals(item.getSourceId(), binding.getChannelId())
                            && "OPEN".equals(item.getIntervalStatus()))
                    .findFirst();
            if (open.isEmpty()) continue;
            Date start = open.get().getStartBoundaryAtUtc();
            List<BtsHistoryRecord> records;
            try { records = simulator.btsRecords(binding.getDevid(), binding.getChlid()); }
            catch (IllegalArgumentException ignored) { continue; }
            for (BtsHistoryRecord record : records)
            {
                if (start != null && record.deviceTime().isBefore(start.toInstant())) continue;
                save(test, battery, binding, open.get(), record);
            }
        }
    }
 
    private void save(TTest test, TTestBattery battery, TTestChannelBinding binding,
            TTestReceptionInterval interval, BtsHistoryRecord record)
    {
        // 模拟器历史 testid 按通道固定;接收事实必须再带测试作用域,避免顺序测试共用全局幂等键。
        String btsTestId = "SIM-" + binding.getDevid() + "-" + binding.getChlid() + "-T" + test.getTestId();
        byte[] hash = hash(record);
        String old = mapper.selectSampleContentHash(binding.getChannelId(), btsTestId, record.sequenceId());
        if (old != null)
        {
            if (!old.equalsIgnoreCase(HexFormat.of().formatHex(hash)))
                mapper.insertBackfillConflict(test.getTestId(), binding.getChannelId(),
                        "实时接收内容冲突 testid=" + btsTestId + ", seqid=" + record.sequenceId());
            return;
        }
        mapper.insertBtsSample(test.getTestId(), binding.getBindingId(), binding.getChannelId(), interval.getIntervalId(),
                btsTestId, record.sequenceId(), Date.from(record.deviceTime()),
                record.deviceTime().toString(), new Date(), record.cycleNo(), record.stepNo(), record.stepType(),
                record.stepName(), null,
                BigDecimal.valueOf(record.voltageV()), BigDecimal.valueOf(record.currentA()),
                BigDecimal.valueOf(record.capacityAh()), BigDecimal.valueOf(record.energyWh()), hash);
    }
 
    private byte[] hash(BtsHistoryRecord record)
    {
        try
        {
            String value = record.sequenceId() + "|" + record.deviceTime() + "|" + record.currentA() + "|"
                    + record.voltageV() + "|" + record.capacityAh() + "|" + record.energyWh() + "|"
                    + record.cycleNo() + "|" + record.stepNo() + "|" + record.stepType();
            return MessageDigest.getInstance("SHA-256").digest(value.getBytes(StandardCharsets.UTF_8));
        }
        catch (Exception exception) { throw new IllegalStateException("无法计算采样内容摘要", exception); }
    }
}