Commit 5761b10c authored by 赵啸非's avatar 赵啸非

修改设备管理

parent 0f289e4a
......@@ -16,6 +16,7 @@ CREATE TABLE mortals_stp_device(
`deviceFirmname` varchar(20) COMMENT '设备生产厂商名称',
`deviceOnlineStatus` tinyint(2) NOT NULL COMMENT '在线状态 (0.离线,1.在线)',
`status` tinyint(2) NOT NULL COMMENT '启用状态 (0.停止,1.启用)',
`deviceSource` tinyint(2) NOT NULL COMMENT '设备来源,为其它时候上线下线通过查询(0.大厅,1.其它)',
`deviceRemark` varchar(256) COMMENT '备注',
`onlineTime` datetime COMMENT '最近上线时间',
`offlineTime` datetime COMMENT '最近离线时间',
......@@ -25,6 +26,7 @@ CREATE TABLE mortals_stp_device(
`updateTime` datetime COMMENT '更新时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='设备';
-- ----------------------------
-- 设备生产厂商表
-- ----------------------------
......
......@@ -31,9 +31,7 @@ const router = new Router({
builder('site/list', 'system/site/index'),//站点
...restBuilder('device', 'device'),//
...restBuilder('device/log', 'device/log'),//
...restBuilder('firm', 'firm'),//
//以下为基础路由配置
......
......@@ -34,12 +34,12 @@ export default {
},
loginFail(error) {
this.$message.error(error.message || '请登录');
this.$router.replace({
path: '/login',
query: {
redirect: this.redirect,
}
});
// this.$router.replace({
// path: '/login',
// query: {
// redirect: this.redirect,
// }
// });
},
getUrlKey (name) {
......
......@@ -10,19 +10,38 @@ import java.io.Serializable;
@Data
public class DeviceReq implements Serializable {
/**
* 行为
*/
private String action;
/**
* 设备编码 唯一
*/
private String devicenum;
/**
* ip地址
*/
private String ip;
/**
* 站点编码
*/
private String sitenum;
/**
* 上传类型
*/
private Integer type;
/**
* 端口
*/
private String port;
/**
* 中心编码
*/
private String centernum;
......
package com.mortals.xhx.busiz.rsp;
import lombok.Data;
import java.io.Serializable;
@Data
public class DeviceResp implements Serializable {
/**
* 在线状态(0在线 1离线)
*/
private String isOnLine;
}
......@@ -9,11 +9,14 @@ import com.mortals.xhx.busiz.req.DeviceReq;
import com.mortals.xhx.busiz.rsp.ApiResp;
import com.mortals.xhx.common.code.ApiRespCodeEnum;
import com.mortals.xhx.common.code.DeviceOnlineStatusEnum;
import com.mortals.xhx.common.utils.SendTaskThreadPool;
import com.mortals.xhx.common.utils.UploadTask;
import com.mortals.xhx.module.device.model.DeviceEntity;
import com.mortals.xhx.module.device.model.DeviceLogEntity;
import com.mortals.xhx.module.device.service.DeviceLogService;
import com.mortals.xhx.module.device.service.DeviceService;
import lombok.extern.apachecommons.CommonsLog;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.PostMapping;
......@@ -29,15 +32,15 @@ import java.util.Date;
* @date: 2021/8/24 20:28
*/
@RestController
@CommonsLog
@Slf4j
@RequestMapping("/api/device")
public class DeviceApiController {
@Autowired
private DeviceLogService deviceLogService;
@Autowired
private DeviceService deviceService;
@Autowired
private SendTaskThreadPool sendTaskThreadPool;
/**
* 设备数据上报
......@@ -47,73 +50,13 @@ public class DeviceApiController {
*/
@PostMapping("upload")
public String upload(DeviceReq req) {
log.info("【设备数据上报】【请求体】--> " + JSONObject.toJSONString(req));
log.debug("【设备数据上报】【请求体】--> " + JSONObject.toJSONString(req));
ApiResp rsp = new ApiResp<>();
rsp.setMsg(ApiRespCodeEnum.SUCCESS.getLabel());
rsp.setCode(ApiRespCodeEnum.SUCCESS.getValue());
try {
//根据设备编码查询设备
DeviceEntity deviceEntity = deviceService.getExtCache(req.getDevicenum());
boolean bool = false;
if (!ObjectUtils.isEmpty(deviceEntity)) {
if (deviceEntity.getDeviceOnlineStatus() == DeviceOnlineStatusEnum.离线.getValue()) {
bool = true;
}
deviceEntity.setOnlineTime(new Date());
deviceEntity.setDeviceOnlineStatus(DeviceOnlineStatusEnum.在线.getValue());
deviceEntity.setIp(req.getIp());
deviceEntity.setPort(req.getPort());
deviceEntity.setSiteNum(req.getSitenum());
deviceEntity.setCenternum(req.getCenternum());
deviceService.update(deviceEntity);
DeviceLogEntity deviceLogEntity = new DeviceLogEntity();
deviceLogEntity.initAttrValue();
deviceLogEntity.setDeviceId(deviceEntity.getId());
deviceLogEntity.setDeviceName(deviceEntity.getDeviceName());
deviceLogEntity.setDeviceNum(deviceEntity.getDeviceCode());
deviceLogEntity.setContent(JSONObject.toJSONString(req));
deviceLogEntity.setCreateTime(new Date());
deviceLogService.save(deviceLogEntity);
if (bool) {
WebSocketUtil.broadcast(SendToAllRequest.TYPE, new SendToAllRequest().setContent(JSON.toJSONString(deviceEntity)));
}
} else {
//新增设备
deviceEntity = new DeviceEntity();
deviceEntity.initAttrValue();
deviceEntity.setDeviceCode(req.getDevicenum());
deviceEntity.setOnlineTime(new Date());
deviceEntity.setDeviceOnlineStatus(DeviceOnlineStatusEnum.在线.getValue());
deviceEntity.setIp(req.getIp());
deviceEntity.setPort(req.getPort());
deviceEntity.setSiteNum(req.getSitenum());
deviceEntity.setCenternum(req.getCenternum());
deviceEntity.setCreateUserId(1L);
deviceEntity.setCreateTime(new Date());
deviceService.save(deviceEntity);
DeviceLogEntity deviceLogEntity = new DeviceLogEntity();
deviceLogEntity.initAttrValue();
deviceLogEntity.setDeviceId(deviceEntity.getId());
deviceLogEntity.setDeviceName(deviceEntity.getDeviceName());
deviceLogEntity.setDeviceNum(deviceEntity.getDeviceCode());
deviceLogEntity.setContent(JSONObject.toJSONString(req));
deviceLogEntity.setCreateTime(new Date());
deviceLogService.save(deviceLogEntity);
WebSocketUtil.broadcast(SendToAllRequest.TYPE, new SendToAllRequest().setContent(JSON.toJSONString(deviceEntity)));
}
} catch (Exception e) {
log.error("接收数据失败", e);
rsp.setCode(ApiRespCodeEnum.FAILED.getValue());
rsp.setMsg(e.getMessage());
return JSON.toJSONString(rsp);
}
log.info("响应【设备数据上报】【响应体】--> " + JSONObject.toJSONString(rsp));
UploadTask uploadTask = new UploadTask(req, deviceLogService, deviceService);
sendTaskThreadPool.execute(uploadTask);
log.debug("响应【设备数据上报】【响应体】--> " + JSONObject.toJSONString(rsp));
return JSON.toJSONString(rsp);
}
......
package com.mortals.xhx.common.code;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* 设备来源,为其它时候上线下线通过查询(0.大厅,1.其它)枚举类
*
* @author zxfei
*/
public enum DeviceSourceEnum {
大厅(0, "大厅"),
其它(1, "其它");
private Integer value;
private String desc;
DeviceSourceEnum(Integer value, String desc) {
this.value = value;
this.desc = desc;
}
public Integer getValue() {
return this.value;
}
public String getDesc() {
return this.desc;
}
public static DeviceSourceEnum getByValue(Integer value) {
for (DeviceSourceEnum deviceSourceEnum : DeviceSourceEnum.values()) {
if (deviceSourceEnum.getValue() == value) {
return deviceSourceEnum;
}
}
return null;
}
/**
* 获取Map集合
*
* @param eItem 不包含项
* @return
*/
public static Map<String, String> getEnumMap(Integer... eItem) {
Map<String, String> resultMap = new LinkedHashMap<>();
for (DeviceSourceEnum item : DeviceSourceEnum.values()) {
try {
boolean hasE = false;
for (Integer e : eItem) {
if (item.getValue() == e) {
hasE = true;
break;
}
}
if (!hasE) {
resultMap.put(item.getValue() + "", item.getDesc());
}
} catch (Exception ex) {
}
}
return resultMap;
}
}
\ No newline at end of file
......@@ -28,4 +28,10 @@ public class ParamKey {
*/
public static String SYS_PARAM_USER_URL = "user_url";
/**
* 设备状态查询url
*/
public static String SYS_PARAM_SEND_QUERY_URL = "send_query_url";
}
package com.mortals.xhx.common.utils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.mortals.framework.util.HttpUtil;
import com.mortals.xhx.busiz.rsp.ApiResp;
import com.mortals.xhx.busiz.rsp.DeviceResp;
import com.mortals.xhx.common.code.DeviceOnlineStatusEnum;
import com.mortals.xhx.daemon.task.CustomerInfo;
import com.mortals.xhx.module.device.model.DeviceEntity;
import com.mortals.xhx.module.device.service.DeviceService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static com.mortals.framework.util.HttpUtil.HEADER_CONTENT_TYPE;
/**
* 发送任务
*
* @author: zxfei
* @date: 2022/4/28 10:56
* @description:
**/
@Slf4j
@AllArgsConstructor
public class SendTask implements Runnable {
private String sendUrl;
private Long deviceId;
private String content;
private DeviceService deviceService;
@Override
public void run() {
try {
Map<String, String> headers = new HashMap<>();
DeviceEntity deviceEntity = new DeviceEntity();
deviceEntity.setId(deviceId);
headers.put(HEADER_CONTENT_TYPE, "application/json");
String resp = HttpUtil.doPost(sendUrl, headers, content);
ApiResp<DeviceResp> apiResp = JSON.parseObject(resp, new TypeReference<ApiResp<DeviceResp>>(){});
if (apiResp.getCode() == 0) {
if (apiResp.getData().getIsOnLine() == "0") {
deviceEntity.setDeviceOnlineStatus(DeviceOnlineStatusEnum.在线.getValue());
deviceEntity.setOnlineTime(new Date());
} else if (apiResp.getData().getIsOnLine() == "1") {
deviceEntity.setDeviceOnlineStatus(DeviceOnlineStatusEnum.离线.getValue());
deviceEntity.setOfflineTime(new Date());
} else {
deviceEntity.setDeviceOnlineStatus(DeviceOnlineStatusEnum.在线.getValue());
deviceEntity.setOnlineTime(new Date());
}
deviceService.update(deviceEntity);
}
log.debug("http resp:{}", resp);
} catch (Exception e) {
log.error("发送异常:" + e);
}
}
}
package com.mortals.xhx.common.utils;
import org.springframework.stereotype.Component;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
/**
* 发送任务线程池
*
* @author: zxfei
* @date: 2022/4/28 10:52
*/
@Component
public class SendTaskThreadPool {
/**
* 线程池
*/
private ThreadPoolExecutor threadPool;
private int poolSize;
private volatile boolean isInit = false;
private Object lock = new Object();
public void init(Integer threadNum) {
if (poolSize < 0) {
throw new IllegalArgumentException();
}
if (poolSize < Runtime.getRuntime().availableProcessors()) {
poolSize = Runtime.getRuntime().availableProcessors() + 1;
}
if (!isInit) {
synchronized (lock) {
if (!isInit) {
threadPool = (ThreadPoolExecutor) Executors.newFixedThreadPool(threadNum);
isInit = true;
}
}
}
}
public void execute(Runnable command) {
threadPool.execute(command);
}
public void setPoolSize(int poolSize) {
threadPool.setCorePoolSize(poolSize);
threadPool.setMaximumPoolSize(poolSize);
}
public void incrementPoolSize(int delta) {
setPoolSize(threadPool.getCorePoolSize() + delta);
}
public synchronized void close() {
if (threadPool != null) {
threadPool.shutdown();
threadPool = null;
isInit = false;
}
}
}
package com.mortals.xhx.common.utils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.mortals.framework.util.HttpUtil;
import com.mortals.xhx.base.framework.ws.message.SendToAllRequest;
import com.mortals.xhx.base.framework.ws.util.WebSocketUtil;
import com.mortals.xhx.busiz.req.DeviceReq;
import com.mortals.xhx.busiz.rsp.ApiResp;
import com.mortals.xhx.busiz.rsp.DeviceResp;
import com.mortals.xhx.common.code.DeviceOnlineStatusEnum;
import com.mortals.xhx.module.device.model.DeviceEntity;
import com.mortals.xhx.module.device.model.DeviceLogEntity;
import com.mortals.xhx.module.device.service.DeviceLogService;
import com.mortals.xhx.module.device.service.DeviceService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.ObjectUtils;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import static com.mortals.framework.util.HttpUtil.HEADER_CONTENT_TYPE;
/**
* 上报任务
*
* @author: zxfei
* @date: 2022/4/28 10:56
* @description:
**/
@Slf4j
@AllArgsConstructor
public class UploadTask implements Runnable {
private DeviceReq req;
private DeviceLogService deviceLogService;
private DeviceService deviceService;
@Override
public void run() {
try {
DeviceEntity deviceEntity = deviceService.getExtCache(req.getDevicenum());
boolean bool = false;
if (!ObjectUtils.isEmpty(deviceEntity)) {
if (deviceEntity.getDeviceOnlineStatus() == DeviceOnlineStatusEnum.离线.getValue()) {
bool = true;
}
deviceEntity.setOnlineTime(new Date());
deviceEntity.setDeviceOnlineStatus(DeviceOnlineStatusEnum.在线.getValue());
deviceEntity.setIp(req.getIp());
deviceEntity.setPort(req.getPort());
deviceEntity.setSiteNum(req.getSitenum());
deviceEntity.setCenternum(req.getCenternum());
deviceService.update(deviceEntity);
DeviceLogEntity deviceLogEntity = new DeviceLogEntity();
deviceLogEntity.initAttrValue();
deviceLogEntity.setDeviceId(deviceEntity.getId());
deviceLogEntity.setDeviceName(deviceEntity.getDeviceName());
deviceLogEntity.setDeviceNum(deviceEntity.getDeviceCode());
deviceLogEntity.setContent(JSONObject.toJSONString(req));
deviceLogEntity.setCreateTime(new Date());
deviceLogService.save(deviceLogEntity);
if (bool) {
WebSocketUtil.broadcast(SendToAllRequest.TYPE, new SendToAllRequest().setContent(JSON.toJSONString(deviceEntity)));
}
} else {
//新增设备
deviceEntity = new DeviceEntity();
deviceEntity.initAttrValue();
deviceEntity.setDeviceCode(req.getDevicenum());
deviceEntity.setOnlineTime(new Date());
deviceEntity.setDeviceOnlineStatus(DeviceOnlineStatusEnum.在线.getValue());
deviceEntity.setIp(req.getIp());
deviceEntity.setPort(req.getPort());
deviceEntity.setSiteNum(req.getSitenum());
deviceEntity.setCenternum(req.getCenternum());
deviceEntity.setCreateUserId(1L);
deviceEntity.setCreateTime(new Date());
deviceService.save(deviceEntity);
DeviceLogEntity deviceLogEntity = new DeviceLogEntity();
deviceLogEntity.initAttrValue();
deviceLogEntity.setDeviceId(deviceEntity.getId());
deviceLogEntity.setDeviceName(deviceEntity.getDeviceName());
deviceLogEntity.setDeviceNum(deviceEntity.getDeviceCode());
deviceLogEntity.setContent(JSONObject.toJSONString(req));
deviceLogEntity.setCreateTime(new Date());
deviceLogService.save(deviceLogEntity);
WebSocketUtil.broadcast(SendToAllRequest.TYPE, new SendToAllRequest().setContent(JSON.toJSONString(deviceEntity)));
}
} catch (Exception e) {
log.error("异常:" ,e);
}
}
}
package com.mortals.xhx.daemon.applicationservice;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.mortals.framework.springcloud.service.IApplicationService;
import com.mortals.xhx.common.utils.SendTaskThreadPool;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.mortals.framework.springcloud.service.IApplicationService;
/**
* 应用级服务,在应用启动、停止过程中调用
*
* 缺陷:类加载完成后就调用,会由于某些组件还未初始化而导致服务异常,
* 比如Kafka的连接以及订阅初始化比较靠后,在服务启动过程中就调用操作kafka相关API,将导致失败
* 比如开启Socket监听端口,可能端口都接收到连接请求了,但数据库连接还未初始化完成,导致请求处理失败
* 比如定时任务,任务执行时,相关缓存还未初始化,导致处理失败
*
* 应用场景:
* 1、无依赖其它模块或框架的数据初始化等操作
* @author GM
* @date 2020年7月15日
*/
@Component
@Slf4j
public class DemoStartService implements IApplicationService {
private static Log logger = LogFactory.getLog(DemoStartService.class);
@Autowired
private SendTaskThreadPool sendTaskThreadPool;
@Override
public void start() {
logger.info("开始服务..[配置已加载完成,但部分框架还未初始化,比如:Kafka]");
int coreThreadNum = Runtime.getRuntime().availableProcessors();
sendTaskThreadPool.init(coreThreadNum*2);
log.info("开始服务..[配置已加载完成,但部分框架还未初始化,比如:Kafka]");
}
@Override
public void stop() {
logger.info("停止服务..");
log.info("停止服务..");
}
}
package com.mortals.xhx.daemon.task;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.mortals.framework.ap.GlobalSysInfo;
import com.mortals.framework.exception.AppException;
import com.mortals.framework.service.ITask;
......@@ -10,7 +11,10 @@ import com.mortals.xhx.base.framework.ws.message.SendToAllRequest;
import com.mortals.xhx.base.framework.ws.message.UserJoinNoticeRequest;
import com.mortals.xhx.base.framework.ws.util.WebSocketUtil;
import com.mortals.xhx.common.code.DeviceOnlineStatusEnum;
import com.mortals.xhx.common.code.DeviceSourceEnum;
import com.mortals.xhx.common.key.ParamKey;
import com.mortals.xhx.common.utils.SendTask;
import com.mortals.xhx.common.utils.SendTaskThreadPool;
import com.mortals.xhx.module.device.model.DeviceLogEntity;
import com.mortals.xhx.module.device.model.DeviceLogQuery;
import com.mortals.xhx.module.device.service.DeviceLogService;
......@@ -38,12 +42,15 @@ public class DeviceStatTaskImpl implements ITaskExcuteService {
@Autowired
private DeviceLogService deviceLogService;
@Autowired
private SendTaskThreadPool sendTaskThreadPool;
@Override
public void excuteTask(ITask task) throws AppException {
log.debug("设备状态统计,开始执行");
doDeviceUpOrDown();
doDeviceLogDel();
doDeviceQuery();
log.debug("设备状态统计,结束执行");
}
......@@ -56,6 +63,7 @@ public class DeviceStatTaskImpl implements ITaskExcuteService {
try {
//获取所有设备,针对每个设备查询最近指定秒的日志,如果没有则更新下线
deviceService.getCacheList().stream()
.filter(f -> f.getDeviceSource() == DeviceSourceEnum.大厅.getValue())
.filter(f -> f.getDeviceOnlineStatus() == DeviceOnlineStatusEnum.在线.getValue())
.peek(device -> {
DeviceLogQuery query = new DeviceLogQuery();
......@@ -68,14 +76,14 @@ public class DeviceStatTaskImpl implements ITaskExcuteService {
device.setDeviceOnlineStatus(DeviceOnlineStatusEnum.离线.getValue());
deviceService.update(device);
WebSocketUtil.broadcast(SendToAllRequest.TYPE,new SendToAllRequest().setContent(JSON.toJSONString(device)));
WebSocketUtil.broadcast(SendToAllRequest.TYPE, new SendToAllRequest().setContent(JSON.toJSONString(device)));
}
}).count();
} catch (Exception e) {
log.error("更新设备状态任务异常,结束执行", e);
}
log.info("更新设备状态任务,结束执行");
log.debug("更新设备状态任务,结束执行");
}
......@@ -95,7 +103,29 @@ public class DeviceStatTaskImpl implements ITaskExcuteService {
} catch (Exception e) {
log.error("设备日志删除任务异常,结束执行", e);
}
log.info("设备日志删除任务,结束执行");
log.debug("设备日志删除任务,结束执行");
}
/**
* 定时查询更新其它设备状态
*/
private void doDeviceQuery() {
try {
deviceService.getCacheList().parallelStream()
.filter(f -> f.getDeviceSource() == DeviceSourceEnum.其它.getValue())
.peek(device -> {
String sendUrl = GlobalSysInfo.getParamValue(ParamKey.SYS_PARAM_SEND_QUERY_URL,"http://127.0.0.1:18211/m/test/equipStateQuery");
JSONObject jsonObject = new JSONObject();
jsonObject.put("macAddress",device.getDeviceMac());
SendTask sendTask = new SendTask(sendUrl, device.getId(), jsonObject.toJSONString(), deviceService);
sendTaskThreadPool.execute(sendTask);
}).count();
} catch (Exception e) {
log.error("查询设备状态任务异常,结束执行", e);
}
log.debug("查询设备状态任务,结束执行");
}
......
package com.mortals.xhx.module.device.service.impl;
import com.mortals.framework.exception.AppException;
import com.mortals.framework.model.Context;
import org.springframework.stereotype.Service;
import com.mortals.framework.service.impl.AbstractCRUDCacheServiceImpl;
import com.mortals.xhx.module.device.dao.DeviceDao;
import com.mortals.xhx.module.device.model.DeviceEntity;
import com.mortals.xhx.module.device.service.DeviceService;
import org.springframework.util.ObjectUtils;
/**
* DeviceService
* 设备 service实现
......@@ -19,4 +23,13 @@ public class DeviceServiceImpl extends AbstractCRUDCacheServiceImpl<DeviceDao, D
protected String getExtKey(DeviceEntity data) {
return data.getDeviceCode();
}
@Override
protected void saveBefore(DeviceEntity entity, Context context) throws AppException {
if(ObjectUtils.isEmpty(entity.getDeviceCode())){
entity.setDeviceCode(entity.getDeviceMac());
}
super.saveBefore(entity, context);
}
}
\ No newline at end of file
......@@ -69,9 +69,8 @@ public class DeviceController extends BaseCRUDJsonMappingController<DeviceServic
this.addDict(model, "deviceOnlineStatus", paramService.getParamBySecondOrganize("Device", "deviceOnlineStatus"));
this.addDict(model, "status", paramService.getParamBySecondOrganize("Device", "status"));
this.addDict(model, "deviceFirmId", firmService.find(new FirmQuery()).stream().collect(Collectors.toMap(x -> x.getId().toString(), y -> y.getFirmName())));
this.addDict(model, "deviceSource", paramService.getParamBySecondOrganize("Device","deviceSource"));
Map<Boolean, Long> collect = this.service.find(new DeviceQuery()).stream().collect(Collectors.partitioningBy(item -> (item.getDeviceOnlineStatus() == DeviceOnlineStatusEnum.在线.getValue()), Collectors.counting()));
model.put("onlineCount", collect.get(true));
model.put("offlineCount", collect.get(false));
super.init(request, response, form, model, context);
......
......@@ -28,7 +28,7 @@ Content-Type: application/json
"status":0,
"deviceRemark":"plxklr",
"onlineTime":"1646755200000",
"offlineTime":"1646755200000",
"offlineTime":"1646755200000"
}
> {%
......@@ -50,4 +50,12 @@ Accept: application/json
###设备上报
POST {{baseUrl}}/api/device/upload
Content-Type: application/json
{
"devicenum":"AB:DD:DF:FD:AD:FA:DA:SS",
"action":"upload"
}
No preview for this file type
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment