This commit is contained in:
2025-11-07 14:40:42 +08:00
parent b2b18972d7
commit 2409c8c819
12 changed files with 1086 additions and 5 deletions

View File

@@ -0,0 +1,226 @@
package com.ruoyi.jarvis.domain;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.ruoyi.common.core.domain.BaseEntity;
import java.util.Date;
import java.util.List;
/**
* 腾讯文档批量推送记录
*/
public class TencentDocBatchPushRecord extends BaseEntity {
private static final long serialVersionUID = 1L;
/** 主键ID */
private Long id;
/** 批次ID */
private String batchId;
/** 文件ID */
private String fileId;
/** 工作表ID */
private String sheetId;
/** 推送类型AUTO-自动推送MANUAL-手动推送 */
private String pushType;
/** 触发来源DELAYED_TIMER-延迟定时器USER-用户手动 */
private String triggerSource;
/** 推送开始时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date startTime;
/** 推送结束时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date endTime;
/** 推送耗时(毫秒) */
private Long durationMs;
/** 起始行号 */
private Integer startRow;
/** 结束行号 */
private Integer endRow;
/** 总行数 */
private Integer totalRows;
/** 成功数量 */
private Integer successCount;
/** 跳过数量 */
private Integer skipCount;
/** 错误数量 */
private Integer errorCount;
/** 状态RUNNING-执行中SUCCESS-成功PARTIAL-部分成功FAILED-失败 */
private String status;
/** 结果消息 */
private String resultMessage;
/** 错误信息 */
private String errorMessage;
/** 关联的操作日志列表(非数据库字段) */
private List<TencentDocOperationLog> operationLogs;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getBatchId() {
return batchId;
}
public void setBatchId(String batchId) {
this.batchId = batchId;
}
public String getFileId() {
return fileId;
}
public void setFileId(String fileId) {
this.fileId = fileId;
}
public String getSheetId() {
return sheetId;
}
public void setSheetId(String sheetId) {
this.sheetId = sheetId;
}
public String getPushType() {
return pushType;
}
public void setPushType(String pushType) {
this.pushType = pushType;
}
public String getTriggerSource() {
return triggerSource;
}
public void setTriggerSource(String triggerSource) {
this.triggerSource = triggerSource;
}
public Date getStartTime() {
return startTime;
}
public void setStartTime(Date startTime) {
this.startTime = startTime;
}
public Date getEndTime() {
return endTime;
}
public void setEndTime(Date endTime) {
this.endTime = endTime;
}
public Long getDurationMs() {
return durationMs;
}
public void setDurationMs(Long durationMs) {
this.durationMs = durationMs;
}
public Integer getStartRow() {
return startRow;
}
public void setStartRow(Integer startRow) {
this.startRow = startRow;
}
public Integer getEndRow() {
return endRow;
}
public void setEndRow(Integer endRow) {
this.endRow = endRow;
}
public Integer getTotalRows() {
return totalRows;
}
public void setTotalRows(Integer totalRows) {
this.totalRows = totalRows;
}
public Integer getSuccessCount() {
return successCount;
}
public void setSuccessCount(Integer successCount) {
this.successCount = successCount;
}
public Integer getSkipCount() {
return skipCount;
}
public void setSkipCount(Integer skipCount) {
this.skipCount = skipCount;
}
public Integer getErrorCount() {
return errorCount;
}
public void setErrorCount(Integer errorCount) {
this.errorCount = errorCount;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public String getResultMessage() {
return resultMessage;
}
public void setResultMessage(String resultMessage) {
this.resultMessage = resultMessage;
}
public String getErrorMessage() {
return errorMessage;
}
public void setErrorMessage(String errorMessage) {
this.errorMessage = errorMessage;
}
public List<TencentDocOperationLog> getOperationLogs() {
return operationLogs;
}
public void setOperationLogs(List<TencentDocOperationLog> operationLogs) {
this.operationLogs = operationLogs;
}
}

View File

@@ -17,6 +17,9 @@ public class TencentDocOperationLog extends BaseEntity {
/** 主键ID */
private Long id;
/** 批次ID关联批量推送记录 */
private String batchId;
/** 文档ID */
private String fileId;

View File

@@ -0,0 +1,45 @@
package com.ruoyi.jarvis.mapper;
import com.ruoyi.jarvis.domain.TencentDocBatchPushRecord;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* 腾讯文档批量推送记录 Mapper
*/
public interface TencentDocBatchPushRecordMapper {
/**
* 插入批量推送记录
*/
int insertBatchPushRecord(TencentDocBatchPushRecord record);
/**
* 更新批量推送记录
*/
int updateBatchPushRecord(TencentDocBatchPushRecord record);
/**
* 根据批次ID查询
*/
TencentDocBatchPushRecord selectByBatchId(@Param("batchId") String batchId);
/**
* 查询批量推送记录列表
*/
List<TencentDocBatchPushRecord> selectBatchPushRecordList(TencentDocBatchPushRecord record);
/**
* 查询最近的推送记录
*/
List<TencentDocBatchPushRecord> selectRecentRecords(@Param("fileId") String fileId,
@Param("limit") int limit);
/**
* 查询最后一次成功的推送记录
*/
TencentDocBatchPushRecord selectLastSuccessRecord(@Param("fileId") String fileId,
@Param("sheetId") String sheetId);
}

View File

@@ -37,5 +37,13 @@ public interface TencentDocOperationLogMapper {
* @return 操作日志集合
*/
List<TencentDocOperationLog> selectRecentLogs(@Param("fileId") String fileId, @Param("limit") int limit);
/**
* 根据批次ID查询操作日志
*
* @param batchId 批次ID
* @return 操作日志集合
*/
List<TencentDocOperationLog> selectLogsByBatchId(@Param("batchId") String batchId);
}

View File

@@ -0,0 +1,45 @@
package com.ruoyi.jarvis.service;
import com.ruoyi.jarvis.domain.TencentDocBatchPushRecord;
import java.util.List;
import java.util.Map;
/**
* 腾讯文档批量推送记录服务
*/
public interface ITencentDocBatchPushService {
/**
* 创建批量推送记录
*/
String createBatchPushRecord(String fileId, String sheetId, String pushType,
String triggerSource, Integer startRow, Integer endRow);
/**
* 更新批量推送记录
*/
void updateBatchPushRecord(String batchId, String status, Integer successCount,
Integer skipCount, Integer errorCount, String resultMessage, String errorMessage);
/**
* 根据批次ID查询
*/
TencentDocBatchPushRecord getBatchPushRecord(String batchId);
/**
* 查询批量推送记录列表(带操作日志)
*/
List<TencentDocBatchPushRecord> getBatchPushRecordListWithLogs(String fileId, String sheetId, Integer limit);
/**
* 查询最后一次成功的推送记录
*/
TencentDocBatchPushRecord getLastSuccessRecord(String fileId, String sheetId);
/**
* 获取推送状态和倒计时信息
*/
Map<String, Object> getPushStatusAndCountdown();
}

View File

@@ -0,0 +1,159 @@
package com.ruoyi.jarvis.service.impl;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.jarvis.domain.TencentDocBatchPushRecord;
import com.ruoyi.jarvis.domain.TencentDocOperationLog;
import com.ruoyi.jarvis.mapper.TencentDocBatchPushRecordMapper;
import com.ruoyi.jarvis.mapper.TencentDocOperationLogMapper;
import com.ruoyi.jarvis.service.ITencentDocBatchPushService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.TimeUnit;
/**
* 腾讯文档批量推送记录服务实现
*/
@Service
public class TencentDocBatchPushServiceImpl implements ITencentDocBatchPushService {
@Resource
private TencentDocBatchPushRecordMapper batchPushRecordMapper;
@Resource
private TencentDocOperationLogMapper operationLogMapper;
@Resource
private RedisCache redisCache;
private static final String DELAYED_PUSH_TASK_KEY = "tendoc:delayed_push:task_scheduled";
private static final String DELAYED_PUSH_SCHEDULE_TIME_KEY = "tendoc:delayed_push:schedule_time";
@Override
public String createBatchPushRecord(String fileId, String sheetId, String pushType,
String triggerSource, Integer startRow, Integer endRow) {
String batchId = UUID.randomUUID().toString().replace("-", "");
TencentDocBatchPushRecord record = new TencentDocBatchPushRecord();
record.setBatchId(batchId);
record.setFileId(fileId);
record.setSheetId(sheetId);
record.setPushType(pushType);
record.setTriggerSource(triggerSource);
record.setStartTime(new Date());
record.setStartRow(startRow);
record.setEndRow(endRow);
record.setTotalRows(endRow - startRow + 1);
record.setSuccessCount(0);
record.setSkipCount(0);
record.setErrorCount(0);
record.setStatus("RUNNING");
batchPushRecordMapper.insertBatchPushRecord(record);
return batchId;
}
@Override
public void updateBatchPushRecord(String batchId, String status, Integer successCount,
Integer skipCount, Integer errorCount, String resultMessage, String errorMessage) {
TencentDocBatchPushRecord record = new TencentDocBatchPushRecord();
record.setBatchId(batchId);
record.setEndTime(new Date());
record.setStatus(status);
record.setSuccessCount(successCount);
record.setSkipCount(skipCount);
record.setErrorCount(errorCount);
record.setResultMessage(resultMessage);
record.setErrorMessage(errorMessage);
// 计算耗时
TencentDocBatchPushRecord existingRecord = batchPushRecordMapper.selectByBatchId(batchId);
if (existingRecord != null && existingRecord.getStartTime() != null) {
long durationMs = new Date().getTime() - existingRecord.getStartTime().getTime();
record.setDurationMs(durationMs);
}
batchPushRecordMapper.updateBatchPushRecord(record);
}
@Override
public TencentDocBatchPushRecord getBatchPushRecord(String batchId) {
TencentDocBatchPushRecord record = batchPushRecordMapper.selectByBatchId(batchId);
if (record != null) {
// 加载关联的操作日志
List<TencentDocOperationLog> logs = operationLogMapper.selectLogsByBatchId(batchId);
record.setOperationLogs(logs);
}
return record;
}
@Override
public List<TencentDocBatchPushRecord> getBatchPushRecordListWithLogs(String fileId, String sheetId, Integer limit) {
TencentDocBatchPushRecord query = new TencentDocBatchPushRecord();
query.setFileId(fileId);
query.setSheetId(sheetId);
List<TencentDocBatchPushRecord> records = limit != null && limit > 0
? batchPushRecordMapper.selectRecentRecords(fileId, limit)
: batchPushRecordMapper.selectBatchPushRecordList(query);
// 为每条记录加载操作日志
for (TencentDocBatchPushRecord record : records) {
List<TencentDocOperationLog> logs = operationLogMapper.selectLogsByBatchId(record.getBatchId());
record.setOperationLogs(logs);
}
return records;
}
@Override
public TencentDocBatchPushRecord getLastSuccessRecord(String fileId, String sheetId) {
TencentDocBatchPushRecord record = batchPushRecordMapper.selectLastSuccessRecord(fileId, sheetId);
if (record != null) {
List<TencentDocOperationLog> logs = operationLogMapper.selectLogsByBatchId(record.getBatchId());
record.setOperationLogs(logs);
}
return record;
}
@Override
public Map<String, Object> getPushStatusAndCountdown() {
Map<String, Object> result = new HashMap<>();
// 检查是否有定时任务
Boolean isScheduled = redisCache.getCacheObject(DELAYED_PUSH_TASK_KEY);
Long scheduleTime = redisCache.getCacheObject(DELAYED_PUSH_SCHEDULE_TIME_KEY);
result.put("isScheduled", isScheduled != null && isScheduled);
if (isScheduled != null && isScheduled && scheduleTime != null) {
long now = System.currentTimeMillis();
long remainingMs = scheduleTime - now;
if (remainingMs > 0) {
result.put("scheduledTime", new Date(scheduleTime));
result.put("remainingSeconds", remainingMs / 1000);
result.put("remainingMs", remainingMs);
// 格式化倒计时显示
long minutes = remainingMs / 60000;
long seconds = (remainingMs % 60000) / 1000;
result.put("countdownText", String.format("%d分%d秒", minutes, seconds));
} else {
result.put("remainingSeconds", 0);
result.put("remainingMs", 0);
result.put("countdownText", "即将执行");
}
} else {
result.put("scheduledTime", null);
result.put("remainingSeconds", 0);
result.put("remainingMs", 0);
result.put("countdownText", "无定时任务");
}
return result;
}
}

View File

@@ -1,12 +1,16 @@
package com.ruoyi.jarvis.service.impl;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.jarvis.config.TencentDocConfig;
import com.ruoyi.jarvis.service.ITencentDocBatchPushService;
import com.ruoyi.jarvis.service.ITencentDocDelayedPushService;
import com.ruoyi.jarvis.service.ITencentDocTokenService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
@@ -33,6 +37,15 @@ public class TencentDocDelayedPushServiceImpl implements ITencentDocDelayedPushS
@Autowired
private RedisCache redisCache;
@Autowired
private ITencentDocBatchPushService batchPushService;
@Autowired
private TencentDocConfig tencentDocConfig;
@Autowired
private ITencentDocTokenService tokenService;
/**
* 延迟时间(分钟),可通过配置文件修改
@@ -237,15 +250,36 @@ public class TencentDocDelayedPushServiceImpl implements ITencentDocDelayedPushS
/**
* 执行批量同步
*
* 说明:这里通过HTTP调用本地接口,避免复杂的依赖注入
* 说明:创建批量推送记录,然后通过HTTP调用本地接口
*/
private void executeBatchSync() {
String batchId = null;
try {
log.info("开始执行批量同步...");
// 使用RestTemplate或HttpClient调用本地接口
// 这里简化处理直接发送HTTP请求到本地
java.net.URL url = new java.net.URL("http://localhost:30313/jarvis-api/jarvis/tendoc/fillLogisticsByOrderNo");
// 获取配置信息
String fileId = tencentDocConfig.getFileId();
String sheetId = tencentDocConfig.getSheetId();
Integer startRow = tencentDocConfig.getStartRow();
if (StringUtils.isEmpty(fileId) || StringUtils.isEmpty(sheetId)) {
log.error("腾讯文档配置不完整,无法执行批量同步");
return;
}
// 创建批量推送记录
batchId = batchPushService.createBatchPushRecord(
fileId,
sheetId,
"AUTO",
"DELAYED_TIMER",
startRow,
startRow + 199 // 暂定范围
);
log.info("✓ 创建批量推送记录批次ID: {}", batchId);
// 调用批量同步接口传递批次ID
java.net.URL url = new java.net.URL("http://localhost:30313/jarvis-api/jarvis/tendoc/fillLogisticsByOrderNo?batchId=" + batchId);
java.net.HttpURLConnection conn = (java.net.HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "application/json");
@@ -273,10 +307,24 @@ public class TencentDocDelayedPushServiceImpl implements ITencentDocDelayedPushS
}
} else {
log.error("批量同步调用失败,响应码: {}", responseCode);
// 更新批量推送记录为失败状态
if (batchId != null) {
batchPushService.updateBatchPushRecord(batchId, "FAILED", 0, 0, 0,
null, "批量同步调用失败,响应码: " + responseCode);
}
}
} catch (Exception e) {
log.error("执行批量同步失败", e);
// 更新批量推送记录为失败状态
if (batchId != null) {
try {
batchPushService.updateBatchPushRecord(batchId, "FAILED", 0, 0, 0,
null, "执行批量同步失败: " + e.getMessage());
} catch (Exception ex) {
log.error("更新批量推送记录失败", ex);
}
}
throw new RuntimeException("执行批量同步失败", e);
}
}