吸收数字员工业务事实物化查询

This commit is contained in:
baiyanyun
2026-06-12 22:24:38 +08:00
parent 8a5d5d6474
commit 26fbf51fc8
20 changed files with 721 additions and 1 deletions

View File

@@ -58,4 +58,5 @@ public class DigitalEmployeeBusinessViewRowDto {
private String latestEventAt;
@JsonProperty("last_event_message")
private String lastEventMessage;
private Boolean materialized;
}

View File

@@ -0,0 +1,8 @@
package com.xspaceagi.agent.core.adapter.repository;
import com.baomidou.mybatisplus.extension.service.IService;
import com.xspaceagi.agent.core.adapter.repository.entity.DigitalEmployeeArtifactLifecycle;
public interface DigitalEmployeeArtifactLifecycleRepository extends IService<DigitalEmployeeArtifactLifecycle> {
void upsertBySyncRecord(DigitalEmployeeArtifactLifecycle lifecycle);
}

View File

@@ -0,0 +1,24 @@
package com.xspaceagi.agent.core.adapter.repository;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.IService;
import com.xspaceagi.agent.core.adapter.repository.entity.DigitalEmployeeBusinessFact;
import java.util.Date;
public interface DigitalEmployeeBusinessFactRepository extends IService<DigitalEmployeeBusinessFact> {
void upsertBySyncRecord(DigitalEmployeeBusinessFact fact);
IPage<DigitalEmployeeBusinessFact> queryFacts(
Long tenantId,
String clientKey,
String deviceId,
String entityType,
String entityId,
Date updatedFrom,
Date updatedTo,
String syncStatus,
long pageNo,
long pageSize
);
}

View File

@@ -0,0 +1,8 @@
package com.xspaceagi.agent.core.adapter.repository;
import com.baomidou.mybatisplus.extension.service.IService;
import com.xspaceagi.agent.core.adapter.repository.entity.DigitalEmployeeDailyReportFact;
public interface DigitalEmployeeDailyReportFactRepository extends IService<DigitalEmployeeDailyReportFact> {
void upsertBySyncRecord(DigitalEmployeeDailyReportFact fact);
}

View File

@@ -0,0 +1,41 @@
package com.xspaceagi.agent.core.adapter.repository.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 lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
@TableName("digital_employee_artifact_lifecycle")
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class DigitalEmployeeArtifactLifecycle {
@TableId(value = "id", type = IdType.AUTO)
private Long id;
@TableField(value = "_tenant_id")
private Long tenantId;
private Long syncRecordId;
private String clientKey;
private String deviceId;
private String artifactId;
private String planId;
private String taskId;
private String runId;
private String status;
private String retentionStatus;
private String cleanupStatus;
private String deletedAt;
private String versionKey;
private String source;
private String businessView;
private Date syncedAt;
private Date modified;
private Date created;
}

View File

@@ -0,0 +1,50 @@
package com.xspaceagi.agent.core.adapter.repository.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 lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
@TableName("digital_employee_business_fact")
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class DigitalEmployeeBusinessFact {
@TableId(value = "id", type = IdType.AUTO)
private Long id;
@TableField(value = "_tenant_id")
private Long tenantId;
private Long userId;
private Long syncRecordId;
private String clientKey;
private String deviceId;
private String outboxId;
private String entityType;
private String entityId;
private String operation;
private String title;
private String status;
private String summary;
private String planId;
private String taskId;
private String runId;
private String kind;
private String category;
private String occurredAt;
private String startedAt;
private String finishedAt;
private Long durationMs;
private String syncStatus;
private String businessView;
private String payload;
private Date syncedAt;
private Date modified;
private Date created;
}

View File

@@ -0,0 +1,38 @@
package com.xspaceagi.agent.core.adapter.repository.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 lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
@TableName("digital_employee_daily_report_fact")
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class DigitalEmployeeDailyReportFact {
@TableId(value = "id", type = IdType.AUTO)
private Long id;
@TableField(value = "_tenant_id")
private Long tenantId;
private Long syncRecordId;
private String clientKey;
private String deviceId;
private String reportId;
private String planId;
private String status;
private String deliveryStatus;
private String approvalStatus;
private String confirmedAt;
private String reportDate;
private String businessView;
private Date syncedAt;
private Date modified;
private Date created;
}

