package com.doumee.service.business.impl;
|
|
import com.alibaba.fastjson.JSON;
|
import com.alibaba.fastjson.JSONObject;
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
|
import com.doumee.core.conditoner.ConditionerUtil;
|
import com.doumee.core.conditoner.model.ConditionerConstant;
|
import com.doumee.core.conditoner.model.request.*;
|
import com.doumee.core.conditoner.model.response.*;
|
import com.doumee.core.constants.ResponseStatus;
|
import com.doumee.core.exception.BusinessException;
|
import com.doumee.core.model.LoginUserInfo;
|
import com.doumee.core.utils.Constants;
|
import com.doumee.dao.business.*;
|
import com.doumee.dao.business.dto.*;
|
import com.doumee.dao.business.model.*;
|
import com.doumee.service.business.ConditionerBizService;
|
import org.apache.commons.lang3.StringUtils;
|
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.stereotype.Service;
|
import org.springframework.transaction.annotation.Transactional;
|
import java.math.BigDecimal;
|
import java.text.SimpleDateFormat;
|
import java.time.LocalDate;
|
import java.time.YearMonth;
|
import java.time.format.DateTimeFormatter;
|
import java.time.temporal.ChronoUnit;
|
import java.util.*;
|
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.stream.Collectors;
|
|
@Service
|
public class ConditionerBizServiceImpl implements ConditionerBizService {
|
|
public static final int ACTION_PWR = 1;
|
public static final int ACTION_MODE = 2;
|
public static final int ACTION_FAN = 3;
|
public static final int ACTION_TEMP = 4;
|
public static final int ACTION_LOCK = 5;
|
public static final int ACTION_QUERY_DL = 6;
|
public static final int ACTION_QUERY_POWER = 7;
|
|
private static final String PID_DLJ = "dlj";
|
private static final String LOCK_SET_TYPE = "lock_many";
|
private static final long ADJUST_OPERATE_INTERVAL_MS = 2000L;
|
private static volatile boolean syncing = false;
|
/** 同一内机:温度/风速/模式操作最小间隔(毫秒) */
|
private static final Map<Integer, Long> LAST_ADJUST_OPERATE_MS = new ConcurrentHashMap<>();
|
|
@Autowired
|
private YwConditionerGatewayMapper gatewayMapper;
|
@Autowired
|
private YwConditionerGatewayLogMapper gatewayLogMapper;
|
@Autowired
|
private YwConditionerMeterMapper meterMapper;
|
@Autowired
|
private YwConditionerBillingMapper billingMapper;
|
@Autowired
|
private YwConditionerMapper conditionerMapper;
|
@Autowired
|
private YwConditionerActionsMapper actionsMapper;
|
@Autowired
|
private YwConditionerUsageMapper usageMapper;
|
|
@Override
|
public void ensureLogin() {
|
if (StringUtils.isNotBlank(ConditionerConstant.kt_token)) {
|
return;
|
}
|
ConditionerBaseResponse<LoginDataResponse> resp = ConditionerUtil.login();
|
if (resp == null || !resp.isSuccess()) {
|
throw new BusinessException(ResponseStatus.SERVER_ERROR.getCode(),
|
resp != null ? resp.getMessage() : "智精灵平台登录失败");
|
}
|
}
|
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
public String syncGateways(String source) {
|
ensureLogin();
|
ConditionerSessionRequest req = new ConditionerSessionRequest();
|
ConditionerBaseResponse<List<GatewayInfoResponse>> resp = ConditionerUtil.getWg(req);
|
if (resp == null || !resp.isSuccess()) {
|
throw new BusinessException(ResponseStatus.SERVER_ERROR.getCode(), apiMsg(resp, "同步网关失败"));
|
}
|
List<GatewayInfoResponse> list = resp.getData() != null ? resp.getData() : Collections.emptyList();
|
Date now = new Date();
|
int add = 0, upd = 0, logs = 0;
|
for (GatewayInfoResponse item : list) {
|
if (StringUtils.isBlank(item.getWg_mac())) {
|
continue;
|
}
|
String newStatus = ConditionerConstant.normalizeGatewayOnline(item.getWg_status());
|
YwConditionerGateway local = gatewayMapper.selectOne(new QueryWrapper<YwConditionerGateway>().lambda()
|
.eq(YwConditionerGateway::getIsdeleted, Constants.ZERO)
|
.eq(YwConditionerGateway::getWgMac, item.getWg_mac())
|
.last(" limit 1 "));
|
if (local == null) {
|
local = new YwConditionerGateway();
|
local.setCreator(0);
|
local.setCreateDate(now);
|
local.setIsdeleted(Constants.ZERO);
|
local.setPlatformWgId(item.getWg_id());
|
local.setWgMac(item.getWg_mac());
|
local.setWgBz(item.getWg_bz());
|
local.setOnlineStatus(newStatus);
|
local.setLastSyncDate(now);
|
gatewayMapper.insert(local);
|
add++;
|
} else {
|
String oldStatus = local.getOnlineStatus();
|
local.setPlatformWgId(item.getWg_id());
|
local.setWgBz(item.getWg_bz());
|
local.setOnlineStatus(newStatus);
|
local.setLastSyncDate(now);
|
local.setEditDate(now);
|
gatewayMapper.updateById(local);
|
upd++;
|
if (!Objects.equals(oldStatus, newStatus)) {
|
writeGatewayLog(local.getId(), item.getWg_mac(), oldStatus, newStatus, source, now);
|
logs++;
|
}
|
}
|
}
|
return "同步网关:新增【" + add + "】更新【" + upd + "】状态变更【" + logs + "】";
|
}
|
|
@Override
|
public String syncGatewayStatus() {
|
return syncGateways("schedule");
|
}
|
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
public String syncMeters() {
|
ensureLogin();
|
MeterDbManageRequest req = new MeterDbManageRequest();
|
ConditionerBaseResponse<List<MeterDbInfoResponse>> resp = ConditionerUtil.getDb(req);
|
if (resp == null || !resp.isSuccess()) {
|
throw new BusinessException(ResponseStatus.SERVER_ERROR.getCode(), apiMsg(resp, "同步电表失败"));
|
}
|
List<MeterDbInfoResponse> list = resp.getData() != null ? resp.getData() : Collections.emptyList();
|
Date now = new Date();
|
int add = 0, upd = 0;
|
for (MeterDbInfoResponse item : list) {
|
if (item.getDb_id() == null) {
|
continue;
|
}
|
YwConditionerMeter local = meterMapper.selectOne(new QueryWrapper<YwConditionerMeter>().lambda()
|
.eq(YwConditionerMeter::getIsdeleted, Constants.ZERO)
|
.eq(YwConditionerMeter::getPlatformDbId, item.getDb_id())
|
.last(" limit 1 "));
|
if (local == null) {
|
local = new YwConditionerMeter();
|
local.setCreator(0);
|
local.setCreateDate(now);
|
local.setIsdeleted(Constants.ZERO);
|
add++;
|
} else {
|
upd++;
|
}
|
fillMeter(local, item, now);
|
if (local.getId() == null) {
|
meterMapper.insert(local);
|
} else {
|
meterMapper.updateById(local);
|
}
|
}
|
return "同步电表:新增【" + add + "】更新【" + upd + "】";
|
}
|
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
public String syncBilling() {
|
ensureLogin();
|
ConditionerSessionRequest req = new ConditionerSessionRequest();
|
ConditionerBaseResponse<List<DlSjXsResponse>> resp = ConditionerUtil.getDlSjXs(req);
|
if (resp == null || !resp.isSuccess()) {
|
throw new BusinessException(ResponseStatus.SERVER_ERROR.getCode(), apiMsg(resp, "同步计费系数失败"));
|
}
|
List<DlSjXsResponse> list = resp.getData() != null ? resp.getData() : Collections.emptyList();
|
Date now = new Date();
|
int add = 0, upd = 0;
|
for (DlSjXsResponse item : list) {
|
if (item.getDev_id() == null) {
|
continue;
|
}
|
YwConditionerBilling local = billingMapper.selectOne(new QueryWrapper<YwConditionerBilling>().lambda()
|
.eq(YwConditionerBilling::getIsdeleted, Constants.ZERO)
|
.eq(YwConditionerBilling::getPlatformDevId, item.getDev_id())
|
.last(" limit 1 "));
|
if (local == null) {
|
local = new YwConditionerBilling();
|
local.setCreator(0);
|
local.setCreateDate(now);
|
local.setIsdeleted(Constants.ZERO);
|
add++;
|
} else {
|
upd++;
|
}
|
local.setPlatformDevId(item.getDev_id());
|
local.setKwType(item.getKw_type());
|
local.setFanArg(item.getFan_arg());
|
local.setFanKw(item.getFan_kw());
|
local.setHigKw(item.getHig_kw());
|
local.setMidKw(item.getMid_kw());
|
local.setLowKw(item.getLow_kw());
|
local.setKtDj(item.getKt_dj());
|
local.setLastSyncDate(now);
|
local.setEditDate(now);
|
YwConditioner dev = findConditionerByPlatformDevId(item.getDev_id());
|
if (dev != null) {
|
local.setDevName(dev.getName());
|
local.setWgMac(dev.getWgMac());
|
}
|
if (local.getId() == null) {
|
billingMapper.insert(local);
|
} else {
|
billingMapper.updateById(local);
|
}
|
}
|
return "同步计费系数:新增【" + add + "】更新【" + upd + "】";
|
}
|
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
public String syncIndoorUnits() {
|
ensureLogin();
|
ConditionerSessionRequest session = new ConditionerSessionRequest();
|
ConditionerBaseResponse<List<DeviceStatusResponse>> statusResp = ConditionerUtil.getDevList(session);
|
if (statusResp == null || !statusResp.isSuccess()) {
|
throw new BusinessException(ResponseStatus.SERVER_ERROR.getCode(), apiMsg(statusResp, "同步内机状态失败"));
|
}
|
ConditionerBaseResponse<List<DeviceArchiveResponse>> archiveResp = ConditionerUtil.getDev(session);
|
Map<Integer, DeviceArchiveResponse> archiveMap = new HashMap<>();
|
if (archiveResp != null && archiveResp.getData() != null) {
|
for (DeviceArchiveResponse a : archiveResp.getData()) {
|
if (a.getDev_id() != null) {
|
archiveMap.put(a.getDev_id(), a);
|
}
|
}
|
}
|
List<DeviceStatusResponse> list = statusResp.getData() != null ? statusResp.getData() : Collections.emptyList();
|
Date now = new Date();
|
int add = 0, upd = 0;
|
for (DeviceStatusResponse item : list) {
|
if (item.getDev_id() == null) {
|
continue;
|
}
|
YwConditioner local = findConditionerByPlatformDevId(item.getDev_id());
|
if (local == null) {
|
local = new YwConditioner();
|
local.setCreator(0);
|
local.setCreateDate(now);
|
local.setIsdeleted(Constants.ZERO);
|
local.setCode(String.valueOf(item.getDev_id()));
|
local.setPlatformDevId(item.getDev_id());
|
add++;
|
} else {
|
upd++;
|
}
|
fillConditionerFromStatus(local, item, archiveMap.get(item.getDev_id()), now);
|
if (local.getId() == null) {
|
conditionerMapper.insert(local);
|
} else {
|
conditionerMapper.updateById(local);
|
}
|
}
|
return "同步设备与状态:新增【" + add + "】更新【" + upd + "】";
|
}
|
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
public String syncUsage(YwConditionerReportQueryDTO query) {
|
YwConditionerReportQueryDTO q = query != null ? query : new YwConditionerReportQueryDTO();
|
ReportDateRange range = resolveReportDateRange(q);
|
ensureLogin();
|
DayDlQueryRequest req = new DayDlQueryRequest();
|
req.setStart_time(range.start.toString());
|
req.setEnd_time(range.end.toString());
|
Integer gsId = q.getGsId();
|
if (gsId != null) {
|
req.setGs_id(gsId);
|
}
|
req.setPage(1);
|
req.setPageSize(5000);
|
ConditionerBaseResponse<List<Object>> resp = ConditionerUtil.getDayDl(req);
|
if (resp == null || !resp.isSuccess()) {
|
throw new BusinessException(ResponseStatus.SERVER_ERROR.getCode(), apiMsg(resp, "同步用量失败"));
|
}
|
List<Object> list = resp.getData() != null ? resp.getData() : Collections.emptyList();
|
Date now = new Date();
|
int upsert = 0;
|
for (Object row : list) {
|
JSONObject o = (JSONObject) JSON.toJSON(row);
|
Integer devId = o.getInteger("dev_id");
|
String uptime = o.getString("uptime");
|
if (devId == null || StringUtils.isBlank(uptime)) {
|
continue;
|
}
|
Date usageDate = parseDate(uptime);
|
if (usageDate == null) {
|
continue;
|
}
|
YwConditionerUsage usage = usageMapper.selectOne(new QueryWrapper<YwConditionerUsage>().lambda()
|
.eq(YwConditionerUsage::getIsdeleted, Constants.ZERO)
|
.eq(YwConditionerUsage::getPlatformDevId, devId)
|
.eq(YwConditionerUsage::getUsageDate, usageDate)
|
.eq(gsId != null, YwConditionerUsage::getGsId, gsId)
|
.isNull(gsId == null, YwConditionerUsage::getGsId)
|
.last(" limit 1 "));
|
if (usage == null) {
|
usage = new YwConditionerUsage();
|
usage.setCreator(0);
|
usage.setCreateDate(now);
|
usage.setIsdeleted(Constants.ZERO);
|
usage.setPlatformDevId(devId);
|
usage.setGsId(gsId);
|
}
|
usage.setDevName(o.getString("dev_name"));
|
usage.setUsageDate(usageDate);
|
usage.setSumTime(o.getBigDecimal("sum_time"));
|
usage.setSumDl(o.getBigDecimal("sum_dl"));
|
usage.setSumDf(o.getBigDecimal("sum_df"));
|
usage.setSyncDate(now);
|
usage.setEditDate(now);
|
if (usage.getId() == null) {
|
usageMapper.insert(usage);
|
} else {
|
usageMapper.updateById(usage);
|
}
|
upsert++;
|
}
|
return "同步用量:处理【" + upsert + "】条";
|
}
|
|
@Override
|
public String syncUsagePreviousDay() {
|
LocalDate yesterday = LocalDate.now().minusDays(1);
|
YwConditionerReportQueryDTO query = new YwConditionerReportQueryDTO();
|
query.setReportType("day");
|
query.setStartTime(yesterday.toString());
|
query.setEndTime(yesterday.toString());
|
return syncUsage(query);
|
}
|
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
public String operate(YwConditionerOperateDTO dto, LoginUserInfo user) {
|
if (dto == null || dto.getId() == null || dto.getActionType() == null) {
|
throw new BusinessException(ResponseStatus.BAD_REQUEST);
|
}
|
YwConditioner dev = requireConditioner(dto.getId());
|
ensureDeviceOnline(dev);
|
ensureLogin();
|
String setType;
|
Object setVal = dto.getSetVal();
|
int actionType = dto.getActionType();
|
reserveAdjustOperateInterval(dev.getId(), actionType);
|
switch (actionType) {
|
case ACTION_PWR:
|
setType = "pwr";
|
break;
|
case ACTION_MODE:
|
setType = "mode";
|
break;
|
case ACTION_FAN:
|
setType = "fan";
|
break;
|
case ACTION_TEMP:
|
setType = "temp";
|
if (setVal != null) {
|
try {
|
setVal = Integer.parseInt(String.valueOf(setVal)) * 10;
|
} catch (NumberFormatException ignored) {
|
}
|
}
|
break;
|
default:
|
throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "不支持的操作类型");
|
}
|
DevControlRequest req = buildDevControl(dev, setType, setVal);
|
String reqJson = JSON.toJSONString(req);
|
ConditionerBaseResponse<Object> resp = ConditionerUtil.devCtr(req);
|
boolean ok = resp != null && resp.isSuccess();
|
String actionDesc = formatOperateDescription(actionType, dto.getSetVal());
|
saveActionRecord(dev, actionType, actionDesc, ok, resp, reqJson, dto.getSource(), user);
|
if (!ok) {
|
throw new BusinessException(ResponseStatus.SERVER_ERROR.getCode(), apiMsg(resp, "控制失败"));
|
}
|
// 温度/风速/模式:控制成功即按设定值更新本地,不再拉取三方设备状态
|
if (actionType == ACTION_PWR) {
|
refreshDevStatus(dev);
|
}
|
applyOperateResultToDevice(dev, actionType, dto.getSetVal());
|
dev.setEditDate(new Date());
|
dev.setLastSyncDate(new Date());
|
conditionerMapper.updateById(dev);
|
return "操作成功";
|
}
|
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
public String lock(YwConditionerLockDTO dto, LoginUserInfo user) {
|
if (dto == null || dto.getId() == null) {
|
throw new BusinessException(ResponseStatus.BAD_REQUEST);
|
}
|
YwConditioner dev = requireConditioner(dto.getId());
|
ensureDeviceOnline(dev);
|
ensureLogin();
|
JSONObject lockVal = buildLockSetVal(dto);
|
DevLockControlRequest req = buildLockManyControlRequest(dev, lockVal);
|
String reqJson = JSON.toJSONString(req);
|
ConditionerBaseResponse<Object> resp = ConditionerUtil.devLockManyCtr(req);
|
boolean ok = resp != null && resp.isSuccess();
|
saveActionRecord(dev, ACTION_LOCK, lockVal.toJSONString(), ok, resp, reqJson, dto.getSource(), user);
|
if (!ok) {
|
throw new BusinessException(ResponseStatus.SERVER_ERROR.getCode(), apiMsg(resp, "锁定失败"));
|
}
|
applyLockResultToDevice(dev, dto);
|
refreshDevStatus(dev);
|
applyLockResultToDevice(dev, dto);
|
Date now = new Date();
|
dev.setEditDate(now);
|
dev.setLastSyncDate(now);
|
conditionerMapper.updateById(dev);
|
return Objects.equals(dto.getLockPwr(), 0) ? "解锁成功" : "锁定成功";
|
}
|
|
private JSONObject buildLockSetVal(YwConditionerLockDTO dto) {
|
JSONObject lockVal = new JSONObject();
|
lockVal.put("lock_pwr", dto.getLockPwr() != null ? dto.getLockPwr() : -1);
|
lockVal.put("pwr", dto.getPwr() != null ? dto.getPwr() : -1);
|
lockVal.put("mode", dto.getMode() != null ? dto.getMode() : -1);
|
lockVal.put("fan", dto.getFan() != null ? dto.getFan() : -1);
|
lockVal.put("min_temp", dto.getMinTemp() != null ? dto.getMinTemp() : -1);
|
lockVal.put("max_temp", dto.getMaxTemp() != null ? dto.getMaxTemp() : -1);
|
return lockVal;
|
}
|
|
private void applyLockResultToDevice(YwConditioner dev, YwConditionerLockDTO dto) {
|
dev.setLockPwr(dto.getLockPwr());
|
dev.setLockMode(dto.getMode());
|
dev.setLockFan(dto.getFan());
|
dev.setLockMinTemp(dto.getMinTemp());
|
dev.setLockMaxTemp(dto.getMaxTemp());
|
dev.setKtLock(hasActiveLock(dto) ? 1 : 0);
|
}
|
|
private DevLockControlRequest buildLockManyControlRequest(YwConditioner dev, JSONObject lockVal) {
|
DevLockControlRequest req = new DevLockControlRequest();
|
req.fillSessionDefaults();
|
req.setCtr_type("set_many");
|
DevLockManyControlItem item = new DevLockManyControlItem();
|
item.setWg_mac(dev.getWgMac());
|
item.setWg_qid(dev.getWgQid());
|
item.setPid(StringUtils.defaultIfBlank(dev.getPid(), PID_DLJ));
|
item.setSet_type(LOCK_SET_TYPE);
|
item.setSet_val(lockVal);
|
req.setLi_data(Collections.singletonList(item));
|
return req;
|
}
|
|
private boolean hasActiveLock(YwConditionerLockDTO dto) {
|
return Objects.equals(dto.getLockPwr(), 1)
|
|| (dto.getMode() != null && dto.getMode() >= 0)
|
|| (dto.getFan() != null && dto.getFan() >= 0)
|
|| (dto.getMinTemp() != null && dto.getMinTemp() >= 0)
|
|| (dto.getMaxTemp() != null && dto.getMaxTemp() >= 0);
|
}
|
|
/**
|
* 同一台内机:设定温度/风速/模式操作间隔不低于 2 秒
|
*/
|
private void reserveAdjustOperateInterval(Integer deviceId, int actionType) {
|
if (deviceId == null
|
|| (actionType != ACTION_MODE && actionType != ACTION_FAN && actionType != ACTION_TEMP)) {
|
return;
|
}
|
long now = System.currentTimeMillis();
|
Long last = LAST_ADJUST_OPERATE_MS.get(deviceId);
|
if (last != null && now - last < ADJUST_OPERATE_INTERVAL_MS) {
|
long waitSec = (ADJUST_OPERATE_INTERVAL_MS - (now - last) + 999) / 1000;
|
throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),
|
"操作过于频繁,请" + waitSec + "秒后再试");
|
}
|
LAST_ADJUST_OPERATE_MS.put(deviceId, now);
|
}
|
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
public String queryMeterEnergy(Integer meterId, LoginUserInfo user) {
|
return queryMeter(meterId, "find_dn", ACTION_QUERY_DL, user);
|
}
|
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
public String queryMeterPower(Integer meterId, LoginUserInfo user) {
|
return queryMeter(meterId, "find_power", ACTION_QUERY_POWER, user);
|
}
|
|
private String queryMeter(Integer meterId, String setType, int actionType, LoginUserInfo user) {
|
YwConditionerMeter meter = meterMapper.selectById(meterId);
|
if (meter == null || Objects.equals(meter.getIsdeleted(), Constants.ONE)) {
|
throw new BusinessException(ResponseStatus.DATA_EMPTY);
|
}
|
ensureLogin();
|
DevControlRequest req = buildMeterQueryRequest(meter, setType);
|
String reqJson = JSON.toJSONString(req);
|
ConditionerBaseResponse<Object> resp = ConditionerUtil.devCtr(req);
|
boolean ok = resp != null && resp.isSuccess();
|
YwConditionerActions action = new YwConditionerActions();
|
action.setActionType(actionType);
|
action.setWgMac(meter.getWgMac());
|
action.setDevName(meter.getDbName());
|
action.setActionContent(setType);
|
action.setRequestBody(reqJson);
|
action.setResponseBody(resp != null ? JSON.toJSONString(resp) : null);
|
action.setResultStatus(ok ? Constants.ONE : Constants.ZERO);
|
action.setResultMsg(ok ? "成功" : apiMsg(resp, "失败"));
|
action.setSource("admin");
|
saveAction(action, user);
|
if (!ok) {
|
throw new BusinessException(ResponseStatus.SERVER_ERROR.getCode(), apiMsg(resp, "查询失败"));
|
}
|
if (ACTION_QUERY_DL == actionType && resp.getData() != null) {
|
try {
|
BigDecimal dl = new BigDecimal(String.valueOf(resp.getData()));
|
meter.setTotalDl(dl);
|
} catch (Exception ignored) {
|
}
|
}
|
if (ACTION_QUERY_POWER == actionType && resp.getData() != null) {
|
try {
|
BigDecimal kw = new BigDecimal(String.valueOf(resp.getData()));
|
meter.setPowerKw(kw);
|
} catch (Exception ignored) {
|
}
|
}
|
meter.setLastSyncDate(new Date());
|
meterMapper.updateById(meter);
|
return "查询成功";
|
}
|
|
@Override
|
public void saveAction(YwConditionerActions action, LoginUserInfo user) {
|
Date now = new Date();
|
if (action.getCreateDate() == null) {
|
action.setCreateDate(now);
|
}
|
if (action.getCreator() == null && user != null) {
|
action.setCreator(user.getId());
|
}
|
action.setIsdeleted(Constants.ZERO);
|
actionsMapper.insert(action);
|
}
|
|
@Override
|
public YwConditionerUsageReportPageDTO queryUsageReport(YwConditionerReportQueryDTO query) {
|
YwConditionerReportQueryDTO q = query != null ? query : new YwConditionerReportQueryDTO();
|
ReportDateRange range = resolveReportDateRange(q);
|
LocalDate start = range.start;
|
LocalDate end = range.end;
|
List<String> dateColumns = new ArrayList<>();
|
DateTimeFormatter colFmt = range.dayMode
|
? DateTimeFormatter.ofPattern("yyyy-MM-dd")
|
: DateTimeFormatter.ofPattern("M.d");
|
for (LocalDate d = start; !d.isAfter(end); d = d.plusDays(1)) {
|
dateColumns.add(d.format(colFmt));
|
}
|
QueryWrapper<YwConditionerUsage> wrapper = new QueryWrapper<>();
|
wrapper.lambda()
|
.eq(YwConditionerUsage::getIsdeleted, Constants.ZERO)
|
.ge(YwConditionerUsage::getUsageDate, java.sql.Date.valueOf(start))
|
.le(YwConditionerUsage::getUsageDate, java.sql.Date.valueOf(end));
|
if (q.getGsId() != null) {
|
wrapper.lambda().eq(YwConditionerUsage::getGsId, q.getGsId());
|
}
|
if (StringUtils.isNotBlank(q.getDevKeyword())) {
|
wrapper.lambda().and(w -> w.like(YwConditionerUsage::getDevName, q.getDevKeyword())
|
.or().eq(YwConditionerUsage::getPlatformDevId, parseIntOrNull(q.getDevKeyword())));
|
}
|
List<YwConditionerUsage> rows = usageMapper.selectList(wrapper);
|
Map<Integer, YwConditionerUsageReportVO> grouped = new LinkedHashMap<>();
|
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
|
for (YwConditionerUsage row : rows) {
|
YwConditionerUsageReportVO vo = grouped.computeIfAbsent(row.getPlatformDevId(), k -> {
|
YwConditionerUsageReportVO n = new YwConditionerUsageReportVO();
|
n.setDevId(row.getPlatformDevId());
|
n.setDevName(row.getDevName());
|
n.setTotalTime(BigDecimal.ZERO);
|
n.setTotalDl(BigDecimal.ZERO);
|
n.setTotalDf(BigDecimal.ZERO);
|
return n;
|
});
|
if (StringUtils.isBlank(vo.getDevName()) && StringUtils.isNotBlank(row.getDevName())) {
|
vo.setDevName(row.getDevName());
|
}
|
String dayKey = sdf.format(row.getUsageDate());
|
YwConditionerUsageReportVO.YwConditionerUsageDailyVO daily = new YwConditionerUsageReportVO.YwConditionerUsageDailyVO();
|
daily.setTime(row.getSumTime());
|
daily.setDl(row.getSumDl());
|
daily.setDf(row.getSumDf());
|
vo.getDaily().put(dayKey, daily);
|
vo.setTotalTime(add(vo.getTotalTime(), row.getSumTime()));
|
vo.setTotalDl(add(vo.getTotalDl(), row.getSumDl()));
|
vo.setTotalDf(add(vo.getTotalDf(), row.getSumDf()));
|
}
|
List<YwConditionerUsageReportVO> all = new ArrayList<>(grouped.values());
|
enrichReportDeviceInfo(all);
|
int page = q.getPage() != null && q.getPage() > 0 ? q.getPage() : 1;
|
int capacity = q.getCapacity() != null && q.getCapacity() > 0 ? q.getCapacity() : 20;
|
int from = (page - 1) * capacity;
|
int to = Math.min(from + capacity, all.size());
|
List<YwConditionerUsageReportVO> pageRecords = from >= all.size()
|
? Collections.emptyList() : all.subList(from, to);
|
|
YwConditionerUsageReportPageDTO result = new YwConditionerUsageReportPageDTO();
|
result.setDateColumns(dateColumns);
|
result.setRecords(pageRecords);
|
result.setTotal(all.size());
|
result.setPage(page);
|
result.setCapacity(capacity);
|
return result;
|
}
|
|
@Override
|
public List<Map<String, Object>> gatewayOptions() {
|
List<YwConditionerGateway> list = gatewayMapper.selectList(new QueryWrapper<YwConditionerGateway>().lambda()
|
.eq(YwConditionerGateway::getIsdeleted, Constants.ZERO)
|
.orderByAsc(YwConditionerGateway::getWgMac));
|
return list.stream().map(g -> {
|
Map<String, Object> m = new LinkedHashMap<>();
|
m.put("id", g.getId());
|
m.put("wgMac", g.getWgMac());
|
m.put("label", g.getWgMac() + (StringUtils.isNotBlank(g.getWgBz()) ? " (" + g.getWgBz() + ")" : ""));
|
return m;
|
}).collect(Collectors.toList());
|
}
|
|
@Override
|
public String syncAll() {
|
if (syncing) {
|
throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(), "同步任务正在执行,请稍后");
|
}
|
syncing = true;
|
try {
|
StringBuilder sb = new StringBuilder();
|
sb.append(syncGateways("manual")).append(";");
|
sb.append(syncMeters()).append(";");
|
sb.append(syncBilling()).append(";");
|
sb.append(syncIndoorUnits());
|
return sb.toString();
|
} finally {
|
syncing = false;
|
}
|
}
|
|
private void refreshDevStatus(YwConditioner dev) {
|
GetDevOneRequest oneReq = new GetDevOneRequest();
|
oneReq.setWg_mac(dev.getWgMac());
|
oneReq.setWg_qid(dev.getWgQid());
|
oneReq.fillSessionDefaults();
|
ConditionerBaseResponse<DeviceStatusResponse> resp = ConditionerUtil.getDevOne(oneReq);
|
if (resp != null && resp.isSuccess() && resp.getData() != null) {
|
fillConditionerFromStatus(dev, resp.getData(), null, new Date());
|
}
|
}
|
|
private void applyOperateResultToDevice(YwConditioner dev, int actionType, Object setVal) {
|
if (setVal == null) {
|
return;
|
}
|
Integer val = parseIntOrNull(String.valueOf(setVal));
|
if (val == null) {
|
return;
|
}
|
switch (actionType) {
|
case ACTION_PWR:
|
dev.setPwr(val);
|
break;
|
case ACTION_MODE:
|
dev.setMode(val);
|
break;
|
case ACTION_FAN:
|
dev.setFanSet(val);
|
dev.setFan(val);
|
break;
|
case ACTION_TEMP:
|
dev.setTempSet(val <= 50 ? val * 10 : val);
|
break;
|
default:
|
break;
|
}
|
}
|
|
/** 内机控制操作可读描述,写入控制历史 actionContent */
|
private String formatOperateDescription(int actionType, Object setVal) {
|
Integer val = setVal == null ? null : parseIntOrNull(String.valueOf(setVal));
|
switch (actionType) {
|
case ACTION_PWR:
|
if (val == null) {
|
return "设置开关";
|
}
|
return String.format("设置开关为【%s】", val == 1 ? "开机" : "关机");
|
case ACTION_MODE:
|
if (val == null) {
|
return "设置模式";
|
}
|
return String.format("设置模式为【%s】", modeLabel(val));
|
case ACTION_FAN:
|
if (val == null) {
|
return "设置风速";
|
}
|
return String.format("设置风速为【%s】", fanLabel(val));
|
case ACTION_TEMP:
|
if (val == null) {
|
return "设置温度";
|
}
|
return String.format("设置温度为【%s】", formatTempDisplay(val));
|
default:
|
return setVal == null ? "设备控制" : String.valueOf(setVal);
|
}
|
}
|
|
private String modeLabel(int mode) {
|
switch (mode) {
|
case 1:
|
return "制热";
|
case 2:
|
return "制冷";
|
case 3:
|
return "送风";
|
case 4:
|
return "除湿";
|
default:
|
return String.valueOf(mode);
|
}
|
}
|
|
private String fanLabel(int fan) {
|
switch (fan) {
|
case 1:
|
return "低速";
|
case 2:
|
return "中速";
|
case 3:
|
return "高速";
|
case 4:
|
return "自动";
|
default:
|
return String.valueOf(fan);
|
}
|
}
|
|
private String formatTempDisplay(int val) {
|
double celsius = val > 100 ? val / 10.0 : val;
|
if (Math.abs(celsius - Math.rint(celsius)) < 0.05) {
|
return String.format("%.0f℃", celsius);
|
}
|
return String.format("%.1f℃", celsius);
|
}
|
|
private DevControlRequest buildMeterQueryRequest(YwConditionerMeter meter, String setType) {
|
if (StringUtils.isBlank(meter.getWgMac())) {
|
throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(), "电表未绑定网关,请先同步电表");
|
}
|
if (StringUtils.isBlank(meter.getDbAdr())) {
|
throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(), "电表地址为空,请先同步电表");
|
}
|
if (StringUtils.isBlank(meter.getXyName())) {
|
throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(), "电表协议为空,请先同步电表");
|
}
|
DevControlRequest req = new DevControlRequest();
|
req.fillSessionDefaults();
|
req.setWg_mac(meter.getWgMac());
|
req.setWg_qid(meter.getDbAdr());
|
req.setCtr_type("set_one");
|
req.setSet_type(setType);
|
JSONObject setVal = new JSONObject();
|
setVal.put("db_bb", meter.getDbBb() != null ? meter.getDbBb() : 1);
|
setVal.put("xy_name", meter.getXyName());
|
req.setSet_val(setVal);
|
return req;
|
}
|
|
private DevControlRequest buildDevControl(YwConditioner dev, String setType, Object setVal) {
|
DevControlRequest req = new DevControlRequest();
|
req.fillSessionDefaults();
|
req.setPid(StringUtils.defaultIfBlank(dev.getPid(), PID_DLJ));
|
req.setWg_mac(dev.getWgMac());
|
req.setWg_qid(dev.getWgQid());
|
req.setCtr_type("set_one");
|
req.setSet_type(setType);
|
req.setSet_val(setVal);
|
return req;
|
}
|
|
private void saveActionRecord(YwConditioner dev, int actionType, String content, boolean ok,
|
ConditionerBaseResponse<?> resp, String reqJson, String source, LoginUserInfo user) {
|
YwConditionerActions action = new YwConditionerActions();
|
action.setConditionerId(dev.getId());
|
action.setPlatformDevId(dev.getPlatformDevId());
|
action.setDevName(dev.getName());
|
action.setWgMac(dev.getWgMac());
|
action.setActionType(actionType);
|
action.setActionContent(content);
|
action.setRequestBody(reqJson);
|
action.setResponseBody(resp != null ? JSON.toJSONString(resp) : null);
|
action.setResultStatus(ok ? Constants.ONE : Constants.ZERO);
|
action.setResultMsg(ok ? "成功" : apiMsg(resp, "失败"));
|
action.setSource(StringUtils.defaultIfBlank(source, "admin"));
|
saveAction(action, user);
|
}
|
|
private void writeGatewayLog(Integer gatewayId, String wgMac, String oldStatus, String newStatus,
|
String source, Date now) {
|
YwConditionerGatewayLog log = new YwConditionerGatewayLog();
|
log.setCreator(0);
|
log.setCreateDate(now);
|
log.setIsdeleted(Constants.ZERO);
|
log.setGatewayId(gatewayId);
|
log.setWgMac(wgMac);
|
log.setOldStatus(oldStatus);
|
log.setNewStatus(newStatus);
|
log.setLogTime(now);
|
log.setSource(StringUtils.defaultIfBlank(source, "manual"));
|
gatewayLogMapper.insert(log);
|
}
|
|
private void fillMeter(YwConditionerMeter local, MeterDbInfoResponse item, Date now) {
|
local.setPlatformDbId(item.getDb_id());
|
local.setDbName(item.getDb_name());
|
local.setDbAdr(item.getDb_adr());
|
local.setWgMac(item.getWg_mac());
|
local.setWgId(item.getWg_id());
|
local.setXyId(item.getXy_id());
|
local.setXyName(item.getXy_name());
|
local.setDbBb(item.getDb_bb());
|
local.setOutdoorLoop(item.getDb_rhd());
|
local.setDbUptime(item.getDb_uptime());
|
if (item.getDb_data() != null) {
|
local.setDbData(JSON.toJSONString(item.getDb_data()));
|
}
|
local.setLastSyncDate(now);
|
local.setEditDate(now);
|
}
|
|
private void fillConditionerFromStatus(YwConditioner local, DeviceStatusResponse item,
|
DeviceArchiveResponse archive, Date now) {
|
local.setPlatformDevId(item.getDev_id());
|
local.setWgId(item.getWg_id());
|
local.setWgMac(item.getWg_mac());
|
local.setWgQid(item.getWg_qid());
|
local.setPid(StringUtils.defaultIfBlank(item.getPid(), PID_DLJ));
|
local.setOnline(ConditionerConstant.normalizeDeviceOnline(item.getOnline()));
|
local.setPwr(item.getPwr());
|
local.setMode(item.getMode());
|
local.setFan(item.getFan());
|
local.setFanSet(item.getFan_set());
|
local.setTemp(item.getTemp());
|
local.setTempSet(item.getTemp_set());
|
local.setKtLock(item.getKt_lock());
|
local.setStopLogo(item.getStop_logo());
|
local.setUptime(item.getUptime());
|
local.setFloorId(item.getFloor_id());
|
local.setFloorName(item.getFloor_name());
|
local.setRoomId(item.getRoom_id());
|
local.setRoomName(item.getRoom_name());
|
local.setDevTypeId(item.getDev_type_id());
|
local.setDevTypeName(item.getDev_type_name());
|
if (StringUtils.isNotBlank(item.getDev_name())) {
|
local.setName(item.getDev_name());
|
}
|
if (archive != null) {
|
if (StringUtils.isNotBlank(archive.getDev_name())) {
|
local.setName(archive.getDev_name());
|
}
|
if (archive.getFloor_id() != null) {
|
local.setFloorId(archive.getFloor_id());
|
}
|
if (StringUtils.isNotBlank(archive.getFloor_name())) {
|
local.setFloorName(archive.getFloor_name());
|
}
|
if (archive.getRoom_id() != null) {
|
local.setRoomId(archive.getRoom_id());
|
}
|
if (StringUtils.isNotBlank(archive.getRoom_name())) {
|
local.setRoomName(archive.getRoom_name());
|
}
|
}
|
local.setLastSyncDate(now);
|
local.setEditDate(now);
|
}
|
|
private YwConditioner findConditionerByPlatformDevId(Integer platformDevId) {
|
return conditionerMapper.selectOne(new QueryWrapper<YwConditioner>().lambda()
|
.eq(YwConditioner::getIsdeleted, Constants.ZERO)
|
.eq(YwConditioner::getPlatformDevId, platformDevId)
|
.last(" limit 1 "));
|
}
|
|
private YwConditioner requireConditioner(Integer id) {
|
YwConditioner dev = conditionerMapper.selectById(id);
|
if (dev == null || Objects.equals(dev.getIsdeleted(), Constants.ONE)) {
|
throw new BusinessException(ResponseStatus.DATA_EMPTY);
|
}
|
if (StringUtils.isBlank(dev.getWgMac()) || StringUtils.isBlank(dev.getWgQid())) {
|
throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(), "设备未绑定平台网关信息,请先同步内机");
|
}
|
return dev;
|
}
|
|
private void ensureDeviceOnline(YwConditioner dev) {
|
if (!"在线".equals(ConditionerConstant.normalizeDeviceOnline(dev.getOnline()))) {
|
throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(), "设备离线了,请检查对应设备网络");
|
}
|
}
|
|
private YearMonth parseMonth(String month) {
|
if (StringUtils.isBlank(month)) {
|
return YearMonth.now().minusMonths(1);
|
}
|
try {
|
return YearMonth.parse(month, DateTimeFormatter.ofPattern("yyyy-MM"));
|
} catch (Exception e) {
|
return YearMonth.now().minusMonths(1);
|
}
|
}
|
|
private void enrichReportDeviceInfo(List<YwConditionerUsageReportVO> records) {
|
if (records == null || records.isEmpty()) {
|
return;
|
}
|
Set<Integer> devIds = records.stream()
|
.map(YwConditionerUsageReportVO::getDevId)
|
.filter(Objects::nonNull)
|
.collect(Collectors.toSet());
|
if (devIds.isEmpty()) {
|
return;
|
}
|
List<YwConditioner> devs = conditionerMapper.selectList(new QueryWrapper<YwConditioner>().lambda()
|
.eq(YwConditioner::getIsdeleted, Constants.ZERO)
|
.in(YwConditioner::getPlatformDevId, devIds));
|
Map<Integer, YwConditioner> devMap = devs.stream()
|
.filter(d -> d.getPlatformDevId() != null)
|
.collect(Collectors.toMap(YwConditioner::getPlatformDevId, d -> d, (a, b) -> a));
|
for (YwConditionerUsageReportVO vo : records) {
|
YwConditioner dev = devMap.get(vo.getDevId());
|
if (dev == null) {
|
continue;
|
}
|
vo.setFloorName(dev.getFloorName());
|
vo.setRoomName(dev.getRoomName());
|
if (StringUtils.isNotBlank(dev.getName())) {
|
vo.setDevName(dev.getName());
|
}
|
}
|
}
|
|
private static class ReportDateRange {
|
LocalDate start;
|
LocalDate end;
|
boolean dayMode;
|
}
|
|
private ReportDateRange resolveReportDateRange(YwConditionerReportQueryDTO q) {
|
String reportType = StringUtils.defaultIfBlank(q.getReportType(), "month");
|
ReportDateRange range = new ReportDateRange();
|
if ("day".equalsIgnoreCase(reportType)) {
|
if (StringUtils.isBlank(q.getStartTime()) || StringUtils.isBlank(q.getEndTime())) {
|
throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "请选择时间段");
|
}
|
LocalDate start;
|
LocalDate end;
|
try {
|
start = LocalDate.parse(q.getStartTime());
|
end = LocalDate.parse(q.getEndTime());
|
} catch (Exception e) {
|
throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "日期格式不正确");
|
}
|
if (end.isBefore(start)) {
|
throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "结束日期不能早于开始日期");
|
}
|
long days = ChronoUnit.DAYS.between(start, end) + 1;
|
if (days > 31) {
|
throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), "时间段不能超过31天");
|
}
|
range.start = start;
|
range.end = end;
|
range.dayMode = true;
|
return range;
|
}
|
YearMonth ym = parseMonth(q.getMonth());
|
range.start = ym.atDay(1);
|
range.end = ym.atEndOfMonth();
|
range.dayMode = false;
|
return range;
|
}
|
|
private Date parseDate(String text) {
|
try {
|
if (text.length() > 10) {
|
return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(text);
|
}
|
return new SimpleDateFormat("yyyy-MM-dd").parse(text);
|
} catch (Exception e) {
|
return null;
|
}
|
}
|
|
private Integer parseIntOrNull(String text) {
|
try {
|
return Integer.parseInt(text.trim());
|
} catch (Exception e) {
|
return null;
|
}
|
}
|
|
private BigDecimal add(BigDecimal a, BigDecimal b) {
|
if (a == null) {
|
a = BigDecimal.ZERO;
|
}
|
return b != null ? a.add(b) : a;
|
}
|
|
private String apiMsg(ConditionerBaseResponse<?> resp, String def) {
|
return resp != null && StringUtils.isNotBlank(resp.getMessage()) ? resp.getMessage() : def;
|
}
|
}
|