吸收数字员工管理端业务查询模型
This commit is contained in:
@@ -1,9 +1,13 @@
|
||||
package com.xspaceagi.agent.core.adapter.application;
|
||||
|
||||
import com.xspaceagi.agent.core.adapter.dto.digital.DigitalEmployeeBusinessViewPageDto;
|
||||
import com.xspaceagi.agent.core.adapter.dto.digital.DigitalEmployeePlanBusinessViewDetailDto;
|
||||
import com.xspaceagi.agent.core.adapter.dto.digital.DigitalEmployeeSyncRecordPageDto;
|
||||
import com.xspaceagi.agent.core.adapter.dto.digital.DigitalEmployeeSyncRequestDto;
|
||||
import com.xspaceagi.agent.core.adapter.dto.digital.DigitalEmployeeSyncResponseDto;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
public interface DigitalEmployeeSyncApplicationService {
|
||||
DigitalEmployeeSyncResponseDto syncOutbox(DigitalEmployeeSyncRequestDto request);
|
||||
|
||||
@@ -16,4 +20,23 @@ public interface DigitalEmployeeSyncApplicationService {
|
||||
Long pageNo,
|
||||
Long pageSize
|
||||
);
|
||||
|
||||
DigitalEmployeeBusinessViewPageDto queryBusinessViews(
|
||||
String entityType,
|
||||
String clientKey,
|
||||
String deviceId,
|
||||
String entityId,
|
||||
String status,
|
||||
String syncStatus,
|
||||
Date updatedFrom,
|
||||
Date updatedTo,
|
||||
Long pageNo,
|
||||
Long pageSize
|
||||
);
|
||||
|
||||
DigitalEmployeePlanBusinessViewDetailDto queryPlanBusinessViewDetail(
|
||||
String planId,
|
||||
String clientKey,
|
||||
String deviceId
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.xspaceagi.agent.core.adapter.dto.digital;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
public class DigitalEmployeeBusinessViewPageDto {
|
||||
private Long total;
|
||||
@JsonProperty("page_no")
|
||||
private Long pageNo;
|
||||
@JsonProperty("page_size")
|
||||
private Long pageSize;
|
||||
private List<DigitalEmployeeBusinessViewRowDto> records;
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package com.xspaceagi.agent.core.adapter.dto.digital;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
public class DigitalEmployeeBusinessViewRowDto {
|
||||
@JsonProperty("sync_record_id")
|
||||
private Long syncRecordId;
|
||||
@JsonProperty("sync_record_url")
|
||||
private String syncRecordUrl;
|
||||
@JsonProperty("entity_type")
|
||||
private String entityType;
|
||||
@JsonProperty("entity_id")
|
||||
private String entityId;
|
||||
private String operation;
|
||||
private String title;
|
||||
private String status;
|
||||
private String summary;
|
||||
@JsonProperty("plan_id")
|
||||
private String planId;
|
||||
@JsonProperty("task_id")
|
||||
private String taskId;
|
||||
@JsonProperty("run_id")
|
||||
private String runId;
|
||||
private String kind;
|
||||
@JsonProperty("occurred_at")
|
||||
private String occurredAt;
|
||||
@JsonProperty("started_at")
|
||||
private String startedAt;
|
||||
@JsonProperty("finished_at")
|
||||
private String finishedAt;
|
||||
@JsonProperty("duration_ms")
|
||||
private Long durationMs;
|
||||
@JsonProperty("sync_status")
|
||||
private String syncStatus;
|
||||
@JsonProperty("client_key_masked")
|
||||
private String clientKeyMasked;
|
||||
@JsonProperty("device_id")
|
||||
private String deviceId;
|
||||
@JsonProperty("synced_at")
|
||||
private Date syncedAt;
|
||||
private Date modified;
|
||||
private Date created;
|
||||
@JsonProperty("business_view")
|
||||
private Map<String, Object> businessView;
|
||||
private Map<String, Object> payload;
|
||||
@JsonProperty("task_count")
|
||||
private Integer taskCount;
|
||||
@JsonProperty("run_count")
|
||||
private Integer runCount;
|
||||
@JsonProperty("latest_event_at")
|
||||
private String latestEventAt;
|
||||
@JsonProperty("last_event_message")
|
||||
private String lastEventMessage;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.xspaceagi.agent.core.adapter.dto.digital;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
public class DigitalEmployeePlanBusinessViewDetailDto {
|
||||
private DigitalEmployeeBusinessViewRowDto plan;
|
||||
private List<DigitalEmployeeBusinessViewRowDto> tasks;
|
||||
private List<DigitalEmployeeBusinessViewRowDto> runs;
|
||||
private List<DigitalEmployeeBusinessViewRowDto> events;
|
||||
private List<DigitalEmployeeBusinessViewRowDto> artifacts;
|
||||
private List<DigitalEmployeeBusinessViewRowDto> approvals;
|
||||
}
|
||||
@@ -14,5 +14,11 @@ public class DigitalEmployeeSyncItemDto {
|
||||
@JsonAlias("entity_id")
|
||||
private String entityId;
|
||||
private String operation;
|
||||
@JsonAlias("contract_version")
|
||||
private String contractVersion;
|
||||
@JsonAlias("entity_summary")
|
||||
private Map<String, Object> entitySummary;
|
||||
@JsonAlias("business_view")
|
||||
private Map<String, Object> businessView;
|
||||
private Map<String, Object> payload;
|
||||
}
|
||||
|
||||
@@ -21,6 +21,12 @@ public class DigitalEmployeeSyncRecordDto {
|
||||
@JsonProperty("entity_id")
|
||||
private String entityId;
|
||||
private String operation;
|
||||
@JsonProperty("contract_version")
|
||||
private String contractVersion;
|
||||
@JsonProperty("entity_summary")
|
||||
private String entitySummary;
|
||||
@JsonProperty("business_view")
|
||||
private String businessView;
|
||||
private String payload;
|
||||
@JsonProperty("synced_at")
|
||||
private Date syncedAt;
|
||||
|
||||
@@ -4,6 +4,8 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.xspaceagi.agent.core.adapter.repository.entity.DigitalEmployeeSyncRecord;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
public interface DigitalEmployeeSyncRecordRepository extends IService<DigitalEmployeeSyncRecord> {
|
||||
IPage<DigitalEmployeeSyncRecord> queryRecords(
|
||||
Long tenantId,
|
||||
@@ -15,4 +17,17 @@ public interface DigitalEmployeeSyncRecordRepository extends IService<DigitalEmp
|
||||
long pageNo,
|
||||
long pageSize
|
||||
);
|
||||
|
||||
IPage<DigitalEmployeeSyncRecord> queryBusinessRecords(
|
||||
Long tenantId,
|
||||
String clientKey,
|
||||
String deviceId,
|
||||
String entityType,
|
||||
String entityId,
|
||||
Date updatedFrom,
|
||||
Date updatedTo,
|
||||
String syncStatus,
|
||||
long pageNo,
|
||||
long pageSize
|
||||
);
|
||||
}
|
||||
|
||||
@@ -28,6 +28,9 @@ public class DigitalEmployeeSyncRecord {
|
||||
private String entityType;
|
||||
private String entityId;
|
||||
private String operation;
|
||||
private String contractVersion;
|
||||
private String entitySummary;
|
||||
private String businessView;
|
||||
private String payload;
|
||||
private Date syncedAt;
|
||||
private Date modified;
|
||||
|
||||
@@ -4,8 +4,12 @@ import com.baomidou.dynamic.datasource.annotation.DSTransactional;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.xspaceagi.agent.core.adapter.application.DigitalEmployeeSyncApplicationService;
|
||||
import com.xspaceagi.agent.core.adapter.dto.digital.DigitalEmployeeBusinessViewPageDto;
|
||||
import com.xspaceagi.agent.core.adapter.dto.digital.DigitalEmployeeBusinessViewRowDto;
|
||||
import com.xspaceagi.agent.core.adapter.dto.digital.DigitalEmployeePlanBusinessViewDetailDto;
|
||||
import com.xspaceagi.agent.core.adapter.dto.digital.DigitalEmployeeSyncAckDto;
|
||||
import com.xspaceagi.agent.core.adapter.dto.digital.DigitalEmployeeSyncItemDto;
|
||||
import com.xspaceagi.agent.core.adapter.dto.digital.DigitalEmployeeSyncRecordDto;
|
||||
@@ -17,11 +21,17 @@ import com.xspaceagi.agent.core.adapter.repository.entity.DigitalEmployeeSyncRec
|
||||
import com.xspaceagi.system.spec.common.RequestContext;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.Date;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
@Service
|
||||
public class DigitalEmployeeSyncApplicationServiceImpl implements DigitalEmployeeSyncApplicationService {
|
||||
@@ -67,6 +77,9 @@ public class DigitalEmployeeSyncApplicationServiceImpl implements DigitalEmploye
|
||||
record.setEntityType(item.getEntityType());
|
||||
record.setEntityId(item.getEntityId());
|
||||
record.setOperation(item.getOperation());
|
||||
record.setContractVersion(item.getContractVersion());
|
||||
record.setEntitySummary(toJson(item.getEntitySummary()));
|
||||
record.setBusinessView(toJson(item.getBusinessView()));
|
||||
record.setPayload(toJson(item.getPayload()));
|
||||
record.setSyncedAt(now);
|
||||
record.setModified(now);
|
||||
@@ -140,6 +153,9 @@ public class DigitalEmployeeSyncApplicationServiceImpl implements DigitalEmploye
|
||||
.entityType(record.getEntityType())
|
||||
.entityId(record.getEntityId())
|
||||
.operation(record.getOperation())
|
||||
.contractVersion(record.getContractVersion())
|
||||
.entitySummary(record.getEntitySummary())
|
||||
.businessView(record.getBusinessView())
|
||||
.payload(record.getPayload())
|
||||
.syncedAt(record.getSyncedAt())
|
||||
.modified(record.getModified())
|
||||
@@ -147,6 +163,258 @@ public class DigitalEmployeeSyncApplicationServiceImpl implements DigitalEmploye
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DigitalEmployeeBusinessViewPageDto queryBusinessViews(
|
||||
String entityType,
|
||||
String clientKey,
|
||||
String deviceId,
|
||||
String entityId,
|
||||
String status,
|
||||
String syncStatus,
|
||||
Date updatedFrom,
|
||||
Date updatedTo,
|
||||
Long pageNo,
|
||||
Long pageSize
|
||||
) {
|
||||
long currentPage = pageNo == null || pageNo < 1 ? DEFAULT_PAGE_NO : pageNo;
|
||||
long currentPageSize = pageSize == null || pageSize < 1
|
||||
? DEFAULT_PAGE_SIZE
|
||||
: Math.min(pageSize, MAX_PAGE_SIZE);
|
||||
Long tenantId = RequestContext.get() == null ? null : RequestContext.get().getTenantId();
|
||||
if (tenantId == null) {
|
||||
return businessPage(List.of(), currentPage, currentPageSize);
|
||||
}
|
||||
|
||||
String normalizedEntityType = normalizeBusinessEntityType(entityType);
|
||||
String repositoryEntityType = "plan".equals(normalizedEntityType) ? null : normalizedEntityType;
|
||||
IPage<DigitalEmployeeSyncRecord> page = digitalEmployeeSyncRecordRepository.queryBusinessRecords(
|
||||
tenantId,
|
||||
clientKey,
|
||||
deviceId,
|
||||
repositoryEntityType,
|
||||
entityId,
|
||||
updatedFrom,
|
||||
updatedTo,
|
||||
syncStatus,
|
||||
currentPage,
|
||||
currentPageSize
|
||||
);
|
||||
List<DigitalEmployeeBusinessViewRowDto> allRows = page.getRecords().stream()
|
||||
.map(this::toBusinessRow)
|
||||
.toList();
|
||||
List<DigitalEmployeeBusinessViewRowDto> rows = "plan".equals(normalizedEntityType)
|
||||
? enrichPlanRows(allRows)
|
||||
: allRows.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);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DigitalEmployeePlanBusinessViewDetailDto queryPlanBusinessViewDetail(
|
||||
String planId,
|
||||
String clientKey,
|
||||
String deviceId
|
||||
) {
|
||||
Long tenantId = RequestContext.get() == null ? null : RequestContext.get().getTenantId();
|
||||
if (tenantId == null || StringUtils.isBlank(planId)) {
|
||||
return planDetail(null, List.of());
|
||||
}
|
||||
IPage<DigitalEmployeeSyncRecord> page = digitalEmployeeSyncRecordRepository.queryBusinessRecords(
|
||||
tenantId,
|
||||
clientKey,
|
||||
deviceId,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
DEFAULT_PAGE_NO,
|
||||
MAX_PAGE_SIZE
|
||||
);
|
||||
List<DigitalEmployeeBusinessViewRowDto> rows = page.getRecords().stream()
|
||||
.map(this::toBusinessRow)
|
||||
.filter(row -> StringUtils.equals(planId, planIdOf(row)))
|
||||
.toList();
|
||||
DigitalEmployeeBusinessViewRowDto plan = enrichPlanRows(rows).stream()
|
||||
.filter(row -> StringUtils.equals(row.getEntityId(), planId))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
return planDetail(plan, rows);
|
||||
}
|
||||
|
||||
private DigitalEmployeeBusinessViewPageDto businessPage(List<DigitalEmployeeBusinessViewRowDto> rows, long pageNo, long pageSize) {
|
||||
int fromIndex = (int) Math.min(Math.max(pageNo - 1, 0) * pageSize, rows.size());
|
||||
int toIndex = (int) Math.min(fromIndex + pageSize, rows.size());
|
||||
return DigitalEmployeeBusinessViewPageDto.builder()
|
||||
.total((long) rows.size())
|
||||
.pageNo(pageNo)
|
||||
.pageSize(pageSize)
|
||||
.records(rows.subList(fromIndex, toIndex))
|
||||
.build();
|
||||
}
|
||||
|
||||
private DigitalEmployeePlanBusinessViewDetailDto planDetail(DigitalEmployeeBusinessViewRowDto plan, List<DigitalEmployeeBusinessViewRowDto> rows) {
|
||||
return DigitalEmployeePlanBusinessViewDetailDto.builder()
|
||||
.plan(plan)
|
||||
.tasks(rowsByType(rows, "task"))
|
||||
.runs(rowsByType(rows, "run"))
|
||||
.events(rowsByType(rows, "event"))
|
||||
.artifacts(rowsByType(rows, "artifact"))
|
||||
.approvals(rowsByType(rows, "approval"))
|
||||
.build();
|
||||
}
|
||||
|
||||
private List<DigitalEmployeeBusinessViewRowDto> rowsByType(List<DigitalEmployeeBusinessViewRowDto> rows, String entityType) {
|
||||
return rows.stream().filter(row -> StringUtils.equals(row.getEntityType(), entityType)).toList();
|
||||
}
|
||||
|
||||
private List<DigitalEmployeeBusinessViewRowDto> enrichPlanRows(List<DigitalEmployeeBusinessViewRowDto> rows) {
|
||||
return rows.stream()
|
||||
.filter(row -> StringUtils.equals(row.getEntityType(), "plan"))
|
||||
.map(plan -> {
|
||||
String planId = plan.getEntityId();
|
||||
int taskCount = (int) rows.stream().filter(row -> StringUtils.equals(row.getEntityType(), "task") && StringUtils.equals(planId, row.getPlanId())).count();
|
||||
int runCount = (int) rows.stream().filter(row -> StringUtils.equals(row.getEntityType(), "run") && StringUtils.equals(planId, row.getPlanId())).count();
|
||||
String latestEventAt = rows.stream()
|
||||
.filter(row -> StringUtils.equals(row.getEntityType(), "event") && StringUtils.equals(planId, row.getPlanId()))
|
||||
.map(DigitalEmployeeBusinessViewRowDto::getOccurredAt)
|
||||
.filter(StringUtils::isNotBlank)
|
||||
.max(Comparator.naturalOrder())
|
||||
.orElse(null);
|
||||
plan.setTaskCount(taskCount);
|
||||
plan.setRunCount(runCount);
|
||||
plan.setLatestEventAt(latestEventAt);
|
||||
return plan;
|
||||
})
|
||||
.toList();
|
||||
}
|
||||
|
||||
private DigitalEmployeeBusinessViewRowDto toBusinessRow(DigitalEmployeeSyncRecord record) {
|
||||
Map<String, Object> businessView = readJsonObject(record.getBusinessView());
|
||||
Map<String, Object> payload = readJsonObject(record.getPayload());
|
||||
Map<String, Object> summary = readJsonObject(record.getEntitySummary());
|
||||
String entityType = stringValue(businessView.get("entity_type"), record.getEntityType());
|
||||
String entityId = record.getEntityId();
|
||||
String title = firstString(
|
||||
businessView.get("title"), businessView.get("name"),
|
||||
summary.get("title"),
|
||||
payload.get("title"), payload.get("name"), payload.get("objective"), payload.get("message"),
|
||||
entityId
|
||||
);
|
||||
String status = firstString(businessView.get("status"), summary.get("status"), payload.get("status"), payload.get("syncStatus"), payload.get("sync_status"));
|
||||
String startedAt = firstString(businessView.get("started_at"), businessView.get("startedAt"), payload.get("startedAt"), payload.get("started_at"));
|
||||
String finishedAt = firstString(businessView.get("finished_at"), businessView.get("finishedAt"), payload.get("finishedAt"), payload.get("finished_at"));
|
||||
Long durationMs = numberValue(businessView.get("duration_ms"));
|
||||
if (durationMs == null) {
|
||||
durationMs = durationMs(startedAt, finishedAt);
|
||||
}
|
||||
return DigitalEmployeeBusinessViewRowDto.builder()
|
||||
.syncRecordId(record.getId())
|
||||
.syncRecordUrl(syncRecordUrl(record.getOutboxId()))
|
||||
.entityType(entityType)
|
||||
.entityId(entityId)
|
||||
.operation(record.getOperation())
|
||||
.title(title)
|
||||
.status(status)
|
||||
.summary(firstString(businessView.get("summary"), businessView.get("objective"), businessView.get("message"), summary.get("summary"), payload.get("summary"), payload.get("objective"), payload.get("message")))
|
||||
.planId(firstString(businessView.get("plan_id"), businessView.get("planId"), payload.get("plan_id"), payload.get("planId"), "plan".equals(entityType) ? entityId : null))
|
||||
.taskId(firstString(businessView.get("task_id"), businessView.get("taskId"), payload.get("task_id"), payload.get("taskId"), "task".equals(entityType) ? entityId : null))
|
||||
.runId(firstString(businessView.get("run_id"), businessView.get("runId"), payload.get("run_id"), payload.get("runId"), "run".equals(entityType) ? entityId : null))
|
||||
.kind(firstString(businessView.get("kind"), payload.get("kind")))
|
||||
.occurredAt(firstString(businessView.get("occurred_at"), businessView.get("occurredAt"), payload.get("occurred_at"), payload.get("occurredAt")))
|
||||
.startedAt(startedAt)
|
||||
.finishedAt(finishedAt)
|
||||
.durationMs(durationMs)
|
||||
.syncStatus(firstString(businessView.get("sync_status"), businessView.get("syncStatus"), payload.get("sync_status"), payload.get("syncStatus")))
|
||||
.clientKeyMasked(maskClientKey(record.getClientKey()))
|
||||
.deviceId(record.getDeviceId())
|
||||
.syncedAt(record.getSyncedAt())
|
||||
.modified(record.getModified())
|
||||
.created(record.getCreated())
|
||||
.businessView(businessView)
|
||||
.payload(payload)
|
||||
.lastEventMessage(lastEventMessage(entityType, businessView, payload))
|
||||
.build();
|
||||
}
|
||||
|
||||
private String planIdOf(DigitalEmployeeBusinessViewRowDto row) {
|
||||
return StringUtils.equals(row.getEntityType(), "plan") ? row.getEntityId() : row.getPlanId();
|
||||
}
|
||||
|
||||
private String lastEventMessage(String entityType, Map<String, Object> businessView, Map<String, Object> payload) {
|
||||
if (!StringUtils.equals(entityType, "run")) return null;
|
||||
return firstString(businessView.get("last_event_message"), payload.get("lastEventMessage"), payload.get("message"));
|
||||
}
|
||||
|
||||
private boolean matchesText(String expected, String actual) {
|
||||
return StringUtils.isBlank(expected) || StringUtils.equals(expected, actual);
|
||||
}
|
||||
|
||||
private String normalizeBusinessEntityType(String value) {
|
||||
String normalized = StringUtils.trimToEmpty(value).toLowerCase();
|
||||
if (normalized.endsWith("s")) normalized = normalized.substring(0, normalized.length() - 1);
|
||||
return normalized;
|
||||
}
|
||||
|
||||
private String syncRecordUrl(String outboxId) {
|
||||
return "/system/content/content-digital-employee-sync?outbox_id=" + StringUtils.defaultString(outboxId);
|
||||
}
|
||||
|
||||
private String maskClientKey(String clientKey) {
|
||||
if (StringUtils.isBlank(clientKey)) return null;
|
||||
String trimmed = clientKey.trim();
|
||||
if (trimmed.length() <= 7) return "***";
|
||||
return trimmed.substring(0, 4) + "*********" + trimmed.substring(trimmed.length() - 3);
|
||||
}
|
||||
|
||||
private Map<String, Object> readJsonObject(String value) {
|
||||
if (StringUtils.isBlank(value)) return new LinkedHashMap<>();
|
||||
try {
|
||||
Map<String, Object> parsed = objectMapper.readValue(value, new TypeReference<>() {});
|
||||
return parsed == null ? new LinkedHashMap<>() : parsed;
|
||||
} catch (Exception e) {
|
||||
return new LinkedHashMap<>();
|
||||
}
|
||||
}
|
||||
|
||||
private String firstString(Object... values) {
|
||||
for (Object value : values) {
|
||||
String candidate = stringValue(value, null);
|
||||
if (StringUtils.isNotBlank(candidate)) return candidate;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String stringValue(Object value, String fallback) {
|
||||
if (value == null) return fallback;
|
||||
String text = Objects.toString(value, "").trim();
|
||||
return StringUtils.isBlank(text) ? fallback : text;
|
||||
}
|
||||
|
||||
private Long numberValue(Object value) {
|
||||
if (value instanceof Number number) return number.longValue();
|
||||
if (value instanceof String text && StringUtils.isNotBlank(text)) {
|
||||
try {
|
||||
return Long.parseLong(text.trim());
|
||||
} catch (NumberFormatException ignored) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private Long durationMs(String startedAt, String finishedAt) {
|
||||
if (StringUtils.isBlank(startedAt) || StringUtils.isBlank(finishedAt)) return null;
|
||||
try {
|
||||
return Instant.parse(finishedAt).toEpochMilli() - Instant.parse(startedAt).toEpochMilli();
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private String toJson(Object payload) {
|
||||
if (payload == null) {
|
||||
return "{}";
|
||||
|
||||
@@ -0,0 +1,250 @@
|
||||
package com.xspaceagi.agent.core.application.service;
|
||||
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.xspaceagi.agent.core.adapter.dto.digital.DigitalEmployeeBusinessViewPageDto;
|
||||
import com.xspaceagi.agent.core.adapter.dto.digital.DigitalEmployeeBusinessViewRowDto;
|
||||
import com.xspaceagi.agent.core.adapter.dto.digital.DigitalEmployeePlanBusinessViewDetailDto;
|
||||
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.DigitalEmployeeSyncRecordRepository;
|
||||
import com.xspaceagi.agent.core.adapter.repository.entity.DigitalEmployeeSyncRecord;
|
||||
import com.xspaceagi.system.spec.common.RequestContext;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
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.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
class DigitalEmployeeSyncApplicationServiceImplTest {
|
||||
|
||||
private DigitalEmployeeSyncRecordRepository repository;
|
||||
private DigitalEmployeeSyncApplicationServiceImpl service;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
RequestContext<Object> context = new RequestContext<>();
|
||||
context.setTenantId(101L);
|
||||
context.setUserId(202L);
|
||||
RequestContext.set(context);
|
||||
|
||||
repository = mock(DigitalEmployeeSyncRecordRepository.class);
|
||||
service = new DigitalEmployeeSyncApplicationServiceImpl();
|
||||
ReflectionTestUtils.setField(service, "digitalEmployeeSyncRecordRepository", repository);
|
||||
ReflectionTestUtils.setField(service, "objectMapper", new ObjectMapper());
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void tearDown() {
|
||||
RequestContext.remove();
|
||||
}
|
||||
|
||||
@Test
|
||||
void syncOutboxPersistsBusinessViewSummaryAndContractVersion() {
|
||||
DigitalEmployeeSyncItemDto item = new DigitalEmployeeSyncItemDto();
|
||||
item.setOutboxId("outbox-plan-1");
|
||||
item.setEntityType("plan");
|
||||
item.setEntityId("plan-1");
|
||||
item.setOperation("upsert");
|
||||
item.setContractVersion("qimingclaw.digital_employee.sync.v1");
|
||||
item.setEntitySummary(Map.of("title", "客户回访", "status", "active", "summary", "跟进高价值客户"));
|
||||
item.setBusinessView(Map.of("local_id", "plan-1", "title", "客户回访", "status", "active", "objective", "跟进高价值客户"));
|
||||
item.setPayload(Map.of("id", "plan-1", "title", "客户回访", "status", "active"));
|
||||
|
||||
DigitalEmployeeSyncRequestDto request = new DigitalEmployeeSyncRequestDto();
|
||||
request.setClientKey("client-key-001");
|
||||
request.setDeviceId("device-001");
|
||||
request.setItems(List.of(item));
|
||||
|
||||
service.syncOutbox(request);
|
||||
|
||||
ArgumentCaptor<DigitalEmployeeSyncRecord> captor = ArgumentCaptor.forClass(DigitalEmployeeSyncRecord.class);
|
||||
verify(repository).save(captor.capture());
|
||||
DigitalEmployeeSyncRecord record = captor.getValue();
|
||||
assertThat(record.getContractVersion()).isEqualTo("qimingclaw.digital_employee.sync.v1");
|
||||
assertThat(record.getEntitySummary()).contains("客户回访");
|
||||
assertThat(record.getBusinessView()).contains("objective").contains("跟进高价值客户");
|
||||
assertThat(record.getPayload()).contains("plan-1");
|
||||
assertThat(record.getTenantId()).isEqualTo(101L);
|
||||
assertThat(record.getUserId()).isEqualTo(202L);
|
||||
}
|
||||
|
||||
@Test
|
||||
void queryRecordsReturnsStoredBusinessMetadata() {
|
||||
DigitalEmployeeSyncRecord record = planRecord("plan-1", "客户回访", "active", 101L, new Date(1_000));
|
||||
Page<DigitalEmployeeSyncRecord> page = new Page<>(1, 20, 1);
|
||||
page.setRecords(List.of(record));
|
||||
when(repository.queryRecords(eq(101L), eq("client-key-001"), eq("device-001"), eq("plan"), eq("plan-1"), eq("outbox-plan-1"), eq(1L), eq(20L)))
|
||||
.thenReturn(page);
|
||||
|
||||
DigitalEmployeeSyncRecordPageDto result = service.queryRecords("client-key-001", "device-001", "plan", "plan-1", "outbox-plan-1", 1L, 20L);
|
||||
|
||||
assertThat(result.getRecords()).hasSize(1);
|
||||
assertThat(result.getRecords().get(0).getContractVersion()).isEqualTo("qimingclaw.digital_employee.sync.v1");
|
||||
assertThat(result.getRecords().get(0).getEntitySummary()).contains("客户回访");
|
||||
assertThat(result.getRecords().get(0).getBusinessView()).contains("active");
|
||||
}
|
||||
|
||||
@Test
|
||||
void queryPlansBuildsBusinessRowsAndAggregatesRelatedCounts() {
|
||||
Date now = new Date(10_000);
|
||||
List<DigitalEmployeeSyncRecord> records = List.of(
|
||||
planRecord("plan-1", "客户回访", "active", 101L, now),
|
||||
taskRecord("task-1", "plan-1", "running", 101L, new Date(11_000)),
|
||||
runRecord("run-1", "plan-1", "task-1", "failed", 101L, new Date(12_000)),
|
||||
eventRecord("event-1", "plan-1", "task-1", "run-1", "plan_step_dispatch_failed", "派发失败", "failed", 101L, new Date(13_000))
|
||||
);
|
||||
when(repository.queryBusinessRecords(eq(101L), eq("client-key-001"), eq(null), eq(null), eq(null), eq(null), eq(null), eq(null), eq(1L), eq(20L)))
|
||||
.thenReturn(page(records));
|
||||
|
||||
DigitalEmployeeBusinessViewPageDto result = service.queryBusinessViews("plan", "client-key-001", null, null, null, null, null, null, 1L, 20L);
|
||||
|
||||
assertThat(result.getTotal()).isEqualTo(1);
|
||||
assertThat(result.getRecords()).hasSize(1);
|
||||
DigitalEmployeeBusinessViewRowDto plan = result.getRecords().get(0);
|
||||
assertThat(plan.getEntityType()).isEqualTo("plan");
|
||||
assertThat(plan.getEntityId()).isEqualTo("plan-1");
|
||||
assertThat(plan.getTitle()).isEqualTo("客户回访");
|
||||
assertThat(plan.getStatus()).isEqualTo("active");
|
||||
assertThat(plan.getTaskCount()).isEqualTo(1);
|
||||
assertThat(plan.getRunCount()).isEqualTo(1);
|
||||
assertThat(plan.getLatestEventAt()).isNotNull();
|
||||
assertThat(plan.getSyncRecordUrl()).contains("outbox-plan-1");
|
||||
assertThat(plan.getClientKeyMasked()).isEqualTo("clie*********001");
|
||||
}
|
||||
|
||||
@Test
|
||||
void queryEventsFiltersStatusEntityAndTimeRangeFromBusinessView() {
|
||||
Date from = new Date(10_000);
|
||||
Date to = new Date(20_000);
|
||||
when(repository.queryBusinessRecords(eq(101L), eq(null), eq(null), eq("event"), eq("event-1"), eq(from), eq(to), eq(null), eq(1L), eq(20L)))
|
||||
.thenReturn(page(List.of(
|
||||
eventRecord("event-1", "plan-1", "task-1", "run-1", "tool_call_audit", "工具允许", "allowed", 101L, new Date(12_000)),
|
||||
eventRecord("event-2", "plan-1", "task-1", "run-1", "tool_call_audit", "工具拒绝", "rejected", 101L, new Date(13_000))
|
||||
)));
|
||||
|
||||
DigitalEmployeeBusinessViewPageDto result = service.queryBusinessViews("event", null, null, "event-1", "allowed", null, from, to, 1L, 20L);
|
||||
|
||||
assertThat(result.getTotal()).isEqualTo(1);
|
||||
assertThat(result.getRecords().get(0).getEntityId()).isEqualTo("event-1");
|
||||
assertThat(result.getRecords().get(0).getKind()).isEqualTo("tool_call_audit");
|
||||
}
|
||||
|
||||
@Test
|
||||
void queryPlanDetailReturnsRelatedBusinessFacts() {
|
||||
when(repository.queryBusinessRecords(eq(101L), eq(null), eq(null), eq(null), eq(null), eq(null), eq(null), eq(null), eq(1L), eq(100L)))
|
||||
.thenReturn(page(List.of(
|
||||
planRecord("plan-1", "客户回访", "active", 101L, new Date(10_000)),
|
||||
taskRecord("task-1", "plan-1", "running", 101L, new Date(11_000)),
|
||||
runRecord("run-1", "plan-1", "task-1", "failed", 101L, new Date(12_000)),
|
||||
eventRecord("event-1", "plan-1", "task-1", "run-1", "approval_decision", "审批通过", "approved", 101L, new Date(13_000)),
|
||||
artifactRecord("artifact-1", "plan-1", "task-1", "ready", 101L, new Date(14_000)),
|
||||
approvalRecord("approval-1", "plan-1", "task-1", "pending", 101L, new Date(15_000))
|
||||
)));
|
||||
|
||||
DigitalEmployeePlanBusinessViewDetailDto result = service.queryPlanBusinessViewDetail("plan-1", null, null);
|
||||
|
||||
assertThat(result.getPlan().getEntityId()).isEqualTo("plan-1");
|
||||
assertThat(result.getTasks()).hasSize(1);
|
||||
assertThat(result.getRuns()).hasSize(1);
|
||||
assertThat(result.getEvents()).hasSize(1);
|
||||
assertThat(result.getArtifacts()).hasSize(1);
|
||||
assertThat(result.getApprovals()).hasSize(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
void queryBusinessViewsReturnsEmptyWhenTenantIsMissing() {
|
||||
RequestContext.remove();
|
||||
|
||||
DigitalEmployeeBusinessViewPageDto result = service.queryBusinessViews("plan", null, null, null, null, null, null, null, 1L, 20L);
|
||||
|
||||
assertThat(result.getTotal()).isZero();
|
||||
assertThat(result.getRecords()).isEmpty();
|
||||
verify(repository, never()).queryBusinessRecords(any(), any(), any(), any(), any(), any(), any(), any(), any(Long.class), any(Long.class));
|
||||
}
|
||||
|
||||
private IPage<DigitalEmployeeSyncRecord> page(List<DigitalEmployeeSyncRecord> records) {
|
||||
Page<DigitalEmployeeSyncRecord> page = new Page<>(1, 20, records.size());
|
||||
page.setRecords(records);
|
||||
return page;
|
||||
}
|
||||
|
||||
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", "计划摘要"),
|
||||
Map.of("id", planId, "title", title, "status", status));
|
||||
}
|
||||
|
||||
private DigitalEmployeeSyncRecord taskRecord(String taskId, String planId, String status, Long tenantId, Date syncedAt) {
|
||||
return record("outbox-" + taskId, "task", taskId, tenantId, syncedAt,
|
||||
Map.of("entity_type", "task", "local_id", taskId, "plan_id", planId, "title", "任务", "status", status),
|
||||
Map.of("id", taskId, "planId", planId, "status", status));
|
||||
}
|
||||
|
||||
private DigitalEmployeeSyncRecord runRecord(String runId, String planId, String taskId, String status, Long tenantId, Date syncedAt) {
|
||||
return record("outbox-" + runId, "run", runId, tenantId, syncedAt,
|
||||
Map.of("entity_type", "run", "local_id", runId, "plan_id", planId, "task_id", taskId, "status", status, "started_at", "2026-06-12T08:00:00.000Z", "finished_at", "2026-06-12T08:01:00.000Z"),
|
||||
Map.of("id", runId, "planId", planId, "taskId", taskId, "status", status));
|
||||
}
|
||||
|
||||
private DigitalEmployeeSyncRecord eventRecord(String eventId, String planId, String taskId, String runId, String kind, String message, String status, Long tenantId, Date syncedAt) {
|
||||
return record("outbox-" + eventId, "event", eventId, tenantId, syncedAt,
|
||||
Map.of("entity_type", "event", "local_id", eventId, "plan_id", planId, "task_id", taskId, "run_id", runId, "kind", kind, "message", message, "status", status, "occurred_at", "2026-06-12T08:02:00.000Z"),
|
||||
Map.of("id", eventId, "planId", planId, "taskId", taskId, "runId", runId, "kind", kind, "message", message, "status", status));
|
||||
}
|
||||
|
||||
private DigitalEmployeeSyncRecord artifactRecord(String artifactId, String planId, String taskId, String status, Long tenantId, Date syncedAt) {
|
||||
return record("outbox-" + artifactId, "artifact", artifactId, tenantId, syncedAt,
|
||||
Map.of("entity_type", "artifact", "local_id", artifactId, "plan_id", planId, "task_id", taskId, "title", "交付物", "status", status),
|
||||
Map.of("id", artifactId, "planId", planId, "taskId", taskId, "status", status));
|
||||
}
|
||||
|
||||
private DigitalEmployeeSyncRecord approvalRecord(String approvalId, String planId, String taskId, String status, Long tenantId, Date syncedAt) {
|
||||
return record("outbox-" + approvalId, "approval", approvalId, tenantId, syncedAt,
|
||||
Map.of("entity_type", "approval", "local_id", approvalId, "plan_id", planId, "task_id", taskId, "title", "审批", "status", status),
|
||||
Map.of("id", approvalId, "planId", planId, "taskId", taskId, "status", status));
|
||||
}
|
||||
|
||||
private DigitalEmployeeSyncRecord record(String outboxId, String entityType, String entityId, Long tenantId, Date syncedAt, Map<String, Object> businessView, Map<String, Object> payload) {
|
||||
DigitalEmployeeSyncRecord record = new DigitalEmployeeSyncRecord();
|
||||
record.setId((long) Math.abs(outboxId.hashCode()));
|
||||
record.setTenantId(tenantId);
|
||||
record.setUserId(202L);
|
||||
record.setClientKey("client-key-001");
|
||||
record.setDeviceId("device-001");
|
||||
record.setOutboxId(outboxId);
|
||||
record.setEntityType(entityType);
|
||||
record.setEntityId(entityId);
|
||||
record.setOperation("upsert");
|
||||
record.setContractVersion("qimingclaw.digital_employee.sync.v1");
|
||||
record.setEntitySummary(toJson(Map.of("title", businessView.getOrDefault("title", entityId), "status", businessView.getOrDefault("status", "unknown"))));
|
||||
record.setBusinessView(toJson(businessView));
|
||||
record.setPayload(toJson(payload));
|
||||
record.setSyncedAt(syncedAt);
|
||||
record.setModified(syncedAt);
|
||||
record.setCreated(syncedAt);
|
||||
return record;
|
||||
}
|
||||
|
||||
private String toJson(Map<String, Object> value) {
|
||||
try {
|
||||
return new ObjectMapper().writeValueAsString(value);
|
||||
} catch (Exception e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,8 @@ import com.xspaceagi.agent.core.infra.dao.mapper.DigitalEmployeeSyncRecordMapper
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@Service
|
||||
public class DigitalEmployeeSyncRecordRepositoryImpl
|
||||
extends ServiceImpl<DigitalEmployeeSyncRecordMapper, DigitalEmployeeSyncRecord>
|
||||
@@ -37,4 +39,30 @@ public class DigitalEmployeeSyncRecordRepositoryImpl
|
||||
.orderByDesc(DigitalEmployeeSyncRecord::getId);
|
||||
return page(new Page<>(pageNo, pageSize), queryWrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IPage<DigitalEmployeeSyncRecord> queryBusinessRecords(
|
||||
Long tenantId,
|
||||
String clientKey,
|
||||
String deviceId,
|
||||
String entityType,
|
||||
String entityId,
|
||||
Date updatedFrom,
|
||||
Date updatedTo,
|
||||
String syncStatus,
|
||||
long pageNo,
|
||||
long pageSize
|
||||
) {
|
||||
LambdaQueryWrapper<DigitalEmployeeSyncRecord> queryWrapper = new LambdaQueryWrapper<DigitalEmployeeSyncRecord>()
|
||||
.eq(tenantId != null, DigitalEmployeeSyncRecord::getTenantId, tenantId)
|
||||
.eq(StringUtils.isNotBlank(clientKey), DigitalEmployeeSyncRecord::getClientKey, clientKey)
|
||||
.eq(StringUtils.isNotBlank(deviceId), DigitalEmployeeSyncRecord::getDeviceId, deviceId)
|
||||
.eq(StringUtils.isNotBlank(entityType), DigitalEmployeeSyncRecord::getEntityType, entityType)
|
||||
.eq(StringUtils.isNotBlank(entityId), DigitalEmployeeSyncRecord::getEntityId, entityId)
|
||||
.ge(updatedFrom != null, DigitalEmployeeSyncRecord::getSyncedAt, updatedFrom)
|
||||
.le(updatedTo != null, DigitalEmployeeSyncRecord::getSyncedAt, updatedTo)
|
||||
.orderByDesc(DigitalEmployeeSyncRecord::getSyncedAt)
|
||||
.orderByDesc(DigitalEmployeeSyncRecord::getId);
|
||||
return page(new Page<>(pageNo, pageSize), queryWrapper);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,177 @@
|
||||
package com.xspaceagi.agent.web.ui.controller;
|
||||
|
||||
import com.xspaceagi.agent.core.adapter.application.DigitalEmployeeSyncApplicationService;
|
||||
import com.xspaceagi.agent.core.adapter.dto.digital.DigitalEmployeeBusinessViewPageDto;
|
||||
import com.xspaceagi.agent.core.adapter.dto.digital.DigitalEmployeePlanBusinessViewDetailDto;
|
||||
import com.xspaceagi.system.spec.annotation.RequireResource;
|
||||
import com.xspaceagi.system.spec.dto.ReqResult;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Date;
|
||||
|
||||
import static com.xspaceagi.system.spec.enums.ResourceEnum.CONTENT_DIGITAL_EMPLOYEE_SYNC_QUERY_LIST;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/digital-employee")
|
||||
public class DigitalEmployeeBusinessViewController {
|
||||
|
||||
@Resource
|
||||
private DigitalEmployeeSyncApplicationService digitalEmployeeSyncApplicationService;
|
||||
|
||||
@RequireResource(CONTENT_DIGITAL_EMPLOYEE_SYNC_QUERY_LIST)
|
||||
@RequestMapping(path = "/plans", method = RequestMethod.GET)
|
||||
public ReqResult<DigitalEmployeeBusinessViewPageDto> queryPlans(
|
||||
@RequestParam(name = "client_key", required = false) String clientKey,
|
||||
@RequestParam(name = "device_id", required = false) String deviceId,
|
||||
@RequestParam(name = "entity_id", required = false) String entityId,
|
||||
@RequestParam(name = "status", required = false) String status,
|
||||
@RequestParam(name = "sync_status", required = false) String syncStatus,
|
||||
@RequestParam(name = "updated_from", required = false) String updatedFrom,
|
||||
@RequestParam(name = "updated_to", required = false) String updatedTo,
|
||||
@RequestParam(name = "page_no", required = false) Long pageNo,
|
||||
@RequestParam(name = "page_size", required = false) Long pageSize
|
||||
) {
|
||||
return ReqResult.success(query("plan", clientKey, deviceId, entityId, status, syncStatus, updatedFrom, updatedTo, pageNo, pageSize));
|
||||
}
|
||||
|
||||
@RequireResource(CONTENT_DIGITAL_EMPLOYEE_SYNC_QUERY_LIST)
|
||||
@RequestMapping(path = "/plans/{plan_id}", method = RequestMethod.GET)
|
||||
public ReqResult<DigitalEmployeePlanBusinessViewDetailDto> queryPlanDetail(
|
||||
@PathVariable("plan_id") String planId,
|
||||
@RequestParam(name = "client_key", required = false) String clientKey,
|
||||
@RequestParam(name = "device_id", required = false) String deviceId
|
||||
) {
|
||||
return ReqResult.success(digitalEmployeeSyncApplicationService.queryPlanBusinessViewDetail(planId, clientKey, deviceId));
|
||||
}
|
||||
|
||||
@RequireResource(CONTENT_DIGITAL_EMPLOYEE_SYNC_QUERY_LIST)
|
||||
@RequestMapping(path = "/tasks", method = RequestMethod.GET)
|
||||
public ReqResult<DigitalEmployeeBusinessViewPageDto> queryTasks(
|
||||
@RequestParam(name = "client_key", required = false) String clientKey,
|
||||
@RequestParam(name = "device_id", required = false) String deviceId,
|
||||
@RequestParam(name = "entity_id", required = false) String entityId,
|
||||
@RequestParam(name = "status", required = false) String status,
|
||||
@RequestParam(name = "sync_status", required = false) String syncStatus,
|
||||
@RequestParam(name = "updated_from", required = false) String updatedFrom,
|
||||
@RequestParam(name = "updated_to", required = false) String updatedTo,
|
||||
@RequestParam(name = "page_no", required = false) Long pageNo,
|
||||
@RequestParam(name = "page_size", required = false) Long pageSize
|
||||
) {
|
||||
return ReqResult.success(query("task", clientKey, deviceId, entityId, status, syncStatus, updatedFrom, updatedTo, pageNo, pageSize));
|
||||
}
|
||||
|
||||
@RequireResource(CONTENT_DIGITAL_EMPLOYEE_SYNC_QUERY_LIST)
|
||||
@RequestMapping(path = "/runs", method = RequestMethod.GET)
|
||||
public ReqResult<DigitalEmployeeBusinessViewPageDto> queryRuns(
|
||||
@RequestParam(name = "client_key", required = false) String clientKey,
|
||||
@RequestParam(name = "device_id", required = false) String deviceId,
|
||||
@RequestParam(name = "entity_id", required = false) String entityId,
|
||||
@RequestParam(name = "status", required = false) String status,
|
||||
@RequestParam(name = "sync_status", required = false) String syncStatus,
|
||||
@RequestParam(name = "updated_from", required = false) String updatedFrom,
|
||||
@RequestParam(name = "updated_to", required = false) String updatedTo,
|
||||
@RequestParam(name = "page_no", required = false) Long pageNo,
|
||||
@RequestParam(name = "page_size", required = false) Long pageSize
|
||||
) {
|
||||
return ReqResult.success(query("run", clientKey, deviceId, entityId, status, syncStatus, updatedFrom, updatedTo, pageNo, pageSize));
|
||||
}
|
||||
|
||||
@RequireResource(CONTENT_DIGITAL_EMPLOYEE_SYNC_QUERY_LIST)
|
||||
@RequestMapping(path = "/events", method = RequestMethod.GET)
|
||||
public ReqResult<DigitalEmployeeBusinessViewPageDto> queryEvents(
|
||||
@RequestParam(name = "client_key", required = false) String clientKey,
|
||||
@RequestParam(name = "device_id", required = false) String deviceId,
|
||||
@RequestParam(name = "entity_id", required = false) String entityId,
|
||||
@RequestParam(name = "status", required = false) String status,
|
||||
@RequestParam(name = "sync_status", required = false) String syncStatus,
|
||||
@RequestParam(name = "updated_from", required = false) String updatedFrom,
|
||||
@RequestParam(name = "updated_to", required = false) String updatedTo,
|
||||
@RequestParam(name = "page_no", required = false) Long pageNo,
|
||||
@RequestParam(name = "page_size", required = false) Long pageSize
|
||||
) {
|
||||
return ReqResult.success(query("event", clientKey, deviceId, entityId, status, syncStatus, updatedFrom, updatedTo, pageNo, pageSize));
|
||||
}
|
||||
|
||||
@RequireResource(CONTENT_DIGITAL_EMPLOYEE_SYNC_QUERY_LIST)
|
||||
@RequestMapping(path = "/artifacts", method = RequestMethod.GET)
|
||||
public ReqResult<DigitalEmployeeBusinessViewPageDto> queryArtifacts(
|
||||
@RequestParam(name = "client_key", required = false) String clientKey,
|
||||
@RequestParam(name = "device_id", required = false) String deviceId,
|
||||
@RequestParam(name = "entity_id", required = false) String entityId,
|
||||
@RequestParam(name = "status", required = false) String status,
|
||||
@RequestParam(name = "sync_status", required = false) String syncStatus,
|
||||
@RequestParam(name = "updated_from", required = false) String updatedFrom,
|
||||
@RequestParam(name = "updated_to", required = false) String updatedTo,
|
||||
@RequestParam(name = "page_no", required = false) Long pageNo,
|
||||
@RequestParam(name = "page_size", required = false) Long pageSize
|
||||
) {
|
||||
return ReqResult.success(query("artifact", clientKey, deviceId, entityId, status, syncStatus, updatedFrom, updatedTo, pageNo, pageSize));
|
||||
}
|
||||
|
||||
@RequireResource(CONTENT_DIGITAL_EMPLOYEE_SYNC_QUERY_LIST)
|
||||
@RequestMapping(path = "/approvals", method = RequestMethod.GET)
|
||||
public ReqResult<DigitalEmployeeBusinessViewPageDto> queryApprovals(
|
||||
@RequestParam(name = "client_key", required = false) String clientKey,
|
||||
@RequestParam(name = "device_id", required = false) String deviceId,
|
||||
@RequestParam(name = "entity_id", required = false) String entityId,
|
||||
@RequestParam(name = "status", required = false) String status,
|
||||
@RequestParam(name = "sync_status", required = false) String syncStatus,
|
||||
@RequestParam(name = "updated_from", required = false) String updatedFrom,
|
||||
@RequestParam(name = "updated_to", required = false) String updatedTo,
|
||||
@RequestParam(name = "page_no", required = false) Long pageNo,
|
||||
@RequestParam(name = "page_size", required = false) Long pageSize
|
||||
) {
|
||||
return ReqResult.success(query("approval", clientKey, deviceId, entityId, status, syncStatus, updatedFrom, updatedTo, pageNo, pageSize));
|
||||
}
|
||||
|
||||
private DigitalEmployeeBusinessViewPageDto query(
|
||||
String entityType,
|
||||
String clientKey,
|
||||
String deviceId,
|
||||
String entityId,
|
||||
String status,
|
||||
String syncStatus,
|
||||
String updatedFrom,
|
||||
String updatedTo,
|
||||
Long pageNo,
|
||||
Long pageSize
|
||||
) {
|
||||
return digitalEmployeeSyncApplicationService.queryBusinessViews(
|
||||
entityType,
|
||||
clientKey,
|
||||
deviceId,
|
||||
entityId,
|
||||
status,
|
||||
syncStatus,
|
||||
parseDate(updatedFrom),
|
||||
parseDate(updatedTo),
|
||||
pageNo,
|
||||
pageSize
|
||||
);
|
||||
}
|
||||
|
||||
private Date parseDate(String value) {
|
||||
if (StringUtils.isBlank(value)) return null;
|
||||
String trimmed = value.trim();
|
||||
try {
|
||||
return Date.from(Instant.parse(trimmed));
|
||||
} catch (Exception ignored) {
|
||||
try {
|
||||
LocalDateTime localDateTime = LocalDateTime.parse(trimmed, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
|
||||
return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
|
||||
} catch (Exception ignoredAgain) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user