Browse Source

设备年费

lijin 1 week ago
parent
commit
132328f7c9

+ 21 - 4
device-api-service/src/main/java/com/xy/entity/DeviceAnnualFee.java

@@ -1,8 +1,5 @@
 package com.xy.entity;
 
-import java.time.LocalDateTime;
-import java.io.Serializable;
-
 import com.baomidou.mybatisplus.annotation.TableId;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
@@ -10,6 +7,9 @@ import lombok.Data;
 import lombok.EqualsAndHashCode;
 import lombok.experimental.Accessors;
 
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
 /**
  * <p>
  * 设备年费表
@@ -21,7 +21,7 @@ import lombok.experimental.Accessors;
 @Data
 @EqualsAndHashCode(callSuper = false)
 @Accessors(chain = true)
-@ApiModel(value="DeviceAnnualFee对象", description="设备年费表")
+@ApiModel(value = "DeviceAnnualFee对象", description = "设备年费表")
 public class DeviceAnnualFee implements Serializable {
 
     private static final long serialVersionUID = 1L;
@@ -35,11 +35,28 @@ public class DeviceAnnualFee implements Serializable {
     @ApiModelProperty(value = "设备id")
     private Long deviceId;
 
+    @ApiModelProperty(value = "设备类型")
+    private Integer deviceType;
+
+    @ApiModelProperty(value = "注册状态")
+    private Boolean registerStatus;
+
+    @ApiModelProperty(value = "注册时间")
+    private LocalDateTime registerTime;
+
     @ApiModelProperty(value = "过期时间")
     private LocalDateTime timeout;
 
+    @ApiModelProperty(value = "运行环境")
+    private String runPlatform;
+
+    @ApiModelProperty(value = "首次付费时间")
+    private LocalDateTime firstTime;
+
     @ApiModelProperty(value = "创建时间")
     private LocalDateTime createTime;
 
+    @ApiModelProperty(value = "当前使用")
+    private Boolean isThis;
 
 }

+ 38 - 5
device-api-service/src/main/java/com/xy/service/DeviceAnnualFeeOrdersServiceImpl.java

@@ -1,6 +1,9 @@
 package com.xy.service;
 
+import cn.hutool.json.JSONObject;
+import cn.hutool.json.JSONUtil;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.github.yitter.idgen.YitIdHelper;
 import com.xy.collections.list.JArrayList;
@@ -15,13 +18,18 @@ import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import lombok.AllArgsConstructor;
 import org.springframework.stereotype.Service;
+import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
 
 import java.time.LocalDateTime;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 
+import static com.xy.utils.PlusBeans.toIPage;
+import static com.xy.utils.PlusBeans.toPageBean;
+
 
 /**
  * <p>
@@ -78,6 +86,9 @@ public class DeviceAnnualFeeOrdersServiceImpl extends ServiceImpl<DeviceAnnualFe
             String timeout = DataTime.getStringAround(annualFeeOrders.getSize(), 0, 0, 0, 0, 0, DataTime.toString(deviceAnnualFee.getTimeout()));
             deviceAnnualFee.setTimeout(DataTime.toLocal(timeout));
             updateDeviceAnnualFees.add(deviceAnnualFee);
+            if (!Emptys.check(deviceAnnualFee.getFirstTime())) {
+                deviceAnnualFee.setFirstTime(now);
+            }
             annualFeeOrders.setStatus(true).setUpdateTime(now);
             updateDeviceAnnualFeeOrderss.add(annualFeeOrders);
         }
@@ -91,12 +102,34 @@ public class DeviceAnnualFeeOrdersServiceImpl extends ServiceImpl<DeviceAnnualFe
     }
 
     @PostMapping("getAnnualFee")
-    @ApiOperation("查询年费标准")
-    public R<Integer> getAnnualFee() {
+    @ApiOperation("查询年费标准(无token)")
+    public R<Integer> getAnnualFee(@RequestBody @Validated DeviceAnnualFeeOrdersDto.GetAnnualFee getAnnualFee) {
         Map<String, SysDictRedis> stringSysDictRedisMap = SysDictUtils.get("merc_device_annual_fee");
-        SysDictRedis sysDictRedis = stringSysDictRedisMap.get(String.valueOf(MercAuthUtils.getMercId()));
-        int money = Integer.parseInt(sysDictRedis.getValue());
-        return R.ok(money);
+        SysDictRedis sysDictRedis = stringSysDictRedisMap.get(getAnnualFee.getCode());
+        if (sysDictRedis == null) {
+            return R.fail("配置异常,请联系开发人员");
+        }
+        SysDictRedis mercSysDictRedis = stringSysDictRedisMap.get(sysDictRedis.getValue());
+        JSONObject jsonObject = JSONUtil.parseObj(mercSysDictRedis.getValue());
+        return R.ok(jsonObject.getInt("money"));
     }
 
+    @PostMapping("page")
+    @ApiOperation("分页查询")
+    public R<PageBean<DeviceAnnualFeeOrdersDto.Vo>> page(@RequestBody DeviceAnnualFeeOrdersDto.Page page) {
+        LambdaQueryWrapper<DeviceAnnualFeeOrders> lambdaQueryWrapper = new MybatisPlusQuery()
+                .eqWrapper(page, DeviceAnnualFeeOrders.class)
+                .ge(DeviceAnnualFeeOrders::getCreateTime, page.getBeginTime())
+                .le(DeviceAnnualFeeOrders::getCreateTime, page.getEndTime())
+                .build();
+        IPage<DeviceAnnualFeeOrders> iPage = page(toIPage(page.getPage()), lambdaQueryWrapper);
+        PageBean<DeviceAnnualFeeOrdersDto.Vo> pageBean = toPageBean(DeviceAnnualFeeOrdersDto.Vo.class, iPage);
+        return R.ok(pageBean);
+    }
+
+    @PostMapping("mercPage")
+    @ApiOperation("商家分页查询(无token)")
+    public R<PageBean<DeviceAnnualFeeOrdersDto.Vo>> mercPage(@RequestBody DeviceAnnualFeeOrdersDto.Page page) {
+        return page(page);
+    }
 }

+ 445 - 16
device-api-service/src/main/java/com/xy/service/DeviceAnnualFeeServiceImpl.java

@@ -1,23 +1,51 @@
 package com.xy.service;
 
+import cn.hutool.http.HttpRequest;
+import cn.hutool.json.JSONArray;
+import cn.hutool.json.JSONObject;
+import cn.hutool.json.JSONUtil;
+import com.alibaba.excel.EasyExcel;
+import com.alibaba.excel.annotation.ExcelProperty;
+import com.alibaba.excel.context.AnalysisContext;
+import com.alibaba.excel.read.listener.ReadListener;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.github.yitter.idgen.YitIdHelper;
+import com.xy.collections.list.JArrayList;
+import com.xy.collections.list.JList;
+import com.xy.collections.map.JHashMap;
+import com.xy.collections.map.JMap;
+import com.xy.config.DeviceThreadPoolConfig;
 import com.xy.dto.DeviceAnnualFeeDto;
-import com.xy.entity.DeviceAnnualFee;
+import com.xy.dto.MqttUserDto;
+import com.xy.entity.*;
 import com.xy.mapper.DeviceAnnualFeeMapper;
-import com.xy.utils.MercAuthUtils;
-import com.xy.utils.MybatisPlusQuery;
-import com.xy.utils.PageBean;
-import com.xy.utils.R;
+import com.xy.utils.*;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.RequiredArgsConstructor;
+import lombok.SneakyThrows;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.context.annotation.Lazy;
 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 org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.multipart.MultipartFile;
 
+import javax.servlet.http.HttpServletResponse;
+import java.io.InputStream;
+import java.io.OutputStream;
 import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 
 import static com.xy.utils.PlusBeans.toIPage;
 import static com.xy.utils.PlusBeans.toPageBean;
@@ -31,42 +59,443 @@ import static com.xy.utils.PlusBeans.toPageBean;
  * @author lijin
  * @since 2025-02-28
  */
