This commit is contained in:
2026-04-20 20:42:57 +08:00
parent 7153c00d0c
commit 111631a426
7 changed files with 206 additions and 109 deletions

View File

@ -70,7 +70,7 @@ spring:
# 端口默认为6379 # 端口默认为6379
port: 6379 port: 6379
# 数据库索引 # 数据库索引
database: 0 database: 3
# 密码 # 密码
password: 12345678 password: 12345678
# 连接超时时间 # 连接超时时间
@ -92,7 +92,7 @@ spring:
druid: druid:
# 主库数据源 # 主库数据源
master: master:
url: jdbc:mysql://172.17.0.13:3306/setri_ems?useUnicode=true&characterEncoding=utf8&rewriteBatchedStatements=true&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 url: jdbc:mysql://172.17.0.13:3306/setri_ems_new?useUnicode=true&characterEncoding=utf8&rewriteBatchedStatements=true&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
username: ems username: ems
password: Aa112211! password: Aa112211!
# 从库数据源 # 从库数据源
@ -188,7 +188,7 @@ xss:
mqtt: mqtt:
broker.url: tcp://121.5.164.6:1883 broker.url: tcp://121.5.164.6:1883
client.id: ems-cloud client.id: ems-cloud-new
username: dmbroker username: dmbroker
password: qwer1234 password: qwer1234
connection-timeout: 15 connection-timeout: 15
@ -216,7 +216,7 @@ weather:
influxdb: influxdb:
enabled: true enabled: true
url: http://172.17.0.7:8086/ url: http://172.17.0.7:8086/
api-token: B_1HvHbUhubQQhLdI0XtNVw7maWS1aIjVZQ1a3PGD6b-VNg3_JUo_jHgZmjeBKYXnGATNdIqfpl-FAVbJ4UIPg== api-token: l_MUXGYFs15utEaLLLgGUUkHYVA84nweimAyeiHNRIg_FWy3ACcdA85LnxDIBKA8bKxbPp2isTkrqHzrhXtZYw==
write-method: POST write-method: POST
read-method: GET read-method: GET
write-path: /api/v2/write write-path: /api/v2/write

View File

@ -94,7 +94,7 @@ spring:
druid: druid:
# 主库数据源 # 主库数据源
master: master:
url: jdbc:mysql://122.51.194.184:13306/setri_ems?useUnicode=true&characterEncoding=utf8&rewriteBatchedStatements=true&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 url: jdbc:mysql://122.51.194.184:13306/setri_ems_new?useUnicode=true&characterEncoding=utf8&rewriteBatchedStatements=true&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
username: ems username: ems
password: 12345678 password: 12345678
# 从库数据源 # 从库数据源

View File

@ -71,6 +71,18 @@
</encoder> </encoder>
</appender> </appender>
<!-- InfluxDB 写入成功日志输出 -->
<appender name="sys-influxdb" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/sys-influxdb.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.path}/sys-influxdb.%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>60</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
</appender>
<!-- 系统模块日志级别控制 --> <!-- 系统模块日志级别控制 -->
<logger name="com.xzzn" level="info" /> <logger name="com.xzzn" level="info" />
<!-- Spring日志级别控制 --> <!-- Spring日志级别控制 -->
@ -90,4 +102,9 @@
<logger name="sys-user" level="info"> <logger name="sys-user" level="info">
<appender-ref ref="sys-user"/> <appender-ref ref="sys-user"/>
</logger> </logger>
<!-- InfluxDB 写入成功专用日志 -->
<logger name="sys-influxdb" level="info" additivity="false">
<appender-ref ref="sys-influxdb"/>
</logger>
</configuration> </configuration>

View File

