package com.xy.service;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.text.StrBuilder;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
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.list.JList;
import com.xy.collections.map.JMap;
import com.xy.config.DeviceThreadPoolConfig;
import com.xy.consts.DictConsts;
import com.xy.device.*;
import com.xy.dto.*;
import com.xy.dto.api.biz.ContainerAddDTO;
import com.xy.dto.be.MercDto;
import com.xy.dto.common.MercPlaceDto;
import com.xy.dto.device.DeviceQueryDTO;
import com.xy.dto.device.DeviceRegDTO;
import com.xy.dto.mini.MiniDeviceInfoDto;
import com.xy.dto.nfc.ActiveDeviceDTO;
import com.xy.entity.*;
import com.xy.enums.FileExportType;
import com.xy.error.CommRuntimeException;
import com.xy.mapper.DeviceInfoMapper;
import com.xy.mapper.entity.DeviceInfoQueryPage;
import com.xy.service.be.MercFeignService;
import com.xy.service.be.MercService;
import com.xy.service.common.MercPlaceService;
import com.xy.service.common.MercRegionService;
import com.xy.sys.EnumDataClearSize;
import com.xy.util.ExcelUtils;
import com.xy.utils.*;
import com.xy.utils.Enum.AlgorithmTypeEnum;
import com.xy.utils.enums.*;
import com.xy.vo.DeviceQueryVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import jodd.introspector.MapperFunction;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;
import static com.xy.utils.PlusBeans.*;
/**
*
* 设备-信息 服务实现类
*
*
* @author lijin
* @since 2022-12-23
*/
@Slf4j
@Service
@RequiredArgsConstructor
@Api(tags = "设备-信息")
public class DeviceInfoServiceImpl extends ServiceImpl implements DeviceInfoService {
/**
* 质检商户code
*/
public static final String QA_MERC_CODE = "10001";
private final CloudWalkApiService cloudWalkApiService;
private final AlgorithmService algorithmService;
private final CountApiService countApiService;
private final TyApiService tyApiService;
private final MercFeignService mercFeignService;
private final DeviceSysinfoServiceImpl deviceSysinfoService;
private final DeviceStatusServiceImpl deviceStatusService;
private final DeviceRegisterServiceImpl deviceRegisterService;
private final DeviceEventMsgServiceImpl deviceEventMsgService;
private final DeviceDataServiceImpl deviceDataService;
private final DeviceTempRecordsServiceImpl deviceTempRecordsService;
private final DeviceNetRecordServiceImpl deviceNetRecordService;
private final GoodsDeviceService goodsDeviceService;
private final FileExportService fileExportService;
private final RedisService redisService;
private final GoodsService goodsService;
private final AlipayDeviceService alipayDeviceService;
private final String keyPrefix = "device:history:";
private final MercRegionService mercRegionService;
private final DeviceAlgorithmChargingServiceImpl deviceAlgorithmChargingService;
private final MercPlaceService mercPlaceService;
private final MercUserBindDeviceService mercUserBindDeviceService;
private final DevicePartServiceImpl devicePartService;
private final MercService mercService;
private final MercDeviceQrConfigService mercDeviceQrConfigService;
private final DeviceCreateIdsServiceImpl deviceCreateIdsService;
@Override
@ApiOperation("设备列表-管理员")
public R> listByAdminName(@RequestBody @Validated DeviceInfoDto.GroupByAdminNameDto dto) {
String noAdmin = "未分配管理员";
List deviceInfoList = baseMapper.listByAdminName(dto);
deviceInfoList.forEach(i -> {
SysDictRedis dictDeviceType = SysDictUtils.get(DictConsts.DEVICE_TYPE, String.valueOf(i.getDeviceType()));
i.setDeviceTypeName(dictDeviceType.getMsg());
if (!Emptys.check(i.getDeviceName())) {
i.setDeviceName("");
}
});
// 没有管理员的的设置默认值
deviceInfoList.stream().filter(s -> s.getAdminName() == null).forEach(s -> s.setAdminName(noAdmin));
return R.ok(deviceInfoList);
}
//@Override
@ApiOperation("设备分页-管理员")
@Override
public R> pageByAdminName(@RequestBody @Validated DeviceInfoDto.PageByAdminNameDto dto) {
PageBean page = dto.getPage();
String noAdmin = "未分配管理员";
IPage deviceInfoList = baseMapper.pageByAdminName(toIPage(page), dto);
deviceInfoList.getRecords().forEach(i -> {
SysDictRedis dictDeviceType = SysDictUtils.get(DictConsts.DEVICE_TYPE, String.valueOf(i.getDeviceType()));
i.setDeviceTypeName(dictDeviceType.getMsg());
if (!Emptys.check(i.getDeviceName())) {
i.setDeviceName("");
}
});
// 没有管理员的的设置默认值
deviceInfoList.getRecords().stream().filter(s -> s.getAdminName() == null).forEach(s -> s.setAdminName(noAdmin));
return R.ok(toPageBean(DeviceInfoDto.ListByAdminName.class, deviceInfoList));
}
@Override
@ApiOperation("设备分组-管理员")
public R> groupByAdminName(@RequestBody @Validated DeviceInfoDto.GroupByAdminNameDto dto) {
String noAdmin = "未分配管理员";
List deviceInfoList = listByAdminName(dto).getData();
// 根据管理员名字分组
Map> deviceMap = deviceInfoList.stream().collect(Collectors.groupingBy(DeviceInfoDto.ListByAdminName::getAdminName));
List list = new ArrayList<>();
// 不包含未分配管理员的
deviceMap.forEach(
(k, i) -> {
DeviceInfoDto.GroupByAdminNameVo vo = new DeviceInfoDto.GroupByAdminNameVo();
if (!noAdmin.equals(k)) {
vo.setAdminName(k)
.setDeviceNum(i.size())
.setDeviceInfos(i);
list.add(vo);
}
}
);
// 包含分配管理员的
List noAdminNamesList = deviceMap.get(noAdmin);
if (Emptys.check(noAdminNamesList)) {
DeviceInfoDto.GroupByAdminNameVo vo = new DeviceInfoDto.GroupByAdminNameVo();
vo.setAdminName(noAdmin)
.setDeviceNum(noAdminNamesList.size())
.setDeviceInfos(noAdminNamesList);
list.add(vo);
}
return R.ok(list);
}
public R> groupByAdminCount(@RequestBody @Validated DeviceInfoDto.GroupByAdminNameDto dto) {
String noAdmin = "未分配管理员";
List deviceInfoList = listByAdminName(dto).getData();
// 根据管理员名字分组
Map> deviceMap = deviceInfoList.stream().collect(Collectors.groupingBy(DeviceInfoDto.ListByAdminName::getAdminName));
List list = new ArrayList<>();
// 不包含未分配管理员的
deviceMap.forEach(
(k, i) -> {
DeviceInfoDto.GroupByAdminNameVo vo = new DeviceInfoDto.GroupByAdminNameVo();
if (!noAdmin.equals(k)) {
vo.setAdminName(k)
.setDeviceNum(i.size())
.setDeviceInfos(i);
list.add(vo);
}
}
);
// 包含分配管理员的
List noAdminNamesList = deviceMap.get(noAdmin);
if (Emptys.check(noAdminNamesList)) {
DeviceInfoDto.GroupByAdminNameVo vo = new DeviceInfoDto.GroupByAdminNameVo();
vo.setAdminName(noAdmin)
.setDeviceNum(noAdminNamesList.size())
.setDeviceInfos(noAdminNamesList);
list.add(vo);
}
return R.ok(list);
}
@PostMapping("eventList")
@ApiOperation("根据事件编码查询设备")
public R> eventList(@RequestBody @Validated DeviceInfoDto.EventList eventList) {
String countAs = "id";
QueryWrapper queryWrapper = new QueryWrapper()
.select(LambdaUtils.getUnderlineCaseName(DeviceEventMsg::getDeviceId) + " as " + LambdaUtils.getProperty(DeviceEventMsg::getDeviceId), "count(*) as " + countAs)
.eq(LambdaUtils.getUnderlineCaseName(DeviceEventMsg::getCode), eventList.getCode())
.between(LambdaUtils.getUnderlineCaseName(DeviceEventMsg::getCreateTime), eventList.getBeginTime(), eventList.getEndTime())
.groupBy(LambdaUtils.getUnderlineCaseName(DeviceEventMsg::getDeviceId))
.last("HAVING " + countAs + " >= " + eventList.getSize());
IPage iPage = deviceEventMsgService.page(toIPage(eventList.getPage()), queryWrapper);
PageBean pageBean = new PageBean()
.setSize(iPage.getSize())
.setCurrent(iPage.getCurrent())
.setTotal(iPage.getTotal());
List list = iPage.getRecords();
if (!Emptys.check(list)) {
return R.ok(pageBean);
}
List deviceInfos = listByIds(new JArrayList<>(list).getProperty(DeviceEventMsg::getDeviceId));
List eventListVos = copy(DeviceInfoDto.EventListVo.class, deviceInfos);
List builder = copy(eventListVos)
.target(list, DeviceInfoDto.EventListVo::getDeviceId, DeviceInfoDto.EventListVo::getSize, DeviceEventMsg::getDeviceId, DeviceEventMsg::getId)
.builder();
return R.ok(pageBean.setRecords(builder));
}
@ApiOperation("拓元算法设备列表")
@PostMapping("tyDeviceList")
public R> tyDeviceList(@RequestBody @Validated DeviceInfoDto.TyDeviceDTO dto) {
PageBean pageBean = dto.getPage();
String searchKey = dto.getSearchKey();
Integer thirdStatus = dto.getThirdStatus();
List statusList = new ArrayList<>();
// 1待审核,2已审核
if (thirdStatus != null && thirdStatus.intValue() == 1) {
statusList = CollUtil.newArrayList("1000", "2000", "3000", "5000");
}
// 2已审核 4000: 设备登记成功
if (thirdStatus != null && thirdStatus.intValue() == 2) {
statusList.add("4000");
}
LambdaQueryWrapper lqw = new LambdaQueryWrapper<>();
lqw.eq(DeviceInfo::getAlgorithmId, AlgorithmTypeEnum.TY.getId());
lqw.in(CollUtil.isNotEmpty(statusList), DeviceInfo::getThirdStatus, statusList);
lqw.and(StrUtil.isNotEmpty(searchKey), wrapper -> wrapper
.eq(DeviceInfo::getDeviceId, searchKey)
.or()
.likeRight(DeviceInfo::getDeviceName, searchKey));
IPage iPage = page(toIPage(pageBean), lqw);
List records = iPage.getRecords();
if (CollUtil.isNotEmpty(records)) {
ThreadPoolUtils.Execute execute = ThreadPoolUtils.excPoll(DeviceThreadPoolConfig.TY_DEVICE_STATUS, records.size());
records.forEach(deviceInfo -> execute.execute(() -> {
Long deviceId = deviceInfo.getDeviceId();
/**
* 请求状态码。
* 1000: 未知的设备CPUID
* 2000: 设备登记 审批中
* 3000: 设备登记已拒绝
* 4000: 设备登记成功
* 5000: 设备已禁⽤
*/
String tyStatus = deviceInfo.getThirdStatus();
if (!"4000".equals(tyStatus)) {
// 未登记成功的需要实时查询
// 查询登记设备
DeviceQueryVO deviceQueryVO = tyApiService.deviceQuery(new DeviceQueryDTO().setCpuId(String.valueOf(deviceId)));
Integer status = deviceQueryVO.getStatus();
String message = deviceQueryVO.getMessage();
deviceInfo.setThirdStatus(String.valueOf(status));
deviceInfo.setThirdResult(message);
updateById(deviceInfo);
}
}));
execute.end();
}
PageBean voPageBean = toPageBean(DeviceInfoDto.Vo.class, iPage);
return R.ok(voPageBean);
}
/**
* 商户设备列表分页-穿梭框用
*
* @param dto
* @return {@link R}<{@link List}<{@link DeviceInfoDto.MyDeviceInfo}>>
*/
public R> myDeviceList(@RequestBody @Validated DeviceInfoDto.MyDeviceDTO dto) {
PageBean pageBean = dto.getPage();
String searchKey = dto.getSearchKey();
Long mercId = dto.getMercId();
Integer type = dto.getType();
Long strategyId = dto.getStrategyId();
GoodsDeviceDto.SelectList selectList = new GoodsDeviceDto.SelectList();
if (strategyId != null) {
selectList.setMercId(mercId).setPriceStrategyId(strategyId);
}
List goodsDevices = R.feignCheckData(goodsDeviceService.list(selectList));
if (type == 2 && CollUtil.isEmpty(goodsDevices)) {
// 右侧已选的
return R.ok(new PageBean<>());
}
List deviceIds = goodsDevices.stream().map(GoodsDeviceDto.Vo::getDeviceId).collect(Collectors.toList());
LambdaQueryWrapper lqw = new MybatisPlusQuery().eqWrapper(dto, DeviceInfo.class)
.build();
lqw.in(type == 2 && CollUtil.isNotEmpty(deviceIds), DeviceInfo::getDeviceId, deviceIds);
// 左侧排除掉已关联的
lqw.notIn(type == 1 && CollUtil.isNotEmpty(deviceIds), DeviceInfo::getDeviceId, deviceIds);
lqw.and(StrUtil.isNotEmpty(searchKey), wrapper -> wrapper
.eq(DeviceInfo::getDeviceId, searchKey)
.or()
.likeRight(DeviceInfo::getDeviceName, searchKey));
IPage iPage = page(toIPage(pageBean), lqw);
return R.ok(toPageBean(DeviceInfoDto.MyDeviceInfo.class, iPage));
}
@ApiOperation("点位设备数量查询")
@Override
public R> placeDeviceNum(@RequestBody @Validated DeviceInfoDto.PlaceDeviceNumDto dto) {
return R.ok(baseMapper.placeDeviceNum(dto));
}
@Override
@ApiOperation("设备列表带卡包数")
public R> algorithmChargingDevice(@RequestBody @Validated DeviceInfoDto.AlgorithmCharging algorithmCharging) {
PageBean pageBean = algorithmCharging.getPage();
// 查询设备
Integer value = SysDictUtils.getValue(EnumDeviceActiveStatus.Code.CODE.getCode(), EnumDeviceActiveStatus.N_1.getCode(), Integer.class);
LambdaUpdateWrapper lambdaUpdateWrapper = new LambdaUpdateWrapper()
.eq(DeviceInfo::getMercId, algorithmCharging.getMercId())
.eq(DeviceInfo::getActiveState, value)
.in(Emptys.check(algorithmCharging.getDeviceIds()), DeviceInfo::getDeviceId, algorithmCharging.getDeviceIds())
.orderByDesc(DeviceInfo::getCreateTime);
IPage page = page(toIPage(pageBean), lambdaUpdateWrapper);
PageBean algorithmChargingVoPageBean = toPageBean(DeviceInfoDto.AlgorithmChargingVo.class, page);
List algorithmChargingVos = algorithmChargingVoPageBean.getRecords();
if (!Emptys.check(algorithmChargingVos)) {
return R.ok(algorithmChargingVoPageBean);
}
// 查询卡包数量
List data = deviceAlgorithmChargingService.count(new DeviceAlgorithmChargingDto.Count()
.setDeviceIds(new JArrayList<>(algorithmChargingVos).getProperty(DeviceInfoDto.AlgorithmChargingVo::getDeviceId))
.setMercId(algorithmCharging.getMercId())
).getData();
JMap cover = new JArrayList<>(data).toMap(DeviceAlgorithmChargingDto.CountVo::getDeviceId).cover();
algorithmChargingVos.forEach(algorithmChargingVo -> {
DeviceAlgorithmChargingDto.CountVo countVo = cover.get(algorithmChargingVo.getDeviceId());
Beans.copy(algorithmChargingVo, countVo);
});
return R.ok(algorithmChargingVoPageBean);
}
@Override
@ApiOperation("设备在线数查询")
public R