20260730:平台对接pass另外一套方案
This commit is contained in:
parent
7963bcd5a6
commit
99e91ffac1
@ -1,196 +0,0 @@
|
||||
package com.fastbee.controller.integration;
|
||||
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.fastbee.common.annotation.Anonymous;
|
||||
import com.fastbee.common.core.controller.BaseController;
|
||||
import com.fastbee.common.core.domain.AjaxResult;
|
||||
import com.fastbee.common.core.page.TableDataInfo;
|
||||
import com.fastbee.common.exception.ServiceException;
|
||||
import com.fastbee.common.utils.StringUtils;
|
||||
import com.fastbee.iot.domain.integration.IntegrationApi;
|
||||
import com.fastbee.iot.domain.integration.IntegrationDeviceMapping;
|
||||
import com.fastbee.iot.domain.integration.IntegrationLog;
|
||||
import com.fastbee.iot.domain.integration.IntegrationPlatform;
|
||||
import com.fastbee.iot.model.integration.IntegrationSyncRequest;
|
||||
import com.fastbee.iot.service.integration.IIntegrationPlatformService;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 第三方平台接入。
|
||||
*/
|
||||
@Api(tags = "第三方平台接入")
|
||||
@RestController
|
||||
@RequestMapping("/iot/integration")
|
||||
public class IntegrationPlatformController extends BaseController {
|
||||
|
||||
@Resource
|
||||
private IIntegrationPlatformService integrationPlatformService;
|
||||
|
||||
@ApiOperation("查询平台接入配置")
|
||||
@PreAuthorize("@ss.hasPermi('iot:integration:list')")
|
||||
@GetMapping("/platform/list")
|
||||
public TableDataInfo list(IntegrationPlatform query) {
|
||||
startPage();
|
||||
List<IntegrationPlatform> list = integrationPlatformService.selectPlatformList(query);
|
||||
return getDataTable(list);
|
||||
}
|
||||
|
||||
@ApiOperation("查询平台接入配置详情")
|
||||
@PreAuthorize("@ss.hasPermi('iot:integration:list')")
|
||||
@GetMapping("/platform/{id}")
|
||||
public AjaxResult getPlatform(@PathVariable Long id) {
|
||||
return AjaxResult.success(integrationPlatformService.selectPlatformById(id));
|
||||
}
|
||||
|
||||
@ApiOperation("新增平台接入配置")
|
||||
@PreAuthorize("@ss.hasPermi('iot:integration:add')")
|
||||
@PostMapping("/platform")
|
||||
public AjaxResult addPlatform(@RequestBody IntegrationPlatform platform) {
|
||||
return toAjax(integrationPlatformService.insertPlatform(platform));
|
||||
}
|
||||
|
||||
@ApiOperation("修改平台接入配置")
|
||||
@PreAuthorize("@ss.hasPermi('iot:integration:edit')")
|
||||
@PutMapping("/platform")
|
||||
public AjaxResult editPlatform(@RequestBody IntegrationPlatform platform) {
|
||||
return toAjax(integrationPlatformService.updatePlatform(platform));
|
||||
}
|
||||
|
||||
@ApiOperation("删除平台接入配置")
|
||||
@PreAuthorize("@ss.hasPermi('iot:integration:remove')")
|
||||
@DeleteMapping("/platform/{ids}")
|
||||
public AjaxResult removePlatform(@PathVariable Long[] ids) {
|
||||
return toAjax(integrationPlatformService.deletePlatformByIds(ids));
|
||||
}
|
||||
|
||||
@ApiOperation("查询平台接口定义")
|
||||
@PreAuthorize("@ss.hasPermi('iot:integration:list')")
|
||||
@GetMapping("/api/list")
|
||||
public TableDataInfo apiList(IntegrationApi query) {
|
||||
startPage();
|
||||
List<IntegrationApi> list = integrationPlatformService.selectApiList(query);
|
||||
return getDataTable(list);
|
||||
}
|
||||
|
||||
@ApiOperation("查询平台接口定义详情")
|
||||
@PreAuthorize("@ss.hasPermi('iot:integration:list')")
|
||||
@GetMapping("/api/{id}")
|
||||
public AjaxResult getApi(@PathVariable Long id) {
|
||||
return AjaxResult.success(integrationPlatformService.selectApiById(id));
|
||||
}
|
||||
|
||||
@ApiOperation("新增平台接口定义")
|
||||
@PreAuthorize("@ss.hasPermi('iot:integration:add')")
|
||||
@PostMapping("/api")
|
||||
public AjaxResult addApi(@RequestBody IntegrationApi api) {
|
||||
return toAjax(integrationPlatformService.insertApi(api));
|
||||
}
|
||||
|
||||
@ApiOperation("修改平台接口定义")
|
||||
@PreAuthorize("@ss.hasPermi('iot:integration:edit')")
|
||||
@PutMapping("/api")
|
||||
public AjaxResult editApi(@RequestBody IntegrationApi api) {
|
||||
return toAjax(integrationPlatformService.updateApi(api));
|
||||
}
|
||||
|
||||
@ApiOperation("删除平台接口定义")
|
||||
@PreAuthorize("@ss.hasPermi('iot:integration:remove')")
|
||||
@DeleteMapping("/api/{ids}")
|
||||
public AjaxResult removeApi(@PathVariable Long[] ids) {
|
||||
return toAjax(integrationPlatformService.deleteApiByIds(ids));
|
||||
}
|
||||
|
||||
@ApiOperation("查询平台设备映射")
|
||||
@PreAuthorize("@ss.hasPermi('iot:integration:list')")
|
||||
@GetMapping("/device-mapping/list")
|
||||
public TableDataInfo deviceMappingList(IntegrationDeviceMapping query) {
|
||||
startPage();
|
||||
List<IntegrationDeviceMapping> list = integrationPlatformService.selectDeviceMappingList(query);
|
||||
return getDataTable(list);
|
||||
}
|
||||
|
||||
@ApiOperation("查询平台设备映射详情")
|
||||
@PreAuthorize("@ss.hasPermi('iot:integration:list')")
|
||||
@GetMapping("/device-mapping/{id}")
|
||||
public AjaxResult getDeviceMapping(@PathVariable Long id) {
|
||||
return AjaxResult.success(integrationPlatformService.selectDeviceMappingById(id));
|
||||
}
|
||||
|
||||
@ApiOperation("新增平台设备映射")
|
||||
@PreAuthorize("@ss.hasPermi('iot:integration:add')")
|
||||
@PostMapping("/device-mapping")
|
||||
public AjaxResult addDeviceMapping(@RequestBody IntegrationDeviceMapping mapping) {
|
||||
return toAjax(integrationPlatformService.insertDeviceMapping(mapping));
|
||||
}
|
||||
|
||||
@ApiOperation("修改平台设备映射")
|
||||
@PreAuthorize("@ss.hasPermi('iot:integration:edit')")
|
||||
@PutMapping("/device-mapping")
|
||||
public AjaxResult editDeviceMapping(@RequestBody IntegrationDeviceMapping mapping) {
|
||||
return toAjax(integrationPlatformService.updateDeviceMapping(mapping));
|
||||
}
|
||||
|
||||
@ApiOperation("删除平台设备映射")
|
||||
@PreAuthorize("@ss.hasPermi('iot:integration:remove')")
|
||||
@DeleteMapping("/device-mapping/{ids}")
|
||||
public AjaxResult removeDeviceMapping(@PathVariable Long[] ids) {
|
||||
return toAjax(integrationPlatformService.deleteDeviceMappingByIds(ids));
|
||||
}
|
||||
|
||||
@ApiOperation("查询平台同步日志")
|
||||
@PreAuthorize("@ss.hasPermi('iot:integration:list')")
|
||||
@GetMapping("/log/list")
|
||||
public TableDataInfo logList(IntegrationLog query) {
|
||||
startPage();
|
||||
List<IntegrationLog> list = integrationPlatformService.selectLogList(query);
|
||||
return getDataTable(list);
|
||||
}
|
||||
|
||||
@ApiOperation("触发平台数据同步")
|
||||
@PreAuthorize("@ss.hasPermi('iot:integration:sync')")
|
||||
@PostMapping("/sync")
|
||||
public AjaxResult sync(@RequestBody IntegrationSyncRequest request) {
|
||||
return AjaxResult.success(integrationPlatformService.sync(request));
|
||||
}
|
||||
|
||||
@Anonymous
|
||||
@ApiOperation("第三方触发平台数据同步")
|
||||
@PostMapping("/open/sync")
|
||||
public AjaxResult openSync(@RequestHeader(value = "X-Integration-Key", required = false) String integrationKey,
|
||||
@RequestBody IntegrationSyncRequest request) {
|
||||
checkOpenKey(request, integrationKey);
|
||||
return AjaxResult.success(integrationPlatformService.sync(request));
|
||||
}
|
||||
|
||||
@ApiOperation("平台适配器自测")
|
||||
@PreAuthorize("@ss.hasPermi('iot:integration:sync')")
|
||||
@PostMapping("/self-test/{platformCode}")
|
||||
public AjaxResult selfTest(@PathVariable String platformCode) {
|
||||
return AjaxResult.success(integrationPlatformService.selfTest(platformCode));
|
||||
}
|
||||
|
||||
private void checkOpenKey(IntegrationSyncRequest request, String integrationKey) {
|
||||
if (request == null || StringUtils.isBlank(request.getPlatformCode())) {
|
||||
throw new ServiceException("平台编码不能为空");
|
||||
}
|
||||
IntegrationPlatform platform = integrationPlatformService.selectPlatformByCode(request.getPlatformCode());
|
||||
if (platform == null) {
|
||||
throw new ServiceException("平台不存在");
|
||||
}
|
||||
JSONObject credential = StringUtils.isBlank(platform.getCredentialJson()) ? new JSONObject() : JSON.parseObject(platform.getCredentialJson());
|
||||
String openApiKey = credential.getString("openApiKey");
|
||||
if (StringUtils.isBlank(openApiKey)) {
|
||||
throw new ServiceException("平台未启用开放调度密钥");
|
||||
}
|
||||
if (!openApiKey.equals(integrationKey)) {
|
||||
throw new ServiceException("开放调度密钥无效");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,65 +0,0 @@
|
||||
package com.fastbee.controller.integration.dcp;
|
||||
|
||||
import com.alibaba.fastjson2.JSONArray;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.fastbee.common.annotation.Anonymous;
|
||||
import com.fastbee.iot.service.integration.IDcpOpenApiService;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* DCP轴力计兼容开放接口。
|
||||
*
|
||||
* <p>接口路径与《DCP接口文档(轴力计)》保持一致,前缀为 /open/dcp。</p>
|
||||
*/
|
||||
@Anonymous
|
||||
@Api(tags = "DCP轴力计兼容开放接口")
|
||||
@RestController
|
||||
@RequestMapping("/open/dcp")
|
||||
public class DcpOpenApiController {
|
||||
|
||||
@Resource
|
||||
private IDcpOpenApiService dcpOpenApiService;
|
||||
|
||||
@ApiOperation("获取访问凭证")
|
||||
@PostMapping("/connect/token")
|
||||
public JSONObject token(@RequestParam Map<String, String> form) {
|
||||
return dcpOpenApiService.createToken(form == null ? new HashMap<>() : form);
|
||||
}
|
||||
|
||||
@ApiOperation("获取用户信息")
|
||||
@GetMapping("/api/app/user/user-id")
|
||||
public JSONObject userId(@RequestHeader("Authorization") String authorization) {
|
||||
return dcpOpenApiService.getUser(authorization);
|
||||
}
|
||||
|
||||
@ApiOperation("获取项目信息")
|
||||
@GetMapping("/api/app/project/by-user-id/{userId}")
|
||||
public JSONArray projects(@RequestHeader("Authorization") String authorization,
|
||||
@PathVariable String userId) {
|
||||
return dcpOpenApiService.getProjects(authorization, userId);
|
||||
}
|
||||
|
||||
@ApiOperation("获取项目轴力计测点")
|
||||
@PostMapping("/api/app/stress-sensor/by-project-id/{projectId}")
|
||||
public JSONArray stressSensors(@RequestHeader("Authorization") String authorization,
|
||||
@PathVariable String projectId) {
|
||||
return dcpOpenApiService.getStressSensors(authorization, projectId);
|
||||
}
|
||||
|
||||
@ApiOperation("批量获取轴力计数据")
|
||||
@PostMapping("/api/app/inclino-data/load-dataset-by-device-ids")
|
||||
public JSONObject dataset(@RequestHeader("Authorization") String authorization,
|
||||
@RequestParam String startTime,
|
||||
@RequestParam String endTime,
|
||||
@RequestParam(defaultValue = "true") Boolean isOriginal,
|
||||
@RequestBody List<String> deviceIds) {
|
||||
return dcpOpenApiService.getDataset(authorization, startTime, endTime, isOriginal, deviceIds);
|
||||
}
|
||||
}
|
||||
@ -1,8 +1,4 @@
|
||||
package com.fastbee.controller.platform.dcp;/**
|
||||
* @description:
|
||||
* @author Sumuxi
|
||||
* @date 2026/5/25
|
||||
*/
|
||||
package com.fastbee.controller.platform.dcp;
|
||||
|
||||
import io.swagger.annotations.Api;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
||||
@ -102,7 +102,7 @@ public class PubMqttCallBack implements MqttCallbackExtended {
|
||||
" ▌▌▌▌▌▌ ▌▌▌▌ ▌▌▌ ▍▌▌▌▏▌▌▌▌ ▌▌▌ ▌▌▌ ▌▌▌ ▌▌▌▌▌▌▌▌ ▌▌▌▌\n" +
|
||||
" ▌▌▌▍ ▌▌▌▍▍▍▌▌▌▌ ▌▌▌▌ ▌▌▌▌▌▌▌ ▌▌▌▌▍▍▍▌▌▌ ▌▌▌▌ ▌▌▌▌▌▌▌▌\n" +
|
||||
" ▌▌▌▏ ▌▌▌▌▌▌▌▌▌▌▌▌ ▌▌▌▌ ▌▌▌▌▌▌ ▌▌▌▌▌▌▌▌▌▌▌▌ ▌▌▌▌ ▌▌▌▌▌▌\n" +
|
||||
" ▌▌▌▏ ▌▌▌▌ ▌▌▌▌ ▌▌▌▌ ▌▌▌▌▌ ▌▌▌▌ ▌▌▌▌ ▌▌▌▌ ▌▌▌▌▌"
|
||||
" ▌▌▌▏ ▌▌▌▌ ▌▌▌▌ ▌▌▌▌ ▌▌▌▌▌ ▌▌▌▌ ▌▌▌▌ ▌▌▌▌ ▌▌▌▌▌\n"
|
||||
);
|
||||
|
||||
|
||||
|
||||
@ -1,68 +0,0 @@
|
||||
package com.fastbee.iot.domain.integration;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.fastbee.common.core.domain.BaseEntity;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* 第三方平台接口定义。
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName("iot_integration_api")
|
||||
@ApiModel(value = "IntegrationApi", description = "第三方平台接口定义")
|
||||
public class IntegrationApi extends BaseEntity {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@TableId(value = "id", type = IdType.AUTO)
|
||||
@ApiModelProperty("主键")
|
||||
private Long id;
|
||||
|
||||
@ApiModelProperty("平台ID")
|
||||
private Long platformId;
|
||||
|
||||
@ApiModelProperty("接口编码")
|
||||
private String apiCode;
|
||||
|
||||
@ApiModelProperty("接口名称")
|
||||
private String apiName;
|
||||
|
||||
@ApiModelProperty("请求方法")
|
||||
private String method;
|
||||
|
||||
@ApiModelProperty("接口 URI")
|
||||
private String uri;
|
||||
|
||||
@ApiModelProperty("Content-Type")
|
||||
private String contentType;
|
||||
|
||||
@ApiModelProperty("请求头模板 JSON")
|
||||
private String headersJson;
|
||||
|
||||
@ApiModelProperty("Query 模板 JSON")
|
||||
private String queryJson;
|
||||
|
||||
@ApiModelProperty("Body 模板 JSON")
|
||||
private String bodyJson;
|
||||
|
||||
@ApiModelProperty("返回数据路径")
|
||||
private String responsePath;
|
||||
|
||||
@ApiModelProperty("依赖接口编码")
|
||||
private String dependsOn;
|
||||
|
||||
@ApiModelProperty("排序")
|
||||
private Integer sortOrder;
|
||||
|
||||
@ApiModelProperty("状态:0=停用 1=启用")
|
||||
private Integer status;
|
||||
|
||||
@ApiModelProperty("删除标志:0=存在 2=删除")
|
||||
private String delFlag;
|
||||
}
|
||||
@ -1,50 +0,0 @@
|
||||
package com.fastbee.iot.domain.integration;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.fastbee.common.core.domain.BaseEntity;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* 第三方设备与本系统设备映射。
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName("iot_integration_device_mapping")
|
||||
@ApiModel(value = "IntegrationDeviceMapping", description = "第三方设备映射")
|
||||
public class IntegrationDeviceMapping extends BaseEntity {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@TableId(value = "id", type = IdType.AUTO)
|
||||
@ApiModelProperty("主键")
|
||||
private Long id;
|
||||
|
||||
@ApiModelProperty("平台ID")
|
||||
private Long platformId;
|
||||
|
||||
@ApiModelProperty("第三方设备ID")
|
||||
private String externalDeviceId;
|
||||
|
||||
@ApiModelProperty("第三方设备名称")
|
||||
private String externalDeviceName;
|
||||
|
||||
@ApiModelProperty("本系统产品ID")
|
||||
private Long productId;
|
||||
|
||||
@ApiModelProperty("本系统设备编号")
|
||||
private String serialNumber;
|
||||
|
||||
@ApiModelProperty("指标映射 JSON,sourceField -> identifier")
|
||||
private String identifierMappingJson;
|
||||
|
||||
@ApiModelProperty("状态:0=停用 1=启用")
|
||||
private Integer status;
|
||||
|
||||
@ApiModelProperty("删除标志:0=存在 2=删除")
|
||||
private String delFlag;
|
||||
}
|
||||
@ -1,61 +0,0 @@
|
||||
package com.fastbee.iot.domain.integration;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.fastbee.common.core.domain.BaseEntity;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 第三方平台接入执行日志。
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName("iot_integration_log")
|
||||
@ApiModel(value = "IntegrationLog", description = "第三方平台接入执行日志")
|
||||
public class IntegrationLog extends BaseEntity {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@TableId(value = "id", type = IdType.AUTO)
|
||||
@ApiModelProperty("主键")
|
||||
private Long id;
|
||||
|
||||
@ApiModelProperty("平台ID")
|
||||
private Long platformId;
|
||||
|
||||
@ApiModelProperty("平台编码")
|
||||
private String platformCode;
|
||||
|
||||
@ApiModelProperty("流程编码")
|
||||
private String flowCode;
|
||||
|
||||
@ApiModelProperty("请求ID")
|
||||
private String requestId;
|
||||
|
||||
@ApiModelProperty("开始时间")
|
||||
private Date startTime;
|
||||
|
||||
@ApiModelProperty("结束时间")
|
||||
private Date endTime;
|
||||
|
||||
@ApiModelProperty("状态:0=失败 1=成功 2=执行中")
|
||||
private Integer status;
|
||||
|
||||
@ApiModelProperty("成功数量")
|
||||
private Integer successCount;
|
||||
|
||||
@ApiModelProperty("失败数量")
|
||||
private Integer failCount;
|
||||
|
||||
@ApiModelProperty("错误信息")
|
||||
private String errorMsg;
|
||||
|
||||
@ApiModelProperty("详情 JSON")
|
||||
private String detailJson;
|
||||
}
|
||||
@ -1,47 +0,0 @@
|
||||
package com.fastbee.iot.domain.integration;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.fastbee.common.core.domain.BaseEntity;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* 第三方平台接入配置。
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName("iot_integration_platform")
|
||||
@ApiModel(value = "IntegrationPlatform", description = "第三方平台接入配置")
|
||||
public class IntegrationPlatform extends BaseEntity {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@TableId(value = "id", type = IdType.AUTO)
|
||||
@ApiModelProperty("主键")
|
||||
private Long id;
|
||||
|
||||
@ApiModelProperty("平台编码")
|
||||
private String platformCode;
|
||||
|
||||
@ApiModelProperty("平台名称")
|
||||
private String platformName;
|
||||
|
||||
@ApiModelProperty("基础地址")
|
||||
private String baseUrl;
|
||||
|
||||
@ApiModelProperty("认证类型")
|
||||
private String authType;
|
||||
|
||||
@ApiModelProperty("凭证配置 JSON")
|
||||
private String credentialJson;
|
||||
|
||||
@ApiModelProperty("状态:0=停用 1=启用")
|
||||
private Integer status;
|
||||
|
||||
@ApiModelProperty("删除标志:0=存在 2=删除")
|
||||
private String delFlag;
|
||||
}
|
||||
@ -1,9 +0,0 @@
|
||||
package com.fastbee.iot.mapper.integration;
|
||||
|
||||
import com.fastbee.framework.mybatis.mapper.BaseMapperX;
|
||||
import com.fastbee.iot.domain.integration.IntegrationApi;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public interface IntegrationApiMapper extends BaseMapperX<IntegrationApi> {
|
||||
}
|
||||
@ -1,9 +0,0 @@
|
||||
package com.fastbee.iot.mapper.integration;
|
||||
|
||||
import com.fastbee.framework.mybatis.mapper.BaseMapperX;
|
||||
import com.fastbee.iot.domain.integration.IntegrationDeviceMapping;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public interface IntegrationDeviceMappingMapper extends BaseMapperX<IntegrationDeviceMapping> {
|
||||
}
|
||||
@ -1,9 +0,0 @@
|
||||
package com.fastbee.iot.mapper.integration;
|
||||
|
||||
import com.fastbee.framework.mybatis.mapper.BaseMapperX;
|
||||
import com.fastbee.iot.domain.integration.IntegrationLog;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public interface IntegrationLogMapper extends BaseMapperX<IntegrationLog> {
|
||||
}
|
||||
@ -1,9 +0,0 @@
|
||||
package com.fastbee.iot.mapper.integration;
|
||||
|
||||
import com.fastbee.framework.mybatis.mapper.BaseMapperX;
|
||||
import com.fastbee.iot.domain.integration.IntegrationPlatform;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public interface IntegrationPlatformMapper extends BaseMapperX<IntegrationPlatform> {
|
||||
}
|
||||
@ -1,40 +0,0 @@
|
||||
package com.fastbee.iot.model.integration;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 第三方平台同步请求。
|
||||
*/
|
||||
@Data
|
||||
@ApiModel(value = "IntegrationSyncRequest", description = "第三方平台同步请求")
|
||||
public class IntegrationSyncRequest {
|
||||
|
||||
@ApiModelProperty("平台编码")
|
||||
private String platformCode;
|
||||
|
||||
@ApiModelProperty("开始时间,ISO-8601 格式")
|
||||
private String startTime;
|
||||
|
||||
@ApiModelProperty("结束时间,ISO-8601 格式")
|
||||
private String endTime;
|
||||
|
||||
@ApiModelProperty("是否原始数据")
|
||||
private Boolean original;
|
||||
|
||||
@ApiModelProperty("是否只演练不写入")
|
||||
private Boolean dryRun;
|
||||
|
||||
@ApiModelProperty("第三方项目ID,未传则使用平台流程获取")
|
||||
private String projectId;
|
||||
|
||||
@ApiModelProperty("指定第三方设备ID")
|
||||
private List<String> externalDeviceIds;
|
||||
|
||||
@ApiModelProperty("运行时参数")
|
||||
private Map<String, Object> params;
|
||||
}
|
||||
@ -1,57 +0,0 @@
|
||||
package com.fastbee.iot.model.integration;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 第三方平台同步结果。
|
||||
*/
|
||||
@Data
|
||||
@ApiModel(value = "IntegrationSyncResult", description = "第三方平台同步结果")
|
||||
public class IntegrationSyncResult {
|
||||
|
||||
@ApiModelProperty("平台编码")
|
||||
private String platformCode;
|
||||
|
||||
@ApiModelProperty("流程编码")
|
||||
private String flowCode;
|
||||
|
||||
@ApiModelProperty("请求ID")
|
||||
private String requestId;
|
||||
|
||||
@ApiModelProperty("是否演练")
|
||||
private boolean dryRun;
|
||||
|
||||
@ApiModelProperty("成功数量")
|
||||
private int successCount;
|
||||
|
||||
@ApiModelProperty("失败数量")
|
||||
private int failCount;
|
||||
|
||||
@ApiModelProperty("设备数量")
|
||||
private int deviceCount;
|
||||
|
||||
@ApiModelProperty("数据数量")
|
||||
private int dataCount;
|
||||
|
||||
@ApiModelProperty("消息")
|
||||
private String message;
|
||||
|
||||
@ApiModelProperty("详情")
|
||||
private List<String> details = new ArrayList<>();
|
||||
|
||||
public void addSuccess() {
|
||||
successCount++;
|
||||
}
|
||||
|
||||
public void addFail(String detail) {
|
||||
failCount++;
|
||||
if (detail != null) {
|
||||
details.add(detail);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,26 +0,0 @@
|
||||
package com.fastbee.iot.model.integration;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 平台接入后的统一遥测数据。
|
||||
*/
|
||||
@Data
|
||||
public class UnifiedTelemetry {
|
||||
|
||||
private String platformCode;
|
||||
|
||||
private String externalDeviceId;
|
||||
|
||||
private String externalDeviceName;
|
||||
|
||||
private Date reportTime;
|
||||
|
||||
private Map<String, Object> values = new LinkedHashMap<>();
|
||||
|
||||
private Object raw;
|
||||
}
|
||||
@ -1,434 +0,0 @@
|
||||
package com.fastbee.iot.service.impl.integration;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.fastbee.common.exception.ServiceException;
|
||||
import com.fastbee.common.utils.StringUtils;
|
||||
import com.fastbee.iot.domain.integration.IntegrationApi;
|
||||
import com.fastbee.iot.domain.integration.IntegrationDeviceMapping;
|
||||
import com.fastbee.iot.domain.integration.IntegrationLog;
|
||||
import com.fastbee.iot.domain.integration.IntegrationPlatform;
|
||||
import com.fastbee.iot.mapper.integration.IntegrationApiMapper;
|
||||
import com.fastbee.iot.mapper.integration.IntegrationDeviceMappingMapper;
|
||||
import com.fastbee.iot.mapper.integration.IntegrationLogMapper;
|
||||
import com.fastbee.iot.mapper.integration.IntegrationPlatformMapper;
|
||||
import com.fastbee.iot.model.integration.IntegrationSyncRequest;
|
||||
import com.fastbee.iot.model.integration.IntegrationSyncResult;
|
||||
import com.fastbee.iot.service.integration.IIntegrationPlatformService;
|
||||
import com.fastbee.iot.service.integration.PlatformAdapter;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* 第三方平台接入服务。
|
||||
*/
|
||||
@Service
|
||||
public class IntegrationPlatformServiceImpl implements IIntegrationPlatformService {
|
||||
|
||||
@Resource
|
||||
private IntegrationPlatformMapper platformMapper;
|
||||
|
||||
@Resource
|
||||
private IntegrationApiMapper apiMapper;
|
||||
|
||||
@Resource
|
||||
private IntegrationDeviceMappingMapper deviceMappingMapper;
|
||||
|
||||
@Resource
|
||||
private IntegrationLogMapper logMapper;
|
||||
|
||||
private final Map<String, PlatformAdapter> adapterMap = new HashMap<>();
|
||||
|
||||
public IntegrationPlatformServiceImpl(List<PlatformAdapter> adapters) {
|
||||
if (adapters != null) {
|
||||
for (PlatformAdapter adapter : adapters) {
|
||||
adapterMap.put(adapter.platformCode().toUpperCase(), adapter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public IntegrationPlatform selectPlatformByCode(String platformCode) {
|
||||
if (StringUtils.isBlank(platformCode)) {
|
||||
return null;
|
||||
}
|
||||
LambdaQueryWrapper<IntegrationPlatform> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(IntegrationPlatform::getPlatformCode, platformCode.toUpperCase())
|
||||
.eq(IntegrationPlatform::getDelFlag, "0")
|
||||
.last("limit 1");
|
||||
return platformMapper.selectOne(wrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IntegrationPlatform selectPlatformById(Long id) {
|
||||
if (id == null) {
|
||||
return null;
|
||||
}
|
||||
LambdaQueryWrapper<IntegrationPlatform> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(IntegrationPlatform::getId, id)
|
||||
.eq(IntegrationPlatform::getDelFlag, "0")
|
||||
.last("limit 1");
|
||||
return platformMapper.selectOne(wrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IntegrationPlatform> selectPlatformList(IntegrationPlatform query) {
|
||||
LambdaQueryWrapper<IntegrationPlatform> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(IntegrationPlatform::getDelFlag, "0");
|
||||
if (query != null) {
|
||||
wrapper.like(StringUtils.isNotBlank(query.getPlatformName()), IntegrationPlatform::getPlatformName, query.getPlatformName());
|
||||
wrapper.eq(StringUtils.isNotBlank(query.getPlatformCode()), IntegrationPlatform::getPlatformCode, query.getPlatformCode());
|
||||
wrapper.eq(query.getStatus() != null, IntegrationPlatform::getStatus, query.getStatus());
|
||||
}
|
||||
wrapper.orderByDesc(IntegrationPlatform::getCreateTime);
|
||||
return platformMapper.selectList(wrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int insertPlatform(IntegrationPlatform platform) {
|
||||
checkPlatform(platform);
|
||||
String platformCode = platform.getPlatformCode().toUpperCase();
|
||||
if (selectPlatformByCode(platformCode) != null) {
|
||||
throw new ServiceException("平台编码已存在:" + platformCode);
|
||||
}
|
||||
platform.setPlatformCode(platformCode);
|
||||
platform.setCredentialJson(normalizeJson(platform.getCredentialJson(), "凭证配置"));
|
||||
if (platform.getStatus() == null) {
|
||||
platform.setStatus(0);
|
||||
}
|
||||
platform.setDelFlag("0");
|
||||
platform.setCreateTime(new Date());
|
||||
return platformMapper.insert(platform);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int updatePlatform(IntegrationPlatform platform) {
|
||||
if (platform == null || platform.getId() == null) {
|
||||
throw new ServiceException("平台ID不能为空");
|
||||
}
|
||||
checkPlatform(platform);
|
||||
String platformCode = platform.getPlatformCode().toUpperCase();
|
||||
IntegrationPlatform exists = selectPlatformByCode(platformCode);
|
||||
if (exists != null && !exists.getId().equals(platform.getId())) {
|
||||
throw new ServiceException("平台编码已存在:" + platformCode);
|
||||
}
|
||||
platform.setPlatformCode(platformCode);
|
||||
platform.setCredentialJson(normalizeJson(platform.getCredentialJson(), "凭证配置"));
|
||||
platform.setUpdateTime(new Date());
|
||||
return platformMapper.updateById(platform);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int deletePlatformByIds(Long[] ids) {
|
||||
int rows = 0;
|
||||
if (ids == null) {
|
||||
return rows;
|
||||
}
|
||||
for (Long id : ids) {
|
||||
if (id == null) {
|
||||
continue;
|
||||
}
|
||||
IntegrationPlatform platform = new IntegrationPlatform();
|
||||
platform.setId(id);
|
||||
platform.setDelFlag("2");
|
||||
platform.setUpdateTime(new Date());
|
||||
rows += platformMapper.updateById(platform);
|
||||
}
|
||||
return rows;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IntegrationApi> selectApiList(IntegrationApi query) {
|
||||
LambdaQueryWrapper<IntegrationApi> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(IntegrationApi::getDelFlag, "0");
|
||||
if (query != null) {
|
||||
wrapper.eq(query.getPlatformId() != null, IntegrationApi::getPlatformId, query.getPlatformId());
|
||||
wrapper.like(StringUtils.isNotBlank(query.getApiCode()), IntegrationApi::getApiCode, query.getApiCode());
|
||||
wrapper.like(StringUtils.isNotBlank(query.getApiName()), IntegrationApi::getApiName, query.getApiName());
|
||||
wrapper.eq(query.getStatus() != null, IntegrationApi::getStatus, query.getStatus());
|
||||
}
|
||||
wrapper.orderByAsc(IntegrationApi::getSortOrder).orderByAsc(IntegrationApi::getId);
|
||||
return apiMapper.selectList(wrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IntegrationApi selectApiById(Long id) {
|
||||
if (id == null) {
|
||||
return null;
|
||||
}
|
||||
LambdaQueryWrapper<IntegrationApi> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(IntegrationApi::getId, id)
|
||||
.eq(IntegrationApi::getDelFlag, "0")
|
||||
.last("limit 1");
|
||||
return apiMapper.selectOne(wrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int insertApi(IntegrationApi api) {
|
||||
checkApi(api);
|
||||
if (api.getStatus() == null) {
|
||||
api.setStatus(1);
|
||||
}
|
||||
if (api.getSortOrder() == null) {
|
||||
api.setSortOrder(0);
|
||||
}
|
||||
api.setApiCode(api.getApiCode().toUpperCase());
|
||||
api.setMethod(api.getMethod().toUpperCase());
|
||||
api.setHeadersJson(normalizeJson(api.getHeadersJson(), "请求头模板"));
|
||||
api.setQueryJson(normalizeJson(api.getQueryJson(), "Query模板"));
|
||||
api.setBodyJson(normalizeJson(api.getBodyJson(), "Body模板"));
|
||||
api.setDelFlag("0");
|
||||
api.setCreateTime(new Date());
|
||||
return apiMapper.insert(api);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int updateApi(IntegrationApi api) {
|
||||
if (api == null || api.getId() == null) {
|
||||
throw new ServiceException("接口ID不能为空");
|
||||
}
|
||||
checkApi(api);
|
||||
api.setApiCode(api.getApiCode().toUpperCase());
|
||||
api.setMethod(api.getMethod().toUpperCase());
|
||||
api.setHeadersJson(normalizeJson(api.getHeadersJson(), "请求头模板"));
|
||||
api.setQueryJson(normalizeJson(api.getQueryJson(), "Query模板"));
|
||||
api.setBodyJson(normalizeJson(api.getBodyJson(), "Body模板"));
|
||||
api.setUpdateTime(new Date());
|
||||
return apiMapper.updateById(api);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int deleteApiByIds(Long[] ids) {
|
||||
int rows = 0;
|
||||
if (ids == null) {
|
||||
return rows;
|
||||
}
|
||||
for (Long id : ids) {
|
||||
if (id == null) {
|
||||
continue;
|
||||
}
|
||||
IntegrationApi api = new IntegrationApi();
|
||||
api.setId(id);
|
||||
api.setDelFlag("2");
|
||||
api.setUpdateTime(new Date());
|
||||
rows += apiMapper.updateById(api);
|
||||
}
|
||||
return rows;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IntegrationDeviceMapping> selectDeviceMappingList(IntegrationDeviceMapping query) {
|
||||
LambdaQueryWrapper<IntegrationDeviceMapping> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(IntegrationDeviceMapping::getDelFlag, "0");
|
||||
if (query != null) {
|
||||
wrapper.eq(query.getPlatformId() != null, IntegrationDeviceMapping::getPlatformId, query.getPlatformId());
|
||||
wrapper.like(StringUtils.isNotBlank(query.getExternalDeviceId()), IntegrationDeviceMapping::getExternalDeviceId, query.getExternalDeviceId());
|
||||
wrapper.like(StringUtils.isNotBlank(query.getExternalDeviceName()), IntegrationDeviceMapping::getExternalDeviceName, query.getExternalDeviceName());
|
||||
wrapper.eq(query.getProductId() != null, IntegrationDeviceMapping::getProductId, query.getProductId());
|
||||
wrapper.like(StringUtils.isNotBlank(query.getSerialNumber()), IntegrationDeviceMapping::getSerialNumber, query.getSerialNumber());
|
||||
wrapper.eq(query.getStatus() != null, IntegrationDeviceMapping::getStatus, query.getStatus());
|
||||
}
|
||||
wrapper.orderByDesc(IntegrationDeviceMapping::getCreateTime);
|
||||
return deviceMappingMapper.selectList(wrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IntegrationDeviceMapping selectDeviceMappingById(Long id) {
|
||||
if (id == null) {
|
||||
return null;
|
||||
}
|
||||
LambdaQueryWrapper<IntegrationDeviceMapping> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(IntegrationDeviceMapping::getId, id)
|
||||
.eq(IntegrationDeviceMapping::getDelFlag, "0")
|
||||
.last("limit 1");
|
||||
return deviceMappingMapper.selectOne(wrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int insertDeviceMapping(IntegrationDeviceMapping mapping) {
|
||||
checkDeviceMapping(mapping);
|
||||
if (mapping.getStatus() == null) {
|
||||
mapping.setStatus(1);
|
||||
}
|
||||
mapping.setIdentifierMappingJson(normalizeJson(mapping.getIdentifierMappingJson(), "指标映射"));
|
||||
mapping.setDelFlag("0");
|
||||
mapping.setCreateTime(new Date());
|
||||
return deviceMappingMapper.insert(mapping);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int updateDeviceMapping(IntegrationDeviceMapping mapping) {
|
||||
if (mapping == null || mapping.getId() == null) {
|
||||
throw new ServiceException("映射ID不能为空");
|
||||
}
|
||||
checkDeviceMapping(mapping);
|
||||
mapping.setIdentifierMappingJson(normalizeJson(mapping.getIdentifierMappingJson(), "指标映射"));
|
||||
mapping.setUpdateTime(new Date());
|
||||
return deviceMappingMapper.updateById(mapping);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int deleteDeviceMappingByIds(Long[] ids) {
|
||||
int rows = 0;
|
||||
if (ids == null) {
|
||||
return rows;
|
||||
}
|
||||
for (Long id : ids) {
|
||||
if (id == null) {
|
||||
continue;
|
||||
}
|
||||
IntegrationDeviceMapping mapping = new IntegrationDeviceMapping();
|
||||
mapping.setId(id);
|
||||
mapping.setDelFlag("2");
|
||||
mapping.setUpdateTime(new Date());
|
||||
rows += deviceMappingMapper.updateById(mapping);
|
||||
}
|
||||
return rows;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IntegrationLog> selectLogList(IntegrationLog query) {
|
||||
LambdaQueryWrapper<IntegrationLog> wrapper = new LambdaQueryWrapper<>();
|
||||
if (query != null) {
|
||||
wrapper.eq(query.getPlatformId() != null, IntegrationLog::getPlatformId, query.getPlatformId());
|
||||
wrapper.like(StringUtils.isNotBlank(query.getPlatformCode()), IntegrationLog::getPlatformCode, query.getPlatformCode());
|
||||
wrapper.like(StringUtils.isNotBlank(query.getFlowCode()), IntegrationLog::getFlowCode, query.getFlowCode());
|
||||
wrapper.like(StringUtils.isNotBlank(query.getRequestId()), IntegrationLog::getRequestId, query.getRequestId());
|
||||
wrapper.eq(query.getStatus() != null, IntegrationLog::getStatus, query.getStatus());
|
||||
}
|
||||
wrapper.orderByDesc(IntegrationLog::getStartTime);
|
||||
return logMapper.selectList(wrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IntegrationSyncResult sync(IntegrationSyncRequest request) {
|
||||
if (request == null || StringUtils.isBlank(request.getPlatformCode())) {
|
||||
throw new ServiceException("平台编码不能为空");
|
||||
}
|
||||
String platformCode = request.getPlatformCode().toUpperCase();
|
||||
IntegrationPlatform platform = selectPlatformByCode(platformCode);
|
||||
if (platform == null || platform.getStatus() == null || platform.getStatus() != 1) {
|
||||
throw new ServiceException("平台不存在或未启用:" + platformCode);
|
||||
}
|
||||
PlatformAdapter adapter = adapterMap.get(platformCode);
|
||||
if (adapter == null) {
|
||||
throw new ServiceException("未找到平台适配器:" + platformCode);
|
||||
}
|
||||
|
||||
String requestId = UUID.randomUUID().toString().replace("-", "");
|
||||
IntegrationLog log = new IntegrationLog();
|
||||
log.setPlatformId(platform.getId());
|
||||
log.setPlatformCode(platformCode);
|
||||
log.setFlowCode(platformCode + "_SYNC");
|
||||
log.setRequestId(requestId);
|
||||
log.setStartTime(new Date());
|
||||
log.setStatus(2);
|
||||
log.setSuccessCount(0);
|
||||
log.setFailCount(0);
|
||||
logMapper.insert(log);
|
||||
|
||||
try {
|
||||
IntegrationSyncResult result = adapter.sync(platform, request);
|
||||
result.setRequestId(requestId);
|
||||
log.setStatus(result.getFailCount() == 0 ? 1 : 0);
|
||||
log.setSuccessCount(result.getSuccessCount());
|
||||
log.setFailCount(result.getFailCount());
|
||||
log.setDetailJson(com.alibaba.fastjson2.JSON.toJSONString(result.getDetails()));
|
||||
log.setEndTime(new Date());
|
||||
logMapper.updateById(log);
|
||||
return result;
|
||||
} catch (Exception e) {
|
||||
log.setStatus(0);
|
||||
log.setErrorMsg(StringUtils.substring(e.getMessage(), 0, 1000));
|
||||
log.setEndTime(new Date());
|
||||
logMapper.updateById(log);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public IntegrationSyncResult selfTest(String platformCode) {
|
||||
String code = StringUtils.isBlank(platformCode) ? "DCP" : platformCode.toUpperCase();
|
||||
PlatformAdapter adapter = adapterMap.get(code);
|
||||
if (adapter == null) {
|
||||
throw new ServiceException("未找到平台适配器:" + code);
|
||||
}
|
||||
IntegrationPlatform platform = selectPlatformByCode(code);
|
||||
if (platform == null) {
|
||||
platform = new IntegrationPlatform();
|
||||
platform.setPlatformCode(code);
|
||||
platform.setPlatformName(code + " 自测平台");
|
||||
platform.setBaseUrl("http://example.com");
|
||||
platform.setStatus(1);
|
||||
}
|
||||
IntegrationSyncResult result = adapter.selfTest(platform);
|
||||
result.setRequestId(UUID.randomUUID().toString().replace("-", ""));
|
||||
return result;
|
||||
}
|
||||
|
||||
private void checkPlatform(IntegrationPlatform platform) {
|
||||
if (platform == null) {
|
||||
throw new ServiceException("平台配置不能为空");
|
||||
}
|
||||
if (StringUtils.isBlank(platform.getPlatformCode())) {
|
||||
throw new ServiceException("平台编码不能为空");
|
||||
}
|
||||
if (StringUtils.isBlank(platform.getPlatformName())) {
|
||||
throw new ServiceException("平台名称不能为空");
|
||||
}
|
||||
if (StringUtils.isBlank(platform.getBaseUrl())) {
|
||||
throw new ServiceException("平台基础地址不能为空");
|
||||
}
|
||||
}
|
||||
|
||||
private void checkApi(IntegrationApi api) {
|
||||
if (api == null) {
|
||||
throw new ServiceException("接口配置不能为空");
|
||||
}
|
||||
if (api.getPlatformId() == null) {
|
||||
throw new ServiceException("平台ID不能为空");
|
||||
}
|
||||
if (StringUtils.isBlank(api.getApiCode())) {
|
||||
throw new ServiceException("接口编码不能为空");
|
||||
}
|
||||
if (StringUtils.isBlank(api.getMethod())) {
|
||||
throw new ServiceException("请求方法不能为空");
|
||||
}
|
||||
if (StringUtils.isBlank(api.getUri())) {
|
||||
throw new ServiceException("接口URI不能为空");
|
||||
}
|
||||
}
|
||||
|
||||
private void checkDeviceMapping(IntegrationDeviceMapping mapping) {
|
||||
if (mapping == null) {
|
||||
throw new ServiceException("设备映射不能为空");
|
||||
}
|
||||
if (mapping.getPlatformId() == null) {
|
||||
throw new ServiceException("平台ID不能为空");
|
||||
}
|
||||
if (StringUtils.isBlank(mapping.getExternalDeviceId())) {
|
||||
throw new ServiceException("第三方设备ID不能为空");
|
||||
}
|
||||
if (StringUtils.isBlank(mapping.getSerialNumber())) {
|
||||
throw new ServiceException("本系统设备编号不能为空");
|
||||
}
|
||||
}
|
||||
|
||||
private String normalizeJson(String json, String label) {
|
||||
if (StringUtils.isBlank(json)) {
|
||||
return null;
|
||||
}
|
||||
String normalized = json.trim();
|
||||
try {
|
||||
com.alibaba.fastjson2.JSON.parse(normalized);
|
||||
return normalized;
|
||||
} catch (Exception e) {
|
||||
throw new ServiceException(label + "必须是合法JSON");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,117 +0,0 @@
|
||||
package com.fastbee.iot.service.impl.integration.dcp;
|
||||
|
||||
import com.alibaba.fastjson2.JSONArray;
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.fastbee.common.core.redis.RedisCache;
|
||||
import com.fastbee.common.exception.ServiceException;
|
||||
import com.fastbee.common.utils.StringUtils;
|
||||
import com.fastbee.iot.domain.integration.IntegrationPlatform;
|
||||
import com.fastbee.iot.service.integration.IDcpOpenApiService;
|
||||
import com.fastbee.iot.service.integration.IIntegrationPlatformService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* DCP兼容开放接口服务。
|
||||
*/
|
||||
@Service
|
||||
public class DcpOpenApiServiceImpl implements IDcpOpenApiService {
|
||||
|
||||
private static final String PLATFORM_CODE = "DCP";
|
||||
private static final String TOKEN_PREFIX = "iot:integration:open:dcp:token:";
|
||||
private static final int TOKEN_SECONDS = 7200;
|
||||
|
||||
@Resource
|
||||
private IIntegrationPlatformService integrationPlatformService;
|
||||
|
||||
@Resource
|
||||
private DcpPlatformAdapter dcpPlatformAdapter;
|
||||
|
||||
@Resource
|
||||
private RedisCache redisCache;
|
||||
|
||||
@Override
|
||||
public JSONObject createToken(Map<String, String> form) {
|
||||
IntegrationPlatform platform = requirePlatform();
|
||||
JSONObject credential = StringUtils.isBlank(platform.getCredentialJson()) ? new JSONObject() : JSON.parseObject(platform.getCredentialJson());
|
||||
String expectedClientId = credential.getString("openClientId");
|
||||
String expectedUserName = credential.getString("openUserName");
|
||||
String expectedPassword = credential.getString("openPassword");
|
||||
if (StringUtils.isAnyBlank(expectedClientId, expectedUserName, expectedPassword)) {
|
||||
throw new ServiceException("DCP开放接口账号未配置");
|
||||
}
|
||||
if (!"password".equals(form.get("grant_type"))) {
|
||||
throw new ServiceException("grant_type不支持");
|
||||
}
|
||||
if (!expectedClientId.equals(form.get("client_id"))
|
||||
|| !expectedUserName.equals(form.get("userName"))
|
||||
|| !expectedPassword.equals(form.get("password"))) {
|
||||
throw new ServiceException("DCP开放接口账号或密码错误");
|
||||
}
|
||||
String token = UUID.randomUUID().toString().replace("-", "");
|
||||
redisCache.setCacheObject(TOKEN_PREFIX + token, platform.getId(), TOKEN_SECONDS, TimeUnit.SECONDS);
|
||||
|
||||
JSONObject result = new JSONObject();
|
||||
result.put("access_token", token);
|
||||
result.put("expires_in", TOKEN_SECONDS);
|
||||
result.put("token_type", "Bearer");
|
||||
result.put("scope", StringUtils.defaultIfBlank(form.get("scope"), "DACP"));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONObject getUser(String authorization) {
|
||||
return dcpPlatformAdapter.fetchUser(requireAuthorizedPlatform(authorization));
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONArray getProjects(String authorization, String userId) {
|
||||
if (StringUtils.isBlank(userId)) {
|
||||
throw new ServiceException("userId不能为空");
|
||||
}
|
||||
return dcpPlatformAdapter.fetchProjects(requireAuthorizedPlatform(authorization), userId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONArray getStressSensors(String authorization, String projectId) {
|
||||
if (StringUtils.isBlank(projectId)) {
|
||||
throw new ServiceException("projectId不能为空");
|
||||
}
|
||||
return dcpPlatformAdapter.fetchStressSensors(requireAuthorizedPlatform(authorization), projectId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONObject getDataset(String authorization, String startTime, String endTime, Boolean original, List<String> deviceIds) {
|
||||
if (deviceIds == null || deviceIds.isEmpty()) {
|
||||
throw new ServiceException("deviceId数组不能为空");
|
||||
}
|
||||
return dcpPlatformAdapter.fetchDataset(requireAuthorizedPlatform(authorization), startTime, endTime, original, deviceIds);
|
||||
}
|
||||
|
||||
private IntegrationPlatform requireAuthorizedPlatform(String authorization) {
|
||||
if (StringUtils.isBlank(authorization) || !authorization.startsWith("Bearer ")) {
|
||||
throw new ServiceException("Authorization不能为空");
|
||||
}
|
||||
String token = authorization.substring("Bearer ".length());
|
||||
Long platformId = redisCache.getCacheObject(TOKEN_PREFIX + token);
|
||||
IntegrationPlatform platform = requirePlatform();
|
||||
if (platformId == null || !platform.getId().equals(platformId)) {
|
||||
throw new ServiceException("Authorization无效或已过期");
|
||||
}
|
||||
return platform;
|
||||
}
|
||||
|
||||
private IntegrationPlatform requirePlatform() {
|
||||
IntegrationPlatform platform = integrationPlatformService.selectPlatformByCode(PLATFORM_CODE);
|
||||
if (platform == null || platform.getStatus() == null || platform.getStatus() != 1) {
|
||||
throw new ServiceException("DCP平台未启用");
|
||||
}
|
||||
return platform;
|
||||
}
|
||||
}
|
||||
@ -1,547 +0,0 @@
|
||||
package com.fastbee.iot.service.impl.integration.dcp;
|
||||
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.alibaba.fastjson2.JSONArray;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.fastbee.common.core.redis.RedisCache;
|
||||
import com.fastbee.common.core.thingsModel.ThingsModelSimpleItem;
|
||||
import com.fastbee.common.core.thingsModel.ThingsModelValuesInput;
|
||||
import com.fastbee.common.exception.ServiceException;
|
||||
import com.fastbee.common.utils.StringUtils;
|
||||
import com.fastbee.iot.domain.integration.IntegrationApi;
|
||||
import com.fastbee.iot.domain.integration.IntegrationDeviceMapping;
|
||||
import com.fastbee.iot.domain.integration.IntegrationPlatform;
|
||||
import com.fastbee.iot.mapper.integration.IntegrationApiMapper;
|
||||
import com.fastbee.iot.mapper.integration.IntegrationDeviceMappingMapper;
|
||||
import com.fastbee.iot.model.integration.IntegrationSyncRequest;
|
||||
import com.fastbee.iot.model.integration.IntegrationSyncResult;
|
||||
import com.fastbee.iot.model.integration.UnifiedTelemetry;
|
||||
import com.fastbee.iot.service.IDeviceService;
|
||||
import com.fastbee.iot.service.integration.PlatformAdapter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.*;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.math.BigDecimal;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLEncoder;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* DCP 轴力计平台适配器。
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class DcpPlatformAdapter implements PlatformAdapter {
|
||||
|
||||
private static final String PLATFORM_CODE = "DCP";
|
||||
private static final String API_TOKEN = "dcp_token";
|
||||
private static final String API_USER = "dcp_user_id";
|
||||
private static final String API_PROJECT = "dcp_project_list";
|
||||
private static final String API_DEVICE = "dcp_stress_sensor_list";
|
||||
private static final String API_DATA = "dcp_stress_sensor_data";
|
||||
|
||||
@Resource
|
||||
private IntegrationApiMapper apiMapper;
|
||||
|
||||
@Resource
|
||||
private IntegrationDeviceMappingMapper deviceMappingMapper;
|
||||
|
||||
@Resource
|
||||
private IDeviceService deviceService;
|
||||
|
||||
@Resource
|
||||
private RedisCache redisCache;
|
||||
|
||||
private final RestTemplate restTemplate = new RestTemplate();
|
||||
|
||||
@Override
|
||||
public String platformCode() {
|
||||
return PLATFORM_CODE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IntegrationSyncResult sync(IntegrationPlatform platform, IntegrationSyncRequest request) {
|
||||
IntegrationSyncResult result = new IntegrationSyncResult();
|
||||
result.setPlatformCode(PLATFORM_CODE);
|
||||
result.setFlowCode("DCP_STRESS_SENSOR_SYNC");
|
||||
result.setDryRun(Boolean.TRUE.equals(request.getDryRun()));
|
||||
|
||||
JSONObject credential = parseObject(platform.getCredentialJson());
|
||||
String authorization = resolveAuthorization(platform, credential);
|
||||
String userId = getUserId(platform, authorization);
|
||||
String projectId = StringUtils.isNotBlank(request.getProjectId()) ? request.getProjectId() : getFirstProjectId(platform, authorization, userId);
|
||||
if (StringUtils.isBlank(projectId)) {
|
||||
throw new ServiceException("DCP项目ID为空");
|
||||
}
|
||||
|
||||
List<JSONObject> devices = getDevices(platform, authorization, projectId);
|
||||
List<String> targetDeviceIds = selectTargetDeviceIds(devices, request.getExternalDeviceIds());
|
||||
result.setDeviceCount(targetDeviceIds.size());
|
||||
if (targetDeviceIds.isEmpty()) {
|
||||
result.setMessage("未获取到可同步的DCP轴力计测点");
|
||||
return result;
|
||||
}
|
||||
|
||||
Map<String, List<JSONObject>> dataMap = getDataset(platform, authorization, request, targetDeviceIds);
|
||||
Map<String, IntegrationDeviceMapping> mappings = loadMappings(platform.getId(), targetDeviceIds);
|
||||
|
||||
int dataCount = 0;
|
||||
for (String externalDeviceId : targetDeviceIds) {
|
||||
List<JSONObject> rows = dataMap.get(externalDeviceId);
|
||||
if (rows == null) {
|
||||
continue;
|
||||
}
|
||||
IntegrationDeviceMapping mapping = mappings.get(externalDeviceId);
|
||||
for (JSONObject row : rows) {
|
||||
dataCount++;
|
||||
if (mapping == null) {
|
||||
result.addFail("未配置设备映射 externalDeviceId=" + externalDeviceId);
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
UnifiedTelemetry telemetry = convertTelemetry(externalDeviceId, findDeviceName(devices, externalDeviceId), row);
|
||||
if (!result.isDryRun()) {
|
||||
writeThingsModel(mapping, telemetry);
|
||||
}
|
||||
result.addSuccess();
|
||||
} catch (Exception e) {
|
||||
result.addFail("写入失败 externalDeviceId=" + externalDeviceId + ", error=" + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
result.setDataCount(dataCount);
|
||||
result.setMessage(result.isDryRun() ? "DCP同步演练完成" : "DCP同步完成");
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IntegrationSyncResult selfTest(IntegrationPlatform platform) {
|
||||
IntegrationSyncResult result = new IntegrationSyncResult();
|
||||
result.setPlatformCode(PLATFORM_CODE);
|
||||
result.setFlowCode("DCP_STRESS_SENSOR_SELF_TEST");
|
||||
result.setDryRun(true);
|
||||
|
||||
JSONObject sample = JSON.parseObject("{\"isDeleted\":false,\"epoch\":\"2026-04-09T08:05:12+08:00\",\"deviceId\":\"3a1e1d88-c0ed-5f77-56f1-7704351b5a33\",\"e\":-323.26,\"fi\":0,\"ti\":0,\"span\":0,\"isOriginal\":true,\"temperature\":0,\"ct\":0,\"pt\":0}");
|
||||
UnifiedTelemetry telemetry = convertTelemetry(sample.getString("deviceId"), "第二层支护结构DK138+931", sample);
|
||||
if (!"3a1e1d88-c0ed-5f77-56f1-7704351b5a33".equals(telemetry.getExternalDeviceId())) {
|
||||
result.addFail("设备ID解析失败");
|
||||
}
|
||||
if (!telemetry.getValues().containsKey("e") || !telemetry.getValues().containsKey("temperature")) {
|
||||
result.addFail("轴力计数据字段解析失败");
|
||||
}
|
||||
if (telemetry.getReportTime() == null) {
|
||||
result.addFail("数据时间解析失败");
|
||||
}
|
||||
if (result.getFailCount() == 0) {
|
||||
result.addSuccess();
|
||||
result.setDataCount(1);
|
||||
result.setDeviceCount(1);
|
||||
result.setMessage("DCP适配器自测通过");
|
||||
} else {
|
||||
result.setMessage("DCP适配器自测失败");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public JSONObject fetchUser(IntegrationPlatform platform) {
|
||||
String authorization = resolveAuthorization(platform, parseObject(platform.getCredentialJson()));
|
||||
IntegrationApi api = getApi(platform.getId(), API_USER);
|
||||
return exchangeJson(platform, api, authorization, null, null);
|
||||
}
|
||||
|
||||
public JSONArray fetchProjects(IntegrationPlatform platform, String userId) {
|
||||
String authorization = resolveAuthorization(platform, parseObject(platform.getCredentialJson()));
|
||||
IntegrationApi api = getApi(platform.getId(), API_PROJECT);
|
||||
Map<String, Object> pathVars = new HashMap<>();
|
||||
pathVars.put("userId", userId);
|
||||
return exchangeArray(platform, api, authorization, pathVars, null);
|
||||
}
|
||||
|
||||
public JSONArray fetchStressSensors(IntegrationPlatform platform, String projectId) {
|
||||
String authorization = resolveAuthorization(platform, parseObject(platform.getCredentialJson()));
|
||||
IntegrationApi api = getApi(platform.getId(), API_DEVICE);
|
||||
Map<String, Object> pathVars = new HashMap<>();
|
||||
pathVars.put("projectId", projectId);
|
||||
pathVars.put("projcetId", projectId);
|
||||
return exchangeArray(platform, api, authorization, pathVars, null);
|
||||
}
|
||||
|
||||
public JSONObject fetchDataset(IntegrationPlatform platform, String startTime, String endTime, Boolean original, List<String> deviceIds) {
|
||||
String authorization = resolveAuthorization(platform, parseObject(platform.getCredentialJson()));
|
||||
IntegrationApi api = getApi(platform.getId(), API_DATA);
|
||||
Map<String, Object> query = new HashMap<>();
|
||||
query.put("startTime", defaultStartTime(startTime));
|
||||
query.put("endTime", defaultEndTime(endTime));
|
||||
query.put("isOriginal", String.valueOf(original == null || original));
|
||||
return exchangeJson(platform, api, authorization, query, deviceIds == null ? Collections.emptyList() : deviceIds);
|
||||
}
|
||||
|
||||
private String resolveAuthorization(IntegrationPlatform platform, JSONObject credential) {
|
||||
String cacheKey = "iot:integration:dcp:token:" + platform.getId();
|
||||
try {
|
||||
String cached = redisCache.getCacheObject(cacheKey);
|
||||
if (StringUtils.isNotBlank(cached)) {
|
||||
return cached;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.debug("读取DCP token缓存失败,将直接请求token:{}", e.getMessage());
|
||||
}
|
||||
|
||||
IntegrationApi api = getApi(platform.getId(), API_TOKEN);
|
||||
String url = buildUrl(platform.getBaseUrl(), api.getUri());
|
||||
MultiValueMap<String, String> body = new LinkedMultiValueMap<>();
|
||||
body.add("grant_type", value(credential, "grant_type", "grantType", "password"));
|
||||
body.add("scope", value(credential, "scope", null, "DACP"));
|
||||
body.add("client_id", value(credential, "client_id", "clientId", "DACP_App"));
|
||||
body.add("userName", value(credential, "userName", "username", null));
|
||||
body.add("password", value(credential, "password", null, null));
|
||||
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
|
||||
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.POST, new HttpEntity<>(body, headers), String.class);
|
||||
JSONObject json = JSON.parseObject(response.getBody());
|
||||
String token = json.getString("access_token");
|
||||
String tokenType = json.getString("token_type");
|
||||
if (StringUtils.isBlank(token)) {
|
||||
throw new ServiceException("DCP token获取失败");
|
||||
}
|
||||
String authorization = (StringUtils.isBlank(tokenType) ? "Bearer" : tokenType) + " " + token;
|
||||
int expires = json.getIntValue("expires_in");
|
||||
try {
|
||||
redisCache.setCacheObject(cacheKey, authorization, Math.max(expires - 60, 60), TimeUnit.SECONDS);
|
||||
} catch (Exception e) {
|
||||
log.debug("写入DCP token缓存失败:{}", e.getMessage());
|
||||
}
|
||||
return authorization;
|
||||
}
|
||||
|
||||
private String getUserId(IntegrationPlatform platform, String authorization) {
|
||||
IntegrationApi api = getApi(platform.getId(), API_USER);
|
||||
JSONObject json = exchangeJson(platform, api, authorization, null, null);
|
||||
String id = json.getString("id");
|
||||
if (StringUtils.isBlank(id)) {
|
||||
throw new ServiceException("DCP用户ID获取失败");
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
private String getFirstProjectId(IntegrationPlatform platform, String authorization, String userId) {
|
||||
IntegrationApi api = getApi(platform.getId(), API_PROJECT);
|
||||
Map<String, Object> pathVars = new HashMap<>();
|
||||
pathVars.put("userId", userId);
|
||||
JSONArray array = exchangeArray(platform, api, authorization, pathVars, null);
|
||||
if (array == null || array.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
return array.getJSONObject(0).getString("id");
|
||||
}
|
||||
|
||||
private List<JSONObject> getDevices(IntegrationPlatform platform, String authorization, String projectId) {
|
||||
IntegrationApi api = getApi(platform.getId(), API_DEVICE);
|
||||
Map<String, Object> pathVars = new HashMap<>();
|
||||
pathVars.put("projectId", projectId);
|
||||
pathVars.put("projcetId", projectId);
|
||||
JSONArray array = exchangeArray(platform, api, authorization, pathVars, null);
|
||||
return toObjectList(array);
|
||||
}
|
||||
|
||||
private Map<String, List<JSONObject>> getDataset(IntegrationPlatform platform, String authorization, IntegrationSyncRequest request, List<String> deviceIds) {
|
||||
IntegrationApi api = getApi(platform.getId(), API_DATA);
|
||||
Map<String, Object> query = new HashMap<>();
|
||||
query.put("startTime", defaultStartTime(request.getStartTime()));
|
||||
query.put("endTime", defaultEndTime(request.getEndTime()));
|
||||
query.put("isOriginal", String.valueOf(request.getOriginal() == null || request.getOriginal()));
|
||||
JSONObject json = exchangeJson(platform, api, authorization, query, deviceIds);
|
||||
Map<String, List<JSONObject>> result = new LinkedHashMap<>();
|
||||
for (String key : json.keySet()) {
|
||||
result.put(key, toObjectList(json.getJSONArray(key)));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private JSONObject exchangeJson(IntegrationPlatform platform, IntegrationApi api, String authorization, Map<String, Object> varsOrQuery, Object body) {
|
||||
String response = exchange(platform, api, authorization, varsOrQuery, body);
|
||||
if (StringUtils.isBlank(response)) {
|
||||
return new JSONObject();
|
||||
}
|
||||
return JSON.parseObject(response);
|
||||
}
|
||||
|
||||
private JSONArray exchangeArray(IntegrationPlatform platform, IntegrationApi api, String authorization, Map<String, Object> varsOrQuery, Object body) {
|
||||
String response = exchange(platform, api, authorization, varsOrQuery, body);
|
||||
if (StringUtils.isBlank(response)) {
|
||||
return new JSONArray();
|
||||
}
|
||||
return JSON.parseArray(response);
|
||||
}
|
||||
|
||||
private String exchange(IntegrationPlatform platform, IntegrationApi api, String authorization, Map<String, Object> varsOrQuery, Object body) {
|
||||
String uri = render(api.getUri(), varsOrQuery);
|
||||
String url = buildUrl(platform.getBaseUrl(), uri);
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.set("Authorization", authorization);
|
||||
if ("application/x-www-form-urlencoded".equalsIgnoreCase(api.getContentType())) {
|
||||
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
|
||||
} else {
|
||||
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||
}
|
||||
if ("GET".equalsIgnoreCase(api.getMethod())) {
|
||||
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.GET, new HttpEntity<>(headers), String.class);
|
||||
return response.getBody();
|
||||
}
|
||||
if (API_DATA.equals(api.getApiCode()) && varsOrQuery != null && !varsOrQuery.isEmpty()) {
|
||||
url = appendQuery(url, varsOrQuery);
|
||||
}
|
||||
HttpMethod method = HttpMethod.resolve(api.getMethod());
|
||||
if (method == null) {
|
||||
throw new ServiceException("不支持的请求方法:" + api.getMethod());
|
||||
}
|
||||
ResponseEntity<String> response = restTemplate.exchange(url, method, new HttpEntity<>(body, headers), String.class);
|
||||
return response.getBody();
|
||||
}
|
||||
|
||||
private void writeThingsModel(IntegrationDeviceMapping mapping, UnifiedTelemetry telemetry) {
|
||||
Map<String, String> identifierMapping = parseStringMap(mapping.getIdentifierMappingJson());
|
||||
if (identifierMapping.isEmpty()) {
|
||||
identifierMapping.put("e", "axialForce");
|
||||
identifierMapping.put("temperature", "temperature");
|
||||
identifierMapping.put("ct", "ct");
|
||||
identifierMapping.put("pt", "pt");
|
||||
}
|
||||
List<ThingsModelSimpleItem> items = new ArrayList<>();
|
||||
for (Map.Entry<String, Object> entry : telemetry.getValues().entrySet()) {
|
||||
String identifier = identifierMapping.get(entry.getKey());
|
||||
if (StringUtils.isBlank(identifier) || entry.getValue() == null) {
|
||||
continue;
|
||||
}
|
||||
ThingsModelSimpleItem item = new ThingsModelSimpleItem();
|
||||
item.setId(identifier);
|
||||
item.setValue(String.valueOf(entry.getValue()));
|
||||
item.setTs(telemetry.getReportTime());
|
||||
item.setRemark("integration:" + PLATFORM_CODE);
|
||||
items.add(item);
|
||||
}
|
||||
if (items.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
ThingsModelValuesInput input = new ThingsModelValuesInput();
|
||||
input.setProductId(mapping.getProductId());
|
||||
input.setDeviceNumber(mapping.getSerialNumber());
|
||||
input.setThingsModelValueRemarkItem(items);
|
||||
deviceService.reportDeviceThingsModelValue(input, 1, false);
|
||||
}
|
||||
|
||||
private UnifiedTelemetry convertTelemetry(String externalDeviceId, String externalDeviceName, JSONObject row) {
|
||||
UnifiedTelemetry telemetry = new UnifiedTelemetry();
|
||||
telemetry.setPlatformCode(PLATFORM_CODE);
|
||||
telemetry.setExternalDeviceId(externalDeviceId);
|
||||
telemetry.setExternalDeviceName(externalDeviceName);
|
||||
telemetry.setRaw(row);
|
||||
telemetry.setReportTime(parseDate(row.getString("epoch")));
|
||||
putIfPresent(telemetry.getValues(), "e", row.get("e"));
|
||||
putIfPresent(telemetry.getValues(), "temperature", row.get("temperature"));
|
||||
putIfPresent(telemetry.getValues(), "ct", row.get("ct"));
|
||||
putIfPresent(telemetry.getValues(), "pt", row.get("pt"));
|
||||
putIfPresent(telemetry.getValues(), "fi", row.get("fi"));
|
||||
putIfPresent(telemetry.getValues(), "ti", row.get("ti"));
|
||||
putIfPresent(telemetry.getValues(), "span", row.get("span"));
|
||||
return telemetry;
|
||||
}
|
||||
|
||||
private Map<String, IntegrationDeviceMapping> loadMappings(Long platformId, List<String> externalDeviceIds) {
|
||||
if (externalDeviceIds.isEmpty()) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
LambdaQueryWrapper<IntegrationDeviceMapping> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(IntegrationDeviceMapping::getPlatformId, platformId)
|
||||
.eq(IntegrationDeviceMapping::getStatus, 1)
|
||||
.eq(IntegrationDeviceMapping::getDelFlag, "0")
|
||||
.in(IntegrationDeviceMapping::getExternalDeviceId, externalDeviceIds);
|
||||
List<IntegrationDeviceMapping> list = deviceMappingMapper.selectList(wrapper);
|
||||
Map<String, IntegrationDeviceMapping> result = new HashMap<>();
|
||||
for (IntegrationDeviceMapping item : list) {
|
||||
result.put(item.getExternalDeviceId(), item);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private IntegrationApi getApi(Long platformId, String apiCode) {
|
||||
LambdaQueryWrapper<IntegrationApi> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(IntegrationApi::getPlatformId, platformId)
|
||||
.eq(IntegrationApi::getApiCode, apiCode)
|
||||
.eq(IntegrationApi::getDelFlag, "0")
|
||||
.last("limit 1");
|
||||
IntegrationApi api = apiMapper.selectOne(wrapper);
|
||||
return api == null ? defaultApi(apiCode) : api;
|
||||
}
|
||||
|
||||
private IntegrationApi defaultApi(String apiCode) {
|
||||
IntegrationApi api = new IntegrationApi();
|
||||
api.setApiCode(apiCode);
|
||||
api.setStatus(1);
|
||||
api.setContentType(MediaType.APPLICATION_JSON_VALUE);
|
||||
if (API_TOKEN.equals(apiCode)) {
|
||||
api.setMethod("POST");
|
||||
api.setUri("/connect/token");
|
||||
api.setContentType(MediaType.APPLICATION_FORM_URLENCODED_VALUE);
|
||||
} else if (API_USER.equals(apiCode)) {
|
||||
api.setMethod("GET");
|
||||
api.setUri("/api/app/user/user-id");
|
||||
} else if (API_PROJECT.equals(apiCode)) {
|
||||
api.setMethod("GET");
|
||||
api.setUri("/api/app/project/by-user-id/{userId}");
|
||||
} else if (API_DEVICE.equals(apiCode)) {
|
||||
api.setMethod("POST");
|
||||
api.setUri("/api/app/stress-sensor/by-project-id/{projectId}");
|
||||
} else if (API_DATA.equals(apiCode)) {
|
||||
api.setMethod("POST");
|
||||
api.setUri("/api/app/inclino-data/load-dataset-by-device-ids");
|
||||
} else {
|
||||
throw new ServiceException("未知DCP接口编码:" + apiCode);
|
||||
}
|
||||
return api;
|
||||
}
|
||||
|
||||
private List<String> selectTargetDeviceIds(List<JSONObject> devices, List<String> requested) {
|
||||
if (requested != null && !requested.isEmpty()) {
|
||||
return requested;
|
||||
}
|
||||
List<String> ids = new ArrayList<>();
|
||||
for (JSONObject device : devices) {
|
||||
String id = device.getString("id");
|
||||
if (StringUtils.isNotBlank(id)) {
|
||||
ids.add(id);
|
||||
}
|
||||
}
|
||||
return ids;
|
||||
}
|
||||
|
||||
private String findDeviceName(List<JSONObject> devices, String id) {
|
||||
for (JSONObject device : devices) {
|
||||
if (id.equals(device.getString("id"))) {
|
||||
return device.getString("name");
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private List<JSONObject> toObjectList(JSONArray array) {
|
||||
List<JSONObject> result = new ArrayList<>();
|
||||
if (array == null) {
|
||||
return result;
|
||||
}
|
||||
for (int i = 0; i < array.size(); i++) {
|
||||
result.add(array.getJSONObject(i));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private JSONObject parseObject(String json) {
|
||||
return StringUtils.isBlank(json) ? new JSONObject() : JSON.parseObject(json);
|
||||
}
|
||||
|
||||
private Map<String, String> parseStringMap(String json) {
|
||||
Map<String, String> result = new LinkedHashMap<>();
|
||||
if (StringUtils.isBlank(json)) {
|
||||
return result;
|
||||
}
|
||||
JSONObject object = JSON.parseObject(json);
|
||||
for (String key : object.keySet()) {
|
||||
result.put(key, object.getString(key));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private String value(JSONObject object, String key, String alias, String defaultValue) {
|
||||
String value = object.getString(key);
|
||||
if (StringUtils.isBlank(value) && StringUtils.isNotBlank(alias)) {
|
||||
value = object.getString(alias);
|
||||
}
|
||||
return StringUtils.isBlank(value) ? defaultValue : value;
|
||||
}
|
||||
|
||||
private Date parseDate(String text) {
|
||||
if (StringUtils.isBlank(text)) {
|
||||
return new Date();
|
||||
}
|
||||
return Date.from(OffsetDateTime.parse(text).toInstant());
|
||||
}
|
||||
|
||||
private void putIfPresent(Map<String, Object> values, String key, Object value) {
|
||||
if (value == null) {
|
||||
return;
|
||||
}
|
||||
if (value instanceof BigDecimal) {
|
||||
values.put(key, ((BigDecimal) value).stripTrailingZeros().toPlainString());
|
||||
} else {
|
||||
values.put(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
private String defaultStartTime(String value) {
|
||||
if (StringUtils.isNotBlank(value)) {
|
||||
return value;
|
||||
}
|
||||
return OffsetDateTime.now().minusDays(1).format(DateTimeFormatter.ISO_OFFSET_DATE_TIME);
|
||||
}
|
||||
|
||||
private String defaultEndTime(String value) {
|
||||
if (StringUtils.isNotBlank(value)) {
|
||||
return value;
|
||||
}
|
||||
return OffsetDateTime.now().format(DateTimeFormatter.ISO_OFFSET_DATE_TIME);
|
||||
}
|
||||
|
||||
private String buildUrl(String baseUrl, String uri) {
|
||||
String base = baseUrl == null ? "" : baseUrl;
|
||||
while (base.endsWith("/")) {
|
||||
base = base.substring(0, base.length() - 1);
|
||||
}
|
||||
String path = uri.startsWith("/") ? uri : "/" + uri;
|
||||
return base + path;
|
||||
}
|
||||
|
||||
private String render(String template, Map<String, Object> vars) {
|
||||
if (template == null || vars == null) {
|
||||
return template;
|
||||
}
|
||||
String result = template;
|
||||
for (Map.Entry<String, Object> entry : vars.entrySet()) {
|
||||
String value = String.valueOf(entry.getValue());
|
||||
result = result.replace("{" + entry.getKey() + "}", value);
|
||||
result = result.replace("${" + entry.getKey() + "}", value);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private String appendQuery(String url, Map<String, Object> query) {
|
||||
StringBuilder builder = new StringBuilder(url);
|
||||
builder.append(url.contains("?") ? "&" : "?");
|
||||
boolean first = true;
|
||||
for (Map.Entry<String, Object> entry : query.entrySet()) {
|
||||
if (!first) {
|
||||
builder.append("&");
|
||||
}
|
||||
builder.append(encode(entry.getKey())).append("=").append(encode(String.valueOf(entry.getValue())));
|
||||
first = false;
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
private String encode(String value) {
|
||||
try {
|
||||
return URLEncoder.encode(value, "UTF-8");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new ServiceException("URL参数编码失败");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,20 +0,0 @@
|
||||
package com.fastbee.iot.service.integration;
|
||||
|
||||
import com.alibaba.fastjson2.JSONArray;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public interface IDcpOpenApiService {
|
||||
|
||||
JSONObject createToken(Map<String, String> form);
|
||||
|
||||
JSONObject getUser(String authorization);
|
||||
|
||||
JSONArray getProjects(String authorization, String userId);
|
||||
|
||||
JSONArray getStressSensors(String authorization, String projectId);
|
||||
|
||||
JSONObject getDataset(String authorization, String startTime, String endTime, Boolean original, List<String> deviceIds);
|
||||
}
|
||||
@ -1,51 +0,0 @@
|
||||
package com.fastbee.iot.service.integration;
|
||||
|
||||
import com.fastbee.iot.domain.integration.IntegrationPlatform;
|
||||
import com.fastbee.iot.domain.integration.IntegrationApi;
|
||||
import com.fastbee.iot.domain.integration.IntegrationDeviceMapping;
|
||||
import com.fastbee.iot.domain.integration.IntegrationLog;
|
||||
import com.fastbee.iot.model.integration.IntegrationSyncRequest;
|
||||
import com.fastbee.iot.model.integration.IntegrationSyncResult;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface IIntegrationPlatformService {
|
||||
|
||||
IntegrationPlatform selectPlatformByCode(String platformCode);
|
||||
|
||||
IntegrationPlatform selectPlatformById(Long id);
|
||||
|
||||
List<IntegrationPlatform> selectPlatformList(IntegrationPlatform query);
|
||||
|
||||
int insertPlatform(IntegrationPlatform platform);
|
||||
|
||||
int updatePlatform(IntegrationPlatform platform);
|
||||
|
||||
int deletePlatformByIds(Long[] ids);
|
||||
|
||||
List<IntegrationApi> selectApiList(IntegrationApi query);
|
||||
|
||||
IntegrationApi selectApiById(Long id);
|
||||
|
||||
int insertApi(IntegrationApi api);
|
||||
|
||||
int updateApi(IntegrationApi api);
|
||||
|
||||
int deleteApiByIds(Long[] ids);
|
||||
|
||||
List<IntegrationDeviceMapping> selectDeviceMappingList(IntegrationDeviceMapping query);
|
||||
|
||||
IntegrationDeviceMapping selectDeviceMappingById(Long id);
|
||||
|
||||
int insertDeviceMapping(IntegrationDeviceMapping mapping);
|
||||
|
||||
int updateDeviceMapping(IntegrationDeviceMapping mapping);
|
||||
|
||||
int deleteDeviceMappingByIds(Long[] ids);
|
||||
|
||||
List<IntegrationLog> selectLogList(IntegrationLog query);
|
||||
|
||||
IntegrationSyncResult sync(IntegrationSyncRequest request);
|
||||
|
||||
IntegrationSyncResult selfTest(String platformCode);
|
||||
}
|
||||
@ -1,14 +0,0 @@
|
||||
package com.fastbee.iot.service.integration;
|
||||
|
||||
import com.fastbee.iot.domain.integration.IntegrationPlatform;
|
||||
import com.fastbee.iot.model.integration.IntegrationSyncRequest;
|
||||
import com.fastbee.iot.model.integration.IntegrationSyncResult;
|
||||
|
||||
public interface PlatformAdapter {
|
||||
|
||||
String platformCode();
|
||||
|
||||
IntegrationSyncResult sync(IntegrationPlatform platform, IntegrationSyncRequest request);
|
||||
|
||||
IntegrationSyncResult selfTest(IntegrationPlatform platform);
|
||||
}
|
||||
@ -238,3 +238,332 @@ CREATE TABLE IF NOT EXISTS `platform_push_log` (
|
||||
-- 注意:platform_id 需在创建 DCP 平台实例后更新,此处用占位符 0
|
||||
-- 实际由 DcpPlatformAdapter 在初始化时写入
|
||||
|
||||
-- 平台对接另外一套方案
|
||||
-- fastbee.iot_platform_api definition
|
||||
|
||||
CREATE TABLE `iot_platform_api` (
|
||||
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
|
||||
`template_id` bigint NOT NULL COMMENT '平台模板ID',
|
||||
`api_code` varchar(64) NOT NULL COMMENT '接口编码',
|
||||
`api_name` varchar(128) NOT NULL COMMENT '接口名称',
|
||||
`api_type` varchar(32) NOT NULL COMMENT '接口类型',
|
||||
`method` varchar(16) DEFAULT NULL COMMENT '请求方法',
|
||||
`path_template` varchar(512) DEFAULT NULL COMMENT '路径模板',
|
||||
`content_type` varchar(64) DEFAULT NULL COMMENT '内容类型',
|
||||
`header_template` json DEFAULT NULL COMMENT 'Header模板',
|
||||
`query_template` json DEFAULT NULL COMMENT 'Query模板',
|
||||
`body_template` json DEFAULT NULL COMMENT 'Body模板',
|
||||
`auth_config` json DEFAULT NULL COMMENT '接口认证配置',
|
||||
`idempotency_config` json DEFAULT NULL COMMENT '幂等配置',
|
||||
`success_condition` json DEFAULT NULL COMMENT '成功条件',
|
||||
`response_mapping` json DEFAULT NULL COMMENT '响应映射',
|
||||
`retry_policy` json DEFAULT NULL COMMENT '重试策略',
|
||||
`timeout_ms` int DEFAULT NULL COMMENT '超时时间毫秒',
|
||||
`status` tinyint(1) DEFAULT '1' COMMENT '状态(0停用 1启用)',
|
||||
`create_by` varchar(64) DEFAULT '' COMMENT '创建者',
|
||||
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
`update_by` varchar(64) DEFAULT '' COMMENT '更新者',
|
||||
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
|
||||
`remark` varchar(500) DEFAULT NULL COMMENT '备注',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_template_api_code` (`template_id`,`api_code`),
|
||||
KEY `idx_template_api_type` (`template_id`,`api_type`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='平台对接-接口定义';
|
||||
|
||||
|
||||
-- fastbee.iot_platform_api_field definition
|
||||
|
||||
CREATE TABLE `iot_platform_api_field` (
|
||||
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
|
||||
`api_id` bigint NOT NULL COMMENT '接口ID',
|
||||
`direction` varchar(16) NOT NULL COMMENT '方向(REQUEST RESPONSE)',
|
||||
`field_path` varchar(256) NOT NULL COMMENT '字段路径',
|
||||
`field_name` varchar(128) DEFAULT NULL COMMENT '字段名称',
|
||||
`data_type` varchar(32) DEFAULT NULL COMMENT '数据类型',
|
||||
`required` tinyint(1) DEFAULT '0' COMMENT '是否必填',
|
||||
`default_value` varchar(512) DEFAULT NULL COMMENT '默认值',
|
||||
`example_value` varchar(512) DEFAULT NULL COMMENT '示例值',
|
||||
`description` varchar(500) DEFAULT NULL COMMENT '说明',
|
||||
`sort_order` int DEFAULT '0' COMMENT '排序',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_api_direction` (`api_id`,`direction`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='平台对接-接口字段';
|
||||
|
||||
|
||||
-- fastbee.iot_platform_binding definition
|
||||
|
||||
CREATE TABLE `iot_platform_binding` (
|
||||
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
|
||||
`tenant_id` bigint NOT NULL COMMENT '租户ID',
|
||||
`tenant_channel_id` bigint NOT NULL COMMENT '租户平台实例ID',
|
||||
`flow_id` bigint NOT NULL COMMENT '平台流程ID',
|
||||
`product_id` bigint DEFAULT NULL COMMENT '产品ID',
|
||||
`product_name` varchar(128) DEFAULT NULL COMMENT '产品名称',
|
||||
`device_id` bigint DEFAULT NULL COMMENT 'FastBee设备ID',
|
||||
`device_name` varchar(128) DEFAULT NULL COMMENT 'FastBee设备名称',
|
||||
`serial_number` varchar(64) NOT NULL COMMENT 'FastBee设备编号',
|
||||
`external_user_id` varchar(128) DEFAULT NULL COMMENT '绑定级第三方用户ID',
|
||||
`external_project_id` varchar(128) DEFAULT NULL COMMENT '绑定级第三方项目ID',
|
||||
`external_device_type` varchar(32) DEFAULT NULL COMMENT '第三方设备类型',
|
||||
`binding_name` varchar(128) DEFAULT NULL COMMENT '绑定名称',
|
||||
`exchange_mode` varchar(32) NOT NULL COMMENT '交换模式',
|
||||
`config_json` json DEFAULT NULL COMMENT '绑定配置',
|
||||
`last_success_time` datetime DEFAULT NULL COMMENT '最近成功时间',
|
||||
`last_success_value` varchar(128) DEFAULT NULL COMMENT '最近成功值',
|
||||
`status` tinyint(1) DEFAULT '1' COMMENT '状态(0停用 1启用)',
|
||||
`del_flag` char(1) DEFAULT '0' COMMENT '删除标志(0代表存在 2代表删除)',
|
||||
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_binding` (`tenant_channel_id`,`flow_id`,`serial_number`,`del_flag`),
|
||||
KEY `idx_binding_device` (`tenant_id`,`product_id`,`serial_number`),
|
||||
KEY `idx_binding_channel_flow` (`tenant_channel_id`,`flow_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='平台对接-设备绑定';
|
||||
|
||||
|
||||
-- fastbee.iot_platform_exchange_attempt definition
|
||||
|
||||
CREATE TABLE `iot_platform_exchange_attempt` (
|
||||
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
|
||||
`tenant_id` bigint NOT NULL COMMENT '租户ID',
|
||||
`record_id` bigint NOT NULL COMMENT '交换记录ID',
|
||||
`attempt_no` int NOT NULL COMMENT '尝试次数',
|
||||
`direction` varchar(32) NOT NULL COMMENT '方向',
|
||||
`request_url` varchar(1024) DEFAULT NULL COMMENT '请求地址或接收入口',
|
||||
`request_headers` json DEFAULT NULL COMMENT '请求头',
|
||||
`request_payload` json DEFAULT NULL COMMENT '请求体',
|
||||
`response_status` int DEFAULT NULL COMMENT '响应状态码',
|
||||
`response_body` mediumtext COMMENT '响应内容',
|
||||
`success` tinyint(1) DEFAULT '0' COMMENT '是否成功',
|
||||
`error_msg` varchar(1000) DEFAULT NULL COMMENT '错误信息',
|
||||
`duration_ms` int DEFAULT NULL COMMENT '耗时毫秒',
|
||||
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_attempt_record` (`record_id`,`attempt_no`),
|
||||
KEY `idx_attempt_tenant` (`tenant_id`,`create_time`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='平台对接-数据交换尝试日志';
|
||||
|
||||
|
||||
-- fastbee.iot_platform_exchange_record definition
|
||||
|
||||
CREATE TABLE `iot_platform_exchange_record` (
|
||||
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
|
||||
`tenant_id` bigint NOT NULL COMMENT '租户ID',
|
||||
`tenant_channel_id` bigint NOT NULL COMMENT '租户平台实例ID',
|
||||
`flow_id` bigint NOT NULL COMMENT '流程ID',
|
||||
`binding_id` bigint DEFAULT NULL COMMENT '绑定ID',
|
||||
`task_id` bigint DEFAULT NULL COMMENT '任务ID',
|
||||
`direction` varchar(32) NOT NULL COMMENT '方向',
|
||||
`source_type` varchar(32) DEFAULT NULL COMMENT '来源类型',
|
||||
`sink_type` varchar(32) DEFAULT NULL COMMENT '落点类型',
|
||||
`source_device_id` bigint DEFAULT NULL COMMENT 'FastBee设备ID',
|
||||
`serial_number` varchar(64) DEFAULT NULL COMMENT '设备编号',
|
||||
`external_message_id` varchar(128) DEFAULT NULL COMMENT '第三方消息ID',
|
||||
`source_ref_id` varchar(128) DEFAULT NULL COMMENT '来源ID',
|
||||
`source_time` datetime DEFAULT NULL COMMENT '数据时间',
|
||||
`time_window_start` datetime DEFAULT NULL COMMENT '窗口开始',
|
||||
`time_window_end` datetime DEFAULT NULL COMMENT '窗口结束',
|
||||
`raw_payload` json DEFAULT NULL COMMENT '原始输入',
|
||||
`standard_payload` json DEFAULT NULL COMMENT '标准消息',
|
||||
`request_payload` json DEFAULT NULL COMMENT '请求载荷',
|
||||
`response_payload` json DEFAULT NULL COMMENT '响应载荷',
|
||||
`payload_hash` varchar(64) DEFAULT NULL COMMENT 'payload哈希',
|
||||
`idempotency_key` varchar(128) NOT NULL COMMENT '幂等键',
|
||||
`status` varchar(32) NOT NULL DEFAULT 'PENDING' COMMENT '状态',
|
||||
`retry_count` int DEFAULT '0' COMMENT '重试次数',
|
||||
`max_retry` int DEFAULT '3' COMMENT '最大重试次数',
|
||||
`next_retry_time` datetime DEFAULT NULL COMMENT '下次重试时间',
|
||||
`last_error` varchar(1000) DEFAULT NULL COMMENT '最近错误',
|
||||
`locked_by` varchar(64) DEFAULT NULL COMMENT 'worker锁',
|
||||
`locked_time` datetime DEFAULT NULL COMMENT '锁定时间',
|
||||
`success_time` datetime DEFAULT NULL COMMENT '成功时间',
|
||||
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_idempotency` (`idempotency_key`),
|
||||
KEY `idx_record_poll` (`status`,`next_retry_time`),
|
||||
KEY `idx_record_direction` (`tenant_channel_id`,`direction`,`source_time`),
|
||||
KEY `idx_record_device` (`tenant_channel_id`,`serial_number`,`source_time`),
|
||||
KEY `idx_record_binding` (`binding_id`,`source_time`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='平台对接-数据交换记录';
|
||||
|
||||
|
||||
-- fastbee.iot_platform_exchange_task definition
|
||||
|
||||
CREATE TABLE `iot_platform_exchange_task` (
|
||||
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
|
||||
`tenant_id` bigint NOT NULL COMMENT '租户ID',
|
||||
`tenant_channel_id` bigint NOT NULL COMMENT '租户平台实例ID',
|
||||
`flow_id` bigint NOT NULL COMMENT '流程ID',
|
||||
`task_name` varchar(128) NOT NULL COMMENT '任务名称',
|
||||
`task_type` varchar(32) NOT NULL COMMENT '任务类型',
|
||||
`cron_expression` varchar(128) DEFAULT NULL COMMENT 'Cron表达式',
|
||||
`window_type` varchar(32) DEFAULT NULL COMMENT '窗口类型',
|
||||
`window_config` json DEFAULT NULL COMMENT '窗口配置',
|
||||
`cursor_json` json DEFAULT NULL COMMENT '拉取游标',
|
||||
`sink_type` varchar(32) DEFAULT NULL COMMENT '入站数据落点',
|
||||
`batch_size` int DEFAULT '100' COMMENT '批次大小',
|
||||
`max_retry` int DEFAULT '3' COMMENT '最大重试次数',
|
||||
`status` tinyint(1) DEFAULT '1' COMMENT '状态(0停用 1启用)',
|
||||
`last_run_time` datetime DEFAULT NULL COMMENT '最近执行时间',
|
||||
`next_run_time` datetime DEFAULT NULL COMMENT '下次执行时间',
|
||||
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_task_channel_type` (`tenant_channel_id`,`task_type`),
|
||||
KEY `idx_task_next_run` (`status`,`next_run_time`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='平台对接-数据交换任务';
|
||||
|
||||
|
||||
-- fastbee.iot_platform_field_mapping definition
|
||||
|
||||
CREATE TABLE `iot_platform_field_mapping` (
|
||||
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
|
||||
`tenant_id` bigint NOT NULL COMMENT '租户ID',
|
||||
`binding_id` bigint NOT NULL COMMENT '绑定ID',
|
||||
`direction` varchar(32) NOT NULL COMMENT '方向',
|
||||
`target_path` varchar(256) NOT NULL COMMENT '目标字段路径',
|
||||
`target_name` varchar(128) DEFAULT NULL COMMENT '目标字段名称',
|
||||
`source_type` varchar(32) NOT NULL COMMENT '来源类型',
|
||||
`source_key` varchar(256) DEFAULT NULL COMMENT '来源键',
|
||||
`source_name` varchar(128) DEFAULT NULL COMMENT '来源字段名称',
|
||||
`transform_type` varchar(32) DEFAULT 'DIRECT' COMMENT '转换类型',
|
||||
`transform_config` json DEFAULT NULL COMMENT '转换配置',
|
||||
`default_value` varchar(512) DEFAULT NULL COMMENT '默认值',
|
||||
`required` tinyint(1) DEFAULT '0' COMMENT '是否必填',
|
||||
`sort_order` int DEFAULT '0' COMMENT '排序',
|
||||
`status` tinyint(1) DEFAULT '1' COMMENT '状态(0停用 1启用)',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_mapping_binding` (`binding_id`,`direction`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='平台对接-字段映射';
|
||||
|
||||
|
||||
-- fastbee.iot_platform_flow definition
|
||||
|
||||
CREATE TABLE `iot_platform_flow` (
|
||||
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
|
||||
`template_id` bigint NOT NULL COMMENT '平台模板ID',
|
||||
`flow_code` varchar(64) NOT NULL COMMENT '流程编码',
|
||||
`flow_name` varchar(128) NOT NULL COMMENT '流程名称',
|
||||
`flow_type` varchar(32) NOT NULL COMMENT '流程类型',
|
||||
`adapter_code` varchar(64) DEFAULT NULL COMMENT '适配器编码',
|
||||
`sink_type` varchar(32) DEFAULT NULL COMMENT '入站数据落点',
|
||||
`status` tinyint(1) DEFAULT '1' COMMENT '状态(0停用 1启用)',
|
||||
`create_by` varchar(64) DEFAULT '' COMMENT '创建者',
|
||||
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
`update_by` varchar(64) DEFAULT '' COMMENT '更新者',
|
||||
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
|
||||
`remark` varchar(500) DEFAULT NULL COMMENT '备注',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_template_flow_code` (`template_id`,`flow_code`),
|
||||
KEY `idx_template_flow_type` (`template_id`,`flow_type`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='平台对接-流程模板';
|
||||
|
||||
|
||||
-- fastbee.iot_platform_flow_step definition
|
||||
|
||||
CREATE TABLE `iot_platform_flow_step` (
|
||||
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
|
||||
`flow_id` bigint NOT NULL COMMENT '流程ID',
|
||||
`step_code` varchar(64) NOT NULL COMMENT '步骤编码',
|
||||
`step_name` varchar(128) NOT NULL COMMENT '步骤名称',
|
||||
`step_type` varchar(32) NOT NULL COMMENT '步骤类型',
|
||||
`api_id` bigint DEFAULT NULL COMMENT '接口ID',
|
||||
`adapter_method` varchar(128) DEFAULT NULL COMMENT '适配器方法',
|
||||
`input_mapping` json DEFAULT NULL COMMENT '入参映射',
|
||||
`output_mapping` json DEFAULT NULL COMMENT '输出映射',
|
||||
`condition_expr` varchar(512) DEFAULT NULL COMMENT '执行条件',
|
||||
`on_fail` varchar(32) DEFAULT 'STOP' COMMENT '失败策略',
|
||||
`sort_order` int DEFAULT '0' COMMENT '排序',
|
||||
`status` tinyint(1) DEFAULT '1' COMMENT '状态(0停用 1启用)',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_flow_sort` (`flow_id`,`sort_order`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='平台对接-流程步骤';
|
||||
|
||||
|
||||
-- fastbee.iot_platform_resource_mapping definition
|
||||
|
||||
CREATE TABLE `iot_platform_resource_mapping` (
|
||||
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
|
||||
`tenant_id` bigint NOT NULL COMMENT '租户ID',
|
||||
`tenant_channel_id` bigint NOT NULL COMMENT '租户平台实例ID',
|
||||
`binding_id` bigint DEFAULT NULL COMMENT '绑定ID',
|
||||
`resource_scope` varchar(32) NOT NULL COMMENT '资源范围',
|
||||
`resource_type` varchar(64) NOT NULL COMMENT '资源类型',
|
||||
`local_key` varchar(128) NOT NULL COMMENT '本地唯一键',
|
||||
`external_id` varchar(128) DEFAULT NULL COMMENT '外部资源ID',
|
||||
`external_code` varchar(128) DEFAULT NULL COMMENT '外部资源编码',
|
||||
`external_name` varchar(128) DEFAULT NULL COMMENT '外部资源名称',
|
||||
`resource_payload` json DEFAULT NULL COMMENT '外部资源详情',
|
||||
`status` tinyint(1) DEFAULT '1' COMMENT '状态(0失效 1有效)',
|
||||
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_resource` (`tenant_channel_id`,`binding_id`,`resource_type`,`local_key`),
|
||||
KEY `idx_resource_tenant_type` (`tenant_id`,`tenant_channel_id`,`resource_type`),
|
||||
KEY `idx_external_id` (`tenant_channel_id`,`resource_type`,`external_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='平台对接-资源映射';
|
||||
|
||||
|
||||
-- fastbee.iot_platform_task_binding definition
|
||||
|
||||
CREATE TABLE `iot_platform_task_binding` (
|
||||
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
|
||||
`task_id` bigint NOT NULL COMMENT '任务ID',
|
||||
`binding_id` bigint NOT NULL COMMENT '绑定ID',
|
||||
`status` tinyint(1) DEFAULT '1' COMMENT '状态(0停用 1启用)',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_task_binding` (`task_id`,`binding_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='平台对接-任务绑定';
|
||||
|
||||
|
||||
-- fastbee.iot_platform_template definition
|
||||
|
||||
CREATE TABLE `iot_platform_template` (
|
||||
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
|
||||
`platform_code` varchar(64) NOT NULL COMMENT '平台编码',
|
||||
`platform_name` varchar(128) NOT NULL COMMENT '平台名称',
|
||||
`platform_type` varchar(32) NOT NULL COMMENT '平台类型',
|
||||
`adapter_code` varchar(64) DEFAULT NULL COMMENT '适配器编码',
|
||||
`base_url_template` varchar(512) DEFAULT NULL COMMENT '默认基础地址模板',
|
||||
`auth_type` varchar(32) DEFAULT NULL COMMENT '认证类型',
|
||||
`auth_schema` json DEFAULT NULL COMMENT '授权配置字段定义',
|
||||
`request_config` json DEFAULT NULL COMMENT '默认请求配置',
|
||||
`status` tinyint(1) DEFAULT '1' COMMENT '状态(0停用 1启用)',
|
||||
`create_by` varchar(64) DEFAULT '' COMMENT '创建者',
|
||||
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
`update_by` varchar(64) DEFAULT '' COMMENT '更新者',
|
||||
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
|
||||
`remark` varchar(500) DEFAULT NULL COMMENT '备注',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_platform_code` (`platform_code`),
|
||||
KEY `idx_platform_type` (`platform_type`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='平台对接-平台模板';
|
||||
|
||||
|
||||
-- fastbee.iot_platform_tenant_channel definition
|
||||
|
||||
CREATE TABLE `iot_platform_tenant_channel` (
|
||||
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
|
||||
`tenant_id` bigint NOT NULL COMMENT '租户ID',
|
||||
`tenant_name` varchar(64) DEFAULT '' COMMENT '租户名称',
|
||||
`template_id` bigint NOT NULL COMMENT '平台模板ID',
|
||||
`channel_code` varchar(64) NOT NULL COMMENT '租户平台实例编码',
|
||||
`channel_name` varchar(128) NOT NULL COMMENT '租户平台实例名称',
|
||||
`base_url` varchar(512) DEFAULT NULL COMMENT '实际基础地址',
|
||||
`auth_config` json DEFAULT NULL COMMENT '租户授权配置',
|
||||
`receive_config` json DEFAULT NULL COMMENT '接收安全配置',
|
||||
`default_user_id` varchar(128) DEFAULT NULL COMMENT '默认第三方用户ID',
|
||||
`default_project_id` varchar(128) DEFAULT NULL COMMENT '默认第三方项目ID',
|
||||
`config_json` json DEFAULT NULL COMMENT '扩展配置',
|
||||
`status` tinyint(1) DEFAULT '1' COMMENT '状态(0停用 1启用)',
|
||||
`del_flag` char(1) DEFAULT '0' COMMENT '删除标志(0代表存在 2代表删除)',
|
||||
`create_by` varchar(64) DEFAULT '' COMMENT '创建者',
|
||||
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
`update_by` varchar(64) DEFAULT '' COMMENT '更新者',
|
||||
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
|
||||
`remark` varchar(500) DEFAULT NULL COMMENT '备注',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_tenant_channel_code` (`tenant_id`,`channel_code`,`del_flag`),
|
||||
KEY `idx_tenant_template` (`tenant_id`,`template_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='平台对接-租户平台实例';
|
||||
@ -1,138 +0,0 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function listPlatform(query) {
|
||||
return request({
|
||||
url: '/iot/integration/platform/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
export function getPlatform(id) {
|
||||
return request({
|
||||
url: '/iot/integration/platform/' + id,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
export function addPlatform(data) {
|
||||
return request({
|
||||
url: '/iot/integration/platform',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
export function updatePlatform(data) {
|
||||
return request({
|
||||
url: '/iot/integration/platform',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
export function delPlatform(id) {
|
||||
return request({
|
||||
url: '/iot/integration/platform/' + id,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
export function listIntegrationApi(query) {
|
||||
return request({
|
||||
url: '/iot/integration/api/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
export function getIntegrationApi(id) {
|
||||
return request({
|
||||
url: '/iot/integration/api/' + id,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
export function addIntegrationApi(data) {
|
||||
return request({
|
||||
url: '/iot/integration/api',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
export function updateIntegrationApi(data) {
|
||||
return request({
|
||||
url: '/iot/integration/api',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
export function delIntegrationApi(id) {
|
||||
return request({
|
||||
url: '/iot/integration/api/' + id,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
export function listDeviceMapping(query) {
|
||||
return request({
|
||||
url: '/iot/integration/device-mapping/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
export function getDeviceMapping(id) {
|
||||
return request({
|
||||
url: '/iot/integration/device-mapping/' + id,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
export function addDeviceMapping(data) {
|
||||
return request({
|
||||
url: '/iot/integration/device-mapping',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
export function updateDeviceMapping(data) {
|
||||
return request({
|
||||
url: '/iot/integration/device-mapping',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
export function delDeviceMapping(id) {
|
||||
return request({
|
||||
url: '/iot/integration/device-mapping/' + id,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
export function listIntegrationLog(query) {
|
||||
return request({
|
||||
url: '/iot/integration/log/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
export function syncIntegration(data) {
|
||||
return request({
|
||||
url: '/iot/integration/sync',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
export function selfTestIntegration(platformCode) {
|
||||
return request({
|
||||
url: '/iot/integration/self-test/' + platformCode,
|
||||
method: 'post'
|
||||
})
|
||||
}
|
||||
@ -1,808 +0,0 @@
|
||||
<template>
|
||||
<div class="app-container integration-page">
|
||||
<el-form ref="queryForm" :model="queryParams" :inline="true" label-width="80px">
|
||||
<el-form-item label="平台编码" prop="platformCode">
|
||||
<el-input
|
||||
v-model="queryParams.platformCode"
|
||||
placeholder="请输入平台编码"
|
||||
clearable
|
||||
size="small"
|
||||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="平台名称" prop="platformName">
|
||||
<el-input
|
||||
v-model="queryParams.platformName"
|
||||
placeholder="请输入平台名称"
|
||||
clearable
|
||||
size="small"
|
||||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="状态" prop="status">
|
||||
<el-select v-model="queryParams.status" placeholder="全部" clearable size="small">
|
||||
<el-option label="启用" :value="1" />
|
||||
<el-option label="停用" :value="0" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
<el-button type="primary" plain icon="el-icon-plus" size="mini" v-hasPermi="['iot:integration:add']" @click="handleAddPlatform">新增平台</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button type="success" plain icon="el-icon-edit" size="mini" :disabled="single" v-hasPermi="['iot:integration:edit']" @click="handleUpdatePlatform">修改平台</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button type="danger" plain icon="el-icon-delete" size="mini" :disabled="multiple" v-hasPermi="['iot:integration:remove']" @click="handleDeletePlatform">删除平台</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button type="warning" plain icon="el-icon-video-play" size="mini" :disabled="!currentPlatform" v-hasPermi="['iot:integration:sync']" @click="openSyncDialog(false)">同步</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button plain icon="el-icon-check" size="mini" :disabled="!currentPlatform" v-hasPermi="['iot:integration:sync']" @click="handleSelfTest">自测</el-button>
|
||||
</el-col>
|
||||
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList" />
|
||||
</el-row>
|
||||
|
||||
<el-table
|
||||
v-loading="loading"
|
||||
:data="platformList"
|
||||
highlight-current-row
|
||||
@selection-change="handleSelectionChange"
|
||||
@current-change="handleCurrentPlatformChange"
|
||||
@row-click="selectPlatform"
|
||||
>
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<el-table-column label="平台编码" align="center" prop="platformCode" width="120" />
|
||||
<el-table-column label="平台名称" align="center" prop="platformName" min-width="160" />
|
||||
<el-table-column label="基础地址" align="center" prop="baseUrl" min-width="240" show-overflow-tooltip />
|
||||
<el-table-column label="认证类型" align="center" prop="authType" width="140" />
|
||||
<el-table-column label="状态" align="center" width="90">
|
||||
<template slot-scope="scope">
|
||||
<el-tag :type="scope.row.status === 1 ? 'success' : 'info'">{{ scope.row.status === 1 ? '启用' : '停用' }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="创建时间" align="center" prop="createTime" width="160" />
|
||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="210">
|
||||
<template slot-scope="scope">
|
||||
<el-button size="mini" type="text" icon="el-icon-edit" v-hasPermi="['iot:integration:edit']" @click.stop="handleUpdatePlatform(scope.row)">修改</el-button>
|
||||
<el-button size="mini" type="text" icon="el-icon-refresh" v-hasPermi="['iot:integration:sync']" @click.stop="openSyncDialog(false, scope.row)">同步</el-button>
|
||||
<el-button size="mini" type="text" icon="el-icon-delete" v-hasPermi="['iot:integration:remove']" @click.stop="handleDeletePlatform(scope.row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<pagination
|
||||
v-show="total > 0"
|
||||
:total="total"
|
||||
:page.sync="queryParams.pageNum"
|
||||
:limit.sync="queryParams.pageSize"
|
||||
@pagination="getList"
|
||||
/>
|
||||
|
||||
<div v-if="currentPlatform" class="integration-detail">
|
||||
<div class="detail-header">
|
||||
<span class="detail-title">{{ currentPlatform.platformName }}</span>
|
||||
<span class="detail-subtitle">{{ currentPlatform.platformCode }}</span>
|
||||
</div>
|
||||
<el-tabs v-model="activeTab" @tab-click="handleTabClick">
|
||||
<el-tab-pane label="接口定义" name="api">
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
<el-button type="primary" plain icon="el-icon-plus" size="mini" v-hasPermi="['iot:integration:add']" @click="handleAddApi">新增接口</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button type="success" plain icon="el-icon-edit" size="mini" :disabled="apiSingle" v-hasPermi="['iot:integration:edit']" @click="handleUpdateApi">修改接口</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button type="danger" plain icon="el-icon-delete" size="mini" :disabled="apiMultiple" v-hasPermi="['iot:integration:remove']" @click="handleDeleteApi">删除接口</el-button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-table v-loading="apiLoading" :data="apiList" @selection-change="handleApiSelectionChange">
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<el-table-column label="编码" align="center" prop="apiCode" min-width="160" />
|
||||
<el-table-column label="名称" align="center" prop="apiName" min-width="160" />
|
||||
<el-table-column label="方法" align="center" prop="method" width="90" />
|
||||
<el-table-column label="URI" align="center" prop="uri" min-width="260" show-overflow-tooltip />
|
||||
<el-table-column label="依赖" align="center" prop="dependsOn" width="150" />
|
||||
<el-table-column label="排序" align="center" prop="sortOrder" width="80" />
|
||||
<el-table-column label="状态" align="center" width="90">
|
||||
<template slot-scope="scope">
|
||||
<el-tag :type="scope.row.status === 1 ? 'success' : 'info'">{{ scope.row.status === 1 ? '启用' : '停用' }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center" width="150">
|
||||
<template slot-scope="scope">
|
||||
<el-button size="mini" type="text" icon="el-icon-edit" v-hasPermi="['iot:integration:edit']" @click="handleUpdateApi(scope.row)">修改</el-button>
|
||||
<el-button size="mini" type="text" icon="el-icon-delete" v-hasPermi="['iot:integration:remove']" @click="handleDeleteApi(scope.row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-tab-pane>
|
||||
|
||||
<el-tab-pane label="设备映射" name="mapping">
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
<el-button type="primary" plain icon="el-icon-plus" size="mini" v-hasPermi="['iot:integration:add']" @click="handleAddMapping">新增映射</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button type="success" plain icon="el-icon-edit" size="mini" :disabled="mappingSingle" v-hasPermi="['iot:integration:edit']" @click="handleUpdateMapping">修改映射</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button type="danger" plain icon="el-icon-delete" size="mini" :disabled="mappingMultiple" v-hasPermi="['iot:integration:remove']" @click="handleDeleteMapping">删除映射</el-button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-table v-loading="mappingLoading" :data="mappingList" @selection-change="handleMappingSelectionChange">
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<el-table-column label="第三方设备ID" align="center" prop="externalDeviceId" min-width="170" show-overflow-tooltip />
|
||||
<el-table-column label="第三方设备名称" align="center" prop="externalDeviceName" min-width="160" show-overflow-tooltip />
|
||||
<el-table-column label="产品ID" align="center" prop="productId" width="100" />
|
||||
<el-table-column label="设备编号" align="center" prop="serialNumber" min-width="160" show-overflow-tooltip />
|
||||
<el-table-column label="指标映射" align="center" prop="identifierMappingJson" min-width="220" show-overflow-tooltip />
|
||||
<el-table-column label="状态" align="center" width="90">
|
||||
<template slot-scope="scope">
|
||||
<el-tag :type="scope.row.status === 1 ? 'success' : 'info'">{{ scope.row.status === 1 ? '启用' : '停用' }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center" width="150">
|
||||
<template slot-scope="scope">
|
||||
<el-button size="mini" type="text" icon="el-icon-edit" v-hasPermi="['iot:integration:edit']" @click="handleUpdateMapping(scope.row)">修改</el-button>
|
||||
<el-button size="mini" type="text" icon="el-icon-delete" v-hasPermi="['iot:integration:remove']" @click="handleDeleteMapping(scope.row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-tab-pane>
|
||||
|
||||
<el-tab-pane label="同步日志" name="log">
|
||||
<el-table v-loading="logLoading" :data="logList">
|
||||
<el-table-column label="请求ID" align="center" prop="requestId" min-width="180" show-overflow-tooltip />
|
||||
<el-table-column label="流程" align="center" prop="flowCode" width="140" />
|
||||
<el-table-column label="开始时间" align="center" prop="startTime" width="160" />
|
||||
<el-table-column label="结束时间" align="center" prop="endTime" width="160" />
|
||||
<el-table-column label="状态" align="center" width="90">
|
||||
<template slot-scope="scope">
|
||||
<el-tag :type="logStatusTag(scope.row.status)">{{ logStatusText(scope.row.status) }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="成功" align="center" prop="successCount" width="80" />
|
||||
<el-table-column label="失败" align="center" prop="failCount" width="80" />
|
||||
<el-table-column label="错误信息" align="center" prop="errorMsg" min-width="220" show-overflow-tooltip />
|
||||
</el-table>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
|
||||
<el-dialog :title="platformTitle" :visible.sync="platformOpen" width="760px" append-to-body>
|
||||
<el-form ref="platformForm" :model="platformForm" :rules="platformRules" label-width="110px">
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="平台编码" prop="platformCode">
|
||||
<el-input v-model="platformForm.platformCode" placeholder="如 DCP" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="平台名称" prop="platformName">
|
||||
<el-input v-model="platformForm.platformName" placeholder="请输入平台名称" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-form-item label="基础地址" prop="baseUrl">
|
||||
<el-input v-model="platformForm.baseUrl" placeholder="请输入第三方平台基础地址" />
|
||||
</el-form-item>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="认证类型" prop="authType">
|
||||
<el-input v-model="platformForm.authType" placeholder="如 PASSWORD_TOKEN" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="状态" prop="status">
|
||||
<el-switch v-model="platformForm.status" :active-value="1" :inactive-value="0" active-text="启用" inactive-text="停用" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-form-item label="凭证配置" prop="credentialJson">
|
||||
<el-input v-model="platformForm.credentialJson" type="textarea" :rows="8" placeholder="请输入 JSON 格式凭证配置" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button type="primary" @click="submitPlatformForm">确 定</el-button>
|
||||
<el-button @click="platformOpen = false">取 消</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog :title="apiTitle" :visible.sync="apiOpen" width="820px" append-to-body>
|
||||
<el-form ref="apiForm" :model="apiForm" :rules="apiRules" label-width="110px">
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="接口编码" prop="apiCode">
|
||||
<el-input v-model="apiForm.apiCode" placeholder="如 dcp_token" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="接口名称" prop="apiName">
|
||||
<el-input v-model="apiForm.apiName" placeholder="请输入接口名称" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="请求方法" prop="method">
|
||||
<el-select v-model="apiForm.method" placeholder="方法">
|
||||
<el-option label="GET" value="GET" />
|
||||
<el-option label="POST" value="POST" />
|
||||
<el-option label="PUT" value="PUT" />
|
||||
<el-option label="DELETE" value="DELETE" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="Content-Type" prop="contentType">
|
||||
<el-input v-model="apiForm.contentType" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="排序" prop="sortOrder">
|
||||
<el-input-number v-model="apiForm.sortOrder" :min="0" controls-position="right" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-form-item label="URI" prop="uri">
|
||||
<el-input v-model="apiForm.uri" placeholder="/api/path/{id}" />
|
||||
</el-form-item>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="依赖接口">
|
||||
<el-input v-model="apiForm.dependsOn" placeholder="可为空" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="状态">
|
||||
<el-switch v-model="apiForm.status" :active-value="1" :inactive-value="0" active-text="启用" inactive-text="停用" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-form-item label="返回路径">
|
||||
<el-input v-model="apiForm.responsePath" placeholder="如 data.items" />
|
||||
</el-form-item>
|
||||
<el-row>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="请求头模板">
|
||||
<el-input v-model="apiForm.headersJson" type="textarea" :rows="5" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="Query模板">
|
||||
<el-input v-model="apiForm.queryJson" type="textarea" :rows="5" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="Body模板">
|
||||
<el-input v-model="apiForm.bodyJson" type="textarea" :rows="5" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button type="primary" @click="submitApiForm">确 定</el-button>
|
||||
<el-button @click="apiOpen = false">取 消</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog :title="mappingTitle" :visible.sync="mappingOpen" width="760px" append-to-body>
|
||||
<el-form ref="mappingForm" :model="mappingForm" :rules="mappingRules" label-width="120px">
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="第三方设备ID" prop="externalDeviceId">
|
||||
<el-input v-model="mappingForm.externalDeviceId" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="第三方设备名">
|
||||
<el-input v-model="mappingForm.externalDeviceName" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="产品ID" prop="productId">
|
||||
<el-input-number v-model="mappingForm.productId" :min="1" controls-position="right" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="设备编号" prop="serialNumber">
|
||||
<el-input v-model="mappingForm.serialNumber" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-form-item label="指标映射">
|
||||
<el-input v-model="mappingForm.identifierMappingJson" type="textarea" :rows="6" placeholder='如 {"e":"axialForce","temperature":"temperature"}' />
|
||||
</el-form-item>
|
||||
<el-form-item label="状态">
|
||||
<el-switch v-model="mappingForm.status" :active-value="1" :inactive-value="0" active-text="启用" inactive-text="停用" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button type="primary" @click="submitMappingForm">确 定</el-button>
|
||||
<el-button @click="mappingOpen = false">取 消</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog title="平台数据同步" :visible.sync="syncOpen" width="620px" append-to-body>
|
||||
<el-form ref="syncForm" :model="syncForm" label-width="110px">
|
||||
<el-form-item label="平台编码">
|
||||
<el-input v-model="syncForm.platformCode" disabled />
|
||||
</el-form-item>
|
||||
<el-form-item label="项目ID">
|
||||
<el-input v-model="syncForm.projectId" placeholder="可选,不填则按平台默认拉取" />
|
||||
</el-form-item>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="开始时间">
|
||||
<el-date-picker v-model="syncForm.startTime" type="datetime" value-format="yyyy-MM-dd HH:mm:ss" placeholder="开始时间" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="结束时间">
|
||||
<el-date-picker v-model="syncForm.endTime" type="datetime" value-format="yyyy-MM-dd HH:mm:ss" placeholder="结束时间" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-form-item label="第三方设备ID">
|
||||
<el-input v-model="syncForm.externalDeviceIdsText" type="textarea" :rows="5" placeholder="可选,一行一个设备ID" />
|
||||
</el-form-item>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="原始数据">
|
||||
<el-switch v-model="syncForm.original" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="只预演">
|
||||
<el-switch v-model="syncForm.dryRun" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button type="primary" @click="submitSync">执 行</el-button>
|
||||
<el-button @click="syncOpen = false">取 消</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
addDeviceMapping,
|
||||
addIntegrationApi,
|
||||
addPlatform,
|
||||
delDeviceMapping,
|
||||
delIntegrationApi,
|
||||
delPlatform,
|
||||
getDeviceMapping,
|
||||
getIntegrationApi,
|
||||
getPlatform,
|
||||
listDeviceMapping,
|
||||
listIntegrationApi,
|
||||
listIntegrationLog,
|
||||
listPlatform,
|
||||
selfTestIntegration,
|
||||
syncIntegration,
|
||||
updateDeviceMapping,
|
||||
updateIntegrationApi,
|
||||
updatePlatform
|
||||
} from '@/api/iot/integration'
|
||||
|
||||
export default {
|
||||
name: 'Integration',
|
||||
data() {
|
||||
return {
|
||||
showSearch: true,
|
||||
loading: false,
|
||||
apiLoading: false,
|
||||
mappingLoading: false,
|
||||
logLoading: false,
|
||||
total: 0,
|
||||
platformList: [],
|
||||
apiList: [],
|
||||
mappingList: [],
|
||||
logList: [],
|
||||
ids: [],
|
||||
apiIds: [],
|
||||
mappingIds: [],
|
||||
single: true,
|
||||
multiple: true,
|
||||
apiSingle: true,
|
||||
apiMultiple: true,
|
||||
mappingSingle: true,
|
||||
mappingMultiple: true,
|
||||
currentPlatform: null,
|
||||
activeTab: 'api',
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
platformCode: null,
|
||||
platformName: null,
|
||||
status: null
|
||||
},
|
||||
platformOpen: false,
|
||||
platformTitle: '',
|
||||
platformForm: {},
|
||||
platformRules: {
|
||||
platformCode: [{ required: true, message: '平台编码不能为空', trigger: 'blur' }],
|
||||
platformName: [{ required: true, message: '平台名称不能为空', trigger: 'blur' }],
|
||||
baseUrl: [{ required: true, message: '基础地址不能为空', trigger: 'blur' }]
|
||||
},
|
||||
apiOpen: false,
|
||||
apiTitle: '',
|
||||
apiForm: {},
|
||||
apiRules: {
|
||||
apiCode: [{ required: true, message: '接口编码不能为空', trigger: 'blur' }],
|
||||
apiName: [{ required: true, message: '接口名称不能为空', trigger: 'blur' }],
|
||||
method: [{ required: true, message: '请求方法不能为空', trigger: 'change' }],
|
||||
uri: [{ required: true, message: '接口URI不能为空', trigger: 'blur' }]
|
||||
},
|
||||
mappingOpen: false,
|
||||
mappingTitle: '',
|
||||
mappingForm: {},
|
||||
mappingRules: {
|
||||
externalDeviceId: [{ required: true, message: '第三方设备ID不能为空', trigger: 'blur' }],
|
||||
productId: [{ required: true, message: '产品ID不能为空', trigger: 'blur' }],
|
||||
serialNumber: [{ required: true, message: '设备编号不能为空', trigger: 'blur' }]
|
||||
},
|
||||
syncOpen: false,
|
||||
syncForm: {}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getList()
|
||||
},
|
||||
methods: {
|
||||
getList() {
|
||||
this.loading = true
|
||||
listPlatform(this.queryParams).then(response => {
|
||||
this.platformList = response.rows || []
|
||||
this.total = response.total || 0
|
||||
this.loading = false
|
||||
if (!this.currentPlatform && this.platformList.length > 0) {
|
||||
this.selectPlatform(this.platformList[0])
|
||||
}
|
||||
})
|
||||
},
|
||||
handleQuery() {
|
||||
this.queryParams.pageNum = 1
|
||||
this.currentPlatform = null
|
||||
this.getList()
|
||||
},
|
||||
resetQuery() {
|
||||
this.resetForm('queryForm')
|
||||
this.handleQuery()
|
||||
},
|
||||
handleSelectionChange(selection) {
|
||||
this.ids = selection.map(item => item.id)
|
||||
this.single = selection.length !== 1
|
||||
this.multiple = !selection.length
|
||||
},
|
||||
handleCurrentPlatformChange(row) {
|
||||
if (row) {
|
||||
this.selectPlatform(row)
|
||||
}
|
||||
},
|
||||
selectPlatform(row) {
|
||||
this.currentPlatform = row
|
||||
this.apiIds = []
|
||||
this.mappingIds = []
|
||||
this.apiSingle = true
|
||||
this.apiMultiple = true
|
||||
this.mappingSingle = true
|
||||
this.mappingMultiple = true
|
||||
this.getApiList()
|
||||
this.getMappingList()
|
||||
this.getLogList()
|
||||
},
|
||||
handleTabClick() {
|
||||
if (!this.currentPlatform) {
|
||||
return
|
||||
}
|
||||
if (this.activeTab === 'api') {
|
||||
this.getApiList()
|
||||
} else if (this.activeTab === 'mapping') {
|
||||
this.getMappingList()
|
||||
} else {
|
||||
this.getLogList()
|
||||
}
|
||||
},
|
||||
resetPlatformForm() {
|
||||
this.platformForm = {
|
||||
id: null,
|
||||
platformCode: null,
|
||||
platformName: null,
|
||||
baseUrl: null,
|
||||
authType: 'PASSWORD_TOKEN',
|
||||
credentialJson: '{}',
|
||||
status: 0
|
||||
}
|
||||
this.resetForm('platformForm')
|
||||
},
|
||||
handleAddPlatform() {
|
||||
this.resetPlatformForm()
|
||||
this.platformOpen = true
|
||||
this.platformTitle = '新增接入平台'
|
||||
},
|
||||
handleUpdatePlatform(row) {
|
||||
this.resetPlatformForm()
|
||||
const id = row.id || this.ids
|
||||
getPlatform(id).then(response => {
|
||||
this.platformForm = response.data
|
||||
this.platformOpen = true
|
||||
this.platformTitle = '修改接入平台'
|
||||
})
|
||||
},
|
||||
submitPlatformForm() {
|
||||
this.$refs.platformForm.validate(valid => {
|
||||
if (!valid) {
|
||||
return
|
||||
}
|
||||
const request = this.platformForm.id != null ? updatePlatform(this.platformForm) : addPlatform(this.platformForm)
|
||||
request.then(() => {
|
||||
this.$modal.msgSuccess(this.platformForm.id != null ? '修改成功' : '新增成功')
|
||||
this.platformOpen = false
|
||||
this.currentPlatform = null
|
||||
this.getList()
|
||||
})
|
||||
})
|
||||
},
|
||||
handleDeletePlatform(row) {
|
||||
const ids = row.id || this.ids
|
||||
this.$modal.confirm('是否确认删除平台编号为 "' + ids + '" 的数据项?').then(function() {
|
||||
return delPlatform(ids)
|
||||
}).then(() => {
|
||||
this.currentPlatform = null
|
||||
this.getList()
|
||||
this.$modal.msgSuccess('删除成功')
|
||||
}).catch(() => {})
|
||||
},
|
||||
getApiList() {
|
||||
if (!this.currentPlatform) {
|
||||
this.apiList = []
|
||||
return
|
||||
}
|
||||
this.apiLoading = true
|
||||
listIntegrationApi({ platformId: this.currentPlatform.id, pageNum: 1, pageSize: 100 }).then(response => {
|
||||
this.apiList = response.rows || []
|
||||
this.apiLoading = false
|
||||
})
|
||||
},
|
||||
handleApiSelectionChange(selection) {
|
||||
this.apiIds = selection.map(item => item.id)
|
||||
this.apiSingle = selection.length !== 1
|
||||
this.apiMultiple = !selection.length
|
||||
},
|
||||
resetApiForm() {
|
||||
this.apiForm = {
|
||||
id: null,
|
||||
platformId: this.currentPlatform ? this.currentPlatform.id : null,
|
||||
apiCode: null,
|
||||
apiName: null,
|
||||
method: 'GET',
|
||||
uri: null,
|
||||
contentType: 'application/json',
|
||||
headersJson: '{}',
|
||||
queryJson: '{}',
|
||||
bodyJson: '{}',
|
||||
responsePath: null,
|
||||
dependsOn: null,
|
||||
sortOrder: 0,
|
||||
status: 1
|
||||
}
|
||||
this.resetForm('apiForm')
|
||||
},
|
||||
handleAddApi() {
|
||||
this.resetApiForm()
|
||||
this.apiOpen = true
|
||||
this.apiTitle = '新增接口定义'
|
||||
},
|
||||
handleUpdateApi(row) {
|
||||
this.resetApiForm()
|
||||
const id = row.id || this.apiIds
|
||||
getIntegrationApi(id).then(response => {
|
||||
this.apiForm = response.data
|
||||
this.apiOpen = true
|
||||
this.apiTitle = '修改接口定义'
|
||||
})
|
||||
},
|
||||
submitApiForm() {
|
||||
this.$refs.apiForm.validate(valid => {
|
||||
if (!valid) {
|
||||
return
|
||||
}
|
||||
const request = this.apiForm.id != null ? updateIntegrationApi(this.apiForm) : addIntegrationApi(this.apiForm)
|
||||
request.then(() => {
|
||||
this.$modal.msgSuccess(this.apiForm.id != null ? '修改成功' : '新增成功')
|
||||
this.apiOpen = false
|
||||
this.getApiList()
|
||||
})
|
||||
})
|
||||
},
|
||||
handleDeleteApi(row) {
|
||||
const ids = row.id || this.apiIds
|
||||
this.$modal.confirm('是否确认删除接口编号为 "' + ids + '" 的数据项?').then(function() {
|
||||
return delIntegrationApi(ids)
|
||||
}).then(() => {
|
||||
this.getApiList()
|
||||
this.$modal.msgSuccess('删除成功')
|
||||
}).catch(() => {})
|
||||
},
|
||||
getMappingList() {
|
||||
if (!this.currentPlatform) {
|
||||
this.mappingList = []
|
||||
return
|
||||
}
|
||||
this.mappingLoading = true
|
||||
listDeviceMapping({ platformId: this.currentPlatform.id, pageNum: 1, pageSize: 100 }).then(response => {
|
||||
this.mappingList = response.rows || []
|
||||
this.mappingLoading = false
|
||||
})
|
||||
},
|
||||
handleMappingSelectionChange(selection) {
|
||||
this.mappingIds = selection.map(item => item.id)
|
||||
this.mappingSingle = selection.length !== 1
|
||||
this.mappingMultiple = !selection.length
|
||||
},
|
||||
resetMappingForm() {
|
||||
this.mappingForm = {
|
||||
id: null,
|
||||
platformId: this.currentPlatform ? this.currentPlatform.id : null,
|
||||
externalDeviceId: null,
|
||||
externalDeviceName: null,
|
||||
productId: null,
|
||||
serialNumber: null,
|
||||
identifierMappingJson: '{"e":"axialForce","temperature":"temperature","ct":"ct","pt":"pt"}',
|
||||
status: 1
|
||||
}
|
||||
this.resetForm('mappingForm')
|
||||
},
|
||||
handleAddMapping() {
|
||||
this.resetMappingForm()
|
||||
this.mappingOpen = true
|
||||
this.mappingTitle = '新增设备映射'
|
||||
},
|
||||
handleUpdateMapping(row) {
|
||||
this.resetMappingForm()
|
||||
const id = row.id || this.mappingIds
|
||||
getDeviceMapping(id).then(response => {
|
||||
this.mappingForm = response.data
|
||||
this.mappingOpen = true
|
||||
this.mappingTitle = '修改设备映射'
|
||||
})
|
||||
},
|
||||
submitMappingForm() {
|
||||
this.$refs.mappingForm.validate(valid => {
|
||||
if (!valid) {
|
||||
return
|
||||
}
|
||||
const request = this.mappingForm.id != null ? updateDeviceMapping(this.mappingForm) : addDeviceMapping(this.mappingForm)
|
||||
request.then(() => {
|
||||
this.$modal.msgSuccess(this.mappingForm.id != null ? '修改成功' : '新增成功')
|
||||
this.mappingOpen = false
|
||||
this.getMappingList()
|
||||
})
|
||||
})
|
||||
},
|
||||
handleDeleteMapping(row) {
|
||||
const ids = row.id || this.mappingIds
|
||||
this.$modal.confirm('是否确认删除映射编号为 "' + ids + '" 的数据项?').then(function() {
|
||||
return delDeviceMapping(ids)
|
||||
}).then(() => {
|
||||
this.getMappingList()
|
||||
this.$modal.msgSuccess('删除成功')
|
||||
}).catch(() => {})
|
||||
},
|
||||
getLogList() {
|
||||
if (!this.currentPlatform) {
|
||||
this.logList = []
|
||||
return
|
||||
}
|
||||
this.logLoading = true
|
||||
listIntegrationLog({ platformId: this.currentPlatform.id, pageNum: 1, pageSize: 20 }).then(response => {
|
||||
this.logList = response.rows || []
|
||||
this.logLoading = false
|
||||
})
|
||||
},
|
||||
openSyncDialog(dryRun, row) {
|
||||
const platform = row || this.currentPlatform
|
||||
if (!platform) {
|
||||
return
|
||||
}
|
||||
this.syncForm = {
|
||||
platformCode: platform.platformCode,
|
||||
projectId: null,
|
||||
startTime: null,
|
||||
endTime: null,
|
||||
original: false,
|
||||
dryRun: !!dryRun,
|
||||
externalDeviceIdsText: ''
|
||||
}
|
||||
this.syncOpen = true
|
||||
},
|
||||
submitSync() {
|
||||
const externalDeviceIds = (this.syncForm.externalDeviceIdsText || '').split(/\r?\n/).map(item => item.trim()).filter(item => item)
|
||||
const data = {
|
||||
platformCode: this.syncForm.platformCode,
|
||||
projectId: this.syncForm.projectId,
|
||||
startTime: this.syncForm.startTime,
|
||||
endTime: this.syncForm.endTime,
|
||||
original: this.syncForm.original,
|
||||
dryRun: this.syncForm.dryRun,
|
||||
externalDeviceIds: externalDeviceIds
|
||||
}
|
||||
syncIntegration(data).then(response => {
|
||||
this.$modal.msgSuccess('执行完成,成功 ' + response.data.successCount + ' 条,失败 ' + response.data.failCount + ' 条')
|
||||
this.syncOpen = false
|
||||
this.getLogList()
|
||||
})
|
||||
},
|
||||
handleSelfTest() {
|
||||
if (!this.currentPlatform) {
|
||||
return
|
||||
}
|
||||
selfTestIntegration(this.currentPlatform.platformCode).then(response => {
|
||||
this.$modal.msgSuccess('自测完成,成功 ' + response.data.successCount + ' 条,失败 ' + response.data.failCount + ' 条')
|
||||
})
|
||||
},
|
||||
logStatusText(status) {
|
||||
if (status === 1) {
|
||||
return '成功'
|
||||
}
|
||||
if (status === 2) {
|
||||
return '执行中'
|
||||
}
|
||||
return '失败'
|
||||
},
|
||||
logStatusTag(status) {
|
||||
if (status === 1) {
|
||||
return 'success'
|
||||
}
|
||||
if (status === 2) {
|
||||
return 'warning'
|
||||
}
|
||||
return 'danger'
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.integration-page {
|
||||
.integration-detail {
|
||||
margin-top: 18px;
|
||||
padding-top: 14px;
|
||||
border-top: 1px solid #ebeef5;
|
||||
}
|
||||
|
||||
.detail-header {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.detail-title {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
.detail-subtitle {
|
||||
margin-left: 10px;
|
||||
font-size: 13px;
|
||||
color: #909399;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Loading…
Reference in New Issue
Block a user