@ -28,6 +28,7 @@ import java.util.Map;
public class InfluxPointDataWriter { public class InfluxPointDataWriter {
private static final Logger log = LoggerFactory.getLogger(InfluxPointDataWriter.class); private static final Logger log = LoggerFactory.getLogger(InfluxPointDataWriter.class);
private static final Logger influxWriteSuccessLog = LoggerFactory.getLogger("sys-influxdb");
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
@Value("${influxdb.enabled:true}") @Value("${influxdb.enabled:true}")
@ -91,6 +92,7 @@ public class InfluxPointDataWriter {
} }
try { try {
StringBuilder body = new StringBuilder(); StringBuilder body = new StringBuilder();
List<String> pointSummaries = new ArrayList<>();
for (PointWritePayload payload : payloads) { for (PointWritePayload payload : payloads) {
if (payload == null || payload.getPointValue() == null) { if (payload == null || payload.getPointValue() == null) {
continue; continue;
@ -103,6 +105,12 @@ public class InfluxPointDataWriter {
.append(" value=").append(payload.getPointValue().toPlainString()) .append(" value=").append(payload.getPointValue().toPlainString())
.append(" ").append(time) .append(" ").append(time)
.append("\n"); .append("\n");
pointSummaries.add(String.format("siteId=%s, deviceId=%s, pointKey=%s, value=%s, time=%s",
safe(payload.getSiteId()),
safe(payload.getDeviceId()),
safe(payload.getPointKey()),
payload.getPointValue(),
new Date(time)));
} }
if (body.length() == 0) { if (body.length() == 0) {
return; return;
@ -112,6 +120,8 @@ public class InfluxPointDataWriter {
log.warn("写入 InfluxDB 失败v2 写入地址未构建成功,请检查 influxdb.org / influxdb.bucket 配置"); log.warn("写入 InfluxDB 失败v2 写入地址未构建成功,请检查 influxdb.org / influxdb.bucket 配置");
return; return;
} }
long startMillis = System.currentTimeMillis();
int writeCount = countWriteLines(body);
HttpResult result = executeRequest(methodOrDefault(writeMethod, "POST"), writeUrl, body.toString()); HttpResult result = executeRequest(methodOrDefault(writeMethod, "POST"), writeUrl, body.toString());
if (result.code < 200 || result.code >= 300) { if (result.code < 200 || result.code >= 300) {
if (result.code == 404 && isV2WritePath() && isOrgOrBucketMissing(result.body)) { if (result.code == 404 && isV2WritePath() && isOrgOrBucketMissing(result.body)) {
@ -119,6 +129,7 @@ public class InfluxPointDataWriter {
HttpResult retryResult = executeRequest(methodOrDefault(writeMethod, "POST"), writeUrl, body.toString()); HttpResult retryResult = executeRequest(methodOrDefault(writeMethod, "POST"), writeUrl, body.toString());
if (retryResult.code >= 200 && retryResult.code < 300) { if (retryResult.code >= 200 && retryResult.code < 300) {
log.info("InfluxDB org/bucket 自动创建成功,写入已恢复"); log.info("InfluxDB org/bucket 自动创建成功,写入已恢复");
logWriteSuccess(writeCount, writeUrl, startMillis, pointSummaries);
return; return;
} }
log.warn("InfluxDB 重试写入失败HTTP状态码: {}, url: {}, body: {}", retryResult.code, writeUrl, safeLog(retryResult.body)); log.warn("InfluxDB 重试写入失败HTTP状态码: {}, url: {}, body: {}", retryResult.code, writeUrl, safeLog(retryResult.body));
@ -126,7 +137,9 @@ public class InfluxPointDataWriter {
} }
} }
log.warn("写入 InfluxDB 失败HTTP状态码: {}, url: {}, body: {}", result.code, writeUrl, safeLog(result.body)); log.warn("写入 InfluxDB 失败HTTP状态码: {}, url: {}, body: {}", result.code, writeUrl, safeLog(result.body));
return;
} }
logWriteSuccess(writeCount, writeUrl, startMillis, pointSummaries);
} catch (Exception e) { } catch (Exception e) {
log.warn("写入 InfluxDB 失败: {}", e.getMessage()); log.warn("写入 InfluxDB 失败: {}", e.getMessage());
} }
@ -173,7 +186,8 @@ public class InfluxPointDataWriter {
startTime.getTime(), startTime.getTime(),
endTime.getTime() endTime.getTime()
); );
values = parseInfluxQlResponse(executeRequestWithResponse(methodOrDefault(readMethod, "GET"), buildQueryUrl(regexQuery))); String regexQueryUrl = buildQueryUrl(regexQuery);
values = parseInfluxQlResponse(executeRequestWithResponse(methodOrDefault(readMethod, "GET"), regexQueryUrl));
return values; return values;
} catch (Exception e) { } catch (Exception e) {
log.warn("查询 InfluxDB 曲线失败: {}", e.getMessage()); log.warn("查询 InfluxDB 曲线失败: {}", e.getMessage());
@ -204,7 +218,8 @@ public class InfluxPointDataWriter {
try { try {
String queryUrl = buildQueryUrl(influxQl); String queryUrl = buildQueryUrl(influxQl);
return parseInfluxQlResponse(executeRequestWithResponse(methodOrDefault(readMethod, "GET"), queryUrl)); List<PointValue> values = parseInfluxQlResponse(executeRequestWithResponse(methodOrDefault(readMethod, "GET"), queryUrl));
return values;
} catch (Exception e) { } catch (Exception e) {
log.warn("按 pointKey 查询 InfluxDB 曲线失败: {}", e.getMessage()); log.warn("按 pointKey 查询 InfluxDB 曲线失败: {}", e.getMessage());
return Collections.emptyList(); return Collections.emptyList();
@ -234,24 +249,9 @@ public class InfluxPointDataWriter {
); );
try { try {
String queryUrl = buildQueryUrl(influxQl);
List<PointValue> values = parseInfluxQlResponse( List<PointValue> values = parseInfluxQlResponse(
executeRequestWithResponse(methodOrDefault(readMethod, "GET"), buildQueryUrl(influxQl)) executeRequestWithResponse(methodOrDefault(readMethod, "GET"), queryUrl)
);
if (!values.isEmpty()) {
return values.get(0);
}
String regexQuery = String.format(
"SELECT \"value\" FROM \"%s\" WHERE \"site_id\" = '%s' AND \"point_key\" =~ /(?i)^%s$/ " +
"AND time >= %dms AND time <= %dms ORDER BY time DESC LIMIT 1",
measurement,
escapeTagValue(normalizedSiteId),
escapeRegex(normalizedPointKey),
startTime.getTime(),
endTime.getTime()
);
values = parseInfluxQlResponse(
executeRequestWithResponse(methodOrDefault(readMethod, "GET"), buildQueryUrl(regexQuery))
); );
return values.isEmpty() ? null : values.get(0); return values.isEmpty() ? null : values.get(0);
} catch (Exception e) { } catch (Exception e) {
@ -260,6 +260,21 @@ public class InfluxPointDataWriter {
} }
} }
private void logWriteSuccess(int writeCount, String writeUrl, long startMillis, List<String> pointSummaries) {
influxWriteSuccessLog.info("InfluxDB写入成功, count: {}, points: {}, url: {}, costMs: {}",
writeCount, pointSummaries, writeUrl, System.currentTimeMillis() - startMillis);
}
private int countWriteLines(StringBuilder body) {
int count = 0;
for (int i = 0; i < body.length(); i++) {
if (body.charAt(i) == '\n') {
count++;
}
}
return count;
}
private String buildWriteUrl() { private String buildWriteUrl() {
if (isV2WritePath()) { if (isV2WritePath()) {
return buildV2WriteUrl(); return buildV2WriteUrl();

View File

@ -2816,15 +2816,16 @@ public class DeviceDataProcessServiceImpl extends AbstractBatteryDataProcessor i
private JSONArray parseJsonData(String message) { private JSONArray parseJsonData(String message) {
try { try {
JSONObject object = JSONObject.parseObject(message); Object parsed = JSON.parse(message);
return object.getJSONArray("payload"); if (parsed instanceof JSONArray) {
} catch (JSONException e) { return (JSONArray) parsed;
log.info("mqtt message is not a json object: " + e.getMessage());
try {
return JSONArray.parseArray(message);
} catch (Exception arrayException) {
log.info("mqtt message is not a json array: " + e.getMessage());
} }
if (parsed instanceof JSONObject) {
return ((JSONObject) parsed).getJSONArray("payload");
}
log.info("mqtt message root type is unsupported: {}", parsed == null ? "null" : parsed.getClass().getName());
} catch (JSONException e) {
log.info("mqtt message parse failed: {}", e.getMessage());
} }
return null; return null;
} }
@ -3954,15 +3955,22 @@ public class DeviceDataProcessServiceImpl extends AbstractBatteryDataProcessor i
log.info("deviceId:" + deviceId); log.info("deviceId:" + deviceId);
if (checkJsonDataEmpty(jsonData)) {
log.warn("设备告警Data为空跳过告警处理siteId: {}deviceId: {}", siteId, deviceId);
continue;
}
// 存放mqtt原始每个设备最晚一次数据便于后面点位获取数据 // 存放mqtt原始每个设备最晚一次数据便于后面点位获取数据
redisCache.setCacheObject(RedisKeyConstants.ORIGINAL_MQTT_DATA_ALARM + siteId + "_" + deviceId, obj); redisCache.setCacheObject(RedisKeyConstants.ORIGINAL_MQTT_DATA_ALARM + siteId + "_" + deviceId, obj);
// 存放每次同步数据,失效时间(同同步时间)-用于判断是否正常同步数据 // 存放每次同步数据,失效时间(同同步时间)-用于判断是否正常同步数据
redisCache.setCacheObject(RedisKeyConstants.SYNC_DATA_ALARM + siteId + "_" + deviceId, obj, 1, TimeUnit.MINUTES); redisCache.setCacheObject(RedisKeyConstants.SYNC_DATA_ALARM + siteId + "_" + deviceId, obj, 1, TimeUnit.MINUTES);
// 处理设备数据,根据不同设备类型进行不同的数据处理 // 处理设备数据,根据不同设备类型进行不同的数据处理
String deviceCategory = processingDeviceAlarmData(siteId, deviceId, jsonData, dataUpdateTime); String deviceCategory = processingDeviceAlarmData(siteId, deviceId, jsonData, dataUpdateTime);
if (StringUtils.isEmpty(deviceCategory)) { if (StringUtils.isNotEmpty(deviceCategory)) {
// 处理告警信息 // 处理告警信息
alarmDataProcess(siteId, deviceId, jsonData, alarmMatchInfo, deviceCategory); alarmDataProcess(siteId, deviceId, jsonData, alarmMatchInfo, deviceCategory);
} else {
log.warn("设备告警数据未识别到设备类型跳过告警处理siteId: {}deviceId: {}", siteId, deviceId);
} }
} }
} }
@ -4097,8 +4105,21 @@ public class DeviceDataProcessServiceImpl extends AbstractBatteryDataProcessor i
private void alarmDataProcess(String siteId, String deviceId, String jsonData, private void alarmDataProcess(String siteId, String deviceId, String jsonData,
Map<String, EmsAlarmMatchData> alarmInfoData, String category) { Map<String, EmsAlarmMatchData> alarmInfoData, String category) {
if (StringUtils.isEmpty(category)) {
log.warn("设备类型为空跳过告警处理siteId: {}deviceId: {}", siteId, deviceId);
return;
}
if (alarmInfoData == null || alarmInfoData.isEmpty()) {
log.warn("告警匹配缓存为空跳过告警处理siteId: {}deviceId: {}category: {}", siteId, deviceId, category);
return;
}
Map<String, Object> obj = JSON.parseObject(jsonData, new TypeReference<Map<String, Object>>() { Map<String, Object> obj = JSON.parseObject(jsonData, new TypeReference<Map<String, Object>>() {
}); });
if (obj == null || obj.isEmpty()) {
log.warn("设备告警Data解析结果为空跳过告警处理siteId: {}deviceId: {}category: {}data: {}",
siteId, deviceId, category, jsonData);
return;
}
String redisKey = RedisKeyConstants.LATEST_ALARM_RECORD + "_" + siteId + "_" + deviceId; String redisKey = RedisKeyConstants.LATEST_ALARM_RECORD + "_" + siteId + "_" + deviceId;
// 获取redis里面的当前有效告警遍历添加到已存在告警key里面 // 获取redis里面的当前有效告警遍历添加到已存在告警key里面
@ -4114,12 +4135,8 @@ public class DeviceDataProcessServiceImpl extends AbstractBatteryDataProcessor i
// 结合同步数据,筛选簇需要更新的告警信息 // 结合同步数据,筛选簇需要更新的告警信息
List<String> needUpdateKeys = obj.entrySet().stream() List<String> needUpdateKeys = obj.entrySet().stream()
.filter(entry -> { .filter(entry -> {
Object valueObj = entry.getValue(); Long value = convertToLong(entry.getValue());
if (valueObj == null) { return value != null && value == 0L && currentAlarmKeys.contains(entry.getKey());
return false;
}
int value = Integer.parseInt(valueObj.toString());
return value == 0 && currentAlarmKeys.contains(entry.getKey());
}) })
.map(Map.Entry::getKey) .map(Map.Entry::getKey)
.collect(Collectors.toList()); .collect(Collectors.toList());
@ -4129,12 +4146,14 @@ public class DeviceDataProcessServiceImpl extends AbstractBatteryDataProcessor i
if (!needUpdateKeys.isEmpty()) { if (!needUpdateKeys.isEmpty()) {
List<EmsAlarmRecords> records = iEmsAlarmRecordsService.getAllUnfinishedRecords(needUpdateKeys, siteId, deviceId); List<EmsAlarmRecords> records = iEmsAlarmRecordsService.getAllUnfinishedRecords(needUpdateKeys, siteId, deviceId);
// 转为Map便于快速获取 // 转为Map便于快速获取
if (CollectionUtils.isNotEmpty(records)) {
needUpdateMap = records.stream() needUpdateMap = records.stream()
.collect(Collectors.toMap( .collect(Collectors.toMap(
EmsAlarmRecords::getAlarmPoint, EmsAlarmRecords::getAlarmPoint,
record -> record record -> record
)); ));
} }
}
List<EmsAlarmRecords> saveOrUpdateList = new ArrayList<>(); List<EmsAlarmRecords> saveOrUpdateList = new ArrayList<>();
@ -4147,20 +4166,28 @@ public class DeviceDataProcessServiceImpl extends AbstractBatteryDataProcessor i
continue; continue;
} }
String key = entry.getKey(); String key = entry.getKey();
Long value = (Long) entry.getValue(); Long value = convertToLong(entry.getValue());
if (value == null) {
log.warn("告警值不是有效数字忽略处理siteId: {}deviceId: {}point: {}value: {}",
siteId, deviceId, key, entry.getValue());
continue;
}
Boolean isCurrentAlarm = currentAlarmKeys.contains(key); Boolean isCurrentAlarm = currentAlarmKeys.contains(key);
String matchRedisKey = siteId + "_" + category + "_" + key; String matchRedisKey = siteId + "_" + category + "_" + key;
// 默认告警值0是正常1是异常 // 默认告警值0是正常1是异常
Long alarmData = 1L; Long alarmData = 1L;
Object cacheObj = alarmInfoData.get(matchRedisKey); EmsAlarmMatchData matchInfo = alarmInfoData.get(matchRedisKey);
if (cacheObj != null) { if (matchInfo != null) {
EmsAlarmMatchData matchInfo = JSON.toJavaObject(cacheObj, EmsAlarmMatchData.class);
alarmData = matchInfo.getAlarmData(); alarmData = matchInfo.getAlarmData();
} }
// 处理告警 // 处理告警
if (value.equals(alarmData) && !isCurrentAlarm) { if (value.equals(alarmData) && !isCurrentAlarm) {
// 上送值和匹配值相同,新增告警 // 上送值和匹配值相同,新增告警
EmsAlarmMatchData matchInfo = JSON.toJavaObject(cacheObj, EmsAlarmMatchData.class); if (matchInfo == null) {
log.warn("未找到告警匹配配置忽略新增告警siteId: {}deviceId: {}category: {}point: {}",
siteId, deviceId, category, key);
continue;
}
EmsAlarmRecords emsAlarmRecord = convertAlarmRecord(siteId, deviceId, matchInfo); EmsAlarmRecords emsAlarmRecord = convertAlarmRecord(siteId, deviceId, matchInfo);
saveOrUpdateList.add(emsAlarmRecord); saveOrUpdateList.add(emsAlarmRecord);
newAddRecordList.add(emsAlarmRecord); newAddRecordList.add(emsAlarmRecord);
@ -4219,6 +4246,24 @@ public class DeviceDataProcessServiceImpl extends AbstractBatteryDataProcessor i
} }
} }
private Long convertToLong(Object value) {
if (value == null) {
return null;
}
if (value instanceof Number) {
return ((Number) value).longValue();
}
String text = String.valueOf(value);
if (StringUtils.isBlank(text)) {
return null;
}
try {
return new BigDecimal(text.trim()).longValue();
} catch (NumberFormatException ex) {
return null;
}
}
private EmsAlarmRecords convertAlarmRecord(String siteId, String deviceId, EmsAlarmMatchData matchInfo) { private EmsAlarmRecords convertAlarmRecord(String siteId, String deviceId, EmsAlarmMatchData matchInfo) {
EmsAlarmRecords emsAlarmRecords = new EmsAlarmRecords(); EmsAlarmRecords emsAlarmRecords = new EmsAlarmRecords();
emsAlarmRecords.setSiteId(siteId); emsAlarmRecords.setSiteId(siteId);

View File

@ -125,7 +125,10 @@
t.alarm_content as alarmContent, t.alarm_content as alarmContent,
t.ticket_no as ticketNo, t.ticket_no as ticketNo,
t.id t.id
from ems_alarm_records t INNER JOIN ems_devices_setting t2 on t.site_id = t2.site_id and t.device_id = t2.device_id from ems_alarm_records t
INNER JOIN ems_devices_setting t2
on t.site_id COLLATE utf8mb4_general_ci = t2.site_id
and t.device_id COLLATE utf8mb4_general_ci = t2.device_id
where t.site_id = #{siteId} where t.site_id = #{siteId}
and t.status != 1 and t.status != 1
and t.alarm_level in ('C','D') and t.alarm_level in ('C','D')
@ -156,7 +159,9 @@
t.ticket_no as ticketNo, t.ticket_no as ticketNo,
t.id t.id
from ems_alarm_records t from ems_alarm_records t
LEFT JOIN ems_devices_setting t2 on t.site_id = t2.site_id and t.device_id = t2.device_id LEFT JOIN ems_devices_setting t2
on t.site_id = t2.site_id
and t.device_id = t2.device_id
where t.site_id = #{siteId} where t.site_id = #{siteId}
<if test="deviceType != null and deviceType != ''"> <if test="deviceType != null and deviceType != ''">
AND t.device_type = #{deviceType} AND t.device_type = #{deviceType}

View File

@ -287,13 +287,27 @@
</select> </select>
<select id="getRevenueDataBySiteId" resultType="com.xzzn.ems.domain.vo.AmmeterRevenueStatisListVo"> <select id="getRevenueDataBySiteId" resultType="com.xzzn.ems.domain.vo.AmmeterRevenueStatisListVo">
select
revenue.dataTime as dataTime,
revenue.isWorkday as isWorkday,
case
when revenue.isWorkday = 1 then '工作日'
else '节假日'
end as dayType,
revenue.weatherDesc as weatherDesc,
revenue.activePeakPrice as activePeakPrice,
revenue.reActivePeakPrice as reActivePeakPrice,
revenue.activeHighPrice as activeHighPrice,
revenue.reActiveHighPrice as reActiveHighPrice,
revenue.activeFlatPrice as activeFlatPrice,
revenue.reActiveFlatPrice as reActiveFlatPrice,
revenue.activeValleyPrice as activeValleyPrice,
revenue.reActiveValleyPrice as reActiveValleyPrice,
revenue.actualRevenue as actualRevenue
from (
select select
DATE_FORMAT(t.data_date, '%Y-%m-%d') as dataTime, DATE_FORMAT(t.data_date, '%Y-%m-%d') as dataTime,
COALESCE(c.is_workday, CASE WHEN WEEKDAY(t.data_date) &lt; 5 THEN 1 ELSE 0 END) as isWorkday, COALESCE(c.is_workday, CASE WHEN WEEKDAY(t.data_date) &lt; 5 THEN 1 ELSE 0 END) as isWorkday,
CASE
WHEN COALESCE(c.is_workday, CASE WHEN WEEKDAY(t.data_date) &lt; 5 THEN 1 ELSE 0 END) = 1 THEN '工作日'
ELSE '节假日'
END as dayType,
COALESCE(NULLIF(TRIM(w.weather_desc), ''), '--') as weatherDesc, COALESCE(NULLIF(TRIM(w.weather_desc), ''), '--') as weatherDesc,
ROUND(SUM(IFNULL(t.peak_charge_diff, 0) * IFNULL(pc.peak, 0)), 3) as activePeakPrice, ROUND(SUM(IFNULL(t.peak_charge_diff, 0) * IFNULL(pc.peak, 0)), 3) as activePeakPrice,
ROUND(SUM(IFNULL(t.peak_discharge_diff, 0) * IFNULL(pc.peak, 0)), 3) as reActivePeakPrice, ROUND(SUM(IFNULL(t.peak_discharge_diff, 0) * IFNULL(pc.peak, 0)), 3) as reActivePeakPrice,
@ -346,7 +360,8 @@
group by t.data_date, group by t.data_date,
COALESCE(c.is_workday, CASE WHEN WEEKDAY(t.data_date) &lt; 5 THEN 1 ELSE 0 END), COALESCE(c.is_workday, CASE WHEN WEEKDAY(t.data_date) &lt; 5 THEN 1 ELSE 0 END),
COALESCE(NULLIF(TRIM(w.weather_desc), ''), '--') COALESCE(NULLIF(TRIM(w.weather_desc), ''), '--')
order by t.data_date asc ) revenue
order by revenue.dataTime asc
</select> </select>
</mapper> </mapper>