+@Slf4j
 @Service
-@AllArgsConstructor
+@AllArgsConstructor(onConstructor_ = @Lazy)
 @Api(tags = "设备年费表")
 public class DeviceAnnualFeeServiceImpl extends ServiceImpl<DeviceAnnualFeeMapper, DeviceAnnualFee> implements DeviceAnnualFeeService {
 
+    private DeviceCreateIdsServiceImpl deviceCreateIdsService;
+
+    private DeviceRegisterServiceImpl deviceRegisterService;
+
+    private DeviceInfoServiceImpl deviceInfoService;
+
+    private DeviceSysinfoServiceImpl deviceSysinfoService;
+
+    private DeviceStatusServiceImpl deviceStatusService;
+
+    private DevicePartServiceImpl devicePartService;
+
+    private MqttUserServiceImpl mqttUserService;
+
     @PostMapping("check")
     @ApiOperation("检查")
-    public R check(@RequestBody DeviceAnnualFeeDto.Check check) {
-        long count = count(new LambdaQueryWrapper<DeviceAnnualFee>()
+    public R<String> check(@RequestBody @Validated DeviceAnnualFeeDto.Check check) {
+        DeviceAnnualFee deviceAnnualFee = getOne(new LambdaQueryWrapper<DeviceAnnualFee>()
                 .eq(DeviceAnnualFee::getDeviceId, check.getDeviceId())
-                .ge(DeviceAnnualFee::getTimeout, LocalDateTime.now())
+                .eq(DeviceAnnualFee::getIsThis, true)
         );
-        if (count == 0) {
+        if (deviceAnnualFee == null) {
+            return R.fail("设备未分配到年费商家");
+        }
+        String timeout = DataTime.toString(deviceAnnualFee.getTimeout());
+        int i = DataTime.stringContrast(timeout, DataTime.getSring());
+        if (i < 0) {
             return R.fail("已欠费");
         }
-        return R.ok();
+        deviceAnnualFee.setRunPlatform(check.getRunPlatform());
+        updateById(deviceAnnualFee);
+        return R.ok(timeout);
     }
 
     @PostMapping("page")
     @ApiOperation("分页查询")
     public R<PageBean<DeviceAnnualFeeDto.Vo>> page(@RequestBody DeviceAnnualFeeDto.Page page) {
-        PageBean pageBean = page.getPage();
         LambdaQueryWrapper<DeviceAnnualFee> lambdaQueryWrapper = new MybatisPlusQuery()
                 .eqWrapper(page, DeviceAnnualFee.class)
                 .ge(DeviceAnnualFee::getTimeout, page.getBeginTime())
                 .le(DeviceAnnualFee::getTimeout, page.getEndTime())
                 .build();
-        IPage<DeviceAnnualFee> iPage = page(toIPage(pageBean), lambdaQueryWrapper);
-        return R.ok(toPageBean(DeviceAnnualFeeDto.Vo.class, iPage));
+        IPage<DeviceAnnualFee> iPage = page(toIPage(page.getPage()), lambdaQueryWrapper);
+        PageBean<DeviceAnnualFeeDto.Vo> pageBean = toPageBean(DeviceAnnualFeeDto.Vo.class, iPage);
+        List<DeviceAnnualFeeDto.Vo> records = pageBean.getRecords();
+        if (Emptys.check(records)) {
+            Map<String, SysDictRedis> stringSysDictRedisMap = SysDictUtils.get("merc_device_annual_fee");
+            for (DeviceAnnualFeeDto.Vo record : records) {
+                SysDictRedis sysDictRedis = stringSysDictRedisMap.get(String.valueOf(record.getMercId()));
+                JSONObject jsonObject = JSONUtil.parseObj(sysDictRedis.getValue());
+                record.setMoney(jsonObject.getInt("money"));
+            }
+        }
+        return R.ok(pageBean);
     }
 
     @PostMapping("mercPage")
-    @ApiOperation("商家分页查询")
+    @ApiOperation("商家分页查询(无token)")
     public R<PageBean<DeviceAnnualFeeDto.Vo>> mercPage(@RequestBody DeviceAnnualFeeDto.Page page) {
-        page.setMercId(MercAuthUtils.getMercId());
+        if (!Emptys.check(page.getCode())) {
+            return R.fail("code不能为空");
+        }
+        Map<String, SysDictRedis> stringSysDictRedisMap = SysDictUtils.get("merc_device_annual_fee");
+        SysDictRedis sysDictRedis = stringSysDictRedisMap.get(page.getCode());
+        if (sysDictRedis == null) {
+            return R.fail("code未配置商家");
+        }
+        page.setMercId(Long.valueOf(sysDictRedis.getValue()));
         return page(page);
     }
 
+    @SneakyThrows
+    @ApiOperation("导出年费模版")
+    @PostMapping("download")
+    public void download(HttpServletResponse response) {
+        InputStream inputStream = IoUtils.inputStream("device_annual_fee_templet.xlsx").get();
+        response.setHeader("Content-Disposition", "attachment; filename=" + "device_annual_fee_templet.xlsx");
+        response.setContentType("application/xlsx");
+        byte[] buffer = new byte[1024];
+        int bytesRead;
+        OutputStream outputStream = response.getOutputStream();
+        while ((bytesRead = inputStream.read(buffer)) != -1) {
+            outputStream.write(buffer, 0, bytesRead);
+        }
+        inputStream.close();
+        outputStream.close();
+    }
+
+    @SneakyThrows
+    @ApiOperation("导入年费数据")
+    @PostMapping("upload")
+    public R upload(@RequestParam("file") MultipartFile file) {
+        EasyExcel.read(file.getInputStream(), UploadInfo.class, new UploadListener(this)).sheet().doRead();
+        return R.ok();
+    }
+
+    @PostMapping("sendDeviceInfo")
+    @ApiOperation("推送设备到商家平台")
+    public R sendDeviceInfo(@RequestBody @Validated DeviceAnnualFeeDto.SendDeviceInfo sendDeviceInfo) {
+        List<Long> deviceIds = sendDeviceInfo.getDeviceIds();
+        //设备年费信息
+        List<DeviceAnnualFee> deviceAnnualFees = list(new LambdaQueryWrapper<DeviceAnnualFee>()
+                .in(DeviceAnnualFee::getDeviceId, deviceIds)
+                .eq(DeviceAnnualFee::getIsThis, true)
+        );
+        JMap<Long, DeviceAnnualFee> deviceAnnualFeesJMaps = new JArrayList<>(deviceAnnualFees).toMap(DeviceAnnualFee::getDeviceId).cover();
+        //设备id创建信息
+        List<DeviceCreateIds> deviceCreateIdss = deviceCreateIdsService.listByIds(deviceIds);
+        JMap<Long, DeviceCreateIds> deviceCreateIdsJMaps = new JArrayList<>(deviceCreateIdss).toMap(DeviceCreateIds::getDeviceId).cover();
+        //设备注册信息
+        List<DeviceRegister> deviceRegisters = deviceRegisterService.listByIds(deviceIds);
+        JMap<Long, DeviceRegister> deviceRegistersJMaps = new JArrayList<>(deviceRegisters).toMap(DeviceRegister::getDeviceId).cover();
+        //设备信息
+        List<DeviceInfo> deviceInfos = deviceInfoService.listByIds(deviceIds);
+        JMap<Long, DeviceInfo> deviceInfosJMaps = new JArrayList<>(deviceInfos).toMap(DeviceInfo::getDeviceId).cover();
+        //设备系统信息
+        List<DeviceSysinfo> deviceSysinfos = deviceSysinfoService.listByIds(deviceIds);
+        JMap<Long, DeviceSysinfo> deviceSysinfosJMaps = new JArrayList<>(deviceSysinfos).toMap(DeviceSysinfo::getDeviceId).cover();
+        //设备状态信息
+        List<DeviceStatus> deviceStatuses = deviceStatusService.listByIds(deviceIds);
+        JMap<Long, DeviceStatus> deviceStatusesJMaps = new JArrayList<>(deviceStatuses).toMap(DeviceStatus::getDeviceId).cover();
+        //设备配件信息
+        List<DevicePart> devicePartss = devicePartService.list(new LambdaQueryWrapper<DevicePart>()
+                .in(DevicePart::getDeviceId, deviceIds)
+        );
+        JMap<Long, List<DevicePart>> devicePartsJMaps = new JHashMap<>();
+        if (Emptys.check(devicePartss)) {
+            devicePartsJMaps = new JArrayList<>(devicePartss).toMap(DevicePart::getDeviceId).group();
+        }
+        JMap<Long, List<DevicePart>> finalDevicePartsJMaps = devicePartsJMaps;
+        //mqtt连接信息
+        List<MqttUser> mqttUsers = mqttUserService.list(new LambdaQueryWrapper<MqttUser>()
+                .in(MqttUser::getDeviceId, deviceIds)
+        );
+        JMap<Long, MqttUser> mqttUsersJMaps = new JArrayList<>(mqttUsers).toMap(MqttUser::getDeviceId).cover();
+        //字典信息
+        Map<String, SysDictRedis> stringSysDictRedisMap = SysDictUtils.get("merc_device_annual_fee");
+        //组装请求对象
+        FunctionUtils.NoParamsResult<Map<Long, JSONObject>> getJsonObjects = () -> {
+            Map<Long, JSONObject> jsonObjects = new HashMap<>();
+            for (Long deviceId : deviceIds) {
+                JSONObject jsonObject = new JSONObject()
+                        .set("deviceId", deviceId);
+                //设备id创建信息
+                DeviceCreateIds deviceCreateIds = deviceCreateIdsJMaps.get(deviceId);
+                JSONObject deviceCreateIdsObj = JSONUtil.parseObj(deviceCreateIds)
+                        .set("bindTime", DataTime.toString(deviceCreateIds.getBindTime()))
+                        .set("createTime", DataTime.toString(deviceCreateIds.getCreateTime()));
+                if (deviceCreateIds.getLastExportQrCodeTime() != null) {
+                    deviceCreateIdsObj.set("lastExportQrCodeTime", DataTime.toString(deviceCreateIds.getLastExportQrCodeTime()));
+                }
+                jsonObject.set("deviceCreateIds", deviceCreateIdsObj);
+                //设备注册信息
+                DeviceRegister deviceRegister = deviceRegistersJMaps.get(deviceId);
+                JSONObject deviceRegisterObj = JSONUtil.parseObj(deviceRegister)
+                        .set("createTime", DataTime.toString(deviceRegister.getCreateTime()));
+                jsonObject.set("deviceRegister", deviceRegisterObj);
+                //设备信息
+                DeviceInfo deviceInfo = deviceInfosJMaps.get(deviceId);
+                SysDictRedis sysDictRedis = stringSysDictRedisMap.get(String.valueOf(deviceInfo.getMercId()));
+                JSONObject obj = JSONUtil.parseObj(sysDictRedis.getValue());
+                deviceInfo.setMercId(obj.getLong("target_merc_id")).setMercCode(obj.getStr("target_merc_code"));
+                JSONObject deviceInfoObj = JSONUtil.parseObj(deviceInfo)
+                        .set("createTime", DataTime.toString(deviceInfo.getCreateTime()));
+                if (deviceInfo.getUpdateTime() != null) {
+                    deviceInfoObj.set("updateTime", DataTime.toString(deviceInfo.getUpdateTime()));
+                }
+                if (deviceInfo.getActiveTime() != null) {
+                    deviceInfoObj.set("activeTime", DataTime.toString(deviceInfo.getActiveTime()));
+                }
+                jsonObject.set("deviceInfo", deviceInfoObj);
+                //设备系统信息
+                DeviceSysinfo deviceSysinfo = deviceSysinfosJMaps.get(deviceId);
+                JSONObject deviceSysinfoObj = JSONUtil.parseObj(deviceSysinfo);
+                if (deviceSysinfo.getCreateTime() != null) {
+                    deviceSysinfoObj.set("createTime", DataTime.toString(deviceSysinfo.getCreateTime()));
+                }
+                jsonObject.set("deviceSysinfo", deviceSysinfoObj);
+                //设备状态信息
+                DeviceStatus deviceStatus = deviceStatusesJMaps.get(deviceId);
+                JSONObject deviceStatusObj = JSONUtil.parseObj(deviceStatus)
+                        .set("netState", 2);
+                if (deviceStatus.getUpdateTime() != null) {
+                    deviceStatusObj.set("updateTime", DataTime.toString(deviceStatus.getUpdateTime()));
+                }
+                if (deviceStatus.getSysStartTime() != null) {
+                    deviceStatusObj.set("sysStartTime", DataTime.toString(deviceStatus.getSysStartTime()));
+                }
+                if (deviceStatus.getSysCurTime() != null) {
+                    deviceStatusObj.set("sysCurTime", DataTime.toString(deviceStatus.getSysCurTime()));
+                }
+                jsonObject.set("deviceStatus", deviceStatusObj);
+                //设备配件信息
+                List<DevicePart> deviceParts = finalDevicePartsJMaps.get(deviceId);
+                if (Emptys.check(deviceParts)) {
+                    List<JSONObject> devicePartObjs = new ArrayList<>(deviceParts.size());
+                    for (DevicePart devicePart : deviceParts) {
+                        JSONObject devicePartObj = JSONUtil.parseObj(devicePart)
+                                .set("createTime", DataTime.toString(devicePart.getCreateTime()));
+                        if (devicePart.getUpdateTime() != null) {
+                            devicePartObj.set("updateTime", DataTime.toString(devicePart.getUpdateTime()));
+                        }
+                        devicePartObjs.add(devicePartObj);
+                    }
+                    jsonObject.set("deviceParts", devicePartObjs);
+                }
+                //mqtt连接信息
+                MqttUser mqttUser = mqttUsersJMaps.get(deviceId);
+                JSONObject mqttUserObj = JSONUtil.parseObj(mqttUser)
+                        .set("created", DataTime.toString(mqttUser.getCreated()))
+                        .set("id", null);
+                jsonObject.set("mqttUser", mqttUserObj);
+                jsonObjects.put(deviceId, jsonObject);
+            }
+            return jsonObjects;
+        };
+        //发送请求
+        FunctionUtils.ParamsNoResult<Map<Long, JSONObject>> sendPost = jsonObjects -> {
+            LocalDateTime now = LocalDateTime.now();
+            ThreadPoolUtils.Execute execute = ThreadPoolUtils.excPoll(DeviceThreadPoolConfig.DEVICE_COMMON_POLL, deviceIds.size());
+            //多线程逐条发送,发送集合担心参数体过大
+            deviceIds.forEach(deviceId -> execute.execute(() -> {
+                                DeviceAnnualFee deviceAnnualFee = deviceAnnualFeesJMaps.get(deviceId);
+                                if (deviceAnnualFee.getRegisterStatus()) {
+                                    return;
+                                }
+                                SysDictRedis sysDictRedis = stringSysDictRedisMap.get(String.valueOf(deviceAnnualFee.getMercId()));
+                                String url = JSONUtil.parseObj(sysDictRedis.getValue()).getStr("device_send_url");
+                                JSONObject jsonObject = jsonObjects.get(deviceId);
+                                JSONObject result = send(url, jsonObject, "发送设备数据到商家平台");
+                                //修改设备年费注册信息
+                                if (result.getInt("code") == 200) {
+                                    deviceAnnualFee.setRegisterStatus(true)
+                                            .setRegisterTime(now);
+                                    updateById(deviceAnnualFee);
+                                }
+                            })
+                            .error(e -> log.error("", e))
+                            .end()
+            );
+        };
+        Map<Long, JSONObject> jsonObjects = getJsonObjects.run();
+        sendPost.run(jsonObjects);
+        return R.ok();
+    }
+
+    @PostMapping("receiveDeviceInfo")
+    @ApiOperation("接收兴元设备数据(无token)")
+    @Transactional(rollbackFor = Exception.class)
+    public R receiveDeviceInfo(@RequestBody Map<String, Object> map) {
+        //设备id创建信息
+        FunctionUtils.NoParamsNoResult deviceCreateIdsFun = () -> {
+            JSONObject deviceCreateIdsSJson = JSONUtil.parseObj(map.get("deviceCreateIds"));
+            DeviceCreateIds deviceCreateIds = deviceCreateIdsSJson.toBean(DeviceCreateIds.class);
+            DeviceCreateIds byId = deviceCreateIdsService.getById(deviceCreateIds.getDeviceId());
+            if (byId != null) {
+                return;
+            }
+            deviceCreateIdsService.save(deviceCreateIds);
+        };
+        //设备注册信息
+        FunctionUtils.NoParamsNoResult deviceRegisterFun = () -> {
+            JSONObject deviceRegisterJson = JSONUtil.parseObj(map.get("deviceRegister"));
+            DeviceRegister deviceRegister = deviceRegisterJson.toBean(DeviceRegister.class);
+            DeviceRegister byId = deviceRegisterService.getById(deviceRegister.getDeviceId());
+            if (byId != null) {
+                return;
+            }
+            deviceRegisterService.save(deviceRegister);
+        };
+        //设备信息
+        FunctionUtils.NoParamsNoResult deviceInfoFun = () -> {
+            JSONObject deviceInfoJson = JSONUtil.parseObj(map.get("deviceInfo"));
+            DeviceInfo deviceInfo = deviceInfoJson.toBean(DeviceInfo.class);
+            DeviceInfo byId = deviceInfoService.getById(deviceInfo.getDeviceId());
+            if (byId != null) {
+                return;
+            }
+            deviceInfoService.save(deviceInfo);
+        };
+        //设备系统信息
+        FunctionUtils.NoParamsNoResult deviceSysinfoFun = () -> {
+            JSONObject deviceSysinfoJson = JSONUtil.parseObj(map.get("deviceSysinfo"));
+            DeviceSysinfo deviceSysinfo = deviceSysinfoJson.toBean(DeviceSysinfo.class);
+            DeviceSysinfo byId = deviceSysinfoService.getById(deviceSysinfo.getDeviceId());
+            if (byId != null) {
+                return;
+            }
+            deviceSysinfoService.save(deviceSysinfo);
+        };
+        //设备状态信息
+        FunctionUtils.NoParamsNoResult deviceStatusFun = () -> {
+            JSONObject deviceStatusJson = JSONUtil.parseObj(map.get("deviceStatus"));
+            DeviceStatus deviceStatus = deviceStatusJson.toBean(DeviceStatus.class);
+            DeviceStatus byId = deviceStatusService.getById(deviceStatus.getDeviceId());
+            if (byId != null) {
+                return;
+            }
+            deviceStatusService.save(deviceStatus);
+        };
+        //设备配件信息
+        FunctionUtils.NoParamsNoResult devicePartsFun = () -> {
+            JSONArray array = JSONUtil.parseArray(map.get("deviceParts"));
+            List<DevicePart> deviceParts = new ArrayList<>();
+            for (Object o : array) {
+                JSONObject devicePartsJson = JSONUtil.parseObj(o);
+                DevicePart devicePart = devicePartsJson.toBean(DevicePart.class)
+                        .setId(YitIdHelper.nextId());
+                DevicePart one = devicePartService.getOne(new LambdaQueryWrapper<DevicePart>()
+                        .eq(DevicePart::getDeviceId, devicePart.getDeviceId())
+                        .eq(DevicePart::getCode, devicePart.getCode())
+                );
+                if (one == null) {
+                    deviceParts.add(devicePart);
+                }
+            }
+            if (Emptys.check(deviceParts)) {
+                devicePartService.saveBatch(deviceParts);
+            }
+        };
+        //mqtt连接信息
+        FunctionUtils.NoParamsNoResult mqttUserFun = () -> {
+            JSONObject mqttUserJson = JSONUtil.parseObj(map.get("mqttUser"));
+            MqttUser mqttUser = mqttUserJson.toBean(MqttUser.class);
+            MqttUser one = mqttUserService.getOne(new LambdaQueryWrapper<MqttUser>()
+                    .eq(MqttUser::getDeviceId, mqttUser.getDeviceId())
+                    .eq(MqttUser::getSn, mqttUser.getSn())
+            );
+            if (one != null) {
+                return;
+            }
+            MqttUserDto.Save mqttUserInfo = Beans.copy(MqttUserDto.Save.class, mqttUser);
+            mqttUserService.save(mqttUserInfo);
+        };
+        long deviceId = Long.parseLong(map.get("deviceId").toString());
+        return new LockUtils2().name("receiveDeviceInfo_" + deviceId)
+                .success(() -> {
+                    deviceCreateIdsFun.run();
+                    deviceRegisterFun.run();
+                    deviceInfoFun.run();
+                    deviceSysinfoFun.run();
+                    deviceStatusFun.run();
+                    devicePartsFun.run();
+                    mqttUserFun.run();
+                    return R.ok();
+                });
+    }
+
+    private JSONObject send(String url, JSONObject params, String msg) {
+        return send(url, params, msg, 5000);
+    }
+
+    private JSONObject send(String url, JSONObject params, String msg, int timeout) {
+        try {
+            String body = params.toString();
+            log.info("{}请求参数:{}", msg, body);
+            String result = HttpRequest.post(url)
+                    .body(body)
+                    .timeout(timeout)
+                    .execute()
+                    .body();
+            log.info("{}响应参数:{}", msg, result);
+            return JSONUtil.parseObj(result);
+        } catch (Exception e) {
+            log.error("", e);
+            return new JSONObject().set("code", 500);
+        }
+    }
+
+
+    @Slf4j
+    @RequiredArgsConstructor
+    public static class UploadListener implements ReadListener<UploadInfo> {
+
+        private final DeviceAnnualFeeServiceImpl deviceAnnualFeeService;
+
+        private JList<UploadInfo> uploadInfos = new JArrayList<>();
+
+        /**
+         * 这个每一条数据解析都会来调用
+         *
+         * @param data    one row value. Is is same as {@link AnalysisContext#readRowHolder()}
+         * @param context
+         */
+        @Override
+        public void invoke(UploadInfo data, AnalysisContext context) {
+            uploadInfos.add(data);
+        }
+
+        /**
+         * 所有数据解析完成了 都会来调用
+         *
+         * @param context
+         */
+        @Override
+        public void doAfterAllAnalysed(AnalysisContext context) {
+            if (!Emptys.check(uploadInfos)) {
+                throw new RuntimeException("导入不能为空");
+            }
+            List<DeviceAnnualFee> deviceAnnualFees = deviceAnnualFeeService.list(new LambdaQueryWrapper<DeviceAnnualFee>()
+                    .in(DeviceAnnualFee::getDeviceId, uploadInfos.getProperty(UploadInfo::getDeviceId))
+                    .eq(DeviceAnnualFee::getIsThis, true)
+            );
+            if (!Emptys.check(deviceAnnualFees)) {
+                throw new RuntimeException("设备不存在");
+            }
+            JMap<Long, DeviceAnnualFee> cover = new JArrayList<>(deviceAnnualFees).toMap(DeviceAnnualFee::getDeviceId).cover();
+            LocalDateTime now = LocalDateTime.now();
+            List<DeviceAnnualFee> updates = new ArrayList<>(uploadInfos.size());
+            for (UploadInfo uploadInfo : uploadInfos) {
+                DeviceAnnualFee deviceAnnualFee = cover.get(uploadInfo.getDeviceId());
+                if (deviceAnnualFee == null) {
+                    throw new RuntimeException("设备" + uploadInfo.getDeviceId() + "不存在");
+                }
+                deviceAnnualFee.setTimeout(DataTime.toLocal(uploadInfo.getTimeout() + " 23:59:59"));
+                if (deviceAnnualFee.getFirstTime() == null) {
+                    deviceAnnualFee.setFirstTime(now);
+                }
+                updates.add(deviceAnnualFee);
+            }
+            deviceAnnualFeeService.updateBatchById(updates);
+        }
+    }
+
+    @Data
+    public static class UploadInfo {
+
+        @ExcelProperty(value = "设备ID")
+        private Long deviceId;
+
+        @ExcelProperty(value = "到期时间(yyyy-MM-dd)")
+        private String timeout;
+    }
 }

+ 17 - 10
device-api-service/src/main/java/com/xy/service/DeviceInfoServiceImpl.java

@@ -918,20 +918,27 @@ public class DeviceInfoServiceImpl extends ServiceImpl<DeviceInfoMapper, DeviceI
             }
             LocalDateTime now = LocalDateTime.now();
             deviceInfos.forEach(deviceInfo -> {
-                long count = deviceAnnualFeeService.count(new LambdaQueryWrapper<DeviceAnnualFee>()
+                deviceAnnualFeeService.update(new LambdaUpdateWrapper<DeviceAnnualFee>()
+                        .set(DeviceAnnualFee::getIsThis, false)
+                        .eq(DeviceAnnualFee::getDeviceId, deviceInfo.getDeviceId())
+                );
+                DeviceAnnualFee saveOrUpdateInfo = deviceAnnualFeeService.getOne(new LambdaQueryWrapper<DeviceAnnualFee>()
                         .eq(DeviceAnnualFee::getDeviceId, deviceInfo.getDeviceId())
                         .eq(DeviceAnnualFee::getMercId, auth.getMercId())
                 );
-                if (count > 0) {
-                    return;
+                if (saveOrUpdateInfo != null) {
+                    saveOrUpdateInfo.setIsThis(true);
+                } else {
+                    saveOrUpdateInfo = new DeviceAnnualFee()
+                            .setId(YitIdHelper.nextId())
+                            .setMercId(auth.getMercId())
+                            .setDeviceId(deviceInfo.getDeviceId())
+                            .setDeviceType(deviceInfo.getDeviceType())
+                            .setTimeout(now)
+                            .setCreateTime(now)
+                            .setIsThis(true);
                 }
-                deviceAnnualFeeService.save(new DeviceAnnualFee()
-                        .setId(YitIdHelper.nextId())
-                        .setMercId(auth.getMercId())
-                        .setDeviceId(deviceInfo.getDeviceId())
-                        .setTimeout(now)
-                        .setCreateTime(now)
-                );
+                deviceAnnualFeeService.saveOrUpdate(saveOrUpdateInfo);
             });
         };
         check.run();

+ 44 - 7
device-api/src/main/java/com/xy/dto/DeviceAnnualFeeDto.java

@@ -6,8 +6,11 @@ import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
 import lombok.experimental.Accessors;
 
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotEmpty;
 import javax.validation.constraints.NotNull;
 import java.time.LocalDateTime;
+import java.util.List;
 
 /**
  * <p>
@@ -26,21 +29,19 @@ public class DeviceAnnualFeeDto {
         @NotNull(message = "deviceId不能为空")
         @ApiModelProperty(value = "设备id", required = true)
         private Long deviceId;
+
+        @NotBlank(message = "运行环境")
+        @ApiModelProperty(value = "运行环境", required = true)
+        private String runPlatform;
     }
 
     @Data
     @Accessors(chain = true)
-    public static class Page {
+    public static class Page extends Vo {
 
         @ApiModelProperty(value = "分页对象", required = true)
         private PageBean page;
 
-        @ApiModelProperty(value = "商户id")
-        private Long mercId;
-
-        @ApiModelProperty(value = "设备id")
-        private Long deviceId;
-
         @ApiModelProperty(value = "开始时间")
         @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
         private LocalDateTime beginTime;
@@ -48,6 +49,20 @@ public class DeviceAnnualFeeDto {
         @ApiModelProperty(value = "结束时间")
         @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
         private LocalDateTime endTime;
+
+        @ApiModelProperty(value = "商家平台标识")
+        private String code;
+
+    }
+
+    @Data
+    @Accessors(chain = true)
+    public static class SendDeviceInfo {
+
+        @NotEmpty(message = "deviceIds不能为空")
+        @ApiModelProperty(value = "设备ID集合", required = true)
+        private List<Long> deviceIds;
+
     }
 
     @Data
@@ -62,14 +77,36 @@ public class DeviceAnnualFeeDto {
         @ApiModelProperty(value = "设备id")
         private Long deviceId;
 
+        @ApiModelProperty(value = "设备类型")
+        private Integer deviceType;
+
+        @ApiModelProperty(value = "注册状态")
+        private Boolean registerStatus;
+
+        @ApiModelProperty(value = "注册时间")
+        @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+        private LocalDateTime registerTime;
+
         @ApiModelProperty(value = "过期时间")
         @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
         private LocalDateTime timeout;
 
+        @ApiModelProperty(value = "运行环境")
+        private String runPlatform;
+
+        @ApiModelProperty(value = "首次付费时间")
+        @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+        private LocalDateTime firstTime;
+
         @ApiModelProperty(value = "创建时间")
         @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
         private LocalDateTime createTime;
 
+        @ApiModelProperty(value = "当前使用")
+        private Boolean isThis;
+
+        @ApiModelProperty(value = "年费标准")
+        private Integer money;
     }
 
 }

+ 35 - 0
device-api/src/main/java/com/xy/dto/DeviceAnnualFeeOrdersDto.java

@@ -58,6 +58,41 @@ public class DeviceAnnualFeeOrdersDto {
 
     }
 
+    @Data
+    @Accessors(chain = true)
+    public static class GetAnnualFee {
+
+        @NotBlank(message = "code不能为空")
+        @ApiModelProperty(value = "商家平台标识", required = true)
+        private String code;
+
+    }
+
+    @Data
+    @Accessors(chain = true)
+    public static class Page {
+
+        @ApiModelProperty(value = "分页对象", required = true)
+        private PageBean page;
+
+        @NotNull(message = "mercId不能为空")
+        @ApiModelProperty(value = "商户id", required = true)
+        private Long mercId;
+
+        @NotNull(message = "deviceId不能为空")
+        @ApiModelProperty(value = "设备id", required = true)
+        private Long deviceId;
+
+        @ApiModelProperty(value = "开始时间")
+        @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+        private LocalDateTime beginTime;
+
+        @ApiModelProperty(value = "结束时间")
+        @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+        private LocalDateTime endTime;
+
+    }
+
     @Data
     @Accessors(chain = true)
     public static class Vo {

+ 1 - 1
device-api/src/main/java/com/xy/service/DeviceAnnualFeeOrdersService.java

@@ -23,7 +23,7 @@ public interface DeviceAnnualFeeOrdersService {
     /**
      * 购买
      *
-     * @param pay
+     * @param pays
      * @return
      */
     @PostMapping("pay")

BIN
device-start/src/main/resources/device_annual_fee_templet.xlsx