package com.xy.service;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xy.collections.list.JArrayList;
import com.xy.collections.map.JConcurrentHashMap;
import com.xy.collections.map.JHashMap;
import com.xy.collections.map.JMap;
import com.xy.device.EnumDeviceActiveStatus;
import com.xy.device.EnumDeviceBusyStatus;
import com.xy.device.EnumDeviceDataType;
import com.xy.device.EnumDeviceOnlineStatus;
import com.xy.dto.*;
import com.xy.entity.*;
import com.xy.mapper.DeviceDataMapper;
import com.xy.utils.*;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import javax.validation.Valid;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import static com.xy.utils.Beans.copy;
import static com.xy.utils.PlusBeans.toIPage;
import static com.xy.utils.PlusBeans.toPageBean;
/**
*
* 设备统计数据 服务实现类
*
*
* @author lijin
* @since 2023-01-11
*/
@Service
@AllArgsConstructor(onConstructor_ = @Lazy)
@Api(tags = "设备统计数据")
public class DeviceDataServiceImpl extends ServiceImpl implements DeviceDataService {
private final DeviceInfoServiceImpl deviceInfoService;
private final DeviceStatusServiceImpl deviceStatusService;
private final OrdersService ordersService;
private final DeviceChargingServiceImpl deviceChargingService;
/**
* 设备统计
*
* @param dto
* @return {@link DeviceDataDto.MercHomePageCountVO}
*/
public DeviceDataDto.MercHomePageCountVO deviceCount(@RequestBody @Valid DeviceDataDto.MercHomePageCount dto) {
DeviceDataDto.MercHomePageCountVO vo = new DeviceDataDto.MercHomePageCountVO()
.setOfflineNum(0).setOnlineNum(0).setUnActiveNum(0).setOutOfServiceNum(0);
Long mercId = dto.getMercId();
List myDeviceIds = dto.getMyDeviceIds();
if (mercId != null && CollUtil.isEmpty(myDeviceIds)) {
//指定商户查询用,平台查询预留逻辑
List vos = R.feignCheckData(deviceInfoService.list(new DeviceInfoDto.ListDto().setMercId(mercId)));
if (CollUtil.isEmpty(vos)) {
return vo;
}
myDeviceIds = vos.stream().map(DeviceInfoDto.Vo::getDeviceId).collect(Collectors.toList());
}
List mercDevices = deviceInfoService.listByIds(myDeviceIds);
if (CollUtil.isEmpty(mercDevices)) {
return vo;
}
//待激活数量
Long unActiveNum = mercDevices.stream()
.filter(device -> device.getActiveState() == 2)
.count();
//停运状态数量
Long outOfServiceNum = mercDevices.stream()
.filter(device -> device.getBusyState() == 2)
.count();
vo.setOutOfServiceNum(outOfServiceNum.intValue());
vo.setUnActiveNum(unActiveNum.intValue());
List deviceStatuses = deviceStatusService.listByIds(myDeviceIds);
//分组统计
Map countNetstateMap = deviceStatuses.stream().collect(Collectors
.groupingBy(DeviceStatus::getNetState, Collectors.counting()));
Integer onlineDictValue = SysDictUtils.getValue(EnumDeviceOnlineStatus.Code.CODE.getCode(), EnumDeviceOnlineStatus.CONNECTED.getCode(), Integer.class);
Integer offlineDictValue = SysDictUtils.getValue(EnumDeviceOnlineStatus.Code.CODE.getCode(), EnumDeviceOnlineStatus.DISCONNECT.getCode(), Integer.class);
int onlineNum = countNetstateMap.get(onlineDictValue) == null ? 0 : countNetstateMap.get(onlineDictValue).intValue();
int offlineNum = countNetstateMap.get(offlineDictValue) == null ? 0 : countNetstateMap.get(offlineDictValue).intValue();
vo.setOnlineNum(onlineNum);
vo.setOfflineNum(offlineNum);
return vo;
}
@PostMapping("sumPage")
@ApiOperation("设备销售统计")
public R> sumPage(@RequestBody @Valid DeviceDataDto.SumPageDto dto) {
PageBean pageBean = dto.getPage();
List mercDeviceIds = dto.getMercDeviceIds();
String salesCount = StringTools.humpToLine(LambdaUtils.getProperty(DeviceData::getSalesCount));
String salesMoney = StringTools.humpToLine(LambdaUtils.getProperty(DeviceData::getSalesMoney));
String goodsCount = StringTools.humpToLine(LambdaUtils.getProperty(DeviceData::getGoodsCount));
String refundMoney = StringTools.humpToLine(LambdaUtils.getProperty(DeviceData::getRefundMoney));
String refundCount = StringTools.humpToLine(LambdaUtils.getProperty(DeviceData::getRefundCount));
String riskCount = StringTools.humpToLine(LambdaUtils.getProperty(DeviceData::getRiskCount));
String zeroCount = StringTools.humpToLine(LambdaUtils.getProperty(DeviceData::getZeroCount));
String deviceId = StringTools.humpToLine(LambdaUtils.getProperty(DeviceData::getDeviceId));
LambdaQueryWrapper lqw = new QueryWrapper()
.select(String.format("%s,sum(%s) %s,sum(%s) %s,sum(%s) %s,sum(%s) %s,sum(%s) %s,sum(%s) %s,sum(%s) %s"
, deviceId, salesCount, salesCount, salesMoney, salesMoney, goodsCount, goodsCount
, refundMoney, refundMoney, refundCount, refundCount, riskCount, riskCount, zeroCount, zeroCount
))
.orderByAsc("asc".equals(dto.getOrderBy()), dto.getOrderByKey())
.orderByDesc("desc".equals(dto.getOrderBy()), dto.getOrderByKey())
.lambda()
.eq(Emptys.check(dto.getMercId()), DeviceData::getMercId, dto.getMercId())
.eq(DeviceData::getType, dto.getType())
.ge(Emptys.check(dto.getBeginDate()), DeviceData::getDateValue, dto.getBeginDate())
.le(Emptys.check(dto.getEndDate()), DeviceData::getDateValue, dto.getEndDate())
.in(Emptys.check(mercDeviceIds), DeviceData::getDeviceId, mercDeviceIds)
.groupBy(DeviceData::getDeviceId);
IPage ipage = page(toIPage(pageBean), lqw);
if (Emptys.check(ipage.getRecords())) {
List deviceIdList = ipage.getRecords().stream().map(DeviceData::getDeviceId).collect(Collectors.toList());
Map deviceMap = deviceInfoService.getDeviceNameList(new DeviceInfoDto.DeviceIdDto().setDeviceId(deviceIdList)).getData();
PageBean sumPageVoPageBean = toPageBean(DeviceDataDto.SumPageVo.class, ipage);
sumPageVoPageBean.getRecords().forEach(i -> {
i.setDeviceName(deviceMap.get(i.getDeviceId()));
});
return R.ok(sumPageVoPageBean);
}
return R.ok();
}
@PostMapping("sumCount")
@ApiOperation("设备销售统计总计")
public R sumCount(@RequestBody @Valid DeviceDataDto.SumCountDto dto) {
List mercDeviceIds = dto.getMercDeviceIds();
String salesCount = StringTools.humpToLine(LambdaUtils.getProperty(DeviceData::getSalesCount));
String salesMoney = StringTools.humpToLine(LambdaUtils.getProperty(DeviceData::getSalesMoney));
String goodsCount = StringTools.humpToLine(LambdaUtils.getProperty(DeviceData::getGoodsCount));
String refundMoney = StringTools.humpToLine(LambdaUtils.getProperty(DeviceData::getRefundMoney));
String refundCount = StringTools.humpToLine(LambdaUtils.getProperty(DeviceData::getRefundCount));
String riskCount = StringTools.humpToLine(LambdaUtils.getProperty(DeviceData::getRiskCount));
String zeroCount = StringTools.humpToLine(LambdaUtils.getProperty(DeviceData::getZeroCount));
//查询总数
LambdaQueryWrapper lqw = new QueryWrapper()
.select(String.format("sum(%s) %s,sum(%s) %s,sum(%s) %s,sum(%s) %s,sum(%s) %s,sum(%s) %s,sum(%s) %s"
, salesCount, salesCount, salesMoney, salesMoney, goodsCount, goodsCount
, refundMoney, refundMoney, refundCount, refundCount, riskCount, riskCount, zeroCount, zeroCount
))
.lambda()
.eq(Emptys.check(dto.getMercId()), DeviceData::getMercId, dto.getMercId())
.eq(DeviceData::getType, dto.getType())
.ge(Emptys.check(dto.getBeginDate()), DeviceData::getDateValue, dto.getBeginDate())
.le(Emptys.check(dto.getEndDate()), DeviceData::getDateValue, dto.getEndDate())
.in(Emptys.check(mercDeviceIds), DeviceData::getDeviceId, mercDeviceIds);
return R.ok(copy(DeviceDataDto.SumCountVo.class, getOne(lqw)));
}
@PostMapping("obj")
@ApiOperation("对象查询")
public R obj(@RequestBody DeviceDataDto.Vo vo) {
LambdaQueryWrapper lambdaQueryWrapper = new MybatisPlusQuery().eqWrapper(vo, DeviceData.class).build();
List list = list(lambdaQueryWrapper);
if (Emptys.check(list)) {
return R.ok(copy(DeviceDataDto.Vo.class, list).get(0));
}
return R.ok();
}
@PostMapping("page")
@ApiOperation("分页查询")
public R> page(@RequestBody DeviceDataDto.Page page) {
PageBean pageBean = page.getPage();
LambdaQueryWrapper lambdaQueryWrapper = new MybatisPlusQuery().eqWrapper(page, DeviceData.class)
.ge(DeviceData::getCreateTime, page.getBeginCreateTime())
.le(DeviceData::getCreateTime, page.getEndCreateTime())
.build()
.orderByDesc(!Emptys.check(pageBean.getOrders()), DeviceData::getCreateTime);
IPage iPage = page(toIPage(pageBean), lambdaQueryWrapper);
return R.ok(toPageBean(DeviceDataDto.Vo.class, iPage));
}
@ApiOperation("添加/累加")
@PostMapping("saveOrAccum")
public R saveOrAccum(@RequestBody DeviceDataDto.SaveOrAccum saveOrAccum) {
return new SaveOrAccum().saveOrAccum(saveOrAccum, this);
}
/**
* 集合查询
*
* @param dto
* @return
*/
public List list(DeviceDataDto.ListDTO dto) {
LambdaQueryWrapper lambdaQueryWrapper = new MybatisPlusQuery().eqWrapper(dto, DeviceData.class).build();
List list = list(lambdaQueryWrapper);
return copy(DeviceDataDto.Vo.class, list);
}
/**
* 指定查询商户某设备某天数据
*
* @param deviceId
* @param mercId
* @param dateValue
* @return
*/
public DeviceDataDto.Vo getByDay(Long deviceId, Long mercId, String dateValue) {
return getOneData(EnumDeviceDataType.DAY.getCode(), deviceId, mercId, dateValue);
}
/**
* 指定查询商户所有设备某天数据
*
* @param mercId
* @param dateValue
* @return
*/
public List getMercDataOneDay(Long mercId, String dateValue) {
return getMercListData(EnumDeviceDataType.DAY.getCode(), mercId, dateValue);
}
/**
* 指定查询商户所有设备某月数据
*
* @param mercId
* @param dateValue
* @return
*/
public List getMercDataOneMonth(Long mercId, String dateValue) {
return getMercListData(EnumDeviceDataType.MONTH.getCode(), mercId, dateValue);
}
/**
* 指定查询商户某设备某月数据
*
* @param deviceId
* @param mercId
* @param dateValue
* @return
*/
public DeviceDataDto.Vo getByMonth(Long deviceId, Long mercId, String dateValue) {
return getOneData(EnumDeviceDataType.MONTH.getCode(), deviceId, mercId, dateValue);
}
/**
* 指定查询商户某设备某年数据
*
* @param deviceId
* @param mercId
* @param dateValue
* @return
*/
public DeviceDataDto.Vo getByYear(Long deviceId, Long mercId, String dateValue) {
return getOneData(EnumDeviceDataType.YEAR.getCode(), deviceId, mercId, dateValue);
}
/**
* 指定查询商户某设备某年、月、日数据
*
* @param type
* @param deviceId
* @param mercId
* @param dateValue
* @return
*/
public DeviceDataDto.Vo getOneData(String type, Long deviceId, Long mercId, String dateValue) {
LambdaQueryWrapper lambdaQueryWrapper = new LambdaQueryWrapper<>();
lambdaQueryWrapper.eq(DeviceData::getType, type);
lambdaQueryWrapper.eq(DeviceData::getDeviceId, deviceId);
lambdaQueryWrapper.eq(DeviceData::getMercId, mercId);
lambdaQueryWrapper.eq(DeviceData::getDateValue, Integer.valueOf(dateValue));
DeviceData data = getOne(lambdaQueryWrapper);
return copy(DeviceDataDto.Vo.class, data);
}
/**
* 指定查询商户所有设备某年、月、日数据
*
* @param type
* @param mercId
* @param dateValue
* @return
*/
public List getMercListData(String type, Long mercId, String dateValue) {
LambdaQueryWrapper lambdaQueryWrapper = new LambdaQueryWrapper<>();
lambdaQueryWrapper.eq(DeviceData::getType, type);
lambdaQueryWrapper.eq(DeviceData::getMercId, mercId);
lambdaQueryWrapper.eq(DeviceData::getDateValue, Integer.valueOf(dateValue));
List list = list(lambdaQueryWrapper);
return BeanUtil.copyToList(list, DeviceDataDto.Vo.class);
}
/**
* 日范围内每天数据
*
* @param deviceId
* @param startDateValue
* @param endDateValue
* @return
*/
public List getListByDay(Long deviceId, Integer startDateValue, Integer endDateValue) {
return getListData(EnumDeviceDataType.DAY.getCode(), deviceId, startDateValue, endDateValue);
}
/**
* 日期范围查询
*
* @param type
* @param deviceId
* @param startDateValue
* @param endDateValue
* @return
*/
public List getListData(String type, Long deviceId, Integer startDateValue, Integer endDateValue) {
LambdaQueryWrapper lambdaQueryWrapper = new LambdaQueryWrapper<>();
lambdaQueryWrapper.eq(DeviceData::getType, type);
lambdaQueryWrapper.eq(DeviceData::getDeviceId, deviceId);
lambdaQueryWrapper.between(DeviceData::getDateValue, startDateValue, endDateValue);
lambdaQueryWrapper.orderBy(true, true, DeviceData::getDateValue);
List list = list(lambdaQueryWrapper);
return copy(DeviceDataDto.Vo.class, list);
}
@Override
public R> getMercDataOneDay(DeviceDataDto.CountByDay dto) {
return R.ok(this.getMercDataOneDay(dto.getMercId(), dto.getDateValue()));
}
@Override
public R> getMercDataOneMonth(DeviceDataDto.CountByMonth dto) {
return R.ok(this.getMercDataOneMonth(dto.getMercId(), dto.getDateValue()));
}
@ApiOperation("图表数据")
@Override
public R> dayChart(@RequestBody @Valid DeviceDataDto.DayChartDto dto) {
List dayChartVos = baseMapper.dayChart(dto.getMercId(), dto.getBeginInt(), dto.getEndDateInt(), dto.getType());
Map voMap = dayChartVos.stream().collect(Collectors.toMap(DeviceDataDto.DayChartVo::getTime, i -> i));
List dayList = DataTime.getBetweenDates(dto.getBeginDate().toString(), dto.getEndDate().toString(), true);
List dayList2 = dayList.stream().map(i -> Integer.valueOf(StrUtil.replace(i, "-", ""))).collect(Collectors.toList());
List list = new ArrayList<>();
dayList2.forEach(
i -> {
Integer num = 0;
Integer totalMoney = 0;
BigDecimal totalMoneyYuan = new BigDecimal(0);
DeviceDataDto.DayChartVo dayChartVo = voMap.get(i);
if (Emptys.check(dayChartVo)) {
num = dayChartVo.getNum();
totalMoney = dayChartVo.getTotalMoney();
totalMoneyYuan = dayChartVo.getTotalMoneyYuan();
}
list.add(new DeviceDataDto.DayChartVo()
.setTime(i)
.setNum(num)
.setTotalMoney(totalMoney)
.setTotalMoneyYuan(totalMoneyYuan)
);
}
);
return R.ok(list);
}
@Override
@ApiOperation("商户日期维度查询")
public R> pageByMercAndDate(DeviceDataDto.PageByMercAndDate pageByMercAndDate) {
PageBean pageBean = pageByMercAndDate.getPage();
LambdaQueryWrapper lambdaQueryWrapper = new MybatisPlusQuery().eqWrapper(pageByMercAndDate, DeviceData.class)
.in(DeviceData::getDeviceId)
.ge(DeviceData::getDateValue, pageByMercAndDate.getBeginDateValue())
.le(DeviceData::getDateValue, pageByMercAndDate.getEndDateValue())
.build()
.orderByDesc(DeviceData::getDeviceId, DeviceData::getDateValue);
IPage iPage = page(toIPage(pageBean), lambdaQueryWrapper);
return R.ok(toPageBean(DeviceDataDto.Vo.class, iPage));
}
@Override
@ApiOperation("商户日期维度统计查询")
public R pageByMercAndDateCount(DeviceDataDto.PageByMercAndDate pageByMercAndDate) {
LambdaQueryWrapper lambdaQueryWrapper = new MybatisPlusQuery().eqWrapper(pageByMercAndDate, DeviceData.class)
.in(DeviceData::getDeviceId)
.ge(DeviceData::getDateValue, pageByMercAndDate.getBeginDateValue())
.le(DeviceData::getDateValue, pageByMercAndDate.getEndDateValue())
.build();
long count = count(lambdaQueryWrapper);
return R.ok(count);
}
public static class SaveOrAccum {
public R saveOrAccum(DeviceDataDto.SaveOrAccum saveOrAccum, DeviceDataServiceImpl deviceDataService) {
return new LockUtils()
.name("saveOrAccum.deviceId")
.prefix("data_save_accum_")
.build(SaveOrAccum.class)
.exec(saveOrAccum, deviceDataService);
}
@SneakyThrows
public R exec(DeviceDataDto.SaveOrAccum saveOrAccum, DeviceDataServiceImpl deviceDataService) {
LocalDateTime now = LocalDateTime.now();
String yyyyMMdd = DataTime.toString(now, "yyyyMMdd");
//获取字典
Map map = SysDictUtils.get(EnumDeviceDataType.Code.CODE.getCode());
JMap jMap = new JHashMap<>(map.size());
map.forEach((type, sysDictRedis) -> {
Integer dateValue = Integer.valueOf(yyyyMMdd.substring(0, Integer.valueOf(sysDictRedis.getValue())));
jMap.put(type, dateValue);
});
//查询已存在数据
List list = deviceDataService.list(new LambdaQueryWrapper()
.eq(DeviceData::getDeviceId, saveOrAccum.getDeviceId())
.in(DeviceData::getDateValue, jMap.toList().value())
);
JMap typeMaps = new JArrayList<>(list).toMap(DeviceData::getType).cover();
//新增或修改的多线程桶map集合
JMap dbMaps = new JConcurrentHashMap<>(map.size());
//封装新增或修改对象
jMap.forEach((type, dateValue) -> {
DeviceData deviceData = typeMaps.get(type);
//添加
if (deviceData == null) {
DeviceData saveOrUpdateInfo = copy(DeviceData.class, saveOrAccum)
.setCreateTime(now)
.setUpdateTime(now)
.setType(type)
.setDateValue(dateValue);
dbMaps.put(type, saveOrUpdateInfo);
return;
}
//累加
DeviceData updateDeviceData = new DeviceData().setId(deviceData.getId()).setUpdateTime(now)
.setSalesMoney(saveOrAccum.getSalesMoney() != null ? saveOrAccum.getSalesMoney() + deviceData.getSalesMoney() : null)
.setSalesCount(saveOrAccum.getSalesCount() != null ? saveOrAccum.getSalesCount() + deviceData.getSalesCount() : null)
.setGoodsCount(saveOrAccum.getGoodsCount() != null ? saveOrAccum.getGoodsCount() + deviceData.getGoodsCount() : null)
.setRefundMoney(saveOrAccum.getRefundMoney() != null ? saveOrAccum.getRefundMoney() + deviceData.getRefundMoney() : null)
.setRefundCount(saveOrAccum.getRefundCount() != null ? saveOrAccum.getRefundCount() + deviceData.getRefundCount() : null)
.setZeroCount(saveOrAccum.getZeroCount() != null ? saveOrAccum.getZeroCount() + deviceData.getZeroCount() : null)
.setDeviceFaultCount(saveOrAccum.getDeviceFaultCount() != null ? saveOrAccum.getDeviceFaultCount() + deviceData.getDeviceFaultCount() : null);
dbMaps.put(type, updateDeviceData);
});
deviceDataService.saveOrUpdateBatch(dbMaps.toList().value());
return R.ok();
}
}
@ApiOperation("设备统计-运营概况")
@PostMapping("countDevice")
R countDevice(@RequestBody DeviceDataDto.CountDTO dto) {
DeviceDataDto.CountVO vo = new DeviceDataDto.CountVO();
Integer timeType = dto.getTimeType();
int day = 0;
if (timeType == 1) {
//天
day = 1;
} else if (timeType == 2) {
//周
day = 7;
} else if (timeType == 3) {
//月
day = 30;
}
Date now = DateUtil.date();
Date queryDate = DateUtil.offsetDay(now, -day);
//总数 ,只查激活的
Long totalNum = deviceInfoService.count(Wrappers.lambdaQuery().eq(DeviceInfo::getActiveState, EnumDeviceActiveStatus.N_1.getCode()));
vo.setTotalNum(totalNum.intValue());
//新增
Long newAdd = deviceInfoService.count(Wrappers.lambdaQuery()
.ge(DeviceInfo::getCreateTime, queryDate).eq(DeviceInfo::getActiveState, EnumDeviceActiveStatus.N_1.getCode()));
vo.setNewNum(newAdd.intValue());
//活跃 产生订单的
Integer activeNum = null;
vo.setActiveNum(activeNum);
//设备管理费
Long debtNum = deviceChargingService.count(Wrappers.lambdaQuery().lt(DeviceCharging::getTimeout, DateUtil.now()));
vo.setDebtNum(debtNum);
Long outOfServiceNum = deviceInfoService.count(Wrappers.lambdaQuery().eq(DeviceInfo::getBusyState, EnumDeviceBusyStatus.N_2.getCode()).eq(DeviceInfo::getActiveState, EnumDeviceActiveStatus.N_1.getCode()));
vo.setOutOfServiceNum(outOfServiceNum.intValue());
return R.ok(vo);
}
}