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); } }