package com.xy.service; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.collection.CollUtil; 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.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.config.DeviceThreadPoolConfig; import com.xy.consts.DictConsts; import com.xy.dto.DeviceInfoDto; import com.xy.dto.DeviceRegisterDto; import com.xy.dto.DeviceStatusDto; import com.xy.dto.DeviceSysinfoDto; import com.xy.entity.DeviceInfo; import com.xy.entity.DeviceStatus; import com.xy.entity.SysDictRedis; import com.xy.error.CommRuntimeException; import com.xy.mapper.DeviceInfoMapper; import com.xy.mapper.entity.DeviceInfoQueryPage; import com.xy.util.ExcelUtils; import com.xy.utils.*; import com.xy.utils.enums.DictEnum; import com.xy.utils.enums.DictSonEnum; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import jodd.introspector.MapperFunction; import lombok.RequiredArgsConstructor; 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.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.stream.Collectors; import static com.xy.utils.PlusBeans.*; /** *

* 设备-信息 服务实现类 *

* * @author lijin * @since 2022-12-23 */ @Service @RequiredArgsConstructor @Api(tags = "设备-信息") public class DeviceInfoServiceImpl extends ServiceImpl implements DeviceInfoService { private final DeviceSysinfoServiceImpl deviceSysinfoService; private final DeviceStatusServiceImpl deviceStatusService; private final DeviceRegisterServiceImpl deviceRegisterService; private final RedisService redisService; private final String keyPrefix = "device:history:"; @Override @ApiOperation("对象查询") public R obj(DeviceInfoDto.Obj obj) { //设备信息 LambdaQueryWrapper lambdaQueryWrapper = new MybatisPlusQuery().eqWrapper(obj, DeviceInfo.class).build(); List list = list(lambdaQueryWrapper); if (!Emptys.check(list)) { return R.ok(); } DeviceInfoDto.Vo deviceInfo = copy(DeviceInfoDto.Vo.class, list.get(0)); ThreadPoolUtils.excPoll(DeviceThreadPoolConfig.DEVICE_COMMON_POLL, 3) .execute(() -> { //系统信息 DeviceSysinfoDto.Vo deviceSysinfo = deviceSysinfoService.get(new DeviceSysinfoDto.Vo().setDeviceId(deviceInfo.getDeviceId())).getData(); deviceInfo.setDeviceSysinfo(deviceSysinfo); }) .execute(() -> { //状态信息 DeviceStatusDto.Vo deviceStatus = deviceStatusService.obj(new DeviceStatusDto.Vo().setDeviceId(deviceInfo.getDeviceId())).getData(); deviceInfo.setDeviceStatus(deviceStatus); }) .execute(() -> { //注册信息 DeviceRegisterDto.Vo deviceRegister = deviceRegisterService.obj(new DeviceRegisterDto.Vo().setDeviceId(deviceInfo.getDeviceId())).getData(); deviceInfo.setDeviceRegister(deviceRegister); }) .end(); return R.ok(deviceInfo); } @Override @ApiOperation("设备访问历史添加") public R history(DeviceInfoDto.Obj obj) { //获取字典 SysDictRedis sysDictRedis = SysDictUtils.get(DictEnum.DATA_CLEAR_SIZE.getKey(), "device_history_twig"); Integer value = Integer.valueOf(sysDictRedis.getValue()); //获取redis String key = keyPrefix + AuthorizeUtils.getLoginId(Long.class); List list = redisService.getList(key); list.add(0, String.valueOf(obj.getDeviceId())); //去重 List redisList = new ArrayList<>(); JList comparing = new JArrayList<>(list).comparing(); if (comparing.size() > value) { for (int i = 0; i < value; i++) { redisList.add(comparing.get(i)); } } else { redisList = comparing; } redisService.removeList(key); redisService.setList(key, redisList); return R.ok(); } @Override @ApiOperation("开门检测") public R checkOpenDoor(DeviceInfoDto.Obj obj) { DeviceInfoDto.Vo deviceInfo = obj(new DeviceInfoDto.Obj().setDeviceId(obj.getDeviceId())).getData(); if (deviceInfo == null) { return R.fail("设备不存在"); } DeviceStatusDto.Vo deviceStatus = deviceInfo.getDeviceStatus(); check(deviceInfo.getFreezeStatus(), 2, "设备已冻结"); SysDictRedis sysDictRedis = SysDictUtils.get(DictEnum.DEVICE_FAULT_LEVEL_PAY_THRESHOLD.getKey(), DictSonEnum.DEVICE_FAULT_LEVEL_PAY_THRESHOLD_NOT_PAY.getKey()); if (deviceInfo.getFaultLevel() >= Integer.valueOf(sysDictRedis.getValue())) { return R.fail("设备故障"); } check(deviceStatus.getNetState(), 2, "设备已离线"); check(obj.getDoor() != null && obj.getDoor() == 1 ? deviceStatus.getDeviceStateR() : deviceStatus.getDeviceStateL(), 2, "设备已锁机"); check(obj.getDoor() != null && obj.getDoor() == 1 ? deviceStatus.getLockStateR() : deviceStatus.getLockStateL(), 2, "设备正在使用中,请稍后"); return R.ok(); } @PostMapping("historyList") @ApiOperation("设备访问历史查询") public R> historyList() { //获取redis String key = keyPrefix + AuthorizeUtils.getLoginId(Long.class); List deviceIds = redisService.getList(key); if (!Emptys.check(deviceIds)) { return R.ok(); } //查询数据库 List list = list(new LambdaQueryWrapper().in(DeviceInfo::getDeviceId, deviceIds)); return R.ok(copy(DeviceInfoDto.Vo.class, list)); } @ApiOperation("修改") @PostMapping("update") public R update(@RequestBody @Validated DeviceInfoDto.Update update) { DeviceInfo deviceInfo = copy(DeviceInfo.class, update); updateById(deviceInfo); return R.ok(); } @Override @ApiOperation("更新商户线路") public R updateLine(@RequestBody @Validated DeviceInfoDto.UpdateLine updateLine) { LambdaUpdateWrapper luw = new LambdaUpdateWrapper().eq(DeviceInfo::getMercId, updateLine.getMercId()); //绑定线路,更换线路 if (DeviceInfoDto.UPDATE.equals(updateLine.getType())) { DeviceInfo deviceInfo = new DeviceInfo(); deviceInfo.setPlaceLineId(updateLine.getPlaceLineId()); luw.in(DeviceInfo::getDeviceId, updateLine.getDeviceIds()); baseMapper.update(deviceInfo, luw); } //删除线路 if (DeviceInfoDto.DEL.equals(updateLine.getType())) { luw.eq(DeviceInfo::getPlaceLineId, updateLine.getWherePlaceLineId()); luw.set(DeviceInfo::getPlaceLineId, null); baseMapper.update(null, luw); } //解绑线路 设置线路ID为null if (DeviceInfoDto.CLEAR.equals(updateLine.getType())) { luw.in(DeviceInfo::getDeviceId, updateLine.getDeviceIds()); luw.set(DeviceInfo::getPlaceLineId, null); baseMapper.update(null, luw); } return R.ok(); } @Override @ApiOperation("更新商户点位") public R updatePlace(@RequestBody @Validated DeviceInfoDto.UpdatePlace updatePlace) { LambdaUpdateWrapper luw = new LambdaUpdateWrapper().eq(DeviceInfo::getMercId, updatePlace.getMercId()); //绑定点位,更换点位 if (DeviceInfoDto.UPDATE.equals(updatePlace.getType())) { DeviceInfo deviceInfo = new DeviceInfo(); deviceInfo.setPlaceId(updatePlace.getPlaceId()); luw.in(DeviceInfo::getDeviceId, updatePlace.getDeviceIds()); baseMapper.update(deviceInfo, luw); } //删除点位 if (DeviceInfoDto.DEL.equals(updatePlace.getType())) { luw.eq(DeviceInfo::getPlaceId, updatePlace.getWherePlaceId()); luw.set(DeviceInfo::getPlaceId, null); baseMapper.update(null, luw); } //解绑点位 设置点位ID为null if (DeviceInfoDto.CLEAR.equals(updatePlace.getType())) { luw.in(DeviceInfo::getDeviceId, updatePlace.getDeviceIds()); luw.set(DeviceInfo::getPlaceId, null); baseMapper.update(null, luw); } return R.ok(); } @PostMapping("page") @ApiOperation("分页查询") public R> page(@RequestBody DeviceInfoDto.Page page) { return R.ok(queryPage(page)); } @ApiOperation("导出设备列表") @PostMapping("exportDevices") public void exportDevices(HttpServletResponse response, @RequestBody @Valid DeviceInfoDto.Page page) throws IOException { PageBean pageBean = queryPage(page); List records = pageBean.getRecords(); List deviceExcelVOS = BeanUtil.copyToList(records, DeviceInfoDto.DeviceExcelVO.class); // 输出 ExcelUtils.write(response, "设备列表.xls", "设备列表", DeviceInfoDto.DeviceExcelVO.class, deviceExcelVOS); } @PostMapping("nearbyPage") @ApiOperation("附近设备分页查询") public R> nearbyPage(@RequestBody DeviceInfoDto.Page page) { if (!Emptys.check(page.getLon()) || !Emptys.check(page.getLat())) { throw new CommRuntimeException("经纬度不能为空"); } return R.ok(queryPage(page)); } @ApiOperation("商户设备授权") @Override @Transactional(rollbackFor = Exception.class) public R mercDeviceAuth(DeviceInfoDto.MercDeviceAuthDto auth) { Long mercId = auth.getMercId(); String mercCode = auth.getMercCode(); Long algorithmId = auth.getAlgorithmId(); //商户最终设备列表 List deviceIds = auth.getDeviceIds(); List devices = getDevicesByMercId(mercId); //取消商户设备授权 if (CollUtil.isEmpty(deviceIds)) { if (CollUtil.isEmpty(devices)) { return R.ok(Boolean.TRUE); } return R.ok(removeMerRefDevices(devices)); } //更新商户设备授权 List deviceInfos = this.listByIds(deviceIds); deviceInfos.forEach(deviceInfo -> { //绑定关系 deviceInfo.setMercId(mercId).setMercCode(mercCode).setAlgorithmId(algorithmId); }); updateBatchById(deviceInfos); //原来存在的设备关系,不在最终设备列表中的移除 if (CollUtil.isNotEmpty(devices)) { List oldIds = new ArrayList<>(); List removeIds = new ArrayList<>(); devices.forEach(device -> oldIds.add(device.getDeviceId())); oldIds.forEach(deviceId -> { //不在最终设备列表中的待移除 if (!deviceIds.contains(deviceId)) { removeIds.add(deviceId); } }); if (CollUtil.isNotEmpty(removeIds)) { List removeList = this.listByIds(removeIds); removeMerRefDevices(removeList); } } return R.ok(Boolean.TRUE); } /** * 批量移除商户设备绑定关系 * * @param deviceInfos * @return */ private Boolean removeMerRefDevices(List deviceInfos) { deviceInfos.forEach(deviceInfo -> { //-1 释放关系 deviceInfo.setMercId(-1L); }); //批量更新 updateBatchById(deviceInfos); return updateBatchById(deviceInfos); } @ApiOperation("集合查询") @Override public R> list(DeviceInfoDto.ListDto dto) { List list = list(new LambdaQueryWrapper().in(CollUtil.isNotEmpty(dto.getDeviceIds()), DeviceInfo::getDeviceId, dto.getDeviceIds())); return R.ok(copy(DeviceInfoDto.Vo.class, list)); } @Override public R> listCommon(DeviceInfoDto.ListCommon dto) { String deviceSearch = dto.getDeviceSearch(); QueryWrapper queryWrapper = new MybatisPlusQuery().eqWrapper(dto.getVo(), DeviceInfo.class).buildQW(); List placeLineIds = dto.getPlaceLineIds(); List deviceIds = dto.getDeviceIds(); List columnList = dto.getColumnList(); if (CollUtil.isNotEmpty(placeLineIds)) { queryWrapper.eq(LambdaUtils.getProperty(DeviceInfo::getPlaceLineId), placeLineIds); } if (StrUtil.isNotEmpty(deviceSearch)) { queryWrapper.and(wrapper -> wrapper.likeRight(LambdaUtils.getProperty(DeviceInfo::getDeviceName), deviceSearch).or() .eq(LambdaUtils.getProperty(DeviceInfo::getMercDeviceCode), deviceSearch)); } if (CollUtil.isNotEmpty(columnList)) { queryWrapper.select(columnList.stream().toArray(String[]::new)); } if (CollUtil.isNotEmpty(deviceIds)) { queryWrapper.eq(LambdaUtils.getProperty(DeviceInfo::getDeviceId), deviceIds); } return R.ok(copy(DeviceInfoDto.Vo.class, list(queryWrapper))); } @Override @ApiOperation("商户设备算法列表") public R> mercAlgorithmIdList(DeviceInfoDto.MercAlgorithmIdListDto dto) { String algorithmIdStr = LambdaUtils.getProperty(DeviceInfo::getAlgorithmId); String mercStr = StringTools.humpToLine(LambdaUtils.getProperty(DeviceInfo::getMercId)); QueryWrapper lqw = new QueryWrapper() .isNotNull(StringTools.humpToLine(algorithmIdStr)) .eq(mercStr, dto.getMercId()) .select(String.format("DISTINCT (%s) as %s", StringTools.humpToLine(algorithmIdStr), algorithmIdStr)); List list = listObjs(lqw, (MapperFunction) o -> (Long) o); return R.ok(list); } @Override @ApiOperation("小程序-商户设备首页统计") public R mercHomeStatistical(DeviceInfoDto.MercHomeQueryDTO dto) { Long mercId = dto.getMercId(); //初始化数据 DeviceInfoDto.MercHomeStatisticalVO mercHomeStatisticalVO = new DeviceInfoDto.MercHomeStatisticalVO() .setClosedNum(0).setOfflineNum(0) .setOnlineNum(0).setOperatingNum(0).setNeedToFillNum(0); //获取商户机器 List mercDevices = getDevicesByMercId(mercId); if (CollUtil.isEmpty(mercDevices)) { return R.ok(mercHomeStatisticalVO); } List deviceIds = mercDevices.stream().map(DeviceInfo::getDeviceId).collect(Collectors.toList()); //在线、离线 List deviceStatuses = deviceStatusService.listByIds(deviceIds); //分组统计 Map countNetstateMap = deviceStatuses.stream().collect(Collectors .groupingBy(DeviceStatus::getNetState, Collectors.counting())); Integer onlineDictValue = SysDictUtils.getValue(DictEnum.DEVICE_ONLINE_STATUS.getKey(), DictSonEnum.DEVICE_ONLINE_STATUS_CONNECTED.getKey(), Integer.class); Integer offlineDictValue = SysDictUtils.getValue(DictEnum.DEVICE_ONLINE_STATUS.getKey(), DictSonEnum.DEVICE_ONLINE_STATUS_DISCONNECT.getKey(), Integer.class); int onlineNum = countNetstateMap.get(onlineDictValue) == null ? 0 : countNetstateMap.get(onlineDictValue).intValue(); int offlineNum = countNetstateMap.get(offlineDictValue) == null ? 0 : countNetstateMap.get(offlineDictValue).intValue(); mercHomeStatisticalVO.setOnlineNum(onlineNum); mercHomeStatisticalVO.setOfflineNum(offlineNum); //运营、停业 Map countBusyStateMap = mercDevices.stream().collect(Collectors .groupingBy(DeviceInfo::getBusyState, Collectors.counting())); Integer busyState1 = SysDictUtils.getValue(DictEnum.DEVICE_BUSY_STATUS.getKey(), DictSonEnum.DEVICE_BUSY_STATUS1.getKey(), Integer.class); Integer busyState2 = SysDictUtils.getValue(DictEnum.DEVICE_BUSY_STATUS.getKey(), DictSonEnum.DEVICE_BUSY_STATUS2.getKey(), Integer.class); int operatingNum = countBusyStateMap.get(busyState1) == null ? 0 : countBusyStateMap.get(busyState1).intValue(); int closedNum = countBusyStateMap.get(busyState2) == null ? 0 : countBusyStateMap.get(busyState2).intValue(); mercHomeStatisticalVO.setOperatingNum(operatingNum); mercHomeStatisticalVO.setClosedNum(closedNum); //待补货 //TODO: 此逻辑需要确认 return R.ok(mercHomeStatisticalVO); } @Override @ApiOperation("小程序-商户设备首页列表") public R> mercHomeList(DeviceInfoDto.MercHomeQueryDTO dto) { Long mercId = dto.getMercId(); String deviceName = dto.getDeviceName(); Long deviceId = dto.getDeviceId(); List list = this.baseMapper.merHomeCountList(dto); if (CollUtil.isEmpty(list)) { return R.ok(Collections.emptyList()); } List dataList = new ArrayList<>(list.size()); //获取通条件设备信息 LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); lqw.eq(mercId != null, DeviceInfo::getMercId, mercId); lqw.eq(deviceId != null, DeviceInfo::getDeviceId, deviceId); lqw.like(StrUtil.isNotEmpty(deviceName), DeviceInfo::getDeviceName, deviceName); List deviceInfoList = this.list(lqw); //未分配线路的设置默认值 deviceInfoList.stream().filter(s -> s.getPlaceLineId() == null).forEach(s -> s.setPlaceLineId(-1L)); //根据线路id分组 Map> deviceMap = deviceInfoList.stream().collect(Collectors.groupingBy(DeviceInfo::getPlaceLineId)); list.forEach(v -> { DeviceInfoDto.MercHomeListVO vo = new DeviceInfoDto.MercHomeListVO(); Long placeLineId = v.getPlaceLineId(); vo.setDeviceNum(v.getDeviceNum()); vo.setPlaceLineId(v.getPlaceLineId()); //线路下的设备列表 List deviceInfos = Beans.copy(DeviceInfoDto.MercHomeDeviceVo.class, deviceMap.get(placeLineId)); deviceInfos.forEach(device -> { //设备类型 反显 SysDictRedis dictDeviceType = SysDictUtils.get(DictConsts.DEVICE_TYPE, String.valueOf(device.getDeviceType())); device.setDeviceTypeName(dictDeviceType.getMsg()); //运营状态 反显 SysDictRedis dictBusyState = SysDictUtils.get(DictConsts.DEVICE_BUSY_STATUS, String.valueOf(device.getBusyState())); device.setBusyStateName(dictBusyState.getMsg()); //初始化数字 device.setDayOrderNum(0).setOnSaleNum(0).setFillNum(0).setDaySalesPrice("0"); //TODO: 数字统计 }); vo.setDeviceInfos(deviceInfos); dataList.add(vo); }); return R.ok(dataList); } /** * 获取商户设备列表 * * @param mercId * @return */ private List getDevicesByMercId(Long mercId) { return list(Wrappers.lambdaQuery().eq(DeviceInfo::getMercId, mercId)); } private PageBean queryPage(DeviceInfoDto.Page page) { IPage iPage = baseMapper.queryPage(toIPage(page.getPage()), page); return toPageBean(DeviceInfoDto.Vo2.class, iPage); } private void check(T value, T value2, String msg) { if (value.toString().equals(value2.toString())) { throw new CommRuntimeException(msg); } } }