Commit 645df86586393e4105547b52cf7dc0afe9399731

Authored by 杨鸣坤
1 parent a021b725

refactor: 重构设备同步服务支持多公司动态数据源

@@ -9,6 +9,7 @@ import org.springframework.web.bind.annotation.GetMapping; @@ -9,6 +9,7 @@ import org.springframework.web.bind.annotation.GetMapping;
9 import org.springframework.web.bind.annotation.RequestParam; 9 import org.springframework.web.bind.annotation.RequestParam;
10 import org.springframework.web.bind.annotation.RestController; 10 import org.springframework.web.bind.annotation.RestController;
11 11
  12 +import java.util.Collections;
12 import java.util.Map; 13 import java.util.Map;
13 14
14 @RestController 15 @RestController
@@ -23,217 +24,208 @@ public class HealthController { @@ -23,217 +24,208 @@ public class HealthController {
23 @Resource 24 @Resource
24 private EnergyPullService energyPullService; 25 private EnergyPullService energyPullService;
25 26
  27 + /**
  28 + * corpCode为空时的统一空数据响应
  29 + */
  30 + private static Map<String, Object> emptyResult() {
  31 + return Collections.emptyMap();
  32 + }
  33 +
26 @GetMapping("/health") 34 @GetMapping("/health")
27 - public String health() throws Exception {  
28 - devicePullService.pullDeviceAndPushToIot(); 35 + public String health(@RequestParam(required = false) String corpCode) throws Exception {
  36 + if (!isValidCorpCode(corpCode)) return "corpCode不能为空";
  37 + devicePullService.pullDeviceAndPushToIot(corpCode);
29 return "IoT Scheduler is running..."; 38 return "IoT Scheduler is running...";
30 } 39 }
31 40
32 @GetMapping("/device/list") 41 @GetMapping("/device/list")
33 public Map<String, Object> deviceList( 42 public Map<String, Object> deviceList(
  43 + @RequestParam(required = false) String corpCode,
34 @RequestParam(required = false) String deviceName, 44 @RequestParam(required = false) String deviceName,
35 @RequestParam(required = false) String lampState, 45 @RequestParam(required = false) String lampState,
36 @RequestParam(defaultValue = "1") Integer pageNo, 46 @RequestParam(defaultValue = "1") Integer pageNo,
37 @RequestParam(defaultValue = "10") Integer pageSize) { 47 @RequestParam(defaultValue = "10") Integer pageSize) {
38 - return deviceSearchService.queryDeviceList(deviceName, lampState, pageNo, pageSize); 48 + if (!isValidCorpCode(corpCode)) return emptyResult();
  49 + return deviceSearchService.queryDeviceList(corpCode, deviceName, lampState, pageNo, pageSize);
39 } 50 }
40 51
41 @GetMapping("/device/stats") 52 @GetMapping("/device/stats")
42 - public Map<String, Object> deviceStats() {  
43 - return deviceSearchService.queryDeviceStats(); 53 + public Map<String, Object> deviceStats(@RequestParam(required = false) String corpCode) {
  54 + if (!isValidCorpCode(corpCode)) return emptyResult();
  55 + return deviceSearchService.queryDeviceStats(corpCode);
44 } 56 }
45 57
46 @GetMapping("/device/lampData") 58 @GetMapping("/device/lampData")
47 public Map<String, Object> lampData( 59 public Map<String, Object> lampData(
  60 + @RequestParam(required = false) String corpCode,
48 @RequestParam String dtuSn, 61 @RequestParam String dtuSn,
49 @RequestParam String date) { 62 @RequestParam String date) {
50 - return deviceSearchService.queryLampData(dtuSn, date); 63 + if (!isValidCorpCode(corpCode)) return emptyResult();
  64 + return deviceSearchService.queryLampData(corpCode, dtuSn, date);
51 } 65 }
52 66
53 @GetMapping("/device/syncDevUtil") 67 @GetMapping("/device/syncDevUtil")
54 - public String syncDevUtil() {  
55 - devicePullService.pullDevUtilAndSave(); 68 + public String syncDevUtil(@RequestParam(required = false) String corpCode) {
  69 + if (!isValidCorpCode(corpCode)) return "corpCode不能为空";
  70 + devicePullService.pullDevUtilAndSave(corpCode);
56 return "设备利用率数据同步完成"; 71 return "设备利用率数据同步完成";
57 } 72 }
58 73
59 @GetMapping("/device/syncOee") 74 @GetMapping("/device/syncOee")
60 - public String syncOee() {  
61 - devicePullService.pullOeeAndSave(); 75 + public String syncOee(@RequestParam(required = false) String corpCode) {
  76 + if (!isValidCorpCode(corpCode)) return "corpCode不能为空";
  77 + devicePullService.pullOeeAndSave(corpCode);
62 return "OEE时序数据同步完成"; 78 return "OEE时序数据同步完成";
63 } 79 }
64 80
65 @GetMapping("/device/oeeStats") 81 @GetMapping("/device/oeeStats")
66 public Map<String, Object> oeeStats( 82 public Map<String, Object> oeeStats(
  83 + @RequestParam(required = false) String corpCode,
67 @RequestParam String dtuSn, 84 @RequestParam String dtuSn,
68 @RequestParam(defaultValue = "day") String type, 85 @RequestParam(defaultValue = "day") String type,
69 @RequestParam(required = false) String startDate, 86 @RequestParam(required = false) String startDate,
70 @RequestParam(required = false) String endDate) { 87 @RequestParam(required = false) String endDate) {
71 - return deviceSearchService.queryOeeStats(dtuSn, type, startDate, endDate); 88 + if (!isValidCorpCode(corpCode)) return emptyResult();
  89 + return deviceSearchService.queryOeeStats(corpCode, dtuSn, type, startDate, endDate);
72 } 90 }
73 91
74 /** 92 /**
75 * OEE时序图分页查询(含稼动率) 93 * OEE时序图分页查询(含稼动率)
76 - * 查询所有设备在指定日期范围内的OEE时序数据,分页返回(每页最多20条)  
77 - *  
78 - * @param startDate 开始日期 yyyy-MM-dd  
79 - * @param endDate 结束日期 yyyy-MM-dd  
80 - * @param pageNo 页码,默认1  
81 - * @param pageSize 每页条数,最大20,默认20  
82 */ 94 */
83 @GetMapping("/device/oeeTimeline") 95 @GetMapping("/device/oeeTimeline")
84 public Map<String, Object> oeeTimeline( 96 public Map<String, Object> oeeTimeline(
  97 + @RequestParam(required = false) String corpCode,
85 @RequestParam String startDate, 98 @RequestParam String startDate,
86 @RequestParam String endDate, 99 @RequestParam String endDate,
87 @RequestParam(defaultValue = "1") Integer pageNo, 100 @RequestParam(defaultValue = "1") Integer pageNo,
88 @RequestParam(defaultValue = "20") Integer pageSize) { 101 @RequestParam(defaultValue = "20") Integer pageSize) {
89 - return deviceSearchService.queryOeeTimeline(startDate, endDate, pageNo, pageSize); 102 + if (!isValidCorpCode(corpCode)) return emptyResult();
  103 + return deviceSearchService.queryOeeTimeline(corpCode, startDate, endDate, pageNo, pageSize);
90 } 104 }
91 105
92 /** 106 /**
93 * 智能灯统计稼动率查询(仪表盘) 107 * 智能灯统计稼动率查询(仪表盘)
94 - * 支持日/周/月查询,返回总时长、稼动率、当前机台状态、异常排行榜、每设备状态时长  
95 - *  
96 - * @param startDate 开始日期 yyyy-MM-dd (day模式必填)  
97 - * @param endDate 结束日期 yyyy-MM-dd (day模式必填)  
98 */ 108 */
99 @GetMapping("/device/lampStatistics") 109 @GetMapping("/device/lampStatistics")
100 public Map<String, Object> lampStatistics( 110 public Map<String, Object> lampStatistics(
  111 + @RequestParam(required = false) String corpCode,
101 @RequestParam(required = false) String startDate, 112 @RequestParam(required = false) String startDate,
102 @RequestParam(required = false) String endDate) { 113 @RequestParam(required = false) String endDate) {
103 - return deviceSearchService.queryLampStatistics(startDate, endDate); 114 + if (!isValidCorpCode(corpCode)) return emptyResult();
  115 + return deviceSearchService.queryLampStatistics(corpCode, startDate, endDate);
104 } 116 }
105 117
106 /** 118 /**
107 * 开机率查询(基于 dev_util 表) 119 * 开机率查询(基于 dev_util 表)
108 - * 灭灯(state=0)=未开机,其他灯=开机,每台设备单独计算,不分页  
109 - *  
110 - * @param startDate 开始日期 yyyy-MM-dd  
111 - * @param endDate 结束日期 yyyy-MM-dd  
112 */ 120 */
113 @GetMapping("/device/bootRate") 121 @GetMapping("/device/bootRate")
114 public Map<String, Object> bootRate( 122 public Map<String, Object> bootRate(
  123 + @RequestParam(required = false) String corpCode,
115 @RequestParam String startDate, 124 @RequestParam String startDate,
116 @RequestParam String endDate) { 125 @RequestParam String endDate) {
117 - return deviceSearchService.queryBootRate(startDate, endDate); 126 + if (!isValidCorpCode(corpCode)) return emptyResult();
  127 + return deviceSearchService.queryBootRate(corpCode, startDate, endDate);
118 } 128 }
119 129
120 @GetMapping("/energy/history") 130 @GetMapping("/energy/history")
121 - public void energyHistory() {  
122 - energyPullService.pullEnergyHistoryAndSave(); 131 + public void energyHistory(@RequestParam(required = false) String corpCode) {
  132 + if (isValidCorpCode(corpCode)) energyPullService.pullEnergyHistoryAndSave(corpCode);
123 } 133 }
124 134
125 /** 135 /**
126 * 分页查询能耗设备信息 136 * 分页查询能耗设备信息
127 - *  
128 - * @param deviceName 设备名称(模糊匹配)  
129 - * @param runStatus 状态(0:离线,1:停机,2:待机,3:运行)  
130 - * @param pageNo 页码,默认1  
131 - * @param pageSize 每页条数,默认10  
132 */ 137 */
133 @GetMapping("/energy/list") 138 @GetMapping("/energy/list")
134 public Map<String, Object> energyList( 139 public Map<String, Object> energyList(
  140 + @RequestParam(required = false) String corpCode,
135 @RequestParam(required = false) String deviceName, 141 @RequestParam(required = false) String deviceName,
136 @RequestParam(required = false) String runStatus, 142 @RequestParam(required = false) String runStatus,
137 @RequestParam(defaultValue = "1") Integer pageNo, 143 @RequestParam(defaultValue = "1") Integer pageNo,
138 @RequestParam(defaultValue = "10") Integer pageSize) { 144 @RequestParam(defaultValue = "10") Integer pageSize) {
139 - return energySearchService.queryEnergyList(deviceName, runStatus, pageNo, pageSize); 145 + if (!isValidCorpCode(corpCode)) return emptyResult();
  146 + return energySearchService.queryEnergyList(corpCode, deviceName, runStatus, pageNo, pageSize);
140 } 147 }
141 148
142 @GetMapping("/energy/stats") 149 @GetMapping("/energy/stats")
143 - public Map<String, Object> energyStats() {  
144 - return energySearchService.queryEnergyStats(); 150 + public Map<String, Object> energyStats(@RequestParam(required = false) String corpCode) {
  151 + if (!isValidCorpCode(corpCode)) return emptyResult();
  152 + return energySearchService.queryEnergyStats(corpCode);
145 } 153 }
146 154
147 /** 155 /**
148 * 根据dtuSn查询指定日期的设备时用电量和OEE时序 156 * 根据dtuSn查询指定日期的设备时用电量和OEE时序
149 - * 返回时用电量数组、总用电量、OEE时序、总时长、各状态运行时长和占比  
150 - *  
151 - * @param dtuSn 设备序列号  
152 - * @param date 查询日期 yyyy-MM-dd  
153 */ 157 */
154 @GetMapping("/energy/detail") 158 @GetMapping("/energy/detail")
155 public Map<String, Object> energyDetail( 159 public Map<String, Object> energyDetail(
  160 + @RequestParam(required = false) String corpCode,
156 @RequestParam String dtuSn, 161 @RequestParam String dtuSn,
157 @RequestParam String date) { 162 @RequestParam String date) {
158 - return energySearchService.queryEnergyDetailByDate(dtuSn, date); 163 + if (!isValidCorpCode(corpCode)) return emptyResult();
  164 + return energySearchService.queryEnergyDetailByDate(corpCode, dtuSn, date);
159 } 165 }
160 166
161 /** 167 /**
162 * 根据dtuSn查询指定设备的运行时长明细 168 * 根据dtuSn查询指定设备的运行时长明细
163 - * type=1(时): 传startDate,获取指定日期的运行时长明细  
164 - * type=2(天): 传startDate和endDate,按日统计  
165 - * type=3(月): 查本年年初到现在,按月统计  
166 - *  
167 - * @param dtuSn 设备序列号  
168 - * @param type 类型:1-时,2-天,3-月  
169 - * @param startDate 开始日期 yyyy-MM-dd (type=1,2必填)  
170 - * @param endDate 结束日期 yyyy-MM-dd (type=2必填)  
171 */ 169 */
172 @GetMapping("/energy/runtimeDetail") 170 @GetMapping("/energy/runtimeDetail")
173 public Map<String, Object> energyRuntimeDetail( 171 public Map<String, Object> energyRuntimeDetail(
  172 + @RequestParam(required = false) String corpCode,
174 @RequestParam String dtuSn, 173 @RequestParam String dtuSn,
175 @RequestParam(defaultValue = "1") String type, 174 @RequestParam(defaultValue = "1") String type,
176 @RequestParam(required = false) String startDate, 175 @RequestParam(required = false) String startDate,
177 @RequestParam(required = false) String endDate) { 176 @RequestParam(required = false) String endDate) {
178 - return energySearchService.queryEnergyRuntimeDetail(dtuSn, type, startDate, endDate); 177 + if (!isValidCorpCode(corpCode)) return emptyResult();
  178 + return energySearchService.queryEnergyRuntimeDetail(corpCode, dtuSn, type, startDate, endDate);
179 } 179 }
180 180
181 /** 181 /**
182 * 查询能耗时序状态 - 分页查询 182 * 查询能耗时序状态 - 分页查询
183 - * 获取指定日期所有设备的用电量数据,计算稼动率和总用电量  
184 - *  
185 - * @param date 查询日期 yyyy-MM-dd  
186 - * @param pageNo 页码,默认1  
187 - * @param pageSize 每页条数,默认12  
188 */ 183 */
189 @GetMapping("/energy/timelineStatus") 184 @GetMapping("/energy/timelineStatus")
190 public Map<String, Object> energyTimelineStatus( 185 public Map<String, Object> energyTimelineStatus(
  186 + @RequestParam(required = false) String corpCode,
191 @RequestParam String date, 187 @RequestParam String date,
192 @RequestParam(defaultValue = "1") Integer pageNo, 188 @RequestParam(defaultValue = "1") Integer pageNo,
193 @RequestParam(defaultValue = "12") Integer pageSize) { 189 @RequestParam(defaultValue = "12") Integer pageSize) {
194 - return energySearchService.queryEnergyTimelineStatus(date, pageNo, pageSize); 190 + if (!isValidCorpCode(corpCode)) return emptyResult();
  191 + return energySearchService.queryEnergyTimelineStatus(corpCode, date, pageNo, pageSize);
195 } 192 }
196 193
197 /** 194 /**
198 * eq_kwh综合统计查询 195 * eq_kwh综合统计查询
199 - * 查询指定日期范围内所有设备的稼动率、各状态时长、异常排名等  
200 - *  
201 - * @param startDate 开始日期 yyyy-MM-dd  
202 - * @param endDate 结束日期 yyyy-MM-dd  
203 - * @return 包含: 总稼动率、各状态时间(xxx.xx时)、当前运行状态、异常机台排名、每设备0/1/2/3状态时间  
204 */ 196 */
205 @GetMapping("/energy/eqKwhStatistics") 197 @GetMapping("/energy/eqKwhStatistics")
206 public Map<String, Object> eqKwhStatistics( 198 public Map<String, Object> eqKwhStatistics(
  199 + @RequestParam(required = false) String corpCode,
207 @RequestParam String startDate, 200 @RequestParam String startDate,
208 @RequestParam String endDate) { 201 @RequestParam String endDate) {
209 - return energySearchService.queryEqKwhStatistics(startDate, endDate); 202 + if (!isValidCorpCode(corpCode)) return emptyResult();
  203 + return energySearchService.queryEqKwhStatistics(corpCode, startDate, endDate);
210 } 204 }
211 205
212 /** 206 /**
213 * 查询eq_kwh多设备能耗数据(按 时/日/月 聚合) 207 * 查询eq_kwh多设备能耗数据(按 时/日/月 聚合)
214 - * type=1 (时): 传startDate,返回该日所有设备的原始用电量明细  
215 - * type=2 (日):  
216 - * - 传startDate+endDate: 按此范围每日统计每台设备能耗  
217 - * - 只传startDate: 自动取当月1号~月末,按日统计  
218 - * type=3 (月): 自动取本年1月~当前月,按月统计每台能耗数据  
219 - *  
220 - * @param type 类型: 1-时, 2-日, 3-月  
221 - * @param startDate 开始日期 yyyy-MM-dd  
222 - * @param endDate 结束日期 yyyy-MM-dd (type=2时可选)  
223 */ 208 */
224 @GetMapping("/energy/eqKwhByType") 209 @GetMapping("/energy/eqKwhByType")
225 public Map<String, Object> eqKwhByType( 210 public Map<String, Object> eqKwhByType(
  211 + @RequestParam(required = false) String corpCode,
226 @RequestParam(defaultValue = "1") String type, 212 @RequestParam(defaultValue = "1") String type,
227 @RequestParam(required = false) String startDate, 213 @RequestParam(required = false) String startDate,
228 @RequestParam(required = false) String endDate) { 214 @RequestParam(required = false) String endDate) {
229 - return energySearchService.queryEqKwhByType(type, startDate, endDate); 215 + if (!isValidCorpCode(corpCode)) return emptyResult();
  216 + return energySearchService.queryEqKwhByType(corpCode, type, startDate, endDate);
230 } 217 }
231 218
232 /** 219 /**
233 * 调试:查看eq_kwh表中的数据概况 220 * 调试:查看eq_kwh表中的数据概况
234 */ 221 */
235 @GetMapping("/energy/debug/eqKwhInfo") 222 @GetMapping("/energy/debug/eqKwhInfo")
236 - public Map<String, Object> debugEqKwhInfo() {  
237 - return energySearchService.debugEqKwhInfo(); 223 + public Map<String, Object> debugEqKwhInfo(@RequestParam(required = false) String corpCode) {
  224 + if (!isValidCorpCode(corpCode)) return emptyResult();
  225 + return energySearchService.debugEqKwhInfo(corpCode);
  226 + }
  227 +
  228 + private boolean isValidCorpCode(String corpCode) {
  229 + return corpCode != null && !corpCode.trim().isEmpty();
238 } 230 }
239 } 231 }
  1 +package com.iot.scheduler.model;
  2 +
  3 +import lombok.Data;
  4 +
  5 +/**
  6 + * 公司配置信息(来自 t_auto_ymk_ccfg_corp_conf 表)
  7 + */
  8 +@Data
  9 +public class CorpConf {
  10 +
  11 + /**
  12 + * 公司名称
  13 + */
  14 + private String corpName;
  15 + /**
  16 + * 数据源连接地址
  17 + */
  18 + private String datasourceUrl;
  19 + /**
  20 + * 数据源用户名
  21 + */
  22 + private String datasourceName;
  23 + /**
  24 + * 数据源密码
  25 + */
  26 + private String datasourcePassword;
  27 + /**
  28 + * 描述
  29 + */
  30 + private String description;
  31 + /**
  32 + * 公司编码(target_corp)
  33 + */
  34 + private String targetCorp;
  35 + /**
  36 + * IoT平台部门名称
  37 + */
  38 + private String iotOrg;
  39 + /**
  40 + * IoT平台密码(token.password)
  41 + */
  42 + private String iotPassword;
  43 + /**
  44 + * IoT平台用户名(token.userName)
  45 + */
  46 + private String iotUsername;
  47 +}
  1 +package com.iot.scheduler.service;
  2 +
  3 +import com.iot.scheduler.model.CorpConf;
  4 +import jakarta.annotation.PostConstruct;
  5 +import jakarta.annotation.Resource;
  6 +import lombok.extern.slf4j.Slf4j;
  7 +import org.apache.commons.lang3.StringUtils;
  8 +import org.springframework.beans.factory.annotation.Value;
  9 +import org.springframework.jdbc.core.JdbcTemplate;
  10 +import org.springframework.stereotype.Service;
  11 +
  12 +import javax.sql.DataSource;
  13 +import java.sql.DriverManager;
  14 +import java.util.*;
  15 +import java.util.concurrent.ConcurrentHashMap;
  16 +
  17 +/**
  18 + * 公司配置服务
  19 + * - 根据 corpCode 查询 t_auto_ymk_ccfg_corp_conf 表获取公司配置
  20 + * - 数据源策略:公司配置了独立数据源则走独立库,否则使用 application.yml 默认库
  21 + * - 每个公司的表通过 t_auto_{corpCode}_iot_xxx 隔离,不同公司数据互不影响
  22 + */
  23 +@Slf4j
  24 +@Service
  25 +public class CorpConfigService {
  26 +
  27 + @Value("${corp.config.tableName}")
  28 + private String corpConfigTableName;
  29 +
  30 + @Value("${spring.datasource.url}")
  31 + private String defaultDatasourceUrl;
  32 + @Value("${spring.datasource.username}")
  33 + private String defaultDatasourceUsername;
  34 + @Value("${spring.datasource.password}")
  35 + private String defaultDatasourcePassword;
  36 +
  37 + @Resource
  38 + private JdbcTemplate masterJdbcTemplate;
  39 +
  40 + /**
  41 + * 配置缓存,避免频繁查数据库
  42 + */
  43 + private final Map<String, CorpConf> confCache = new ConcurrentHashMap<>();
  44 +
  45 + @PostConstruct
  46 + public void init() {
  47 + log.info("【公司配置服务】初始化完成, 配置表: {}, 默认数据库: {}", corpConfigTableName, defaultDatasourceUrl);
  48 + }
  49 +
  50 + /**
  51 + * 根据 corpCode 获取公司配置信息(带缓存)
  52 + *
  53 + * @param corpCode 公司编码
  54 + * @return 公司配置,未找到返回null
  55 + */
  56 + public CorpConf getCorpConf(String corpCode) {
  57 + if (corpCode == null || corpCode.isEmpty()) return null;
  58 + return confCache.computeIfAbsent(corpCode, this::loadCorpConfFromDb);
  59 + }
  60 +
  61 + /**
  62 + * 清除指定公司缓存
  63 + */
  64 + public void clearCache(String corpCode) {
  65 + if (corpCode != null) confCache.remove(corpCode);
  66 + }
  67 +
  68 + /**
  69 + * 获取所有已配置的公司编码列表
  70 + * 从配置表查询所有有效的 target_corp,用于定时任务遍历
  71 + *
  72 + * @return 公司编码列表(不为null)
  73 + */
  74 + public List<String> getAllCorpCodes() {
  75 + try {
  76 + String sql = "SELECT DISTINCT target_corp FROM " + corpConfigTableName +
  77 + " WHERE target_corp IS NOT NULL AND target_corp != '' ORDER BY target_corp";
  78 + List<Map<String, Object>> rows = masterJdbcTemplate.queryForList(sql);
  79 + List<String> result = new ArrayList<>(rows.size());
  80 + for (Map<String, Object> row : rows) {
  81 + String code = getStringVal(row.get("target_corp"));
  82 + if (code != null) result.add(code);
  83 + }
  84 + log.info("【公司配置】查询到 {} 个已配置公司: {}", result.size(), result);
  85 + return result;
  86 + } catch (Exception e) {
  87 + log.error("【公司配置】查询所有公司编码异常", e);
  88 + return Collections.emptyList();
  89 + }
  90 + }
  91 +
  92 + /**
  93 + * 清除全部缓存
  94 + */
  95 + public void clearAllCache() {
  96 + confCache.clear();
  97 + }
  98 +
  99 + /**
  100 + * 从数据库加载公司配置
  101 + */
  102 + private CorpConf loadCorpConfFromDb(String corpCode) {
  103 + try {
  104 + String sql = "SELECT corp_name, datasource_name, datasource_password, datasource_url, description, " +
  105 + "target_corp, iot_org, iot_password, iot_username FROM " + corpConfigTableName +
  106 + " WHERE target_corp = ? LIMIT 1";
  107 + Map<String, Object> row = masterJdbcTemplate.queryForMap(sql, corpCode);
  108 + CorpConf conf = new CorpConf();
  109 + conf.setCorpName(getStringVal(row.get("corp_name")));
  110 + conf.setDatasourceName(getStringVal(row.get("datasource_name")));
  111 + conf.setDatasourcePassword(getStringVal(row.get("datasource_password")));
  112 + conf.setDatasourceUrl(getStringVal(row.get("datasource_url")));
  113 + conf.setDescription(getStringVal(row.get("description")));
  114 + conf.setTargetCorp(getStringVal(row.get("target_corp")));
  115 + conf.setIotOrg(getStringVal(row.get("iot_org")));
  116 + conf.setIotPassword(getStringVal(row.get("iot_password")));
  117 + conf.setIotUsername(getStringVal(row.get("iot_username")));
  118 + log.info("【公司配置】加载成功, corpCode={}, corpName={}, hasCustomDs={}",
  119 + corpCode, conf.getCorpName(), hasCustomDatasource(conf));
  120 + return conf;
  121 + } catch (org.springframework.dao.EmptyResultDataAccessException e) {
  122 + // 查询无结果,属于正常情况(该corpCode未在配置表中注册)
  123 + log.warn("【公司配置】未找到corpCode={}的配置记录", corpCode);
  124 + return null;
  125 + } catch (Exception e) {
  126 + log.error("【公司配置】查询corpCode={}异常", corpCode, e);
  127 + return null;
  128 + }
  129 + }
  130 +
  131 + /**
  132 + * 获取公司的 JdbcTemplate(动态数据源)
  133 + * <p>
  134 + * 数据源选择策略:
  135 + * 1. 如果 t_auto_ymk_ccfg_corp_conf 中该公司配置了 datasource_url → 使用该独立数据源
  136 + * 2. 如果该公司未配置数据源 → 使用 application.yml 中的默认数据源
  137 + * </p>
  138 + *
  139 + * @param corpCode 公司编码
  140 + * @return JdbcTemplate
  141 + */
  142 + public JdbcTemplate getJdbcTemplate(String corpCode) {
  143 + CorpConf conf = getCorpConf(corpCode);
  144 + if (conf == null || !hasCustomDatasource(conf)) {
  145 + log.info("【公司数据源】corpCode={}, 未配置独立数据源, 使用application.yml默认数据源: {}", corpCode, defaultDatasourceUrl);
  146 + return masterJdbcTemplate;
  147 + }
  148 + try {
  149 + DataSource ds = DriverManager.getConnection(
  150 + conf.getDatasourceUrl(),
  151 + conf.getDatasourceName(),
  152 + conf.getDatasourcePassword()
  153 + ).unwrap(DataSource.class);
  154 + JdbcTemplate jt = new JdbcTemplate(ds);
  155 + log.info("【公司数据源】corpCode={}, 使用独立数据源: {}", corpCode, conf.getDatasourceUrl());
  156 + return jt;
  157 + } catch (Exception e) {
  158 + log.error("【公司数据源】corpCode={} 连接独立数据源失败! url={}, error={}", corpCode, conf.getDatasourceUrl(), e.getMessage());
  159 + throw new RuntimeException("公司 " + corpCode + " 的独立数据源连接失败: " + e.getMessage(), e);
  160 + }
  161 + }
  162 +
  163 + /**
  164 + * 获取IoT平台部门名称(groupName),无配置返回null
  165 + */
  166 + public String getIotOrg(String corpCode) {
  167 + CorpConf conf = getCorpConf(corpCode);
  168 + if (conf != null && conf.getIotOrg() != null && !conf.getIotOrg().isEmpty()) {
  169 + return conf.getIotOrg();
  170 + }
  171 + return null;
  172 + }
  173 +
  174 + /**
  175 + * 获取IoT平台用户名(token.userName),无配置返回null
  176 + */
  177 + public String getIotUsername(String corpCode) {
  178 + CorpConf conf = getCorpConf(corpCode);
  179 + if (conf != null && conf.getIotUsername() != null && !conf.getIotUsername().isEmpty()) {
  180 + return conf.getIotUsername();
  181 + }
  182 + return null;
  183 + }
  184 +
  185 + /**
  186 + * 获取IoT平台密码(token.password),无配置返回null
  187 + */
  188 + public String getIotPassword(String corpCode) {
  189 + CorpConf conf = getCorpConf(corpCode);
  190 + if (conf != null && conf.getIotPassword() != null && !conf.getIotPassword().isEmpty()) {
  191 + return conf.getIotPassword();
  192 + }
  193 + return null;
  194 + }
  195 +
  196 + /**
  197 + * 检查公司是否配置了有效的IoT平台凭证(org/username/password)
  198 + */
  199 + public boolean hasValidIotCredentials(String corpCode) {
  200 + String org = getIotOrg(corpCode);
  201 + String username = getIotUsername(corpCode);
  202 + String password = getIotPassword(corpCode);
  203 + boolean valid = StringUtils.isNotBlank(org)
  204 + && StringUtils.isNotBlank(username)
  205 + && StringUtils.isNotBlank(password);
  206 + if (!valid) {
  207 + log.warn("【IoT凭证】corpCode={} 的IoT配置不完整: org={}, username={}, password={}",
  208 + corpCode, org != null ? "***" : "null",
  209 + username != null ? "***" : "null",
  210 + password != null ? "***" : "null");
  211 + }
  212 + return valid;
  213 + }
  214 +
  215 + // ==================== 表名工具方法 ====================
  216 +
  217 + /**
  218 + * 生成设备主表名: t_auto_{corpCode}_iot_device
  219 + */
  220 + public String getDeviceTableName(String corpCode) {
  221 + return "t_auto_" + corpCode + "_iot_device";
  222 + }
  223 +
  224 + /**
  225 + * 生成设备利用率表名: t_auto_{corpCode}_iot_dev_util
  226 + */
  227 + public String getDevUtilTableName(String corpCode) {
  228 + return "t_auto_" + corpCode + "_iot_dev_util";
  229 + }
  230 +
  231 + /**
  232 + * 生成OEE表名: t_auto_{corpCode}_iot_dev_oee
  233 + */
  234 + public String getOeeTableName(String corpCode) {
  235 + return "t_auto_" + corpCode + "_iot_dev_oee";
  236 + }
  237 +
  238 + /**
  239 + * 生成能耗主表名: t_auto_{corpCode}_iot_energy
  240 + */
  241 + public String getEnergyTableName(String corpCode) {
  242 + return "t_auto_" + corpCode + "_iot_energy";
  243 + }
  244 +
  245 + /**
  246 + * 生成能耗用电量表名: t_auto_{corpCode}_iot_eq_kwh
  247 + */
  248 + public String getEqKwhTableName(String corpCode) {
  249 + return "t_auto_" + corpCode + "_iot_eq_kwh";
  250 + }
  251 +
  252 + /**
  253 + * 生成能耗运行状态明细表名: t_auto_{corpCode}_iot_e_run_dtl
  254 + */
  255 + public String getERunDtlTableName(String corpCode) {
  256 + return "t_auto_" + corpCode + "_iot_e_run_dtl";
  257 + }
  258 +
  259 + // ==================== 内部工具 ====================
  260 +
  261 + private boolean hasCustomDatasource(CorpConf conf) {
  262 + return conf.getDatasourceUrl() != null && !conf.getDatasourceUrl().isEmpty();
  263 + }
  264 +
  265 + private String getStringVal(Object val) {
  266 + return val != null ? String.valueOf(val) : null;
  267 + }
  268 +}
@@ -40,13 +40,8 @@ import org.springframework.scheduling.annotation.Scheduled; @@ -40,13 +40,8 @@ import org.springframework.scheduling.annotation.Scheduled;
40 @Service 40 @Service
41 public class DevicePullService { 41 public class DevicePullService {
42 42
43 -  
44 @Value("${device.token.url}") 43 @Value("${device.token.url}")
45 private String deviceTokenUrl; 44 private String deviceTokenUrl;
46 - @Value("${device.token.userName}")  
47 - private String deviceUserName;  
48 - @Value("${device.token.password}")  
49 - private String devicePassword;  
50 @Value("${device.info.url}") 45 @Value("${device.info.url}")
51 private String deviceInfoUrl; 46 private String deviceInfoUrl;
52 @Value("${device.detail.url}") 47 @Value("${device.detail.url}")
@@ -55,14 +50,6 @@ public class DevicePullService { @@ -55,14 +50,6 @@ public class DevicePullService {
55 private String deviceSnRateUrl; 50 private String deviceSnRateUrl;
56 @Value("${device.energyInfo.url}") 51 @Value("${device.energyInfo.url}")
57 private String energyInfoUrl; 52 private String energyInfoUrl;
58 - @Value("${device.db.corpCode}")  
59 - private String deviceCorpCode;  
60 - @Value("${device.db.tableName}")  
61 - private String deviceTableName;  
62 - @Value("${device.db.devUtilTableName}")  
63 - private String devUtilTableName;  
64 - @Value("${device.db.oeeTableName}")  
65 - private String oeeTableName;  
66 @Value("${device.lamp.url}") 53 @Value("${device.lamp.url}")
67 private String deviceLampUrl; 54 private String deviceLampUrl;
68 55
@@ -70,11 +57,17 @@ public class DevicePullService { @@ -70,11 +57,17 @@ public class DevicePullService {
70 private RedisTemplate<String, String> redisTemplate; 57 private RedisTemplate<String, String> redisTemplate;
71 @Resource 58 @Resource
72 private JdbcTemplate jdbcTemplate; 59 private JdbcTemplate jdbcTemplate;
  60 + @Resource
  61 + private CorpConfigService corpConfigService;
73 62
74 final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 63 final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
75 64
76 - public void pullDeviceAndPushToIot() throws ParseException {  
77 - String deviceResult = getDeviceInfo(); 65 + public void pullDeviceAndPushToIot(String corpCode) throws ParseException {
  66 + if (!corpConfigService.hasValidIotCredentials(corpCode)) {
  67 + log.warn("【设备同步】IoT凭证为空, 跳过同步, corpCode={}", corpCode);
  68 + return;
  69 + }
  70 + String deviceResult = getDeviceInfo(corpCode);
78 Map<String, Object> deviceInfos = JSON.parseObject(deviceResult, new TypeReference<>() { 71 Map<String, Object> deviceInfos = JSON.parseObject(deviceResult, new TypeReference<>() {
79 }); 72 });
80 73
@@ -89,21 +82,19 @@ public class DevicePullService { @@ -89,21 +82,19 @@ public class DevicePullService {
89 String deviceId = deviceInfoJson.getString("deviceId"); 82 String deviceId = deviceInfoJson.getString("deviceId");
90 String dtuSn = deviceInfoJson.getString("dtuSn"); 83 String dtuSn = deviceInfoJson.getString("dtuSn");
91 84
92 - String deviceInfoDetails = getDeviceInfoDetail(dtuSn); 85 + String deviceInfoDetails = getDeviceInfoDetail(corpCode, dtuSn);
93 if (StringUtils.isBlank(deviceInfoDetails)) { 86 if (StringUtils.isBlank(deviceInfoDetails)) {
94 return; 87 return;
95 } 88 }
96 89
97 Map<String, Object> deviceInfoDetailMap = JSON.parseObject(deviceInfoDetails, new TypeReference<>() { 90 Map<String, Object> deviceInfoDetailMap = JSON.parseObject(deviceInfoDetails, new TypeReference<>() {
98 }); 91 });
99 -  
100 JSONArray deviceInfoDetailList = (JSONArray) deviceInfoDetailMap.get("data"); 92 JSONArray deviceInfoDetailList = (JSONArray) deviceInfoDetailMap.get("data");
101 if (CollectionUtils.isEmpty(deviceInfoDetailList)) { 93 if (CollectionUtils.isEmpty(deviceInfoDetailList)) {
102 return; 94 return;
103 } 95 }
104 96
105 JSONObject deviceInfoDetailJson = (JSONObject) deviceInfoDetailList.get(0); 97 JSONObject deviceInfoDetailJson = (JSONObject) deviceInfoDetailList.get(0);
106 -  
107 String lampState = deviceInfoDetailJson.getString("lampState"); 98 String lampState = deviceInfoDetailJson.getString("lampState");
108 String startTime = deviceInfoDetailJson.getString("startTime"); 99 String startTime = deviceInfoDetailJson.getString("startTime");
109 100
@@ -118,111 +109,74 @@ public class DevicePullService { @@ -118,111 +109,74 @@ public class DevicePullService {
118 long minutes = (diffMillis % (1000 * 60 * 60)) / (1000 * 60); 109 long minutes = (diffMillis % (1000 * 60 * 60)) / (1000 * 60);
119 long seconds = (diffMillis % (1000 * 60)) / 1000; 110 long seconds = (diffMillis % (1000 * 60)) / 1000;
120 StringBuilder durationBuilder = new StringBuilder(); 111 StringBuilder durationBuilder = new StringBuilder();
121 - if (hours > 0) {  
122 - durationBuilder.append(hours).append("时");  
123 - }  
124 -  
125 - if (minutes > 0) {  
126 - durationBuilder.append(minutes).append("分");  
127 - }  
128 - 112 + if (hours > 0) durationBuilder.append(hours).append("时");
  113 + if (minutes > 0) durationBuilder.append(minutes).append("分");
129 durationBuilder.append(seconds).append("秒"); 114 durationBuilder.append(seconds).append("秒");
130 String duration = durationBuilder.toString(); 115 String duration = durationBuilder.toString();
131 116
132 - // 获取稼动率  
133 - String utilizationRate = getUtilizationRate(dtuSn); 117 + String utilizationRate = getUtilizationRate(corpCode, dtuSn);
134 118
135 - log.info("设备数据汇总 - projectState:{}, projectType:{}, deviceName:{}, dtuId:{}, deviceId:{}, dtuSn:{}, " + 119 + log.info("设备数据汇总 - corpCode:{}, projectState:{}, projectType:{}, deviceName:{}, dtuId:{}, deviceId:{}, dtuSn:{}, " +
136 "lampState:{}, duration:{}, utilizationRate:{}", 120 "lampState:{}, duration:{}, utilizationRate:{}",
137 - projectState, projectType, deviceName, dtuId, deviceId, dtuSn, 121 + corpCode, projectState, projectType, deviceName, dtuId, deviceId, dtuSn,
138 lampState, duration, utilizationRate); 122 lampState, duration, utilizationRate);
139 123
140 - // 保存或更新数据库  
141 - saveOrUpdateDevice(projectState, projectType, deviceName, dtuId, deviceId, dtuSn, 124 + saveOrUpdateDevice(corpCode, projectState, projectType, deviceName, dtuId, deviceId, dtuSn,
142 lampState, startTime, duration, utilizationRate); 125 lampState, startTime, duration, utilizationRate);
143 } 126 }
144 -  
145 -  
146 } 127 }
147 128
148 - public String getDeviceInfoDetail(String dtuSn) {  
149 - String accessToken = getAccessToken(); 129 + public String getDeviceInfoDetail(String corpCode, String dtuSn) {
  130 + String accessToken = getAccessToken(corpCode);
150 Map<String, String> dtuSnOb = new HashMap<>(1); 131 Map<String, String> dtuSnOb = new HashMap<>(1);
151 dtuSnOb.put("dtuSn", dtuSn); 132 dtuSnOb.put("dtuSn", dtuSn);
152 Map<String, String> headerMap = new HashMap<>(1); 133 Map<String, String> headerMap = new HashMap<>(1);
153 headerMap.put("Authorization", "Bearer " + accessToken); 134 headerMap.put("Authorization", "Bearer " + accessToken);
154 String deviceInfoDetail = sendRequestGet(deviceDetailUrl, dtuSnOb, headerMap); 135 String deviceInfoDetail = sendRequestGet(deviceDetailUrl, dtuSnOb, headerMap);
155 - if (StringUtils.isBlank(deviceInfoDetail)) {  
156 - return null;  
157 - } 136 + if (StringUtils.isBlank(deviceInfoDetail)) return null;
158 137
159 - Map<String, Object> deviceInfoDetailMap = JSON.parseObject(deviceInfoDetail,  
160 - new TypeReference<>() {  
161 - }); 138 + Map<String, Object> deviceInfoDetailMap = JSON.parseObject(deviceInfoDetail, new TypeReference<>() {
  139 + });
162 Integer deviceInfoDetailCode = (Integer) deviceInfoDetailMap.get("code"); 140 Integer deviceInfoDetailCode = (Integer) deviceInfoDetailMap.get("code");
163 - if (deviceInfoDetailCode != 200) {  
164 - return null;  
165 - } 141 + if (deviceInfoDetailCode != 200) return null;
166 142
167 JSONArray deviceInfoDetailList = (JSONArray) deviceInfoDetailMap.get("data"); 143 JSONArray deviceInfoDetailList = (JSONArray) deviceInfoDetailMap.get("data");
168 - if (CollectionUtils.isEmpty(deviceInfoDetailList)) {  
169 - return null;  
170 - } 144 + if (CollectionUtils.isEmpty(deviceInfoDetailList)) return null;
171 145
172 JSONObject deviceInfoDetailJson = (JSONObject) deviceInfoDetailList.get(0); 146 JSONObject deviceInfoDetailJson = (JSONObject) deviceInfoDetailList.get(0);
173 - //灯详情数据  
174 - //灯状态(0:灭灯,1:红,2:黄,3:绿,4:蓝)  
175 Integer lampState = deviceInfoDetailJson.getInteger("lampState"); 147 Integer lampState = deviceInfoDetailJson.getInteger("lampState");
176 - if (lampState == null) {  
177 - return null;  
178 - }  
179 - 148 + if (lampState == null) return null;
180 return deviceInfoDetail; 149 return deviceInfoDetail;
181 } 150 }
182 151
183 - public String getDtuSnRateOfAction(String dtuSn, String startDate, String endDate) {  
184 - String accessToken = getAccessToken(); 152 + public String getDtuSnRateOfAction(String corpCode, String dtuSn, String startDate, String endDate) {
  153 + String accessToken = getAccessToken(corpCode);
185 Map<String, String> headerMap = new HashMap<>(1); 154 Map<String, String> headerMap = new HashMap<>(1);
186 headerMap.put("Authorization", "Bearer " + accessToken); 155 headerMap.put("Authorization", "Bearer " + accessToken);
187 -  
188 Map<String, String> paramsMap = new HashMap<>(); 156 Map<String, String> paramsMap = new HashMap<>();
189 paramsMap.put("startDate", startDate); 157 paramsMap.put("startDate", startDate);
190 paramsMap.put("endDate", endDate); 158 paramsMap.put("endDate", endDate);
191 paramsMap.put("dtuSn", dtuSn); 159 paramsMap.put("dtuSn", dtuSn);
192 -  
193 String rateResult = sendRequestGet(deviceSnRateUrl, paramsMap, headerMap); 160 String rateResult = sendRequestGet(deviceSnRateUrl, paramsMap, headerMap);
194 - if (StringUtils.isBlank(rateResult)) {  
195 - return null;  
196 - }  
197 -  
198 - Map<String, Object> rateMap = JSON.parseObject(rateResult, new TypeReference<>() {}); 161 + if (StringUtils.isBlank(rateResult)) return null;
  162 + Map<String, Object> rateMap = JSON.parseObject(rateResult, new TypeReference<>() {
  163 + });
199 Integer rateCode = (Integer) rateMap.get("code"); 164 Integer rateCode = (Integer) rateMap.get("code");
200 - if (rateCode != 200) {  
201 - return null;  
202 - }  
203 - 165 + if (rateCode != 200) return null;
204 return rateResult; 166 return rateResult;
205 } 167 }
206 168
207 - public String getUtilizationRate(String dtuSn) { 169 + public String getUtilizationRate(String corpCode, String dtuSn) {
208 String today = new SimpleDateFormat("yyyy-MM-dd").format(new Date()); 170 String today = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
209 - String rateResult = getDtuSnRateOfAction(dtuSn, today, today);  
210 - if (StringUtils.isBlank(rateResult)) {  
211 - return "0%";  
212 - }  
213 -  
214 - Map<String, Object> rateMap = JSON.parseObject(rateResult, new TypeReference<>() {}); 171 + String rateResult = getDtuSnRateOfAction(corpCode, dtuSn, today, today);
  172 + if (StringUtils.isBlank(rateResult)) return "0%";
  173 + Map<String, Object> rateMap = JSON.parseObject(rateResult, new TypeReference<>() {
  174 + });
215 JSONArray dataList = (JSONArray) rateMap.get("data"); 175 JSONArray dataList = (JSONArray) rateMap.get("data");
216 - if (CollectionUtils.isEmpty(dataList)) {  
217 - return "0%";  
218 - }  
219 - 176 + if (CollectionUtils.isEmpty(dataList)) return "0%";
220 JSONObject todayData = (JSONObject) dataList.get(0); 177 JSONObject todayData = (JSONObject) dataList.get(0);
221 JSONArray realRateList = todayData.getJSONArray("realRate"); 178 JSONArray realRateList = todayData.getJSONArray("realRate");
222 - if (CollectionUtils.isEmpty(realRateList)) {  
223 - return "0%";  
224 - }  
225 - 179 + if (CollectionUtils.isEmpty(realRateList)) return "0%";
226 JSONObject rateObj = (JSONObject) realRateList.get(0); 180 JSONObject rateObj = (JSONObject) realRateList.get(0);
227 long state0 = rateObj.getLongValue("0"); 181 long state0 = rateObj.getLongValue("0");
228 long state1 = rateObj.getLongValue("1"); 182 long state1 = rateObj.getLongValue("1");
@@ -231,149 +185,132 @@ public class DevicePullService { @@ -231,149 +185,132 @@ public class DevicePullService {
231 long state4 = rateObj.getLongValue("4"); 185 long state4 = rateObj.getLongValue("4");
232 long state5 = rateObj.getLongValue("5"); 186 long state5 = rateObj.getLongValue("5");
233 long totalTime = state0 + state1 + state2 + state3 + state4 + state5; 187 long totalTime = state0 + state1 + state2 + state3 + state4 + state5;
234 - if (totalTime == 0) {  
235 - return "0%";  
236 - }  
237 - 188 + if (totalTime == 0) return "0%";
238 double rate = (double) state3 / totalTime * 100; 189 double rate = (double) state3 / totalTime * 100;
239 return String.format("%.2f%%", rate); 190 return String.format("%.2f%%", rate);
240 } 191 }
241 192
242 - public String getLampData(String dtuSn, String date) {  
243 - String accessToken = getAccessToken(); 193 + public String getLampData(String corpCode, String dtuSn, String date) {
  194 + String accessToken = getAccessToken(corpCode);
244 Map<String, String> headerMap = new HashMap<>(1); 195 Map<String, String> headerMap = new HashMap<>(1);
245 headerMap.put("Authorization", "Bearer " + accessToken); 196 headerMap.put("Authorization", "Bearer " + accessToken);
246 -  
247 Map<String, String> paramsMap = new HashMap<>(); 197 Map<String, String> paramsMap = new HashMap<>();
248 paramsMap.put("dtuSn", dtuSn); 198 paramsMap.put("dtuSn", dtuSn);
249 paramsMap.put("date", date); 199 paramsMap.put("date", date);
250 -  
251 return sendRequestGet(deviceLampUrl, paramsMap, headerMap); 200 return sendRequestGet(deviceLampUrl, paramsMap, headerMap);
252 } 201 }
253 202
254 - public void saveOrUpdateDevice(String projectState, String projectType, String deviceName, String dtuId, 203 + private void saveOrUpdateDevice(String corpCode, String projectState, String projectType, String deviceName, String dtuId,
255 String deviceId, String dtuSn, String lampState, String startTime, 204 String deviceId, String dtuSn, String lampState, String startTime,
256 String duration, String utilizationRate) { 205 String duration, String utilizationRate) {
257 - // 查询是否已存在(按公司+dtuSn判断)  
258 - List<Map<String, Object>> existList = jdbcTemplate.queryForList(  
259 - "SELECT id FROM " + deviceTableName + " WHERE corp_code = ? AND dtuSn = ?", deviceCorpCode, dtuSn); 206 + String tableName = corpConfigService.getDeviceTableName(corpCode);
  207 + JdbcTemplate jt = corpConfigService.getJdbcTemplate(corpCode);
260 208
  209 + List<Map<String, Object>> existList = jt.queryForList(
  210 + "SELECT id FROM " + tableName + " WHERE corp_code = ? AND dtuSn = ?", corpCode, dtuSn);
261 Date now = new Date(); 211 Date now = new Date();
262 if (!existList.isEmpty()) { 212 if (!existList.isEmpty()) {
263 - // 更新  
264 - jdbcTemplate.update("UPDATE " + deviceTableName + " SET projectState = ?, projectType = ?, deviceName = ?, " + 213 + jt.update("UPDATE " + tableName + " SET projectState = ?, projectType = ?, deviceName = ?, " +
265 "dtuId = ?, deviceId = ?, lampState = ?, startTime = ?, duration = ?, utilizationRate = ?, updated_at = ? WHERE dtuSn = ?", 214 "dtuId = ?, deviceId = ?, lampState = ?, startTime = ?, duration = ?, utilizationRate = ?, updated_at = ? WHERE dtuSn = ?",
266 - projectState, projectType, deviceName, dtuId, deviceId, lampState,  
267 - startTime, duration, utilizationRate, now, dtuSn);  
268 - log.info("设备数据更新成功 - dtuSn:{}", dtuSn); 215 + projectState, projectType, deviceName, dtuId, deviceId, lampState, startTime, duration, utilizationRate, now, dtuSn);
  216 + log.info("设备数据更新成功 - corpCode:{}, dtuSn:{}", corpCode, dtuSn);
269 } else { 217 } else {
270 - // 新增  
271 String id = UUID.randomUUID().toString().replace("-", ""); 218 String id = UUID.randomUUID().toString().replace("-", "");
272 - jdbcTemplate.update("INSERT INTO " + deviceTableName + " (id, corp_code, created_at, created_by, updated_at, updated_by, " + 219 + jt.update("INSERT INTO " + tableName + " (id, corp_code, created_at, created_by, updated_at, updated_by, " +
273 "deviceName, projectType, projectState, dtuSn, dtuId, deviceId, lampState, startTime, duration, utilizationRate) " + 220 "deviceName, projectType, projectState, dtuSn, dtuId, deviceId, lampState, startTime, duration, utilizationRate) " +
274 - "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",  
275 - id, deviceCorpCode, now, "system", now, "system",  
276 - deviceName, projectType, projectState, dtuSn, dtuId, deviceId, lampState,  
277 - startTime, duration, utilizationRate);  
278 - log.info("设备数据新增成功 - dtuSn:{}", dtuSn); 221 + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
  222 + id, corpCode, now, "system", now, "system",
  223 + deviceName, projectType, projectState, dtuSn, dtuId, deviceId, lampState, startTime, duration, utilizationRate);
  224 + log.info("设备数据新增成功 - corpCode:{}, dtuSn:{}", corpCode, dtuSn);
279 } 225 }
280 } 226 }
281 227
282 /** 228 /**
283 - * 首次全量同步:本年1月1日 ~ 昨天(手动触发一次) 229 + * 首次全量同步
284 */ 230 */
285 - public void pullDevUtilAndSave() { 231 + public void pullDevUtilAndSave(String corpCode) {
  232 + if (!corpConfigService.hasValidIotCredentials(corpCode)) {
  233 + log.warn("【全量同步-利用率】IoT凭证为空, 跳过同步, corpCode={}", corpCode);
  234 + return;
  235 + }
286 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); 236 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
287 Calendar cal = Calendar.getInstance(); 237 Calendar cal = Calendar.getInstance();
288 - cal.add(Calendar.DAY_OF_MONTH, -1); // 昨天 238 + cal.add(Calendar.DAY_OF_MONTH, -1);
289 String endDate = sdf.format(cal.getTime()); 239 String endDate = sdf.format(cal.getTime());
290 cal.set(cal.get(Calendar.YEAR), Calendar.JANUARY, 1); 240 cal.set(cal.get(Calendar.YEAR), Calendar.JANUARY, 1);
291 String startDate = sdf.format(cal.getTime()); 241 String startDate = sdf.format(cal.getTime());
292 -  
293 - log.info("【全量同步】设备利用率,日期范围: {} ~ {}", startDate, endDate);  
294 - doSyncDevUtil(startDate, endDate); 242 + log.info("【全量同步】设备利用率, corpCode:{}, 日期范围: {} ~ {}", corpCode, startDate, endDate);
  243 + doSyncDevUtil(corpCode, "2026-05-01", endDate);
295 } 244 }
296 245
297 - /**  
298 - * 每日增量同步:仅同步昨天的数据(定时任务自动触发)  
299 - */  
300 @Scheduled(cron = "${scheduler.devUtil.cron:0 30 2 * * ?}") 246 @Scheduled(cron = "${scheduler.devUtil.cron:0 30 2 * * ?}")
301 public void pullDevUtilDaily() { 247 public void pullDevUtilDaily() {
  248 + List<String> corpCodes = corpConfigService.getAllCorpCodes();
  249 + if (corpCodes.isEmpty()) {
  250 + log.warn("【每日增量】设备利用率: 未找到任何公司配置,跳过");
  251 + return;
  252 + }
302 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); 253 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
303 Calendar cal = Calendar.getInstance(); 254 Calendar cal = Calendar.getInstance();
304 cal.add(Calendar.DAY_OF_MONTH, -1); 255 cal.add(Calendar.DAY_OF_MONTH, -1);
305 String yesterday = sdf.format(cal.getTime()); 256 String yesterday = sdf.format(cal.getTime());
306 -  
307 - log.info("【每日增量】同步设备利用率,日期: {}", yesterday);  
308 - doSyncDevUtil(yesterday, yesterday); 257 + for (String corpCode : corpCodes) {
  258 + log.info("【每日增量】同步设备利用率, corpCode:{}, 日期: {}", corpCode, yesterday);
  259 + doSyncDevUtil(corpCode, yesterday, yesterday);
  260 + }
309 } 261 }
310 262
311 - /**  
312 - * 核心同步逻辑:获取设备列表 → 按每31天分批调用 dtuSnRateOfAction → 写入/更新 t_auto_ymk_iot_dev_util  
313 - */  
314 - private void doSyncDevUtil(String startDate, String endDate) {  
315 - String deviceResult = getDeviceInfo(); 263 + private void doSyncDevUtil(String corpCode, String startDate, String endDate) {
  264 + String deviceResult = getDeviceInfo(corpCode);
316 if (StringUtils.isBlank(deviceResult)) { 265 if (StringUtils.isBlank(deviceResult)) {
317 log.error("获取设备列表失败"); 266 log.error("获取设备列表失败");
318 return; 267 return;
319 } 268 }
320 - Map<String, Object> deviceInfos = JSON.parseObject(deviceResult, new TypeReference<>() {}); 269 + Map<String, Object> deviceInfos = JSON.parseObject(deviceResult, new TypeReference<>() {
  270 + });
321 JSONArray deviceInfoList = (JSONArray) deviceInfos.get("data"); 271 JSONArray deviceInfoList = (JSONArray) deviceInfos.get("data");
322 if (CollectionUtils.isEmpty(deviceInfoList)) { 272 if (CollectionUtils.isEmpty(deviceInfoList)) {
323 log.warn("设备列表为空"); 273 log.warn("设备列表为空");
324 return; 274 return;
325 } 275 }
326 276
327 - // 按最多31天拆分为多个日期区间  
328 List<DateRange> batches = splitDateRange(startDate, endDate); 277 List<DateRange> batches = splitDateRange(startDate, endDate);
329 - log.info("开始同步设备利用率数据,设备数: {}, 日期范围: {} ~ {}, 共分{}批次",  
330 - deviceInfoList.size(), startDate, endDate, batches.size());  
331 - int totalSaved = 0; 278 + log.info("开始同步设备利用率数据, corpCode:{}, 设备数:{}, 日期范围: {} ~ {}, 共分{}批次",
  279 + corpCode, deviceInfoList.size(), startDate, endDate, batches.size());
332 280
333 for (Object o : deviceInfoList) { 281 for (Object o : deviceInfoList) {
334 JSONObject deviceInfoJson = (JSONObject) o; 282 JSONObject deviceInfoJson = (JSONObject) o;
335 String dtuSn = deviceInfoJson.getString("dtuSn"); 283 String dtuSn = deviceInfoJson.getString("dtuSn");
336 -  
337 - // 每个设备按31天一批次逐批调用  
338 for (DateRange batch : batches) { 284 for (DateRange batch : batches) {
339 try { 285 try {
340 - String rateResult = getDtuSnRateOfAction(dtuSn, batch.start, batch.end); 286 + String rateResult = getDtuSnRateOfAction(corpCode, dtuSn, batch.start, batch.end);
341 if (StringUtils.isBlank(rateResult)) continue; 287 if (StringUtils.isBlank(rateResult)) continue;
342 -  
343 - Map<String, Object> rateMap = JSON.parseObject(rateResult, new TypeReference<>() {}); 288 + Map<String, Object> rateMap = JSON.parseObject(rateResult, new TypeReference<>() {
  289 + });
344 Integer code = (Integer) rateMap.get("code"); 290 Integer code = (Integer) rateMap.get("code");
345 if (code == null || code != 200) continue; 291 if (code == null || code != 200) continue;
346 -  
347 JSONArray dataList = (JSONArray) rateMap.get("data"); 292 JSONArray dataList = (JSONArray) rateMap.get("data");
348 if (CollectionUtils.isEmpty(dataList)) continue; 293 if (CollectionUtils.isEmpty(dataList)) continue;
349 -  
350 for (int i = 0; i < dataList.size(); i++) { 294 for (int i = 0; i < dataList.size(); i++) {
351 JSONObject dayData = (JSONObject) dataList.get(i); 295 JSONObject dayData = (JSONObject) dataList.get(i);
352 String dateStr = dayData.getString("date"); 296 String dateStr = dayData.getString("date");
353 JSONArray realRateList = dayData.getJSONArray("realRate"); 297 JSONArray realRateList = dayData.getJSONArray("realRate");
354 if (CollectionUtils.isEmpty(realRateList)) continue; 298 if (CollectionUtils.isEmpty(realRateList)) continue;
355 -  
356 JSONObject rateObj = (JSONObject) realRateList.get(0); 299 JSONObject rateObj = (JSONObject) realRateList.get(0);
357 - double state0 = rateObj.getDoubleValue("0");  
358 - double state1 = rateObj.getDoubleValue("1");  
359 - double state2 = rateObj.getDoubleValue("2");  
360 - double state3 = rateObj.getDoubleValue("3");  
361 - double state4 = rateObj.getDoubleValue("4");  
362 -  
363 - saveOrUpdateDevUtil(dtuSn, dateStr, state0, state1, state2, state3, state4);  
364 - totalSaved++; 300 + double s0 = rateObj.getDoubleValue("0");
  301 + double s1 = rateObj.getDoubleValue("1");
  302 + double s2 = rateObj.getDoubleValue("2");
  303 + double s3 = rateObj.getDoubleValue("3");
  304 + double s4 = rateObj.getDoubleValue("4");
  305 + saveOrUpdateDevUtil(corpCode, dtuSn, dateStr, s0, s1, s2, s3, s4);
365 } 306 }
366 } catch (Exception e) { 307 } catch (Exception e) {
367 log.error("处理设备 {} 数据异常 - 批次:{}~{}", dtuSn, batch.start, batch.end, e); 308 log.error("处理设备 {} 数据异常 - 批次:{}~{}", dtuSn, batch.start, batch.end, e);
368 } 309 }
369 } 310 }
370 } 311 }
371 - log.info("设备利用率数据同步完成,共保存 {} 条记录", totalSaved);  
372 } 312 }
373 313
374 - /**  
375 - * 按最大31天将日期范围拆分为多段  
376 - */  
377 private static List<DateRange> splitDateRange(String startDate, String endDate) { 314 private static List<DateRange> splitDateRange(String startDate, String endDate) {
378 List<DateRange> ranges = new ArrayList<>(); 315 List<DateRange> ranges = new ArrayList<>();
379 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); 316 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
@@ -382,21 +319,13 @@ public class DevicePullService { @@ -382,21 +319,13 @@ public class DevicePullService {
382 cur.setTime(sdf.parse(startDate)); 319 cur.setTime(sdf.parse(startDate));
383 Calendar endCal = Calendar.getInstance(); 320 Calendar endCal = Calendar.getInstance();
384 endCal.setTime(sdf.parse(endDate)); 321 endCal.setTime(sdf.parse(endDate));
385 -  
386 while (!cur.after(endCal)) { 322 while (!cur.after(endCal)) {
387 DateRange range = new DateRange(sdf.format(cur.getTime()), null); 323 DateRange range = new DateRange(sdf.format(cur.getTime()), null);
388 -  
389 - // 向后推进30天(即当前日+30,共31天)  
390 Calendar batchEnd = Calendar.getInstance(); 324 Calendar batchEnd = Calendar.getInstance();
391 batchEnd.setTime(cur.getTime()); 325 batchEnd.setTime(cur.getTime());
392 batchEnd.add(Calendar.DAY_OF_MONTH, 30); 326 batchEnd.add(Calendar.DAY_OF_MONTH, 30);
393 -  
394 - if (!batchEnd.after(endCal)) {  
395 - range.end = sdf.format(batchEnd.getTime());  
396 - } else {  
397 - range.end = sdf.format(endCal.getTime());  
398 - }  
399 - 327 + if (!batchEnd.after(endCal)) range.end = sdf.format(batchEnd.getTime());
  328 + else range.end = sdf.format(endCal.getTime());
400 ranges.add(range); 329 ranges.add(range);
401 cur.add(Calendar.DAY_OF_MONTH, 31); 330 cur.add(Calendar.DAY_OF_MONTH, 31);
402 } 331 }
@@ -406,7 +335,7 @@ public class DevicePullService { @@ -406,7 +335,7 @@ public class DevicePullService {
406 return ranges; 335 return ranges;
407 } 336 }
408 337
409 - private static class DateRange { 338 + static class DateRange {
410 String start; 339 String start;
411 String end; 340 String end;
412 341
@@ -416,67 +345,66 @@ public class DevicePullService { @@ -416,67 +345,66 @@ public class DevicePullService {
416 } 345 }
417 } 346 }
418 347
419 - private void saveOrUpdateDevUtil(String dtuSn, String dateUtil,  
420 - double s0, double s1, double s2, double s3, double s4) {  
421 - List<Map<String, Object>> existList = jdbcTemplate.queryForList(  
422 - "SELECT id FROM " + devUtilTableName + " WHERE corp_code = ? AND dtuSn = ? AND date_util = ?",  
423 - deviceCorpCode, dtuSn, dateUtil); 348 + private void saveOrUpdateDevUtil(String corpCode, String dtuSn, String dateUtil, double s0, double s1, double s2, double s3, double s4) {
  349 + String devUtilTableName = corpConfigService.getDevUtilTableName(corpCode);
  350 + JdbcTemplate jt = corpConfigService.getJdbcTemplate(corpCode);
424 351
  352 + List<Map<String, Object>> existList = jt.queryForList(
  353 + "SELECT id FROM " + devUtilTableName + " WHERE corp_code = ? AND dtuSn = ? AND date_util = ?",
  354 + corpCode, dtuSn, dateUtil);
425 Date now = new Date(); 355 Date now = new Date();
426 if (!existList.isEmpty()) { 356 if (!existList.isEmpty()) {
427 - jdbcTemplate.update(  
428 - "UPDATE " + devUtilTableName + " SET `0`=?,`1`=?,`2`=?,`3`=?,`4`=?,updated_at=? WHERE dtuSn=? AND date_util=?", 357 + jt.update("UPDATE " + devUtilTableName + " SET `0`=?,`1`=?,`2`=?,`3`=?,`4`=?,updated_at=? WHERE dtuSn=? AND date_util=?",
429 s0, s1, s2, s3, s4, now, dtuSn, dateUtil); 358 s0, s1, s2, s3, s4, now, dtuSn, dateUtil);
430 } else { 359 } else {
431 String id = UUID.randomUUID().toString().replace("-", ""); 360 String id = UUID.randomUUID().toString().replace("-", "");
432 - jdbcTemplate.update(  
433 - "INSERT INTO " + devUtilTableName + " (id,corp_code,created_at,created_by,updated_at,updated_by,date_util,dtuSn,`0`,`1`,`2`,`3`,`4`) " +  
434 - "VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)",  
435 - id, deviceCorpCode, now, "system", now, "system", dateUtil, dtuSn, s0, s1, s2, s3, s4); 361 + jt.update("INSERT INTO " + devUtilTableName + " (id,corp_code,created_at,created_by,updated_at,updated_by,date_util,dtuSn,`0`,`1`,`2`,`3`,`4`) " +
  362 + "VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)", id, corpCode, now, "system", now, "system", dateUtil, dtuSn, s0, s1, s2, s3, s4);
436 } 363 }
437 } 364 }
438 365
439 // ==================== OEE 时序数据同步 ==================== 366 // ==================== OEE 时序数据同步 ====================
440 367
441 - /**  
442 - * 首次全量同步 OEE:本年1月1日 ~ 昨天(手动触发一次)  
443 - */  
444 - public void pullOeeAndSave() { 368 + public void pullOeeAndSave(String corpCode) {
  369 + if (!corpConfigService.hasValidIotCredentials(corpCode)) {
  370 + log.warn("【全量同步-OEE】IoT凭证为空, 跳过同步, corpCode={}", corpCode);
  371 + return;
  372 + }
445 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); 373 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
446 Calendar cal = Calendar.getInstance(); 374 Calendar cal = Calendar.getInstance();
447 cal.add(Calendar.DAY_OF_MONTH, -1); 375 cal.add(Calendar.DAY_OF_MONTH, -1);
448 String endDate = sdf.format(cal.getTime()); 376 String endDate = sdf.format(cal.getTime());
449 cal.set(cal.get(Calendar.YEAR), Calendar.JANUARY, 1); 377 cal.set(cal.get(Calendar.YEAR), Calendar.JANUARY, 1);
450 String startDate = sdf.format(cal.getTime()); 378 String startDate = sdf.format(cal.getTime());
451 -  
452 - log.info("【全量同步】OEE时序数据,日期范围: {} ~ {}", startDate, endDate);  
453 - doSyncOee(startDate, endDate); 379 + log.info("【全量同步】OEE时序数据, corpCode:{}, 日期范围: {} ~ {}", corpCode, startDate, endDate);
  380 + doSyncOee(corpCode, "2026-05-01", endDate);
454 } 381 }
455 382
456 - /**  
457 - * 每日增量同步 OEE:仅同步昨天(定时任务自动触发)  
458 - */  
459 @Scheduled(cron = "${scheduler.oee.cron:0 35 2 * * ?}") 383 @Scheduled(cron = "${scheduler.oee.cron:0 35 2 * * ?}")
460 public void pullOeeDaily() { 384 public void pullOeeDaily() {
  385 + List<String> corpCodes = corpConfigService.getAllCorpCodes();
  386 + if (corpCodes.isEmpty()) {
  387 + log.warn("OEE: no corp config found, skip");
  388 + return;
  389 + }
461 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); 390 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
462 Calendar cal = Calendar.getInstance(); 391 Calendar cal = Calendar.getInstance();
463 cal.add(Calendar.DAY_OF_MONTH, -1); 392 cal.add(Calendar.DAY_OF_MONTH, -1);
464 String yesterday = sdf.format(cal.getTime()); 393 String yesterday = sdf.format(cal.getTime());
465 -  
466 - log.info("【每日增量】同步OEE时序数据,日期: {}", yesterday);  
467 - doSyncOee(yesterday, yesterday); 394 + for (String corpCode : corpCodes) {
  395 + log.info("[Daily] sync OEE, corpCode:{}, date: {}", corpCode, yesterday);
  396 + doSyncOee(corpCode, yesterday, yesterday);
  397 + }
468 } 398 }
469 399
470 - /**  
471 - * OEE 核心同步:获取设备列表 → 每个设备每天调用 /triColorLamp/dtuSn → lampData JSON 存入 description  
472 - */  
473 - private void doSyncOee(String startDate, String endDate) {  
474 - String deviceResult = getDeviceInfo(); 400 + private void doSyncOee(String corpCode, String startDate, String endDate) {
  401 + String deviceResult = getDeviceInfo(corpCode);
475 if (StringUtils.isBlank(deviceResult)) { 402 if (StringUtils.isBlank(deviceResult)) {
476 log.error("获取设备列表失败"); 403 log.error("获取设备列表失败");
477 return; 404 return;
478 } 405 }
479 - Map<String, Object> deviceInfos = JSON.parseObject(deviceResult, new TypeReference<>() {}); 406 + Map<String, Object> deviceInfos = JSON.parseObject(deviceResult, new TypeReference<>() {
  407 + });
480 JSONArray deviceInfoList = (JSONArray) deviceInfos.get("data"); 408 JSONArray deviceInfoList = (JSONArray) deviceInfos.get("data");
481 if (CollectionUtils.isEmpty(deviceInfoList)) { 409 if (CollectionUtils.isEmpty(deviceInfoList)) {
482 log.warn("设备列表为空"); 410 log.warn("设备列表为空");
@@ -499,30 +427,24 @@ public class DevicePullService { @@ -499,30 +427,24 @@ public class DevicePullService {
499 return; 427 return;
500 } 428 }
501 429
502 - log.info("开始同步OEE时序数据,设备数: {}, 天数: {}", deviceInfoList.size(), dateList.size());  
503 int totalSaved = 0; 430 int totalSaved = 0;
504 -  
505 for (Object o : deviceInfoList) { 431 for (Object o : deviceInfoList) {
506 JSONObject deviceInfoJson = (JSONObject) o; 432 JSONObject deviceInfoJson = (JSONObject) o;
507 String dtuSn = deviceInfoJson.getString("dtuSn"); 433 String dtuSn = deviceInfoJson.getString("dtuSn");
508 -  
509 for (String dateStr : dateList) { 434 for (String dateStr : dateList) {
510 try { 435 try {
511 - String lampResult = getLampData(dtuSn, dateStr); 436 + String lampResult = getLampData(corpCode, dtuSn, dateStr);
512 if (StringUtils.isBlank(lampResult)) continue; 437 if (StringUtils.isBlank(lampResult)) continue;
513 -  
514 - Map<String, Object> lampMap = JSON.parseObject(lampResult, new TypeReference<>() {}); 438 + Map<String, Object> lampMap = JSON.parseObject(lampResult, new TypeReference<>() {
  439 + });
515 Integer code = (Integer) lampMap.get("code"); 440 Integer code = (Integer) lampMap.get("code");
516 if (code == null || code != 200) continue; 441 if (code == null || code != 200) continue;
517 -  
518 JSONArray dataList = (JSONArray) lampMap.get("data"); 442 JSONArray dataList = (JSONArray) lampMap.get("data");
519 if (CollectionUtils.isEmpty(dataList)) continue; 443 if (CollectionUtils.isEmpty(dataList)) continue;
520 -  
521 JSONObject dataObj = (JSONObject) dataList.get(0); 444 JSONObject dataObj = (JSONObject) dataList.get(0);
522 JSONArray lampDataArr = dataObj.getJSONArray("lampData"); 445 JSONArray lampDataArr = dataObj.getJSONArray("lampData");
523 String description = lampDataArr != null ? lampDataArr.toJSONString() : "[]"; 446 String description = lampDataArr != null ? lampDataArr.toJSONString() : "[]";
524 -  
525 - saveOrUpdateOee(dtuSn, dateStr, description); 447 + saveOrUpdateOee(corpCode, dtuSn, dateStr, description);
526 totalSaved++; 448 totalSaved++;
527 } catch (Exception e) { 449 } catch (Exception e) {
528 log.error("处理OEE设备 {} 数据异常 - date:{}", dtuSn, dateStr, e); 450 log.error("处理OEE设备 {} 数据异常 - date:{}", dtuSn, dateStr, e);
@@ -532,11 +454,12 @@ public class DevicePullService { @@ -532,11 +454,12 @@ public class DevicePullService {
532 log.info("OEE时序数据同步完成,共保存 {} 条记录", totalSaved); 454 log.info("OEE时序数据同步完成,共保存 {} 条记录", totalSaved);
533 } 455 }
534 456
535 - private void saveOrUpdateOee(String dtuSn, String oeeDate, String description) { 457 + private void saveOrUpdateOee(String corpCode, String dtuSn, String oeeDate, String description) {
  458 + String oeeTableName = corpConfigService.getOeeTableName(corpCode);
  459 + JdbcTemplate jt = corpConfigService.getJdbcTemplate(corpCode);
536 int maxLen = 60000; 460 int maxLen = 60000;
537 String lamp1 = ""; 461 String lamp1 = "";
538 String lamp2 = ""; 462 String lamp2 = "";
539 -  
540 if (description.length() > maxLen) { 463 if (description.length() > maxLen) {
541 lamp1 = description.substring(0, maxLen); 464 lamp1 = description.substring(0, maxLen);
542 lamp2 = description.substring(maxLen); 465 lamp2 = description.substring(maxLen);
@@ -544,175 +467,107 @@ public class DevicePullService { @@ -544,175 +467,107 @@ public class DevicePullService {
544 lamp1 = description; 467 lamp1 = description;
545 } 468 }
546 469
547 - List<Map<String, Object>> existList = jdbcTemplate.queryForList( 470 + List<Map<String, Object>> existList = jt.queryForList(
548 "SELECT id FROM " + oeeTableName + " WHERE corp_code = ? AND dtuSn = ? AND oee_date = ?", 471 "SELECT id FROM " + oeeTableName + " WHERE corp_code = ? AND dtuSn = ? AND oee_date = ?",
549 - deviceCorpCode, dtuSn, oeeDate);  
550 - 472 + corpCode, dtuSn, oeeDate);
551 Date now = new Date(); 473 Date now = new Date();
552 if (!existList.isEmpty()) { 474 if (!existList.isEmpty()) {
553 - jdbcTemplate.update(  
554 - "UPDATE " + oeeTableName + " SET triColorLamp1=?, triColorLamp2=?, updated_at=? WHERE dtuSn=? AND oee_date=?",  
555 - lamp1, lamp2, now, dtuSn, oeeDate); 475 + jt.update("UPDATE " + oeeTableName + " SET triColorLamp1=?, triColorLamp2=?, updated_at=? WHERE dtuSn=? AND oee_date=?", lamp1, lamp2, now, dtuSn, oeeDate);
556 } else { 476 } else {
557 String id = UUID.randomUUID().toString().replace("-", ""); 477 String id = UUID.randomUUID().toString().replace("-", "");
558 - jdbcTemplate.update(  
559 - "INSERT INTO " + oeeTableName + " (id,corp_code,created_at,created_by,updated_at,updated_by,dtuSn,oee_date,triColorLamp1,triColorLamp2) " +  
560 - "VALUES (?,?,?,?,?,?,?,?,?,?)",  
561 - id, deviceCorpCode, now, "system", now, "system", dtuSn, oeeDate, lamp1, lamp2); 478 + jt.update("INSERT INTO " + oeeTableName + " (id,corp_code,created_at,created_by,updated_at,updated_by,dtuSn,oee_date,triColorLamp1,triColorLamp2) " +
  479 + "VALUES (?,?,?,?,?,?,?,?,?,?)", id, corpCode, now, "system", now, "system", dtuSn, oeeDate, lamp1, lamp2);
562 } 480 }
563 } 481 }
564 482
565 - public String getEnergyInfo() {  
566 - String accessToken = getAccessToken(); 483 + public String getEnergyInfo(String corpCode) {
  484 + String accessToken = getAccessToken(corpCode);
567 Map<String, String> headerMap = new HashMap<>(1); 485 Map<String, String> headerMap = new HashMap<>(1);
568 headerMap.put("Authorization", "Bearer " + accessToken); 486 headerMap.put("Authorization", "Bearer " + accessToken);
569 -  
570 Map<String, String> paramsMap = new HashMap<>(); 487 Map<String, String> paramsMap = new HashMap<>();
571 - paramsMap.put("groupName", "SHC");  
572 - 488 + paramsMap.put("groupName", corpConfigService.getIotOrg(corpCode));
573 String energyInfoResult = sendRequestGet(energyInfoUrl, paramsMap, headerMap); 489 String energyInfoResult = sendRequestGet(energyInfoUrl, paramsMap, headerMap);
574 - if (StringUtils.isBlank(energyInfoResult)) {  
575 - return null;  
576 - }  
577 -  
578 - // 解析设备信息 490 + if (StringUtils.isBlank(energyInfoResult)) return null;
579 Map<String, Object> energyInfos = JSON.parseObject(energyInfoResult, new TypeReference<>() { 491 Map<String, Object> energyInfos = JSON.parseObject(energyInfoResult, new TypeReference<>() {
580 }); 492 });
581 Integer energyInfoCode = (Integer) energyInfos.get("code"); 493 Integer energyInfoCode = (Integer) energyInfos.get("code");
582 -  
583 - // 如果code不为200,可能是accessToken失效,重新获取token并重试  
584 if (energyInfoCode != 200) { 494 if (energyInfoCode != 200) {
585 - accessToken = getAccessToken();  
586 - if (StringUtils.isEmpty(accessToken)) {  
587 - return null;  
588 - }  
589 -  
590 - // 更新headerMap中的Authorization 495 + accessToken = getAccessToken(corpCode);
  496 + if (StringUtils.isEmpty(accessToken)) return null;
591 headerMap.put("Authorization", "Bearer " + accessToken); 497 headerMap.put("Authorization", "Bearer " + accessToken);
592 -  
593 - // 第二次请求设备信息  
594 energyInfoResult = sendRequestGet(energyInfoUrl, paramsMap, headerMap); 498 energyInfoResult = sendRequestGet(energyInfoUrl, paramsMap, headerMap);
595 - if (StringUtils.isBlank(energyInfoResult)) {  
596 - return null;  
597 - }  
598 -  
599 - // 重新解析设备信息 499 + if (StringUtils.isBlank(energyInfoResult)) return null;
600 energyInfos = JSON.parseObject(energyInfoResult, new TypeReference<Map<String, Object>>() { 500 energyInfos = JSON.parseObject(energyInfoResult, new TypeReference<Map<String, Object>>() {
601 }); 501 });
602 energyInfoCode = (Integer) energyInfos.get("code"); 502 energyInfoCode = (Integer) energyInfos.get("code");
603 -  
604 - // 如果第二次请求仍然失败,返回错误信息  
605 - if (energyInfoCode != 200) {  
606 - return null;  
607 - } 503 + if (energyInfoCode != 200) return null;
608 } 504 }
609 -  
610 - // 返回成功的设备信息  
611 return energyInfoResult; 505 return energyInfoResult;
612 } 506 }
613 507
614 - public String getDeviceInfo() {  
615 - String accessToken = getAccessToken();  
616 - // 初始化headerMap并设置Authorization 508 + public String getDeviceInfo(String corpCode) {
  509 + String accessToken = getAccessToken(corpCode);
617 Map<String, String> headerMap = new HashMap<>(1); 510 Map<String, String> headerMap = new HashMap<>(1);
618 headerMap.put("Authorization", "Bearer " + accessToken); 511 headerMap.put("Authorization", "Bearer " + accessToken);
619 -  
620 Map<String, String> paramsMap = new HashMap<>(); 512 Map<String, String> paramsMap = new HashMap<>();
621 - paramsMap.put("groupName", "SHC");  
622 -  
623 - // 第一次请求设备信息 513 + paramsMap.put("groupName", corpConfigService.getIotOrg(corpCode));
624 String deviceResult = sendRequestGet(deviceInfoUrl, paramsMap, headerMap); 514 String deviceResult = sendRequestGet(deviceInfoUrl, paramsMap, headerMap);
625 -  
626 - // 检查设备信息是否为空  
627 - if (StringUtils.isBlank(deviceResult)) {  
628 - return null;  
629 - }  
630 -  
631 - // 解析设备信息 515 + if (StringUtils.isBlank(deviceResult)) return null;
632 Map<String, Object> deviceInfos = JSON.parseObject(deviceResult, new TypeReference<Map<String, Object>>() { 516 Map<String, Object> deviceInfos = JSON.parseObject(deviceResult, new TypeReference<Map<String, Object>>() {
633 }); 517 });
634 Integer deviceInfoCode = (Integer) deviceInfos.get("code"); 518 Integer deviceInfoCode = (Integer) deviceInfos.get("code");
635 -  
636 - // 如果code不为200,可能是accessToken失效,重新获取token并重试  
637 if (deviceInfoCode != 200) { 519 if (deviceInfoCode != 200) {
638 - accessToken = getAccessToken();  
639 - if (StringUtils.isEmpty(accessToken)) {  
640 - return null;  
641 - }  
642 -  
643 - // 更新headerMap中的Authorization 520 + accessToken = getAccessToken(corpCode);
  521 + if (StringUtils.isEmpty(accessToken)) return null;
644 headerMap.put("Authorization", "Bearer " + accessToken); 522 headerMap.put("Authorization", "Bearer " + accessToken);
645 -  
646 - // 第二次请求设备信息  
647 deviceResult = sendRequestGet(deviceInfoUrl, paramsMap, headerMap); 523 deviceResult = sendRequestGet(deviceInfoUrl, paramsMap, headerMap);
648 - if (StringUtils.isBlank(deviceResult)) {  
649 - return null;  
650 - }  
651 -  
652 - // 重新解析设备信息 524 + if (StringUtils.isBlank(deviceResult)) return null;
653 deviceInfos = JSON.parseObject(deviceResult, new TypeReference<Map<String, Object>>() { 525 deviceInfos = JSON.parseObject(deviceResult, new TypeReference<Map<String, Object>>() {
654 }); 526 });
655 deviceInfoCode = (Integer) deviceInfos.get("code"); 527 deviceInfoCode = (Integer) deviceInfos.get("code");
656 -  
657 - // 如果第二次请求仍然失败,返回错误信息  
658 - if (deviceInfoCode != 200) {  
659 - return null;  
660 - } 528 + if (deviceInfoCode != 200) return null;
661 } 529 }
662 -  
663 - // 返回成功的设备信息  
664 return deviceResult; 530 return deviceResult;
665 } 531 }
666 532
667 - private String getAccessToken() { 533 + private String getAccessToken(String corpCode) {
  534 + String redisKey = "hnyssl_device_token_" + corpCode;
668 String accessToken = ""; 535 String accessToken = "";
669 - String redisKey = "hnyssl_device_token";  
670 if (StringUtils.isNotBlank(redisTemplate.opsForValue().get(redisKey)) && redisTemplate.getExpire(redisKey) > 0) { 536 if (StringUtils.isNotBlank(redisTemplate.opsForValue().get(redisKey)) && redisTemplate.getExpire(redisKey) > 0) {
671 return redisTemplate.opsForValue().get(redisKey); 537 return redisTemplate.opsForValue().get(redisKey);
672 } 538 }
673 - 539 + // 使用公司配置中的用户名密码,如果没有则用默认值
  540 + String userName = corpConfigService.getIotUsername(corpCode);
  541 + String password = corpConfigService.getIotPassword(corpCode);
674 Map<String, String> param = new HashMap<>(2); 542 Map<String, String> param = new HashMap<>(2);
675 - param.put("username", deviceUserName);  
676 - param.put("password", devicePassword); 543 + param.put("username", userName);
  544 + param.put("password", password);
677 HttpPost httpPost = new HttpPost(deviceTokenUrl); 545 HttpPost httpPost = new HttpPost(deviceTokenUrl);
678 String result = sendPost(httpPost, JSON.toJSONString(param)); 546 String result = sendPost(httpPost, JSON.toJSONString(param));
679 - if (StringUtils.isBlank(result)) {  
680 - return accessToken;  
681 - }  
682 - 547 + if (StringUtils.isBlank(result)) return accessToken;
683 Map<String, Object> res = JSON.parseObject(result, new TypeReference<>() { 548 Map<String, Object> res = JSON.parseObject(result, new TypeReference<>() {
684 }); 549 });
685 -  
686 Integer code = (Integer) res.get("code"); 550 Integer code = (Integer) res.get("code");
687 if (code == 200) { 551 if (code == 200) {
688 JSONObject data = (JSONObject) res.get("data"); 552 JSONObject data = (JSONObject) res.get("data");
689 accessToken = (String) data.get("token"); 553 accessToken = (String) data.get("token");
690 - redisTemplate.opsForValue().set(redisKey, accessToken, 3600, TimeUnit.SECONDS); // 一小时过期 554 + redisTemplate.opsForValue().set(redisKey, accessToken, 3600, TimeUnit.SECONDS);
691 } 555 }
692 -  
693 return accessToken; 556 return accessToken;
694 } 557 }
695 558
696 public static String sendRequestGet(String url, Map<String, String> params, Map<String, String> header) { 559 public static String sendRequestGet(String url, Map<String, String> params, Map<String, String> header) {
697 - //实例化httpclient  
698 CloseableHttpClient httpclient = HttpClients.createDefault(); 560 CloseableHttpClient httpclient = HttpClients.createDefault();
699 url = builderUrl(url, params); 561 url = builderUrl(url, params);
700 - //请求结果  
701 String content = ""; 562 String content = "";
702 - //实例化get方法  
703 HttpGet httpget = new HttpGet(url); 563 HttpGet httpget = new HttpGet(url);
704 if (!CollectionUtils.isEmpty(header)) { 564 if (!CollectionUtils.isEmpty(header)) {
705 - for (Map.Entry<String, String> entry : header.entrySet()) { 565 + for (Map.Entry<String, String> entry : header.entrySet())
706 httpget.setHeader(entry.getKey(), entry.getValue()); 566 httpget.setHeader(entry.getKey(), entry.getValue());
707 - }  
708 } 567 }
709 -  
710 try (CloseableHttpResponse response = httpclient.execute(httpget)) { 568 try (CloseableHttpResponse response = httpclient.execute(httpget)) {
711 -  
712 - //执行get方法  
713 - if (response.getStatusLine().getStatusCode() == 200) { 569 + if (response.getStatusLine().getStatusCode() == 200)
714 content = EntityUtils.toString(response.getEntity(), "UTF-8"); 570 content = EntityUtils.toString(response.getEntity(), "UTF-8");
715 - }  
716 } catch (IOException e) { 571 } catch (IOException e) {
717 log.error("sendRequest---GET Error!", e); 572 log.error("sendRequest---GET Error!", e);
718 } 573 }
@@ -723,13 +578,9 @@ public class DevicePullService { @@ -723,13 +578,9 @@ public class DevicePullService {
723 UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromHttpUrl(url); 578 UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromHttpUrl(url);
724 if (!CollectionUtils.isEmpty(params)) { 579 if (!CollectionUtils.isEmpty(params)) {
725 MultiValueMap<String, String> paramsValue = new LinkedMultiValueMap<>(); 580 MultiValueMap<String, String> paramsValue = new LinkedMultiValueMap<>();
726 - for (Map.Entry<String, String> entry : params.entrySet()) {  
727 - paramsValue.add(entry.getKey(), entry.getValue());  
728 - }  
729 - 581 + for (Map.Entry<String, String> entry : params.entrySet()) paramsValue.add(entry.getKey(), entry.getValue());
730 uriBuilder = uriBuilder.queryParams(paramsValue); 582 uriBuilder = uriBuilder.queryParams(paramsValue);
731 } 583 }
732 -  
733 return uriBuilder.toUriString(); 584 return uriBuilder.toUriString();
734 } 585 }
735 586
@@ -745,9 +596,7 @@ public class DevicePullService { @@ -745,9 +596,7 @@ public class DevicePullService {
745 int len; 596 int len;
746 byte[] buf = new byte[128]; 597 byte[] buf = new byte[128];
747 ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); 598 ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
748 - while ((len = is.read(buf)) != -1) {  
749 - byteArrayOutputStream.write(buf, 0, len);  
750 - } 599 + while ((len = is.read(buf)) != -1) byteArrayOutputStream.write(buf, 0, len);
751 result = byteArrayOutputStream.toString(); 600 result = byteArrayOutputStream.toString();
752 } catch (IOException e) { 601 } catch (IOException e) {
753 e.printStackTrace(); 602 e.printStackTrace();
@@ -4,7 +4,6 @@ import com.alibaba.fastjson.JSON; @@ -4,7 +4,6 @@ import com.alibaba.fastjson.JSON;
4 import com.alibaba.fastjson.JSONArray; 4 import com.alibaba.fastjson.JSONArray;
5 import com.alibaba.fastjson.JSONObject; 5 import com.alibaba.fastjson.JSONObject;
6 import lombok.extern.slf4j.Slf4j; 6 import lombok.extern.slf4j.Slf4j;
7 -import org.springframework.beans.factory.annotation.Value;  
8 import org.springframework.jdbc.core.JdbcTemplate; 7 import org.springframework.jdbc.core.JdbcTemplate;
9 import org.springframework.stereotype.Service; 8 import org.springframework.stereotype.Service;
10 import org.springframework.util.StringUtils; 9 import org.springframework.util.StringUtils;
@@ -18,26 +17,22 @@ import java.util.*; @@ -18,26 +17,22 @@ import java.util.*;
18 @Service 17 @Service
19 public class DeviceSearchService { 18 public class DeviceSearchService {
20 19
21 - @Value("${device.db.corpCode}")  
22 - private String deviceCorpCode;  
23 - @Value("${device.db.tableName}")  
24 - private String deviceTableName;  
25 - @Value("${device.db.oeeTableName}")  
26 - private String oeeTableName;  
27 - @Value("${device.db.devUtilTableName}")  
28 - private String devUtilTableName;  
29 -  
30 @Resource 20 @Resource
31 private JdbcTemplate jdbcTemplate; 21 private JdbcTemplate jdbcTemplate;
32 @Resource 22 @Resource
33 private DevicePullService devicePullService; 23 private DevicePullService devicePullService;
  24 + @Resource
  25 + private CorpConfigService corpConfigService;
34 26
35 - public Map<String, Object> queryDeviceList(String deviceName, String lampState, Integer pageNo, Integer pageSize) {  
36 - StringBuilder countSql = new StringBuilder("SELECT COUNT(*) FROM " + deviceTableName + " WHERE corp_code = ?"); 27 + public Map<String, Object> queryDeviceList(String corpCode, String deviceName, String lampState, Integer pageNo, Integer pageSize) {
  28 + String tableName = corpConfigService.getDeviceTableName(corpCode);
  29 + JdbcTemplate jt = corpConfigService.getJdbcTemplate(corpCode);
  30 +
  31 + StringBuilder countSql = new StringBuilder("SELECT COUNT(*) FROM " + tableName + " WHERE corp_code = ?");
37 StringBuilder querySql = new StringBuilder("SELECT id, deviceName, projectType, projectState, dtuSn, dtuId, deviceId, " + 32 StringBuilder querySql = new StringBuilder("SELECT id, deviceName, projectType, projectState, dtuSn, dtuId, deviceId, " +
38 - "lampState, startTime, duration, utilizationRate FROM " + deviceTableName + " WHERE corp_code = ?"); 33 + "lampState, startTime, duration, utilizationRate FROM " + tableName + " WHERE corp_code = ?");
39 List<Object> params = new java.util.ArrayList<>(); 34 List<Object> params = new java.util.ArrayList<>();
40 - params.add(deviceCorpCode); 35 + params.add(corpCode);
41 36
42 if (StringUtils.hasText(deviceName)) { 37 if (StringUtils.hasText(deviceName)) {
43 countSql.append(" AND deviceName LIKE ?"); 38 countSql.append(" AND deviceName LIKE ?");
@@ -50,13 +45,13 @@ public class DeviceSearchService { @@ -50,13 +45,13 @@ public class DeviceSearchService {
50 params.add(lampState); 45 params.add(lampState);
51 } 46 }
52 47
53 - Long total = jdbcTemplate.queryForObject(countSql.toString(), Long.class, params.toArray()); 48 + Long total = jt.queryForObject(countSql.toString(), Long.class, params.toArray());
54 int offset = (pageNo - 1) * pageSize; 49 int offset = (pageNo - 1) * pageSize;
55 querySql.append(" ORDER BY created_at DESC LIMIT ?, ?"); 50 querySql.append(" ORDER BY created_at DESC LIMIT ?, ?");
56 params.add(offset); 51 params.add(offset);
57 params.add(pageSize); 52 params.add(pageSize);
58 53
59 - List<Map<String, Object>> list = jdbcTemplate.queryForList(querySql.toString(), params.toArray()); 54 + List<Map<String, Object>> list = jt.queryForList(querySql.toString(), params.toArray());
60 55
61 return Map.of( 56 return Map.of(
62 "total", total != null ? total : 0, 57 "total", total != null ? total : 0,
@@ -66,10 +61,13 @@ public class DeviceSearchService { @@ -66,10 +61,13 @@ public class DeviceSearchService {
66 ); 61 );
67 } 62 }
68 63
69 - public Map<String, Object> queryDeviceStats() {  
70 - String sql = "SELECT lampState, COUNT(*) as cnt FROM " + deviceTableName + 64 + public Map<String, Object> queryDeviceStats(String corpCode) {
  65 + String tableName = corpConfigService.getDeviceTableName(corpCode);
  66 + JdbcTemplate jt = corpConfigService.getJdbcTemplate(corpCode);
  67 +
  68 + String sql = "SELECT lampState, COUNT(*) as cnt FROM " + tableName +
71 " WHERE corp_code = ? GROUP BY lampState"; 69 " WHERE corp_code = ? GROUP BY lampState";
72 - List<Map<String, Object>> rows = jdbcTemplate.queryForList(sql, deviceCorpCode); 70 + List<Map<String, Object>> rows = jt.queryForList(sql, corpCode);
73 71
74 long all = 0; 72 long all = 0;
75 long red = 0, yellow = 0, green = 0, blue = 0, off = 0; 73 long red = 0, yellow = 0, green = 0, blue = 0, off = 0;
@@ -96,9 +94,10 @@ public class DeviceSearchService { @@ -96,9 +94,10 @@ public class DeviceSearchService {
96 ); 94 );
97 } 95 }
98 96
99 - public Map<String, Object> queryLampData(String dtuSn, String date) {  
100 - String result = devicePullService.getLampData(dtuSn, date);  
101 - Map<String, Object> res = com.alibaba.fastjson.JSON.parseObject(result, new com.alibaba.fastjson.TypeReference<>() {}); 97 + public Map<String, Object> queryLampData(String corpCode, String dtuSn, String date) {
  98 + String result = devicePullService.getLampData(corpCode, dtuSn, date);
  99 + Map<String, Object> res = com.alibaba.fastjson.JSON.parseObject(result, new com.alibaba.fastjson.TypeReference<>() {
  100 + });
102 Integer code = (Integer) res.get("code"); 101 Integer code = (Integer) res.get("code");
103 if (code == null || code != 200) { 102 if (code == null || code != 200) {
104 return Map.of("lampDurationStats", Map.of(), "list", List.of()); 103 return Map.of("lampDurationStats", Map.of(), "list", List.of());
@@ -159,28 +158,29 @@ public class DeviceSearchService { @@ -159,28 +158,29 @@ public class DeviceSearchService {
159 158
160 /** 159 /**
161 * 稼动率/OEE统计查询 160 * 稼动率/OEE统计查询
162 - * @param dtuSn 设备序列号(可选,为空查全部)  
163 - * @param type 查询类型:day-日(按日期段), week-周(今年第1周~本周), month-月(今年1月~本月) 161 + *
  162 + * @param corpCode 公司编码
  163 + * @param dtuSn 设备序列号(可选,为空查全部)
  164 + * @param type 查询类型:day-日(按日期段), week-周(今年第1周~本周), month-月(今年1月~本月)
164 * @param startDate 日模式下的开始日期(yyyy-MM-dd) 165 * @param startDate 日模式下的开始日期(yyyy-MM-dd)
165 * @param endDate 日模式下的结束日期(yyyy-MM-dd) 166 * @param endDate 日模式下的结束日期(yyyy-MM-dd)
166 */ 167 */
167 - public Map<String, Object> queryOeeStats(String dtuSn, String type, String startDate, String endDate) { 168 + public Map<String, Object> queryOeeStats(String corpCode, String dtuSn, String type, String startDate, String endDate) {
168 // 1. 根据类型确定日期范围 169 // 1. 根据类型确定日期范围
169 List<String> dates = buildDateRange(type, startDate, endDate); 170 List<String> dates = buildDateRange(type, startDate, endDate);
170 - log.info("OEE查询 - type:{}, dtuSn:{}, 日期范围:{}天, 起始:{}, 结束:{}", type, dtuSn, dates.size(), dates.get(0), dates.get(dates.size() - 1)); 171 + log.info("OEE查询 - corpCode:{}, type:{}, dtuSn:{}, 日期范围:{}天, 起始:{}, 结束:{}", corpCode, type, dtuSn, dates.size(), dates.get(0), dates.get(dates.size() - 1));
171 172
172 // 判断是否包含今天 173 // 判断是否包含今天
173 String todayStr = new SimpleDateFormat("yyyy-MM-dd").format(new Date()); 174 String todayStr = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
174 boolean includeToday = dates.contains(todayStr); 175 boolean includeToday = dates.contains(todayStr);
175 176
176 // 2. 从数据库查询 oee 表数据 177 // 2. 从数据库查询 oee 表数据
177 - List<Map<String, Object>> dbRecords = queryOeeFromDb(dtuSn, dates, includeToday ? todayStr : null); 178 + List<Map<String, Object>> dbRecords = queryOeeFromDb(corpCode, dtuSn, dates, includeToday ? todayStr : null);
178 log.info("OEE查询 - DB返回记录数:{}, 排除today:{}", dbRecords.size(), includeToday ? todayStr : "无"); 179 log.info("OEE查询 - DB返回记录数:{}, 排除today:{}", dbRecords.size(), includeToday ? todayStr : "无");
179 - 180 +
180 Map<String, JSONObject> dbDataMap = new LinkedHashMap<>(); 181 Map<String, JSONObject> dbDataMap = new LinkedHashMap<>();
181 for (Map<String, Object> record : dbRecords) { 182 for (Map<String, Object> record : dbRecords) {
182 String oeeDate = String.valueOf(record.get("oee_date")); 183 String oeeDate = String.valueOf(record.get("oee_date"));
183 - // 截断时间部分,只保留日期 yyyy-MM-dd  
184 if (oeeDate.length() > 10) { 184 if (oeeDate.length() > 10) {
185 oeeDate = oeeDate.substring(0, 10); 185 oeeDate = oeeDate.substring(0, 10);
186 } 186 }
@@ -200,10 +200,11 @@ public class DeviceSearchService { @@ -200,10 +200,11 @@ public class DeviceSearchService {
200 // 3. 如果包含今天且数据库没有今天的实时数据,则调用接口获取 200 // 3. 如果包含今天且数据库没有今天的实时数据,则调用接口获取
201 if (includeToday && !dbDataMap.containsKey(todayStr)) { 201 if (includeToday && !dbDataMap.containsKey(todayStr)) {
202 if (StringUtils.hasText(dtuSn)) { 202 if (StringUtils.hasText(dtuSn)) {
203 - String apiResult = devicePullService.getLampData(dtuSn, todayStr); 203 + String apiResult = devicePullService.getLampData(corpCode, dtuSn, todayStr);
204 if (StringUtils.hasText(apiResult)) { 204 if (StringUtils.hasText(apiResult)) {
205 Map<String, Object> res = com.alibaba.fastjson.JSON.parseObject(apiResult, 205 Map<String, Object> res = com.alibaba.fastjson.JSON.parseObject(apiResult,
206 - new com.alibaba.fastjson.TypeReference<>() {}); 206 + new com.alibaba.fastjson.TypeReference<>() {
  207 + });
207 Integer code = (Integer) res.get("code"); 208 Integer code = (Integer) res.get("code");
208 if (code != null && code == 200) { 209 if (code != null && code == 200) {
209 JSONArray dataList = (JSONArray) res.get("data"); 210 JSONArray dataList = (JSONArray) res.get("data");
@@ -241,9 +242,6 @@ public class DeviceSearchService { @@ -241,9 +242,6 @@ public class DeviceSearchService {
241 ); 242 );
242 } 243 }
243 244
244 - /**  
245 - * 按天统计  
246 - */  
247 private Map<String, Object> aggregateByDay(List<String> dates, Map<String, JSONObject> dbDataMap) { 245 private Map<String, Object> aggregateByDay(List<String> dates, Map<String, JSONObject> dbDataMap) {
248 List<Map<String, Object>> dailyStats = new ArrayList<>(); 246 List<Map<String, Object>> dailyStats = new ArrayList<>();
249 long totalOffDur = 0, totalRedDur = 0, totalYellowDur = 0, totalGreenDur = 0, totalBlueDur = 0; 247 long totalOffDur = 0, totalRedDur = 0, totalYellowDur = 0, totalGreenDur = 0, totalBlueDur = 0;
@@ -252,19 +250,25 @@ public class DeviceSearchService { @@ -252,19 +250,25 @@ public class DeviceSearchService {
252 for (String d : dates) { 250 for (String d : dates) {
253 long[] counts = countLampData(dbDataMap.get(d)); 251 long[] counts = countLampData(dbDataMap.get(d));
254 252
255 - totalOffDur += counts[0]; totalRedDur += counts[2]; totalYellowDur += counts[4];  
256 - totalGreenDur += counts[6]; totalBlueDur += counts[8];  
257 - totalOffCnt += (int)counts[1]; totalRedCnt += (int)counts[3]; totalYellowCnt += (int)counts[5];  
258 - totalGreenCnt += (int)counts[7]; totalBlueCnt += (int)counts[9]; 253 + totalOffDur += counts[0];
  254 + totalRedDur += counts[2];
  255 + totalYellowDur += counts[4];
  256 + totalGreenDur += counts[6];
  257 + totalBlueDur += counts[8];
  258 + totalOffCnt += (int) counts[1];
  259 + totalRedCnt += (int) counts[3];
  260 + totalYellowCnt += (int) counts[5];
  261 + totalGreenCnt += (int) counts[7];
  262 + totalBlueCnt += (int) counts[9];
259 263
260 Map<String, Object> dayStat = new LinkedHashMap<>(); 264 Map<String, Object> dayStat = new LinkedHashMap<>();
261 dayStat.put("label", d); 265 dayStat.put("label", d);
262 dayStat.put("date", d); 266 dayStat.put("date", d);
263 - dayStat.put("off", Map.of("duration", formatDuration(counts[0]), "seconds", counts[0], "count", (int)counts[1]));  
264 - dayStat.put("red", Map.of("duration", formatDuration(counts[2]), "seconds", counts[2], "count", (int)counts[3]));  
265 - dayStat.put("yellow", Map.of("duration", formatDuration(counts[4]), "seconds", counts[4], "count", (int)counts[5]));  
266 - dayStat.put("green", Map.of("duration", formatDuration(counts[6]), "seconds", counts[6], "count", (int)counts[7]));  
267 - dayStat.put("blue", Map.of("duration", formatDuration(counts[8]), "seconds", counts[8], "count", (int)counts[9])); 267 + dayStat.put("off", Map.of("duration", formatDuration(counts[0]), "seconds", counts[0], "count", (int) counts[1]));
  268 + dayStat.put("red", Map.of("duration", formatDuration(counts[2]), "seconds", counts[2], "count", (int) counts[3]));
  269 + dayStat.put("yellow", Map.of("duration", formatDuration(counts[4]), "seconds", counts[4], "count", (int) counts[5]));
  270 + dayStat.put("green", Map.of("duration", formatDuration(counts[6]), "seconds", counts[6], "count", (int) counts[7]));
  271 + dayStat.put("blue", Map.of("duration", formatDuration(counts[8]), "seconds", counts[8], "count", (int) counts[9]));
268 dailyStats.add(dayStat); 272 dailyStats.add(dayStat);
269 } 273 }
270 274
@@ -274,22 +278,16 @@ public class DeviceSearchService { @@ -274,22 +278,16 @@ public class DeviceSearchService {
274 return Map.of("list", dailyStats, "summary", summary); 278 return Map.of("list", dailyStats, "summary", summary);
275 } 279 }
276 280
277 - /**  
278 - * 按周统计  
279 - */  
280 private Map<String, Object> aggregateByWeek(List<String> dates, Map<String, JSONObject> dbDataMap) { 281 private Map<String, Object> aggregateByWeek(List<String> dates, Map<String, JSONObject> dbDataMap) {
281 - // 按自然周(周一~周日)分组,第一周从1月1日开始(可能不足7天)  
282 List<List<String>> weekBuckets = new ArrayList<>(); 282 List<List<String>> weekBuckets = new ArrayList<>();
283 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); 283 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
284 284
285 - // 确定年份和该年第一个周一的日期  
286 String yearStr = dates.get(0).substring(0, 4); 285 String yearStr = dates.get(0).substring(0, 4);
287 int year = Integer.parseInt(yearStr); 286 int year = Integer.parseInt(yearStr);
288 Calendar jan1 = Calendar.getInstance(); 287 Calendar jan1 = Calendar.getInstance();
289 jan1.set(year, Calendar.JANUARY, 1); 288 jan1.set(year, Calendar.JANUARY, 1);
290 int jan1Dow = jan1.get(Calendar.DAY_OF_WEEK); 289 int jan1Dow = jan1.get(Calendar.DAY_OF_WEEK);
291 290
292 - // 找到第一个周一:如果1月1日就是周一,则firstMonday=1月1日;否则往后推到周一  
293 Calendar firstMonday = Calendar.getInstance(); 291 Calendar firstMonday = Calendar.getInstance();
294 firstMonday.setTime(jan1.getTime()); 292 firstMonday.setTime(jan1.getTime());
295 int daysToAdd = jan1Dow == Calendar.MONDAY ? 0 : (Calendar.MONDAY - jan1Dow + 7) % 7; 293 int daysToAdd = jan1Dow == Calendar.MONDAY ? 0 : (Calendar.MONDAY - jan1Dow + 7) % 7;
@@ -307,13 +305,11 @@ public class DeviceSearchService { @@ -307,13 +305,11 @@ public class DeviceSearchService {
307 305
308 int bucketIndex; 306 int bucketIndex;
309 if (!cal.after(firstMonday)) { 307 if (!cal.after(firstMonday)) {
310 - // 在第一个周一之前(含当天),属于第1周(从1月1日开始)  
311 bucketIndex = 0; 308 bucketIndex = 0;
312 } else { 309 } else {
313 - // 第一个周一之后,按完整自然周计算  
314 long diffMs = cal.getTimeInMillis() - firstMonday.getTimeInMillis(); 310 long diffMs = cal.getTimeInMillis() - firstMonday.getTimeInMillis();
315 long diffDays = diffMs / (1000 * 60 * 60 * 24); 311 long diffDays = diffMs / (1000 * 60 * 60 * 24);
316 - bucketIndex = 1 + (int)(diffDays / 7); // 第2周、第3周... 312 + bucketIndex = 1 + (int) (diffDays / 7);
317 } 313 }
318 314
319 while (weekBuckets.size() <= bucketIndex) { 315 while (weekBuckets.size() <= bucketIndex) {
@@ -326,23 +322,39 @@ public class DeviceSearchService { @@ -326,23 +322,39 @@ public class DeviceSearchService {
326 } 322 }
327 323
328 List<Map<String, Object>> weeklyStats = new ArrayList<>(); 324 List<Map<String, Object>> weeklyStats = new ArrayList<>();
329 - long tOffD=0, tRedD=0, tYelD=0, tGrnD=0, tBluD=0;  
330 - int tOffC=0, tRedC=0, tYelC=0, tGrnC=0, tBluC=0; 325 + long tOffD = 0, tRedD = 0, tYelD = 0, tGrnD = 0, tBluD = 0;
  326 + int tOffC = 0, tRedC = 0, tYelC = 0, tGrnC = 0, tBluC = 0;
331 327
332 for (int i = 0; i < weekBuckets.size(); i++) { 328 for (int i = 0; i < weekBuckets.size(); i++) {
333 List<String> daysInWeek = weekBuckets.get(i); 329 List<String> daysInWeek = weekBuckets.get(i);
334 if (daysInWeek.isEmpty()) continue; 330 if (daysInWeek.isEmpty()) continue;
335 - long wOffD=0, wRedD=0, wYelD=0, wGrnD=0, wBluD=0;  
336 - int wOffC=0, wRedC=0, wYelC=0, wGrnC=0, wBluC=0; 331 + long wOffD = 0, wRedD = 0, wYelD = 0, wGrnD = 0, wBluD = 0;
  332 + int wOffC = 0, wRedC = 0, wYelC = 0, wGrnC = 0, wBluC = 0;
337 333
338 for (String d : daysInWeek) { 334 for (String d : daysInWeek) {
339 long[] cnt = countLampData(dbDataMap.get(d)); 335 long[] cnt = countLampData(dbDataMap.get(d));
340 - wOffD += cnt[0]; wRedD += cnt[2]; wYelD += cnt[4]; wGrnD += cnt[6]; wBluD += cnt[8];  
341 - wOffC += (int)cnt[1]; wRedC += (int)cnt[3]; wYelC += (int)cnt[5]; wGrnC += (int)cnt[7]; wBluC += (int)cnt[9]; 336 + wOffD += cnt[0];
  337 + wRedD += cnt[2];
  338 + wYelD += cnt[4];
  339 + wGrnD += cnt[6];
  340 + wBluD += cnt[8];
  341 + wOffC += (int) cnt[1];
  342 + wRedC += (int) cnt[3];
  343 + wYelC += (int) cnt[5];
  344 + wGrnC += (int) cnt[7];
  345 + wBluC += (int) cnt[9];
342 } 346 }
343 347
344 - tOffD+=wOffD; tRedD+=wRedD; tYelD+=wYelD; tGrnD+=wGrnD; tBluD+=wBluD;  
345 - tOffC+=wOffC; tRedC+=wRedC; tYelC+=wYelC; tGrnC+=wGrnC; tBluC+=wBluC; 348 + tOffD += wOffD;
  349 + tRedD += wRedD;
  350 + tYelD += wYelD;
  351 + tGrnD += wGrnD;
  352 + tBluD += wBluD;
  353 + tOffC += wOffC;
  354 + tRedC += wRedC;
  355 + tYelC += wYelC;
  356 + tGrnC += wGrnC;
  357 + tBluC += wBluC;
346 358
347 Collections.sort(daysInWeek); 359 Collections.sort(daysInWeek);
348 Map<String, Object> ws = new LinkedHashMap<>(); 360 Map<String, Object> ws = new LinkedHashMap<>();
@@ -363,39 +375,51 @@ public class DeviceSearchService { @@ -363,39 +375,51 @@ public class DeviceSearchService {
363 return Map.of("list", weeklyStats, "summary", summary); 375 return Map.of("list", weeklyStats, "summary", summary);
364 } 376 }
365 377
366 - /**  
367 - * 按月统计  
368 - */  
369 private Map<String, Object> aggregateByMonth(List<String> dates, Map<String, JSONObject> dbDataMap) { 378 private Map<String, Object> aggregateByMonth(List<String> dates, Map<String, JSONObject> dbDataMap) {
370 - // 按 年-月 分组  
371 Map<String, List<String>> monthGroups = new LinkedHashMap<>(); 379 Map<String, List<String>> monthGroups = new LinkedHashMap<>();
372 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); 380 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
373 381
374 for (String d : dates) { 382 for (String d : dates) {
375 - String monthKey = d.substring(0, 7); // yyyy-MM 383 + String monthKey = d.substring(0, 7);
376 monthGroups.computeIfAbsent(monthKey, k -> new ArrayList<>()).add(d); 384 monthGroups.computeIfAbsent(monthKey, k -> new ArrayList<>()).add(d);
377 } 385 }
378 386
379 List<Map<String, Object>> monthlyStats = new ArrayList<>(); 387 List<Map<String, Object>> monthlyStats = new ArrayList<>();
380 - long tOffD=0, tRedD=0, tYelD=0, tGrnD=0, tBluD=0;  
381 - int tOffC=0, tRedC=0, tYelC=0, tGrnC=0, tBluC=0; 388 + long tOffD = 0, tRedD = 0, tYelD = 0, tGrnD = 0, tBluD = 0;
  389 + int tOffC = 0, tRedC = 0, tYelC = 0, tGrnC = 0, tBluC = 0;
382 390
383 for (Map.Entry<String, List<String>> entry : monthGroups.entrySet()) { 391 for (Map.Entry<String, List<String>> entry : monthGroups.entrySet()) {
384 String monthKey = entry.getKey(); 392 String monthKey = entry.getKey();
385 List<String> daysInMonth = entry.getValue(); 393 List<String> daysInMonth = entry.getValue();
386 - long mOffD=0, mRedD=0, mYelD=0, mGrnD=0, mBluD=0;  
387 - int mOffC=0, mRedC=0, mYelC=0, mGrnC=0, mBluC=0; 394 + long mOffD = 0, mRedD = 0, mYelD = 0, mGrnD = 0, mBluD = 0;
  395 + int mOffC = 0, mRedC = 0, mYelC = 0, mGrnC = 0, mBluC = 0;
388 396
389 for (String d : daysInMonth) { 397 for (String d : daysInMonth) {
390 long[] cnt = countLampData(dbDataMap.get(d)); 398 long[] cnt = countLampData(dbDataMap.get(d));
391 - mOffD += cnt[0]; mRedD += cnt[2]; mYelD += cnt[4]; mGrnD += cnt[6]; mBluD += cnt[8];  
392 - mOffC += (int)cnt[1]; mRedC += (int)cnt[3]; mYelC += (int)cnt[5]; mGrnC += (int)cnt[7]; mBluC += (int)cnt[9]; 399 + mOffD += cnt[0];
  400 + mRedD += cnt[2];
  401 + mYelD += cnt[4];
  402 + mGrnD += cnt[6];
  403 + mBluD += cnt[8];
  404 + mOffC += (int) cnt[1];
  405 + mRedC += (int) cnt[3];
  406 + mYelC += (int) cnt[5];
  407 + mGrnC += (int) cnt[7];
  408 + mBluC += (int) cnt[9];
393 } 409 }
394 410
395 - tOffD+=mOffD; tRedD+=mRedD; tYelD+=mYelD; tGrnD+=mGrnD; tBluD+=mBluD;  
396 - tOffC+=mOffC; tRedC+=mRedC; tYelC+=mYelC; tGrnC+=mGrnC; tBluC+=mBluC;  
397 -  
398 - String monthNum = monthKey.substring(5); // "01", "02" ... 411 + tOffD += mOffD;
  412 + tRedD += mRedD;
  413 + tYelD += mYelD;
  414 + tGrnD += mGrnD;
  415 + tBluD += mBluD;
  416 + tOffC += mOffC;
  417 + tRedC += mRedC;
  418 + tYelC += mYelC;
  419 + tGrnC += mGrnC;
  420 + tBluC += mBluC;
  421 +
  422 + String monthNum = monthKey.substring(5);
399 Map<String, Object> ms = new LinkedHashMap<>(); 423 Map<String, Object> ms = new LinkedHashMap<>();
400 ms.put("label", Integer.parseInt(monthNum) + "月"); 424 ms.put("label", Integer.parseInt(monthNum) + "月");
401 ms.put("month", monthKey); 425 ms.put("month", monthKey);
@@ -412,10 +436,6 @@ public class DeviceSearchService { @@ -412,10 +436,6 @@ public class DeviceSearchService {
412 return Map.of("list", monthlyStats, "summary", summary); 436 return Map.of("list", monthlyStats, "summary", summary);
413 } 437 }
414 438
415 - /**  
416 - * 统计单日 lampData 各状态时长和次数  
417 - * 返回 [offDur, offCnt, redDur, redCnt, yelDur, yelCnt, grnDur, grnCnt, bluDur, bluCnt]  
418 - */  
419 private long[] countLampData(JSONObject dayData) { 439 private long[] countLampData(JSONObject dayData) {
420 long[] result = new long[10]; 440 long[] result = new long[10];
421 if (dayData != null) { 441 if (dayData != null) {
@@ -423,14 +443,30 @@ public class DeviceSearchService { @@ -423,14 +443,30 @@ public class DeviceSearchService {
423 if (lampArr != null) { 443 if (lampArr != null) {
424 for (int i = 0; i < lampArr.size(); i++) { 444 for (int i = 0; i < lampArr.size(); i++) {
425 JSONObject item = lampArr.getJSONObject(i); 445 JSONObject item = lampArr.getJSONObject(i);
  446 + if (item == null) continue;
426 int state = item.getIntValue("lampState"); 447 int state = item.getIntValue("lampState");
427 long dur = item.getLongValue("duration"); 448 long dur = item.getLongValue("duration");
428 switch (state) { 449 switch (state) {
429 - case 0 -> { result[0] += dur; result[1]++; }  
430 - case 1 -> { result[2] += dur; result[3]++; }  
431 - case 2 -> { result[4] += dur; result[5]++; }  
432 - case 3 -> { result[6] += dur; result[7]++; }  
433 - case 4 -> { result[8] += dur; result[9]++; } 450 + case 0 -> {
  451 + result[0] += dur;
  452 + result[1]++;
  453 + }
  454 + case 1 -> {
  455 + result[2] += dur;
  456 + result[3]++;
  457 + }
  458 + case 2 -> {
  459 + result[4] += dur;
  460 + result[5]++;
  461 + }
  462 + case 3 -> {
  463 + result[6] += dur;
  464 + result[7]++;
  465 + }
  466 + case 4 -> {
  467 + result[8] += dur;
  468 + result[9]++;
  469 + }
434 } 470 }
435 } 471 }
436 } 472 }
@@ -438,11 +474,8 @@ public class DeviceSearchService { @@ -438,11 +474,8 @@ public class DeviceSearchService {
438 return result; 474 return result;
439 } 475 }
440 476
441 - /**  
442 - * 构建 summary 汇总对象  
443 - */  
444 private Map<String, Object> buildSummary(long offD, long redD, long yelD, long grnD, long bluD, 477 private Map<String, Object> buildSummary(long offD, long redD, long yelD, long grnD, long bluD,
445 - int offC, int redC, int yelC, int grnC, int bluC) { 478 + int offC, int redC, int yelC, int grnC, int bluC) {
446 Map<String, Object> summary = new LinkedHashMap<>(); 479 Map<String, Object> summary = new LinkedHashMap<>();
447 summary.put("off", Map.of("duration", formatDuration(offD), "seconds", offD, "count", offC)); 480 summary.put("off", Map.of("duration", formatDuration(offD), "seconds", offD, "count", offC));
448 summary.put("red", Map.of("duration", formatDuration(redD), "seconds", redD, "count", redC)); 481 summary.put("red", Map.of("duration", formatDuration(redD), "seconds", redD, "count", redC));
@@ -452,16 +485,12 @@ public class DeviceSearchService { @@ -452,16 +485,12 @@ public class DeviceSearchService {
452 return summary; 485 return summary;
453 } 486 }
454 487
455 - /**  
456 - * 根据查询类型构建日期列表  
457 - */  
458 private List<String> buildDateRange(String type, String startDate, String endDate) { 488 private List<String> buildDateRange(String type, String startDate, String endDate) {
459 List<String> result = new ArrayList<>(); 489 List<String> result = new ArrayList<>();
460 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); 490 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
461 491
462 switch (type) { 492 switch (type) {
463 case "day": { 493 case "day": {
464 - // 指定日期范围  
465 if (StringUtils.hasText(startDate) && StringUtils.hasText(endDate)) { 494 if (StringUtils.hasText(startDate) && StringUtils.hasText(endDate)) {
466 try { 495 try {
467 Date start = sdf.parse(startDate); 496 Date start = sdf.parse(startDate);
@@ -479,19 +508,14 @@ public class DeviceSearchService { @@ -479,19 +508,14 @@ public class DeviceSearchService {
479 break; 508 break;
480 } 509 }
481 case "week": { 510 case "week": {
482 - // 今年1月1日 ~ 今天所在周的周日(自然周,不跨年)  
483 Calendar now = Calendar.getInstance(); 511 Calendar now = Calendar.getInstance();
484 int currentYear = now.get(Calendar.YEAR); 512 int currentYear = now.get(Calendar.YEAR);
485 -  
486 Calendar startCal = Calendar.getInstance(); 513 Calendar startCal = Calendar.getInstance();
487 startCal.set(currentYear, Calendar.JANUARY, 1); 514 startCal.set(currentYear, Calendar.JANUARY, 1);
488 -  
489 - // 本周结束(周日)  
490 Calendar endCal = (Calendar) now.clone(); 515 Calendar endCal = (Calendar) now.clone();
491 int todayDow = endCal.get(Calendar.DAY_OF_WEEK); 516 int todayDow = endCal.get(Calendar.DAY_OF_WEEK);
492 int toSunday = todayDow == Calendar.SUNDAY ? 0 : (7 - todayDow); 517 int toSunday = todayDow == Calendar.SUNDAY ? 0 : (7 - todayDow);
493 endCal.add(Calendar.DATE, toSunday); 518 endCal.add(Calendar.DATE, toSunday);
494 -  
495 Calendar cur = Calendar.getInstance(); 519 Calendar cur = Calendar.getInstance();
496 cur.setTime(startCal.getTime()); 520 cur.setTime(startCal.getTime());
497 while (!cur.after(endCal)) { 521 while (!cur.after(endCal)) {
@@ -501,11 +525,9 @@ public class DeviceSearchService { @@ -501,11 +525,9 @@ public class DeviceSearchService {
501 break; 525 break;
502 } 526 }
503 case "month": { 527 case "month": {
504 - // 今年1月 ~ 本月最后一天  
505 Calendar now = Calendar.getInstance(); 528 Calendar now = Calendar.getInstance();
506 int year = now.get(Calendar.YEAR); 529 int year = now.get(Calendar.YEAR);
507 - int thisMonth = now.get(Calendar.MONTH); // 0-indexed  
508 - 530 + int thisMonth = now.get(Calendar.MONTH);
509 for (int m = 0; m <= thisMonth; m++) { 531 for (int m = 0; m <= thisMonth; m++) {
510 Calendar cal = Calendar.getInstance(); 532 Calendar cal = Calendar.getInstance();
511 cal.set(year, m, 1); 533 cal.set(year, m, 1);
@@ -521,16 +543,16 @@ public class DeviceSearchService { @@ -521,16 +543,16 @@ public class DeviceSearchService {
521 return result; 543 return result;
522 } 544 }
523 545
524 - /**  
525 - * 从 oee 表查询指定日期范围的数据  
526 - */  
527 - private List<Map<String, Object>> queryOeeFromDb(String dtuSn, List<String> dates, String excludeToday) { 546 + private List<Map<String, Object>> queryOeeFromDb(String corpCode, String dtuSn, List<String> dates, String excludeToday) {
528 if (dates.isEmpty()) return Collections.emptyList(); 547 if (dates.isEmpty()) return Collections.emptyList();
529 548
  549 + String oeeTableName = corpConfigService.getOeeTableName(corpCode);
  550 + JdbcTemplate jt = corpConfigService.getJdbcTemplate(corpCode);
  551 +
530 StringBuilder sql = new StringBuilder( 552 StringBuilder sql = new StringBuilder(
531 "SELECT oee_date, triColorLamp1, triColorLamp2 FROM " + oeeTableName + " WHERE corp_code = ?"); 553 "SELECT oee_date, triColorLamp1, triColorLamp2 FROM " + oeeTableName + " WHERE corp_code = ?");
532 List<Object> params = new ArrayList<>(); 554 List<Object> params = new ArrayList<>();
533 - params.add(deviceCorpCode); 555 + params.add(corpCode);
534 556
535 if (StringUtils.hasText(dtuSn)) { 557 if (StringUtils.hasText(dtuSn)) {
536 sql.append(" AND dtuSn = ?"); 558 sql.append(" AND dtuSn = ?");
@@ -540,35 +562,24 @@ public class DeviceSearchService { @@ -540,35 +562,24 @@ public class DeviceSearchService {
540 sql.append(" AND oee_date IN ("); 562 sql.append(" AND oee_date IN (");
541 List<Object> dateParams = new ArrayList<>(); 563 List<Object> dateParams = new ArrayList<>();
542 for (String d : dates) { 564 for (String d : dates) {
543 - if (d.equals(excludeToday)) continue; // 排除今天,今天走接口 565 + if (d.equals(excludeToday)) continue;
544 sql.append("?,"); 566 sql.append("?,");
545 dateParams.add(d); 567 dateParams.add(d);
546 } 568 }
547 - if (dateParams.isEmpty()) {  
548 - return Collections.emptyList(); // 所有日期都是今天  
549 - } 569 + if (dateParams.isEmpty()) return Collections.emptyList();
550 sql.deleteCharAt(sql.length() - 1).append(")"); 570 sql.deleteCharAt(sql.length() - 1).append(")");
551 params.addAll(dateParams); 571 params.addAll(dateParams);
552 sql.append(" ORDER BY oee_date ASC"); 572 sql.append(" ORDER BY oee_date ASC");
553 573
554 - return jdbcTemplate.queryForList(sql.toString(), params.toArray()); 574 + return jt.queryForList(sql.toString(), params.toArray());
555 } 575 }
556 576
557 // ==================== OEE 时序图分页查询(含稼动率计算) ==================== 577 // ==================== OEE 时序图分页查询(含稼动率计算) ====================
558 578
559 - /**  
560 - * 按设备分页查询所有设备的OEE时序数据,并计算稼动率  
561 - *  
562 - * @param startDate 开始日期 yyyy-MM-dd  
563 - * @param endDate 结束日期 yyyy-MM-dd  
564 - * @param pageNo 页码,从1开始  
565 - * @param pageSize 每页设备数,最大20  
566 - */  
567 - public Map<String, Object> queryOeeTimeline(String startDate, String endDate, Integer pageNo, Integer pageSize) {  
568 - log.info("========== [OEE时序图查询-按设备分页] startDate={}, endDate={}, pageNo={}, pageSize={} ==========",  
569 - startDate, endDate, pageNo, pageSize); 579 + public Map<String, Object> queryOeeTimeline(String corpCode, String startDate, String endDate, Integer pageNo, Integer pageSize) {
  580 + log.info("========== [OEE时序图查询-按设备分页] corpCode={}, startDate={}, endDate={}, pageNo={}, pageSize={} ==========",
  581 + corpCode, startDate, endDate, pageNo, pageSize);
570 582
571 - // 参数校验与默认值  
572 if (!StringUtils.hasText(startDate) || !StringUtils.hasText(endDate)) { 583 if (!StringUtils.hasText(startDate) || !StringUtils.hasText(endDate)) {
573 return Map.of("total", 0, "pageNo", pageNo, "pageSize", pageSize, "list", List.of()); 584 return Map.of("total", 0, "pageNo", pageNo, "pageSize", pageSize, "list", List.of());
574 } 585 }
@@ -581,7 +592,7 @@ public class DeviceSearchService { @@ -581,7 +592,7 @@ public class DeviceSearchService {
581 log.info("包含今日({}): {}", todayStr, includeToday); 592 log.info("包含今日({}): {}", todayStr, includeToday);
582 593
583 // 1. 从设备表查询所有 dtuSn 及设备名称 594 // 1. 从设备表查询所有 dtuSn 及设备名称
584 - Map<String, String> deviceNameMap = queryAllDtuSnWithName(); 595 + Map<String, String> deviceNameMap = queryAllDtuSnWithName(corpCode);
585 List<String> allDtuSns = new ArrayList<>(deviceNameMap.keySet()); 596 List<String> allDtuSns = new ArrayList<>(deviceNameMap.keySet());
586 int deviceTotal = allDtuSns.size(); 597 int deviceTotal = allDtuSns.size();
587 log.info("设备总数: {}", deviceTotal); 598 log.info("设备总数: {}", deviceTotal);
@@ -590,31 +601,25 @@ public class DeviceSearchService { @@ -590,31 +601,25 @@ public class DeviceSearchService {
590 return buildPageResult(0, pn, ps, List.of()); 601 return buildPageResult(0, pn, ps, List.of());
591 } 602 }
592 603
593 - // 2. 构建日期范围列表  
594 List<String> dateList = buildDayList(startDate, endDate); 604 List<String> dateList = buildDayList(startDate, endDate);
595 log.info("日期范围共 {} 天: {} ~ {}", dateList.size(), dateList.get(0), dateList.get(dateList.size() - 1)); 605 log.info("日期范围共 {} 天: {} ~ {}", dateList.size(), dateList.get(0), dateList.get(dateList.size() - 1));
596 606
597 - // 3. 批量从数据库查询全部设备的 OEE 数据  
598 - List<OeeRecord> allRecords = queryOeeBatch(allDtuSns, dateList, includeToday ? todayStr : null); 607 + List<OeeRecord> allRecords = queryOeeBatch(corpCode, allDtuSns, dateList, includeToday ? todayStr : null);
599 608
600 - // 4. 如果包含今天,补充调用接口获取今天的实时数据  
601 if (includeToday) { 609 if (includeToday) {
602 - supplementTodayData(allDtuSns, todayStr, allRecords); 610 + supplementTodayData(corpCode, allDtuSns, todayStr, allRecords);
603 } 611 }
604 612
605 - // 5. 按 dtuSn 分组,每个设备包含该日期范围内所有天的数据  
606 Map<String, List<OeeRecord>> deviceMap = new LinkedHashMap<>(); 613 Map<String, List<OeeRecord>> deviceMap = new LinkedHashMap<>();
607 for (OeeRecord r : allRecords) { 614 for (OeeRecord r : allRecords) {
608 deviceMap.computeIfAbsent(r.dtuSn, k -> new ArrayList<>()).add(r); 615 deviceMap.computeIfAbsent(r.dtuSn, k -> new ArrayList<>()).add(r);
609 } 616 }
610 - // 确保没有数据的设备也有空列表(保持顺序一致)  
611 for (String sn : allDtuSns) { 617 for (String sn : allDtuSns) {
612 if (!deviceMap.containsKey(sn)) { 618 if (!deviceMap.containsKey(sn)) {
613 deviceMap.put(sn, new ArrayList<>()); 619 deviceMap.put(sn, new ArrayList<>());
614 } 620 }
615 } 621 }
616 622
617 - // 6. 设备维度分页  
618 List<Map<String, Object>> pageList; 623 List<Map<String, Object>> pageList;
619 int offset = (pn - 1) * ps; 624 int offset = (pn - 1) * ps;
620 List<String> pagedDevices = new ArrayList<>(deviceMap.keySet()).subList( 625 List<String> pagedDevices = new ArrayList<>(deviceMap.keySet()).subList(
@@ -624,10 +629,11 @@ public class DeviceSearchService { @@ -624,10 +629,11 @@ public class DeviceSearchService {
624 return buildPageResult(deviceTotal, pn, ps, pageList); 629 return buildPageResult(deviceTotal, pn, ps, pageList);
625 } 630 }
626 631
627 - /** 查询设备表所有dtuSn及对应设备名称 */  
628 - private Map<String, String> queryAllDtuSnWithName() {  
629 - String sql = "SELECT dtuSn, deviceName FROM " + deviceTableName + " WHERE corp_code = ? ORDER BY dtuSn";  
630 - List<Map<String, Object>> rows = jdbcTemplate.queryForList(sql, deviceCorpCode); 632 + private Map<String, String> queryAllDtuSnWithName(String corpCode) {
  633 + String tableName = corpConfigService.getDeviceTableName(corpCode);
  634 + JdbcTemplate jt = corpConfigService.getJdbcTemplate(corpCode);
  635 + String sql = "SELECT dtuSn, deviceName FROM " + tableName + " WHERE corp_code = ? ORDER BY dtuSn";
  636 + List<Map<String, Object>> rows = jt.queryForList(sql, corpCode);
631 Map<String, String> result = new LinkedHashMap<>(rows.size()); 637 Map<String, String> result = new LinkedHashMap<>(rows.size());
632 for (Map<String, Object> row : rows) { 638 for (Map<String, Object> row : rows) {
633 result.put((String) row.get("dtuSn"), (String) row.get("deviceName")); 639 result.put((String) row.get("dtuSn"), (String) row.get("deviceName"));
@@ -635,7 +641,6 @@ public class DeviceSearchService { @@ -635,7 +641,6 @@ public class DeviceSearchService {
635 return result; 641 return result;
636 } 642 }
637 643
638 - /** 判断某日期是否在范围内 */  
639 private boolean isDateInRange(String dateStr, String start, String end) { 644 private boolean isDateInRange(String dateStr, String start, String end) {
640 try { 645 try {
641 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); 646 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
@@ -648,7 +653,6 @@ public class DeviceSearchService { @@ -648,7 +653,6 @@ public class DeviceSearchService {
648 } 653 }
649 } 654 }
650 655
651 - /** 构建连续日期列表 */  
652 private List<String> buildDayList(String startDate, String endDate) { 656 private List<String> buildDayList(String startDate, String endDate) {
653 List<String> result = new ArrayList<>(); 657 List<String> result = new ArrayList<>();
654 try { 658 try {
@@ -667,12 +671,11 @@ public class DeviceSearchService { @@ -667,12 +671,11 @@ public class DeviceSearchService {
667 return result; 671 return result;
668 } 672 }
669 673
670 - /** OEE内部记录结构 */  
671 - private static class OeeRecord { 674 + static class OeeRecord {
672 String dtuSn; 675 String dtuSn;
673 String oeeDate; 676 String oeeDate;
674 - JSONArray lampData; // 该日lampData数组  
675 - double availabilityRate; // 稼动率 (%) 677 + JSONArray lampData;
  678 + double availabilityRate;
676 679
677 OeeRecord(String dtuSn, String oeeDate) { 680 OeeRecord(String dtuSn, String oeeDate) {
678 this.dtuSn = dtuSn; 681 this.dtuSn = dtuSn;
@@ -681,34 +684,37 @@ public class DeviceSearchService { @@ -681,34 +684,37 @@ public class DeviceSearchService {
681 } 684 }
682 } 685 }
683 686
684 - /** 批量从数据库查询OEE数据 */  
685 - private List<OeeRecord> queryOeeBatch(List<String> dtuSns, List<String> dateList, String excludeToday) { 687 + private List<OeeRecord> queryOeeBatch(String corpCode, List<String> dtuSns, List<String> dateList, String excludeToday) {
686 List<OeeRecord> records = new ArrayList<>(); 688 List<OeeRecord> records = new ArrayList<>();
687 -  
688 if (dateList.isEmpty()) return records; 689 if (dateList.isEmpty()) return records;
689 690
  691 + String oeeTableName = corpConfigService.getOeeTableName(corpCode);
  692 + JdbcTemplate jt = corpConfigService.getJdbcTemplate(corpCode);
  693 +
690 StringBuilder sql = new StringBuilder( 694 StringBuilder sql = new StringBuilder(
691 "SELECT dtuSn, oee_date, triColorLamp1, triColorLamp2 FROM " + oeeTableName + 695 "SELECT dtuSn, oee_date, triColorLamp1, triColorLamp2 FROM " + oeeTableName +
692 " WHERE corp_code = ? AND dtuSn IN ("); 696 " WHERE corp_code = ? AND dtuSn IN (");
693 List<Object> params = new ArrayList<>(); 697 List<Object> params = new ArrayList<>();
694 - params.add(deviceCorpCode); 698 + params.add(corpCode);
695 699
696 - // dtuSn IN 条件  
697 - for (String sn : dtuSns) { sql.append("?,"); params.add(sn); } 700 + for (String sn : dtuSns) {
  701 + sql.append("?,");
  702 + params.add(sn);
  703 + }
698 sql.deleteCharAt(sql.length() - 1).append(")"); 704 sql.deleteCharAt(sql.length() - 1).append(")");
699 705
700 - // 日期条件(排除今天)  
701 sql.append(" AND oee_date IN ("); 706 sql.append(" AND oee_date IN (");
702 List<Object> dateParams = new ArrayList<>(); 707 List<Object> dateParams = new ArrayList<>();
703 for (String d : dateList) { 708 for (String d : dateList) {
704 if (d.equals(excludeToday)) continue; 709 if (d.equals(excludeToday)) continue;
705 - sql.append("?,"); dateParams.add(d); 710 + sql.append("?,");
  711 + dateParams.add(d);
706 } 712 }
707 - if (dateParams.isEmpty()) return records; // 全是今天 713 + if (dateParams.isEmpty()) return records;
708 sql.deleteCharAt(sql.length() - 1).append(")"); 714 sql.deleteCharAt(sql.length() - 1).append(")");
709 params.addAll(dateParams); 715 params.addAll(dateParams);
710 716
711 - List<Map<String, Object>> rows = jdbcTemplate.queryForList(sql.toString(), params.toArray()); 717 + List<Map<String, Object>> rows = jt.queryForList(sql.toString(), params.toArray());
712 log.info("DB批量查询返回 {} 行OEE数据", rows.size()); 718 log.info("DB批量查询返回 {} 行OEE数据", rows.size());
713 719
714 for (Map<String, Object> row : rows) { 720 for (Map<String, Object> row : rows) {
@@ -734,59 +740,45 @@ public class DeviceSearchService { @@ -734,59 +740,45 @@ public class DeviceSearchService {
734 record.availabilityRate = calcAvailabilityRate(record.lampData); 740 record.availabilityRate = calcAvailabilityRate(record.lampData);
735 records.add(record); 741 records.add(record);
736 } 742 }
737 -  
738 return records; 743 return records;
739 } 744 }
740 745
741 - /** 补充今天的实时接口数据 */  
742 - private void supplementTodayData(List<String> dtuSns, String todayStr, List<OeeRecord> records) { 746 + private void supplementTodayData(String corpCode, List<String> dtuSns, String todayStr, List<OeeRecord> records) {
743 log.info("开始补充今日({})实时OEE数据...", todayStr); 747 log.info("开始补充今日({})实时OEE数据...", todayStr);
744 - int apiCount = 0;  
745 for (String dtuSn : dtuSns) { 748 for (String dtuSn : dtuSns) {
746 - // 先检查是否已有该设备今天的数据  
747 boolean exists = false; 749 boolean exists = false;
748 for (OeeRecord r : records) { 750 for (OeeRecord r : records) {
749 if (r.dtuSn.equals(dtuSn) && r.oeeDate.equals(todayStr)) { 751 if (r.dtuSn.equals(dtuSn) && r.oeeDate.equals(todayStr)) {
750 - exists = true; break; 752 + exists = true;
  753 + break;
751 } 754 }
752 } 755 }
753 if (exists) continue; 756 if (exists) continue;
754 -  
755 try { 757 try {
756 - String apiResult = devicePullService.getLampData(dtuSn, todayStr); 758 + String apiResult = devicePullService.getLampData(corpCode, dtuSn, todayStr);
757 if (!StringUtils.hasText(apiResult)) continue; 759 if (!StringUtils.hasText(apiResult)) continue;
758 -  
759 - Map<String, Object> res = JSON.parseObject(apiResult, new com.alibaba.fastjson.TypeReference<>() {}); 760 + Map<String, Object> res = JSON.parseObject(apiResult, new com.alibaba.fastjson.TypeReference<>() {
  761 + });
760 Integer code = (Integer) res.get("code"); 762 Integer code = (Integer) res.get("code");
761 if (code == null || code != 200) continue; 763 if (code == null || code != 200) continue;
762 -  
763 JSONArray dataList = (JSONArray) res.get("data"); 764 JSONArray dataList = (JSONArray) res.get("data");
764 if (dataList == null || dataList.isEmpty()) continue; 765 if (dataList == null || dataList.isEmpty()) continue;
765 -  
766 JSONObject dataObj = (JSONObject) dataList.get(0); 766 JSONObject dataObj = (JSONObject) dataList.get(0);
767 OeeRecord record = new OeeRecord(dtuSn, todayStr); 767 OeeRecord record = new OeeRecord(dtuSn, todayStr);
768 record.lampData = dataObj.getJSONArray("lampData"); 768 record.lampData = dataObj.getJSONArray("lampData");
769 if (record.lampData == null) record.lampData = new JSONArray(); 769 if (record.lampData == null) record.lampData = new JSONArray();
770 record.availabilityRate = calcAvailabilityRate(record.lampData); 770 record.availabilityRate = calcAvailabilityRate(record.lampData);
771 records.add(record); 771 records.add(record);
772 - apiCount++;  
773 } catch (Exception e) { 772 } catch (Exception e) {
774 log.error("获取今日OEE数据异常 - dtuSn:{}", dtuSn, e); 773 log.error("获取今日OEE数据异常 - dtuSn:{}", dtuSn, e);
775 } 774 }
776 } 775 }
777 - log.info("今日实时数据补充完成, 新增 {} 条", apiCount);  
778 } 776 }
779 777
780 - /**  
781 - * 计算稼动率  
782 - * 稼动率 = 绿灯(state=3)时长 / 总时长 * 100%  
783 - */  
784 private double calcAvailabilityRate(JSONArray lampData) { 778 private double calcAvailabilityRate(JSONArray lampData) {
785 if (lampData == null || lampData.isEmpty()) return 0.0; 779 if (lampData == null || lampData.isEmpty()) return 0.0;
786 -  
787 long totalDuration = 0; 780 long totalDuration = 0;
788 long greenDuration = 0; 781 long greenDuration = 0;
789 -  
790 for (int i = 0; i < lampData.size(); i++) { 782 for (int i = 0; i < lampData.size(); i++) {
791 JSONObject item = lampData.getJSONObject(i); 783 JSONObject item = lampData.getJSONObject(i);
792 if (item == null) continue; 784 if (item == null) continue;
@@ -795,36 +787,30 @@ public class DeviceSearchService { @@ -795,36 +787,30 @@ public class DeviceSearchService {
795 totalDuration += dur; 787 totalDuration += dur;
796 if (state == 3) greenDuration += dur; 788 if (state == 3) greenDuration += dur;
797 } 789 }
798 -  
799 if (totalDuration == 0) return 0.0; 790 if (totalDuration == 0) return 0.0;
800 - return Math.round(greenDuration * 10000.0 / totalDuration) / 100.0; // 保留2位小数 791 + return Math.round(greenDuration * 10000.0 / totalDuration) / 100.0;
801 } 792 }
802 793
803 - /** 按设备分组转换为响应格式:每个设备一条记录,包含lampData和设备名称 */  
804 private List<Map<String, Object>> convertDeviceGroupToResponse(List<String> pagedDevices, 794 private List<Map<String, Object>> convertDeviceGroupToResponse(List<String> pagedDevices,
805 - Map<String, List<OeeRecord>> deviceMap,  
806 - List<String> dateList,  
807 - Map<String, String> deviceNameMap) { 795 + Map<String, List<OeeRecord>> deviceMap,
  796 + List<String> dateList,
  797 + Map<String, String> deviceNameMap) {
808 List<Map<String, Object>> list = new ArrayList<>(pagedDevices.size()); 798 List<Map<String, Object>> list = new ArrayList<>(pagedDevices.size());
809 -  
810 for (String dtuSn : pagedDevices) { 799 for (String dtuSn : pagedDevices) {
811 Map<String, Object> item = new LinkedHashMap<>(); 800 Map<String, Object> item = new LinkedHashMap<>();
812 item.put("dtuSn", dtuSn); 801 item.put("dtuSn", dtuSn);
813 item.put("deviceName", deviceNameMap.getOrDefault(dtuSn, "")); 802 item.put("deviceName", deviceNameMap.getOrDefault(dtuSn, ""));
814 803
815 List<OeeRecord> dayRecords = deviceMap.getOrDefault(dtuSn, Collections.emptyList()); 804 List<OeeRecord> dayRecords = deviceMap.getOrDefault(dtuSn, Collections.emptyList());
816 - // 构建日期→record的快速查找map  
817 Map<String, OeeRecord> recordByDate = new LinkedHashMap<>(); 805 Map<String, OeeRecord> recordByDate = new LinkedHashMap<>();
818 for (OeeRecord r : dayRecords) { 806 for (OeeRecord r : dayRecords) {
819 recordByDate.put(r.oeeDate, r); 807 recordByDate.put(r.oeeDate, r);
820 } 808 }
821 809
822 - // 汇总计算综合稼动率  
823 long totalDur = 0, greenDur = 0; 810 long totalDur = 0, greenDur = 0;
824 long offD = 0, redD = 0, yellowD = 0, greenD = 0, blueD = 0; 811 long offD = 0, redD = 0, yellowD = 0, greenD = 0, blueD = 0;
825 int offC = 0, redC = 0, yellowC = 0, greenC = 0, blueC = 0; 812 int offC = 0, redC = 0, yellowC = 0, greenC = 0, blueC = 0;
826 813
827 - // 拼接所有天的 lampData 为一个数组(按日期排序)  
828 JSONArray allLampData = new JSONArray(); 814 JSONArray allLampData = new JSONArray();
829 List<Map<String, Object>> dailyDetails = new ArrayList<>(); 815 List<Map<String, Object>> dailyDetails = new ArrayList<>();
830 816
@@ -837,11 +823,26 @@ public class DeviceSearchService { @@ -837,11 +823,26 @@ public class DeviceSearchService {
837 int state = lamp.getIntValue("lampState"); 823 int state = lamp.getIntValue("lampState");
838 long dur = lamp.getLongValue("duration"); 824 long dur = lamp.getLongValue("duration");
839 switch (state) { 825 switch (state) {
840 - case 0 -> { offD += dur; offC++; }  
841 - case 1 -> { redD += dur; redC++; }  
842 - case 2 -> { yellowD += dur; yellowC++; }  
843 - case 3 -> { greenD += dur; greenC++; }  
844 - case 4 -> { blueD += dur; blueC++; } 826 + case 0 -> {
  827 + offD += dur;
  828 + offC++;
  829 + }
  830 + case 1 -> {
  831 + redD += dur;
  832 + redC++;
  833 + }
  834 + case 2 -> {
  835 + yellowD += dur;
  836 + yellowC++;
  837 + }
  838 + case 3 -> {
  839 + greenD += dur;
  840 + greenC++;
  841 + }
  842 + case 4 -> {
  843 + blueD += dur;
  844 + blueC++;
  845 + }
845 } 846 }
846 totalDur += dur; 847 totalDur += dur;
847 if (state == 3) greenDur += dur; 848 if (state == 3) greenDur += dur;
@@ -849,16 +850,11 @@ public class DeviceSearchService { @@ -849,16 +850,11 @@ public class DeviceSearchService {
849 allLampData.addAll(rec.lampData); 850 allLampData.addAll(rec.lampData);
850 } 851 }
851 double dayRate = (rec != null) ? rec.availabilityRate : 0.0; 852 double dayRate = (rec != null) ? rec.availabilityRate : 0.0;
852 - dailyDetails.add(Map.of(  
853 - "oeeDate", d,  
854 - "availabilityRate", dayRate,  
855 - "hasData", rec != null  
856 - )); 853 + dailyDetails.add(Map.of("oeeDate", d, "availabilityRate", dayRate, "hasData", rec != null));
857 } 854 }
858 855
859 double overallRate = (totalDur > 0) ? Math.round(greenDur * 10000.0 / totalDur) / 100.0 : 0.0; 856 double overallRate = (totalDur > 0) ? Math.round(greenDur * 10000.0 / totalDur) / 100.0 : 0.0;
860 857
861 - // 扁平化字段,对齐截图格式  
862 item.put("availabilityRatio", String.format("%.2f%%", overallRate)); 858 item.put("availabilityRatio", String.format("%.2f%%", overallRate));
863 item.put("offDuration", formatDuration(offD)); 859 item.put("offDuration", formatDuration(offD));
864 item.put("redDuration", formatDuration(redD)); 860 item.put("redDuration", formatDuration(redD));
@@ -869,28 +865,21 @@ public class DeviceSearchService { @@ -869,28 +865,21 @@ public class DeviceSearchService {
869 item.put("totalDays", dateList.size()); 865 item.put("totalDays", dateList.size());
870 item.put("lampData", allLampData); 866 item.put("lampData", allLampData);
871 item.put("dailyDetails", dailyDetails); 867 item.put("dailyDetails", dailyDetails);
872 -  
873 list.add(item); 868 list.add(item);
874 } 869 }
875 -  
876 return list; 870 return list;
877 } 871 }
878 872
879 - /** 转换为响应格式 */  
880 private List<Map<String, Object>> convertToResponse(List<OeeRecord> records) { 873 private List<Map<String, Object>> convertToResponse(List<OeeRecord> records) {
881 List<Map<String, Object>> list = new ArrayList<>(records.size()); 874 List<Map<String, Object>> list = new ArrayList<>(records.size());
882 -  
883 for (OeeRecord r : records) { 875 for (OeeRecord r : records) {
884 Map<String, Object> item = new LinkedHashMap<>(); 876 Map<String, Object> item = new LinkedHashMap<>();
885 item.put("dtuSn", r.dtuSn); 877 item.put("dtuSn", r.dtuSn);
886 item.put("oeeDate", r.oeeDate); 878 item.put("oeeDate", r.oeeDate);
887 - item.put("availabilityRate", r.availabilityRate); // 稼动率 879 + item.put("availabilityRate", r.availabilityRate);
888 item.put("availabilityRateStr", r.availabilityRate + "%"); 880 item.put("availabilityRateStr", r.availabilityRate + "%");
889 -  
890 - // 各状态时长统计  
891 long offDur = 0, redDur = 0, yellowDur = 0, greenDur = 0, blueDur = 0; 881 long offDur = 0, redDur = 0, yellowDur = 0, greenDur = 0, blueDur = 0;
892 int offCnt = 0, redCnt = 0, yellowCnt = 0, greenCnt = 0, blueCnt = 0; 882 int offCnt = 0, redCnt = 0, yellowCnt = 0, greenCnt = 0, blueCnt = 0;
893 -  
894 if (r.lampData != null) { 883 if (r.lampData != null) {
895 for (int i = 0; i < r.lampData.size(); i++) { 884 for (int i = 0; i < r.lampData.size(); i++) {
896 JSONObject lamp = r.lampData.getJSONObject(i); 885 JSONObject lamp = r.lampData.getJSONObject(i);
@@ -898,52 +887,49 @@ public class DeviceSearchService { @@ -898,52 +887,49 @@ public class DeviceSearchService {
898 int state = lamp.getIntValue("lampState"); 887 int state = lamp.getIntValue("lampState");
899 long dur = lamp.getLongValue("duration"); 888 long dur = lamp.getLongValue("duration");
900 switch (state) { 889 switch (state) {
901 - case 0 -> { offDur += dur; offCnt++; }  
902 - case 1 -> { redDur += dur; redCnt++; }  
903 - case 2 -> { yellowDur += dur; yellowCnt++; }  
904 - case 3 -> { greenDur += dur; greenCnt++; }  
905 - case 4 -> { blueDur += dur; blueCnt++; } 890 + case 0 -> {
  891 + offDur += dur;
  892 + offCnt++;
  893 + }
  894 + case 1 -> {
  895 + redDur += dur;
  896 + redCnt++;
  897 + }
  898 + case 2 -> {
  899 + yellowDur += dur;
  900 + yellowCnt++;
  901 + }
  902 + case 3 -> {
  903 + greenDur += dur;
  904 + greenCnt++;
  905 + }
  906 + case 4 -> {
  907 + blueDur += dur;
  908 + blueCnt++;
  909 + }
906 } 910 }
907 } 911 }
908 } 912 }
909 -  
910 item.put("off", Map.of("duration", formatDuration(offDur), "seconds", offDur, "count", offCnt)); 913 item.put("off", Map.of("duration", formatDuration(offDur), "seconds", offDur, "count", offCnt));
911 item.put("red", Map.of("duration", formatDuration(redDur), "seconds", redDur, "count", redCnt)); 914 item.put("red", Map.of("duration", formatDuration(redDur), "seconds", redDur, "count", redCnt));
912 item.put("yellow", Map.of("duration", formatDuration(yellowDur), "seconds", yellowDur, "count", yellowCnt)); 915 item.put("yellow", Map.of("duration", formatDuration(yellowDur), "seconds", yellowDur, "count", yellowCnt));
913 item.put("green", Map.of("duration", formatDuration(greenDur), "seconds", greenDur, "count", greenCnt)); 916 item.put("green", Map.of("duration", formatDuration(greenDur), "seconds", greenDur, "count", greenCnt));
914 item.put("blue", Map.of("duration", formatDuration(blueDur), "seconds", blueDur, "count", blueCnt)); 917 item.put("blue", Map.of("duration", formatDuration(blueDur), "seconds", blueDur, "count", blueCnt));
915 item.put("lampData", r.lampData != null ? r.lampData : new JSONArray()); 918 item.put("lampData", r.lampData != null ? r.lampData : new JSONArray());
916 -  
917 list.add(item); 919 list.add(item);
918 } 920 }
919 return list; 921 return list;
920 } 922 }
921 923
922 - /** 构建分页结果(标准分页格式) */  
923 private Map<String, Object> buildPageResult(long total, int pageNo, int pageSize, List<Map<String, Object>> list) { 924 private Map<String, Object> buildPageResult(long total, int pageNo, int pageSize, List<Map<String, Object>> list) {
924 - return Map.of(  
925 - "data", Map.of(  
926 - "total", total,  
927 - "size", pageSize,  
928 - "current", pageNo,  
929 - "records", list  
930 - )  
931 - ); 925 + return Map.of("data", Map.of("total", total, "size", pageSize, "current", pageNo, "records", list));
932 } 926 }
933 927
934 // ==================== 智能灯统计稼动率查询(仪表盘) ==================== 928 // ==================== 智能灯统计稼动率查询(仪表盘) ====================
935 929
936 - /**  
937 - * 智能灯统计稼动率综合查询(仪表盘数据)  
938 - * 返回:总时长、稼动率、当前机台运行状态、异常排行榜、每设备状态时长  
939 - *  
940 - * @param startDate 开始日期 yyyy-MM-dd  
941 - * @param endDate 结束日期 yyyy-MM-dd  
942 - */  
943 - public Map<String, Object> queryLampStatistics(String startDate, String endDate) {  
944 - log.info("========== [智能灯统计查询] startDate={}, endDate={} ==========", startDate, endDate); 930 + public Map<String, Object> queryLampStatistics(String corpCode, String startDate, String endDate) {
  931 + log.info("========== [智能灯统计查询] corpCode={}, startDate={}, endDate={} ==========", corpCode, startDate, endDate);
945 932
946 - // 1. 根据前端传入的起止日期构建日期范围  
947 List<String> dateList = buildDayList(startDate, endDate); 933 List<String> dateList = buildDayList(startDate, endDate);
948 if (dateList.isEmpty()) { 934 if (dateList.isEmpty()) {
949 return buildEmptyLampStats(); 935 return buildEmptyLampStats();
@@ -953,22 +939,17 @@ public class DeviceSearchService { @@ -953,22 +939,17 @@ public class DeviceSearchService {
953 boolean includeToday = dateList.contains(todayStr); 939 boolean includeToday = dateList.contains(todayStr);
954 log.info("日期范围共 {} 天, 包含今日({}): {}", dateList.size(), todayStr, includeToday); 940 log.info("日期范围共 {} 天, 包含今日({}): {}", dateList.size(), todayStr, includeToday);
955 941
956 - // 2. 获取所有设备及名称  
957 - Map<String, String> deviceNameMap = queryAllDtuSnWithName(); 942 + Map<String, String> deviceNameMap = queryAllDtuSnWithName(corpCode);
958 List<String> allDtuSns = new ArrayList<>(deviceNameMap.keySet()); 943 List<String> allDtuSns = new ArrayList<>(deviceNameMap.keySet());
959 if (allDtuSns.isEmpty()) { 944 if (allDtuSns.isEmpty()) {
960 return buildEmptyLampStats(); 945 return buildEmptyLampStats();
961 } 946 }
962 947
963 - // 3. 批量从OEE表查询数据  
964 - List<OeeRecord> allRecords = queryOeeBatch(allDtuSns, dateList, includeToday ? todayStr : null);  
965 -  
966 - // 4. 补充今天的实时数据 948 + List<OeeRecord> allRecords = queryOeeBatch(corpCode, allDtuSns, dateList, includeToday ? todayStr : null);
967 if (includeToday) { 949 if (includeToday) {
968 - supplementTodayData(allDtuSns, todayStr, allRecords); 950 + supplementTodayData(corpCode, allDtuSns, todayStr, allRecords);
969 } 951 }
970 952
971 - // 5. 按 dtuSn 分组  
972 Map<String, List<OeeRecord>> deviceMap = new LinkedHashMap<>(); 953 Map<String, List<OeeRecord>> deviceMap = new LinkedHashMap<>();
973 for (OeeRecord r : allRecords) { 954 for (OeeRecord r : allRecords) {
974 deviceMap.computeIfAbsent(r.dtuSn, k -> new ArrayList<>()).add(r); 955 deviceMap.computeIfAbsent(r.dtuSn, k -> new ArrayList<>()).add(r);
@@ -979,43 +960,27 @@ public class DeviceSearchService { @@ -979,43 +960,27 @@ public class DeviceSearchService {
979 } 960 }
980 } 961 }
981 962
982 - // 6. 计算各项统计数据  
983 - return buildLampStatisticsResult(allDtuSns, deviceMap, deviceNameMap, dateList); 963 + return buildLampStatisticsResult(allDtuSns, deviceMap, deviceNameMap, dateList, corpCode);
984 } 964 }
985 965
986 - /** 构建空结果 */  
987 private Map<String, Object> buildEmptyLampStats() { 966 private Map<String, Object> buildEmptyLampStats() {
988 - return Map.of(  
989 - "totalDuration", Map.of(  
990 - "off", Map.of("duration", "0时0分0秒", "seconds", 0),  
991 - "red", Map.of("duration", "0时0分0秒", "seconds", 0),  
992 - "yellow", Map.of("duration", "0时0分0秒", "seconds", 0),  
993 - "green", Map.of("duration", "0时0分0秒", "seconds", 0),  
994 - "blue", Map.of("duration", "0时0分0秒", "seconds", 0)  
995 - ),  
996 - "availabilityRate", "0.00%",  
997 - "currentStatus", Map.of(  
998 - "off", 0, "red", 0, "yellow", 0, "green", 0, "blue", 0  
999 - ),  
1000 - "abnormalRanking", List.of(),  
1001 - "deviceList", List.of()  
1002 - ); 967 + return Map.of("totalDuration", Map.of("off", Map.of("duration", "0时0分0秒", "seconds", 0),
  968 + "red", Map.of("duration", "0时0分0秒", "seconds", 0), "yellow", Map.of("duration", "0时0分0秒", "seconds", 0),
  969 + "green", Map.of("duration", "0时0分0秒", "seconds", 0), "blue", Map.of("duration", "0时0分0秒", "seconds", 0)),
  970 + "availabilityRate", "0.00%", "currentStatus", Map.of("off", 0, "red", 0, "yellow", 0, "green", 0, "blue", 0),
  971 + "abnormalRanking", List.of(), "deviceList", List.of());
1003 } 972 }
1004 973
1005 - /** 构建智能灯统计结果 */  
1006 private Map<String, Object> buildLampStatisticsResult(List<String> allDtuSns, 974 private Map<String, Object> buildLampStatisticsResult(List<String> allDtuSns,
1007 - Map<String, List<OeeRecord>> deviceMap,  
1008 - Map<String, String> deviceNameMap,  
1009 - List<String> dateList) {  
1010 - // ---- ① 总时长:汇总所有设备各状态时长 ---- 975 + Map<String, List<OeeRecord>> deviceMap,
  976 + Map<String, String> deviceNameMap,
  977 + List<String> dateList,
  978 + String corpCode) {
1011 long totalOff = 0, totalRed = 0, totalYellow = 0, totalGreen = 0, totalBlue = 0; 979 long totalOff = 0, totalRed = 0, totalYellow = 0, totalGreen = 0, totalBlue = 0;
1012 -  
1013 - // ---- ② 设备维度统计:用于异常排名和每设备详情 ----  
1014 List<Map<String, Object>> deviceStatList = new ArrayList<>(); 980 List<Map<String, Object>> deviceStatList = new ArrayList<>();
1015 981
1016 for (String dtuSn : allDtuSns) { 982 for (String dtuSn : allDtuSns) {
1017 List<OeeRecord> dayRecords = deviceMap.getOrDefault(dtuSn, Collections.emptyList()); 983 List<OeeRecord> dayRecords = deviceMap.getOrDefault(dtuSn, Collections.emptyList());
1018 -  
1019 long devOff = 0, devRed = 0, devYellow = 0, devGreen = 0, devBlue = 0; 984 long devOff = 0, devRed = 0, devYellow = 0, devGreen = 0, devBlue = 0;
1020 long devTotalDur = 0, devGreenDur = 0; 985 long devTotalDur = 0, devGreenDur = 0;
1021 986
@@ -1030,18 +995,19 @@ public class DeviceSearchService { @@ -1030,18 +995,19 @@ public class DeviceSearchService {
1030 case 0 -> devOff += dur; 995 case 0 -> devOff += dur;
1031 case 1 -> devRed += dur; 996 case 1 -> devRed += dur;
1032 case 2 -> devYellow += dur; 997 case 2 -> devYellow += dur;
1033 - case 3 -> { devGreen += dur; devGreenDur += dur; } 998 + case 3 -> {
  999 + devGreen += dur;
  1000 + devGreenDur += dur;
  1001 + }
1034 case 4 -> devBlue += dur; 1002 case 4 -> devBlue += dur;
1035 } 1003 }
1036 devTotalDur += dur; 1004 devTotalDur += dur;
1037 } 1005 }
1038 } 1006 }
1039 } 1007 }
1040 -  
1041 - // 稼动率 = 绿 / (红 + 黄 + 绿) * 100%  
1042 long devRygDur = devRed + devYellow + devGreen; 1008 long devRygDur = devRed + devYellow + devGreen;
1043 double rate = (devRygDur > 0) ? Math.round(devGreenDur * 10000.0 / devRygDur) / 100.0 : 0.0; 1009 double rate = (devRygDur > 0) ? Math.round(devGreenDur * 10000.0 / devRygDur) / 100.0 : 0.0;
1044 - long abnormalDur = devRed + devYellow; // 异常时长 = 红+黄 1010 + long abnormalDur = devRed + devYellow;
1045 1011
1046 Map<String, Object> devStat = new LinkedHashMap<>(); 1012 Map<String, Object> devStat = new LinkedHashMap<>();
1047 devStat.put("dtuSn", dtuSn); 1013 devStat.put("dtuSn", dtuSn);
@@ -1057,12 +1023,10 @@ public class DeviceSearchService { @@ -1057,12 +1023,10 @@ public class DeviceSearchService {
1057 devStat.put("blueDuration", formatDuration(devBlue)); 1023 devStat.put("blueDuration", formatDuration(devBlue));
1058 devStat.put("blueSeconds", devBlue); 1024 devStat.put("blueSeconds", devBlue);
1059 devStat.put("availabilityRatio", String.format("%.2f%%", rate)); 1025 devStat.put("availabilityRatio", String.format("%.2f%%", rate));
1060 - devStat.put("rygTotalDuration", formatDuration(devRygDur)); // 红+黄+绿 总时长  
1061 - devStat.put("abnormalDuration", abnormalDur); // 用于排序  
1062 - 1026 + devStat.put("rygTotalDuration", formatDuration(devRygDur));
  1027 + devStat.put("abnormalDuration", abnormalDur);
1063 deviceStatList.add(devStat); 1028 deviceStatList.add(devStat);
1064 1029
1065 - // 累加到全局总计  
1066 totalOff += devOff; 1030 totalOff += devOff;
1067 totalRed += devRed; 1031 totalRed += devRed;
1068 totalYellow += devYellow; 1032 totalYellow += devYellow;
@@ -1070,45 +1034,29 @@ public class DeviceSearchService { @@ -1070,45 +1034,29 @@ public class DeviceSearchService {
1070 totalBlue += devBlue; 1034 totalBlue += devBlue;
1071 } 1035 }
1072 1036
1073 - // ---- ③ 稼动率 = 绿 / (红 + 黄 + 绿) ----  
1074 long totalRygDur = totalRed + totalYellow + totalGreen; 1037 long totalRygDur = totalRed + totalYellow + totalGreen;
1075 double overallRate = (totalRygDur > 0) ? Math.round(totalGreen * 10000.0 / totalRygDur) / 100.0 : 0.0; 1038 double overallRate = (totalRygDur > 0) ? Math.round(totalGreen * 10000.0 / totalRygDur) / 100.0 : 0.0;
  1039 + Map<String, Integer> currentStatus = queryCurrentDeviceStatus(corpCode);
1076 1040
1077 - // ---- ④ 当前机台运行状态(从设备表实时查) ----  
1078 - Map<String, Integer> currentStatus = queryCurrentDeviceStatus();  
1079 -  
1080 - // ---- ⑤ 异常排行榜(按红+黄时长降序) ----  
1081 - deviceStatList.sort((a, b) -> Long.compare(  
1082 - ((Number) b.get("abnormalDuration")).longValue(),  
1083 - ((Number) a.get("abnormalDuration")).longValue()  
1084 - ));  
1085 - // 排序后移除辅助字段 1041 + deviceStatList.sort((a, b) -> Long.compare(((Number) b.get("abnormalDuration")).longValue(), ((Number) a.get("abnormalDuration")).longValue()));
1086 for (Map<String, Object> d : deviceStatList) { 1042 for (Map<String, Object> d : deviceStatList) {
1087 d.remove("abnormalDuration"); 1043 d.remove("abnormalDuration");
1088 } 1044 }
1089 1045
1090 - return Map.of(  
1091 - "totalDuration", Map.of(  
1092 - "off", Map.of("duration", formatDuration(totalOff), "seconds", totalOff), 1046 + return Map.of("totalDuration", Map.of("off", Map.of("duration", formatDuration(totalOff), "seconds", totalOff),
1093 "red", Map.of("duration", formatDuration(totalRed), "seconds", totalRed), 1047 "red", Map.of("duration", formatDuration(totalRed), "seconds", totalRed),
1094 "yellow", Map.of("duration", formatDuration(totalYellow), "seconds", totalYellow), 1048 "yellow", Map.of("duration", formatDuration(totalYellow), "seconds", totalYellow),
1095 "green", Map.of("duration", formatDuration(totalGreen), "seconds", totalGreen), 1049 "green", Map.of("duration", formatDuration(totalGreen), "seconds", totalGreen),
1096 - "blue", Map.of("duration", formatDuration(totalBlue), "seconds", totalBlue)  
1097 - ),  
1098 - "availabilityRate", String.format("%.2f%%", overallRate),  
1099 - "rygTotalDuration", formatDuration(totalRygDur), // 红黄绿总时长  
1100 - "currentStatus", currentStatus,  
1101 - "abnormalRanking", deviceStatList,  
1102 - "deviceList", deviceStatList  
1103 - ); 1050 + "blue", Map.of("duration", formatDuration(totalBlue), "seconds", totalBlue)),
  1051 + "availabilityRate", String.format("%.2f%%", overallRate), "rygTotalDuration", formatDuration(totalRygDur),
  1052 + "currentStatus", currentStatus, "abnormalRanking", deviceStatList, "deviceList", deviceStatList);
1104 } 1053 }
1105 1054
1106 - /** 查询当前设备的运行状态分布(从设备表) */  
1107 - private Map<String, Integer> queryCurrentDeviceStatus() {  
1108 - String sql = "SELECT lampState, COUNT(*) as cnt FROM " + deviceTableName +  
1109 - " WHERE corp_code = ? GROUP BY lampState";  
1110 - List<Map<String, Object>> rows = jdbcTemplate.queryForList(sql, deviceCorpCode);  
1111 - 1055 + private Map<String, Integer> queryCurrentDeviceStatus(String corpCode) {
  1056 + String tableName = corpConfigService.getDeviceTableName(corpCode);
  1057 + JdbcTemplate jt = corpConfigService.getJdbcTemplate(corpCode);
  1058 + String sql = "SELECT lampState, COUNT(*) as cnt FROM " + tableName + " WHERE corp_code = ? GROUP BY lampState";
  1059 + List<Map<String, Object>> rows = jt.queryForList(sql, corpCode);
1112 int off = 0, red = 0, yellow = 0, green = 0, blue = 0; 1060 int off = 0, red = 0, yellow = 0, green = 0, blue = 0;
1113 for (Map<String, Object> row : rows) { 1061 for (Map<String, Object> row : rows) {
1114 String state = String.valueOf(row.get("lampState")); 1062 String state = String.valueOf(row.get("lampState"));
@@ -1126,50 +1074,36 @@ public class DeviceSearchService { @@ -1126,50 +1074,36 @@ public class DeviceSearchService {
1126 1074
1127 // ==================== 开机率查询 ==================== 1075 // ==================== 开机率查询 ====================
1128 1076
1129 - /**  
1130 - * 查询每台设备的开机率(基于 dev_util 表)  
1131 - * 规则:灭灯(state=0)=未开机,其他灯(state=1/2/3/4)=开机  
1132 - * 开机率 = 非灭灯时长 / 总时长 * 100%  
1133 - *  
1134 - * @param startDate 开始日期 yyyy-MM-dd  
1135 - * @param endDate 结束日期 yyyy-MM-dd  
1136 - */  
1137 - public Map<String, Object> queryBootRate(String startDate, String endDate) {  
1138 - log.info("========== [开机率查询] startDate={}, endDate={} ==========", startDate, endDate);  
1139 - 1077 + public Map<String, Object> queryBootRate(String corpCode, String startDate, String endDate) {
  1078 + log.info("========== [开机率查询] corpCode={}, startDate={}, endDate={} ==========", corpCode, startDate, endDate);
1140 if (!StringUtils.hasText(startDate) || !StringUtils.hasText(endDate)) { 1079 if (!StringUtils.hasText(startDate) || !StringUtils.hasText(endDate)) {
1141 return Map.of("list", List.of(), "startDate", startDate, "endDate", endDate); 1080 return Map.of("list", List.of(), "startDate", startDate, "endDate", endDate);
1142 } 1081 }
1143 -  
1144 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); 1082 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
1145 String todayStr = sdf.format(new Date()); 1083 String todayStr = sdf.format(new Date());
1146 boolean includeToday = isDateInRange(todayStr, startDate, endDate); 1084 boolean includeToday = isDateInRange(todayStr, startDate, endDate);
1147 - log.info("设备总数: {}, 包含今日({}): {}", includeToday);  
1148 1085
1149 - // 1. 获取所有设备列表  
1150 - Map<String, String> deviceNameMap = queryAllDtuSnWithName(); 1086 + Map<String, String> deviceNameMap = queryAllDtuSnWithName(corpCode);
1151 List<String> allDtuSns = new ArrayList<>(deviceNameMap.keySet()); 1087 List<String> allDtuSns = new ArrayList<>(deviceNameMap.keySet());
1152 if (allDtuSns.isEmpty()) { 1088 if (allDtuSns.isEmpty()) {
1153 return Map.of("list", List.of(), "startDate", startDate, "endDate", endDate); 1089 return Map.of("list", List.of(), "startDate", startDate, "endDate", endDate);
1154 } 1090 }
1155 log.info("设备总数: {}", allDtuSns.size()); 1091 log.info("设备总数: {}", allDtuSns.size());
1156 1092
1157 - // 2. 从 dev_util 表按 dtuSn 和日期范围汇总各状态时长(排除今天)  
1158 - String dbStartDate = includeToday && startDate.equals(todayStr) ? getNextDay(todayStr) : startDate; 1093 + String devUtilTableName = corpConfigService.getDevUtilTableName(corpCode);
  1094 + JdbcTemplate jt = corpConfigService.getJdbcTemplate(corpCode);
  1095 +
1159 List<Map<String, Object>> rows; 1096 List<Map<String, Object>> rows;
1160 if (includeToday) { 1097 if (includeToday) {
1161 - // 排除今天,今天走接口  
1162 - rows = queryDevUtilBatch(deviceCorpCode, allDtuSns, startDate, endDate, todayStr); 1098 + rows = queryDevUtilBatch(jt, devUtilTableName, corpCode, allDtuSns, startDate, endDate, todayStr);
1163 } else { 1099 } else {
1164 String sql = "SELECT dtuSn, SUM(`0`) as s0, SUM(`1`) as s1, SUM(`2`) as s2, SUM(`3`) as s3, SUM(`4`) as s4, COUNT(*) as days " + 1100 String sql = "SELECT dtuSn, SUM(`0`) as s0, SUM(`1`) as s1, SUM(`2`) as s2, SUM(`3`) as s3, SUM(`4`) as s4, COUNT(*) as days " +
1165 - "FROM " + devUtilTableName +  
1166 - " WHERE corp_code = ? AND date_util BETWEEN ? AND ? GROUP BY dtuSn";  
1167 - rows = jdbcTemplate.queryForList(sql, deviceCorpCode, startDate, endDate); 1101 + "FROM " + devUtilTableName + " WHERE corp_code = ? AND date_util BETWEEN ? AND ? GROUP BY dtuSn";
  1102 + rows = jt.queryForList(sql, corpCode, startDate, endDate);
1168 } 1103 }
1169 log.info("dev_util 查询返回 {} 条记录", rows.size()); 1104 log.info("dev_util 查询返回 {} 条记录", rows.size());
1170 1105
1171 - // 3. 按 dtuSn 构建查询结果 map  
1172 - Map<String, double[]> rawMap = new LinkedHashMap<>(); // [s0, s1, s2, s3, s4, dataDays] 1106 + Map<String, double[]> rawMap = new LinkedHashMap<>();
1173 for (Map<String, Object> row : rows) { 1107 for (Map<String, Object> row : rows) {
1174 String sn = (String) row.get("dtuSn"); 1108 String sn = (String) row.get("dtuSn");
1175 double s0 = ((Number) row.get("s0")).doubleValue(); 1109 double s0 = ((Number) row.get("s0")).doubleValue();
@@ -1181,20 +1115,17 @@ public class DeviceSearchService { @@ -1181,20 +1115,17 @@ public class DeviceSearchService {
1181 rawMap.put(sn, new double[]{s0, s1, s2, s3, s4, dataDays}); 1115 rawMap.put(sn, new double[]{s0, s1, s2, s3, s4, dataDays});
1182 } 1116 }
1183 1117
1184 - // 4. 如果包含今天,补充调用稼动率接口获取今天的实时数据  
1185 if (includeToday) { 1118 if (includeToday) {
1186 - supplementTodayDevUtil(allDtuSns, todayStr, rawMap); 1119 + supplementTodayDevUtil(corpCode, allDtuSns, todayStr, rawMap);
1187 } 1120 }
1188 1121
1189 - // 5. 构建最终结果  
1190 Map<String, Map<String, Object>> rateMap = new LinkedHashMap<>(); 1122 Map<String, Map<String, Object>> rateMap = new LinkedHashMap<>();
1191 for (Map.Entry<String, double[]> entry : rawMap.entrySet()) { 1123 for (Map.Entry<String, double[]> entry : rawMap.entrySet()) {
1192 String sn = entry.getKey(); 1124 String sn = entry.getKey();
1193 double[] vals = entry.getValue(); 1125 double[] vals = entry.getValue();
1194 double totalDur = vals[0] + vals[1] + vals[2] + vals[3] + vals[4]; 1126 double totalDur = vals[0] + vals[1] + vals[2] + vals[3] + vals[4];
1195 - double onDur = vals[1] + vals[2] + vals[3] + vals[4]; // 非灭灯时长 = 开机时长 1127 + double onDur = vals[1] + vals[2] + vals[3] + vals[4];
1196 double bootRate = totalDur > 0 ? Math.round(onDur * 10000.0 / totalDur) / 100.0 : 0.0; 1128 double bootRate = totalDur > 0 ? Math.round(onDur * 10000.0 / totalDur) / 100.0 : 0.0;
1197 -  
1198 Map<String, Object> item = new LinkedHashMap<>(); 1129 Map<String, Object> item = new LinkedHashMap<>();
1199 item.put("dtuSn", sn); 1130 item.put("dtuSn", sn);
1200 item.put("deviceName", deviceNameMap.getOrDefault(sn, "")); 1131 item.put("deviceName", deviceNameMap.getOrDefault(sn, ""));
@@ -1207,11 +1138,9 @@ public class DeviceSearchService { @@ -1207,11 +1138,9 @@ public class DeviceSearchService {
1207 item.put("bootRate", String.format("%.2f%%", bootRate)); 1138 item.put("bootRate", String.format("%.2f%%", bootRate));
1208 item.put("bootRateValue", bootRate); 1139 item.put("bootRateValue", bootRate);
1209 item.put("dataDays", (int) vals[5]); 1140 item.put("dataDays", (int) vals[5]);
1210 -  
1211 rateMap.put(sn, item); 1141 rateMap.put(sn, item);
1212 } 1142 }
1213 1143
1214 - // 6. 确保所有设备都在返回列表中(没有数据的设备开机率为0)  
1215 List<Map<String, Object>> resultList = new ArrayList<>(allDtuSns.size()); 1144 List<Map<String, Object>> resultList = new ArrayList<>(allDtuSns.size());
1216 for (String sn : allDtuSns) { 1145 for (String sn : allDtuSns) {
1217 if (rateMap.containsKey(sn)) { 1146 if (rateMap.containsKey(sn)) {
@@ -1233,7 +1162,6 @@ public class DeviceSearchService { @@ -1233,7 +1162,6 @@ public class DeviceSearchService {
1233 } 1162 }
1234 } 1163 }
1235 1164
1236 - // 计算整体汇总  
1237 double sumTotal = 0, sumOn = 0, sumOff = 0; 1165 double sumTotal = 0, sumOn = 0, sumOff = 0;
1238 for (Map<String, Object> r : rateMap.values()) { 1166 for (Map<String, Object> r : rateMap.values()) {
1239 sumTotal += ((Number) r.get("totalSeconds")).doubleValue(); 1167 sumTotal += ((Number) r.get("totalSeconds")).doubleValue();
@@ -1242,105 +1170,82 @@ public class DeviceSearchService { @@ -1242,105 +1170,82 @@ public class DeviceSearchService {
1242 } 1170 }
1243 double overallBootRate = sumTotal > 0 ? Math.round(sumOn * 10000.0 / sumTotal) / 100.0 : 0.0; 1171 double overallBootRate = sumTotal > 0 ? Math.round(sumOn * 10000.0 / sumTotal) / 100.0 : 0.0;
1244 1172
1245 - return Map.of(  
1246 - "summary", Map.of(  
1247 - "totalDevices", allDtuSns.size(),  
1248 - "totalDuration", formatDuration((long) sumTotal),  
1249 - "totalSeconds", Math.round(sumTotal),  
1250 - "onDuration", formatDuration((long) sumOn),  
1251 - "onSeconds", Math.round(sumOn),  
1252 - "offDuration", formatDuration((long) sumOff),  
1253 - "offSeconds", Math.round(sumOff),  
1254 - "overallBootRate", String.format("%.2f%%", overallBootRate),  
1255 - "overallBootRateValue", overallBootRate  
1256 - ),  
1257 - "list", resultList,  
1258 - "startDate", startDate,  
1259 - "endDate", endDate  
1260 - ); 1173 + return Map.of("summary", Map.of("totalDevices", allDtuSns.size(),
  1174 + "totalDuration", formatDuration((long) sumTotal), "totalSeconds", Math.round(sumTotal),
  1175 + "onDuration", formatDuration((long) sumOn), "onSeconds", Math.round(sumOn),
  1176 + "offDuration", formatDuration((long) sumOff), "offSeconds", Math.round(sumOff),
  1177 + "overallBootRate", String.format("%.2f%%", overallBootRate), "overallBootRateValue", overallBootRate),
  1178 + "list", resultList, "startDate", startDate, "endDate", endDate);
1261 } 1179 }
1262 1180
1263 - /** 批量从 dev_util 表查询(排除指定日期) */  
1264 - private List<Map<String, Object>> queryDevUtilBatch(String corpCode, List<String> dtuSns,  
1265 - String startDate, String endDate, String excludeToday) {  
1266 - StringBuilder sql = new StringBuilder(  
1267 - "SELECT dtuSn, SUM(`0`) as s0, SUM(`1`) as s1, SUM(`2`) as s2, SUM(`3`) as s3, SUM(`4`) as s4, COUNT(*) as days " +  
1268 - "FROM " + devUtilTableName +  
1269 - " WHERE corp_code = ? AND dtuSn IN ("); 1181 + private List<Map<String, Object>> queryDevUtilBatch(JdbcTemplate jt, String devUtilTableName, String corpCode,
  1182 + List<String> dtuSns, String startDate, String endDate, String excludeToday) {
  1183 + StringBuilder sql = new StringBuilder("SELECT dtuSn, SUM(`0`) as s0, SUM(`1`) as s1, SUM(`2`) as s2, SUM(`3`) as s3, SUM(`4`) as s4, COUNT(*) as days " +
  1184 + "FROM " + devUtilTableName + " WHERE corp_code = ? AND dtuSn IN (");
1270 List<Object> params = new ArrayList<>(); 1185 List<Object> params = new ArrayList<>();
1271 params.add(corpCode); 1186 params.add(corpCode);
1272 -  
1273 - for (String sn : dtuSns) { sql.append("?,"); params.add(sn); } 1187 + for (String sn : dtuSns) {
  1188 + sql.append("?,");
  1189 + params.add(sn);
  1190 + }
1274 sql.deleteCharAt(sql.length() - 1).append(")"); 1191 sql.deleteCharAt(sql.length() - 1).append(")");
1275 -  
1276 - // 日期范围:如果开始日期=excludeToday,则从明天开始查  
1277 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); 1192 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
1278 String actualStart = startDate.equals(excludeToday) ? getNextDay(excludeToday) : startDate; 1193 String actualStart = startDate.equals(excludeToday) ? getNextDay(excludeToday) : startDate;
1279 -  
1280 try { 1194 try {
1281 Date startD = sdf.parse(actualStart); 1195 Date startD = sdf.parse(actualStart);
1282 Date endD = sdf.parse(endDate); 1196 Date endD = sdf.parse(endDate);
1283 Date excD = sdf.parse(excludeToday); 1197 Date excD = sdf.parse(excludeToday);
1284 - if (!startD.before(excD) || endD.before(startD)) {  
1285 - return Collections.emptyList(); // 只有今天一天或无效范围  
1286 - } 1198 + if (!startD.before(excD) || endD.before(startD)) return Collections.emptyList();
1287 } catch (Exception e) { 1199 } catch (Exception e) {
1288 log.error("日期解析失败: {} ~ {}, 排除: {}", actualStart, endDate, excludeToday, e); 1200 log.error("日期解析失败: {} ~ {}, 排除: {}", actualStart, endDate, excludeToday, e);
1289 return Collections.emptyList(); 1201 return Collections.emptyList();
1290 } 1202 }
1291 -  
1292 sql.append(" AND date_util BETWEEN ? AND ?"); 1203 sql.append(" AND date_util BETWEEN ? AND ?");
1293 params.add(actualStart); 1204 params.add(actualStart);
1294 params.add(endDate); 1205 params.add(endDate);
1295 sql.append(" GROUP BY dtuSn"); 1206 sql.append(" GROUP BY dtuSn");
1296 -  
1297 - return jdbcTemplate.queryForList(sql.toString(), params.toArray()); 1207 + return jt.queryForList(sql.toString(), params.toArray());
1298 } 1208 }
1299 1209
1300 - /** 补充今天的稼动率接口实时数据 */  
1301 - private void supplementTodayDevUtil(List<String> dtuSns, String todayStr, Map<String, double[]> rawMap) { 1210 + private void supplementTodayDevUtil(String corpCode, List<String> dtuSns, String todayStr, Map<String, double[]> rawMap) {
1302 log.info("开机率查询 - 开始补充今日({})实时dev_util数据...", todayStr); 1211 log.info("开机率查询 - 开始补充今日({})实时dev_util数据...", todayStr);
1303 - int apiCount = 0;  
1304 for (String dtuSn : dtuSns) { 1212 for (String dtuSn : dtuSns) {
1305 try { 1213 try {
1306 - String rateResult = devicePullService.getDtuSnRateOfAction(dtuSn, todayStr, todayStr); 1214 + String rateResult = devicePullService.getDtuSnRateOfAction(corpCode, dtuSn, todayStr, todayStr);
1307 if (StringUtils.hasText(rateResult)) { 1215 if (StringUtils.hasText(rateResult)) {
1308 - Map<String, Object> res = JSON.parseObject(rateResult, new com.alibaba.fastjson.TypeReference<>() {}); 1216 + Map<String, Object> res = JSON.parseObject(rateResult, new com.alibaba.fastjson.TypeReference<>() {
  1217 + });
1309 Integer code = (Integer) res.get("code"); 1218 Integer code = (Integer) res.get("code");
1310 if (code == null || code != 200) continue; 1219 if (code == null || code != 200) continue;
1311 -  
1312 JSONArray dataList = (JSONArray) res.get("data"); 1220 JSONArray dataList = (JSONArray) res.get("data");
1313 if (dataList == null || dataList.isEmpty()) continue; 1221 if (dataList == null || dataList.isEmpty()) continue;
1314 -  
1315 JSONObject dayData = (JSONObject) dataList.get(0); 1222 JSONObject dayData = (JSONObject) dataList.get(0);
1316 JSONArray realRateList = dayData.getJSONArray("realRate"); 1223 JSONArray realRateList = dayData.getJSONArray("realRate");
1317 if (realRateList == null || realRateList.isEmpty()) continue; 1224 if (realRateList == null || realRateList.isEmpty()) continue;
1318 -  
1319 JSONObject rateObj = (JSONObject) realRateList.get(0); 1225 JSONObject rateObj = (JSONObject) realRateList.get(0);
1320 double s0 = rateObj.getDoubleValue("0"); 1226 double s0 = rateObj.getDoubleValue("0");
1321 double s1 = rateObj.getDoubleValue("1"); 1227 double s1 = rateObj.getDoubleValue("1");
1322 double s2 = rateObj.getDoubleValue("2"); 1228 double s2 = rateObj.getDoubleValue("2");
1323 double s3 = rateObj.getDoubleValue("3"); 1229 double s3 = rateObj.getDoubleValue("3");
1324 double s4 = rateObj.getDoubleValue("4"); 1230 double s4 = rateObj.getDoubleValue("4");
1325 -  
1326 - // 累加到已有数据上(DB已有历史数据 + 今天实时数据)  
1327 double[] existing = rawMap.get(dtuSn); 1231 double[] existing = rawMap.get(dtuSn);
1328 if (existing != null) { 1232 if (existing != null) {
1329 - existing[0] += s0; existing[1] += s1; existing[2] += s2;  
1330 - existing[3] += s3; existing[4] += s4; existing[5] += 1; 1233 + existing[0] += s0;
  1234 + existing[1] += s1;
  1235 + existing[2] += s2;
  1236 + existing[3] += s3;
  1237 + existing[4] += s4;
  1238 + existing[5] += 1;
1331 } else { 1239 } else {
1332 rawMap.put(dtuSn, new double[]{s0, s1, s2, s3, s4, 1}); 1240 rawMap.put(dtuSn, new double[]{s0, s1, s2, s3, s4, 1});
1333 } 1241 }
1334 - apiCount++;  
1335 } 1242 }
1336 } catch (Exception e) { 1243 } catch (Exception e) {
1337 log.error("获取今日稼动率数据异常 - dtuSn:{}", dtuSn, e); 1244 log.error("获取今日稼动率数据异常 - dtuSn:{}", dtuSn, e);
1338 } 1245 }
1339 } 1246 }
1340 - log.info("开机率查询 - 今日实时数据补充完成, 新增 {} 条", apiCount);  
1341 } 1247 }
1342 1248
1343 - /** 获取下一天的日期字符串 */  
1344 private static String getNextDay(String dateStr) { 1249 private static String getNextDay(String dateStr) {
1345 try { 1250 try {
1346 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); 1251 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
@@ -40,22 +40,10 @@ public class EnergyPullService { @@ -40,22 +40,10 @@ public class EnergyPullService {
40 40
41 @Value("${energy.token.url}") 41 @Value("${energy.token.url}")
42 private String energyTokenUrl; 42 private String energyTokenUrl;
43 - @Value("${energy.token.userName}")  
44 - private String energyUserName;  
45 - @Value("${energy.token.password}")  
46 - private String energyPassword;  
47 @Value("${energy.deviceList.url}") 43 @Value("${energy.deviceList.url}")
48 private String energyDeviceListUrl; 44 private String energyDeviceListUrl;
49 @Value("${energy.detail.url}") 45 @Value("${energy.detail.url}")
50 private String energyDetailUrl; 46 private String energyDetailUrl;
51 - @Value("${energy.db.corpCode}")  
52 - private String energyCorpCode;  
53 - @Value("${energy.db.tableName}")  
54 - private String energyTableName;  
55 - @Value("${energy.db.eqKwhTableName}")  
56 - private String eqKwhTableName;  
57 - @Value("${energy.db.eRunDtlTableName}")  
58 - private String eRunDtlTableName;  
59 @Value("${energy.runStatus.url}") 47 @Value("${energy.runStatus.url}")
60 private String energyRunStatusUrl; 48 private String energyRunStatusUrl;
61 49
@@ -63,21 +51,39 @@ public class EnergyPullService { @@ -63,21 +51,39 @@ public class EnergyPullService {
63 private RedisTemplate<String, String> redisTemplate; 51 private RedisTemplate<String, String> redisTemplate;
64 @Resource 52 @Resource
65 private JdbcTemplate jdbcTemplate; 53 private JdbcTemplate jdbcTemplate;
  54 + @Resource
  55 + private CorpConfigService corpConfigService;
66 56
67 /** 57 /**
68 - * 定时任务:同步能耗设备数据 58 + * 定时任务:同步能耗设备数据(遍历所有已配置公司)
69 */ 59 */
70 @Scheduled(cron = "${scheduler.energy.cron:0 0/5 * * ?}") 60 @Scheduled(cron = "${scheduler.energy.cron:0 0/5 * * ?}")
71 public void pullEnergyDeviceAndSave() { 61 public void pullEnergyDeviceAndSave() {
72 - log.info("【能耗数据同步】开始同步能耗设备数据"); 62 + List<String> corpCodes = corpConfigService.getAllCorpCodes();
  63 + if (corpCodes.isEmpty()) {
  64 + log.warn("[Scheduled] energy: no corp config found, skip");
  65 + return;
  66 + }
  67 + for (String corpCode : corpCodes) {
  68 + pullEnergyDeviceAndSave(corpCode);
  69 + }
  70 + }
  71 +
  72 + public void pullEnergyDeviceAndSave(String corpCode) {
  73 + if (!corpConfigService.hasValidIotCredentials(corpCode)) {
  74 + log.warn("【能耗数据同步】IoT凭证为空, 跳过同步, corpCode={}", corpCode);
  75 + return;
  76 + }
  77 + log.info("【能耗数据同步】开始同步能耗设备数据, corpCode={}", corpCode);
73 try { 78 try {
74 - String energyResult = getEnergyDeviceList(); 79 + String energyResult = getEnergyDeviceList(corpCode);
75 if (StringUtils.isBlank(energyResult)) { 80 if (StringUtils.isBlank(energyResult)) {
76 log.error("【能耗数据同步】获取能耗设备列表失败"); 81 log.error("【能耗数据同步】获取能耗设备列表失败");
77 return; 82 return;
78 } 83 }
79 84
80 - Map<String, Object> energyInfos = JSON.parseObject(energyResult, new TypeReference<>() {}); 85 + Map<String, Object> energyInfos = JSON.parseObject(energyResult, new TypeReference<>() {
  86 + });
81 Integer code = (Integer) energyInfos.get("code"); 87 Integer code = (Integer) energyInfos.get("code");
82 if (code == null || code != 200) { 88 if (code == null || code != 200) {
83 log.error("【能耗数据同步】获取能耗设备列表返回code不为200, code:{}, response:{}", code, energyResult); 89 log.error("【能耗数据同步】获取能耗设备列表返回code不为200, code:{}, response:{}", code, energyResult);
@@ -93,97 +99,72 @@ public class EnergyPullService { @@ -93,97 +99,72 @@ public class EnergyPullService {
93 int successCount = 0; 99 int successCount = 0;
94 for (Object o : dataList) { 100 for (Object o : dataList) {
95 JSONObject deviceJson = (JSONObject) o; 101 JSONObject deviceJson = (JSONObject) o;
96 -  
97 String projectState = deviceJson.getString("projectState"); 102 String projectState = deviceJson.getString("projectState");
98 String projectType = deviceJson.getString("projectType"); 103 String projectType = deviceJson.getString("projectType");
99 String deviceName = deviceJson.getString("deviceName"); 104 String deviceName = deviceJson.getString("deviceName");
100 String dtuId = deviceJson.getString("dtuId"); 105 String dtuId = deviceJson.getString("dtuId");
101 String deviceId = deviceJson.getString("deviceId"); 106 String deviceId = deviceJson.getString("deviceId");
102 String dtuSn = deviceJson.getString("dtuSn"); 107 String dtuSn = deviceJson.getString("dtuSn");
  108 + log.info("【能耗数据处理】corpCode:{}, deviceName:{}, dtuSn:{}, projectState:{}, projectType:{}",
  109 + corpCode, deviceName, dtuSn, projectState, projectType);
103 110
104 - log.info("【能耗数据处理】deviceName:{}, dtuSn:{}, projectState:{}, projectType:{}",  
105 - deviceName, dtuSn, projectState, projectType);  
106 -  
107 - // 获取今日用电量  
108 - String todayEvalue = getTodayEnergyValue(dtuSn);  
109 -  
110 - // 获取能耗OEE历史数据(最后一条的duration和runStatus)  
111 - Map<String, String> runStatusMap = getEnergyRunStatus(dtuSn); 111 + String todayEvalue = getTodayEnergyValue(corpCode, dtuSn);
  112 + Map<String, String> runStatusMap = getEnergyRunStatus(corpCode, dtuSn);
112 String duration = runStatusMap.get("duration"); 113 String duration = runStatusMap.get("duration");
113 String runStatus = runStatusMap.get("runStatus"); 114 String runStatus = runStatusMap.get("runStatus");
114 115
115 - saveOrUpdateEnergyDevice(projectState, projectType, deviceName, dtuId, deviceId, dtuSn, 116 + saveOrUpdateEnergyDevice(corpCode, projectState, projectType, deviceName, dtuId, deviceId, dtuSn,
116 todayEvalue, duration, runStatus); 117 todayEvalue, duration, runStatus);
117 successCount++; 118 successCount++;
118 } 119 }
119 -  
120 log.info("【能耗数据同步】同步完成,共处理 {} 条设备数据", successCount); 120 log.info("【能耗数据同步】同步完成,共处理 {} 条设备数据", successCount);
121 } catch (Exception e) { 121 } catch (Exception e) {
122 log.error("【能耗数据同步】同步过程发生异常", e); 122 log.error("【能耗数据同步】同步过程发生异常", e);
123 } 123 }
124 } 124 }
125 125
126 - /**  
127 - * 获取能耗设备列表  
128 - */  
129 - public String getEnergyDeviceList() {  
130 - String accessToken = getEnergyAccessToken(); 126 + public String getEnergyDeviceList(String corpCode) {
  127 + String accessToken = getEnergyAccessToken(corpCode);
131 Map<String, String> headerMap = new HashMap<>(1); 128 Map<String, String> headerMap = new HashMap<>(1);
132 headerMap.put("Authorization", "Bearer " + accessToken); 129 headerMap.put("Authorization", "Bearer " + accessToken);
133 -  
134 Map<String, String> paramsMap = new HashMap<>(); 130 Map<String, String> paramsMap = new HashMap<>();
135 - paramsMap.put("groupName", "SHC");  
136 -  
137 - // 第一次请求 131 + paramsMap.put("groupName", corpConfigService.getIotOrg(corpCode));
138 String result = sendRequestGet(energyDeviceListUrl, paramsMap, headerMap); 132 String result = sendRequestGet(energyDeviceListUrl, paramsMap, headerMap);
139 - if (StringUtils.isBlank(result)) {  
140 - return null;  
141 - } 133 + if (StringUtils.isBlank(result)) return null;
142 134
143 - Map<String, Object> resultMap = JSON.parseObject(result, new TypeReference<>() {}); 135 + Map<String, Object> resultMap = JSON.parseObject(result, new TypeReference<>() {
  136 + });
144 Integer resultCode = (Integer) resultMap.get("code"); 137 Integer resultCode = (Integer) resultMap.get("code");
145 138
146 - // Token失效,重试一次  
147 if (resultCode == null || resultCode != 200) { 139 if (resultCode == null || resultCode != 200) {
148 log.warn("【能耗设备列表】第一次请求失败,重新获取Token重试"); 140 log.warn("【能耗设备列表】第一次请求失败,重新获取Token重试");
149 - accessToken = getEnergyAccessToken();  
150 - if (StringUtils.isEmpty(accessToken)) {  
151 - return null;  
152 - } 141 + accessToken = getEnergyAccessToken(corpCode);
  142 + if (StringUtils.isEmpty(accessToken)) return null;
153 headerMap.put("Authorization", "Bearer " + accessToken); 143 headerMap.put("Authorization", "Bearer " + accessToken);
154 -  
155 result = sendRequestGet(energyDeviceListUrl, paramsMap, headerMap); 144 result = sendRequestGet(energyDeviceListUrl, paramsMap, headerMap);
156 - if (StringUtils.isBlank(result)) {  
157 - return null;  
158 - }  
159 -  
160 - resultMap = JSON.parseObject(result, new TypeReference<>() {}); 145 + if (StringUtils.isBlank(result)) return null;
  146 + resultMap = JSON.parseObject(result, new TypeReference<>() {
  147 + });
161 resultCode = (Integer) resultMap.get("code"); 148 resultCode = (Integer) resultMap.get("code");
162 if (resultCode == null || resultCode != 200) { 149 if (resultCode == null || resultCode != 200) {
163 log.error("【能耗设备列表】重试后仍然失败, code:{}", resultCode); 150 log.error("【能耗设备列表】重试后仍然失败, code:{}", resultCode);
164 return null; 151 return null;
165 } 152 }
166 } 153 }
167 -  
168 return result; 154 return result;
169 } 155 }
170 156
171 - /**  
172 - * 获取能耗Token  
173 - */  
174 - private String getEnergyAccessToken() {  
175 - String redisKey = "hnyssl_energy_token";  
176 -  
177 - // 检查Redis中是否有有效Token 157 + private String getEnergyAccessToken(String corpCode) {
  158 + String redisKey = "hnyssl_energy_token_" + corpCode;
178 String cachedToken = redisTemplate.opsForValue().get(redisKey); 159 String cachedToken = redisTemplate.opsForValue().get(redisKey);
179 - if (StringUtils.isNotBlank(cachedToken) && redisTemplate.getExpire(redisKey) > 0) {  
180 - return cachedToken;  
181 - } 160 + if (StringUtils.isNotBlank(cachedToken) && redisTemplate.getExpire(redisKey) > 0) return cachedToken;
182 161
183 - // 请求新Token 162 + // 使用公司配置中的用户名密码
  163 + String userName = corpConfigService.getIotUsername(corpCode);
  164 + String password = corpConfigService.getIotPassword(corpCode);
184 Map<String, String> param = new HashMap<>(2); 165 Map<String, String> param = new HashMap<>(2);
185 - param.put("username", energyUserName);  
186 - param.put("password", energyPassword); 166 + param.put("username", userName);
  167 + param.put("password", password);
187 168
188 HttpPost httpPost = new HttpPost(energyTokenUrl); 169 HttpPost httpPost = new HttpPost(energyTokenUrl);
189 String result = sendPost(httpPost, JSON.toJSONString(param)); 170 String result = sendPost(httpPost, JSON.toJSONString(param));
@@ -192,7 +173,8 @@ public class EnergyPullService { @@ -192,7 +173,8 @@ public class EnergyPullService {
192 return ""; 173 return "";
193 } 174 }
194 175
195 - Map<String, Object> res = JSON.parseObject(result, new TypeReference<>() {}); 176 + Map<String, Object> res = JSON.parseObject(result, new TypeReference<>() {
  177 + });
196 Integer code = (Integer) res.get("code"); 178 Integer code = (Integer) res.get("code");
197 if (code == null || code != 200) { 179 if (code == null || code != 200) {
198 log.error("【能耗Token】请求Token返回异常, code:{}", code); 180 log.error("【能耗Token】请求Token返回异常, code:{}", code);
@@ -206,118 +188,85 @@ public class EnergyPullService { @@ -206,118 +188,85 @@ public class EnergyPullService {
206 return ""; 188 return "";
207 } 189 }
208 190
209 - // 缓存Token,有效期1小时(Token实际有效期2小时)  
210 redisTemplate.opsForValue().set(redisKey, token, 3600, TimeUnit.SECONDS); 191 redisTemplate.opsForValue().set(redisKey, token, 3600, TimeUnit.SECONDS);
211 - log.info("【能耗Token】获取Token成功并缓存");  
212 - 192 + log.info("【能耗Token】获取Token成功并缓存, corpCode={}", corpCode);
213 return token; 193 return token;
214 } 194 }
215 195
216 - /**  
217 - * 保存或更新能耗设备数据(含用电量evalue、duration、runStatus)  
218 - */  
219 - private void saveOrUpdateEnergyDevice(String projectState, String projectType, String deviceName, 196 + private void saveOrUpdateEnergyDevice(String corpCode, String projectState, String projectType, String deviceName,
220 String dtuId, String deviceId, String dtuSn, 197 String dtuId, String deviceId, String dtuSn,
221 String evalue, String duration, String runStatus) { 198 String evalue, String duration, String runStatus) {
222 - // 查询是否已存在(按公司+dtuSn判断)  
223 - List<Map<String, Object>> existList = jdbcTemplate.queryForList(  
224 - "SELECT id FROM " + energyTableName + " WHERE corp_code = ? AND dtuSn = ?", energyCorpCode, dtuSn); 199 + String energyTableName = corpConfigService.getEnergyTableName(corpCode);
  200 + JdbcTemplate jt = corpConfigService.getJdbcTemplate(corpCode);
225 201
  202 + List<Map<String, Object>> existList = jt.queryForList(
  203 + "SELECT id FROM " + energyTableName + " WHERE corp_code = ? AND dtuSn = ?", corpCode, dtuSn);
226 Date now = new Date(); 204 Date now = new Date();
227 if (!existList.isEmpty()) { 205 if (!existList.isEmpty()) {
228 - // 更新  
229 - jdbcTemplate.update(  
230 - "UPDATE " + energyTableName +  
231 - " SET projectState = ?, projectType = ?, deviceName = ?, dtuId = ?, deviceId = ?, evalue = ?, duration = ?, runStatus = ?, updated_at = ?" +  
232 - " WHERE corp_code = ? AND dtuSn = ?",  
233 - projectState, projectType, deviceName, dtuId, deviceId, evalue, duration, runStatus, now, energyCorpCode, dtuSn);  
234 - log.debug("【能耗数据】更新成功 - dtuSn:{}, evalue:{}, runStatus:{}", dtuSn, evalue, runStatus); 206 + jt.update("UPDATE " + energyTableName +
  207 + " SET projectState = ?, projectType = ?, deviceName = ?, dtuId = ?, deviceId = ?, evalue = ?, duration = ?, runStatus = ?, updated_at = ?" +
  208 + " WHERE corp_code = ? AND dtuSn = ?",
  209 + projectState, projectType, deviceName, dtuId, deviceId, evalue, duration, runStatus, now, corpCode, dtuSn);
235 } else { 210 } else {
236 - // 新增  
237 String id = UUID.randomUUID().toString().replace("-", ""); 211 String id = UUID.randomUUID().toString().replace("-", "");
238 - jdbcTemplate.update(  
239 - "INSERT INTO " + energyTableName +  
240 - " (id, corp_code, created_at, created_by, updated_at, updated_by, deviceName, projectType, projectState, dtuSn, dtuId, deviceId, evalue, duration, runStatus)" +  
241 - " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",  
242 - id, energyCorpCode, now, "system", now, "system", 212 + jt.update("INSERT INTO " + energyTableName +
  213 + " (id, corp_code, created_at, created_by, updated_at, updated_by, deviceName, projectType, projectState, dtuSn, dtuId, deviceId, evalue, duration, runStatus)" +
  214 + " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
  215 + id, corpCode, now, "system", now, "system",
243 deviceName, projectType, projectState, dtuSn, dtuId, deviceId, evalue, duration, runStatus); 216 deviceName, projectType, projectState, dtuSn, dtuId, deviceId, evalue, duration, runStatus);
244 - log.debug("【能耗数据】新增成功 - dtuSn:{}, evalue:{}", dtuSn, evalue);  
245 } 217 }
246 } 218 }
247 219
248 - /**  
249 - * 获取能耗OEE历史数据  
250 - * 调用 /api/energy/runStatus?dtuSn=xxx&date=today  
251 - * @return Map包含 lastDuration(最后一条的duration)和 lastRunStatus(最后一条的runStatus),失败返回空Map  
252 - */  
253 - private Map<String, String> getEnergyRunStatus(String dtuSn) { 220 + private Map<String, String> getEnergyRunStatus(String corpCode, String dtuSn) {
254 Map<String, String> result = new HashMap<>(); 221 Map<String, String> result = new HashMap<>();
255 result.put("duration", null); 222 result.put("duration", null);
256 result.put("runStatus", null); 223 result.put("runStatus", null);
257 try { 224 try {
258 - String accessToken = getEnergyAccessToken(); 225 + String accessToken = getEnergyAccessToken(corpCode);
259 Map<String, String> headerMap = new HashMap<>(1); 226 Map<String, String> headerMap = new HashMap<>(1);
260 headerMap.put("Authorization", "Bearer " + accessToken); 227 headerMap.put("Authorization", "Bearer " + accessToken);
261 -  
262 Map<String, String> paramsMap = new HashMap<>(); 228 Map<String, String> paramsMap = new HashMap<>();
263 paramsMap.put("dtuSn", dtuSn); 229 paramsMap.put("dtuSn", dtuSn);
264 paramsMap.put("date", new SimpleDateFormat("yyyy-MM-dd").format(new Date())); 230 paramsMap.put("date", new SimpleDateFormat("yyyy-MM-dd").format(new Date()));
265 -  
266 String response = sendRequestGet(energyRunStatusUrl, paramsMap, headerMap); 231 String response = sendRequestGet(energyRunStatusUrl, paramsMap, headerMap);
267 - if (StringUtils.isBlank(response)) {  
268 - return result;  
269 - }  
270 -  
271 - Map<String, Object> resultMap = JSON.parseObject(response, new TypeReference<>() {}); 232 + if (StringUtils.isBlank(response)) return result;
  233 + Map<String, Object> resultMap = JSON.parseObject(response, new TypeReference<>() {
  234 + });
272 Integer resultCode = (Integer) resultMap.get("code"); 235 Integer resultCode = (Integer) resultMap.get("code");
273 if (resultCode == null || resultCode != 200) { 236 if (resultCode == null || resultCode != 200) {
274 - // Token失效重试  
275 - accessToken = getEnergyAccessToken();  
276 - if (StringUtils.isEmpty(accessToken)) {  
277 - return result;  
278 - } 237 + accessToken = getEnergyAccessToken(corpCode);
  238 + if (StringUtils.isEmpty(accessToken)) return result;
279 headerMap.put("Authorization", "Bearer " + accessToken); 239 headerMap.put("Authorization", "Bearer " + accessToken);
280 response = sendRequestGet(energyRunStatusUrl, paramsMap, headerMap); 240 response = sendRequestGet(energyRunStatusUrl, paramsMap, headerMap);
281 - if (StringUtils.isBlank(response)) {  
282 - return result;  
283 - }  
284 - resultMap = JSON.parseObject(response, new TypeReference<>() {}); 241 + if (StringUtils.isBlank(response)) return result;
  242 + resultMap = JSON.parseObject(response, new TypeReference<>() {
  243 + });
285 resultCode = (Integer) resultMap.get("code"); 244 resultCode = (Integer) resultMap.get("code");
286 - if (resultCode == null || resultCode != 200) {  
287 - return result;  
288 - } 245 + if (resultCode == null || resultCode != 200) return result;
289 } 246 }
290 -  
291 JSONArray dataList = (JSONArray) resultMap.get("data"); 247 JSONArray dataList = (JSONArray) resultMap.get("data");
292 - // 完整data保存到 t_auto_ymk_iot_e_run_dtl 表  
293 String description = dataList != null ? dataList.toJSONString() : "[]"; 248 String description = dataList != null ? dataList.toJSONString() : "[]";
294 - saveOrUpdateERunDtl(dtuSn, description, new SimpleDateFormat("yyyy-MM-dd 00:00:00").format(new Date())); 249 + saveOrUpdateERunDtl(corpCode, dtuSn, description, new SimpleDateFormat("yyyy-MM-dd 00:00:00").format(new Date()));
295 250
296 - // 取最后一条数据的 duration 和 runStatus  
297 if (!CollectionUtils.isEmpty(dataList)) { 251 if (!CollectionUtils.isEmpty(dataList)) {
298 JSONObject lastItem = (JSONObject) dataList.get(dataList.size() - 1); 252 JSONObject lastItem = (JSONObject) dataList.get(dataList.size() - 1);
299 Long durVal = lastItem.getLong("duration"); 253 Long durVal = lastItem.getLong("duration");
300 Integer statusVal = lastItem.getInteger("runStatus"); 254 Integer statusVal = lastItem.getInteger("runStatus");
301 result.put("duration", durVal != null ? String.valueOf(durVal) : null); 255 result.put("duration", durVal != null ? String.valueOf(durVal) : null);
302 result.put("runStatus", statusVal != null ? String.valueOf(statusVal) : null); 256 result.put("runStatus", statusVal != null ? String.valueOf(statusVal) : null);
303 - log.info("【能耗OEE】dtuSn:{}, 最后一条 - duration:{}, runStatus:{}",  
304 - dtuSn, result.get("duration"), result.get("runStatus"));  
305 } 257 }
306 } catch (Exception e) { 258 } catch (Exception e) {
307 - log.error("【能耗OEE】获取异常 - dtuSn:{}", dtuSn, e); 259 + log.error("【能耗OEE】获取异常 - corpCode:{}, dtuSn:{}", corpCode, dtuSn, e);
308 } 260 }
309 return result; 261 return result;
310 } 262 }
311 263
312 - /**  
313 - * 保存或更新能耗OEE运行状态明细到 t_auto_ymk_iot_e_run_dtl 表  
314 - * 超过60000字符拆分存入runStatus2  
315 - */  
316 - private void saveOrUpdateERunDtl(String dtuSn, String description, String useDate) { 264 + private void saveOrUpdateERunDtl(String corpCode, String dtuSn, String description, String useDate) {
  265 + String eRunDtlTableName = corpConfigService.getERunDtlTableName(corpCode);
  266 + JdbcTemplate jt = corpConfigService.getJdbcTemplate(corpCode);
317 int maxLen = 60000; 267 int maxLen = 60000;
318 String rs1 = ""; 268 String rs1 = "";
319 String rs2 = ""; 269 String rs2 = "";
320 -  
321 if (description.length() > maxLen) { 270 if (description.length() > maxLen) {
322 rs1 = description.substring(0, maxLen); 271 rs1 = description.substring(0, maxLen);
323 rs2 = description.substring(maxLen); 272 rs2 = description.substring(maxLen);
@@ -325,67 +274,44 @@ public class EnergyPullService { @@ -325,67 +274,44 @@ public class EnergyPullService {
325 rs1 = description; 274 rs1 = description;
326 } 275 }
327 276
328 - List<Map<String, Object>> existList = jdbcTemplate.queryForList(  
329 - "SELECT id FROM " + eRunDtlTableName + " WHERE corp_code = ? AND dtuSn = ? AND use_date = ?",  
330 - energyCorpCode, dtuSn, useDate);  
331 - 277 + List<Map<String, Object>> existList = jt.queryForList(
  278 + "SELECT id FROM " + eRunDtlTableName + " WHERE corp_code = ? AND dtuSn = ? AND use_date = ?", corpCode, dtuSn, useDate);
332 Date now = new Date(); 279 Date now = new Date();
333 if (!existList.isEmpty()) { 280 if (!existList.isEmpty()) {
334 - jdbcTemplate.update(  
335 - "UPDATE " + eRunDtlTableName + " SET runStatus1=?, runStatus2=?, updated_at=? WHERE corp_code=? AND dtuSn=? AND use_date=?",  
336 - rs1, rs2, now, energyCorpCode, dtuSn, useDate); 281 + jt.update("UPDATE " + eRunDtlTableName + " SET runStatus1=?, runStatus2=?, updated_at=? WHERE corp_code=? AND dtuSn=? AND use_date=?", rs1, rs2, now, corpCode, dtuSn, useDate);
337 } else { 282 } else {
338 String id = UUID.randomUUID().toString().replace("-", ""); 283 String id = UUID.randomUUID().toString().replace("-", "");
339 - jdbcTemplate.update(  
340 - "INSERT INTO " + eRunDtlTableName +  
341 - " (id,corp_code,created_at,created_by,updated_at,updated_by,dtuSn,use_date,runStatus1,runStatus2)" +  
342 - " VALUES (?,?,?,?,?,?,?,?,?,?)",  
343 - id, energyCorpCode, now, "system", now, "system", dtuSn, useDate, rs1, rs2); 284 + jt.update("INSERT INTO " + eRunDtlTableName + " (id,corp_code,created_at,created_by,updated_at,updated_by,dtuSn,use_date,runStatus1,runStatus2)" +
  285 + " VALUES (?,?,?,?,?,?,?,?,?,?)", id, corpCode, now, "system", now, "system", dtuSn, useDate, rs1, rs2);
344 } 286 }
345 } 287 }
346 288
347 // ==================== 能耗历史数据全量/增量同步 ==================== 289 // ==================== 能耗历史数据全量/增量同步 ====================
348 290
349 - /**  
350 - * 首次全量同步:本年1月1日 ~ 昨天(手动触发一次)  
351 - */  
352 - public void pullEnergyHistoryAndSave() { 291 + public void pullEnergyHistoryAndSave(String corpCode) {
  292 + if (!corpConfigService.hasValidIotCredentials(corpCode)) {
  293 + log.warn("【能耗历史-全量】IoT凭证为空, 跳过同步, corpCode={}", corpCode);
  294 + return;
  295 + }
353 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); 296 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
354 Calendar cal = Calendar.getInstance(); 297 Calendar cal = Calendar.getInstance();
355 - cal.add(Calendar.DAY_OF_MONTH, -1); // 昨天 298 + cal.add(Calendar.DAY_OF_MONTH, -1);
356 String endDate = sdf.format(cal.getTime()); 299 String endDate = sdf.format(cal.getTime());
357 cal.set(cal.get(Calendar.YEAR), Calendar.JANUARY, 1); 300 cal.set(cal.get(Calendar.YEAR), Calendar.JANUARY, 1);
358 String startDate = sdf.format(cal.getTime()); 301 String startDate = sdf.format(cal.getTime());
359 -  
360 - log.info("【能耗历史-全量】开始同步,日期范围: {} ~ {}", startDate, endDate);  
361 - doSyncEnergyHistory(startDate, endDate); 302 + log.info("【能耗历史-全量】开始同步, corpCode:{}, 日期范围: {} ~ {}", corpCode, startDate, endDate);
  303 + doSyncEnergyHistory(corpCode, startDate, endDate);
362 } 304 }
363 -//  
364 -// /**  
365 -// * 每日增量同步:仅同步昨天的数据(定时任务自动触发)  
366 -// */  
367 -// @Scheduled(cron = "${scheduler.energyHistory.cron:0 40 2 * * ?}")  
368 -// public void pullEnergyHistoryDaily() {  
369 -// SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");  
370 -// Calendar cal = Calendar.getInstance();  
371 -// cal.add(Calendar.DAY_OF_MONTH, -1);  
372 -// String yesterday = sdf.format(cal.getTime());  
373 -//  
374 -// log.info("【能耗历史-每日增量】同步,日期: {}", yesterday);  
375 -// doSyncEnergyHistory(yesterday, yesterday);  
376 -// }  
377 305
378 - /**  
379 - * 核心同步逻辑:获取能耗设备列表 → 每个设备每天调用用电量+OEE接口 → 写入 eq_kwh / e_run_dtl 表  
380 - */  
381 - private void doSyncEnergyHistory(String startDate, String endDate) {  
382 - String energyResult = getEnergyDeviceList(); 306 + private void doSyncEnergyHistory(String corpCode, String startDate, String endDate) {
  307 + String energyResult = getEnergyDeviceList(corpCode);
383 if (StringUtils.isBlank(energyResult)) { 308 if (StringUtils.isBlank(energyResult)) {
384 log.error("【能耗历史】获取设备列表失败"); 309 log.error("【能耗历史】获取设备列表失败");
385 return; 310 return;
386 } 311 }
387 312
388 - Map<String, Object> energyInfos = JSON.parseObject(energyResult, new TypeReference<>() {}); 313 + Map<String, Object> energyInfos = JSON.parseObject(energyResult, new TypeReference<>() {
  314 + });
389 Integer code = (Integer) energyInfos.get("code"); 315 Integer code = (Integer) energyInfos.get("code");
390 if (code == null || code != 200) { 316 if (code == null || code != 200) {
391 log.error("【能耗历史】获取设备列表返回code异常, code:{}", code); 317 log.error("【能耗历史】获取设备列表返回code异常, code:{}", code);
@@ -414,161 +340,109 @@ public class EnergyPullService { @@ -414,161 +340,109 @@ public class EnergyPullService {
414 return; 340 return;
415 } 341 }
416 342
417 - log.info("【能耗历史】开始同步,设备数:{}, 天数:{}, 总计 {} 条记录待处理",  
418 - deviceList.size(), dateList.size(), deviceList.size() * dateList.size());  
419 - 343 + log.info("【能耗历史】开始同步, corpCode:{}, 设备数:{}, 天数:{}, 总计{}条记录待处理", corpCode, deviceList.size(), dateList.size(), deviceList.size() * dateList.size());
420 int totalSaved = 0; 344 int totalSaved = 0;
421 for (Object o : deviceList) { 345 for (Object o : deviceList) {
422 JSONObject deviceJson = (JSONObject) o; 346 JSONObject deviceJson = (JSONObject) o;
423 String dtuSn = deviceJson.getString("dtuSn"); 347 String dtuSn = deviceJson.getString("dtuSn");
424 -  
425 for (String dateStr : dateList) { 348 for (String dateStr : dateList) {
426 try { 349 try {
427 - // 1. 同步当日用电量数据到 t_auto_ymk_iot_eq_kwh  
428 - syncEnergyValueForDate(dtuSn, dateStr);  
429 -  
430 - // 2. 同步当日OEE时序数据到 t_auto_ymk_iot_e_run_dtl  
431 - syncRunStatusForDate(dtuSn, dateStr);  
432 - 350 + syncEnergyValueForDate(corpCode, dtuSn, dateStr);
  351 + syncRunStatusForDate(corpCode, dtuSn, dateStr);
433 totalSaved++; 352 totalSaved++;
434 } catch (Exception e) { 353 } catch (Exception e) {
435 - log.error("【能耗历史】处理异常 - dtuSn:{}, date:{}", dtuSn, dateStr, e); 354 + log.error("【能耗历史】处理异常 - corpCode:{}, dtuSn:{}, date:{}", corpCode, dtuSn, dateStr, e);
436 } 355 }
437 } 356 }
438 } 357 }
439 -  
440 log.info("【能耗历史】同步完成,共保存 {} 条记录", totalSaved); 358 log.info("【能耗历史】同步完成,共保存 {} 条记录", totalSaved);
441 } 359 }
442 360
443 - /**  
444 - * 同步指定日期的设备用电量数据到 t_auto_ymk_iot_eq_kwh 表  
445 - */  
446 - private void syncEnergyValueForDate(String dtuSn, String dateStr) {  
447 - String accessToken = getEnergyAccessToken(); 361 + private void syncEnergyValueForDate(String corpCode, String dtuSn, String dateStr) {
  362 + String accessToken = getEnergyAccessToken(corpCode);
448 Map<String, String> headerMap = new HashMap<>(1); 363 Map<String, String> headerMap = new HashMap<>(1);
449 headerMap.put("Authorization", "Bearer " + accessToken); 364 headerMap.put("Authorization", "Bearer " + accessToken);
450 -  
451 Map<String, String> paramsMap = new HashMap<>(); 365 Map<String, String> paramsMap = new HashMap<>();
452 paramsMap.put("dtuSn", dtuSn); 366 paramsMap.put("dtuSn", dtuSn);
453 paramsMap.put("startDate", dateStr); 367 paramsMap.put("startDate", dateStr);
454 paramsMap.put("type", "0"); 368 paramsMap.put("type", "0");
455 -  
456 String result = sendRequestGet(energyDetailUrl, paramsMap, headerMap); 369 String result = sendRequestGet(energyDetailUrl, paramsMap, headerMap);
457 - if (StringUtils.isBlank(result)) {  
458 - return;  
459 - }  
460 -  
461 - Map<String, Object> resultMap = JSON.parseObject(result, new TypeReference<>() {}); 370 + if (StringUtils.isBlank(result)) return;
  371 + Map<String, Object> resultMap = JSON.parseObject(result, new TypeReference<>() {
  372 + });
462 Integer resultCode = (Integer) resultMap.get("code"); 373 Integer resultCode = (Integer) resultMap.get("code");
463 if (resultCode == null || resultCode != 200) { 374 if (resultCode == null || resultCode != 200) {
464 - accessToken = getEnergyAccessToken();  
465 - if (StringUtils.isEmpty(accessToken)) {  
466 - return;  
467 - } 375 + accessToken = getEnergyAccessToken(corpCode);
  376 + if (StringUtils.isEmpty(accessToken)) return;
468 headerMap.put("Authorization", "Bearer " + accessToken); 377 headerMap.put("Authorization", "Bearer " + accessToken);
469 result = sendRequestGet(energyDetailUrl, paramsMap, headerMap); 378 result = sendRequestGet(energyDetailUrl, paramsMap, headerMap);
470 - if (StringUtils.isBlank(result)) {  
471 - return;  
472 - }  
473 - resultMap = JSON.parseObject(result, new TypeReference<>() {}); 379 + if (StringUtils.isBlank(result)) return;
  380 + resultMap = JSON.parseObject(result, new TypeReference<>() {
  381 + });
474 resultCode = (Integer) resultMap.get("code"); 382 resultCode = (Integer) resultMap.get("code");
475 - if (resultCode == null || resultCode != 200) {  
476 - return;  
477 - } 383 + if (resultCode == null || resultCode != 200) return;
478 } 384 }
479 -  
480 JSONArray dataList = (JSONArray) resultMap.get("data"); 385 JSONArray dataList = (JSONArray) resultMap.get("data");
481 String description = dataList != null ? dataList.toJSONString() : "[]"; 386 String description = dataList != null ? dataList.toJSONString() : "[]";
482 - saveOrUpdateEqKwh(dtuSn, description, dateStr + " 00:00:00"); 387 + saveOrUpdateEqKwh(corpCode, dtuSn, description, dateStr + " 00:00:00");
483 } 388 }
484 389
485 - /**  
486 - * 同步指定日期的设备OEE时序数据到 t_auto_ymk_iot_e_run_dtl 表  
487 - */  
488 - private void syncRunStatusForDate(String dtuSn, String dateStr) {  
489 - String accessToken = getEnergyAccessToken(); 390 + private void syncRunStatusForDate(String corpCode, String dtuSn, String dateStr) {
  391 + String accessToken = getEnergyAccessToken(corpCode);
490 Map<String, String> headerMap = new HashMap<>(1); 392 Map<String, String> headerMap = new HashMap<>(1);
491 headerMap.put("Authorization", "Bearer " + accessToken); 393 headerMap.put("Authorization", "Bearer " + accessToken);
492 -  
493 Map<String, String> paramsMap = new HashMap<>(); 394 Map<String, String> paramsMap = new HashMap<>();
494 paramsMap.put("dtuSn", dtuSn); 395 paramsMap.put("dtuSn", dtuSn);
495 paramsMap.put("date", dateStr); 396 paramsMap.put("date", dateStr);
496 -  
497 String response = sendRequestGet(energyRunStatusUrl, paramsMap, headerMap); 397 String response = sendRequestGet(energyRunStatusUrl, paramsMap, headerMap);
498 - if (StringUtils.isBlank(response)) {  
499 - return;  
500 - }  
501 -  
502 - Map<String, Object> resultMap = JSON.parseObject(response, new TypeReference<>() {}); 398 + if (StringUtils.isBlank(response)) return;
  399 + Map<String, Object> resultMap = JSON.parseObject(response, new TypeReference<>() {
  400 + });
503 Integer resultCode = (Integer) resultMap.get("code"); 401 Integer resultCode = (Integer) resultMap.get("code");
504 if (resultCode == null || resultCode != 200) { 402 if (resultCode == null || resultCode != 200) {
505 - accessToken = getEnergyAccessToken();  
506 - if (StringUtils.isEmpty(accessToken)) {  
507 - return;  
508 - } 403 + accessToken = getEnergyAccessToken(corpCode);
  404 + if (StringUtils.isEmpty(accessToken)) return;
509 headerMap.put("Authorization", "Bearer " + accessToken); 405 headerMap.put("Authorization", "Bearer " + accessToken);
510 response = sendRequestGet(energyRunStatusUrl, paramsMap, headerMap); 406 response = sendRequestGet(energyRunStatusUrl, paramsMap, headerMap);
511 - if (StringUtils.isBlank(response)) {  
512 - return;  
513 - }  
514 - resultMap = JSON.parseObject(response, new TypeReference<>() {}); 407 + if (StringUtils.isBlank(response)) return;
  408 + resultMap = JSON.parseObject(response, new TypeReference<>() {
  409 + });
515 resultCode = (Integer) resultMap.get("code"); 410 resultCode = (Integer) resultMap.get("code");
516 - if (resultCode == null || resultCode != 200) {  
517 - return;  
518 - } 411 + if (resultCode == null || resultCode != 200) return;
519 } 412 }
520 -  
521 JSONArray dataList = (JSONArray) resultMap.get("data"); 413 JSONArray dataList = (JSONArray) resultMap.get("data");
522 String description = dataList != null ? dataList.toJSONString() : "[]"; 414 String description = dataList != null ? dataList.toJSONString() : "[]";
523 - saveOrUpdateERunDtl(dtuSn, description, dateStr + " 00:00:00"); 415 + saveOrUpdateERunDtl(corpCode, dtuSn, description, dateStr + " 00:00:00");
524 } 416 }
525 417
526 - /**  
527 - * 获取今日设备用电量 (type=0 按小时查询)  
528 - * 同时将完整响应data保存到 t_auto_ymk_iot_eq_kwh 表  
529 - * @return 今日用电量value,失败返回null  
530 - */  
531 - private String getTodayEnergyValue(String dtuSn) { 418 + private String getTodayEnergyValue(String corpCode, String dtuSn) {
532 try { 419 try {
533 - String accessToken = getEnergyAccessToken(); 420 + String accessToken = getEnergyAccessToken(corpCode);
534 Map<String, String> headerMap = new HashMap<>(1); 421 Map<String, String> headerMap = new HashMap<>(1);
535 headerMap.put("Authorization", "Bearer " + accessToken); 422 headerMap.put("Authorization", "Bearer " + accessToken);
536 -  
537 Map<String, String> paramsMap = new HashMap<>(); 423 Map<String, String> paramsMap = new HashMap<>();
538 paramsMap.put("dtuSn", dtuSn); 424 paramsMap.put("dtuSn", dtuSn);
539 paramsMap.put("startDate", new SimpleDateFormat("yyyy-MM-dd").format(new Date())); 425 paramsMap.put("startDate", new SimpleDateFormat("yyyy-MM-dd").format(new Date()));
540 paramsMap.put("type", "0"); 426 paramsMap.put("type", "0");
541 -  
542 String result = sendRequestGet(energyDetailUrl, paramsMap, headerMap); 427 String result = sendRequestGet(energyDetailUrl, paramsMap, headerMap);
543 - if (StringUtils.isBlank(result)) {  
544 - return null;  
545 - }  
546 -  
547 - Map<String, Object> resultMap = JSON.parseObject(result, new TypeReference<>() {}); 428 + if (StringUtils.isBlank(result)) return null;
  429 + Map<String, Object> resultMap = JSON.parseObject(result, new TypeReference<>() {
  430 + });
548 Integer resultCode = (Integer) resultMap.get("code"); 431 Integer resultCode = (Integer) resultMap.get("code");
549 if (resultCode == null || resultCode != 200) { 432 if (resultCode == null || resultCode != 200) {
550 - accessToken = getEnergyAccessToken();  
551 - if (StringUtils.isEmpty(accessToken)) {  
552 - return null;  
553 - } 433 + accessToken = getEnergyAccessToken(corpCode);
  434 + if (StringUtils.isEmpty(accessToken)) return null;
554 headerMap.put("Authorization", "Bearer " + accessToken); 435 headerMap.put("Authorization", "Bearer " + accessToken);
555 result = sendRequestGet(energyDetailUrl, paramsMap, headerMap); 436 result = sendRequestGet(energyDetailUrl, paramsMap, headerMap);
556 - if (StringUtils.isBlank(result)) {  
557 - return null;  
558 - }  
559 - resultMap = JSON.parseObject(result, new TypeReference<>() {}); 437 + if (StringUtils.isBlank(result)) return null;
  438 + resultMap = JSON.parseObject(result, new TypeReference<>() {
  439 + });
560 resultCode = (Integer) resultMap.get("code"); 440 resultCode = (Integer) resultMap.get("code");
561 - if (resultCode == null || resultCode != 200) {  
562 - return null;  
563 - } 441 + if (resultCode == null || resultCode != 200) return null;
564 } 442 }
565 -  
566 JSONArray dataList = (JSONArray) resultMap.get("data"); 443 JSONArray dataList = (JSONArray) resultMap.get("data");
567 - // 将完整data保存到eq_kwh表  
568 String description = dataList != null ? dataList.toJSONString() : "[]"; 444 String description = dataList != null ? dataList.toJSONString() : "[]";
569 - saveOrUpdateEqKwh(dtuSn, description, new SimpleDateFormat("yyyy-MM-dd 00:00:00").format(new Date()));  
570 -  
571 - // 累加所有小时的value作为今日总用电量 445 + saveOrUpdateEqKwh(corpCode, dtuSn, description, new SimpleDateFormat("yyyy-MM-dd 00:00:00").format(new Date()));
572 double totalValue = 0; 446 double totalValue = 0;
573 if (!CollectionUtils.isEmpty(dataList)) { 447 if (!CollectionUtils.isEmpty(dataList)) {
574 for (Object o : dataList) { 448 for (Object o : dataList) {
@@ -576,82 +450,58 @@ public class EnergyPullService { @@ -576,82 +450,58 @@ public class EnergyPullService {
576 totalValue += item.getDoubleValue("value"); 450 totalValue += item.getDoubleValue("value");
577 } 451 }
578 } 452 }
579 -  
580 String evalueStr = String.valueOf(totalValue); 453 String evalueStr = String.valueOf(totalValue);
581 - log.info("【能耗用电量】dtuSn:{}, 今日用电量:{}", dtuSn, evalueStr); 454 + log.info("【能耗用电量】corpCode:{}, dtuSn:{}, 今日用电量:{}", corpCode, dtuSn, evalueStr);
582 return evalueStr; 455 return evalueStr;
583 -  
584 } catch (Exception e) { 456 } catch (Exception e) {
585 - log.error("【能耗用电量】获取异常 - dtuSn:{}", dtuSn, e); 457 + log.error("【能耗用电量】获取异常 - corpCode:{}, dtuSn:{}", corpCode, dtuSn, e);
586 return null; 458 return null;
587 } 459 }
588 } 460 }
589 461
590 - /**  
591 - * 保存或更新用电量数据到 t_auto_ymk_iot_eq_kwh 表  
592 - */  
593 - private void saveOrUpdateEqKwh(String dtuSn, String description, String useDate) {  
594 - List<Map<String, Object>> existList = jdbcTemplate.queryForList(  
595 - "SELECT id FROM " + eqKwhTableName + " WHERE corp_code = ? AND dtuSn = ? AND use_date = ?",  
596 - energyCorpCode, dtuSn, useDate);  
597 - 462 + private void saveOrUpdateEqKwh(String corpCode, String dtuSn, String description, String useDate) {
  463 + String eqKwhTableName = corpConfigService.getEqKwhTableName(corpCode);
  464 + JdbcTemplate jt = corpConfigService.getJdbcTemplate(corpCode);
  465 + List<Map<String, Object>> existList = jt.queryForList(
  466 + "SELECT id FROM " + eqKwhTableName + " WHERE corp_code = ? AND dtuSn = ? AND use_date = ?", corpCode, dtuSn, useDate);
598 Date now = new Date(); 467 Date now = new Date();
599 if (!existList.isEmpty()) { 468 if (!existList.isEmpty()) {
600 - jdbcTemplate.update(  
601 - "UPDATE " + eqKwhTableName + " SET description = ?, updated_at = ? WHERE corp_code = ? AND dtuSn = ? AND use_date = ?",  
602 - description, now, energyCorpCode, dtuSn, useDate); 469 + jt.update("UPDATE " + eqKwhTableName + " SET description = ?, updated_at = ? WHERE corp_code = ? AND dtuSn = ? AND use_date = ?", description, now, corpCode, dtuSn, useDate);
603 } else { 470 } else {
604 String id = UUID.randomUUID().toString().replace("-", ""); 471 String id = UUID.randomUUID().toString().replace("-", "");
605 - jdbcTemplate.update(  
606 - "INSERT INTO " + eqKwhTableName +  
607 - " (id, corp_code, created_at, created_by, updated_at, updated_by, dtuSn, use_date, description)" +  
608 - " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)",  
609 - id, energyCorpCode, now, "system", now, "system", dtuSn, useDate, description); 472 + jt.update("INSERT INTO " + eqKwhTableName + " (id, corp_code, created_at, created_by, updated_at, updated_by, dtuSn, use_date, description)" +
  473 + " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)", id, corpCode, now, "system", now, "system", dtuSn, useDate, description);
610 } 474 }
611 } 475 }
612 476
613 - /**  
614 - * 发送GET请求  
615 - */  
616 public static String sendRequestGet(String url, Map<String, String> params, Map<String, String> header) { 477 public static String sendRequestGet(String url, Map<String, String> params, Map<String, String> header) {
617 CloseableHttpClient httpclient = HttpClients.createDefault(); 478 CloseableHttpClient httpclient = HttpClients.createDefault();
618 url = builderUrl(url, params); 479 url = builderUrl(url, params);
619 String content = ""; 480 String content = "";
620 HttpGet httpget = new HttpGet(url); 481 HttpGet httpget = new HttpGet(url);
621 if (!CollectionUtils.isEmpty(header)) { 482 if (!CollectionUtils.isEmpty(header)) {
622 - for (Map.Entry<String, String> entry : header.entrySet()) { 483 + for (Map.Entry<String, String> entry : header.entrySet())
623 httpget.setHeader(entry.getKey(), entry.getValue()); 484 httpget.setHeader(entry.getKey(), entry.getValue());
624 - }  
625 } 485 }
626 -  
627 try (CloseableHttpResponse response = httpclient.execute(httpget)) { 486 try (CloseableHttpResponse response = httpclient.execute(httpget)) {
628 - if (response.getStatusLine().getStatusCode() == 200) { 487 + if (response.getStatusLine().getStatusCode() == 200)
629 content = EntityUtils.toString(response.getEntity(), "UTF-8"); 488 content = EntityUtils.toString(response.getEntity(), "UTF-8");
630 - }  
631 } catch (IOException e) { 489 } catch (IOException e) {
632 log.error("sendRequest---GET Error!", e); 490 log.error("sendRequest---GET Error!", e);
633 } 491 }
634 return content; 492 return content;
635 } 493 }
636 494
637 - /**  
638 - * 构建带参数的URL  
639 - */  
640 private static String builderUrl(String url, Map<String, String> params) { 495 private static String builderUrl(String url, Map<String, String> params) {
641 UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromHttpUrl(url); 496 UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromHttpUrl(url);
642 if (!CollectionUtils.isEmpty(params)) { 497 if (!CollectionUtils.isEmpty(params)) {
643 MultiValueMap<String, String> paramsValue = new LinkedMultiValueMap<>(); 498 MultiValueMap<String, String> paramsValue = new LinkedMultiValueMap<>();
644 - for (Map.Entry<String, String> entry : params.entrySet()) {  
645 - paramsValue.add(entry.getKey(), entry.getValue());  
646 - } 499 + for (Map.Entry<String, String> entry : params.entrySet()) paramsValue.add(entry.getKey(), entry.getValue());
647 uriBuilder = uriBuilder.queryParams(paramsValue); 500 uriBuilder = uriBuilder.queryParams(paramsValue);
648 } 501 }
649 return uriBuilder.toUriString(); 502 return uriBuilder.toUriString();
650 } 503 }
651 504
652 - /**  
653 - * 发送POST请求  
654 - */  
655 private String sendPost(HttpPost httpPost, String jsonData) { 505 private String sendPost(HttpPost httpPost, String jsonData) {
656 CloseableHttpClient httpClient = HttpClients.createDefault(); 506 CloseableHttpClient httpClient = HttpClients.createDefault();
657 StringEntity entity = new StringEntity(jsonData, ContentType.create("application/json", Consts.UTF_8)); 507 StringEntity entity = new StringEntity(jsonData, ContentType.create("application/json", Consts.UTF_8));
@@ -664,9 +514,7 @@ public class EnergyPullService { @@ -664,9 +514,7 @@ public class EnergyPullService {
664 int len; 514 int len;
665 byte[] buf = new byte[128]; 515 byte[] buf = new byte[128];
666 ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); 516 ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
667 - while ((len = is.read(buf)) != -1) {  
668 - byteArrayOutputStream.write(buf, 0, len);  
669 - } 517 + while ((len = is.read(buf)) != -1) byteArrayOutputStream.write(buf, 0, len);
670 result = byteArrayOutputStream.toString(); 518 result = byteArrayOutputStream.toString();
671 } catch (IOException e) { 519 } catch (IOException e) {
672 log.error("sendPost error!", e); 520 log.error("sendPost error!", e);
@@ -4,7 +4,6 @@ import com.alibaba.fastjson.JSON; @@ -4,7 +4,6 @@ import com.alibaba.fastjson.JSON;
4 import com.alibaba.fastjson.JSONArray; 4 import com.alibaba.fastjson.JSONArray;
5 import com.alibaba.fastjson.JSONObject; 5 import com.alibaba.fastjson.JSONObject;
6 import lombok.extern.slf4j.Slf4j; 6 import lombok.extern.slf4j.Slf4j;
7 -import org.springframework.beans.factory.annotation.Value;  
8 import org.springframework.jdbc.core.JdbcTemplate; 7 import org.springframework.jdbc.core.JdbcTemplate;
9 import org.springframework.stereotype.Service; 8 import org.springframework.stereotype.Service;
10 import org.springframework.util.StringUtils; 9 import org.springframework.util.StringUtils;
@@ -20,59 +19,45 @@ import java.util.*; @@ -20,59 +19,45 @@ import java.util.*;
20 @Service 19 @Service
21 public class EnergySearchService { 20 public class EnergySearchService {
22 21
23 - @Value("${energy.db.corpCode}")  
24 - private String energyCorpCode;  
25 - @Value("${energy.db.tableName}")  
26 - private String energyTableName;  
27 - @Value("${energy.db.eqKwhTableName}")  
28 - private String eqKwhTableName;  
29 - @Value("${energy.db.eRunDtlTableName}")  
30 - private String eRunDtlTableName;  
31 -  
32 @Resource 22 @Resource
33 private JdbcTemplate jdbcTemplate; 23 private JdbcTemplate jdbcTemplate;
  24 + @Resource
  25 + private CorpConfigService corpConfigService;
34 26
35 /** 27 /**
36 * 分页查询能耗设备信息 28 * 分页查询能耗设备信息
37 - * 查询表 t_auto_ymk_iot_energy,按设备名称排序  
38 - *  
39 - * @param deviceName 设备名称(模糊匹配)  
40 - * @param runStatus 状态(0:离线,1:停机,2:待机,3:运行)  
41 - * @param pageNo 页码,默认1  
42 - * @param pageSize 每页条数,默认10  
43 */ 29 */
44 - public Map<String, Object> queryEnergyList(String deviceName, String runStatus, 30 + public Map<String, Object> queryEnergyList(String corpCode, String deviceName, String runStatus,
45 Integer pageNo, Integer pageSize) { 31 Integer pageNo, Integer pageSize) {
  32 + String energyTableName = corpConfigService.getEnergyTableName(corpCode);
  33 + JdbcTemplate jt = corpConfigService.getJdbcTemplate(corpCode);
  34 +
46 StringBuilder countSql = new StringBuilder("SELECT COUNT(*) FROM " + energyTableName + " WHERE corp_code = ?"); 35 StringBuilder countSql = new StringBuilder("SELECT COUNT(*) FROM " + energyTableName + " WHERE corp_code = ?");
47 StringBuilder querySql = new StringBuilder( 36 StringBuilder querySql = new StringBuilder(
48 "SELECT id, deviceName, projectType, projectState, dtuSn, dtuId, deviceId, " + 37 "SELECT id, deviceName, projectType, projectState, dtuSn, dtuId, deviceId, " +
49 "evalue, duration, runStatus, created_at, updated_at " + 38 "evalue, duration, runStatus, created_at, updated_at " +
50 "FROM " + energyTableName + " WHERE corp_code = ?"); 39 "FROM " + energyTableName + " WHERE corp_code = ?");
51 List<Object> params = new ArrayList<>(); 40 List<Object> params = new ArrayList<>();
52 - params.add(energyCorpCode); 41 + params.add(corpCode);
53 42
54 - // 设备名称模糊查询  
55 if (StringUtils.hasText(deviceName)) { 43 if (StringUtils.hasText(deviceName)) {
56 countSql.append(" AND deviceName LIKE ?"); 44 countSql.append(" AND deviceName LIKE ?");
57 querySql.append(" AND deviceName LIKE ?"); 45 querySql.append(" AND deviceName LIKE ?");
58 params.add("%" + deviceName + "%"); 46 params.add("%" + deviceName + "%");
59 } 47 }
60 -  
61 - // 设备状态精确匹配  
62 if (StringUtils.hasText(runStatus)) { 48 if (StringUtils.hasText(runStatus)) {
63 countSql.append(" AND runStatus = ?"); 49 countSql.append(" AND runStatus = ?");
64 querySql.append(" AND runStatus = ?"); 50 querySql.append(" AND runStatus = ?");
65 params.add(runStatus); 51 params.add(runStatus);
66 } 52 }
67 53
68 - Long total = jdbcTemplate.queryForObject(countSql.toString(), Long.class, params.toArray()); 54 + Long total = jt.queryForObject(countSql.toString(), Long.class, params.toArray());
69 int offset = (pageNo - 1) * pageSize; 55 int offset = (pageNo - 1) * pageSize;
70 -  
71 querySql.append(" ORDER BY deviceName ASC LIMIT ?, ?"); 56 querySql.append(" ORDER BY deviceName ASC LIMIT ?, ?");
72 params.add(offset); 57 params.add(offset);
73 params.add(pageSize); 58 params.add(pageSize);
74 59
75 - List<Map<String, Object>> list = jdbcTemplate.queryForList(querySql.toString(), params.toArray()); 60 + List<Map<String, Object>> list = jt.queryForList(querySql.toString(), params.toArray());
76 list.forEach(row -> { 61 list.forEach(row -> {
77 if (row.get("duration") != null) { 62 if (row.get("duration") != null) {
78 long seconds = Long.parseLong(String.valueOf(row.get("duration"))); 63 long seconds = Long.parseLong(String.valueOf(row.get("duration")));
@@ -86,111 +71,75 @@ public class EnergySearchService { @@ -86,111 +71,75 @@ public class EnergySearchService {
86 row.put("duration", sb.toString()); 71 row.put("duration", sb.toString());
87 } 72 }
88 }); 73 });
89 -  
90 - return Map.of(  
91 - "code", 200,  
92 - "msg", "请求成功",  
93 - "total", total != null ? total : 0,  
94 - "pageNo", pageNo,  
95 - "pageSize", pageSize,  
96 - "list", list  
97 - ); 74 + return Map.of("code", 200, "msg", "请求成功", "total", total != null ? total : 0, "pageNo", pageNo,
  75 + "pageSize", pageSize, "list", list);
98 } 76 }
99 77
100 - /**  
101 - * 统计能耗设备各runStatus数量及总数量  
102 - * runStatus: 0-离线, 1-停机, 2-待机, 3-运行  
103 - */  
104 - public Map<String, Object> queryEnergyStats() {  
105 - String sql = "SELECT runStatus, COUNT(*) AS cnt FROM " + energyTableName  
106 - + " WHERE corp_code = ? GROUP BY runStatus";  
107 - List<Map<String, Object>> rows = jdbcTemplate.queryForList(sql, energyCorpCode);  
108 - 78 + public Map<String, Object> queryEnergyStats(String corpCode) {
  79 + String energyTableName = corpConfigService.getEnergyTableName(corpCode);
  80 + JdbcTemplate jt = corpConfigService.getJdbcTemplate(corpCode);
  81 + String sql = "SELECT runStatus, COUNT(*) AS cnt FROM " + energyTableName + " WHERE corp_code = ? GROUP BY runStatus";
  82 + List<Map<String, Object>> rows = jt.queryForList(sql, corpCode);
109 int total = 0; 83 int total = 0;
110 Map<String, Integer> statusMap = new LinkedHashMap<>(); 84 Map<String, Integer> statusMap = new LinkedHashMap<>();
111 statusMap.put("0", 0); 85 statusMap.put("0", 0);
112 statusMap.put("1", 0); 86 statusMap.put("1", 0);
113 statusMap.put("2", 0); 87 statusMap.put("2", 0);
114 statusMap.put("3", 0); 88 statusMap.put("3", 0);
115 -  
116 for (Map<String, Object> row : rows) { 89 for (Map<String, Object> row : rows) {
117 String key = String.valueOf(row.get("runStatus")); 90 String key = String.valueOf(row.get("runStatus"));
118 int cnt = ((Number) row.get("cnt")).intValue(); 91 int cnt = ((Number) row.get("cnt")).intValue();
119 total += cnt; 92 total += cnt;
120 statusMap.merge(key, cnt, Integer::sum); 93 statusMap.merge(key, cnt, Integer::sum);
121 } 94 }
122 -  
123 - return Map.of(  
124 - "code", 200,  
125 - "msg", "请求成功",  
126 - "total", total,  
127 - "0", statusMap.get("0"),  
128 - "1", statusMap.get("1"),  
129 - "2", statusMap.get("2"),  
130 - "3", statusMap.get("3")  
131 - ); 95 + return Map.of("code", 200, "msg", "请求成功", "total", total, "0", statusMap.get("0"),
  96 + "1", statusMap.get("1"), "2", statusMap.get("2"), "3", statusMap.get("3"));
132 } 97 }
133 98
134 - /**  
135 - * 根据dtuSn查询指定日期的设备时用电量和OEE时序  
136 - * 1. 时用电量:从t_auto_ymk_iot_eq_kwh表获取,并计算当日总用电量  
137 - * 2. OEE时序:从t_auto_ymk_iot_e_run_dtl表获取,统计总时长、各状态运行时长和占比  
138 - *  
139 - * @param dtuSn 设备序列号  
140 - * @param date 查询日期 yyyy-MM-dd  
141 - */  
142 - public Map<String, Object> queryEnergyDetailByDate(String dtuSn, String date) {  
143 - // 1. 查询时用电量数据 - 原始数据直接返回 99 + public Map<String, Object> queryEnergyDetailByDate(String corpCode, String dtuSn, String date) {
  100 + String eqKwhTableName = corpConfigService.getEqKwhTableName(corpCode);
  101 + String eRunDtlTableName = corpConfigService.getERunDtlTableName(corpCode);
  102 + JdbcTemplate jt = corpConfigService.getJdbcTemplate(corpCode);
  103 +
144 Object kwhRawData = Collections.emptyList(); 104 Object kwhRawData = Collections.emptyList();
145 BigDecimal totalKwh = BigDecimal.ZERO; 105 BigDecimal totalKwh = BigDecimal.ZERO;
146 try { 106 try {
147 - String kwhSql = "SELECT description FROM " + eqKwhTableName  
148 - + " WHERE corp_code = ? AND dtuSn = ? AND use_date = ?";  
149 - Map<String, Object> kwhRow = jdbcTemplate.queryForMap(kwhSql, energyCorpCode, dtuSn, date + " 00:00:00"); 107 + String kwhSql = "SELECT description FROM " + eqKwhTableName + " WHERE corp_code = ? AND dtuSn = ? AND use_date = ?";
  108 + Map<String, Object> kwhRow = jt.queryForMap(kwhSql, corpCode, dtuSn, date + " 00:00:00");
150 if (kwhRow != null && kwhRow.get("description") != null) { 109 if (kwhRow != null && kwhRow.get("description") != null) {
151 String description = String.valueOf(kwhRow.get("description")); 110 String description = String.valueOf(kwhRow.get("description"));
152 kwhRawData = JSON.parseArray(description); 111 kwhRawData = JSON.parseArray(description);
153 - // 计算总用电量  
154 JSONArray dataArray = JSON.parseArray(description); 112 JSONArray dataArray = JSON.parseArray(description);
155 for (int i = 0; i < dataArray.size(); i++) { 113 for (int i = 0; i < dataArray.size(); i++) {
156 JSONObject item = dataArray.getJSONObject(i); 114 JSONObject item = dataArray.getJSONObject(i);
157 Double value = item.getDouble("value"); 115 Double value = item.getDouble("value");
158 - if (value != null) {  
159 - totalKwh = totalKwh.add(BigDecimal.valueOf(value));  
160 - } 116 + if (value != null) totalKwh = totalKwh.add(BigDecimal.valueOf(value));
161 } 117 }
162 } 118 }
163 } catch (Exception e) { 119 } catch (Exception e) {
164 - log.warn("【能耗明细】查询时用电量数据为空或异常 - dtuSn:{}, date:{}", dtuSn, date); 120 + log.warn("【能耗明细】查询时用电量数据为空或异常 - corpCode:{}, dtuSn:{}, date:{}", corpCode, dtuSn, date, e);
165 } 121 }
166 122
167 - // 2. 查询OEE时序数据 - 原始数据直接返回  
168 Object oeeRawData = Collections.emptyList(); 123 Object oeeRawData = Collections.emptyList();
169 long totalDuration = 0; 124 long totalDuration = 0;
170 - // runStatus状态: 0-离线, 1-停机, 2-待机, 3-运行  
171 Map<Integer, Long> statusDurationMap = new LinkedHashMap<>(); 125 Map<Integer, Long> statusDurationMap = new LinkedHashMap<>();
172 - statusDurationMap.put(0, 0L); // 离线  
173 - statusDurationMap.put(1, 0L); // 停机  
174 - statusDurationMap.put(2, 0L); // 待机  
175 - statusDurationMap.put(3, 0L); // 运行  
176 - 126 + statusDurationMap.put(0, 0L);
  127 + statusDurationMap.put(1, 0L);
  128 + statusDurationMap.put(2, 0L);
  129 + statusDurationMap.put(3, 0L);
177 try { 130 try {
178 - String oeeSql = "SELECT runStatus1, runStatus2 FROM " + eRunDtlTableName  
179 - + " WHERE corp_code = ? AND dtuSn = ? AND use_date = ?";  
180 - Map<String, Object> oeeRow = jdbcTemplate.queryForMap(oeeSql, energyCorpCode, dtuSn, date + " 00:00:00"); 131 + String oeeSql = "SELECT runStatus1, runStatus2 FROM " + eRunDtlTableName + " WHERE corp_code = ? AND dtuSn = ? AND use_date = ?";
  132 + Map<String, Object> oeeRow = jt.queryForMap(oeeSql, corpCode, dtuSn, date + " 00:00:00");
181 if (oeeRow != null) { 133 if (oeeRow != null) {
182 String rs1 = oeeRow.get("runStatus1") != null ? String.valueOf(oeeRow.get("runStatus1")) : ""; 134 String rs1 = oeeRow.get("runStatus1") != null ? String.valueOf(oeeRow.get("runStatus1")) : "";
183 String rs2 = oeeRow.get("runStatus2") != null ? String.valueOf(oeeRow.get("runStatus2")) : ""; 135 String rs2 = oeeRow.get("runStatus2") != null ? String.valueOf(oeeRow.get("runStatus2")) : "";
184 String jsonStr = rs1 + rs2; 136 String jsonStr = rs1 + rs2;
185 oeeRawData = JSON.parseArray(jsonStr); 137 oeeRawData = JSON.parseArray(jsonStr);
186 -  
187 - // 统计各状态时长  
188 JSONArray dataArray = JSON.parseArray(jsonStr); 138 JSONArray dataArray = JSON.parseArray(jsonStr);
189 for (int i = 0; i < dataArray.size(); i++) { 139 for (int i = 0; i < dataArray.size(); i++) {
190 JSONObject item = dataArray.getJSONObject(i); 140 JSONObject item = dataArray.getJSONObject(i);
191 Long duration = item.getLong("duration"); 141 Long duration = item.getLong("duration");
192 Integer runStatus = item.getInteger("runStatus"); 142 Integer runStatus = item.getInteger("runStatus");
193 -  
194 if (duration != null && duration > 0) { 143 if (duration != null && duration > 0) {
195 totalDuration += duration; 144 totalDuration += duration;
196 int statusKey = runStatus != null ? runStatus : 0; 145 int statusKey = runStatus != null ? runStatus : 0;
@@ -199,16 +148,13 @@ public class EnergySearchService { @@ -199,16 +148,13 @@ public class EnergySearchService {
199 } 148 }
200 } 149 }
201 } catch (Exception e) { 150 } catch (Exception e) {
202 - log.warn("【能耗明细】查询OEE时序数据为空或异常 - dtuSn:{}, date:{}", dtuSn, date); 151 + log.warn("【能耗明细】查询OEE时序数据为空或异常 - corpCode:{}, dtuSn:{}, date:{}", corpCode, dtuSn, date, e);
203 } 152 }
204 153
205 - // 3. 构建OEE统计结果(含格式化时长和占比)  
206 List<Map<String, Object>> statusStats = new ArrayList<>(); 154 List<Map<String, Object>> statusStats = new ArrayList<>();
207 for (Map.Entry<Integer, Long> entry : statusDurationMap.entrySet()) { 155 for (Map.Entry<Integer, Long> entry : statusDurationMap.entrySet()) {
208 long dur = entry.getValue(); 156 long dur = entry.getValue();
209 - double percent = totalDuration > 0 ? BigDecimal.valueOf(dur * 100.0 / totalDuration)  
210 - .setScale(2, RoundingMode.HALF_UP).doubleValue() : 0.0;  
211 - 157 + double percent = totalDuration > 0 ? BigDecimal.valueOf(dur * 100.0 / totalDuration).setScale(2, RoundingMode.HALF_UP).doubleValue() : 0.0;
212 Map<String, Object> stat = new LinkedHashMap<>(); 158 Map<String, Object> stat = new LinkedHashMap<>();
213 stat.put("status", entry.getKey()); 159 stat.put("status", entry.getKey());
214 stat.put("durationSeconds", dur); 160 stat.put("durationSeconds", dur);
@@ -216,43 +162,13 @@ public class EnergySearchService { @@ -216,43 +162,13 @@ public class EnergySearchService {
216 stat.put("percent", percent); 162 stat.put("percent", percent);
217 statusStats.add(stat); 163 statusStats.add(stat);
218 } 164 }
219 -  
220 - return Map.of(  
221 - "code", 200,  
222 - "msg", "请求成功",  
223 - "dtuSn", dtuSn,  
224 - "date", date,  
225 - "kwhData", Map.of(  
226 - "list", kwhRawData,  
227 - "totalKwh", totalKwh.setScale(2, RoundingMode.HALF_UP)  
228 - ),  
229 - "oeeData", Map.of(  
230 - "list", oeeRawData,  
231 - "totalDurationFormatted", formatDuration(totalDuration),  
232 - "totalDurationSeconds", totalDuration,  
233 - "statusStats", statusStats  
234 - )  
235 - ); 165 + return Map.of("code", 200, "msg", "请求成功", "dtuSn", dtuSn, "date", date, "kwhData", Map.of("list", kwhRawData, "totalKwh", totalKwh.setScale(2, RoundingMode.HALF_UP)),
  166 + "oeeData", Map.of("list", oeeRawData, "totalDurationFormatted", formatDuration(totalDuration), "totalDurationSeconds", totalDuration, "statusStats", statusStats));
236 } 167 }
237 168
238 - /**  
239 - * 根据dtuSn查询指定设备的运行时长明细  
240 - * 核心数据为设备时用电量(eq_kwh),其中包含每个状态的运行时长,需要统计  
241 - * type=1(时): 传startDate,获取指定日期的时用电量明细+各状态时长统计  
242 - * type=2(天): 传startDate和endDate,按日统计  
243 - * type=3(月): 查本年年初到现在,按月统计  
244 - *  
245 - * @param dtuSn 设备序列号  
246 - * @param type 类型:1-时,2-天,3-月  
247 - * @param startDate 开始日期 yyyy-MM-dd (type=1,2必填)  
248 - * @param endDate 结束日期 yyyy-MM-dd (type=2必填)  
249 - */  
250 - public Map<String, Object> queryEnergyRuntimeDetail(String dtuSn, String type,  
251 - String startDate, String endDate) { 169 + public Map<String, Object> queryEnergyRuntimeDetail(String corpCode, String dtuSn, String type, String startDate, String endDate) {
252 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); 170 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
253 List<String> dateList = new ArrayList<>(); 171 List<String> dateList = new ArrayList<>();
254 -  
255 - // 根据type构建日期列表  
256 if ("1".equals(type)) { 172 if ("1".equals(type)) {
257 dateList.add(startDate); 173 dateList.add(startDate);
258 } else if ("2".equals(type)) { 174 } else if ("2".equals(type)) {
@@ -278,41 +194,32 @@ public class EnergySearchService { @@ -278,41 +194,32 @@ public class EnergySearchService {
278 startCal.add(Calendar.DAY_OF_MONTH, 1); 194 startCal.add(Calendar.DAY_OF_MONTH, 1);
279 } 195 }
280 } 196 }
  197 + String eqKwhTableName = corpConfigService.getEqKwhTableName(corpCode);
  198 + JdbcTemplate jt = corpConfigService.getJdbcTemplate(corpCode);
281 199
282 - // 统计汇总数据  
283 long totalDurationAll = 0; 200 long totalDurationAll = 0;
284 BigDecimal totalKwhAll = BigDecimal.ZERO; 201 BigDecimal totalKwhAll = BigDecimal.ZERO;
285 Map<Integer, Long> statusDurationAllMap = initStatusMap(); 202 Map<Integer, Long> statusDurationAllMap = initStatusMap();
286 -  
287 - // type=1: 直接返回每日明细; type=2/3: 按日期聚合后返回  
288 List<Map<String, Object>> detailList = new ArrayList<>(); 203 List<Map<String, Object>> detailList = new ArrayList<>();
289 - // type=3 按月聚合用  
290 Map<String, Map<String, Object>> monthAggMap = "3".equals(type) ? new LinkedHashMap<>() : null; 204 Map<String, Map<String, Object>> monthAggMap = "3".equals(type) ? new LinkedHashMap<>() : null;
291 205
292 for (String dateStr : dateList) { 206 for (String dateStr : dateList) {
293 - // 从eq_kwh表查询时用电量数据  
294 Object kwhRawData = Collections.emptyList(); 207 Object kwhRawData = Collections.emptyList();
295 BigDecimal dayKwh = BigDecimal.ZERO; 208 BigDecimal dayKwh = BigDecimal.ZERO;
296 long dayTotalDuration = 0; 209 long dayTotalDuration = 0;
297 Map<Integer, Long> dayStatusDuration = initStatusMap(); 210 Map<Integer, Long> dayStatusDuration = initStatusMap();
298 -  
299 try { 211 try {
300 - String kwhSql = "SELECT description FROM " + eqKwhTableName  
301 - + " WHERE corp_code = ? AND dtuSn = ? AND use_date = ?";  
302 - Map<String, Object> kwhRow = jdbcTemplate.queryForMap(kwhSql, energyCorpCode, dtuSn, dateStr + " 00:00:00"); 212 + String kwhSql = "SELECT description FROM " + eqKwhTableName + " WHERE corp_code = ? AND dtuSn = ? AND use_date = ?";
  213 + Map<String, Object> kwhRow = jt.queryForMap(kwhSql, corpCode, dtuSn, dateStr + " 00:00:00");
303 if (kwhRow != null && kwhRow.get("description") != null) { 214 if (kwhRow != null && kwhRow.get("description") != null) {
304 String desc = String.valueOf(kwhRow.get("description")); 215 String desc = String.valueOf(kwhRow.get("description"));
305 JSONArray dataArray = JSON.parseArray(desc); 216 JSONArray dataArray = JSON.parseArray(desc);
306 -  
307 for (int i = 0; i < dataArray.size(); i++) { 217 for (int i = 0; i < dataArray.size(); i++) {
308 JSONObject item = dataArray.getJSONObject(i); 218 JSONObject item = dataArray.getJSONObject(i);
309 Double value = item.getDouble("value"); 219 Double value = item.getDouble("value");
310 if (value != null) dayKwh = dayKwh.add(BigDecimal.valueOf(value)); 220 if (value != null) dayKwh = dayKwh.add(BigDecimal.valueOf(value));
311 -  
312 - // 从字段 0/1/2/3 统计各状态运行时长 + 格式化新字段  
313 for (int statusKey = 0; statusKey <= 3; statusKey++) { 221 for (int statusKey = 0; statusKey <= 3; statusKey++) {
314 Long dur = item.getLong(String.valueOf(statusKey)); 222 Long dur = item.getLong(String.valueOf(statusKey));
315 - item.put(statusKey + "Formatted", formatDuration(dur != null ? dur : 0L));  
316 if (dur != null && dur > 0) { 223 if (dur != null && dur > 0) {
317 dayTotalDuration += dur; 224 dayTotalDuration += dur;
318 totalDurationAll += dur; 225 totalDurationAll += dur;
@@ -326,11 +233,9 @@ public class EnergySearchService { @@ -326,11 +233,9 @@ public class EnergySearchService {
326 } catch (Exception ignored) { 233 } catch (Exception ignored) {
327 } 234 }
328 totalKwhAll = totalKwhAll.add(dayKwh); 235 totalKwhAll = totalKwhAll.add(dayKwh);
329 -  
330 String periodKey = "3".equals(type) ? dateStr.substring(0, 7) : dateStr; 236 String periodKey = "3".equals(type) ? dateStr.substring(0, 7) : dateStr;
331 237
332 if ("1".equals(type)) { 238 if ("1".equals(type)) {
333 - // type=1(时): 返回原始kwhList + 当日统计  
334 Map<String, Object> entry = new LinkedHashMap<>(); 239 Map<String, Object> entry = new LinkedHashMap<>();
335 entry.put("date", periodKey); 240 entry.put("date", periodKey);
336 entry.put("kwhList", kwhRawData); 241 entry.put("kwhList", kwhRawData);
@@ -340,7 +245,6 @@ public class EnergySearchService { @@ -340,7 +245,6 @@ public class EnergySearchService {
340 entry.put("statusStats", buildStatusStats(dayStatusDuration, dayTotalDuration)); 245 entry.put("statusStats", buildStatusStats(dayStatusDuration, dayTotalDuration));
341 detailList.add(entry); 246 detailList.add(entry);
342 } else if ("2".equals(type)) { 247 } else if ("2".equals(type)) {
343 - // type=2(天): 返回每日汇总统计,不含kwhList  
344 Map<String, Object> entry = new LinkedHashMap<>(); 248 Map<String, Object> entry = new LinkedHashMap<>();
345 entry.put("date", periodKey); 249 entry.put("date", periodKey);
346 entry.put("totalKwh", dayKwh.setScale(2, RoundingMode.HALF_UP)); 250 entry.put("totalKwh", dayKwh.setScale(2, RoundingMode.HALF_UP));
@@ -349,7 +253,6 @@ public class EnergySearchService { @@ -349,7 +253,6 @@ public class EnergySearchService {
349 entry.put("statusStats", buildStatusStats(dayStatusDuration, dayTotalDuration)); 253 entry.put("statusStats", buildStatusStats(dayStatusDuration, dayTotalDuration));
350 detailList.add(entry); 254 detailList.add(entry);
351 } else if ("3".equals(type)) { 255 } else if ("3".equals(type)) {
352 - // type=3(月): 按月聚合  
353 monthAggMap.computeIfAbsent(periodKey, k -> { 256 monthAggMap.computeIfAbsent(periodKey, k -> {
354 Map<String, Object> m = new LinkedHashMap<>(); 257 Map<String, Object> m = new LinkedHashMap<>();
355 m.put("date", k); 258 m.put("date", k);
@@ -361,24 +264,17 @@ public class EnergySearchService { @@ -361,24 +264,17 @@ public class EnergySearchService {
361 Map<String, Object> monthEntry = monthAggMap.get(periodKey); 264 Map<String, Object> monthEntry = monthAggMap.get(periodKey);
362 monthEntry.put("totalKwh", ((BigDecimal) monthEntry.get("totalKwh")).add(dayKwh)); 265 monthEntry.put("totalKwh", ((BigDecimal) monthEntry.get("totalKwh")).add(dayKwh));
363 monthEntry.put("totalDurationSeconds", (Long) monthEntry.get("totalDurationSeconds") + dayTotalDuration); 266 monthEntry.put("totalDurationSeconds", (Long) monthEntry.get("totalDurationSeconds") + dayTotalDuration);
364 - @SuppressWarnings("unchecked")  
365 - Map<Integer, Long> mStatusMap = (Map<Integer, Long>) monthEntry.get("statusDurationMap"); 267 + @SuppressWarnings("unchecked") Map<Integer, Long> mStatusMap = (Map<Integer, Long>) monthEntry.get("statusDurationMap");
366 for (int sk = 0; sk <= 3; sk++) { 268 for (int sk = 0; sk <= 3; sk++) {
367 - if (dayStatusDuration.get(sk) > 0) {  
368 - mStatusMap.merge(sk, dayStatusDuration.get(sk), Long::sum);  
369 - } 269 + if (dayStatusDuration.get(sk) > 0) mStatusMap.merge(sk, dayStatusDuration.get(sk), Long::sum);
370 } 270 }
371 } 271 }
372 } 272 }
373 -  
374 - // type=3 构建月度聚合结果  
375 if ("3".equals(type) && monthAggMap != null) { 273 if ("3".equals(type) && monthAggMap != null) {
376 for (Map.Entry<String, Map<String, Object>> me : monthAggMap.entrySet()) { 274 for (Map.Entry<String, Map<String, Object>> me : monthAggMap.entrySet()) {
377 Map<String, Object> m = me.getValue(); 275 Map<String, Object> m = me.getValue();
378 long mDur = (Long) m.get("totalDurationSeconds"); 276 long mDur = (Long) m.get("totalDurationSeconds");
379 - @SuppressWarnings("unchecked")  
380 - Map<Integer, Long> mStatusMap = (Map<Integer, Long>) m.get("statusDurationMap");  
381 - 277 + @SuppressWarnings("unchecked") Map<Integer, Long> mStatusMap = (Map<Integer, Long>) m.get("statusDurationMap");
382 Map<String, Object> entry = new LinkedHashMap<>(); 278 Map<String, Object> entry = new LinkedHashMap<>();
383 entry.put("date", m.get("date")); 279 entry.put("date", m.get("date"));
384 entry.put("totalKwh", ((BigDecimal) m.get("totalKwh")).setScale(2, RoundingMode.HALF_UP)); 280 entry.put("totalKwh", ((BigDecimal) m.get("totalKwh")).setScale(2, RoundingMode.HALF_UP));
@@ -388,58 +284,36 @@ public class EnergySearchService { @@ -388,58 +284,36 @@ public class EnergySearchService {
388 detailList.add(entry); 284 detailList.add(entry);
389 } 285 }
390 } 286 }
391 -  
392 List<Map<String, Object>> allStatusStats = buildStatusStats(statusDurationAllMap, totalDurationAll); 287 List<Map<String, Object>> allStatusStats = buildStatusStats(statusDurationAllMap, totalDurationAll);
393 -  
394 - return Map.of(  
395 - "code", 200,  
396 - "msg", "请求成功",  
397 - "dtuSn", dtuSn,  
398 - "type", type,  
399 - "detailList", detailList,  
400 - "summary", Map.of(  
401 - "totalDurationFormatted", formatDuration(totalDurationAll),  
402 - "totalDurationSeconds", totalDurationAll,  
403 - "totalKwh", totalKwhAll.setScale(2, RoundingMode.HALF_UP),  
404 - "statusStats", allStatusStats  
405 - )  
406 - ); 288 + return Map.of("code", 200, "msg", "请求成功", "dtuSn", dtuSn, "type", type, "detailList", detailList,
  289 + "summary", Map.of("totalDurationFormatted", formatDuration(totalDurationAll), "totalDurationSeconds", totalDurationAll,
  290 + "totalKwh", totalKwhAll.setScale(2, RoundingMode.HALF_UP), "statusStats", allStatusStats));
407 } 291 }
408 292
409 - /**  
410 - * 查询能耗时序状态 - 分页查询  
411 - * 从e_run_dtl(OEE时序)表获取指定日期的设备时序数据,每页12条  
412 - * 同时计算每个设备的稼动率和总用电量(从eq_kwh表)  
413 - *  
414 - * @param date 查询日期 yyyy-MM-dd  
415 - * @param pageNo 页码,默认1  
416 - * @param pageSize 每页条数,默认12  
417 - */  
418 - public Map<String, Object> queryEnergyTimelineStatus(String date, Integer pageNo, Integer pageSize) {  
419 - // 先查OEE时序表获取有数据的设备列表  
420 - String countSql = "SELECT COUNT(DISTINCT r.dtuSn) FROM " + eRunDtlTableName + " r "  
421 - + " INNER JOIN " + energyTableName + " e ON e.dtuSn = r.dtuSn AND e.corp_code = r.corp_code "  
422 - + " WHERE r.corp_code = ? AND r.use_date = ?";  
423 - Long total = jdbcTemplate.queryForObject(countSql, Long.class, energyCorpCode, date + " 00:00:00"); 293 + public Map<String, Object> queryEnergyTimelineStatus(String corpCode, String date, Integer pageNo, Integer pageSize) {
  294 + String eRunDtlTableName = corpConfigService.getERunDtlTableName(corpCode);
  295 + String energyTableName = corpConfigService.getEnergyTableName(corpCode);
  296 + String eqKwhTableName = corpConfigService.getEqKwhTableName(corpCode);
  297 + JdbcTemplate jt = corpConfigService.getJdbcTemplate(corpCode);
  298 +
  299 + String countSql = "SELECT COUNT(DISTINCT r.dtuSn) FROM " + eRunDtlTableName + " r " +
  300 + "INNER JOIN " + energyTableName + " e ON e.dtuSn = r.dtuSn AND e.corp_code = r.corp_code WHERE r.corp_code = ? AND r.use_date = ?";
  301 + Long total = jt.queryForObject(countSql, Long.class, corpCode, date + " 00:00:00");
424 302
425 int offset = (pageNo - 1) * pageSize; 303 int offset = (pageNo - 1) * pageSize;
426 - String querySql = "SELECT r.dtuSn, e.deviceName, r.runStatus1, r.runStatus2 FROM " + eRunDtlTableName + " r "  
427 - + " INNER JOIN " + energyTableName + " e ON e.dtuSn = r.dtuSn AND e.corp_code = r.corp_code "  
428 - + " WHERE r.corp_code = ? AND r.use_date = ? "  
429 - + " ORDER BY e.deviceName ASC LIMIT ?, ?";  
430 - List<Map<String, Object>> rows = jdbcTemplate.queryForList(querySql, energyCorpCode, date + " 00:00:00", offset, pageSize); 304 + String querySql = "SELECT r.dtuSn, e.deviceName, r.runStatus1, r.runStatus2 FROM " + eRunDtlTableName + " r " +
  305 + "INNER JOIN " + energyTableName + " e ON e.dtuSn = r.dtuSn AND e.corp_code = r.corp_code WHERE r.corp_code = ? AND r.use_date = ? " +
  306 + "ORDER BY e.deviceName ASC LIMIT ?, ?";
  307 + List<Map<String, Object>> rows = jt.queryForList(querySql, corpCode, date + " 00:00:00", offset, pageSize);
431 308
432 List<Map<String, Object>> list = new ArrayList<>(); 309 List<Map<String, Object>> list = new ArrayList<>();
433 for (Map<String, Object> row : rows) { 310 for (Map<String, Object> row : rows) {
434 Map<String, Object> item = new LinkedHashMap<>(); 311 Map<String, Object> item = new LinkedHashMap<>();
435 item.put("dtuSn", row.get("dtuSn")); 312 item.put("dtuSn", row.get("dtuSn"));
436 item.put("deviceName", row.get("deviceName")); 313 item.put("deviceName", row.get("deviceName"));
437 -  
438 - // OEE时序数据(原始返回)  
439 Object oeeRawData = Collections.emptyList(); 314 Object oeeRawData = Collections.emptyList();
440 long totalDuration = 0; 315 long totalDuration = 0;
441 long runDuration = 0; 316 long runDuration = 0;
442 -  
443 String rs1 = row.get("runStatus1") != null ? String.valueOf(row.get("runStatus1")) : ""; 317 String rs1 = row.get("runStatus1") != null ? String.valueOf(row.get("runStatus1")) : "";
444 String rs2 = row.get("runStatus2") != null ? String.valueOf(row.get("runStatus2")) : ""; 318 String rs2 = row.get("runStatus2") != null ? String.valueOf(row.get("runStatus2")) : "";
445 if (StringUtils.hasText(rs1) || StringUtils.hasText(rs2)) { 319 if (StringUtils.hasText(rs1) || StringUtils.hasText(rs2)) {
@@ -453,23 +327,20 @@ public class EnergySearchService { @@ -453,23 +327,20 @@ public class EnergySearchService {
453 Integer runStatus = jo.getInteger("runStatus"); 327 Integer runStatus = jo.getInteger("runStatus");
454 if (duration != null && duration > 0 && runStatus != null) { 328 if (duration != null && duration > 0 && runStatus != null) {
455 totalDuration += duration; 329 totalDuration += duration;
456 - if (runStatus == 3) runDuration += duration; // 运行状态 330 + if (runStatus == 3) runDuration += duration;
457 } 331 }
458 } 332 }
459 } catch (Exception ignored) { 333 } catch (Exception ignored) {
460 } 334 }
461 } 335 }
462 -  
463 item.put("timelineList", oeeRawData); 336 item.put("timelineList", oeeRawData);
464 item.put("totalDurationFormatted", formatDuration(totalDuration)); 337 item.put("totalDurationFormatted", formatDuration(totalDuration));
465 item.put("totalDurationSeconds", totalDuration); 338 item.put("totalDurationSeconds", totalDuration);
466 339
467 - // 从eq_kwh表获取用电量  
468 BigDecimal totalKwh = BigDecimal.ZERO; 340 BigDecimal totalKwh = BigDecimal.ZERO;
469 try { 341 try {
470 - String kwhSql = "SELECT description FROM " + eqKwhTableName  
471 - + " WHERE corp_code = ? AND dtuSn = ? AND use_date = ?";  
472 - Map<String, Object> kwhRow = jdbcTemplate.queryForMap(kwhSql, energyCorpCode, row.get("dtuSn"), date + " 00:00:00"); 342 + String kwhSql = "SELECT description FROM " + eqKwhTableName + " WHERE corp_code = ? AND dtuSn = ? AND use_date = ?";
  343 + Map<String, Object> kwhRow = jt.queryForMap(kwhSql, corpCode, row.get("dtuSn"), date + " 00:00:00");
473 if (kwhRow != null && kwhRow.get("description") != null) { 344 if (kwhRow != null && kwhRow.get("description") != null) {
474 JSONArray dataArray = JSON.parseArray(String.valueOf(kwhRow.get("description"))); 345 JSONArray dataArray = JSON.parseArray(String.valueOf(kwhRow.get("description")));
475 for (int i = 0; i < dataArray.size(); i++) { 346 for (int i = 0; i < dataArray.size(); i++) {
@@ -479,25 +350,12 @@ public class EnergySearchService { @@ -479,25 +350,12 @@ public class EnergySearchService {
479 } 350 }
480 } catch (Exception ignored) { 351 } catch (Exception ignored) {
481 } 352 }
482 -  
483 item.put("totalKwh", totalKwh.setScale(2, RoundingMode.HALF_UP)); 353 item.put("totalKwh", totalKwh.setScale(2, RoundingMode.HALF_UP));
484 - // 稼动率 = 运行时长 / 总时长  
485 - double utilizationRate = totalDuration > 0  
486 - ? BigDecimal.valueOf(runDuration * 100.0 / totalDuration).setScale(2, RoundingMode.HALF_UP).doubleValue()  
487 - : 0.0; 354 + double utilizationRate = totalDuration > 0 ? BigDecimal.valueOf(runDuration * 100.0 / totalDuration).setScale(2, RoundingMode.HALF_UP).doubleValue() : 0.0;
488 item.put("utilizationRate", utilizationRate); 355 item.put("utilizationRate", utilizationRate);
489 -  
490 list.add(item); 356 list.add(item);
491 } 357 }
492 -  
493 - return Map.of(  
494 - "code", 200,  
495 - "msg", "请求成功",  
496 - "total", total != null ? total : 0,  
497 - "pageNo", pageNo,  
498 - "pageSize", pageSize,  
499 - "list", list  
500 - ); 358 + return Map.of("code", 200, "msg", "请求成功", "total", total != null ? total : 0, "pageNo", pageNo, "pageSize", pageSize, "list", list);
501 } 359 }
502 360
503 private static Map<Integer, Long> initStatusMap() { 361 private static Map<Integer, Long> initStatusMap() {
@@ -513,8 +371,7 @@ public class EnergySearchService { @@ -513,8 +371,7 @@ public class EnergySearchService {
513 List<Map<String, Object>> list = new ArrayList<>(); 371 List<Map<String, Object>> list = new ArrayList<>();
514 for (Map.Entry<Integer, Long> entry : statusMap.entrySet()) { 372 for (Map.Entry<Integer, Long> entry : statusMap.entrySet()) {
515 long dur = entry.getValue(); 373 long dur = entry.getValue();
516 - double percent = totalDur > 0 ? BigDecimal.valueOf(dur * 100.0 / totalDur)  
517 - .setScale(2, RoundingMode.HALF_UP).doubleValue() : 0.0; 374 + double percent = totalDur > 0 ? BigDecimal.valueOf(dur * 100.0 / totalDur).setScale(2, RoundingMode.HALF_UP).doubleValue() : 0.0;
518 Map<String, Object> stat = new LinkedHashMap<>(); 375 Map<String, Object> stat = new LinkedHashMap<>();
519 stat.put("status", entry.getKey()); 376 stat.put("status", entry.getKey());
520 stat.put("durationSeconds", dur); 377 stat.put("durationSeconds", dur);
@@ -527,17 +384,10 @@ public class EnergySearchService { @@ -527,17 +384,10 @@ public class EnergySearchService {
527 384
528 private static Object itemToMap(JSONArray dataArray) { 385 private static Object itemToMap(JSONArray dataArray) {
529 List<Object> list = new ArrayList<>(); 386 List<Object> list = new ArrayList<>();
530 - for (int i = 0; i < dataArray.size(); i++) {  
531 - list.add(dataArray.getJSONObject(i));  
532 - } 387 + for (int i = 0; i < dataArray.size(); i++) list.add(dataArray.getJSONObject(i));
533 return list; 388 return list;
534 } 389 }
535 390
536 - /**  
537 - * 格式化时长为 xx时xx分xx秒 格式  
538 - * 时不为0则展示xx时xx分xx秒  
539 - * 时和分都为0则只展示xx秒  
540 - */  
541 private static String formatDuration(long totalSeconds) { 391 private static String formatDuration(long totalSeconds) {
542 long h = totalSeconds / 3600; 392 long h = totalSeconds / 3600;
543 long m = (totalSeconds % 3600) / 60; 393 long m = (totalSeconds % 3600) / 60;
@@ -549,143 +399,79 @@ public class EnergySearchService { @@ -549,143 +399,79 @@ public class EnergySearchService {
549 return sb.toString(); 399 return sb.toString();
550 } 400 }
551 401
552 - /**  
553 - * 格式化时长为 xxx.xx 时  
554 - */  
555 private static String formatDurationToHours(long totalSeconds) { 402 private static String formatDurationToHours(long totalSeconds) {
556 double hours = totalSeconds / 3600.0; 403 double hours = totalSeconds / 3600.0;
557 return String.format("%.2f时", hours); 404 return String.format("%.2f时", hours);
558 } 405 }
559 406
560 - // ==================== eq_kwh 综合统计查询 ==================== 407 + // ==================== eq_kwh 综合统计 ====================
561 408
562 - /**  
563 - * 查询 eq_kwh 表的综合统计数据  
564 - * 返回:  
565 - * 1. 所有设备的总的稼动率 + 每个状态的时间(xxx.xx时)  
566 - * 2. 当前设备的运行状态  
567 - * 3. 异常机台排名(待机+停机时间最长往下排, xx时xx分xx秒)  
568 - * 4. 每个设备统计时间内的总的0/1/2/3的时间(xx时xx分xx秒)  
569 - *  
570 - * @param startDate 开始日期 yyyy-MM-dd  
571 - * @param endDate 结束日期 yyyy-MM-dd  
572 - */  
573 - public Map<String, Object> queryEqKwhStatistics(String startDate, String endDate) {  
574 - log.info("========== [eq_kwh综合统计] startDate={}, endDate={} ==========", startDate, endDate);  
575 -  
576 - if (!StringUtils.hasText(startDate) || !StringUtils.hasText(endDate)) {  
577 - return Map.of(  
578 - "code", 400, "msg", "参数错误: startDate和endDate必填",  
579 - "data", Map.of()  
580 - );  
581 - } 409 + public Map<String, Object> queryEqKwhStatistics(String corpCode, String startDate, String endDate) {
  410 + log.info("========== [eq_kwh综合统计] corpCode={}, startDate={}, endDate={} ==========", corpCode, startDate, endDate);
  411 + if (!StringUtils.hasText(startDate) || !StringUtils.hasText(endDate))
  412 + return Map.of("code", 400, "msg", "参数错误: startDate和endDate必填", "data", Map.of());
582 413
583 - // 1. 构建日期列表  
584 List<String> dateList = buildDateList(startDate, endDate); 414 List<String> dateList = buildDateList(startDate, endDate);
585 - if (dateList.isEmpty()) {  
586 - return buildEmptyEqKwhStats();  
587 - } 415 + if (dateList.isEmpty()) return buildEmptyEqKwhStats();
588 log.info("日期范围共 {} 天: {} ~ {}", dateList.size(), dateList.get(0), dateList.get(dateList.size() - 1)); 416 log.info("日期范围共 {} 天: {} ~ {}", dateList.size(), dateList.get(0), dateList.get(dateList.size() - 1));
589 417
590 - // 2. 获取所有设备列表及名称  
591 - Map<String, String> deviceNameMap = queryAllEnergyDeviceNames();  
592 -  
593 - // 3. 从 eq_kwh 表批量查询所有设备在指定日期范围内的数据  
594 - List<Map<String, Object>> allRawData = queryEqKwhBatch(dateList); 418 + Map<String, String> deviceNameMap = queryAllEnergyDeviceNames(corpCode);
  419 + List<Map<String, Object>> allRawData = queryEqKwhBatch(corpCode, dateList);
595 log.info("eq_kwh 批量查询返回 {} 条原始记录", allRawData.size()); 420 log.info("eq_kwh 批量查询返回 {} 条原始记录", allRawData.size());
596 421
597 - // 4. 按 dtuSn 分组聚合数据,计算每个设备的各状态时长  
598 Map<String, DeviceStatResult> deviceStatMap = aggregateByDevice(allRawData, deviceNameMap); 422 Map<String, DeviceStatResult> deviceStatMap = aggregateByDevice(allRawData, deviceNameMap);
599 -  
600 - // 确保所有设备都在结果中(无数据的设为0)  
601 for (String sn : deviceNameMap.keySet()) { 423 for (String sn : deviceNameMap.keySet()) {
602 - if (!deviceStatMap.containsKey(sn)) { 424 + if (!deviceStatMap.containsKey(sn))
603 deviceStatMap.put(sn, new DeviceStatResult(sn, deviceNameMap.getOrDefault(sn, ""))); 425 deviceStatMap.put(sn, new DeviceStatResult(sn, deviceNameMap.getOrDefault(sn, "")));
604 - }  
605 } 426 }
606 -  
607 - // 5. 计算全局汇总  
608 - return buildEqKwhStatisticsResult(deviceStatMap, deviceNameMap); 427 + return buildEqKwhStatisticsResult(corpCode, deviceStatMap, deviceNameMap);
609 } 428 }
610 429
611 - /**  
612 - * 设备统计内部结构  
613 - */  
614 static class DeviceStatResult { 430 static class DeviceStatResult {
615 String dtuSn; 431 String dtuSn;
616 String deviceName; 432 String deviceName;
617 - long status0; // 离线时长(秒)  
618 - long status1; // 停机时长(秒)  
619 - long status2; // 待机时长(秒)  
620 - long status3; // 运行时长(秒)  
621 - double totalKwh; // 总用电量 433 + long status0, status1, status2, status3;
  434 + double totalKwh;
622 435
623 DeviceStatResult(String dtuSn, String deviceName) { 436 DeviceStatResult(String dtuSn, String deviceName) {
624 this.dtuSn = dtuSn; 437 this.dtuSn = dtuSn;
625 this.deviceName = deviceName; 438 this.deviceName = deviceName;
626 } 439 }
627 440
628 - /**  
629 - * 总时长(秒)  
630 - */  
631 long totalDuration() { 441 long totalDuration() {
632 return status0 + status1 + status2 + status3; 442 return status0 + status1 + status2 + status3;
633 } 443 }
634 444
635 - /**  
636 - * 异常时长 = 停机 + 待机  
637 - */  
638 long abnormalDuration() { 445 long abnormalDuration() {
639 return status1 + status2; 446 return status1 + status2;
640 } 447 }
641 448
642 - /**  
643 - * 稼动分母 = 停机 + 待机 + 运行 (排除离线)  
644 - */  
645 long activeDuration() { 449 long activeDuration() {
646 return status1 + status2 + status3; 450 return status1 + status2 + status3;
647 } 451 }
648 } 452 }
649 453
650 - /**  
651 - * 构建空结果  
652 - */  
653 private Map<String, Object> buildEmptyEqKwhStats() { 454 private Map<String, Object> buildEmptyEqKwhStats() {
654 - return Map.of(  
655 - "code", 200, "msg", "请求成功", "data",  
656 - Map.of(  
657 - "summary", Map.of(  
658 - "availabilityRate", "0.00%",  
659 - "totalStatusDuration", Map.of(  
660 - "status0", Map.of("durationFormatted", "0时0分0秒", "durationSeconds", 0L, "durationHours", "0.00时"),  
661 - "status1", Map.of("durationFormatted", "0时0分0秒", "durationSeconds", 0L, "durationHours", "0.00时"),  
662 - "status2", Map.of("durationFormatted", "0时0分0秒", "durationSeconds", 0L, "durationHours", "0.00时"),  
663 - "status3", Map.of("durationFormatted", "0时0分0秒", "durationSeconds", 0L, "durationHours", "0.00时")  
664 - )  
665 - ), 455 + return Map.of("code", 200, "msg", "请求成功", "data", Map.of(
  456 + "summary", Map.of("availabilityRate", "0.00%", "totalStatusDuration",
  457 + Map.of("status0", Map.of("durationFormatted", "0时0分0秒", "durationSeconds", 0L, "durationHours", "0.00时"),
  458 + "status1", Map.of("durationFormatted", "0时0分0秒", "durationSeconds", 0L, "durationHours", "0.00时"),
  459 + "status2", Map.of("durationFormatted", "0时0分0秒", "durationSeconds", 0L, "durationHours", "0.00时"),
  460 + "status3", Map.of("durationFormatted", "0时0分0秒", "durationSeconds", 0L, "durationHours", "0.00时")),
666 "currentStatus", Map.of("0", 0, "1", 0, "2", 0, "3", 0), 461 "currentStatus", Map.of("0", 0, "1", 0, "2", 0, "3", 0),
667 - "abnormalRanking", List.of(),  
668 - "deviceList", List.of()  
669 - )  
670 - ); 462 + "abnormalRanking", List.of(), "deviceList", List.of())));
671 } 463 }
672 464
673 - /**  
674 - * 获取能耗设备表所有dtuSn及名称  
675 - */  
676 - private Map<String, String> queryAllEnergyDeviceNames() { 465 + private Map<String, String> queryAllEnergyDeviceNames(String corpCode) {
  466 + String energyTableName = corpConfigService.getEnergyTableName(corpCode);
  467 + JdbcTemplate jt = corpConfigService.getJdbcTemplate(corpCode);
677 String sql = "SELECT dtuSn, deviceName FROM " + energyTableName + " WHERE corp_code = ? ORDER BY dtuSn"; 468 String sql = "SELECT dtuSn, deviceName FROM " + energyTableName + " WHERE corp_code = ? ORDER BY dtuSn";
678 - List<Map<String, Object>> rows = jdbcTemplate.queryForList(sql, energyCorpCode); 469 + List<Map<String, Object>> rows = jt.queryForList(sql, corpCode);
679 Map<String, String> result = new LinkedHashMap<>(rows.size()); 470 Map<String, String> result = new LinkedHashMap<>(rows.size());
680 - for (Map<String, Object> row : rows) {  
681 - result.put((String) row.get("dtuSn"), (String) row.get("deviceName"));  
682 - } 471 + for (Map<String, Object> row : rows) result.put((String) row.get("dtuSn"), (String) row.get("deviceName"));
683 return result; 472 return result;
684 } 473 }
685 474
686 - /**  
687 - * 构建连续日期列表  
688 - */  
689 private List<String> buildDateList(String startDate, String endDate) { 475 private List<String> buildDateList(String startDate, String endDate) {
690 List<String> result = new ArrayList<>(); 476 List<String> result = new ArrayList<>();
691 try { 477 try {
@@ -704,66 +490,43 @@ public class EnergySearchService { @@ -704,66 +490,43 @@ public class EnergySearchService {
704 return result; 490 return result;
705 } 491 }
706 492
707 - /**  
708 - * 从 eq_kwh 表批量查询指定日期范围的所有记录  
709 - */  
710 - private List<Map<String, Object>> queryEqKwhBatch(List<String> dateList) { 493 + private List<Map<String, Object>> queryEqKwhBatch(String corpCode, List<String> dateList) {
711 if (dateList.isEmpty()) return Collections.emptyList(); 494 if (dateList.isEmpty()) return Collections.emptyList();
712 -  
713 - StringBuilder sql = new StringBuilder(  
714 - "SELECT dtuSn, use_date, description FROM " + eqKwhTableName +  
715 - " WHERE corp_code = ? AND use_date IN ("); 495 + String eqKwhTableName = corpConfigService.getEqKwhTableName(corpCode);
  496 + JdbcTemplate jt = corpConfigService.getJdbcTemplate(corpCode);
  497 + StringBuilder sql = new StringBuilder("SELECT dtuSn, use_date, description FROM " + eqKwhTableName + " WHERE corp_code = ? AND use_date IN (");
716 List<Object> params = new ArrayList<>(); 498 List<Object> params = new ArrayList<>();
717 - params.add(energyCorpCode);  
718 - 499 + params.add(corpCode);
719 for (String d : dateList) { 500 for (String d : dateList) {
720 sql.append("?,"); 501 sql.append("?,");
721 params.add(d + "T00:00:00"); 502 params.add(d + "T00:00:00");
722 } 503 }
723 - sql.deleteCharAt(sql.length() - 1).append(")");  
724 - sql.append(" ORDER BY dtuSn, use_date");  
725 -  
726 - return jdbcTemplate.queryForList(sql.toString(), params.toArray()); 504 + sql.deleteCharAt(sql.length() - 1).append(")").append(" ORDER BY dtuSn, use_date");
  505 + return jt.queryForList(sql.toString(), params.toArray());
727 } 506 }
728 507
729 - /**  
730 - * 按 dtuSn 分组聚合各状态时长  
731 - */  
732 - private Map<String, DeviceStatResult> aggregateByDevice(List<Map<String, Object>> rawData,  
733 - Map<String, String> deviceNameMap) { 508 + private Map<String, DeviceStatResult> aggregateByDevice(List<Map<String, Object>> rawData, Map<String, String> deviceNameMap) {
734 Map<String, DeviceStatResult> resultMap = new LinkedHashMap<>(); 509 Map<String, DeviceStatResult> resultMap = new LinkedHashMap<>();
735 -  
736 for (Map<String, Object> row : rawData) { 510 for (Map<String, Object> row : rawData) {
737 String sn = (String) row.get("dtuSn"); 511 String sn = (String) row.get("dtuSn");
738 String desc = row.get("description") != null ? String.valueOf(row.get("description")) : ""; 512 String desc = row.get("description") != null ? String.valueOf(row.get("description")) : "";
739 -  
740 - DeviceStatResult dsr = resultMap.computeIfAbsent(sn,  
741 - k -> new DeviceStatResult(k, deviceNameMap.getOrDefault(k, "")));  
742 - 513 + DeviceStatResult dsr = resultMap.computeIfAbsent(sn, k -> new DeviceStatResult(k, deviceNameMap.getOrDefault(k, "")));
743 if (!StringUtils.hasText(desc)) continue; 514 if (!StringUtils.hasText(desc)) continue;
744 -  
745 try { 515 try {
746 JSONArray dataArray = JSON.parseArray(desc); 516 JSONArray dataArray = JSON.parseArray(desc);
747 if (dataArray == null) continue; 517 if (dataArray == null) continue;
748 -  
749 for (int i = 0; i < dataArray.size(); i++) { 518 for (int i = 0; i < dataArray.size(); i++) {
750 JSONObject item = dataArray.getJSONObject(i); 519 JSONObject item = dataArray.getJSONObject(i);
751 if (item == null) continue; 520 if (item == null) continue;
752 -  
753 - // 用电量  
754 Double value = item.getDouble("value"); 521 Double value = item.getDouble("value");
755 if (value != null) dsr.totalKwh += value; 522 if (value != null) dsr.totalKwh += value;
756 -  
757 - // 各状态时长: 0-离线, 1-停机, 2-待机, 3-运行  
758 for (int sk = 0; sk <= 3; sk++) { 523 for (int sk = 0; sk <= 3; sk++) {
759 Long dur = item.getLong(String.valueOf(sk)); 524 Long dur = item.getLong(String.valueOf(sk));
760 - if (dur != null && dur > 0) {  
761 - switch (sk) {  
762 - case 0 -> dsr.status0 += dur;  
763 - case 1 -> dsr.status1 += dur;  
764 - case 2 -> dsr.status2 += dur;  
765 - case 3 -> dsr.status3 += dur;  
766 - } 525 + if (dur != null && dur > 0) switch (sk) {
  526 + case 0 -> dsr.status0 += dur;
  527 + case 1 -> dsr.status1 += dur;
  528 + case 2 -> dsr.status2 += dur;
  529 + case 3 -> dsr.status3 += dur;
767 } 530 }
768 } 531 }
769 } 532 }
@@ -771,135 +534,57 @@ public class EnergySearchService { @@ -771,135 +534,57 @@ public class EnergySearchService {
771 log.warn("解析eq_kwh description异常 - dtuSn:{}", sn, e); 534 log.warn("解析eq_kwh description异常 - dtuSn:{}", sn, e);
772 } 535 }
773 } 536 }
774 -  
775 return resultMap; 537 return resultMap;
776 } 538 }
777 539
778 - /**  
779 - * 构建最终统计结果  
780 - */  
781 - private Map<String, Object> buildEqKwhStatisticsResult(Map<String, DeviceStatResult> deviceStatMap,  
782 - Map<String, String> deviceNameMap) {  
783 - // ---- 全局汇总 ---- 540 + private Map<String, Object> buildEqKwhStatisticsResult(String corpCode, Map<String, DeviceStatResult> deviceStatMap, Map<String, String> deviceNameMap) {
784 long totalS0 = 0, totalS1 = 0, totalS2 = 0, totalS3 = 0; 541 long totalS0 = 0, totalS1 = 0, totalS2 = 0, totalS3 = 0;
785 double totalKwhSum = 0; 542 double totalKwhSum = 0;
786 -  
787 - // ---- 设备详情列表 ----  
788 List<Map<String, Object>> deviceList = new ArrayList<>(deviceStatMap.size()); 543 List<Map<String, Object>> deviceList = new ArrayList<>(deviceStatMap.size());
789 -  
790 for (Map.Entry<String, DeviceStatResult> entry : deviceStatMap.entrySet()) { 544 for (Map.Entry<String, DeviceStatResult> entry : deviceStatMap.entrySet()) {
791 DeviceStatResult dsr = entry.getValue(); 545 DeviceStatResult dsr = entry.getValue();
792 -  
793 totalS0 += dsr.status0; 546 totalS0 += dsr.status0;
794 totalS1 += dsr.status1; 547 totalS1 += dsr.status1;
795 totalS2 += dsr.status2; 548 totalS2 += dsr.status2;
796 totalS3 += dsr.status3; 549 totalS3 += dsr.status3;
797 totalKwhSum += dsr.totalKwh; 550 totalKwhSum += dsr.totalKwh;
798 -  
799 - // 单设备稼动率 = 运行 / (停机+待机+运行)  
800 long active = dsr.activeDuration(); 551 long active = dsr.activeDuration();
801 double devRate = active > 0 ? Math.round(dsr.status3 * 10000.0 / active) / 100.0 : 0.0; 552 double devRate = active > 0 ? Math.round(dsr.status3 * 10000.0 / active) / 100.0 : 0.0;
802 -  
803 Map<String, Object> devItem = new LinkedHashMap<>(); 553 Map<String, Object> devItem = new LinkedHashMap<>();
804 devItem.put("dtuSn", dsr.dtuSn); 554 devItem.put("dtuSn", dsr.dtuSn);
805 devItem.put("deviceName", dsr.deviceName); 555 devItem.put("deviceName", dsr.deviceName);
806 - // 各状态时长 - 格式化为 xx时xx分xx秒  
807 - devItem.put("status0", Map.of(  
808 - "durationFormatted", formatDuration(dsr.status0),  
809 - "durationSeconds", dsr.status0,  
810 - "durationHours", formatDurationToHours(dsr.status0)  
811 - ));  
812 - devItem.put("status1", Map.of(  
813 - "durationFormatted", formatDuration(dsr.status1),  
814 - "durationSeconds", dsr.status1,  
815 - "durationHours", formatDurationToHours(dsr.status1)  
816 - ));  
817 - devItem.put("status2", Map.of(  
818 - "durationFormatted", formatDuration(dsr.status2),  
819 - "durationSeconds", dsr.status2,  
820 - "durationHours", formatDurationToHours(dsr.status2)  
821 - ));  
822 - devItem.put("status3", Map.of(  
823 - "durationFormatted", formatDuration(dsr.status3),  
824 - "durationSeconds", dsr.status3,  
825 - "durationHours", formatDurationToHours(dsr.status3)  
826 - )); 556 + devItem.put("status0", Map.of("durationFormatted", formatDuration(dsr.status0), "durationSeconds", dsr.status0, "durationHours", formatDurationToHours(dsr.status0)));
  557 + devItem.put("status1", Map.of("durationFormatted", formatDuration(dsr.status1), "durationSeconds", dsr.status1, "durationHours", formatDurationToHours(dsr.status1)));
  558 + devItem.put("status2", Map.of("durationFormatted", formatDuration(dsr.status2), "durationSeconds", dsr.status2, "durationHours", formatDurationToHours(dsr.status2)));
  559 + devItem.put("status3", Map.of("durationFormatted", formatDuration(dsr.status3), "durationSeconds", dsr.status3, "durationHours", formatDurationToHours(dsr.status3)));
827 devItem.put("totalDurationFormatted", formatDuration(dsr.totalDuration())); 560 devItem.put("totalDurationFormatted", formatDuration(dsr.totalDuration()));
828 devItem.put("totalDurationSeconds", dsr.totalDuration()); 561 devItem.put("totalDurationSeconds", dsr.totalDuration());
829 devItem.put("totalDurationHours", formatDurationToHours(dsr.totalDuration())); 562 devItem.put("totalDurationHours", formatDurationToHours(dsr.totalDuration()));
830 devItem.put("totalKwh", Math.round(dsr.totalKwh * 100.0) / 100.0); 563 devItem.put("totalKwh", Math.round(dsr.totalKwh * 100.0) / 100.0);
831 devItem.put("availabilityRate", String.format("%.2f%%", devRate)); 564 devItem.put("availabilityRate", String.format("%.2f%%", devRate));
832 - devItem.put("availabilityRateValue", devRate);  
833 - // 异常时长用于排序(内部字段,后面移除)  
834 devItem.put("_abnormalDur", dsr.abnormalDuration()); 565 devItem.put("_abnormalDur", dsr.abnormalDuration());
835 -  
836 deviceList.add(devItem); 566 deviceList.add(devItem);
837 } 567 }
838 -  
839 - // ---- ① 总稼动率 ----  
840 long totalActive = totalS1 + totalS2 + totalS3; 568 long totalActive = totalS1 + totalS2 + totalS3;
841 - double overallAvailabilityRate = totalActive > 0  
842 - ? Math.round(totalS3 * 10000.0 / totalActive) / 100.0 : 0.0;  
843 -  
844 - // ---- ② 当前设备运行状态(从energy表查) ----  
845 - Map<String, Integer> currentStatus = queryCurrentRunStatus();  
846 -  
847 - // ---- ③ 异常机台排名(按 停机+待机 降序) ----  
848 - deviceList.sort((a, b) -> Long.compare(  
849 - ((Number) b.get("_abnormalDur")).longValue(),  
850 - ((Number) a.get("_abnormalDur")).longValue()  
851 - ));  
852 - // 移除辅助字段  
853 - for (Map<String, Object> d : deviceList) {  
854 - d.remove("_abnormalDur");  
855 - }  
856 -  
857 - return Map.of(  
858 - "code", 200, "msg", "请求成功", "data",  
859 - Map.of(  
860 - "summary", Map.of(  
861 - "availabilityRate", String.format("%.2f%%", overallAvailabilityRate),  
862 - "availabilityRateValue", overallAvailabilityRate,  
863 - "totalDevices", deviceNameMap.size(),  
864 - "totalKwh", Math.round(totalKwhSum * 100.0) / 100.0,  
865 - "totalStatusDuration", Map.of(  
866 - "status0", Map.of(  
867 - "durationFormatted", formatDuration(totalS0),  
868 - "durationSeconds", totalS0,  
869 - "durationHours", formatDurationToHours(totalS0)  
870 - ),  
871 - "status1", Map.of(  
872 - "durationFormatted", formatDuration(totalS1),  
873 - "durationSeconds", totalS1,  
874 - "durationHours", formatDurationToHours(totalS1)  
875 - ),  
876 - "status2", Map.of(  
877 - "durationFormatted", formatDuration(totalS2),  
878 - "durationSeconds", totalS2,  
879 - "durationHours", formatDurationToHours(totalS2)  
880 - ),  
881 - "status3", Map.of(  
882 - "durationFormatted", formatDuration(totalS3),  
883 - "durationSeconds", totalS3,  
884 - "durationHours", formatDurationToHours(totalS3)  
885 - )  
886 - )  
887 - ),  
888 - "currentStatus", currentStatus,  
889 - "abnormalRanking", deviceList,  
890 - "deviceList", deviceList  
891 - )  
892 - ); 569 + double overallAvailabilityRate = totalActive > 0 ? Math.round(totalS3 * 10000.0 / totalActive) / 100.0 : 0.0;
  570 + Map<String, Integer> currentStatus = queryCurrentRunStatus(corpCode);
  571 + deviceList.sort((a, b) -> Long.compare(((Number) b.get("_abnormalDur")).longValue(), ((Number) a.get("_abnormalDur")).longValue()));
  572 + for (Map<String, Object> d : deviceList) d.remove("_abnormalDur");
  573 + return Map.of("code", 200, "msg", "请求成功", "data", Map.of(
  574 + "summary", Map.of("availabilityRate", String.format("%.2f%%", overallAvailabilityRate), "availabilityRateValue", overallAvailabilityRate,
  575 + "totalDevices", deviceNameMap.size(), "totalKwh", Math.round(totalKwhSum * 100.0) / 100.0,
  576 + "totalStatusDuration", Map.of("status0", Map.of("durationFormatted", formatDuration(totalS0), "durationSeconds", totalS0, "durationHours", formatDurationToHours(totalS0)),
  577 + "status1", Map.of("durationFormatted", formatDuration(totalS1), "durationSeconds", totalS1, "durationHours", formatDurationToHours(totalS1)),
  578 + "status2", Map.of("durationFormatted", formatDuration(totalS2), "durationSeconds", totalS2, "durationHours", formatDurationToHours(totalS2)),
  579 + "status3", Map.of("durationFormatted", formatDuration(totalS3), "durationSeconds", totalS3, "durationHours", formatDurationToHours(totalS3))),
  580 + "currentStatus", currentStatus, "abnormalRanking", deviceList, "deviceList", deviceList)));
893 } 581 }
894 582
895 - /**  
896 - * 查询当前设备运行状态分布(从energy表) runStatus: 0-离线, 1-停机, 2-待机, 3-运行  
897 - */  
898 - private Map<String, Integer> queryCurrentRunStatus() {  
899 - String sql = "SELECT runStatus, COUNT(*) as cnt FROM " + energyTableName +  
900 - " WHERE corp_code = ? GROUP BY runStatus";  
901 - List<Map<String, Object>> rows = jdbcTemplate.queryForList(sql, energyCorpCode);  
902 - 583 + private Map<String, Integer> queryCurrentRunStatus(String corpCode) {
  584 + String energyTableName = corpConfigService.getEnergyTableName(corpCode);
  585 + JdbcTemplate jt = corpConfigService.getJdbcTemplate(corpCode);
  586 + String sql = "SELECT runStatus, COUNT(*) as cnt FROM " + energyTableName + " WHERE corp_code = ? GROUP BY runStatus";
  587 + List<Map<String, Object>> rows = jt.queryForList(sql, corpCode);
903 int s0 = 0, s1 = 0, s2 = 0, s3 = 0; 588 int s0 = 0, s1 = 0, s2 = 0, s3 = 0;
904 for (Map<String, Object> row : rows) { 589 for (Map<String, Object> row : rows) {
905 String key = String.valueOf(row.get("runStatus")); 590 String key = String.valueOf(row.get("runStatus"));
@@ -914,46 +599,22 @@ public class EnergySearchService { @@ -914,46 +599,22 @@ public class EnergySearchService {
914 return Map.of("0", s0, "1", s1, "2", s2, "3", s3); 599 return Map.of("0", s0, "1", s1, "2", s2, "3", s3);
915 } 600 }
916 601
917 - // ==================== eq_kwh 多设备时/日/月查询 ====================  
918 -  
919 - /**  
920 - * 查询 eq_kwh 表的多设备能耗数据(按 时/日/月 聚合)  
921 - * <p>  
922 - * type=1 (时): 只需传 startDate,返回该日所有设备的原始用电量明细(kwhList)  
923 - * type=2 (日):  
924 - * - 若传了 startDate+endDate: 按此范围每日统计每台设备能耗  
925 - * - 若只传 startDate: 自动补全为当月的第1天~最后一天  
926 - * type=3 (月): 自动取本年1月~当前月,按月统计每台设备能耗  
927 - *  
928 - * @param type 查询类型: 1-时, 2-日, 3-月  
929 - * @param startDate 开始日期 yyyy-MM-dd (type=1,2必填; type=3可选)  
930 - * @param endDate 结束日期 yyyy-MM-dd (type=2可选)  
931 - */  
932 - public Map<String, Object> queryEqKwhByType(String type, String startDate, String endDate) {  
933 - log.info("========== [eq_kwh多设备查询] type={}, startDate={}, endDate={} ==========", type, startDate, endDate); 602 + // ==================== eq_kwh 多设备查询 ====================
934 603
  604 + public Map<String, Object> queryEqKwhByType(String corpCode, String type, String startDate, String endDate) {
  605 + log.info("========== [eq_kwh多设备查询] corpCode={}, type={}, startDate={}, endDate={} ==========", corpCode, type, startDate, endDate);
935 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); 606 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
936 List<String> dateList = new ArrayList<>(); 607 List<String> dateList = new ArrayList<>();
937 -  
938 - // 根据type构建日期列表 + 实际起止日期  
939 String actualStart; 608 String actualStart;
940 String actualEnd; 609 String actualEnd;
941 -  
942 if ("1".equals(type)) { 610 if ("1".equals(type)) {
943 - // type=1: 单日查询,直接返回原始kwh数据  
944 - if (!StringUtils.hasText(startDate)) {  
945 - return Map.of("code", 400, "msg", "参数错误: type=1时startDate必填");  
946 - } 611 + if (!StringUtils.hasText(startDate)) return Map.of("code", 400, "msg", "参数错误: type=1时startDate必填");
947 dateList.add(startDate); 612 dateList.add(startDate);
948 actualStart = startDate; 613 actualStart = startDate;
949 actualEnd = startDate; 614 actualEnd = startDate;
950 } else if ("2".equals(type)) { 615 } else if ("2".equals(type)) {
951 - // type=2: 按日统计  
952 - if (!StringUtils.hasText(startDate)) {  
953 - return Map.of("code", 400, "msg", "参数错误: type=2时startDate必填");  
954 - } 616 + if (!StringUtils.hasText(startDate)) return Map.of("code", 400, "msg", "参数错误: type=2时startDate必填");
955 if (StringUtils.hasText(endDate)) { 617 if (StringUtils.hasText(endDate)) {
956 - // 有结束日期,直接用传入范围  
957 try { 618 try {
958 Date start = sdf.parse(startDate); 619 Date start = sdf.parse(startDate);
959 Date end = sdf.parse(endDate); 620 Date end = sdf.parse(endDate);
@@ -969,19 +630,17 @@ public class EnergySearchService { @@ -969,19 +630,17 @@ public class EnergySearchService {
969 return Map.of("code", 400, "msg", "日期格式错误: " + startDate + " ~ " + endDate); 630 return Map.of("code", 400, "msg", "日期格式错误: " + startDate + " ~ " + endDate);
970 } 631 }
971 } else { 632 } else {
972 - // 只有开始日期 -> 自动取所在月的1号~最后一天  
973 try { 633 try {
974 Date startD = sdf.parse(startDate); 634 Date startD = sdf.parse(startDate);
975 Calendar cal = Calendar.getInstance(); 635 Calendar cal = Calendar.getInstance();
976 cal.setTime(startD); 636 cal.setTime(startD);
977 - cal.set(Calendar.DAY_OF_MONTH, 1); // 月初 637 + cal.set(Calendar.DAY_OF_MONTH, 1);
978 actualStart = sdf.format(cal.getTime()); 638 actualStart = sdf.format(cal.getTime());
979 - cal.set(Calendar.DAY_OF_MONTH, cal.getActualMaximum(Calendar.DAY_OF_MONTH)); // 月末 639 + cal.set(Calendar.DAY_OF_MONTH, cal.getActualMaximum(Calendar.DAY_OF_MONTH));
980 actualEnd = sdf.format(cal.getTime()); 640 actualEnd = sdf.format(cal.getTime());
981 -  
982 Calendar cur = Calendar.getInstance(); 641 Calendar cur = Calendar.getInstance();
983 cur.setTime(sdf.parse(actualStart)); 642 cur.setTime(sdf.parse(actualStart));
984 - while (!cur.after(cal)) { // cur <= actualEnd 643 + while (!cur.after(cal)) {
985 dateList.add(sdf.format(cur.getTime())); 644 dateList.add(sdf.format(cur.getTime()));
986 cur.add(Calendar.DAY_OF_MONTH, 1); 645 cur.add(Calendar.DAY_OF_MONTH, 1);
987 } 646 }
@@ -990,9 +649,7 @@ public class EnergySearchService { @@ -990,9 +649,7 @@ public class EnergySearchService {
990 } 649 }
991 } 650 }
992 } else if ("3".equals(type)) { 651 } else if ("3".equals(type)) {
993 - // type=3: 按月统计  
994 if (StringUtils.hasText(startDate) && StringUtils.hasText(endDate)) { 652 if (StringUtils.hasText(startDate) && StringUtils.hasText(endDate)) {
995 - // 有起止日期:按传入范围按月聚合  
996 try { 653 try {
997 Date start = sdf.parse(startDate); 654 Date start = sdf.parse(startDate);
998 Date end = sdf.parse(endDate); 655 Date end = sdf.parse(endDate);
@@ -1008,14 +665,12 @@ public class EnergySearchService { @@ -1008,14 +665,12 @@ public class EnergySearchService {
1008 return Map.of("code", 400, "msg", "日期格式错误: " + startDate + " ~ " + endDate); 665 return Map.of("code", 400, "msg", "日期格式错误: " + startDate + " ~ " + endDate);
1009 } 666 }
1010 } else { 667 } else {
1011 - // 无日期:默认本年1月1日 ~ 今天  
1012 Calendar now = Calendar.getInstance(); 668 Calendar now = Calendar.getInstance();
1013 int year = now.get(Calendar.YEAR); 669 int year = now.get(Calendar.YEAR);
1014 Calendar startCal = Calendar.getInstance(); 670 Calendar startCal = Calendar.getInstance();
1015 startCal.set(year, Calendar.JANUARY, 1); 671 startCal.set(year, Calendar.JANUARY, 1);
1016 actualStart = sdf.format(startCal.getTime()); 672 actualStart = sdf.format(startCal.getTime());
1017 actualEnd = sdf.format(now.getTime()); 673 actualEnd = sdf.format(now.getTime());
1018 -  
1019 Calendar cur = Calendar.getInstance(); 674 Calendar cur = Calendar.getInstance();
1020 cur.setTime(startCal.getTime()); 675 cur.setTime(startCal.getTime());
1021 while (!cur.getTime().after(now.getTime())) { 676 while (!cur.getTime().after(now.getTime())) {
@@ -1026,28 +681,13 @@ public class EnergySearchService { @@ -1026,28 +681,13 @@ public class EnergySearchService {
1026 } else { 681 } else {
1027 return Map.of("code", 400, "msg", "参数错误: type只支持1/2/3"); 682 return Map.of("code", 400, "msg", "参数错误: type只支持1/2/3");
1028 } 683 }
1029 -  
1030 log.info("实际日期范围: {} ~ {}, 共{}天", actualStart, actualEnd, dateList.size()); 684 log.info("实际日期范围: {} ~ {}, 共{}天", actualStart, actualEnd, dateList.size());
1031 -  
1032 - // 获取所有设备列表及名称  
1033 - Map<String, String> deviceNameMap = queryAllEnergyDeviceNames();  
1034 -  
1035 - // 从 eq_kwh 批量查询所有记录  
1036 - List<Map<String, Object>> allRawData = queryEqKwhBatch(dateList);  
1037 - log.info("eq_kwh 批量查询返回 {} 条原始记录", allRawData.size());  
1038 -  
1039 - // 构建结果  
1040 - return buildEqKwhByTypeResult(type, dateList, allRawData, deviceNameMap, actualStart, actualEnd); 685 + Map<String, String> deviceNameMap = queryAllEnergyDeviceNames(corpCode);
  686 + List<Map<String, Object>> allRawData = queryEqKwhBatch(corpCode, dateList);
  687 + return buildEqKwhByTypeResult(corpCode, type, dateList, allRawData, deviceNameMap, actualStart, actualEnd);
1041 } 688 }
1042 689
1043 - /**  
1044 - * 构建 type=1/2/3 的多设备查询结果  
1045 - */  
1046 - private Map<String, Object> buildEqKwhByTypeResult(String type, List<String> dateList,  
1047 - List<Map<String, Object>> allRawData,  
1048 - Map<String, String> deviceNameMap,  
1049 - String actualStart, String actualEnd) {  
1050 - // 按 dtuSn+日期 建立快速查找Map: key="dtuSn|yyyy-MM-dd" -> JSONArray(kwh原始数据) 690 + private Map<String, Object> buildEqKwhByTypeResult(String corpCode, String type, List<String> dateList, List<Map<String, Object>> allRawData, Map<String, String> deviceNameMap, String actualStart, String actualEnd) {
1051 Map<String, Object> rawDataMap = new LinkedHashMap<>(); 691 Map<String, Object> rawDataMap = new LinkedHashMap<>();
1052 for (Map<String, Object> row : allRawData) { 692 for (Map<String, Object> row : allRawData) {
1053 String sn = (String) row.get("dtuSn"); 693 String sn = (String) row.get("dtuSn");
@@ -1055,56 +695,32 @@ public class EnergySearchService { @@ -1055,56 +695,32 @@ public class EnergySearchService {
1055 String desc = row.get("description") != null ? String.valueOf(row.get("description")) : ""; 695 String desc = row.get("description") != null ? String.valueOf(row.get("description")) : "";
1056 if (StringUtils.hasText(desc)) { 696 if (StringUtils.hasText(desc)) {
1057 try { 697 try {
1058 - // use_date 可能是 "2026-05-21T00:00:00" 或 "2026-05-21 00:00:00",统一截取前10位作为纯日期key  
1059 String dateKey = ud.length() > 10 ? ud.substring(0, 10) : ud; 698 String dateKey = ud.length() > 10 ? ud.substring(0, 10) : ud;
1060 rawDataMap.put(sn + "|" + dateKey, JSON.parseArray(desc)); 699 rawDataMap.put(sn + "|" + dateKey, JSON.parseArray(desc));
1061 } catch (Exception ignored) { 700 } catch (Exception ignored) {
1062 } 701 }
1063 } 702 }
1064 } 703 }
1065 -  
1066 - // ---- type=1: 返回所有设备的原始kwh明细 ----  
1067 - if ("1".equals(type)) {  
1068 - return buildType1Result(dateList.get(0), rawDataMap, deviceNameMap);  
1069 - }  
1070 -  
1071 - // ---- type=2: 按日统计 ----  
1072 - if ("2".equals(type)) {  
1073 - return buildType2Result(dateList, rawDataMap, deviceNameMap, actualStart, actualEnd);  
1074 - }  
1075 -  
1076 - // ---- type=3: 按月统计 ----  
1077 - if ("3".equals(type)) {  
1078 - return buildType3Result(dateList, rawDataMap, deviceNameMap, actualStart, actualEnd);  
1079 - }  
1080 - 704 + if ("1".equals(type)) return buildType1Result(dateList.get(0), rawDataMap, deviceNameMap);
  705 + if ("2".equals(type)) return buildType2Result(dateList, rawDataMap, deviceNameMap, actualStart, actualEnd);
  706 + if ("3".equals(type)) return buildType3Result(dateList, rawDataMap, deviceNameMap, actualStart, actualEnd);
1081 return Map.of("code", 500, "msg", "未知type"); 707 return Map.of("code", 500, "msg", "未知type");
1082 } 708 }
1083 709
1084 - /**  
1085 - * type=1 (时): 单日查询 - 返回每个设备的 kwh 原始数据 + 当日汇总  
1086 - */  
1087 - private Map<String, Object> buildType1Result(String dateStr, Map<String, Object> rawDataMap,  
1088 - Map<String, String> deviceNameMap) { 710 + private Map<String, Object> buildType1Result(String dateStr, Map<String, Object> rawDataMap, Map<String, String> deviceNameMap) {
1089 List<Map<String, Object>> list = new ArrayList<>(); 711 List<Map<String, Object>> list = new ArrayList<>();
1090 BigDecimal totalKwhAll = BigDecimal.ZERO; 712 BigDecimal totalKwhAll = BigDecimal.ZERO;
1091 -  
1092 for (String sn : deviceNameMap.keySet()) { 713 for (String sn : deviceNameMap.keySet()) {
1093 String mapKey = sn + "|" + dateStr; 714 String mapKey = sn + "|" + dateStr;
1094 Object rawObj = rawDataMap.getOrDefault(mapKey, Collections.emptyList()); 715 Object rawObj = rawDataMap.getOrDefault(mapKey, Collections.emptyList());
1095 - @SuppressWarnings("unchecked")  
1096 - JSONArray dataArray = rawObj instanceof JSONArray ? (JSONArray) rawObj : new JSONArray();  
1097 -  
1098 - // 统计当日总用电量 716 + @SuppressWarnings("unchecked") JSONArray dataArray = rawObj instanceof JSONArray ? (JSONArray) rawObj : new JSONArray();
1099 BigDecimal dayKwh = BigDecimal.ZERO; 717 BigDecimal dayKwh = BigDecimal.ZERO;
1100 for (int i = 0; i < dataArray.size(); i++) { 718 for (int i = 0; i < dataArray.size(); i++) {
1101 JSONObject item = dataArray.getJSONObject(i); 719 JSONObject item = dataArray.getJSONObject(i);
1102 - if (item != null && item.getDouble("value") != null) { 720 + if (item != null && item.getDouble("value") != null)
1103 dayKwh = dayKwh.add(BigDecimal.valueOf(item.getDouble("value"))); 721 dayKwh = dayKwh.add(BigDecimal.valueOf(item.getDouble("value")));
1104 - }  
1105 } 722 }
1106 totalKwhAll = totalKwhAll.add(dayKwh); 723 totalKwhAll = totalKwhAll.add(dayKwh);
1107 -  
1108 Map<String, Object> item = new LinkedHashMap<>(); 724 Map<String, Object> item = new LinkedHashMap<>();
1109 item.put("dtuSn", sn); 725 item.put("dtuSn", sn);
1110 item.put("deviceName", deviceNameMap.getOrDefault(sn, "")); 726 item.put("deviceName", deviceNameMap.getOrDefault(sn, ""));
@@ -1113,67 +729,44 @@ public class EnergySearchService { @@ -1113,67 +729,44 @@ public class EnergySearchService {
1113 item.put("totalKwh", dayKwh.setScale(2, RoundingMode.HALF_UP)); 729 item.put("totalKwh", dayKwh.setScale(2, RoundingMode.HALF_UP));
1114 list.add(item); 730 list.add(item);
1115 } 731 }
1116 -  
1117 - return Map.of(  
1118 - "code", 200, "msg", "请求成功",  
1119 - "type", "1",  
1120 - "date", dateStr,  
1121 - "totalDevices", deviceNameMap.size(),  
1122 - "totalKwh", totalKwhAll.setScale(2, RoundingMode.HALF_UP),  
1123 - "list", list  
1124 - ); 732 + return Map.of("code", 200, "msg", "请求成功", "type", "1", "date", dateStr, "totalDevices", deviceNameMap.size(), "totalKwh", totalKwhAll.setScale(2, RoundingMode.HALF_UP), "list", list);
1125 } 733 }
1126 734
1127 - /**  
1128 - * type=2 (日): 按设备统计 - 每个设备一行,包含该设备每天的能耗明细  
1129 - */  
1130 - private Map<String, Object> buildType2Result(List<String> dateList, Map<String, Object> rawDataMap,  
1131 - Map<String, String> deviceNameMap,  
1132 - String actualStart, String actualEnd) { 735 + private Map<String, Object> buildType2Result(List<String> dateList, Map<String, Object> rawDataMap, Map<String, String> deviceNameMap, String actualStart, String actualEnd) {
1133 BigDecimal grandTotalKwh = BigDecimal.ZERO; 736 BigDecimal grandTotalKwh = BigDecimal.ZERO;
1134 List<Map<String, Object>> deviceList = new ArrayList<>(deviceNameMap.size()); 737 List<Map<String, Object>> deviceList = new ArrayList<>(deviceNameMap.size());
1135 -  
1136 for (String sn : deviceNameMap.keySet()) { 738 for (String sn : deviceNameMap.keySet()) {
1137 Map<String, Object> devItem = new LinkedHashMap<>(); 739 Map<String, Object> devItem = new LinkedHashMap<>();
1138 devItem.put("dtuSn", sn); 740 devItem.put("dtuSn", sn);
1139 devItem.put("deviceName", deviceNameMap.getOrDefault(sn, "")); 741 devItem.put("deviceName", deviceNameMap.getOrDefault(sn, ""));
1140 -  
1141 - // 该设备的每日数据列表  
1142 List<Map<String, Object>> dailyDataList = new ArrayList<>(dateList.size()); 742 List<Map<String, Object>> dailyDataList = new ArrayList<>(dateList.size());
1143 BigDecimal devTotalKwh = BigDecimal.ZERO; 743 BigDecimal devTotalKwh = BigDecimal.ZERO;
1144 long devTotalDur = 0; 744 long devTotalDur = 0;
1145 Map<Integer, Long> devStatusAll = initStatusMap(); 745 Map<Integer, Long> devStatusAll = initStatusMap();
1146 -  
1147 for (String d : dateList) { 746 for (String d : dateList) {
1148 String mapKey = sn + "|" + d; 747 String mapKey = sn + "|" + d;
1149 Object rawObj = rawDataMap.getOrDefault(mapKey, Collections.emptyList()); 748 Object rawObj = rawDataMap.getOrDefault(mapKey, Collections.emptyList());
1150 - @SuppressWarnings("unchecked")  
1151 - JSONArray dataArray = rawObj instanceof JSONArray ? (JSONArray) rawObj : new JSONArray();  
1152 - 749 + @SuppressWarnings("unchecked") JSONArray dataArray = rawObj instanceof JSONArray ? (JSONArray) rawObj : new JSONArray();
1153 BigDecimal dayKwh = BigDecimal.ZERO; 750 BigDecimal dayKwh = BigDecimal.ZERO;
1154 long dayDur = 0; 751 long dayDur = 0;
1155 Map<Integer, Long> dayStatus = initStatusMap(); 752 Map<Integer, Long> dayStatus = initStatusMap();
1156 -  
1157 for (int i = 0; i < dataArray.size(); i++) { 753 for (int i = 0; i < dataArray.size(); i++) {
1158 JSONObject item = dataArray.getJSONObject(i); 754 JSONObject item = dataArray.getJSONObject(i);
1159 if (item == null) continue; 755 if (item == null) continue;
1160 -  
1161 Double value = item.getDouble("value"); 756 Double value = item.getDouble("value");
1162 if (value != null) dayKwh = dayKwh.add(BigDecimal.valueOf(value)); 757 if (value != null) dayKwh = dayKwh.add(BigDecimal.valueOf(value));
1163 -  
1164 for (int sk = 0; sk <= 3; sk++) { 758 for (int sk = 0; sk <= 3; sk++) {
1165 Long dur = item.getLong(String.valueOf(sk)); 759 Long dur = item.getLong(String.valueOf(sk));
1166 if (dur != null && dur > 0) { 760 if (dur != null && dur > 0) {
1167 dayDur += dur; 761 dayDur += dur;
1168 - dayStatus.merge(sk, dur, Long::sum);  
1169 devTotalDur += dur; 762 devTotalDur += dur;
  763 + dayStatus.merge(sk, dur, Long::sum);
1170 devStatusAll.merge(sk, dur, Long::sum); 764 devStatusAll.merge(sk, dur, Long::sum);
1171 } 765 }
1172 } 766 }
1173 } 767 }
1174 -  
1175 devTotalKwh = devTotalKwh.add(dayKwh); 768 devTotalKwh = devTotalKwh.add(dayKwh);
1176 - 769 + grandTotalKwh = grandTotalKwh.add(devTotalKwh);
1177 Map<String, Object> dayEntry = new LinkedHashMap<>(); 770 Map<String, Object> dayEntry = new LinkedHashMap<>();
1178 dayEntry.put("date", d); 771 dayEntry.put("date", d);
1179 dayEntry.put("totalKwh", dayKwh.setScale(2, RoundingMode.HALF_UP)); 772 dayEntry.put("totalKwh", dayKwh.setScale(2, RoundingMode.HALF_UP));
@@ -1182,50 +775,27 @@ public class EnergySearchService { @@ -1182,50 +775,27 @@ public class EnergySearchService {
1182 dayEntry.put("statusStats", buildStatusStats(dayStatus, dayDur)); 775 dayEntry.put("statusStats", buildStatusStats(dayStatus, dayDur));
1183 dailyDataList.add(dayEntry); 776 dailyDataList.add(dayEntry);
1184 } 777 }
1185 -  
1186 - grandTotalKwh = grandTotalKwh.add(devTotalKwh);  
1187 -  
1188 devItem.put("totalKwh", devTotalKwh.setScale(2, RoundingMode.HALF_UP)); 778 devItem.put("totalKwh", devTotalKwh.setScale(2, RoundingMode.HALF_UP));
1189 devItem.put("totalDurationFormatted", formatDuration(devTotalDur)); 779 devItem.put("totalDurationFormatted", formatDuration(devTotalDur));
1190 devItem.put("totalDurationSeconds", devTotalDur); 780 devItem.put("totalDurationSeconds", devTotalDur);
1191 devItem.put("statusStats", buildStatusStats(devStatusAll, devTotalDur)); 781 devItem.put("statusStats", buildStatusStats(devStatusAll, devTotalDur));
1192 devItem.put("dailyData", dailyDataList); 782 devItem.put("dailyData", dailyDataList);
1193 -  
1194 deviceList.add(devItem); 783 deviceList.add(devItem);
1195 } 784 }
1196 -  
1197 - return Map.of(  
1198 - "code", 200, "msg", "请求成功",  
1199 - "type", "2",  
1200 - "actualStartDate", actualStart,  
1201 - "actualEndDate", actualEnd,  
1202 - "totalDays", dateList.size(),  
1203 - "totalDevices", deviceList.size(),  
1204 - "grandTotalKwh", grandTotalKwh.setScale(2, RoundingMode.HALF_UP),  
1205 - "list", deviceList  
1206 - ); 785 + return Map.of("code", 200, "msg", "请求成功", "type", "2", "actualStartDate", actualStart, "actualEndDate", actualEnd,
  786 + "totalDays", dateList.size(), "totalDevices", deviceList.size(), "grandTotalKwh", grandTotalKwh.setScale(2, RoundingMode.HALF_UP), "list", deviceList);
1207 } 787 }
1208 788
1209 - /**  
1210 - * type=3 (月): 按设备统计 - 每个设备一行,包含该设备每月的能耗明细  
1211 - */  
1212 - private Map<String, Object> buildType3Result(List<String> dateList, Map<String, Object> rawDataMap,  
1213 - Map<String, String> deviceNameMap,  
1214 - String actualStart, String actualEnd) { 789 + private Map<String, Object> buildType3Result(List<String> dateList, Map<String, Object> rawDataMap, Map<String, String> deviceNameMap, String actualStart, String actualEnd) {
1215 BigDecimal grandTotalKwh = BigDecimal.ZERO; 790 BigDecimal grandTotalKwh = BigDecimal.ZERO;
1216 List<Map<String, Object>> deviceList = new ArrayList<>(deviceNameMap.size()); 791 List<Map<String, Object>> deviceList = new ArrayList<>(deviceNameMap.size());
1217 -  
1218 for (String sn : deviceNameMap.keySet()) { 792 for (String sn : deviceNameMap.keySet()) {
1219 Map<String, Object> devItem = new LinkedHashMap<>(); 793 Map<String, Object> devItem = new LinkedHashMap<>();
1220 devItem.put("dtuSn", sn); 794 devItem.put("dtuSn", sn);
1221 devItem.put("deviceName", deviceNameMap.getOrDefault(sn, "")); 795 devItem.put("deviceName", deviceNameMap.getOrDefault(sn, ""));
1222 -  
1223 - // 该设备的按月聚合数据  
1224 Map<String, Map<String, Object>> monthAgg = new LinkedHashMap<>(); 796 Map<String, Map<String, Object>> monthAgg = new LinkedHashMap<>();
1225 -  
1226 for (String d : dateList) { 797 for (String d : dateList) {
1227 String monthKey = d.substring(0, 7); 798 String monthKey = d.substring(0, 7);
1228 -  
1229 monthAgg.computeIfAbsent(monthKey, k -> { 799 monthAgg.computeIfAbsent(monthKey, k -> {
1230 Map<String, Object> m = new LinkedHashMap<>(); 800 Map<String, Object> m = new LinkedHashMap<>();
1231 m.put("month", k); 801 m.put("month", k);
@@ -1235,18 +805,15 @@ public class EnergySearchService { @@ -1235,18 +805,15 @@ public class EnergySearchService {
1235 m.put("statusDurationMap", initStatusMap()); 805 m.put("statusDurationMap", initStatusMap());
1236 return m; 806 return m;
1237 }); 807 });
1238 -  
1239 String mapKey = sn + "|" + d; 808 String mapKey = sn + "|" + d;
1240 Object rawObj = rawDataMap.getOrDefault(mapKey, Collections.emptyList()); 809 Object rawObj = rawDataMap.getOrDefault(mapKey, Collections.emptyList());
1241 @SuppressWarnings("unchecked") 810 @SuppressWarnings("unchecked")
1242 JSONArray dataArray = rawObj instanceof JSONArray ? (JSONArray) rawObj : new JSONArray(); 811 JSONArray dataArray = rawObj instanceof JSONArray ? (JSONArray) rawObj : new JSONArray();
1243 812
1244 Map<String, Object> mEntry = monthAgg.get(monthKey); 813 Map<String, Object> mEntry = monthAgg.get(monthKey);
1245 -  
1246 for (int i = 0; i < dataArray.size(); i++) { 814 for (int i = 0; i < dataArray.size(); i++) {
1247 JSONObject item = dataArray.getJSONObject(i); 815 JSONObject item = dataArray.getJSONObject(i);
1248 if (item == null) continue; 816 if (item == null) continue;
1249 -  
1250 Double value = item.getDouble("value"); 817 Double value = item.getDouble("value");
1251 if (value != null) { 818 if (value != null) {
1252 BigDecimal valBd = BigDecimal.valueOf(value); 819 BigDecimal valBd = BigDecimal.valueOf(value);
@@ -1270,21 +837,17 @@ public class EnergySearchService { @@ -1270,21 +837,17 @@ public class EnergySearchService {
1270 BigDecimal devTotalKwh = BigDecimal.ZERO; 837 BigDecimal devTotalKwh = BigDecimal.ZERO;
1271 long devTotalDur = 0; 838 long devTotalDur = 0;
1272 Map<Integer, Long> devStatusAll = initStatusMap(); 839 Map<Integer, Long> devStatusAll = initStatusMap();
1273 -  
1274 for (Map.Entry<String, Map<String, Object>> me : monthAgg.entrySet()) { 840 for (Map.Entry<String, Map<String, Object>> me : monthAgg.entrySet()) {
1275 Map<String, Object> m = me.getValue(); 841 Map<String, Object> m = me.getValue();
1276 long mDur = (Long) m.get("totalDurationSeconds"); 842 long mDur = (Long) m.get("totalDurationSeconds");
1277 BigDecimal mKwh = (BigDecimal) m.get("totalKwh"); 843 BigDecimal mKwh = (BigDecimal) m.get("totalKwh");
1278 - @SuppressWarnings("unchecked")  
1279 - Map<Integer, Long> mStatus = (Map<Integer, Long>) m.get("statusDurationMap");  
1280 - 844 + @SuppressWarnings("unchecked") Map<Integer, Long> mStatus = (Map<Integer, Long>) m.get("statusDurationMap");
1281 devTotalKwh = devTotalKwh.add(mKwh); 845 devTotalKwh = devTotalKwh.add(mKwh);
1282 devTotalDur += mDur; 846 devTotalDur += mDur;
1283 for (int sk = 0; sk <= 3; sk++) { 847 for (int sk = 0; sk <= 3; sk++) {
1284 long sd = mStatus.getOrDefault(sk, 0L); 848 long sd = mStatus.getOrDefault(sk, 0L);
1285 if (sd > 0) devStatusAll.merge(sk, sd, Long::sum); 849 if (sd > 0) devStatusAll.merge(sk, sd, Long::sum);
1286 } 850 }
1287 -  
1288 Map<String, Object> monthEntry = new LinkedHashMap<>(); 851 Map<String, Object> monthEntry = new LinkedHashMap<>();
1289 monthEntry.put("month", m.get("month")); 852 monthEntry.put("month", m.get("month"));
1290 monthEntry.put("label", m.get("label")); 853 monthEntry.put("label", m.get("label"));
@@ -1294,71 +857,37 @@ public class EnergySearchService { @@ -1294,71 +857,37 @@ public class EnergySearchService {
1294 monthEntry.put("statusStats", buildStatusStats(mStatus, mDur)); 857 monthEntry.put("statusStats", buildStatusStats(mStatus, mDur));
1295 monthlyDataList.add(monthEntry); 858 monthlyDataList.add(monthEntry);
1296 } 859 }
1297 -  
1298 grandTotalKwh = grandTotalKwh.add(devTotalKwh); 860 grandTotalKwh = grandTotalKwh.add(devTotalKwh);
1299 -  
1300 devItem.put("totalKwh", devTotalKwh.setScale(2, RoundingMode.HALF_UP)); 861 devItem.put("totalKwh", devTotalKwh.setScale(2, RoundingMode.HALF_UP));
1301 devItem.put("totalDurationFormatted", formatDuration(devTotalDur)); 862 devItem.put("totalDurationFormatted", formatDuration(devTotalDur));
1302 devItem.put("totalDurationSeconds", devTotalDur); 863 devItem.put("totalDurationSeconds", devTotalDur);
1303 devItem.put("statusStats", buildStatusStats(devStatusAll, devTotalDur)); 864 devItem.put("statusStats", buildStatusStats(devStatusAll, devTotalDur));
1304 devItem.put("monthlyData", monthlyDataList); 865 devItem.put("monthlyData", monthlyDataList);
1305 -  
1306 deviceList.add(devItem); 866 deviceList.add(devItem);
1307 } 867 }
1308 -  
1309 - return Map.of(  
1310 - "code", 200, "msg", "请求成功",  
1311 - "type", "3",  
1312 - "year", actualStart.substring(0, 4),  
1313 - "actualStartDate", actualStart,  
1314 - "actualEndDate", actualEnd,  
1315 - "totalMonths", dateList.isEmpty() ? 0 :  
1316 - (dateList.stream().map(d -> d.substring(0, 7)).distinct().toList()).size(),  
1317 - "totalDevices", deviceList.size(),  
1318 - "grandTotalKwh", grandTotalKwh.setScale(2, RoundingMode.HALF_UP),  
1319 - "list", deviceList  
1320 - ); 868 + return Map.of("code", 200, "msg", "请求成功", "type", "3", "year", actualStart.substring(0, 4), "actualStartDate", actualStart,
  869 + "actualEndDate", actualEnd, "totalMonths", dateList.isEmpty() ? 0 : (dateList.stream().map(d -> d.substring(0, 7)).distinct().toList()).size(),
  870 + "totalDevices", deviceList.size(), "grandTotalKwh", grandTotalKwh.setScale(2, RoundingMode.HALF_UP), "list", deviceList);
1321 } 871 }
1322 872
1323 - /** 调试接口: 查看eq_kwh表中的数据概况 */  
1324 - public Map<String, Object> debugEqKwhInfo() {  
1325 - // 总记录数  
1326 - Long totalCount = jdbcTemplate.queryForObject(  
1327 - "SELECT COUNT(*) FROM " + eqKwhTableName + " WHERE corp_code = ?", Long.class, energyCorpCode);  
1328 -  
1329 - // 按日期分组统计  
1330 - List<Map<String, Object>> dateStats = jdbcTemplate.queryForList(  
1331 - "SELECT use_date, COUNT(*) as cnt FROM " + eqKwhTableName +  
1332 - " WHERE corp_code = ? GROUP BY use_date ORDER BY use_date DESC LIMIT 20",  
1333 - energyCorpCode);  
1334 -  
1335 - // 按设备分组统计  
1336 - List<Map<String, Object>> deviceStats = jdbcTemplate.queryForList(  
1337 - "SELECT dtuSn, COUNT(*) as cnt FROM " + eqKwhTableName +  
1338 - " WHERE corp_code = ? GROUP BY dtuSn ORDER BY dtuSn",  
1339 - energyCorpCode);  
1340 -  
1341 - // 最新一条记录的 description 预览 873 + /**
  874 + * 调试接口
  875 + */
  876 + public Map<String, Object> debugEqKwhInfo(String corpCode) {
  877 + String eqKwhTableName = corpConfigService.getEqKwhTableName(corpCode);
  878 + String energyTableName = corpConfigService.getEnergyTableName(corpCode);
  879 + JdbcTemplate jt = corpConfigService.getJdbcTemplate(corpCode);
  880 + Long totalCount = jt.queryForObject("SELECT COUNT(*) FROM " + eqKwhTableName + " WHERE corp_code = ?", Long.class, corpCode);
  881 + List<Map<String, Object>> dateStats = jt.queryForList("SELECT use_date, COUNT(*) as cnt FROM " + eqKwhTableName + " WHERE corp_code = ? GROUP BY use_date ORDER BY use_date DESC LIMIT 20", corpCode);
  882 + List<Map<String, Object>> deviceStats = jt.queryForList("SELECT dtuSn, COUNT(*) as cnt FROM " + eqKwhTableName + " WHERE corp_code = ? GROUP BY dtuSn ORDER BY dtuSn", corpCode);
1342 Map<String, Object> lastRecord = null; 883 Map<String, Object> lastRecord = null;
1343 try { 884 try {
1344 - String sql = "SELECT dtuSn, use_date, LEFT(description, 500) AS desc_preview, LENGTH(description) as desc_len " +  
1345 - "FROM " + eqKwhTableName + " WHERE corp_code = ? ORDER BY use_date DESC LIMIT 1";  
1346 - lastRecord = jdbcTemplate.queryForMap(sql, energyCorpCode);  
1347 - } catch (Exception ignored) {}  
1348 -  
1349 - // energy 表设备数  
1350 - Long deviceCount = jdbcTemplate.queryForObject(  
1351 - "SELECT COUNT(*) FROM " + energyTableName + " WHERE corp_code = ?", Long.class, energyCorpCode);  
1352 -  
1353 - return Map.of(  
1354 - "code", 200, "msg", "请求成功",  
1355 - "tableName", eqKwhTableName,  
1356 - "corpCode", energyCorpCode,  
1357 - "totalRecords", totalCount != null ? totalCount : 0,  
1358 - "deviceCountInEnergyTable", deviceCount != null ? deviceCount : 0,  
1359 - "latestDateRecords", dateStats,  
1360 - "perDeviceRecordCount", deviceStats,  
1361 - "lastRecordPreview", lastRecord  
1362 - ); 885 + String sql = "SELECT dtuSn, use_date, LEFT(description, 500) AS desc_preview, LENGTH(description) as desc_len FROM " + eqKwhTableName + " WHERE corp_code = ? ORDER BY use_date DESC LIMIT 1";
  886 + lastRecord = jt.queryForMap(sql, corpCode);
  887 + } catch (Exception ignored) {
  888 + }
  889 + Long deviceCount = jt.queryForObject("SELECT COUNT(*) FROM " + energyTableName + " WHERE corp_code = ?", Long.class, corpCode);
  890 + return Map.of("code", 200, "msg", "请求成功", "tableName", eqKwhTableName, "corpCode", corpCode, "totalRecords", totalCount != null ? totalCount : 0,
  891 + "deviceCountInEnergyTable", deviceCount != null ? deviceCount : 0, "latestDateRecords", dateStats, "perDeviceRecordCount", deviceStats, "lastRecordPreview", lastRecord);
1363 } 892 }
1364 } 893 }
@@ -89,3 +89,8 @@ energy: @@ -89,3 +89,8 @@ energy:
89 eRunDtlTableName: "t_auto_ymk_iot_e_run_dtl" 89 eRunDtlTableName: "t_auto_ymk_iot_e_run_dtl"
90 runStatus: 90 runStatus:
91 url: "https://iotgc.cniot.vip/api/energy/runStatus" 91 url: "https://iotgc.cniot.vip/api/energy/runStatus"
  92 +
  93 +# 公司配置表(主数据库中存储各公司的数据源和IoT配置)
  94 +corp:
  95 + config:
  96 + tableName: "t_auto_ymk_ccfg_corp_conf"