diff --git a/jeelowcode-admin/src/test/java/com/jeelowcode/test/alibaba/WorkOrderSimpleTest.java b/jeelowcode-admin/src/test/java/com/jeelowcode/test/alibaba/WorkOrderSimpleTest.java new file mode 100644 index 0000000..332fcd4 --- /dev/null +++ b/jeelowcode-admin/src/test/java/com/jeelowcode/test/alibaba/WorkOrderSimpleTest.java @@ -0,0 +1,19 @@ +package com.jeelowcode.test.alibaba; + +import com.jeelowcode.module.biz.job.AlibabaWorkOrderJob; +import com.jeelowcode.tool.framework.test.core.ut.BaseDbAndRedisUnitTest; +import org.junit.jupiter.api.Test; + +import javax.annotation.Resource; + +public class WorkOrderSimpleTest extends BaseDbAndRedisUnitTest { + + @Resource + private AlibabaWorkOrderJob alibabaWorkOrderJob; + + @Test + public void testBuildSql() { + System.out.println(alibabaWorkOrderJob.buildSql(null, null)); + } + +} diff --git a/jeelowcode-module/jeelowcode-module-biz/src/main/java/com/jeelowcode/module/biz/entity/AlibabaWorkOrder.java b/jeelowcode-module/jeelowcode-module-biz/src/main/java/com/jeelowcode/module/biz/entity/AlibabaWorkOrder.java new file mode 100644 index 0000000..c541747 --- /dev/null +++ b/jeelowcode-module/jeelowcode-module-biz/src/main/java/com/jeelowcode/module/biz/entity/AlibabaWorkOrder.java @@ -0,0 +1,157 @@ +package com.jeelowcode.module.biz.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.jeelowcode.framework.utils.model.global.BaseTenantEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.time.LocalDateTime; + +/** + * 阿里工单实体类 + *

+ * 用于存储和管理阿里平台产生的工单信息,包括检查项、整改要求、责任人等相关信息 + * + * @author yangchenjj + */ +@Data +@EqualsAndHashCode +@TableName("lc_alibaba_work_order") +public class AlibabaWorkOrder extends BaseTenantEntity { + + /** + * 主键 + */ + @TableId(value = "id", type = IdType.ASSIGN_ID) + private Long id; + + /** + * 阿里工单ID + */ + @TableField("work_order_id") + private String workOrderId; + + /** + * 园区ID + */ + @TableField("campus_id") + private String campusId; + + /** + * 园区名称 + */ + @TableField("campus_name") + private String campusName; + + /** + * 工单等级 + */ + @TableField("work_order_level") + private String workOrderLevel; + + /** + * 检查区域 + */ + @TableField("check_area") + private String checkArea; + + /** + * 检查项 + */ + @TableField("check_item") + private String checkItem; + + /** + * 检查内容 + */ + @TableField("check_content") + private String checkContent; + + /** + * 检查人ID + */ + @TableField("check_person_id") + private String checkPersonId; + + /** + * 检查人姓名 + */ + @TableField("check_person_name") + private String checkPersonName; + + /** + * 检查时间 + */ + @TableField("check_time") + private LocalDateTime checkTime; + + /** + * 检查发现的问题 + */ + @TableField("check_question") + private String checkQuestion; + + /** + * 整改截止时间 + */ + @TableField("correct_deadline") + private LocalDateTime correctDeadline; + + /** + * 整改责任人ID + */ + @TableField("correct_person_id") + private String correctPersonId; + + /** + * 整改责任人姓名 + */ + @TableField("correct_person_name") + private String correctPersonName; + + /** + * 整改措施 + */ + @TableField("correct_action") + private String correctAction; + + /** + * 确认人ID + */ + @TableField("confirm_person_id") + private String confirmPersonId; + + /** + * 确认人姓名 + */ + @TableField("confirm_person_name") + private String confirmPersonName; + + /** + * 修改时间 + */ + @TableField("gmt_modified") + private LocalDateTime gmtModified; + + /** + * 子表修改时间 + */ + @TableField("gmt_sub_modified") + private LocalDateTime gmtSubModified; + + /** + * 关联数据修改时间 + */ + @TableField("gmt_relate_modified") + private LocalDateTime gmtRelateModified; + + /** + * 关联子表修改时间 + */ + @TableField("gmt_relate_sub_modified") + private LocalDateTime gmtRelateSubModified; + +} \ No newline at end of file diff --git a/jeelowcode-module/jeelowcode-module-biz/src/main/java/com/jeelowcode/module/biz/job/AlibabaWorkOrderJob.java b/jeelowcode-module/jeelowcode-module-biz/src/main/java/com/jeelowcode/module/biz/job/AlibabaWorkOrderJob.java new file mode 100644 index 0000000..c752ef2 --- /dev/null +++ b/jeelowcode-module/jeelowcode-module-biz/src/main/java/com/jeelowcode/module/biz/job/AlibabaWorkOrderJob.java @@ -0,0 +1,514 @@ +package com.jeelowcode.module.biz.job; + +import cn.hutool.core.date.LocalDateTimeUtil; +import com.baomidou.dynamic.datasource.DynamicRoutingDataSource; +import com.jeelowcode.module.biz.entity.AlibabaWorkOrder; +import com.jeelowcode.module.biz.service.IAlibabaWorkOrderService; +import com.jeelowcode.tool.framework.quartz.core.handler.JobHandler; +import com.jeelowcode.tool.framework.tenant.core.job.TenantJob; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import javax.sql.DataSource; +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +import static com.jeelowcode.tool.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +/** + * 从阿里巴巴工单同步任务(包含查询、清洗) + */ +@Slf4j +@Component +public class AlibabaWorkOrderJob implements JobHandler { + + /** + * 阿里数据源名称 + */ + private static final String ALIBABA_DATASOURCE_NAME = "alidb"; + + @Resource + private IAlibabaWorkOrderService workOrderService; + + @Resource + private DynamicRoutingDataSource dynamicRoutingDataSource; + + @Override + @TenantJob + public String execute(String param) throws Exception { + // 拿到系统中的所有的数据源,检查是否有阿里的数据源 + Map dataSources = dynamicRoutingDataSource.getDataSources(); + if (!dataSources.containsKey(ALIBABA_DATASOURCE_NAME)) { + log.error("未找到阿里数据源,请检查数据源配置"); + return "未找到阿里数据源,请检查数据源配置"; + } + // 查询我数据库中最新的时间点 + LocalDateTime maxWorkOrderTime = workOrderService.getMaxWorkOrderTime(); + StringBuilder sqlBuilder = new StringBuilder(); + if (maxWorkOrderTime == null) { + sqlBuilder.append(buildSql(null, null)); + } else { + LocalDateTime endTime = LocalDateTimeUtil.endOfDay(LocalDateTime.now()); + sqlBuilder.append(buildSql(maxWorkOrderTime, endTime)); + } + // 执行SQL查询数据 + DataSource dataSource = dataSources.get(ALIBABA_DATASOURCE_NAME); + try (Connection connection = dataSource.getConnection(); + ResultSet resultSet = connection.createStatement().executeQuery(sqlBuilder.toString())) { + // 使用连接执行SQL并得到结果 + List workOrderList = new ArrayList<>(); + // 将resultSet解析成List list + while (resultSet.next()) { + AlibabaWorkOrder workOrder = new AlibabaWorkOrder(); + workOrder.setId(resultSet.getLong("id")); + workOrder.setWorkOrderId(resultSet.getString("workOrderId")); + workOrder.setCampusId(resultSet.getString("campusId")); + workOrder.setCampusName(resultSet.getString("campusName")); + workOrder.setCheckArea(resultSet.getString("checkArea")); + workOrder.setCheckItem(resultSet.getString("checkItem")); + workOrder.setCheckContent(resultSet.getString("checkContent")); + workOrder.setCheckPersonId(resultSet.getString("checkPersonId")); + workOrder.setCheckPersonName(resultSet.getString("checkPersonName")); + workOrder.setCheckTime(resultSet.getObject("checkTime", LocalDateTime.class)); + workOrder.setCheckQuestion(resultSet.getString("checkQuestion")); + workOrder.setCorrectAction(resultSet.getString("correctAction")); + workOrder.setCorrectPersonId(resultSet.getString("correctPersonId")); + workOrder.setCorrectPersonName(resultSet.getString("correctPersonName")); + workOrder.setWorkOrderLevel(resultSet.getString("workOrderLevel")); + workOrder.setCorrectDeadline(resultSet.getObject("correctDeadline", LocalDateTime.class)); + workOrder.setConfirmPersonId(resultSet.getString("confirmPersonId")); + workOrder.setConfirmPersonName(resultSet.getString("confirmPersonName")); + workOrder.setGmtModified(resultSet.getObject("gmtModified", LocalDateTime.class)); + workOrder.setGmtSubModified(resultSet.getObject("gmtSubModified", LocalDateTime.class)); + workOrder.setGmtRelateModified(resultSet.getObject("gmtRelateModified", LocalDateTime.class)); + workOrder.setGmtRelateSubModified(resultSet.getObject("gmtRelateSubModified", LocalDateTime.class)); + workOrderList.add(workOrder); + } + + // 解析得到的数据由服务存储到数据库 + int num = workOrderService.batchSaveWorkOrder(workOrderList); + log.info("同步阿里工单完成,共处理{}条数据", workOrderList.size()); + log.info("同步阿里工单完成,共成功{}条数据", num); + return "同步阿里工单完成,共处理" + num + "条数据"; + } catch (SQLException e) { + log.error("执行SQL查询或解析ResultSet异常", e); + throw e; + } + } + + /** + * 构建查询SQL + * + * @param startTime 开始时间 + * @param endTime 结束时间 + * @return SQL + */ + public static String buildSql(LocalDateTime startTime, LocalDateTime endTime) { + StringBuilder sqlBuilder = new StringBuilder(); + sqlBuilder.append("SELECT\n" + + " mwoe.ID AS \"id\",\n" + + " mwoe.WORK_ORDER_ID AS \"workOrderId\",\n" + + " mwoe.CAMPUS_ID AS \"campusId\",\n" + + " mwoe.CAMPUS_NAME AS \"campusName\",\n" + + " mwoe.REMARK AS \"checkArea\",\n" + + " mwoe.OBJ_NAME AS \"checkItem\",\n" + + " mwoe.SUB_SOP_SCHEMA AS \"checkContent\",\n" + + " mwoe.CREATOR_ID AS \"checkPersonId\",\n" + + " mwoe.CREATOR_NAME AS \"checkPersonName\",\n" + + " mwoe.GMT_CREATE AS \"checkTime\",\n" + + " mwoe.PROCESS_CONTENT AS \"checkQuestion\",\n" + + " CONCAT_WS(',', rwoa.PROCESS_CONTENT, rwoa.SUB_SOP_SCHEMA) AS \"correctAction\",\n" + + " rwoa.PROCESSOR_ID AS \"correctPersonId\",\n" + + " rwoa.PROCESSOR_NAME AS \"correctPersonName\",\n" + + " mwoe.\"LEVEL\" AS \"workOrderLevel\",\n" + + " rwoa.RESERVED_TIME3 AS \"correctDeadline\",\n" + + " rwoa.CONFIRM_PERSON_ID AS \"confirmPersonId\",\n" + + " rwoa.CONFIRM_PERSON_NAME AS \"confirmPersonName\",\n" + + " mwoe.GMT_MODIFIED AS \"gmtModified\",\n" + + " mwoe.SUB_GMT_MODIFIED AS \"gmtSubModified\",\n" + + " rwoa.GMT_MODIFIED AS \"gmtRelateModified\",\n" + + " rwoa.SUB_GMT_MODIFIED AS \"gmtRelateSubModified\"\n" + + "FROM\n" + + " (\n" + + " SELECT\n" + + " mwo.*,\n" + + " swo.SOP_SCHEMA AS SUB_SOP_SCHEMA,\n" + + " swo.PROCESS_CONTENT AS SUB_PROCESS_CONTENT,\n" + + " swo.GMT_MODIFIED AS SUB_GMT_MODIFIED,\n" + + " swo.OBJ_NAME AS OBJ_NAME\n" + + " FROM\n" + + " (\n" + + " SELECT\n" + + " wo.ID,\n" + + " wo.WORK_ORDER_ID,\n" + + " wo.CAMPUS_ID,\n" + + " c.NAME AS CAMPUS_NAME,\n" + + " wo.REMARK,\n" + + " wo.CREATOR_ID,\n" + + " wo.CREATOR_NAME,\n" + + " wo.GMT_CREATE,\n" + + " wo.GMT_MODIFIED,\n" + + " wo.RESERVED_TIME3,\n" + + " CASE\n" + + " WHEN wo.\"LEVEL\" = 'P' THEN '重大'\n" + + " ELSE '一般'\n" + + " END AS \"LEVEL\",\n" + + " wo.\"CONFIRM_PERSON_ID\",\n" + + " wo.CONFIRM_PERSON_NAME,\n" + + " wo.TENANT,\n" + + " ml.PROCESSOR_ID,\n" + + " ml.PROCESSOR_NAME,\n" + + " JSON_VALUE(ml.CONTENT, '$.processedContent') AS PROCESS_CONTENT\n" + + " FROM\n" + + " \"XCAMPUS_WORKORDER\".\"WORK_ORDER\" wo\n" + + " LEFT JOIN (\n" + + " SELECT\n" + + " *\n" + + " FROM\n" + + " \"XCAMPUS_WORKORDER\".\"WORK_ORDER_LOG\" wol\n" + + " WHERE\n" + + " wol.\"OPERATE_NAME\" = '完成'\n" + + " ) ml ON wo.\"WORK_ORDER_ID\" = ml.\"WORK_ORDER_ID\"\n" + + " LEFT JOIN \"XCAMPUS_SPACECENTER\".\"CAMPUS\" c ON c.UUID = wo.CAMPUS_ID\n" + + " WHERE\n" + + " wo.PARENT_ID IS NULL\n" + + " AND wo.ORDER_TYPE_PATH_NAME = '风险隐患'\n" + + " AND wo.TENANT = '1821414781587267584'\n" + + " AND EXISTS (\n" + + " SELECT\n" + + " 1\n" + + " FROM\n" + + " \"XCAMPUS_WORKORDER\".\"WORK_ORDER\" wo2\n" + + " WHERE\n" + + " wo.\"WORK_ORDER_ID\" = wo2.\"WORK_ORDER_ID\"\n" + + " AND wo2.\"RELATE_WORK_ORDER_ID\" IS NULL\n" + + " )\n" + + " ) mwo\n" + + " LEFT JOIN (\n" + + " SELECT\n" + + " wo.PARENT_ID,\n" + + " LISTAGG(\n" + + " REPLACE(\n" + + " REPLACE(\n" + + " JSON_QUERY(\n" + + " wos.SOP_SCHEMA,\n" + + " '$[0].sopSchema.componentsTree[0].children[0].children[*].props.label' WITH CONDITIONAL WRAPPER,\n" + + " '[',\n" + + " ']',\n" + + " ','\n" + + " ),\n" + + " ']',\n" + + " ''\n" + + " ),\n" + + " '[',\n" + + " ''\n" + + " ),\n" + + " ','\n" + + " ) WITHIN GROUP (\n" + + " ORDER BY\n" + + " wo.WORK_ORDER_ID\n" + + " ) AS SOP_SCHEMA,\n" + + " LISTAGG(\n" + + " REPLACE(\n" + + " REPLACE(\n" + + " JSON_QUERY(\n" + + " sl.CONTENT,\n" + + " '$.sopInfo.*' WITH CONDITIONAL WRAPPER,\n" + + " '[',\n" + + " ']',\n" + + " ','\n" + + " ),\n" + + " ']',\n" + + " ''\n" + + " ),\n" + + " '[',\n" + + " ''\n" + + " ),\n" + + " ','\n" + + " ) WITHIN GROUP (\n" + + " ORDER BY\n" + + " wo.WORK_ORDER_ID\n" + + " ) AS PROCESS_CONTENT,\n" + + " LISTAGG(OBJ_NAME, ',') WITHIN GROUP (\n" + + " ORDER BY\n" + + " wo.WORK_ORDER_ID\n" + + " ) AS OBJ_NAME,\n" + + " MAX(wo.GMT_MODIFIED) AS GMT_MODIFIED\n" + + " FROM\n" + + " \"XCAMPUS_WORKORDER\".\"WORK_ORDER\" wo\n" + + " LEFT JOIN (\n" + + " SELECT\n" + + " *\n" + + " FROM\n" + + " \"XCAMPUS_WORKORDER\".\"WORK_ORDER_LOG\" wol\n" + + " WHERE\n" + + " wol.\"OPERATE_NAME\" = '处理'\n" + + " ) sl ON wo.\"WORK_ORDER_ID\" = sl.\"WORK_ORDER_ID\"\n" + + " LEFT JOIN \"XCAMPUS_WORKORDER\".\"WORK_ORDER_SCHEMA\" wos ON wo.\"WORK_ORDER_ID\" = wos.\"WORK_ORDER_ID\"\n" + + " WHERE\n" + + " wo.PARENT_ID IN (\n" + + " SELECT\n" + + " WORK_ORDER_ID\n" + + " FROM\n" + + " \"XCAMPUS_WORKORDER\".\"WORK_ORDER\"\n" + + " WHERE\n" + + " ORDER_TYPE_PATH_NAME = '风险隐患'\n" + + " )\n" + + " AND wo.ORDER_TYPE_PATH_NAME = '系统默认子单类型'\n" + + " AND wo.TENANT = '1821414781587267584'\n" + + " GROUP BY\n" + + " wo.PARENT_ID\n" + + " ) swo ON mwo.WORK_ORDER_ID = swo.PARENT_ID\n" + + " ) mwoe\n" + + " LEFT JOIN (\n" + + " SELECT\n" + + " rwoe.\"RELATE_WORK_ORDER_ID\",\n" + + " LISTAGG(rwoe.\"PROCESS_CONTENT\", ',') WITHIN GROUP (\n" + + " ORDER BY\n" + + " rwoe.WORK_ORDER_ID\n" + + " ) AS PROCESS_CONTENT,\n" + + " LISTAGG(rwoe.SUB_PROCESS_CONTENT, ',') WITHIN GROUP (\n" + + " ORDER BY\n" + + " rwoe.WORK_ORDER_ID\n" + + " ) AS SUB_PROCESS_CONTENT,\n" + + " LISTAGG(rwoe.SUB_SOP_SCHEMA, ',') WITHIN GROUP (\n" + + " ORDER BY\n" + + " rwoe.WORK_ORDER_ID\n" + + " ) AS SUB_SOP_SCHEMA,\n" + + " LISTAGG(rwoe.PROCESSOR_ID, ',') WITHIN GROUP (\n" + + " ORDER BY\n" + + " rwoe.WORK_ORDER_ID\n" + + " ) AS PROCESSOR_ID,\n" + + " LISTAGG(rwoe.PROCESSOR_NAME, ',') WITHIN GROUP (\n" + + " ORDER BY\n" + + " rwoe.WORK_ORDER_ID\n" + + " ) AS PROCESSOR_NAME,\n" + + " LISTAGG(rwoe.CONFIRM_PERSON_ID, ',') WITHIN GROUP (\n" + + " ORDER BY\n" + + " rwoe.WORK_ORDER_ID\n" + + " ) AS CONFIRM_PERSON_ID,\n" + + " LISTAGG(rwoe.CONFIRM_PERSON_NAME, ',') WITHIN GROUP (\n" + + " ORDER BY\n" + + " rwoe.WORK_ORDER_ID\n" + + " ) AS CONFIRM_PERSON_NAME,\n" + + " MAX(rwoe.RESERVED_TIME3) AS RESERVED_TIME3,\n" + + " MAX(rwoe.GMT_MODIFIED) AS GMT_MODIFIED,\n" + + " MAX(rwoe.SUB_GMT_MODIFIED) AS SUB_GMT_MODIFIED\n" + + " FROM\n" + + " (\n" + + " SELECT\n" + + " rwo.*,\n" + + " swo.SOP_SCHEMA AS SUB_SOP_SCHEMA,\n" + + " swo.PROCESS_CONTENT AS SUB_PROCESS_CONTENT,\n" + + " swo.GMT_MODIFIED AS SUB_GMT_MODIFIED,\n" + + " swo.OBJ_NAME AS OBJ_NAME\n" + + " FROM\n" + + " (\n" + + " SELECT\n" + + " wo.ID,\n" + + " wo.WORK_ORDER_ID,\n" + + " wo.CAMPUS_ID,\n" + + " c.NAME AS CAMPUS_NAME,\n" + + " wo.REMARK,\n" + + " wo.CREATOR_ID,\n" + + " wo.CREATOR_NAME,\n" + + " wo.GMT_CREATE,\n" + + " wo.GMT_MODIFIED,\n" + + " wo.RESERVED_TIME3,\n" + + " CASE\n" + + " WHEN wo.\"LEVEL\" = 'P' THEN '重大'\n" + + " ELSE '一般'\n" + + " END AS \"LEVEL\",\n" + + " wo.\"CONFIRM_PERSON_ID\",\n" + + " wo.CONFIRM_PERSON_NAME,\n" + + " wo.TENANT,\n" + + " wo.RELATE_WORK_ORDER_ID,\n" + + " ml.PROCESSOR_ID,\n" + + " ml.PROCESSOR_NAME,\n" + + " JSON_VALUE(ml.CONTENT, '$.processedContent') AS PROCESS_CONTENT\n" + + " FROM\n" + + " \"XCAMPUS_WORKORDER\".\"WORK_ORDER\" wo\n" + + " LEFT JOIN (\n" + + " SELECT\n" + + " *\n" + + " FROM\n" + + " \"XCAMPUS_WORKORDER\".\"WORK_ORDER_LOG\" wol\n" + + " WHERE\n" + + " wol.\"OPERATE_NAME\" = '完成'\n" + + " ) ml ON wo.\"WORK_ORDER_ID\" = ml.\"WORK_ORDER_ID\"\n" + + " LEFT JOIN \"XCAMPUS_SPACECENTER\".\"CAMPUS\" c ON c.UUID = wo.CAMPUS_ID\n" + + " WHERE\n" + + " wo.PARENT_ID IS NULL\n" + + " AND wo.ORDER_TYPE_PATH_NAME = '风险隐患'\n" + + " AND wo.TENANT = '1821414781587267584'\n" + + " AND EXISTS (\n" + + " SELECT\n" + + " 1\n" + + " FROM\n" + + " \"XCAMPUS_WORKORDER\".\"WORK_ORDER\" wo2\n" + + " WHERE\n" + + " wo.\"WORK_ORDER_ID\" = wo2.\"WORK_ORDER_ID\"\n" + + " AND wo2.\"RELATE_WORK_ORDER_ID\" IS NOT NULL\n" + + " )\n" + + " ) rwo\n" + + " LEFT JOIN (\n" + + " SELECT\n" + + " wo.PARENT_ID,\n" + + " LISTAGG(\n" + + " REPLACE(\n" + + " REPLACE(\n" + + " JSON_QUERY(\n" + + " wos.SOP_SCHEMA,\n" + + " '$[0].sopSchema.componentsTree[0].children[0].children[*].props.label' WITH CONDITIONAL WRAPPER,\n" + + " '[',\n" + + " ']',\n" + + " ','\n" + + " ),\n" + + " ']',\n" + + " ''\n" + + " ),\n" + + " '[',\n" + + " ''\n" + + " ),\n" + + " ','\n" + + " ) WITHIN GROUP (\n" + + " ORDER BY\n" + + " wo.WORK_ORDER_ID\n" + + " ) AS SOP_SCHEMA,\n" + + " LISTAGG(\n" + + " REPLACE(\n" + + " REPLACE(\n" + + " JSON_QUERY(\n" + + " sl.CONTENT,\n" + + " '$.sopInfo.*' WITH CONDITIONAL WRAPPER,\n" + + " '[',\n" + + " ']',\n" + + " ','\n" + + " ),\n" + + " ']',\n" + + " ''\n" + + " ),\n" + + " '[',\n" + + " ''\n" + + " ),\n" + + " ','\n" + + " ) WITHIN GROUP (\n" + + " ORDER BY\n" + + " wo.WORK_ORDER_ID\n" + + " ) AS PROCESS_CONTENT,\n" + + " LISTAGG(OBJ_NAME, ',') WITHIN GROUP (\n" + + " ORDER BY\n" + + " wo.WORK_ORDER_ID\n" + + " ) AS OBJ_NAME,\n" + + " MAX(wo.GMT_MODIFIED) AS GMT_MODIFIED\n" + + " FROM\n" + + " \"XCAMPUS_WORKORDER\".\"WORK_ORDER\" wo\n" + + " LEFT JOIN (\n" + + " SELECT\n" + + " *\n" + + " FROM\n" + + " \"XCAMPUS_WORKORDER\".\"WORK_ORDER_LOG\" wol\n" + + " WHERE\n" + + " wol.\"OPERATE_NAME\" = '处理'\n" + + " ) sl ON wo.\"WORK_ORDER_ID\" = sl.\"WORK_ORDER_ID\"\n" + + " LEFT JOIN \"XCAMPUS_WORKORDER\".\"WORK_ORDER_SCHEMA\" wos ON wo.\"WORK_ORDER_ID\" = wos.\"WORK_ORDER_ID\"\n" + + " WHERE\n" + + " wo.PARENT_ID IN (\n" + + " SELECT\n" + + " WORK_ORDER_ID\n" + + " FROM\n" + + " \"XCAMPUS_WORKORDER\".\"WORK_ORDER\"\n" + + " WHERE\n" + + " ORDER_TYPE_PATH_NAME = '风险隐患'\n" + + " )\n" + + " AND wo.ORDER_TYPE_PATH_NAME = '系统默认子单类型'\n" + + " AND wo.TENANT = '1821414781587267584'\n" + + " GROUP BY\n" + + " wo.PARENT_ID\n" + + " ) swo ON rwo.WORK_ORDER_ID = swo.PARENT_ID\n" + + " ) rwoe\n" + + " GROUP BY\n" + + " rwoe.\"RELATE_WORK_ORDER_ID\"\n" + + " ) rwoa ON mwoe.WORK_ORDER_ID = rwoa.RELATE_WORK_ORDER_ID\n"); + // 如果时间参数存在并且合法,则添加时间条件 + if (Objects.nonNull(startTime) && Objects.nonNull(endTime) && startTime.isBefore(endTime)) { + String formattedStart = LocalDateTimeUtil.format(startTime, FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND); + String formattedEnd = LocalDateTimeUtil.format(endTime, FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND); + + sqlBuilder.append("WHERE\n" + + " (\n" + + " mwoe.GMT_MODIFIED BETWEEN TO_DATE(\n" + + " NVL(\n" + + " '" + formattedStart + "',\n" + + " TO_CHAR(SYSDATE, 'YYYY-MM-DD') || ' 00:00:00'\n" + + " ),\n" + + " 'YYYY-MM-DD HH24:MI:SS'\n" + + " )\n" + + " AND TO_DATE(\n" + + " NVL(\n" + + " '" + formattedEnd + "',\n" + + " TO_CHAR(SYSDATE, 'YYYY-MM-DD') || ' 23:59:59'\n" + + " ),\n" + + " 'YYYY-MM-DD HH24:MI:SS'\n" + + " )\n" + + " )\n" + + " OR (\n" + + " mwoe.SUB_GMT_MODIFIED BETWEEN TO_DATE(\n" + + " NVL(\n" + + " '" + formattedStart + "',\n" + + " TO_CHAR(SYSDATE, 'YYYY-MM-DD') || ' 00:00:00'\n" + + " ),\n" + + " 'YYYY-MM-DD HH24:MI:SS'\n" + + " )\n" + + " AND TO_DATE(\n" + + " NVL(\n" + + " '" + formattedEnd + "',\n" + + " TO_CHAR(SYSDATE, 'YYYY-MM-DD') || ' 23:59:59'\n" + + " ),\n" + + " 'YYYY-MM-DD HH24:MI:SS'\n" + + " )\n" + + " )\n" + + " OR (\n" + + " rwoa.GMT_MODIFIED BETWEEN TO_DATE(\n" + + " NVL(\n" + + " '" + formattedStart + "',\n" + + " TO_CHAR(SYSDATE, 'YYYY-MM-DD') || ' 00:00:00'\n" + + " ),\n" + + " 'YYYY-MM-DD HH24:MI:SS'\n" + + " )\n" + + " AND TO_DATE(\n" + + " NVL(\n" + + " '" + formattedEnd + "',\n" + + " TO_CHAR(SYSDATE, 'YYYY-MM-DD') || ' 23:59:59'\n" + + " ),\n" + + " 'YYYY-MM-DD HH24:MI:SS'\n" + + " )\n" + + " )\n" + + " OR (\n" + + " rwoa.SUB_GMT_MODIFIED BETWEEN TO_DATE(\n" + + " NVL(\n" + + " '" + formattedStart + "',\n" + + " TO_CHAR(SYSDATE, 'YYYY-MM-DD') || ' 00:00:00'\n" + + " ),\n" + + " 'YYYY-MM-DD HH24:MI:SS'\n" + + " )\n" + + " AND TO_DATE(\n" + + " NVL(\n" + + " '" + formattedEnd + "',\n" + + " TO_CHAR(SYSDATE, 'YYYY-MM-DD') || ' 23:59:59'\n" + + " ),\n" + + " 'YYYY-MM-DD HH24:MI:SS'\n" + + " )\n" + + " )"); + } + return sqlBuilder.toString(); + } + +} diff --git a/jeelowcode-module/jeelowcode-module-biz/src/main/java/com/jeelowcode/module/biz/mapper/AlibabaWorkOrderMapper.java b/jeelowcode-module/jeelowcode-module-biz/src/main/java/com/jeelowcode/module/biz/mapper/AlibabaWorkOrderMapper.java new file mode 100644 index 0000000..ee2dcae --- /dev/null +++ b/jeelowcode-module/jeelowcode-module-biz/src/main/java/com/jeelowcode/module/biz/mapper/AlibabaWorkOrderMapper.java @@ -0,0 +1,32 @@ +package com.jeelowcode.module.biz.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.jeelowcode.module.biz.entity.AlibabaWorkOrder; +import com.jeelowcode.tool.framework.mybatis.core.query.LambdaQueryWrapperX; + +import java.time.LocalDateTime; + +/** + * 阿里工单Mapper + */ +public interface AlibabaWorkOrderMapper extends BaseMapper { + + /** + * 根据工单ID查询工单信息 + * + * @param workOrderId 工单ID + * @return 工单信息 + */ + default AlibabaWorkOrder selectByWorkOrderId(String workOrderId) { + return selectOne(new LambdaQueryWrapperX() + .eq(AlibabaWorkOrder::getWorkOrderId, workOrderId)); + } + + /** + * 查询最大更新时间 + * + * @return 最大更新时间 + */ + LocalDateTime selectMaxUpdateTime(); + +} diff --git a/jeelowcode-module/jeelowcode-module-biz/src/main/java/com/jeelowcode/module/biz/service/IAlibabaWorkOrderService.java b/jeelowcode-module/jeelowcode-module-biz/src/main/java/com/jeelowcode/module/biz/service/IAlibabaWorkOrderService.java new file mode 100644 index 0000000..6e675ae --- /dev/null +++ b/jeelowcode-module/jeelowcode-module-biz/src/main/java/com/jeelowcode/module/biz/service/IAlibabaWorkOrderService.java @@ -0,0 +1,36 @@ +package com.jeelowcode.module.biz.service; + +import com.jeelowcode.module.biz.entity.AlibabaWorkOrder; + +import java.time.LocalDateTime; +import java.util.List; + +/** + * 阿里工单服务 + */ +public interface IAlibabaWorkOrderService { + + /** + * 保存阿里工单 + * + * @param workOrder 阿里工单 + * @return 影响行数 + */ + int saveWorkOrder(AlibabaWorkOrder workOrder); + + /** + * 批量保存阿里工单 + * + * @param workOrders 阿里工单 + * @return 影响行数 + */ + int batchSaveWorkOrder(List workOrders); + + /** + * 获取最大工单时间 + * + * @return 最大工单时间 + */ + LocalDateTime getMaxWorkOrderTime(); + +} diff --git a/jeelowcode-module/jeelowcode-module-biz/src/main/java/com/jeelowcode/module/biz/service/impl/AlibabaWorkOrderServiceImpl.java b/jeelowcode-module/jeelowcode-module-biz/src/main/java/com/jeelowcode/module/biz/service/impl/AlibabaWorkOrderServiceImpl.java new file mode 100644 index 0000000..0fc5069 --- /dev/null +++ b/jeelowcode-module/jeelowcode-module-biz/src/main/java/com/jeelowcode/module/biz/service/impl/AlibabaWorkOrderServiceImpl.java @@ -0,0 +1,97 @@ +package com.jeelowcode.module.biz.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.IdUtil; +import com.jeelowcode.module.biz.entity.AlibabaWorkOrder; +import com.jeelowcode.module.biz.mapper.AlibabaWorkOrderMapper; +import com.jeelowcode.module.biz.service.IAlibabaWorkOrderService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.time.LocalDateTime; +import java.util.List; +import java.util.Objects; + +/** + * 阿里工单服务实现类 + * + * @author yangchenjj + */ +@Slf4j +@Service +public class AlibabaWorkOrderServiceImpl implements IAlibabaWorkOrderService { + + @Resource + private AlibabaWorkOrderMapper baseMapper; + + /** + * 保存工单信息 + *

根据工单对象的状态和数据库中的现有记录,决定执行插入或更新操作

+ * + * @param workOrder 工单对象,包含要保存的工单信息 + * @return 返回操作影响的行数,0表示保存失败 + */ + @Override + public int saveWorkOrder(AlibabaWorkOrder workOrder) { + // 检查工单对象及工单ID是否为空 + if (Objects.isNull(workOrder)) return 0; + if (Objects.isNull(workOrder.getWorkOrderId())) return 0; + + // 判断工单ID是否为空,为空表示新增工单 + if (Objects.isNull(workOrder.getId())) { + // 先检查工单id是否有重复 + AlibabaWorkOrder dbWorkOrder = baseMapper.selectByWorkOrderId(workOrder.getWorkOrderId()); + if (Objects.nonNull(dbWorkOrder)) { + // 如果工单已存在,则更新工单信息 + return baseMapper.updateById(workOrder.setId(dbWorkOrder.getId())); + } else { + // 如果工单不存在,则插入新的工单信息 + return baseMapper.insert(workOrder.setId(IdUtil.getSnowflakeNextId())); + } + } else { + // 工单ID不为空,可能是更新操作 + + // 先确定数据库中是否有工单信息,如果有则更新,如果没有则插入 + AlibabaWorkOrder dbWorkOrder1 = baseMapper.selectById(workOrder.getId()); + AlibabaWorkOrder dbWorkOrder2 = baseMapper.selectByWorkOrderId(workOrder.getWorkOrderId()); + + // dbWorkOrder2优先,如果dbWorkOrder2不为空则尽量使用dbWorkOrder2 + if (Objects.isNull(dbWorkOrder2) && Objects.isNull(dbWorkOrder1)) { + // 如果dbWorkOrder1和dbWorkOrder2都为空,则插入 + return baseMapper.insert(workOrder); + } else { + // 如果dbWorkOrder1和dbWorkOrder2至少有一个不为空 + if (Objects.nonNull(dbWorkOrder2)) { + workOrder.setId(dbWorkOrder2.getId()); + } else { + workOrder.setId(dbWorkOrder1.getId()); + } + // 更新工单信息 + return baseMapper.updateById(workOrder); + } + } + } + + /** + * 批量保存工单信息 + *

使用并行流处理多个工单的保存操作,提高处理效率

+ * + * @param workOrders 工单对象列表 + * @return 返回成功保存的工单数量 + */ + @Override + public int batchSaveWorkOrder(List workOrders) { + // 检查工单列表是否为空 + if (CollUtil.isEmpty(workOrders)) return 0; + // 使用并行流处理每个工单,并统计成功保存的工单数量 + return workOrders.parallelStream() + .mapToInt(this::saveWorkOrder).sum(); + } + + @Override + public LocalDateTime getMaxWorkOrderTime() { + return baseMapper.selectMaxUpdateTime(); + } + +} diff --git a/jeelowcode-module/jeelowcode-module-biz/src/main/resources/mapper/AlibabaWorkOrderMapper.xml b/jeelowcode-module/jeelowcode-module-biz/src/main/resources/mapper/AlibabaWorkOrderMapper.xml new file mode 100644 index 0000000..9f490fc --- /dev/null +++ b/jeelowcode-module/jeelowcode-module-biz/src/main/resources/mapper/AlibabaWorkOrderMapper.xml @@ -0,0 +1,16 @@ + + + + + + + + \ No newline at end of file diff --git a/jeelowcode-tool/tool-spring-boot-starter-test/src/main/java/com/jeelowcode/tool/framework/test/core/ut/BaseDbAndRedisUnitTest.java b/jeelowcode-tool/tool-spring-boot-starter-test/src/main/java/com/jeelowcode/tool/framework/test/core/ut/BaseDbAndRedisUnitTest.java index d25b761..7ccf8f8 100644 --- a/jeelowcode-tool/tool-spring-boot-starter-test/src/main/java/com/jeelowcode/tool/framework/test/core/ut/BaseDbAndRedisUnitTest.java +++ b/jeelowcode-tool/tool-spring-boot-starter-test/src/main/java/com/jeelowcode/tool/framework/test/core/ut/BaseDbAndRedisUnitTest.java @@ -16,13 +16,13 @@ import org.springframework.test.context.jdbc.Sql; /** * 依赖内存 DB + Redis 的单元测试 - * + *

* 相比 {@link BaseDbUnitTest} 来说,额外增加了内存 Redis * * @author 芋道源码 */ @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE, classes = BaseDbAndRedisUnitTest.Application.class) -@ActiveProfiles("unit-test") // 设置使用 application-unit-test 配置文件 +@ActiveProfiles("local") // 设置使用 application-unit-test 配置文件 @Sql(scripts = "/sql/clean.sql", executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) // 每个单元测试结束后,清理 DB public class BaseDbAndRedisUnitTest {