This commit is contained in:
2025-07-27 22:40:39 +08:00
parent 23e3100146
commit 15b25144f0
14 changed files with 900 additions and 0 deletions

View File

@@ -5,6 +5,7 @@ import org.dromara.sis.sdk.hik.service.SdkBaseServer;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup; import org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup;
import org.springframework.scheduling.annotation.EnableScheduling;
/** /**
* 物业模块 * 物业模块
@@ -12,6 +13,7 @@ import org.springframework.boot.context.metrics.buffering.BufferingApplicationSt
* @author ruoyi * @author ruoyi
*/ */
@EnableDubbo @EnableDubbo
@EnableScheduling
@SpringBootApplication @SpringBootApplication
public class SisApplication { public class SisApplication {
public static void main(String[] args) { public static void main(String[] args) {

View File

@@ -0,0 +1,21 @@
package org.dromara.sis.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
/**
* 应用配置类
*/
@Configuration
public class SOSAppConfig {
/**
* 配置 RestTemplate 用于 API 调用
* @return RestTemplate 实例
*/
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
}

View File

@@ -0,0 +1,201 @@
package org.dromara.sis.domain;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
/**
* 报警记录实体类,对应数据库表 alarm_record
* 存储系统中的报警事件信息,包括设备信息、时间信息、处理状态等
*/
@Data
@TableName("alarm_record")
public class AlarmRecord implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 报警记录唯一标识,对应 API 返回的 Id 字段
* 采用 INPUT 策略,使用 API 返回的实际 ID 值
*/
@TableId(type = IdType.INPUT)
private Long id;
/**
* 任务编码,用于标识特定的报警任务
*/
private String taskCode;
/**
* 设备ID关联具体的报警设备
*/
private Integer deviceId;
/**
* 设备名称,如 "7楼办公室"
*/
private String deviceName;
/**
* 设备许可证ID用于唯一标识设备
*/
private String deviceLicenseId;
/**
* 设备SIP号码用于通信
*/
private String deviceSipNum;
/**
* 设备所在经度
*/
private Double deviceLng;
/**
* 设备所在纬度
*/
private Double deviceLat;
/**
* 会议ID关联报警处理过程中的会议
*/
private Long conferenceId;
/**
* 会议SIP编码
*/
private String confSipCode;
/**
* 报警状态,如 "finished"(已完成)、"noAnswer"(未接听)等
*/
private String state;
/**
* 报警开始时间Java Date 类型)
*/
private Date startTime;
/**
* 报警开始时间的 Unix 时间戳(毫秒)
*/
private Long startTimeUnix;
/**
* 报警结束时间Java Date 类型)
*/
private Date finishTime;
/**
* 报警结束时间的 Unix 时间戳(毫秒)
*/
private Long finishTimeUnix;
/**
* 响铃开始时间Java Date 类型)
*/
private Date ringingTime;
/**
* 响铃开始时间的 Unix 时间戳(毫秒)
*/
private Long ringingTimeUnix;
/**
* 过期时间Java Date 类型)
*/
private Date expireTime;
/**
* 过期时间的 Unix 时间戳(毫秒)
*/
private Long expireTimeUnix;
/**
* 呼叫过期时间Java Date 类型)
*/
private Date callExpireTime;
/**
* 呼叫过期时间的 Unix 时间戳(毫秒)
*/
private Long callExpireTimeUnix;
/**
* 呼叫开始时间Java Date 类型)
*/
private Date callTime;
/**
* 呼叫开始时间的 Unix 时间戳(毫秒)
*/
private Long callTimeUnix;
/**
* 设备是否带有摄像头0-不带1-带)
*/
private Integer deviceWithCamera;
/**
* 公司编码,标识所属公司
*/
private String companyCode;
/**
* 报警类型,如 "button"(按钮报警)
*/
private String alarmType;
/**
* 业务类型,如 "normal"(正常业务)
*/
private String businessType;
/**
* 分组ID用于对设备进行分组管理
*/
private Integer groupId;
/**
* 报告通知级别
*/
private Integer reportNotifyLevel;
/**
* 是否挂起0-未挂起1-挂起)
*/
private Integer isHold;
/**
* 显示的报警类型(可能为空)
*/
private String displayAlarmType;
/**
* 接收类型(可能为空)
*/
private String acceptType;
/**
* 分组名称(可能为空)
*/
private String groupName;
/**
* 设备联系人(可能为空)
*/
private String deviceLinkman;
/**
* 设备联系电话(可能为空)
*/
private String devicePhoneNum;
/**
* 记录创建时间,由数据库自动填充
* 使用 MyBatis-Plus 的自动填充功能,插入时自动设置为当前时间
*/
@TableField(fill = FieldFill.INSERT)
private Date createTime;
}

View File

@@ -0,0 +1,99 @@
package org.dromara.sis.domain;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
/**
* 报警任务操作记录实体类,对应数据库表 alarm_record_task_operator
* 记录每个报警任务的操作人信息和处理时间
*/
@Data
@TableName("alarm_record_task_operator")
public class AlarmTaskOperator implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 自增主键
*/
@TableId(type = IdType.AUTO)
private Long id;
/**
* 关联的报警记录ID外键
*/
private Long alarmRecordId;
/**
* 操作记录ID来自API返回
*/
private Integer operatorId;
/**
* 关联的报警ID
*/
private Long alarmId;
/**
* 任务编码
*/
private String taskCode;
/**
* 操作人ID
*/
private Integer userId;
/**
* 操作人类型1-普通用户2-管理员等,具体根据业务定义)
*/
private Integer userType;
/**
* 操作人昵称
*/
private String nickName;
/**
* 操作人头像URL
*/
private String avatarUrl;
/**
* 操作人SIP号码
*/
private String sipNum;
/**
* 接听时间Java Date 类型)
*/
private Date answerTime;
/**
* 接听时间的 Unix 时间戳(毫秒)
*/
private Long answerTimeUnix;
/**
* 处理完成时间Java Date 类型)
*/
private Date finishTime;
/**
* 处理完成时间的 Unix 时间戳(毫秒)
*/
private Long finishTimeUnix;
/**
* 转接级别(如 "levelOne"、"levelTwo" 等)
*/
private String transferLevel;
/**
* 记录创建时间,由数据库自动填充
*/
@TableField(fill = FieldFill.INSERT)
private Date createTime;
}

View File

@@ -0,0 +1,14 @@
package org.dromara.sis.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.dromara.sis.domain.AlarmRecord;
import org.springframework.stereotype.Repository;
/**
* 报警记录 Mapper 接口
*/
@Repository
public interface AlarmRecordMapper extends BaseMapper<AlarmRecord> {
}

View File

@@ -0,0 +1,13 @@
package org.dromara.sis.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.dromara.sis.domain.AlarmTaskOperator;
import org.springframework.stereotype.Repository;
/**
* 报警任务操作记录 Mapper 接口
*/
@Repository
public interface AlarmTaskOperatorMapper extends BaseMapper<AlarmTaskOperator> {
}

View File

@@ -0,0 +1,29 @@
package org.dromara.sis.service;
import com.baomidou.mybatisplus.extension.service.IService;
import org.dromara.sis.domain.AlarmRecord;
import java.util.List;
import java.util.Map;
/**
* 报警记录服务接口
*/
public interface AlarmRecordService extends IService<AlarmRecord> {
/**
* 从 API 返回的 Map 数据转换为实体对象
* @param map API 返回的单个报警记录数据
* @return 转换后的实体对象
*/
AlarmRecord convertFromMap(Map<String, Object> map);
/**
* 保存新的报警记录,并关联保存其操作记录
* @param records 报警记录列表
* @param operatorMap 操作记录映射键为报警记录ID值为对应操作记录列表
* @return 成功保存的记录数
*/
int saveNewRecords(List<AlarmRecord> records, Map<Long, List<Map<String, Object>>> operatorMap);
}

View File

@@ -0,0 +1,30 @@
package org.dromara.sis.service;
import com.baomidou.mybatisplus.extension.service.IService;
import org.dromara.sis.domain.AlarmTaskOperator;
import java.util.List;
import java.util.Map;
/**
* 报警任务操作记录服务接口
*/
public interface AlarmTaskOperatorService extends IService<AlarmTaskOperator> {
/**
* 从 API 返回的 Map 数据转换为实体列表
* @param alarmRecordId 关联的报警记录ID
* @param operatorMaps API 返回的操作人数据列表
* @return 转换后的实体列表
*/
List<AlarmTaskOperator> convertFromMaps(Long alarmRecordId, List<Map<String, Object>> operatorMaps);
/**
* 批量保存操作记录,自动过滤已存在的记录
* @param operators 操作记录列表
* @return 成功保存的记录数
*/
int saveNewOperators(List<AlarmTaskOperator> operators);
}

View File

@@ -0,0 +1,18 @@
package org.dromara.sis.service;
import java.util.Map;
/**
* API服务接口定义与外部API通信的方法
*/
public interface ApiService {
/**
* 获取报警记录列表
* @param pageNum 页码
* @param pageSize 每页数量
* @return API返回的结果数据包含状态码和记录列表
*/
Map<String, Object> fetchAlarmRecords(int pageNum, int pageSize);
}

View File

@@ -0,0 +1,166 @@
package org.dromara.sis.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.dromara.sis.domain.AlarmRecord;
import org.dromara.sis.domain.AlarmTaskOperator;
import org.dromara.sis.mapper.AlarmRecordMapper;
import org.dromara.sis.service.AlarmRecordService;
import org.dromara.sis.service.AlarmTaskOperatorService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.*;
import java.util.stream.Collectors;
/**
* 报警记录服务实现类
*/
@Slf4j
@Service
public class AlarmRecordServiceImpl extends ServiceImpl<AlarmRecordMapper, AlarmRecord> implements AlarmRecordService {
@Autowired
private AlarmTaskOperatorService taskOperatorService;
@Override
@Transactional(rollbackFor = Exception.class)
public int saveNewRecords(List<AlarmRecord> records, Map<Long, List<Map<String, Object>>> operatorMap) {
if (records == null || records.isEmpty()) return 0;
// 提取待插入记录的ID列表
List<Long> ids = records.stream().map(AlarmRecord::getId).collect(Collectors.toList());
// 查询数据库中已存在的记录
LambdaQueryWrapper<AlarmRecord> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.in(AlarmRecord::getId, ids);
List<AlarmRecord> existingRecords = this.list(queryWrapper);
List<Long> existingIds = existingRecords.stream().map(AlarmRecord::getId).collect(Collectors.toList());
// 过滤出新增记录
List<AlarmRecord> newRecords = records.stream()
.filter(record -> !existingIds.contains(record.getId()))
.collect(Collectors.toList());
// 批量插入新记录
int savedCount = 0;
if (!newRecords.isEmpty()) {
if (this.saveBatch(newRecords)) {
savedCount = newRecords.size();
// 保存关联的操作记录
saveRelatedOperators(newRecords, operatorMap);
}
}
return savedCount;
}
private void saveRelatedOperators(List<AlarmRecord> newRecords, Map<Long, List<Map<String, Object>>> operatorMap) {
if (operatorMap == null || operatorMap.isEmpty()) return;
// 收集需要保存的操作记录
List<AlarmTaskOperator> allOperators = new ArrayList<>();
for (AlarmRecord record : newRecords) {
Long recordId = record.getId();
if (operatorMap.containsKey(recordId)) {
List<Map<String, Object>> operatorsData = operatorMap.get(recordId);
List<AlarmTaskOperator> operators = taskOperatorService.convertFromMaps(recordId, operatorsData);
allOperators.addAll(operators);
}
}
// 批量保存操作记录
if (!allOperators.isEmpty()) {
taskOperatorService.saveNewOperators(allOperators);
}
}
@Override
public AlarmRecord convertFromMap(Map<String, Object> map) {
if (map == null) return null;
AlarmRecord record = new AlarmRecord();
record.setId(getLongValue(map, "Id"));
record.setTaskCode((String) map.get("TaskCode"));
record.setDeviceId(getIntValue(map, "DeviceId"));
record.setDeviceName((String) map.get("DeviceName"));
record.setDeviceLicenseId((String) map.get("DeviceLicenseId"));
record.setDeviceSipNum((String) map.get("DeviceSipNum"));
record.setDeviceLng(getDoubleValue(map, "DeviceLng"));
record.setDeviceLat(getDoubleValue(map, "DeviceLat"));
record.setConferenceId(getLongValue(map, "ConferenceId"));
record.setConfSipCode((String) map.get("ConfSipCode"));
record.setState((String) map.get("State"));
// 处理时间字段
record.setStartTime(parseDate(map, "StartTime"));
record.setStartTimeUnix(getLongValue(map, "StartTimeUnix"));
record.setFinishTime(parseDate(map, "FinishTime"));
record.setFinishTimeUnix(getLongValue(map, "FinishTimeUnix"));
record.setRingingTime(parseDate(map, "RingingTime"));
record.setRingingTimeUnix(getLongValue(map, "RingingTimeUnix"));
record.setExpireTime(parseDate(map, "ExpireTime"));
record.setExpireTimeUnix(getLongValue(map, "ExpireTimeUnix"));
record.setCallExpireTime(parseDate(map, "CallExpireTime"));
record.setCallExpireTimeUnix(getLongValue(map, "CallExpireTimeUnix"));
record.setCallTime(parseDate(map, "CallTime"));
record.setCallTimeUnix(getLongValue(map, "CallTimeUnix"));
record.setDeviceWithCamera(getIntValue(map, "DeviceWithCamera"));
record.setCompanyCode((String) map.get("CompanyCode"));
record.setAlarmType((String) map.get("AlarmType"));
record.setBusinessType((String) map.get("BusinessType"));
record.setGroupId(getIntValue(map, "GroupId"));
record.setReportNotifyLevel(getIntValue(map, "ReportNotifyLevel"));
record.setIsHold(getIntValue(map, "IsHold"));
record.setDisplayAlarmType((String) map.get("DisplayAlarmType"));
record.setAcceptType((String) map.get("AcceptType"));
record.setGroupName((String) map.get("GroupName"));
record.setDeviceLinkman((String) map.get("DeviceLinkman"));
record.setDevicePhoneNum((String) map.get("DevicePhoneNum"));
return record;
}
// 类型转换辅助方法
private Long getLongValue(Map<String, Object> map, String key) {
Object value = map.get(key);
if (value instanceof Number) {
return ((Number) value).longValue();
}
return null;
}
private Integer getIntValue(Map<String, Object> map, String key) {
Object value = map.get(key);
if (value instanceof Number) {
return ((Number) value).intValue();
}
return null;
}
private Double getDoubleValue(Map<String, Object> map, String key) {
Object value = map.get(key);
if (value instanceof Number) {
return ((Number) value).doubleValue();
}
return null;
}
private java.util.Date parseDate(Map<String, Object> map, String key) {
try {
String dateStr = (String) map.get(key);
if (dateStr != null && !dateStr.isEmpty() && !"1970-01-01 00:00:00".equals(dateStr)) {
java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return sdf.parse(dateStr);
}
} catch (Exception e) {
log.error("日期转换失败: {}", e.getMessage());
}
return null;
}
}

View File

@@ -0,0 +1,123 @@
package org.dromara.sis.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.dromara.sis.domain.AlarmTaskOperator;
import org.dromara.sis.mapper.AlarmTaskOperatorMapper;
import org.dromara.sis.service.AlarmTaskOperatorService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* 报警任务操作记录服务实现类
*/
@Slf4j
@Service
public class AlarmTaskOperatorServiceImpl extends ServiceImpl<AlarmTaskOperatorMapper, AlarmTaskOperator> implements AlarmTaskOperatorService {
@Override
@Transactional(rollbackFor = Exception.class)
public int saveNewOperators(List<AlarmTaskOperator> operators) {
if (operators == null || operators.isEmpty()) return 0;
// 生成唯一键集合 (alarmRecordId_operatorId)
List<String> uniqueKeys = operators.stream()
.map(op -> op.getAlarmRecordId() + "_" + op.getOperatorId())
.collect(Collectors.toList());
// 查询已存在的记录(修正后的代码)
LambdaQueryWrapper<AlarmTaskOperator> queryWrapper = new LambdaQueryWrapper<>();
for (String uniqueKey : uniqueKeys) {
String[] parts = uniqueKey.split("_");
if (parts.length == 2) {
Long alarmRecordId = Long.parseLong(parts[0]);
Integer operatorId = Integer.parseInt(parts[1]);
if (!queryWrapper.isEmptyOfWhere()) {
queryWrapper.or();
}
queryWrapper.nested(wrapper ->
wrapper.eq(AlarmTaskOperator::getAlarmRecordId, alarmRecordId)
.eq(AlarmTaskOperator::getOperatorId, operatorId)
);
}
}
List<AlarmTaskOperator> existingRecords = this.list(queryWrapper);
// 生成已存在的唯一键集合
List<String> existingKeys = existingRecords.stream()
.map(op -> op.getAlarmRecordId() + "_" + op.getOperatorId())
.collect(Collectors.toList());
// 过滤出新记录
List<AlarmTaskOperator> newRecords = operators.stream()
.filter(op -> !existingKeys.contains(op.getAlarmRecordId() + "_" + op.getOperatorId()))
.collect(Collectors.toList());
// 批量插入新记录
return newRecords.isEmpty() ? 0 : this.saveBatch(newRecords) ? newRecords.size() : 0;
}
@Override
public List<AlarmTaskOperator> convertFromMaps(Long alarmRecordId, List<Map<String, Object>> operatorMaps) {
List<AlarmTaskOperator> result = new ArrayList<>();
if (operatorMaps == null || operatorMaps.isEmpty()) return result;
for (Map<String, Object> map : operatorMaps) {
AlarmTaskOperator operator = new AlarmTaskOperator();
operator.setAlarmRecordId(alarmRecordId);
operator.setOperatorId(getIntValue(map, "Id"));
operator.setAlarmId(getLongValue(map, "AlarmId"));
operator.setTaskCode((String) map.get("TaskCode"));
operator.setUserId(getIntValue(map, "UserId"));
operator.setUserType(getIntValue(map, "UserType"));
operator.setNickName((String) map.get("NickName"));
operator.setAvatarUrl((String) map.get("AvatarUrl"));
operator.setSipNum((String) map.get("SipNum"));
operator.setAnswerTime(parseDate(map, "AnswerTime"));
operator.setAnswerTimeUnix(getLongValue(map, "AnswerTimeUnix"));
operator.setFinishTime(parseDate(map, "FinishTime"));
operator.setFinishTimeUnix(getLongValue(map, "FinishTimeUnix"));
operator.setTransferLevel((String) map.get("TransferLevel"));
result.add(operator);
}
return result;
}
// 类型转换辅助方法
private Long getLongValue(Map<String, Object> map, String key) {
Object value = map.get(key);
if (value instanceof Number) {
return ((Number) value).longValue();
}
return null;
}
private Integer getIntValue(Map<String, Object> map, String key) {
Object value = map.get(key);
if (value instanceof Number) {
return ((Number) value).intValue();
}
return null;
}
private java.util.Date parseDate(Map<String, Object> map, String key) {
try {
String dateStr = (String) map.get(key);
if (dateStr != null && !dateStr.isEmpty() && !"1970-01-01 00:00:00".equals(dateStr)) {
java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return sdf.parse(dateStr);
}
} catch (Exception e) {
log.error("日期转换失败: {}", e.getMessage());
}
return null;
}
}

View File

@@ -0,0 +1,79 @@
package org.dromara.sis.service.impl;
import lombok.extern.slf4j.Slf4j;
import org.dromara.sis.service.ApiService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* API 服务实现类
* 负责与外部 API 进行通信
*/
@Service
@Slf4j
public class ApiServiceImpl implements ApiService {
@Value("${api.url}")
private String apiUrl;
private final RestTemplate restTemplate;
public ApiServiceImpl(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
@Override
public Map<String, Object> fetchAlarmRecords(int pageNum, int pageSize) {
try {
// 设置请求头
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
// 构建请求体
Map<String, Object> requestBody = new HashMap<>();
requestBody.put("PageSize", pageSize);
requestBody.put("PageNum", pageNum);
List<List<Map<String, Object>>> filters = List.of(
List.of(Map.of("Key", "FinishTime", "Type", "str", "Value", "2025-07-27"))
);
requestBody.put("Filters", filters);
requestBody.put("OrderKey", "StartTime");
requestBody.put("Desc", "0");
requestBody.put("OrFirst", true);
// 发送请求
HttpEntity<Map<String, Object>> requestEntity = new HttpEntity<>(requestBody, headers);
ResponseEntity<Map> response = restTemplate.exchange(
apiUrl,
HttpMethod.POST,
requestEntity,
Map.class
);
// 处理响应
if (response.getStatusCode() == HttpStatus.OK) {
Map<String, Object> result = response.getBody();
if (result != null && result.get("Status").equals(0)) {
return result;
} else {
log.error("API 返回错误状态: {}", result);
return null;
}
} else {
log.error("API 请求失败,状态码: {}", response.getStatusCode());
return null;
}
} catch (Exception e) {
log.error("调用 API 异常: {}", e.getMessage(), e);
return null;
}
}
}

View File

@@ -0,0 +1,98 @@
package org.dromara.sis.task;
import lombok.extern.slf4j.Slf4j;
import org.dromara.sis.domain.AlarmRecord;
import org.dromara.sis.service.AlarmRecordService;
import org.dromara.sis.service.ApiService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.util.*;
import java.util.stream.Collectors;
/**
* 数据同步定时任务
* 每分钟执行一次,从 API 获取最新报警记录并同步到数据库
*/
@Slf4j
@Component
public class DataSyncTask {
private final ApiService apiService;
private final AlarmRecordService alarmRecordService;
@Value("${sync.pageSize:100}")
private int pageSize;
public DataSyncTask(ApiService apiService, AlarmRecordService alarmRecordService) {
this.apiService = apiService;
this.alarmRecordService = alarmRecordService;
}
/**
* 定时同步报警记录数据
*/
@Scheduled(fixedRate = 60 * 1000) // 每分钟执行一次
public void syncAlarmRecords() {
log.info("开始同步报警记录数据...");
int pageNum = 1;
boolean hasMoreData = true;
int totalSynced = 0;
try {
while (hasMoreData) {
// 调用 API 获取数据
Map<String, Object> apiResult = apiService.fetchAlarmRecords(pageNum, pageSize);
if (apiResult == null) {
log.error("API 返回空结果,停止同步");
break;
}
// 解析数据
int totalNum = (int) apiResult.getOrDefault("TotalNum", 0);
List<Map<String, Object>> recordList = (List<Map<String, Object>>) apiResult.get("RecordList");
if (recordList == null || recordList.isEmpty()) {
log.info("没有更多数据可同步");
hasMoreData = false;
break;
}
// 转换报警记录
List<AlarmRecord> records = recordList.stream()
.map(alarmRecordService::convertFromMap)
.collect(Collectors.toList());
// 提取操作记录数据
Map<Long, List<Map<String, Object>>> operatorMap = new HashMap<>();
for (Map<String, Object> recordMap : recordList) {
Long recordId = (Long) recordMap.get("Id");
List<Map<String, Object>> operators = (List<Map<String, Object>>) recordMap.get("TaskOperators");
if (operators != null && !operators.isEmpty()) {
operatorMap.put(recordId, operators);
}
}
// 保存数据(包含操作记录)
int savedCount = alarmRecordService.saveNewRecords(records, operatorMap);
totalSynced += savedCount;
log.info("第 {} 页同步完成,共 {} 条记录,新增 {} 条", pageNum, recordList.size(), savedCount);
// 判断是否还有更多数据
if (pageNum * pageSize >= totalNum) {
hasMoreData = false;
} else {
pageNum++;
}
}
log.info("报警记录数据同步完成,共新增 {} 条记录", totalSynced);
} catch (Exception e) {
log.error("同步报警记录数据失败: {}", e.getMessage(), e);
}
}
}

View File

@@ -10,6 +10,13 @@ spring:
profiles: profiles:
# 环境配置 # 环境配置
active: @profiles.active@ active: @profiles.active@
# API 配置
api:
url: https://norsos.lionking110.com/sos/v1/mntn/business/appId/alarm/list
# 同步配置
sync:
pageSize: 100
--- # nacos 配置 --- # nacos 配置
spring: spring: