Bladeren bron

定时任务推送

xiongwanxiong 2 dagen geleden
bovenliggende
commit
48451461e3

+ 114 - 34
wxjy-wxjy-service/src/main/java/cn/gov/customs/wxjy/task/BaseBusinessTask.java

@@ -8,19 +8,19 @@ import cn.gov.customs.wxjy.ibmmq.async.AsyncPushService;
 import cn.gov.customs.wxjy.ibmmq.config.PushContext;
 import cn.gov.customs.wxjy.ibmmq.enums.IbmmqEnum;
 import cn.gov.customs.wxjy.task.dao.TaskLogMapper;
+import cn.gov.customs.wxjy.task.dao.SyncDataStatusMapper; // 新增
 import cn.gov.customs.wxjy.task.pojo.TaskLog;
+import cn.gov.customs.wxjy.task.pojo.SyncDataStatus; // 新增
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.collections.CollectionUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Date;
-import java.util.List;
+import java.util.*;
+import java.util.stream.Collectors;
 
 /**
  * 基础业务任务抽象类
- * 所有具体业务任务都继承此类
+ * 使用 sync_data_status 表来区分新增和修改数据
  */
 @Slf4j
 public abstract class BaseBusinessTask<T> {
@@ -28,6 +28,9 @@ public abstract class BaseBusinessTask<T> {
     @Autowired
     protected TaskLogMapper taskLogMapper;
 
+    @Autowired
+    protected SyncDataStatusMapper syncDataStatusMapper; // 新增
+
     @Autowired
     protected AsyncPushService asyncPushService;
 
@@ -66,13 +69,6 @@ public abstract class BaseBusinessTask<T> {
      */
     public abstract List<T> queryData(Date lastSyncTime);
 
-    /**
-     * 判断是否为新增数据
-     * @param data 数据对象
-     * @return true-新增,false-修改
-     */
-    public abstract boolean isNewData(T data);
-
     /**
      * 获取数据ID
      * @param data 数据对象
@@ -84,33 +80,67 @@ public abstract class BaseBusinessTask<T> {
      * 执行任务
      */
     public void execute() {
-        Date lastSyncTime = getLastSyncTime();
-        List<T> dataList = queryData(lastSyncTime);
+        long startTime = System.currentTimeMillis();
+        String errorMsg = null;
+        List<String> businessIds = new ArrayList<>();
 
-        if (CollectionUtils.isEmpty(dataList)) {
-            log.info("{}:没有需要同步的数据", getTaskName());
-            return;
-        }
+        try {
+            // 1. 获取上次同步时间
+            Date lastSyncTime = getLastSyncTime();
 
-        // 区分新增和修改数据
-        List<T> addList = new ArrayList<>();
-        List<T> updateList = new ArrayList<>();
+            // 2. 查询需要同步的数据
+            List<T> dataList = queryData(lastSyncTime);
 
-        for (T data : dataList) {
-            if (isNewData(data)) {
-                addList.add(data);
-            } else {
-                updateList.add(data);
+            if (CollectionUtils.isEmpty(dataList)) {
+                log.info("{}:没有需要同步的数据", getTaskName());
+                recordTaskLog(TaskStatusEnum.SUCCESS, startTime, null);
+                return;
             }
-        }
 
-        // 推送数据
-        if (CollectionUtils.isNotEmpty(addList)) {
-            pushData(addList, IbmmqEnum.SAVE.getCode());
-        }
+            // 3. 获取已同步的数据ID集合(从 sync_data_status 表)
+            Set<String> syncedDataIds = getSyncedDataIds();
+
+            // 4. 区分新增和修改
+            List<T> addList = new ArrayList<>();
+            List<T> updateList = new ArrayList<>();
+
+            for (T data : dataList) {
+                String dataId = getDataId(data);
+                businessIds.add(dataId);
+
+                // 判断逻辑:如果在 sync_data_status 表中存在,则是修改;否则是新增
+                if (syncedDataIds.contains(dataId)) {
+                    updateList.add(data);
+                } else {
+                    addList.add(data);
+                }
+            }
+
+            // 5. 推送数据
+            if (CollectionUtils.isNotEmpty(addList)) {
+                pushData(addList, IbmmqEnum.SAVE.getCode());
+            }
+
+            if (CollectionUtils.isNotEmpty(updateList)) {
+                pushData(updateList, IbmmqEnum.UPDATE.getCode());
+            }
+
+            // 6. 更新同步状态到 sync_data_status 表
+            updateSyncDataStatus(dataList);
+
+            log.info("{}:同步完成,新增{}条,修改{}条",
+                    getTaskName(), addList.size(), updateList.size());
 
-        if (CollectionUtils.isNotEmpty(updateList)) {
-            pushData(updateList, IbmmqEnum.UPDATE.getCode());
+        } catch (Exception e) {
+            errorMsg = e.getMessage();
+            log.error("{}:任务执行失败", getTaskName(), e);
+            throw e;
+        } finally {
+            recordTaskLog(
+                    errorMsg == null ? TaskStatusEnum.SUCCESS : TaskStatusEnum.FAILED,
+                    startTime,
+                    errorMsg
+            );
         }
     }
 
@@ -118,7 +148,57 @@ public abstract class BaseBusinessTask<T> {
      * 获取上次同步时间
      */
     protected Date getLastSyncTime() {
-        return taskLogMapper.getMaxBussinessDate(getBusinessType());
+        Date lastDate = taskLogMapper.getMaxBussinessDate(getBusinessType());
+        if (lastDate == null) {
+            return null;
+        }
+        return lastDate;
+    }
+
+    /**
+     * 获取已同步的数据ID集合(从 sync_data_status 表)
+     */
+    protected Set<String> getSyncedDataIds() {
+        List<String> dataIds = syncDataStatusMapper.selectDataIdsByBusinessType(
+                getBusinessType()
+        );
+        return new HashSet<>(dataIds);
+    }
+
+    /**
+     * 更新同步数据状态到 sync_data_status 表
+     */
+    protected void updateSyncDataStatus(List<T> dataList) {
+        if (CollectionUtils.isEmpty(dataList)) {
+            return;
+        }
+
+        Date now = new Date();
+        String businessType = getBusinessType();
+
+        for (T data : dataList) {
+            String dataId = getDataId(data);
+
+            // 查询是否已存在
+            SyncDataStatus status = syncDataStatusMapper.selectByBusinessAndDataId(
+                    businessType, dataId
+            );
+
+            if (status == null) {
+                // 新增状态记录
+                status = new SyncDataStatus();
+                status.setID(idHelper.nextId());
+                status.setBusinessType(businessType);
+                status.setBusinessId(dataId);
+                status.setSyncTime(DateUtils.getDate());
+                status.setSyncVersion("1");
+                status.setIsDeleted("0");
+                syncDataStatusMapper.insert(status);
+            } else {
+                // 更新状态记录(只更新时间戳,版本号+1)
+                syncDataStatusMapper.updateSyncTime(businessType, dataId, now);
+            }
+        }
     }
 
     /**

+ 0 - 5
wxjy-wxjy-service/src/main/java/cn/gov/customs/wxjy/task/ChemicalsCatalogTask.java

@@ -56,11 +56,6 @@ public class ChemicalsCatalogTask extends BaseBusinessTask<ChemicalsCatalog> {
         return chemicalsCatalogMapper.selectList(query);
     }
 
-    @Override
-    public boolean isNewData(ChemicalsCatalog data) {
-        return data.getCreateTime().after(data.getUpdateTime());
-    }
-
     @Override
     public String getDataId(ChemicalsCatalog data) {
         return data.getId();

+ 0 - 5
wxjy-wxjy-service/src/main/java/cn/gov/customs/wxjy/task/GoodsCatalogTask.java

@@ -53,11 +53,6 @@ public class GoodsCatalogTask extends BaseBusinessTask<GoodsCatalog> {
         return goodsCatalogMapper.selectList(query);
     }
 
-    @Override
-    public boolean isNewData(GoodsCatalog data) {
-        return data.getCreateTime().after(data.getUpdateTime());
-    }
-
     @Override
     public String getDataId(GoodsCatalog data) {
         return data.getId();

+ 0 - 5
wxjy-wxjy-service/src/main/java/cn/gov/customs/wxjy/task/PackCatalogTask.java

@@ -53,11 +53,6 @@ public class PackCatalogTask extends BaseBusinessTask<PackCatalog> {
         return packCatalogMapper.selectList(query);
     }
 
-    @Override
-    public boolean isNewData(PackCatalog data) {
-        return data.getCreateTime().after(data.getUpdateTime());
-    }
-
     @Override
     public String getDataId(PackCatalog data) {
         return data.getId();

+ 9 - 23
wxjy-wxjy-service/src/main/java/cn/gov/customs/wxjy/task/ScheduledTasks.java

@@ -74,7 +74,7 @@ public class ScheduledTasks {
     /**
      * 包装种类定时任务调度
      */
-    @Scheduled(cron = "${task.cron.pack-catalog:30 * * * * ?}")
+    @Scheduled(cron = "0 10 3 ? * SAT")
     public void schedulePackCatalogTask() {
         executeTask(packCatalogTask, "包装种类目录推送数据");
     }
@@ -82,18 +82,18 @@ public class ScheduledTasks {
     /**
      * 危险货物定时任务调度
      */
-//    @Scheduled(cron = "${task.cron.goods-catalog:30 * * * * ?}")
-//    public void scheduleGoodsCatalogTask() {
-//        executeTask(goodsCatalogTask, "危险货物目录推送数据");
-//    }
+    @Scheduled(cron = "0 20 3 ? * SAT")
+    public void scheduleGoodsCatalogTask() {
+        executeTask(goodsCatalogTask, "危险货物目录推送数据");
+    }
 
     /**
      * 危化品目录定时任务调度
      */
-//    @Scheduled(cron = "${task.cron.chemicals-catalog:30 * * * * ?}")
-//    public void scheduleChemicalsCatalogTask() {
-//        executeTask(chemicalsCatalogTask, "危化品目录推送数据");
-//    }
+    @Scheduled(cron = "0 30 3 ? * SAT")
+    public void scheduleChemicalsCatalogTask() {
+        executeTask(chemicalsCatalogTask, "危化品目录推送数据");
+    }
 
     /**
      * 执行任务
@@ -110,28 +110,14 @@ public class ScheduledTasks {
         // 提交任务到线程池执行
         taskExecutor.submit(() -> {
             long startTime = System.currentTimeMillis();
-            TaskStatusEnum status = TaskStatusEnum.SUCCESS;
-            String errorMsg = null;
-
             try {
                 // 执行任务
                 task.execute();
                 log.info("{}定时任务执行完成,耗时:{}ms",
                         taskName, System.currentTimeMillis() - startTime);
-
             } catch (Exception e) {
-                status = TaskStatusEnum.FAILED;
-                errorMsg = String.format("执行失败:%s", e.getMessage());
                 log.error("{}定时任务执行异常,业务类型:{}",
                         taskName, task.getTaskCode(), e);
-
-            } finally {
-                // 记录任务执行日志
-                try {
-                    task.recordTaskLog(status, startTime, errorMsg);
-                } catch (Exception logEx) {
-                    log.error("记录任务日志失败,任务:{}", taskName, logEx);
-                }
             }
         });
     }

+ 114 - 0
wxjy-wxjy-service/src/main/java/cn/gov/customs/wxjy/task/controller/SyncDataStatusController.java

@@ -0,0 +1,114 @@
+package cn.gov.customs.wxjy.task.controller;
+
+import java.util.List;
+import javax.servlet.http.HttpServletResponse;
+
+import cn.gov.customs.cacp.sdks.core.result.Result;
+import cn.gov.customs.cacp.sdks.core.user.trans.CacpTransUser;
+import cn.gov.customs.cacp.sdks.core.user.trans.UserContextHolder;
+import cn.gov.customs.wxjy.common.utils.StringUtils;
+import lombok.RequiredArgsConstructor;
+import org.springframework.web.bind.annotation.*;
+import cn.gov.customs.wxjy.common.core.controller.BaseController;
+import org.springframework.web.multipart.MultipartFile;
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import cn.gov.customs.wxjy.task.pojo.SyncDataStatus;
+import cn.gov.customs.wxjy.task.pojo.SyncDataStatusQuery;
+import cn.gov.customs.wxjy.task.service.ISyncDataStatusService;
+import cn.gov.customs.wxjy.common.utils.poi.ExcelUtil;
+import cn.gov.customs.wxjy.common.core.page.TableDataInfo;
+
+/**
+ * 数据同步状态记录Controller
+ *
+ * @author xiong
+ * @date 2025-12-19
+ */
+@RestController
+@RequestMapping("/task/SyncDataStatus")
+@RequiredArgsConstructor
+public class SyncDataStatusController extends BaseController {
+
+    private final ISyncDataStatusService syncDataStatusService;
+
+    /**
+     * 查询数据同步状态记录列表
+     */
+    @PostMapping("/get-list")
+    public Result<PageInfo<SyncDataStatus>> list(@RequestBody SyncDataStatusQuery query) {
+        PageHelper.startPage(query.getPageIndex(), query.getPageSize());
+        PageInfo<SyncDataStatus> list = syncDataStatusService.selectPageList(query);
+        return Result.success(list);
+    }
+
+    /**
+     * 获取数据同步状态记录详细信息
+     */
+    @GetMapping(value = "/get-detail")
+    public Result<SyncDataStatus> getInfo(@RequestParam String ID) {
+        return Result.success(syncDataStatusService.selectByID(ID));
+    }
+
+    /**
+     * 新增数据同步状态记录
+     */
+    @PostMapping("/insert-syncDataStatus")
+    public Result<Integer> add(@RequestBody SyncDataStatus syncDataStatus) {
+        return Result.success(syncDataStatusService.insert(syncDataStatus));
+    }
+
+    /**
+     * 修改数据同步状态记录
+     */
+    @PostMapping("/update-syncDataStatus")
+    public Result<Integer> edit(@RequestBody SyncDataStatus syncDataStatus) {
+        return Result.success(syncDataStatusService.update(syncDataStatus));
+    }
+
+    /**
+     * 删除数据同步状态记录
+     */
+    @PostMapping("/delete-syncDataStatus")
+    public Result<Integer> remove(@RequestBody String[] ids) {
+        return Result.success(syncDataStatusService.deleteByIDs(ids));
+    }
+
+    /**
+    * 导入 数据同步状态记录
+    * @param file
+    * @param updateSupport
+    * @return
+    * @throws Exception
+    */
+    @PostMapping("/import-syncDataStatus")
+    public Result<String> importData(MultipartFile file, boolean updateSupport) throws Exception
+    {
+        CacpTransUser user = UserContextHolder.currentUser();
+        ExcelUtil<SyncDataStatus> util = new ExcelUtil<SyncDataStatus>(SyncDataStatus.class);
+        List<SyncDataStatus> syncDataStatusList = util.importExcel(file.getInputStream());
+        String message = syncDataStatusService.importSyncDataStatus(syncDataStatusList, updateSupport, user);
+        return Result.success(message);
+    }
+
+    /**
+     * 导出数据同步状态记录列表
+     */
+    @PostMapping("/get-syncDataStatus-export")
+    public void export(HttpServletResponse response, @RequestBody SyncDataStatusQuery query) {
+        List<SyncDataStatus> list = syncDataStatusService.selectList(query);
+        ExcelUtil<SyncDataStatus> util = new ExcelUtil<SyncDataStatus>(SyncDataStatus. class);
+        util.exportExcel(response, list, "数据同步状态记录数据");
+    }
+
+    /**
+    * 获取导入模板
+    * @param response
+    */
+    @PostMapping("/template-syncDataStatus")
+    public void importTemplate(HttpServletResponse response)
+    {
+        ExcelUtil<SyncDataStatus> util = new ExcelUtil<SyncDataStatus>(SyncDataStatus.class);
+        util.importTemplateExcel(response, "数据同步状态记录");
+    }
+}

+ 22 - 0
wxjy-wxjy-service/src/main/java/cn/gov/customs/wxjy/task/controller/TaskLogController.java

@@ -7,6 +7,8 @@ import cn.gov.customs.cacp.sdks.core.result.Result;
 import cn.gov.customs.cacp.sdks.core.user.trans.CacpTransUser;
 import cn.gov.customs.cacp.sdks.core.user.trans.UserContextHolder;
 import cn.gov.customs.wxjy.common.utils.StringUtils;
+import cn.gov.customs.wxjy.ibmmq.enums.BillTypeEnum;
+import cn.gov.customs.wxjy.task.ScheduledTasks;
 import lombok.RequiredArgsConstructor;
 import org.springframework.web.bind.annotation.*;
 import cn.gov.customs.wxjy.common.core.controller.BaseController;
@@ -32,6 +34,8 @@ public class TaskLogController extends BaseController {
 
     private final ITaskLogService taskLogService;
 
+    private final ScheduledTasks scheduledTasks;
+
     /**
      * 查询定时任务执行时间记录列表
      */
@@ -73,4 +77,22 @@ public class TaskLogController extends BaseController {
     public Result<Integer> remove(@RequestBody String[] ids) {
         return Result.success(taskLogService.deleteByPkTaskLogs(ids));
     }
+
+    /**
+     * 收到触发数据同步,推送到企业操作
+     * @param businessType 模块类型
+     */
+    @PostMapping("/scheduled-task")
+    public void remove(@RequestBody String businessType) {
+        if(businessType.equals(BillTypeEnum.BUS_TYPE_PACK_CATALOG.getCode())){
+            //包装种类
+            scheduledTasks.schedulePackCatalogTask();
+        }else if(businessType.equals(BillTypeEnum.BUS_TYPE_CHEMICALS_CATALOG.getCode())){
+            //危化品
+            scheduledTasks.scheduleChemicalsCatalogTask();
+        }else if(businessType.equals(BillTypeEnum.BUS_TYPE_GOODS_CATALOG.getCode())){
+            //危险货物
+            scheduledTasks.scheduleGoodsCatalogTask();
+        }
+    }
 }

+ 79 - 0
wxjy-wxjy-service/src/main/java/cn/gov/customs/wxjy/task/dao/SyncDataStatusMapper.java

@@ -0,0 +1,79 @@
+package cn.gov.customs.wxjy.task.dao;
+
+import java.util.Date;
+import java.util.List;
+
+import org.apache.ibatis.annotations.Mapper;
+import cn.gov.customs.wxjy.task.pojo.SyncDataStatus;
+import cn.gov.customs.wxjy.task.pojo.SyncDataStatusQuery;
+
+/**
+ * 数据同步状态记录Mapper接口
+ *
+ * @author xiong
+ * @date 2025-12-19
+ */
+@Mapper
+public interface SyncDataStatusMapper {
+    /**
+     * 查询数据同步状态记录
+     *
+     * @param ID 数据同步状态记录主键
+     * @return 数据同步状态记录
+     */
+    public SyncDataStatus selectByID(String ID);
+
+    /**
+     * 查询数据同步状态记录列表
+     *
+     * @param syncDataStatus 数据同步状态记录
+     * @return 数据同步状态记录集合
+     */
+    public List<SyncDataStatus> selectList(SyncDataStatusQuery syncDataStatus);
+
+    /**
+     * 新增数据同步状态记录
+     *
+     * @param syncDataStatus 数据同步状态记录
+     * @return 结果
+     */
+    public int insert(SyncDataStatus syncDataStatus);
+
+    /**
+     * 修改数据同步状态记录
+     *
+     * @param syncDataStatus 数据同步状态记录
+     * @return 结果
+     */
+    public int update(SyncDataStatus syncDataStatus);
+
+    /**
+     * 删除数据同步状态记录
+     *
+     * @param ID 数据同步状态记录主键
+     * @return 结果
+     */
+    public int deleteByID(String ID);
+
+    /**
+     * 批量删除数据同步状态记录
+     *
+     * @param IDs 需要删除的数据主键集合
+     * @return 结果
+     */
+    public int deleteByIDs(String[] IDs);
+
+    /**
+     * 逻辑删除数据同步状态记录
+     *
+     * @param ID 数据同步状态记录主键
+     * @return 结果
+     */
+    public int logicDelete(String ID);
+
+    List<String> selectDataIdsByBusinessType(String businessType);
+
+    SyncDataStatus selectByBusinessAndDataId(String businessType, String businessId);
+
+    void updateSyncTime(String businessType, String businessId, Date syncTime);
+}

+ 38 - 0
wxjy-wxjy-service/src/main/java/cn/gov/customs/wxjy/task/pojo/SyncDataStatus.java

@@ -0,0 +1,38 @@
+package cn.gov.customs.wxjy.task.pojo;
+
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
+import lombok.Data;
+import cn.gov.customs.wxjy.common.annotation.Excel;
+import cn.gov.customs.wxjy.common.core.domain.BaseEntity;
+
+/**
+ * 数据同步状态记录对象 WXJY_SYNC_DATA_STATUS
+ *
+ * @author xiong
+ * @date 2025-12-19
+ */
+@Data
+public class SyncDataStatus extends BaseEntity {
+private static final long serialVersionUID = 1L;
+
+    /** 主键ID */
+    private String ID;
+
+    /** 业务类型 */
+    @Excel(name = "业务类型")
+    private String businessType;
+
+    /** 数据ID */
+    @Excel(name = "数据ID")
+    private String businessId;
+
+    /** 同步时间 */
+    @Excel(name = "同步时间")
+    private String syncTime;
+
+    /** 同步版本 */
+    @Excel(name = "同步版本")
+    private String syncVersion;
+
+}

+ 40 - 0
wxjy-wxjy-service/src/main/java/cn/gov/customs/wxjy/task/pojo/SyncDataStatusQuery.java

@@ -0,0 +1,40 @@
+package cn.gov.customs.wxjy.task.pojo;
+
+import cn.gov.customs.wxjy.common.core.domain.BaseEntity;
+import lombok.Data;
+import java.io.Serializable;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import java.util.Date;
+
+/**
+ * 数据同步状态记录对象 WXJY_SYNC_DATA_STATUS
+ *
+ * @author xiong
+ * @date 2025-12-19
+ */
+@Data
+public class SyncDataStatusQuery extends BaseEntity {
+
+    private static final long serialVersionUID = 1L;
+
+    /** 主键ID */
+    private String ID;
+
+    /** 业务类型 */
+    private String businessType;
+
+    /** 数据ID */
+    private String businessId;
+
+    /** 同步时间 */
+    private String syncTime;
+
+    /** 同步版本 */
+    private String syncVersion;
+
+
+    private String beginDate;
+    private String endDate;
+    private int pageIndex;
+    private int pageSize;
+}

+ 89 - 0
wxjy-wxjy-service/src/main/java/cn/gov/customs/wxjy/task/service/ISyncDataStatusService.java

@@ -0,0 +1,89 @@
+package cn.gov.customs.wxjy.task.service;
+
+import java.util.List;
+import cn.gov.customs.cacp.sdks.core.user.trans.CacpTransUser;
+import cn.gov.customs.wxjy.task.pojo.SyncDataStatus;
+import cn.gov.customs.wxjy.task.pojo.SyncDataStatusQuery;
+import com.github.pagehelper.PageInfo;
+
+/**
+ * 数据同步状态记录Service接口
+ *
+ * @author xiong
+ * @date 2025-12-19
+ */
+public interface ISyncDataStatusService {
+    /**
+     * 查询数据同步状态记录
+     *
+     * @param ID 数据同步状态记录主键
+     * @return 数据同步状态记录
+     */
+    public SyncDataStatus selectByID(String ID);
+
+    /**
+     * 分页查询数据同步状态记录列表
+     *
+     * @param query
+     * @return 数据同步状态记录集合
+     */
+    public PageInfo<SyncDataStatus> selectPageList(SyncDataStatusQuery query);
+
+    /**
+     * 查询数据同步状态记录列表
+     *
+     * @param query
+     * @return 数据同步状态记录集合
+     */
+    public List<SyncDataStatus> selectList(SyncDataStatusQuery query);
+
+    /**
+     * 新增数据同步状态记录
+     *
+     * @param syncDataStatus 数据同步状态记录
+     * @return 结果
+     */
+    public int insert(SyncDataStatus syncDataStatus);
+
+    /**
+     * 修改数据同步状态记录
+     *
+     * @param syncDataStatus 数据同步状态记录
+     * @return 结果
+     */
+    public int update(SyncDataStatus syncDataStatus);
+
+    /**
+     * 批量删除数据同步状态记录
+     *
+     * @param ids 需要删除的ids主键集合
+     * @return 结果
+     */
+    public int deleteByIDs(String[] ids);
+
+    /**
+     * 删除数据同步状态记录信息
+     *
+     * @param ID 数据同步状态记录主键
+     * @return 结果
+     */
+    public int deleteByID(String ID);
+
+    /**
+     * 逻辑删除数据同步状态记录信息
+     *
+     * @param ID 数据同步状态记录主键
+     * @return 结果
+     */
+    public int logicDelete(String ID);
+
+    /**
+     * 导入数据同步状态记录数据
+     *
+     * @param syncDataStatusList 数据同步状态记录数据列表
+     * @param isUpdateSupport 是否更新支持,如果已存在,则进行更新数据
+     * @param cacpTransUser 操作用户
+     * @return 结果
+     */
+    public String importSyncDataStatus(List<SyncDataStatus> syncDataStatusList, Boolean isUpdateSupport, CacpTransUser cacpTransUser);
+}

+ 171 - 0
wxjy-wxjy-service/src/main/java/cn/gov/customs/wxjy/task/service/impl/SyncDataStatusServiceImpl.java

@@ -0,0 +1,171 @@
+package cn.gov.customs.wxjy.task.service.impl;
+
+import cn.gov.customs.cacp.sdks.core.user.trans.CacpTransUser;
+import cn.gov.customs.wxjy.common.exception.ServiceException;
+import cn.gov.customs.wxjy.common.utils.StringUtils;
+import cn.gov.customs.wxjy.common.utils.bean.BeanValidators;
+import cn.gov.customs.wxjy.common.utils.uuid.SnowflakeIdWorker;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import javax.validation.Validator;
+import java.util.List;
+import org.apache.commons.collections4.CollectionUtils;
+import cn.gov.customs.wxjy.common.utils.DateUtils;
+import com.github.pagehelper.PageInfo;
+import cn.gov.customs.wxjy.task.dao.SyncDataStatusMapper;
+import cn.gov.customs.wxjy.task.pojo.SyncDataStatus;
+import cn.gov.customs.wxjy.task.pojo.SyncDataStatusQuery;
+import cn.gov.customs.wxjy.task.service.ISyncDataStatusService;
+
+/**
+ * 数据同步状态记录Service业务层处理
+ *
+ * @author xiong
+ * @date 2025-12-19
+ */
+@Service
+@Slf4j
+@RequiredArgsConstructor
+public class SyncDataStatusServiceImpl implements ISyncDataStatusService {
+
+    private final SyncDataStatusMapper syncDataStatusMapper;
+
+    private final Validator validator;
+
+    /**
+     * 查询数据同步状态记录
+     *
+     * @param ID 数据同步状态记录主键
+     * @return 数据同步状态记录
+     */
+    @Override
+    public SyncDataStatus selectByID(String ID) {
+        return syncDataStatusMapper.selectByID(ID);
+    }
+
+    /**
+     * 分页查询数据同步状态记录列表
+     *
+     * @param query
+     * @return 数据同步状态记录
+     */
+    @Override
+    public PageInfo<SyncDataStatus> selectPageList(SyncDataStatusQuery query) {
+        return PageInfo.of(syncDataStatusMapper.selectList(query));
+    }
+
+    /**
+     * 查询数据同步状态记录列表
+     *
+     * @param query
+     * @return 数据同步状态记录
+     */
+    @Override
+    public List<SyncDataStatus> selectList(SyncDataStatusQuery query) {
+        return syncDataStatusMapper.selectList(query);
+    }
+
+    /**
+     * 新增数据同步状态记录
+     *
+     * @param syncDataStatus 数据同步状态记录
+     * @return 结果
+     */
+    @Override
+    public int insert(SyncDataStatus syncDataStatus) {
+            return syncDataStatusMapper.insert(syncDataStatus);
+    }
+
+    /**
+     * 修改数据同步状态记录
+     *
+     * @param syncDataStatus 数据同步状态记录
+     * @return 结果
+     */
+    @Override
+    public int update(SyncDataStatus syncDataStatus) {
+        return syncDataStatusMapper.update(syncDataStatus);
+    }
+
+    /**
+     * 批量删除数据同步状态记录
+     *
+     * @param ids 需要删除的数据同步状态记录主键
+     * @return 结果
+     */
+    @Override
+    public int deleteByIDs(String[] ids) {
+        return syncDataStatusMapper.deleteByIDs(ids);
+    }
+
+    /**
+     * 删除数据同步状态记录信息
+     *
+     * @param ID 数据同步状态记录主键
+     * @return 结果
+     */
+    @Override
+    public int deleteByID(String ID) {
+        return syncDataStatusMapper.deleteByID(ID);
+    }
+
+    /**
+     * 逻辑删除数据同步状态记录信息
+     *
+     * @param ID 数据同步状态记录主键
+     * @return 结果
+     */
+    @Override
+    public int logicDelete(String ID) {
+
+        return syncDataStatusMapper.logicDelete(ID);
+    }
+
+    /**
+     * 导入数据同步状态记录数据
+     *
+     * @param syncDataStatusList 数据同步状态记录数据列表
+     * @param isUpdateSupport 是否更新支持,如果已存在,则进行更新数据
+     * @param cacpTransUser 操作用户
+     * @return 结果
+     */
+    @Override
+    public String importSyncDataStatus(List<SyncDataStatus> syncDataStatusList, Boolean isUpdateSupport, CacpTransUser cacpTransUser) {
+        if (CollectionUtils.isEmpty(syncDataStatusList)) {
+            throw new ServiceException("导入数据不能为空!");
+        }
+        int successNum = 0;
+        int failureNum = 0;
+        StringBuilder successMsg = new StringBuilder();
+        StringBuilder failureMsg = new StringBuilder();
+        for (SyncDataStatus syncDataStatus : syncDataStatusList) {
+            try {
+
+                BeanValidators.validateWithException(validator, syncDataStatus);
+                //id名称不统一,自行处理
+                syncDataStatus.setCreateTime(DateUtils.getNowDate());
+                syncDataStatus.setUpdateTime(DateUtils.getNowDate());
+                syncDataStatus.setCreateUser(cacpTransUser.getUserId());
+                syncDataStatus.setCreateDept(cacpTransUser.getParentGuid());
+
+                syncDataStatusMapper.insert(syncDataStatus);
+                successNum++;
+                successMsg.append("<br/>" + successNum + "、 " + cacpTransUser.getUserName() + " 导入成功");
+
+            } catch (Exception e) {
+                failureNum++;
+                String msg = "<br/>" + failureNum + "、" + cacpTransUser.getUserName() + " 导入失败:";
+                failureMsg.append(msg + e.getMessage());
+                log.error(msg, e);
+            }
+        }
+        if (failureNum > 0) {
+            failureMsg.insert(0, "很抱歉,导入失败!共 " + failureNum + " 条数据格式不正确,错误如下:");
+            throw new ServiceException(failureMsg.toString());
+        } else {
+            successMsg.insert(0, "恭喜您,数据已全部导入成功!共 " + successNum + " 条,数据如下:");
+        }
+        return successMsg.toString();
+    }
+}

+ 127 - 0
wxjy-wxjy-service/src/main/resources/mapper/task/SyncDataStatusMapper.xml

@@ -0,0 +1,127 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="cn.gov.customs.wxjy.task.dao.SyncDataStatusMapper">
+
+    <resultMap type="SyncDataStatus" id="SyncDataStatusResult">
+        <result property="ID" column="ID"/>
+        <result property="businessType" column="BUSINESS_TYPE"/>
+        <result property="businessId" column="BUSINESS_ID"/>
+        <result property="syncTime" column="SYNC_TIME"/>
+        <result property="syncVersion" column="SYNC_VERSION"/>
+        <result property="isDeleted" column="IS_DELETED"/>
+    </resultMap>
+
+    <sql id="baseVo">
+        select ID, BUSINESS_TYPE, BUSINESS_ID, SYNC_TIME, SYNC_VERSION, IS_DELETED
+        from WXJY_SYNC_DATA_STATUS
+    </sql>
+
+    <select id="selectList" parameterType="SyncDataStatusQuery" resultMap="SyncDataStatusResult">
+        <include refid="baseVo"/>
+        <where>
+        <if test="businessType != null  and businessType != ''">
+            and BUSINESS_TYPE = #{businessType}
+        </if>
+        <if test="businessId != null  and businessId != ''">
+            and BUSINESS_ID = #{businessId}
+        </if>
+        <if test="syncTime != null  and syncTime != ''">
+            and SYNC_TIME = #{syncTime}
+        </if>
+        <if test="syncVersion != null  and syncVersion != ''">
+            and SYNC_VERSION = #{syncVersion}
+        </if>
+        <if test="isDeleted != null  and isDeleted != ''">
+            and IS_DELETED = #{isDeleted}
+        </if>
+        </where>
+    </select>
+
+    <select id="selectByID" parameterType="String"
+        resultMap="SyncDataStatusResult">
+        <include refid="baseVo"/>
+        where ID = #{ID}
+    </select>
+    <select id="selectDataIdsByBusinessType" resultType="java.lang.String">
+        select BUSINESS_ID from WXJY_SYNC_DATA_STATUS where BUSINESS_TYPE = #{businessType} and IS_DELETED = 0
+    </select>
+    <select id="selectByBusinessAndDataId" resultType="cn.gov.customs.wxjy.task.pojo.SyncDataStatus">
+        <include refid="baseVo"/> where BUSINESS_TYPE = #{businessType} and BUSINESS_ID = #{businessId}
+    </select>
+
+    <insert id="insert" parameterType="SyncDataStatus">
+        insert into WXJY_SYNC_DATA_STATUS
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="ID != null and ID != ''">ID,
+            </if>
+            <if test="businessType != null and businessType != ''">BUSINESS_TYPE,
+            </if>
+            <if test="businessId != null and businessId != ''">BUSINESS_ID,
+            </if>
+            <if test="syncTime != null and syncTime != ''">SYNC_TIME,
+            </if>
+            <if test="syncVersion != null">SYNC_VERSION,
+            </if>
+            <if test="isDeleted != null">IS_DELETED,
+            </if>
+        </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="ID != null and ID != ''">#{ID},
+            </if>
+            <if test="businessType != null and businessType != ''">#{businessType},
+            </if>
+            <if test="businessId != null and businessId != ''">#{businessId},
+            </if>
+            <if test="syncTime != null and syncTime != ''">#{syncTime},
+            </if>
+            <if test="syncVersion != null">#{syncVersion},
+            </if>
+            <if test="isDeleted != null">#{isDeleted},
+            </if>
+        </trim>
+    </insert>
+
+    <update id="update" parameterType="SyncDataStatus">
+        update WXJY_SYNC_DATA_STATUS
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="businessType != null and businessType != ''">BUSINESS_TYPE =
+                #{businessType},
+            </if>
+            <if test="businessId != null and businessId != ''">BUSINESS_ID =
+                #{businessId},
+            </if>
+            <if test="syncTime != null and syncTime != ''">SYNC_TIME =
+                #{syncTime},
+            </if>
+            <if test="syncVersion != null">SYNC_VERSION =
+                #{syncVersion},
+            </if>
+            <if test="isDeleted != null">IS_DELETED =
+                #{isDeleted},
+            </if>
+        </trim>
+        where ID = #{ID}
+    </update>
+    <update id="updateSyncTime">
+        UPDATE WXJY_SYNC_DATA_STATUS SET sync_time = #{syncTime}, sync_version = sync_version + 1
+            WHERE business_type = #{businessType} AND BUSINESS_ID = #{businessId}
+    </update>
+
+    <delete id="deleteByID" parameterType="String">
+        delete
+        from WXJY_SYNC_DATA_STATUS where ID = #{ID}
+    </delete>
+
+    <delete id="deleteByIDs" parameterType="String">
+        delete from WXJY_SYNC_DATA_STATUS where ID in
+        <foreach item="ID" collection="array" open="(" separator="," close=")">
+            #{ID}
+        </foreach>
+    </delete>
+
+    <delete id="logicDelete" parameterType="String">
+        update  WXJY_SYNC_DATA_STATUS set is_del = 1  where ID = #{ID}
+    </delete>
+</mapper>

+ 9 - 0
wxjy-wxjy-web/src/apis/base/TaskLog.ts

@@ -0,0 +1,9 @@
+import request from '@/utils/request'
+
+const contextPath = '/task/TaskLog'
+
+// 手动触发同步操作
+export async function scheduledTask(businessType: string) {
+  await request.post(`${contextPath}/scheduled-task`, businessType)
+}
+

+ 13 - 0
wxjy-wxjy-web/src/views/base/PackCatalog.vue

@@ -113,6 +113,7 @@ import {
 import type { PackCatalog, PackCatalogQuery } from '@/types/base/PackCatalog'
 import { getList } from '@/apis/base/PackCatalog'
 import { permissionStatus } from '@/utils/globalPermission'
+import { scheduledTask } from '@/apis/base/TaskLog'
 
 // 表单引用
 const queryFormRef = ref<SearchPanelLayoutInstance>()
@@ -168,6 +169,13 @@ const state = reactive<State>({
 
 // 表格操作按钮配置
 const actions = <Array<TableAction>>[
+  {
+    key: 'syncBaseData',
+    text: '数据同步',
+    onclick: onSyncData,
+    limit: 'none',
+    type: 'primary'
+  },
   {
     key: 'view',
     text: '查看',
@@ -218,6 +226,11 @@ function onView(row: PackCatalog) {
   state.viewTitle = '包装类型详情'
 }
 
+//数据同步
+async function onSyncData() {
+  await scheduledTask("8")
+}
+
 // 数据查询
 async function onLoadData() {
   setLoading(true)