View File

@@ -25,8 +25,14 @@ import com.xspaceagi.agent.core.adapter.dto.digital.DigitalEmployeeSyncRecordPag
import com.xspaceagi.agent.core.adapter.dto.digital.DigitalEmployeeSyncRequestDto;
import com.xspaceagi.agent.core.adapter.dto.digital.DigitalEmployeeSyncResponseDto;
import com.xspaceagi.agent.core.adapter.repository.DigitalEmployeeAdminActionRepository;
import com.xspaceagi.agent.core.adapter.repository.DigitalEmployeeArtifactLifecycleRepository;
import com.xspaceagi.agent.core.adapter.repository.DigitalEmployeeBusinessFactRepository;
import com.xspaceagi.agent.core.adapter.repository.DigitalEmployeeDailyReportFactRepository;
import com.xspaceagi.agent.core.adapter.repository.DigitalEmployeeSyncRecordRepository;
import com.xspaceagi.agent.core.adapter.repository.entity.DigitalEmployeeAdminAction;
import com.xspaceagi.agent.core.adapter.repository.entity.DigitalEmployeeArtifactLifecycle;
import com.xspaceagi.agent.core.adapter.repository.entity.DigitalEmployeeBusinessFact;
import com.xspaceagi.agent.core.adapter.repository.entity.DigitalEmployeeDailyReportFact;
import com.xspaceagi.agent.core.adapter.repository.entity.DigitalEmployeeSyncRecord;
import com.xspaceagi.system.spec.common.RequestContext;
import jakarta.annotation.Resource;
@@ -70,6 +76,15 @@ public class DigitalEmployeeSyncApplicationServiceImpl implements DigitalEmploye
@Resource
private DigitalEmployeeAdminActionRepository digitalEmployeeAdminActionRepository;
@Resource
private DigitalEmployeeBusinessFactRepository digitalEmployeeBusinessFactRepository;
@Resource
private DigitalEmployeeArtifactLifecycleRepository digitalEmployeeArtifactLifecycleRepository;
@Resource
private DigitalEmployeeDailyReportFactRepository digitalEmployeeDailyReportFactRepository;
@Resource
private ObjectMapper objectMapper;
@@ -116,6 +131,7 @@ public class DigitalEmployeeSyncApplicationServiceImpl implements DigitalEmploye
} else {
digitalEmployeeSyncRecordRepository.updateById(record);
}
materializeSyncRecord(record, now);
acked.add(DigitalEmployeeSyncAckDto.builder()
.outboxId(item.getOutboxId())
@@ -190,6 +206,94 @@ public class DigitalEmployeeSyncApplicationServiceImpl implements DigitalEmploye
.build();
}
private void materializeSyncRecord(DigitalEmployeeSyncRecord record, Date now) {
if (record == null || record.getId() == null || digitalEmployeeBusinessFactRepository == null) return;
DigitalEmployeeBusinessViewRowDto row = toBusinessRow(record);
digitalEmployeeBusinessFactRepository.upsertBySyncRecord(DigitalEmployeeBusinessFact.builder()
.tenantId(record.getTenantId())
.userId(record.getUserId())
.syncRecordId(record.getId())
.clientKey(record.getClientKey())
.deviceId(record.getDeviceId())
.outboxId(record.getOutboxId())
.entityType(row.getEntityType())
.entityId(row.getEntityId())
.operation(row.getOperation())
.title(row.getTitle())
.status(row.getStatus())
.summary(row.getSummary())
.planId(row.getPlanId())
.taskId(row.getTaskId())
.runId(row.getRunId())
.kind(row.getKind())
.category(firstString(row.getBusinessView().get("category"), row.getEntityType()))
.occurredAt(row.getOccurredAt())
.startedAt(row.getStartedAt())
.finishedAt(row.getFinishedAt())
.durationMs(row.getDurationMs())
.syncStatus(row.getSyncStatus())
.businessView(record.getBusinessView())
.payload(record.getPayload())
.syncedAt(record.getSyncedAt())
.modified(now)
.created(now)
.build());
materializeArtifactLifecycle(record, row, now);
materializeDailyReportFact(record, row, now);
}
private void materializeArtifactLifecycle(DigitalEmployeeSyncRecord record, DigitalEmployeeBusinessViewRowDto row, Date now) {
if (digitalEmployeeArtifactLifecycleRepository == null || !StringUtils.equals(row.getEntityType(), "artifact")) return;
Map<String, Object> view = row.getBusinessView();
String artifactId = firstString(view.get("artifact_id"), view.get("artifactId"), row.getEntityId());
digitalEmployeeArtifactLifecycleRepository.upsertBySyncRecord(DigitalEmployeeArtifactLifecycle.builder()
.tenantId(record.getTenantId())
.syncRecordId(record.getId())
.clientKey(record.getClientKey())
.deviceId(record.getDeviceId())
.artifactId(artifactId)
.planId(row.getPlanId())
.taskId(row.getTaskId())
.runId(row.getRunId())
.status(row.getStatus())
.retentionStatus(firstString(view.get("retention_status"), view.get("retentionStatus")))
.cleanupStatus(firstString(view.get("cleanup_status"), view.get("cleanupStatus")))
.deletedAt(firstString(view.get("deleted_at"), view.get("deletedAt")))
.versionKey(firstString(view.get("version_key"), view.get("versionKey")))
.source(firstString(view.get("source"), view.get("artifact_source"), view.get("artifactSource")))
.businessView(record.getBusinessView())
.syncedAt(record.getSyncedAt())
.modified(now)
.created(now)
.build());
}
private void materializeDailyReportFact(DigitalEmployeeSyncRecord record, DigitalEmployeeBusinessViewRowDto row, Date now) {
Map<String, Object> view = row.getBusinessView();
if (digitalEmployeeDailyReportFactRepository == null
|| !(StringUtils.equals(row.getEntityType(), "daily_report") || StringUtils.equals(firstString(view.get("category")), "daily_report"))) {
return;
}
String reportId = firstString(view.get("report_id"), view.get("reportId"), row.getEntityId());
digitalEmployeeDailyReportFactRepository.upsertBySyncRecord(DigitalEmployeeDailyReportFact.builder()
.tenantId(record.getTenantId())
.syncRecordId(record.getId())
.clientKey(record.getClientKey())
.deviceId(record.getDeviceId())
.reportId(reportId)
.planId(row.getPlanId())
.status(row.getStatus())
.deliveryStatus(firstString(view.get("delivery_status"), view.get("deliveryStatus")))
.approvalStatus(firstString(view.get("approval_status"), view.get("approvalStatus")))
.confirmedAt(firstString(view.get("confirmed_at"), view.get("confirmedAt")))
.reportDate(firstString(view.get("report_date"), view.get("reportDate")))
.businessView(record.getBusinessView())
.syncedAt(record.getSyncedAt())
.modified(now)
.created(now)
.build());
}
@Override
public DigitalEmployeeBusinessViewPageDto queryBusinessViews(
String entityType,
@@ -214,6 +318,28 @@ public class DigitalEmployeeSyncApplicationServiceImpl implements DigitalEmploye
String normalizedEntityType = normalizeBusinessEntityType(entityType);
String repositoryEntityType = "plan".equals(normalizedEntityType) ? null : normalizedEntityType;
List<DigitalEmployeeBusinessViewRowDto> materializedRows = queryMaterializedBusinessRows(
tenantId,
clientKey,
deviceId,
repositoryEntityType,
entityId,
updatedFrom,
updatedTo,
syncStatus,
currentPage,
currentPageSize
);
if (materializedRows != null) {
List<DigitalEmployeeBusinessViewRowDto> rows = "plan".equals(normalizedEntityType)
? enrichPlanRows(materializedRows)
: materializedRows.stream().filter(row -> StringUtils.equals(row.getEntityType(), normalizedEntityType)).toList();
rows = rows.stream()
.filter(row -> matchesText(status, row.getStatus()))
.filter(row -> matchesText(syncStatus, row.getSyncStatus()))
.toList();
return businessPage(rows, currentPage, currentPageSize);
}
IPage<DigitalEmployeeSyncRecord> page = digitalEmployeeSyncRecordRepository.queryBusinessRecords(
tenantId,
clientKey,
@@ -239,6 +365,35 @@ public class DigitalEmployeeSyncApplicationServiceImpl implements DigitalEmploye
return businessPage(rows, currentPage, currentPageSize);
}
private List<DigitalEmployeeBusinessViewRowDto> queryMaterializedBusinessRows(
Long tenantId,
String clientKey,
String deviceId,
String entityType,
String entityId,
Date updatedFrom,
Date updatedTo,
String syncStatus,
long pageNo,
long pageSize
) {
if (digitalEmployeeBusinessFactRepository == null) return null;
IPage<DigitalEmployeeBusinessFact> factPage = digitalEmployeeBusinessFactRepository.queryFacts(
tenantId,
clientKey,
deviceId,
entityType,
entityId,
updatedFrom,
updatedTo,
syncStatus,
pageNo,
pageSize
);
if (factPage == null || factPage.getTotal() <= 0) return null;
return factPage.getRecords().stream().map(this::toBusinessRow).toList();
}
@Override
public DigitalEmployeePlanBusinessViewDetailDto queryPlanBusinessViewDetail(
String planId,
@@ -814,6 +969,38 @@ public class DigitalEmployeeSyncApplicationServiceImpl implements DigitalEmploye
.businessView(businessView)
.payload(payload)
.lastEventMessage(lastEventMessage(entityType, businessView, payload))
.materialized(false)
.build();
}
private DigitalEmployeeBusinessViewRowDto toBusinessRow(DigitalEmployeeBusinessFact fact) {
return DigitalEmployeeBusinessViewRowDto.builder()
.syncRecordId(fact.getSyncRecordId())
.syncRecordUrl(syncRecordUrl(fact.getOutboxId()))
.entityType(fact.getEntityType())
.entityId(fact.getEntityId())
.operation(fact.getOperation())
.title(fact.getTitle())
.status(fact.getStatus())
.summary(fact.getSummary())
.planId(fact.getPlanId())
.taskId(fact.getTaskId())
.runId(fact.getRunId())
.kind(fact.getKind())
.occurredAt(fact.getOccurredAt())
.startedAt(fact.getStartedAt())
.finishedAt(fact.getFinishedAt())
.durationMs(fact.getDurationMs())
.syncStatus(fact.getSyncStatus())
.clientKeyMasked(maskClientKey(fact.getClientKey()))
.deviceId(fact.getDeviceId())
.syncedAt(fact.getSyncedAt())
.modified(fact.getModified())
.created(fact.getCreated())
.businessView(readJsonObject(fact.getBusinessView()))
.payload(readJsonObject(fact.getPayload()))
.lastEventMessage(lastEventMessage(fact.getEntityType(), readJsonObject(fact.getBusinessView()), readJsonObject(fact.getPayload())))
.materialized(true)
.build();
}

View File

@@ -18,8 +18,12 @@ import com.xspaceagi.agent.core.adapter.dto.digital.DigitalEmployeeSyncItemDto;
import com.xspaceagi.agent.core.adapter.dto.digital.DigitalEmployeeSyncRecordPageDto;
import com.xspaceagi.agent.core.adapter.dto.digital.DigitalEmployeeSyncRequestDto;
import com.xspaceagi.agent.core.adapter.repository.DigitalEmployeeAdminActionRepository;
import com.xspaceagi.agent.core.adapter.repository.DigitalEmployeeArtifactLifecycleRepository;
import com.xspaceagi.agent.core.adapter.repository.DigitalEmployeeBusinessFactRepository;
import com.xspaceagi.agent.core.adapter.repository.DigitalEmployeeDailyReportFactRepository;
import com.xspaceagi.agent.core.adapter.repository.DigitalEmployeeSyncRecordRepository;
import com.xspaceagi.agent.core.adapter.repository.entity.DigitalEmployeeAdminAction;
import com.xspaceagi.agent.core.adapter.repository.entity.DigitalEmployeeBusinessFact;
import com.xspaceagi.agent.core.adapter.repository.entity.DigitalEmployeeSyncRecord;
import com.xspaceagi.system.spec.common.RequestContext;
import org.junit.jupiter.api.AfterEach;
@@ -35,6 +39,7 @@ import java.util.Map;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
@@ -44,6 +49,9 @@ class DigitalEmployeeSyncApplicationServiceImplTest {
private DigitalEmployeeSyncRecordRepository repository;
private DigitalEmployeeAdminActionRepository adminActionRepository;
private DigitalEmployeeBusinessFactRepository businessFactRepository;
private DigitalEmployeeArtifactLifecycleRepository artifactLifecycleRepository;
private DigitalEmployeeDailyReportFactRepository dailyReportFactRepository;
private DigitalEmployeeSyncApplicationServiceImpl service;
@BeforeEach
@@ -55,9 +63,15 @@ class DigitalEmployeeSyncApplicationServiceImplTest {
repository = mock(DigitalEmployeeSyncRecordRepository.class);
adminActionRepository = mock(DigitalEmployeeAdminActionRepository.class);
businessFactRepository = mock(DigitalEmployeeBusinessFactRepository.class);
artifactLifecycleRepository = mock(DigitalEmployeeArtifactLifecycleRepository.class);
dailyReportFactRepository = mock(DigitalEmployeeDailyReportFactRepository.class);
service = new DigitalEmployeeSyncApplicationServiceImpl();
ReflectionTestUtils.setField(service, "digitalEmployeeSyncRecordRepository", repository);
ReflectionTestUtils.setField(service, "digitalEmployeeAdminActionRepository", adminActionRepository);
ReflectionTestUtils.setField(service, "digitalEmployeeBusinessFactRepository", businessFactRepository);
ReflectionTestUtils.setField(service, "digitalEmployeeArtifactLifecycleRepository", artifactLifecycleRepository);
ReflectionTestUtils.setField(service, "digitalEmployeeDailyReportFactRepository", dailyReportFactRepository);
ReflectionTestUtils.setField(service, "objectMapper", new ObjectMapper());
}
@@ -82,6 +96,11 @@ class DigitalEmployeeSyncApplicationServiceImplTest {
request.setClientKey("client-key-001");
request.setDeviceId("device-001");
request.setItems(List.of(item));
doAnswer(invocation -> {
DigitalEmployeeSyncRecord saved = invocation.getArgument(0);
saved.setId(1001L);
return true;
}).when(repository).save(any(DigitalEmployeeSyncRecord.class));
service.syncOutbox(request);
@@ -94,6 +113,11 @@ class DigitalEmployeeSyncApplicationServiceImplTest {
assertThat(record.getPayload()).contains("plan-1");
assertThat(record.getTenantId()).isEqualTo(101L);
assertThat(record.getUserId()).isEqualTo(202L);
ArgumentCaptor<DigitalEmployeeBusinessFact> factCaptor = ArgumentCaptor.forClass(DigitalEmployeeBusinessFact.class);
verify(businessFactRepository).upsertBySyncRecord(factCaptor.capture());
assertThat(factCaptor.getValue().getSyncRecordId()).isEqualTo(1001L);
assertThat(factCaptor.getValue().getTitle()).isEqualTo("客户回访");
assertThat(factCaptor.getValue().getStatus()).isEqualTo("active");
}
@Test
@@ -140,6 +164,22 @@ class DigitalEmployeeSyncApplicationServiceImplTest {
assertThat(plan.getClientKeyMasked()).isEqualTo("clie*********001");
}
@Test
void queryBusinessViewsPrefersMaterializedFactsWhenAvailable() {
DigitalEmployeeBusinessFact fact = businessFact("plan-1", "客户回访", "active", new Date(10_000));
Page<DigitalEmployeeBusinessFact> page = new Page<>(1, 20, 1);
page.setRecords(List.of(fact));
when(businessFactRepository.queryFacts(eq(101L), eq("client-key-001"), eq(null), eq(null), eq(null), eq(null), eq(null), eq(null), eq(1L), eq(20L)))
.thenReturn(page);
DigitalEmployeeBusinessViewPageDto result = service.queryBusinessViews("plan", "client-key-001", null, null, null, null, null, null, 1L, 20L);
assertThat(result.getRecords()).hasSize(1);
assertThat(result.getRecords().get(0).getTitle()).isEqualTo("客户回访");
assertThat(result.getRecords().get(0).getMaterialized()).isTrue();
verify(repository, never()).queryBusinessRecords(any(), any(), any(), any(), any(), any(), any(), any(), any(Long.class), any(Long.class));
}
@Test
void queryEventsFiltersStatusEntityAndTimeRangeFromBusinessView() {
Date from = new Date(10_000);
@@ -416,6 +456,30 @@ class DigitalEmployeeSyncApplicationServiceImplTest {
return record;
}
private DigitalEmployeeBusinessFact businessFact(String planId, String title, String status, Date syncedAt) {
DigitalEmployeeBusinessFact fact = new DigitalEmployeeBusinessFact();
fact.setId(7001L);
fact.setTenantId(101L);
fact.setUserId(202L);
fact.setSyncRecordId(1001L);
fact.setClientKey("client-key-001");
fact.setDeviceId("device-001");
fact.setOutboxId("outbox-" + planId);
fact.setEntityType("plan");
fact.setEntityId(planId);
fact.setOperation("upsert");
fact.setTitle(title);
fact.setStatus(status);
fact.setSummary("计划摘要");
fact.setPlanId(planId);
fact.setBusinessView(toJson(Map.of("entity_type", "plan", "local_id", planId, "title", title, "status", status)));
fact.setPayload(toJson(Map.of("id", planId, "title", title, "status", status)));
fact.setSyncedAt(syncedAt);
fact.setCreated(syncedAt);
fact.setModified(syncedAt);
return fact;
}
private DigitalEmployeeSyncRecord planRecord(String planId, String title, String status, Long tenantId, Date syncedAt) {
return record("outbox-" + planId, "plan", planId, tenantId, syncedAt,
Map.of("entity_type", "plan", "local_id", planId, "title", title, "status", status, "summary", "计划摘要"),

View File

@@ -0,0 +1,9 @@
package com.xspaceagi.agent.core.infra.dao.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.xspaceagi.agent.core.adapter.repository.entity.DigitalEmployeeArtifactLifecycle;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface DigitalEmployeeArtifactLifecycleMapper extends BaseMapper<DigitalEmployeeArtifactLifecycle> {
}

View File

@@ -0,0 +1,9 @@
package com.xspaceagi.agent.core.infra.dao.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.xspaceagi.agent.core.adapter.repository.entity.DigitalEmployeeBusinessFact;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface DigitalEmployeeBusinessFactMapper extends BaseMapper<DigitalEmployeeBusinessFact> {
}

View File

@@ -0,0 +1,9 @@
package com.xspaceagi.agent.core.infra.dao.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.xspaceagi.agent.core.adapter.repository.entity.DigitalEmployeeDailyReportFact;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface DigitalEmployeeDailyReportFactMapper extends BaseMapper<DigitalEmployeeDailyReportFact> {
}

View File

@@ -0,0 +1,29 @@
package com.xspaceagi.agent.core.infra.repository;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xspaceagi.agent.core.adapter.repository.DigitalEmployeeArtifactLifecycleRepository;
import com.xspaceagi.agent.core.adapter.repository.entity.DigitalEmployeeArtifactLifecycle;
import com.xspaceagi.agent.core.infra.dao.mapper.DigitalEmployeeArtifactLifecycleMapper;
import org.springframework.stereotype.Service;
@Service
public class DigitalEmployeeArtifactLifecycleRepositoryImpl
extends ServiceImpl<DigitalEmployeeArtifactLifecycleMapper, DigitalEmployeeArtifactLifecycle>
implements DigitalEmployeeArtifactLifecycleRepository {
@Override
public void upsertBySyncRecord(DigitalEmployeeArtifactLifecycle lifecycle) {
if (lifecycle == null || lifecycle.getTenantId() == null || lifecycle.getSyncRecordId() == null) return;
DigitalEmployeeArtifactLifecycle existing = getOne(new LambdaQueryWrapper<DigitalEmployeeArtifactLifecycle>()
.eq(DigitalEmployeeArtifactLifecycle::getTenantId, lifecycle.getTenantId())
.eq(DigitalEmployeeArtifactLifecycle::getSyncRecordId, lifecycle.getSyncRecordId()), false);
if (existing == null) {
save(lifecycle);
} else {
lifecycle.setId(existing.getId());
lifecycle.setCreated(existing.getCreated());
updateById(lifecycle);
}
}
}

View File

@@ -0,0 +1,61 @@
package com.xspaceagi.agent.core.infra.repository;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xspaceagi.agent.core.adapter.repository.DigitalEmployeeBusinessFactRepository;
import com.xspaceagi.agent.core.adapter.repository.entity.DigitalEmployeeBusinessFact;
import com.xspaceagi.agent.core.infra.dao.mapper.DigitalEmployeeBusinessFactMapper;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import java.util.Date;
@Service
public class DigitalEmployeeBusinessFactRepositoryImpl
extends ServiceImpl<DigitalEmployeeBusinessFactMapper, DigitalEmployeeBusinessFact>
implements DigitalEmployeeBusinessFactRepository {
@Override
public void upsertBySyncRecord(DigitalEmployeeBusinessFact fact) {
if (fact == null || fact.getTenantId() == null || fact.getSyncRecordId() == null) return;
DigitalEmployeeBusinessFact existing = getOne(new LambdaQueryWrapper<DigitalEmployeeBusinessFact>()
.eq(DigitalEmployeeBusinessFact::getTenantId, fact.getTenantId())
.eq(DigitalEmployeeBusinessFact::getSyncRecordId, fact.getSyncRecordId()), false);
if (existing == null) {
save(fact);
} else {
fact.setId(existing.getId());
fact.setCreated(existing.getCreated());
updateById(fact);
}
}
@Override
public IPage<DigitalEmployeeBusinessFact> queryFacts(
Long tenantId,
String clientKey,
String deviceId,
String entityType,
String entityId,
Date updatedFrom,
Date updatedTo,
String syncStatus,
long pageNo,
long pageSize
) {
LambdaQueryWrapper<DigitalEmployeeBusinessFact> queryWrapper = new LambdaQueryWrapper<DigitalEmployeeBusinessFact>()
.eq(tenantId != null, DigitalEmployeeBusinessFact::getTenantId, tenantId)
.eq(StringUtils.isNotBlank(clientKey), DigitalEmployeeBusinessFact::getClientKey, clientKey)
.eq(StringUtils.isNotBlank(deviceId), DigitalEmployeeBusinessFact::getDeviceId, deviceId)
.eq(StringUtils.isNotBlank(entityType), DigitalEmployeeBusinessFact::getEntityType, entityType)
.eq(StringUtils.isNotBlank(entityId), DigitalEmployeeBusinessFact::getEntityId, entityId)
.eq(StringUtils.isNotBlank(syncStatus), DigitalEmployeeBusinessFact::getSyncStatus, syncStatus)
.ge(updatedFrom != null, DigitalEmployeeBusinessFact::getSyncedAt, updatedFrom)
.le(updatedTo != null, DigitalEmployeeBusinessFact::getSyncedAt, updatedTo)
.orderByDesc(DigitalEmployeeBusinessFact::getSyncedAt)
.orderByDesc(DigitalEmployeeBusinessFact::getId);
return page(new Page<>(pageNo, pageSize), queryWrapper);
}
}

View File

@@ -0,0 +1,29 @@
package com.xspaceagi.agent.core.infra.repository;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xspaceagi.agent.core.adapter.repository.DigitalEmployeeDailyReportFactRepository;
import com.xspaceagi.agent.core.adapter.repository.entity.DigitalEmployeeDailyReportFact;
import com.xspaceagi.agent.core.infra.dao.mapper.DigitalEmployeeDailyReportFactMapper;
import org.springframework.stereotype.Service;
@Service
public class DigitalEmployeeDailyReportFactRepositoryImpl
extends ServiceImpl<DigitalEmployeeDailyReportFactMapper, DigitalEmployeeDailyReportFact>
implements DigitalEmployeeDailyReportFactRepository {
@Override
public void upsertBySyncRecord(DigitalEmployeeDailyReportFact fact) {
if (fact == null || fact.getTenantId() == null || fact.getSyncRecordId() == null) return;
DigitalEmployeeDailyReportFact existing = getOne(new LambdaQueryWrapper<DigitalEmployeeDailyReportFact>()
.eq(DigitalEmployeeDailyReportFact::getTenantId, fact.getTenantId())
.eq(DigitalEmployeeDailyReportFact::getSyncRecordId, fact.getSyncRecordId()), false);
if (existing == null) {
save(fact);
} else {
fact.setId(existing.getId());
fact.setCreated(existing.getCreated());
updateById(fact);
}
}
}