吸收数字员工资产通知日报业务收口
This commit is contained in:
@@ -72,8 +72,14 @@ public class DigitalEmployeeAdminWorkbenchRowDto {
|
|||||||
private Boolean hardInterruptDisabled;
|
private Boolean hardInterruptDisabled;
|
||||||
@JsonProperty("artifact_id")
|
@JsonProperty("artifact_id")
|
||||||
private String artifactId;
|
private String artifactId;
|
||||||
|
@JsonProperty("artifact_graph_id")
|
||||||
|
private String artifactGraphId;
|
||||||
@JsonProperty("artifact_group_id")
|
@JsonProperty("artifact_group_id")
|
||||||
private String artifactGroupId;
|
private String artifactGroupId;
|
||||||
|
@JsonProperty("group_key")
|
||||||
|
private String groupKey;
|
||||||
|
@JsonProperty("related_artifact_ids")
|
||||||
|
private List<String> relatedArtifactIds;
|
||||||
@JsonProperty("artifact_count")
|
@JsonProperty("artifact_count")
|
||||||
private Long artifactCount;
|
private Long artifactCount;
|
||||||
@JsonProperty("device_count")
|
@JsonProperty("device_count")
|
||||||
@@ -90,10 +96,20 @@ public class DigitalEmployeeAdminWorkbenchRowDto {
|
|||||||
private Long cleanupEligibleCount;
|
private Long cleanupEligibleCount;
|
||||||
@JsonProperty("batch_cleanup_disabled")
|
@JsonProperty("batch_cleanup_disabled")
|
||||||
private Boolean batchCleanupDisabled;
|
private Boolean batchCleanupDisabled;
|
||||||
|
@JsonProperty("retention_conflict_status")
|
||||||
|
private String retentionConflictStatus;
|
||||||
|
@JsonProperty("cleanup_conflict_status")
|
||||||
|
private String cleanupConflictStatus;
|
||||||
|
@JsonProperty("remote_delete_disabled")
|
||||||
|
private Boolean remoteDeleteDisabled;
|
||||||
@JsonProperty("notification_id")
|
@JsonProperty("notification_id")
|
||||||
private String notificationId;
|
private String notificationId;
|
||||||
|
@JsonProperty("collaboration_thread_id")
|
||||||
|
private String collaborationThreadId;
|
||||||
@JsonProperty("subscription_policy_id")
|
@JsonProperty("subscription_policy_id")
|
||||||
private String subscriptionPolicyId;
|
private String subscriptionPolicyId;
|
||||||
|
@JsonProperty("subscription_conflict_status")
|
||||||
|
private String subscriptionConflictStatus;
|
||||||
@JsonProperty("notification_policy_id")
|
@JsonProperty("notification_policy_id")
|
||||||
private String notificationPolicyId;
|
private String notificationPolicyId;
|
||||||
@JsonProperty("subscription_status")
|
@JsonProperty("subscription_status")
|
||||||
@@ -105,16 +121,38 @@ public class DigitalEmployeeAdminWorkbenchRowDto {
|
|||||||
private String channel;
|
private String channel;
|
||||||
@JsonProperty("delivery_status")
|
@JsonProperty("delivery_status")
|
||||||
private String deliveryStatus;
|
private String deliveryStatus;
|
||||||
|
@JsonProperty("delivery_attempt_id")
|
||||||
|
private String deliveryAttemptId;
|
||||||
|
@JsonProperty("send_request_id")
|
||||||
|
private String sendRequestId;
|
||||||
|
@JsonProperty("real_push_disabled")
|
||||||
|
private Boolean realPushDisabled;
|
||||||
@JsonProperty("conflict_status")
|
@JsonProperty("conflict_status")
|
||||||
private String conflictStatus;
|
private String conflictStatus;
|
||||||
@JsonProperty("report_id")
|
@JsonProperty("report_id")
|
||||||
private String reportId;
|
private String reportId;
|
||||||
@JsonProperty("daily_report_fact_id")
|
@JsonProperty("daily_report_fact_id")
|
||||||
private String dailyReportFactId;
|
private String dailyReportFactId;
|
||||||
|
@JsonProperty("daily_report_physical_fact_status")
|
||||||
|
private String dailyReportPhysicalFactStatus;
|
||||||
@JsonProperty("send_record_id")
|
@JsonProperty("send_record_id")
|
||||||
private String sendRecordId;
|
private String sendRecordId;
|
||||||
|
@JsonProperty("send_channel")
|
||||||
|
private String sendChannel;
|
||||||
|
@JsonProperty("send_request_status")
|
||||||
|
private String sendRequestStatus;
|
||||||
|
@JsonProperty("external_send_disabled")
|
||||||
|
private Boolean externalSendDisabled;
|
||||||
|
@JsonProperty("third_party_channel_disabled")
|
||||||
|
private Boolean thirdPartyChannelDisabled;
|
||||||
@JsonProperty("approval_decision_status")
|
@JsonProperty("approval_decision_status")
|
||||||
private String approvalDecisionStatus;
|
private String approvalDecisionStatus;
|
||||||
|
@JsonProperty("advanced_query_supported")
|
||||||
|
private Boolean advancedQuerySupported;
|
||||||
|
@JsonProperty("aggregation_scope")
|
||||||
|
private String aggregationScope;
|
||||||
|
@JsonProperty("materialized_source")
|
||||||
|
private String materializedSource;
|
||||||
@JsonProperty("daily_report_approval_id")
|
@JsonProperty("daily_report_approval_id")
|
||||||
private String dailyReportApprovalId;
|
private String dailyReportApprovalId;
|
||||||
@JsonProperty("daily_report_approval_action")
|
@JsonProperty("daily_report_approval_action")
|
||||||
|
|||||||
@@ -58,5 +58,11 @@ public class DigitalEmployeeBusinessViewRowDto {
|
|||||||
private String latestEventAt;
|
private String latestEventAt;
|
||||||
@JsonProperty("last_event_message")
|
@JsonProperty("last_event_message")
|
||||||
private String lastEventMessage;
|
private String lastEventMessage;
|
||||||
|
@JsonProperty("advanced_query_supported")
|
||||||
|
private Boolean advancedQuerySupported;
|
||||||
|
@JsonProperty("aggregation_scope")
|
||||||
|
private String aggregationScope;
|
||||||
|
@JsonProperty("materialized_source")
|
||||||
|
private String materializedSource;
|
||||||
private Boolean materialized;
|
private Boolean materialized;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,7 +71,8 @@ public class DigitalEmployeeSyncApplicationServiceImpl implements DigitalEmploye
|
|||||||
"notification:mark_read", "notification:dismiss",
|
"notification:mark_read", "notification:dismiss",
|
||||||
"notification_policy:pull_policy", "notification_policy:mark_reviewed", "notification_policy:dismiss",
|
"notification_policy:pull_policy", "notification_policy:mark_reviewed", "notification_policy:dismiss",
|
||||||
"artifact:mark_keep", "artifact:mark_expire", "artifact:mark_reviewed", "artifact:record_cleanup_request",
|
"artifact:mark_keep", "artifact:mark_expire", "artifact:mark_reviewed", "artifact:record_cleanup_request",
|
||||||
"daily_report:mark_delivered", "daily_report:mark_confirmed", "daily_report:request_approval", "daily_report:record_approval_decision",
|
"notification:record_send_request", "notification:record_send_result",
|
||||||
|
"daily_report:mark_delivered", "daily_report:mark_confirmed", "daily_report:request_approval", "daily_report:record_approval_decision", "daily_report:record_send_request", "daily_report:record_send_result",
|
||||||
"memory:archive_memory", "memory:restore_memory", "memory:mark_reviewed",
|
"memory:archive_memory", "memory:restore_memory", "memory:mark_reviewed",
|
||||||
"memory_policy:pull_policy", "memory_policy:mark_reviewed", "memory_policy:dismiss",
|
"memory_policy:pull_policy", "memory_policy:mark_reviewed", "memory_policy:dismiss",
|
||||||
"skill:mark_reviewed", "skill:dismiss",
|
"skill:mark_reviewed", "skill:dismiss",
|
||||||
@@ -1028,6 +1029,11 @@ public class DigitalEmployeeSyncApplicationServiceImpl implements DigitalEmploye
|
|||||||
case "auto_merge_policy" -> List.of("auto_merge_policy_disabled");
|
case "auto_merge_policy" -> List.of("auto_merge_policy_disabled");
|
||||||
case "auto_decide_approval" -> List.of("auto_decision_disabled");
|
case "auto_decide_approval" -> List.of("auto_decision_disabled");
|
||||||
case "route_recover_execute" -> List.of("route_recovery_disabled");
|
case "route_recover_execute" -> List.of("route_recovery_disabled");
|
||||||
|
case "cleanup_file_batch" -> List.of("batch_cleanup_disabled");
|
||||||
|
case "remote_delete_artifact" -> List.of("remote_delete_disabled");
|
||||||
|
case "real_push_notification" -> List.of("real_push_disabled");
|
||||||
|
case "external_send_daily_report" -> List.of("external_send_disabled");
|
||||||
|
case "third_party_send" -> List.of("third_party_channel_disabled");
|
||||||
case "run_schedule_now" -> List.of("run_schedule_now_disabled");
|
case "run_schedule_now" -> List.of("run_schedule_now_disabled");
|
||||||
case "start_scheduler" -> List.of("start_scheduler_disabled");
|
case "start_scheduler" -> List.of("start_scheduler_disabled");
|
||||||
case "hard_interrupt" -> List.of("hard_interrupt_disabled");
|
case "hard_interrupt" -> List.of("hard_interrupt_disabled");
|
||||||
@@ -1114,7 +1120,10 @@ public class DigitalEmployeeSyncApplicationServiceImpl implements DigitalEmploye
|
|||||||
.policyGuardStatus(firstString(businessView.get("policy_guard_status"), businessView.get("policyGuardStatus"), payload.get("policy_guard_status"), payload.get("policyGuardStatus")))
|
.policyGuardStatus(firstString(businessView.get("policy_guard_status"), businessView.get("policyGuardStatus"), payload.get("policy_guard_status"), payload.get("policyGuardStatus")))
|
||||||
.hardInterruptDisabled(nullableBooleanValue(firstPresent(businessView.get("hard_interrupt_disabled"), businessView.get("hardInterruptDisabled"), payload.get("hard_interrupt_disabled"), payload.get("hardInterruptDisabled"))))
|
.hardInterruptDisabled(nullableBooleanValue(firstPresent(businessView.get("hard_interrupt_disabled"), businessView.get("hardInterruptDisabled"), payload.get("hard_interrupt_disabled"), payload.get("hardInterruptDisabled"))))
|
||||||
.artifactId(firstString(businessView.get("artifact_id"), payload.get("artifact_id"), "artifact".equals(record.getEntityType()) ? record.getEntityId() : null))
|
.artifactId(firstString(businessView.get("artifact_id"), payload.get("artifact_id"), "artifact".equals(record.getEntityType()) ? record.getEntityId() : null))
|
||||||
|
.artifactGraphId(firstString(businessView.get("artifact_graph_id"), businessView.get("artifactGraphId"), payload.get("artifact_graph_id"), payload.get("artifactGraphId")))
|
||||||
.artifactGroupId(firstString(businessView.get("artifact_group_id"), businessView.get("artifactGroupId"), payload.get("artifact_group_id"), payload.get("artifactGroupId")))
|
.artifactGroupId(firstString(businessView.get("artifact_group_id"), businessView.get("artifactGroupId"), payload.get("artifact_group_id"), payload.get("artifactGroupId")))
|
||||||
|
.groupKey(firstString(businessView.get("group_key"), businessView.get("groupKey"), payload.get("group_key"), payload.get("groupKey")))
|
||||||
|
.relatedArtifactIds(stringListValue(firstPresent(businessView.get("related_artifact_ids"), businessView.get("relatedArtifactIds"), payload.get("related_artifact_ids"), payload.get("relatedArtifactIds"))))
|
||||||
.artifactCount(numberValue(firstPresent(businessView.get("artifact_count"), businessView.get("artifactCount"), payload.get("artifact_count"), payload.get("artifactCount"))))
|
.artifactCount(numberValue(firstPresent(businessView.get("artifact_count"), businessView.get("artifactCount"), payload.get("artifact_count"), payload.get("artifactCount"))))
|
||||||
.deviceCount(numberValue(firstPresent(businessView.get("device_count"), businessView.get("deviceCount"), payload.get("device_count"), payload.get("deviceCount"))))
|
.deviceCount(numberValue(firstPresent(businessView.get("device_count"), businessView.get("deviceCount"), payload.get("device_count"), payload.get("deviceCount"))))
|
||||||
.versionCount(numberValue(firstPresent(businessView.get("version_count"), businessView.get("versionCount"), payload.get("version_count"), payload.get("versionCount"))))
|
.versionCount(numberValue(firstPresent(businessView.get("version_count"), businessView.get("versionCount"), payload.get("version_count"), payload.get("versionCount"))))
|
||||||
@@ -1123,19 +1132,35 @@ public class DigitalEmployeeSyncApplicationServiceImpl implements DigitalEmploye
|
|||||||
.cleanupRequestId(firstString(businessView.get("cleanup_request_id"), businessView.get("cleanupRequestId"), payload.get("cleanup_request_id"), payload.get("cleanupRequestId")))
|
.cleanupRequestId(firstString(businessView.get("cleanup_request_id"), businessView.get("cleanupRequestId"), payload.get("cleanup_request_id"), payload.get("cleanupRequestId")))
|
||||||
.cleanupEligibleCount(numberValue(firstPresent(businessView.get("cleanup_eligible_count"), businessView.get("cleanupEligibleCount"), payload.get("cleanup_eligible_count"), payload.get("cleanupEligibleCount"))))
|
.cleanupEligibleCount(numberValue(firstPresent(businessView.get("cleanup_eligible_count"), businessView.get("cleanupEligibleCount"), payload.get("cleanup_eligible_count"), payload.get("cleanupEligibleCount"))))
|
||||||
.batchCleanupDisabled(nullableBooleanValue(firstPresent(businessView.get("batch_cleanup_disabled"), businessView.get("batchCleanupDisabled"), payload.get("batch_cleanup_disabled"), payload.get("batchCleanupDisabled"))))
|
.batchCleanupDisabled(nullableBooleanValue(firstPresent(businessView.get("batch_cleanup_disabled"), businessView.get("batchCleanupDisabled"), payload.get("batch_cleanup_disabled"), payload.get("batchCleanupDisabled"))))
|
||||||
|
.retentionConflictStatus(firstString(businessView.get("retention_conflict_status"), businessView.get("retentionConflictStatus"), payload.get("retention_conflict_status"), payload.get("retentionConflictStatus")))
|
||||||
|
.cleanupConflictStatus(firstString(businessView.get("cleanup_conflict_status"), businessView.get("cleanupConflictStatus"), payload.get("cleanup_conflict_status"), payload.get("cleanupConflictStatus")))
|
||||||
|
.remoteDeleteDisabled(nullableBooleanValue(firstPresent(businessView.get("remote_delete_disabled"), businessView.get("remoteDeleteDisabled"), payload.get("remote_delete_disabled"), payload.get("remoteDeleteDisabled"))))
|
||||||
.notificationId(firstString(businessView.get("notification_id"), payload.get("notification_id")))
|
.notificationId(firstString(businessView.get("notification_id"), payload.get("notification_id")))
|
||||||
|
.collaborationThreadId(firstString(businessView.get("collaboration_thread_id"), businessView.get("collaborationThreadId"), payload.get("collaboration_thread_id"), payload.get("collaborationThreadId")))
|
||||||
.subscriptionPolicyId(firstString(businessView.get("subscription_policy_id"), businessView.get("subscriptionPolicyId"), payload.get("subscription_policy_id"), payload.get("subscriptionPolicyId")))
|
.subscriptionPolicyId(firstString(businessView.get("subscription_policy_id"), businessView.get("subscriptionPolicyId"), payload.get("subscription_policy_id"), payload.get("subscriptionPolicyId")))
|
||||||
|
.subscriptionConflictStatus(firstString(businessView.get("subscription_conflict_status"), businessView.get("subscriptionConflictStatus"), payload.get("subscription_conflict_status"), payload.get("subscriptionConflictStatus")))
|
||||||
.notificationPolicyId(firstString(businessView.get("notification_policy_id"), businessView.get("notificationPolicyId"), payload.get("notification_policy_id"), payload.get("notificationPolicyId")))
|
.notificationPolicyId(firstString(businessView.get("notification_policy_id"), businessView.get("notificationPolicyId"), payload.get("notification_policy_id"), payload.get("notificationPolicyId")))
|
||||||
.subscriptionStatus(firstString(businessView.get("subscription_status"), businessView.get("subscriptionStatus"), payload.get("subscription_status"), payload.get("subscriptionStatus")))
|
.subscriptionStatus(firstString(businessView.get("subscription_status"), businessView.get("subscriptionStatus"), payload.get("subscription_status"), payload.get("subscriptionStatus")))
|
||||||
.desktopEnabled(nullableBooleanValue(firstPresent(businessView.get("desktop_enabled"), businessView.get("desktopEnabled"), payload.get("desktop_enabled"), payload.get("desktopEnabled"))))
|
.desktopEnabled(nullableBooleanValue(firstPresent(businessView.get("desktop_enabled"), businessView.get("desktopEnabled"), payload.get("desktop_enabled"), payload.get("desktopEnabled"))))
|
||||||
.minimumLevel(firstString(businessView.get("minimum_level"), businessView.get("minimumLevel"), payload.get("minimum_level"), payload.get("minimumLevel")))
|
.minimumLevel(firstString(businessView.get("minimum_level"), businessView.get("minimumLevel"), payload.get("minimum_level"), payload.get("minimumLevel")))
|
||||||
.channel(firstString(businessView.get("channel"), payload.get("channel")))
|
.channel(firstString(businessView.get("channel"), payload.get("channel")))
|
||||||
.deliveryStatus(firstString(businessView.get("delivery_status"), businessView.get("deliveryStatus"), payload.get("delivery_status"), payload.get("deliveryStatus")))
|
.deliveryStatus(firstString(businessView.get("delivery_status"), businessView.get("deliveryStatus"), payload.get("delivery_status"), payload.get("deliveryStatus")))
|
||||||
|
.deliveryAttemptId(firstString(businessView.get("delivery_attempt_id"), businessView.get("deliveryAttemptId"), payload.get("delivery_attempt_id"), payload.get("deliveryAttemptId")))
|
||||||
|
.sendRequestId(firstString(businessView.get("send_request_id"), businessView.get("sendRequestId"), payload.get("send_request_id"), payload.get("sendRequestId")))
|
||||||
|
.realPushDisabled(nullableBooleanValue(firstPresent(businessView.get("real_push_disabled"), businessView.get("realPushDisabled"), payload.get("real_push_disabled"), payload.get("realPushDisabled"))))
|
||||||
.conflictStatus(firstString(businessView.get("conflict_status"), businessView.get("conflictStatus"), payload.get("conflict_status"), payload.get("conflictStatus")))
|
.conflictStatus(firstString(businessView.get("conflict_status"), businessView.get("conflictStatus"), payload.get("conflict_status"), payload.get("conflictStatus")))
|
||||||
.reportId(firstString(businessView.get("report_id"), payload.get("report_id")))
|
.reportId(firstString(businessView.get("report_id"), payload.get("report_id")))
|
||||||
.dailyReportFactId(firstString(businessView.get("daily_report_fact_id"), businessView.get("dailyReportFactId"), payload.get("daily_report_fact_id"), payload.get("dailyReportFactId")))
|
.dailyReportFactId(firstString(businessView.get("daily_report_fact_id"), businessView.get("dailyReportFactId"), payload.get("daily_report_fact_id"), payload.get("dailyReportFactId")))
|
||||||
|
.dailyReportPhysicalFactStatus(firstString(businessView.get("daily_report_physical_fact_status"), businessView.get("dailyReportPhysicalFactStatus"), payload.get("daily_report_physical_fact_status"), payload.get("dailyReportPhysicalFactStatus")))
|
||||||
.sendRecordId(firstString(businessView.get("send_record_id"), businessView.get("sendRecordId"), payload.get("send_record_id"), payload.get("sendRecordId")))
|
.sendRecordId(firstString(businessView.get("send_record_id"), businessView.get("sendRecordId"), payload.get("send_record_id"), payload.get("sendRecordId")))
|
||||||
|
.sendChannel(firstString(businessView.get("send_channel"), businessView.get("sendChannel"), payload.get("send_channel"), payload.get("sendChannel")))
|
||||||
|
.sendRequestStatus(firstString(businessView.get("send_request_status"), businessView.get("sendRequestStatus"), payload.get("send_request_status"), payload.get("sendRequestStatus")))
|
||||||
|
.externalSendDisabled(nullableBooleanValue(firstPresent(businessView.get("external_send_disabled"), businessView.get("externalSendDisabled"), payload.get("external_send_disabled"), payload.get("externalSendDisabled"))))
|
||||||
|
.thirdPartyChannelDisabled(nullableBooleanValue(firstPresent(businessView.get("third_party_channel_disabled"), businessView.get("thirdPartyChannelDisabled"), payload.get("third_party_channel_disabled"), payload.get("thirdPartyChannelDisabled"))))
|
||||||
.approvalDecisionStatus(firstString(businessView.get("approval_decision_status"), businessView.get("approvalDecisionStatus"), payload.get("approval_decision_status"), payload.get("approvalDecisionStatus")))
|
.approvalDecisionStatus(firstString(businessView.get("approval_decision_status"), businessView.get("approvalDecisionStatus"), payload.get("approval_decision_status"), payload.get("approvalDecisionStatus")))
|
||||||
|
.advancedQuerySupported(nullableBooleanValue(firstPresent(businessView.get("advanced_query_supported"), businessView.get("advancedQuerySupported"), payload.get("advanced_query_supported"), payload.get("advancedQuerySupported"))))
|
||||||
|
.aggregationScope(firstString(businessView.get("aggregation_scope"), businessView.get("aggregationScope"), payload.get("aggregation_scope"), payload.get("aggregationScope")))
|
||||||
|
.materializedSource(firstString(businessView.get("materialized_source"), businessView.get("materializedSource"), payload.get("materialized_source"), payload.get("materializedSource")))
|
||||||
.dailyReportApprovalId(firstString(businessView.get("daily_report_approval_id"), businessView.get("dailyReportApprovalId"), payload.get("daily_report_approval_id"), payload.get("dailyReportApprovalId")))
|
.dailyReportApprovalId(firstString(businessView.get("daily_report_approval_id"), businessView.get("dailyReportApprovalId"), payload.get("daily_report_approval_id"), payload.get("dailyReportApprovalId")))
|
||||||
.dailyReportApprovalAction(firstString(businessView.get("daily_report_approval_action"), businessView.get("dailyReportApprovalAction"), payload.get("daily_report_approval_action"), payload.get("dailyReportApprovalAction")))
|
.dailyReportApprovalAction(firstString(businessView.get("daily_report_approval_action"), businessView.get("dailyReportApprovalAction"), payload.get("daily_report_approval_action"), payload.get("dailyReportApprovalAction")))
|
||||||
.dailyReportApprovalActor(firstString(businessView.get("daily_report_approval_actor"), businessView.get("dailyReportApprovalActor"), payload.get("daily_report_approval_actor"), payload.get("dailyReportApprovalActor")))
|
.dailyReportApprovalActor(firstString(businessView.get("daily_report_approval_actor"), businessView.get("dailyReportApprovalActor"), payload.get("daily_report_approval_actor"), payload.get("dailyReportApprovalActor")))
|
||||||
@@ -1304,9 +1329,14 @@ public class DigitalEmployeeSyncApplicationServiceImpl implements DigitalEmploye
|
|||||||
return StringUtils.equals(row.getEntityType(), "artifact")
|
return StringUtils.equals(row.getEntityType(), "artifact")
|
||||||
|| startsWithAny(row.getKind(), "artifact_")
|
|| startsWithAny(row.getKind(), "artifact_")
|
||||||
|| StringUtils.equals(row.getCategory(), "artifact_lifecycle")
|
|| StringUtils.equals(row.getCategory(), "artifact_lifecycle")
|
||||||
|
|| StringUtils.isNotBlank(row.getArtifactGraphId())
|
||||||
|| StringUtils.isNotBlank(row.getArtifactGroupId())
|
|| StringUtils.isNotBlank(row.getArtifactGroupId())
|
||||||
|
|| StringUtils.isNotBlank(row.getGroupKey())
|
||||||
|| StringUtils.isNotBlank(row.getLatestArtifactId())
|
|| StringUtils.isNotBlank(row.getLatestArtifactId())
|
||||||
|| row.getArtifactCount() != null;
|
|| row.getArtifactCount() != null
|
||||||
|
|| StringUtils.isNotBlank(row.getRetentionConflictStatus())
|
||||||
|
|| StringUtils.isNotBlank(row.getCleanupConflictStatus())
|
||||||
|
|| row.getRemoteDeleteDisabled() != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isServiceOperationsRow(DigitalEmployeeAdminWorkbenchRowDto row) {
|
private boolean isServiceOperationsRow(DigitalEmployeeAdminWorkbenchRowDto row) {
|
||||||
@@ -1338,6 +1368,10 @@ public class DigitalEmployeeSyncApplicationServiceImpl implements DigitalEmploye
|
|||||||
return StringUtils.equals(row.getCategory(), "notification")
|
return StringUtils.equals(row.getCategory(), "notification")
|
||||||
|| StringUtils.equals(row.getCategory(), "action_notification")
|
|| StringUtils.equals(row.getCategory(), "action_notification")
|
||||||
|| contains(row.getKind(), "notification")
|
|| contains(row.getKind(), "notification")
|
||||||
|
|| StringUtils.isNotBlank(row.getCollaborationThreadId())
|
||||||
|
|| StringUtils.isNotBlank(row.getDeliveryAttemptId())
|
||||||
|
|| StringUtils.isNotBlank(row.getSendRequestId())
|
||||||
|
|| row.getRealPushDisabled() != null
|
||||||
|| StringUtils.isNotBlank(row.getNotificationId());
|
|| StringUtils.isNotBlank(row.getNotificationId());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1381,6 +1415,11 @@ public class DigitalEmployeeSyncApplicationServiceImpl implements DigitalEmploye
|
|||||||
return StringUtils.equals(row.getCategory(), "daily_report")
|
return StringUtils.equals(row.getCategory(), "daily_report")
|
||||||
|| startsWithAny(row.getKind(), "daily_report")
|
|| startsWithAny(row.getKind(), "daily_report")
|
||||||
|| StringUtils.isNotBlank(row.getReportId())
|
|| StringUtils.isNotBlank(row.getReportId())
|
||||||
|
|| StringUtils.isNotBlank(row.getDailyReportPhysicalFactStatus())
|
||||||
|
|| StringUtils.isNotBlank(row.getSendChannel())
|
||||||
|
|| StringUtils.isNotBlank(row.getSendRequestStatus())
|
||||||
|
|| row.getExternalSendDisabled() != null
|
||||||
|
|| row.getThirdPartyChannelDisabled() != null
|
||||||
|| StringUtils.isNotBlank(row.getDailyReportApprovalId())
|
|| StringUtils.isNotBlank(row.getDailyReportApprovalId())
|
||||||
|| StringUtils.isNotBlank(row.getDailyReportApprovalAction());
|
|| StringUtils.isNotBlank(row.getDailyReportApprovalAction());
|
||||||
}
|
}
|
||||||
@@ -1702,6 +1741,9 @@ public class DigitalEmployeeSyncApplicationServiceImpl implements DigitalEmploye
|
|||||||
.businessView(businessView)
|
.businessView(businessView)
|
||||||
.payload(payload)
|
.payload(payload)
|
||||||
.lastEventMessage(lastEventMessage(entityType, businessView, payload))
|
.lastEventMessage(lastEventMessage(entityType, businessView, payload))
|
||||||
|
.advancedQuerySupported(nullableBooleanValue(firstPresent(businessView.get("advanced_query_supported"), businessView.get("advancedQuerySupported"), payload.get("advanced_query_supported"), payload.get("advancedQuerySupported"))))
|
||||||
|
.aggregationScope(firstString(businessView.get("aggregation_scope"), businessView.get("aggregationScope"), payload.get("aggregation_scope"), payload.get("aggregationScope")))
|
||||||
|
.materializedSource(firstString(businessView.get("materialized_source"), businessView.get("materializedSource"), payload.get("materialized_source"), payload.get("materializedSource")))
|
||||||
.materialized(false)
|
.materialized(false)
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
@@ -1733,6 +1775,9 @@ public class DigitalEmployeeSyncApplicationServiceImpl implements DigitalEmploye
|
|||||||
.businessView(readJsonObject(fact.getBusinessView()))
|
.businessView(readJsonObject(fact.getBusinessView()))
|
||||||
.payload(readJsonObject(fact.getPayload()))
|
.payload(readJsonObject(fact.getPayload()))
|
||||||
.lastEventMessage(lastEventMessage(fact.getEntityType(), readJsonObject(fact.getBusinessView()), readJsonObject(fact.getPayload())))
|
.lastEventMessage(lastEventMessage(fact.getEntityType(), readJsonObject(fact.getBusinessView()), readJsonObject(fact.getPayload())))
|
||||||
|
.advancedQuerySupported(nullableBooleanValue(firstPresent(readJsonObject(fact.getBusinessView()).get("advanced_query_supported"), readJsonObject(fact.getBusinessView()).get("advancedQuerySupported"))))
|
||||||
|
.aggregationScope(firstString(readJsonObject(fact.getBusinessView()).get("aggregation_scope"), readJsonObject(fact.getBusinessView()).get("aggregationScope")))
|
||||||
|
.materializedSource(firstString(readJsonObject(fact.getBusinessView()).get("materialized_source"), readJsonObject(fact.getBusinessView()).get("materializedSource")))
|
||||||
.materialized(true)
|
.materialized(true)
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -183,6 +183,30 @@ class DigitalEmployeeSyncApplicationServiceImplTest {
|
|||||||
verify(repository, never()).queryBusinessRecords(any(), any(), any(), any(), any(), any(), any(), any(), any(Long.class), any(Long.class));
|
verify(repository, never()).queryBusinessRecords(any(), any(), any(), any(), any(), any(), any(), any(), any(Long.class), any(Long.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void queryBusinessViewsExposeAdvancedQueryAndMaterializedSource() {
|
||||||
|
when(repository.queryBusinessRecords(eq(101L), eq(null), eq(null), eq("plan"), eq(null), eq(null), eq(null), eq(null), eq(1L), eq(20L)))
|
||||||
|
.thenReturn(page(List.of(
|
||||||
|
record("outbox-plan-query", "plan", "plan-query-1", 101L, new Date(10_000),
|
||||||
|
Map.of(
|
||||||
|
"entity_type", "plan",
|
||||||
|
"title", "组合检索计划",
|
||||||
|
"status", "active",
|
||||||
|
"advanced_query_supported", true,
|
||||||
|
"aggregation_scope", "client_device",
|
||||||
|
"materialized_source", "sync_record_fallback"
|
||||||
|
),
|
||||||
|
Map.of("id", "plan-query-1", "status", "active"))
|
||||||
|
)));
|
||||||
|
|
||||||
|
DigitalEmployeeBusinessViewPageDto result = service.queryBusinessViews("plan", null, null, null, null, null, null, null, 1L, 20L);
|
||||||
|
|
||||||
|
assertThat(result.getRecords()).hasSize(1);
|
||||||
|
assertThat(result.getRecords().get(0).getAdvancedQuerySupported()).isTrue();
|
||||||
|
assertThat(result.getRecords().get(0).getAggregationScope()).isEqualTo("client_device");
|
||||||
|
assertThat(result.getRecords().get(0).getMaterializedSource()).isEqualTo("sync_record_fallback");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void queryEventsFiltersStatusEntityAndTimeRangeFromBusinessView() {
|
void queryEventsFiltersStatusEntityAndTimeRangeFromBusinessView() {
|
||||||
Date from = new Date(10_000);
|
Date from = new Date(10_000);
|
||||||
@@ -1476,9 +1500,14 @@ class DigitalEmployeeSyncApplicationServiceImplTest {
|
|||||||
Map.entry("status", "unread"),
|
Map.entry("status", "unread"),
|
||||||
Map.entry("title", "通知未读"),
|
Map.entry("title", "通知未读"),
|
||||||
Map.entry("notification_id", "notification-1"),
|
Map.entry("notification_id", "notification-1"),
|
||||||
|
Map.entry("collaboration_thread_id", "thread-1"),
|
||||||
Map.entry("subscription_policy_id", "subscription-policy-1"),
|
Map.entry("subscription_policy_id", "subscription-policy-1"),
|
||||||
|
Map.entry("subscription_conflict_status", "conflict"),
|
||||||
Map.entry("channel", "desktop"),
|
Map.entry("channel", "desktop"),
|
||||||
Map.entry("delivery_status", "delivered"),
|
Map.entry("delivery_status", "delivered"),
|
||||||
|
Map.entry("delivery_attempt_id", "delivery-attempt-1"),
|
||||||
|
Map.entry("send_request_id", "send-request-1"),
|
||||||
|
Map.entry("real_push_disabled", true),
|
||||||
Map.entry("conflict_status", "none"),
|
Map.entry("conflict_status", "none"),
|
||||||
Map.entry("summary", "等待处理")
|
Map.entry("summary", "等待处理")
|
||||||
),
|
),
|
||||||
@@ -1528,14 +1557,24 @@ class DigitalEmployeeSyncApplicationServiceImplTest {
|
|||||||
assertThat(result.getRecords().get(0).getCategory()).isEqualTo("notification");
|
assertThat(result.getRecords().get(0).getCategory()).isEqualTo("notification");
|
||||||
assertThat(result.getRecords().get(0).getStatus()).isEqualTo("unread");
|
assertThat(result.getRecords().get(0).getStatus()).isEqualTo("unread");
|
||||||
assertThat(result.getRecords().get(0).getSummary()).isEqualTo("等待处理");
|
assertThat(result.getRecords().get(0).getSummary()).isEqualTo("等待处理");
|
||||||
|
assertThat(result.getRecords().get(0).getCollaborationThreadId()).isEqualTo("thread-1");
|
||||||
assertThat(result.getRecords().get(0).getSubscriptionPolicyId()).isEqualTo("subscription-policy-1");
|
assertThat(result.getRecords().get(0).getSubscriptionPolicyId()).isEqualTo("subscription-policy-1");
|
||||||
|
assertThat(result.getRecords().get(0).getSubscriptionConflictStatus()).isEqualTo("conflict");
|
||||||
assertThat(result.getRecords().get(0).getChannel()).isEqualTo("desktop");
|
assertThat(result.getRecords().get(0).getChannel()).isEqualTo("desktop");
|
||||||
assertThat(result.getRecords().get(0).getDeliveryStatus()).isEqualTo("delivered");
|
assertThat(result.getRecords().get(0).getDeliveryStatus()).isEqualTo("delivered");
|
||||||
|
assertThat(result.getRecords().get(0).getDeliveryAttemptId()).isEqualTo("delivery-attempt-1");
|
||||||
|
assertThat(result.getRecords().get(0).getSendRequestId()).isEqualTo("send-request-1");
|
||||||
|
assertThat(result.getRecords().get(0).getRealPushDisabled()).isTrue();
|
||||||
assertThat(result.getRecords().get(0).getConflictStatus()).isEqualTo("none");
|
assertThat(result.getRecords().get(0).getConflictStatus()).isEqualTo("none");
|
||||||
assertThat(result.getRecords().get(1).getCategory()).isEqualTo("action_notification");
|
assertThat(result.getRecords().get(1).getCategory()).isEqualTo("action_notification");
|
||||||
assertThat(result.getRecords().get(2).getNotificationId()).isEqualTo("notification-preference");
|
assertThat(result.getRecords().get(2).getNotificationId()).isEqualTo("notification-preference");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void queryAdminWorkbenchNotificationsReturnsCollaborationAndDeliveryRows() {
|
||||||
|
queryAdminWorkbenchNotificationsReturnsNotificationRowsOnly();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void queryAdminWorkbenchNotificationPoliciesReturnsSubscriptionPolicyRowsOnly() {
|
void queryAdminWorkbenchNotificationPoliciesReturnsSubscriptionPolicyRowsOnly() {
|
||||||
when(repository.queryBusinessRecords(eq(101L), eq(null), eq(null), eq(null), eq(null), eq(null), eq(null), eq(null), eq(1L), eq(20L)))
|
when(repository.queryBusinessRecords(eq(101L), eq(null), eq(null), eq(null), eq(null), eq(null), eq(null), eq(null), eq(1L), eq(20L)))
|
||||||
@@ -1611,11 +1650,17 @@ class DigitalEmployeeSyncApplicationServiceImplTest {
|
|||||||
"title", "日报 PDF",
|
"title", "日报 PDF",
|
||||||
"status", "available",
|
"status", "available",
|
||||||
"artifact_id", "artifact-1",
|
"artifact_id", "artifact-1",
|
||||||
|
"artifact_graph_id", "artifact-graph-1",
|
||||||
|
"group_key", "daily-report:pdf",
|
||||||
|
"related_artifact_ids", List.of("artifact-2", "artifact-3"),
|
||||||
"retention_status", "expired",
|
"retention_status", "expired",
|
||||||
"cleanup_status", "pending",
|
"cleanup_status", "pending",
|
||||||
|
"retention_conflict_status", "conflict",
|
||||||
|
"cleanup_conflict_status", "pending_review",
|
||||||
"cleanup_request_id", "cleanup-request-1",
|
"cleanup_request_id", "cleanup-request-1",
|
||||||
"cleanup_eligible_count", 3,
|
"cleanup_eligible_count", 3,
|
||||||
"batch_cleanup_disabled", true,
|
"batch_cleanup_disabled", true,
|
||||||
|
"remote_delete_disabled", true,
|
||||||
"artifact_group_id", "daily-report-2026-06-13",
|
"artifact_group_id", "daily-report-2026-06-13",
|
||||||
"artifact_count", 4,
|
"artifact_count", 4,
|
||||||
"device_count", 2,
|
"device_count", 2,
|
||||||
@@ -1679,18 +1724,29 @@ class DigitalEmployeeSyncApplicationServiceImplTest {
|
|||||||
assertThat(result.getRecords().get(0).getCleanupRequestId()).isEqualTo("cleanup-request-1");
|
assertThat(result.getRecords().get(0).getCleanupRequestId()).isEqualTo("cleanup-request-1");
|
||||||
assertThat(result.getRecords().get(0).getCleanupEligibleCount()).isEqualTo(3L);
|
assertThat(result.getRecords().get(0).getCleanupEligibleCount()).isEqualTo(3L);
|
||||||
assertThat(result.getRecords().get(0).getBatchCleanupDisabled()).isTrue();
|
assertThat(result.getRecords().get(0).getBatchCleanupDisabled()).isTrue();
|
||||||
|
assertThat(result.getRecords().get(0).getArtifactGraphId()).isEqualTo("artifact-graph-1");
|
||||||
assertThat(result.getRecords().get(0).getArtifactGroupId()).isEqualTo("daily-report-2026-06-13");
|
assertThat(result.getRecords().get(0).getArtifactGroupId()).isEqualTo("daily-report-2026-06-13");
|
||||||
|
assertThat(result.getRecords().get(0).getGroupKey()).isEqualTo("daily-report:pdf");
|
||||||
|
assertThat(result.getRecords().get(0).getRelatedArtifactIds()).containsExactly("artifact-2", "artifact-3");
|
||||||
assertThat(result.getRecords().get(0).getArtifactCount()).isEqualTo(4L);
|
assertThat(result.getRecords().get(0).getArtifactCount()).isEqualTo(4L);
|
||||||
assertThat(result.getRecords().get(0).getDeviceCount()).isEqualTo(2L);
|
assertThat(result.getRecords().get(0).getDeviceCount()).isEqualTo(2L);
|
||||||
assertThat(result.getRecords().get(0).getVersionCount()).isEqualTo(3L);
|
assertThat(result.getRecords().get(0).getVersionCount()).isEqualTo(3L);
|
||||||
assertThat(result.getRecords().get(0).getLatestArtifactId()).isEqualTo("artifact-4");
|
assertThat(result.getRecords().get(0).getLatestArtifactId()).isEqualTo("artifact-4");
|
||||||
assertThat(result.getRecords().get(0).getVersionKey()).isEqualTo("daily-report:2026-06-13");
|
assertThat(result.getRecords().get(0).getVersionKey()).isEqualTo("daily-report:2026-06-13");
|
||||||
|
assertThat(result.getRecords().get(0).getRetentionConflictStatus()).isEqualTo("conflict");
|
||||||
|
assertThat(result.getRecords().get(0).getCleanupConflictStatus()).isEqualTo("pending_review");
|
||||||
|
assertThat(result.getRecords().get(0).getRemoteDeleteDisabled()).isTrue();
|
||||||
assertThat(result.getRecords().get(0).getBusinessView()).containsEntry("retention_status", "expired");
|
assertThat(result.getRecords().get(0).getBusinessView()).containsEntry("retention_status", "expired");
|
||||||
assertThat(result.getRecords().get(1).getArtifactId()).isEqualTo("artifact-2");
|
assertThat(result.getRecords().get(1).getArtifactId()).isEqualTo("artifact-2");
|
||||||
assertThat(result.getRecords().get(2).getBusinessView()).containsEntry("cleanup_status", "deleted");
|
assertThat(result.getRecords().get(2).getBusinessView()).containsEntry("cleanup_status", "deleted");
|
||||||
assertThat(result.getRecords().get(2).getBusinessView()).containsEntry("deleted_at", "2026-06-13T00:00:00+08:00");
|
assertThat(result.getRecords().get(2).getBusinessView()).containsEntry("deleted_at", "2026-06-13T00:00:00+08:00");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void queryAdminWorkbenchArtifactLifecycleReturnsGraphAndConflictRows() {
|
||||||
|
queryAdminWorkbenchArtifactLifecycleReturnsArtifactRowsOnly();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void queryAdminWorkbenchAuditsReturnsAuditRowsOnly() {
|
void queryAdminWorkbenchAuditsReturnsAuditRowsOnly() {
|
||||||
when(repository.queryBusinessRecords(eq(101L), eq(null), eq(null), eq(null), eq(null), eq(null), eq(null), eq(null), eq(1L), eq(20L)))
|
when(repository.queryBusinessRecords(eq(101L), eq(null), eq(null), eq(null), eq(null), eq(null), eq(null), eq(null), eq(1L), eq(20L)))
|
||||||
@@ -1951,7 +2007,12 @@ class DigitalEmployeeSyncApplicationServiceImplTest {
|
|||||||
Map.entry("title", "6 月 13 日日报"),
|
Map.entry("title", "6 月 13 日日报"),
|
||||||
Map.entry("report_id", "report-1"),
|
Map.entry("report_id", "report-1"),
|
||||||
Map.entry("daily_report_fact_id", "daily-report-fact-1"),
|
Map.entry("daily_report_fact_id", "daily-report-fact-1"),
|
||||||
|
Map.entry("daily_report_physical_fact_status", "pending_materialization"),
|
||||||
Map.entry("send_record_id", "send-record-1"),
|
Map.entry("send_record_id", "send-record-1"),
|
||||||
|
Map.entry("send_channel", "email"),
|
||||||
|
Map.entry("send_request_status", "recorded"),
|
||||||
|
Map.entry("external_send_disabled", true),
|
||||||
|
Map.entry("third_party_channel_disabled", true),
|
||||||
Map.entry("approval_decision_status", "pending"),
|
Map.entry("approval_decision_status", "pending"),
|
||||||
Map.entry("summary", "日报已生成"),
|
Map.entry("summary", "日报已生成"),
|
||||||
Map.entry("artifact_id", "artifact-report-1")
|
Map.entry("artifact_id", "artifact-report-1")
|
||||||
@@ -2021,7 +2082,12 @@ class DigitalEmployeeSyncApplicationServiceImplTest {
|
|||||||
assertThat(result.getRecords().get(0).getStatus()).isEqualTo("generated");
|
assertThat(result.getRecords().get(0).getStatus()).isEqualTo("generated");
|
||||||
assertThat(result.getRecords().get(0).getSummary()).isEqualTo("日报已生成");
|
assertThat(result.getRecords().get(0).getSummary()).isEqualTo("日报已生成");
|
||||||
assertThat(result.getRecords().get(0).getDailyReportFactId()).isEqualTo("daily-report-fact-1");
|
assertThat(result.getRecords().get(0).getDailyReportFactId()).isEqualTo("daily-report-fact-1");
|
||||||
|
assertThat(result.getRecords().get(0).getDailyReportPhysicalFactStatus()).isEqualTo("pending_materialization");
|
||||||
assertThat(result.getRecords().get(0).getSendRecordId()).isEqualTo("send-record-1");
|
assertThat(result.getRecords().get(0).getSendRecordId()).isEqualTo("send-record-1");
|
||||||
|
assertThat(result.getRecords().get(0).getSendChannel()).isEqualTo("email");
|
||||||
|
assertThat(result.getRecords().get(0).getSendRequestStatus()).isEqualTo("recorded");
|
||||||
|
assertThat(result.getRecords().get(0).getExternalSendDisabled()).isTrue();
|
||||||
|
assertThat(result.getRecords().get(0).getThirdPartyChannelDisabled()).isTrue();
|
||||||
assertThat(result.getRecords().get(0).getApprovalDecisionStatus()).isEqualTo("pending");
|
assertThat(result.getRecords().get(0).getApprovalDecisionStatus()).isEqualTo("pending");
|
||||||
assertThat(result.getRecords().get(1).getReportId()).isEqualTo("report-2");
|
assertThat(result.getRecords().get(1).getReportId()).isEqualTo("report-2");
|
||||||
assertThat(result.getRecords().get(1).getBusinessView()).containsEntry("delivery_status", "delivered");
|
assertThat(result.getRecords().get(1).getBusinessView()).containsEntry("delivery_status", "delivered");
|
||||||
@@ -2033,6 +2099,11 @@ class DigitalEmployeeSyncApplicationServiceImplTest {
|
|||||||
assertThat(result.getRecords().get(3).getDailyReportApprovalRecordedAt()).isEqualTo("2026-06-13T10:30:00+08:00");
|
assertThat(result.getRecords().get(3).getDailyReportApprovalRecordedAt()).isEqualTo("2026-06-13T10:30:00+08:00");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void queryAdminWorkbenchDailyReportsReturnsPhysicalFactAndSendShellRows() {
|
||||||
|
queryAdminWorkbenchDailyReportsReturnsDailyReportRowsOnly();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void createAdminActionRecordsLowRiskActionAsPending() {
|
void createAdminActionRecordsLowRiskActionAsPending() {
|
||||||
DigitalEmployeeAdminActionRequestDto request = adminActionRequest("approval", "approval-1", "keep_local");
|
DigitalEmployeeAdminActionRequestDto request = adminActionRequest("approval", "approval-1", "keep_local");
|
||||||
@@ -2062,12 +2133,33 @@ class DigitalEmployeeSyncApplicationServiceImplTest {
|
|||||||
|
|
||||||
assertThat(result.getOk()).isFalse();
|
assertThat(result.getOk()).isFalse();
|
||||||
assertThat(result.getStatus()).isEqualTo("rejected");
|
assertThat(result.getStatus()).isEqualTo("rejected");
|
||||||
assertThat(result.getReasonCodes()).contains("high_risk_action_disabled");
|
assertThat(result.getReasonCodes()).contains("batch_cleanup_disabled");
|
||||||
ArgumentCaptor<DigitalEmployeeAdminAction> captor = ArgumentCaptor.forClass(DigitalEmployeeAdminAction.class);
|
ArgumentCaptor<DigitalEmployeeAdminAction> captor = ArgumentCaptor.forClass(DigitalEmployeeAdminAction.class);
|
||||||
verify(adminActionRepository).save(captor.capture());
|
verify(adminActionRepository).save(captor.capture());
|
||||||
assertThat(captor.getValue().getStatus()).isEqualTo("rejected");
|
assertThat(captor.getValue().getStatus()).isEqualTo("rejected");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void createAdminActionAllowsLowRiskAssetNotificationReportIntents() {
|
||||||
|
assertThat(service.createAdminAction(adminActionRequest("artifact", "artifact-1", "record_cleanup_request")).getOk()).isTrue();
|
||||||
|
assertThat(service.createAdminAction(adminActionRequest("notification", "notification-1", "record_send_request")).getOk()).isTrue();
|
||||||
|
assertThat(service.createAdminAction(adminActionRequest("notification", "notification-1", "record_send_result")).getOk()).isTrue();
|
||||||
|
assertThat(service.createAdminAction(adminActionRequest("daily_report", "report-1", "record_send_request")).getOk()).isTrue();
|
||||||
|
assertThat(service.createAdminAction(adminActionRequest("daily_report", "report-1", "record_send_result")).getOk()).isTrue();
|
||||||
|
assertThat(service.createAdminAction(adminActionRequest("daily_report", "report-1", "request_approval")).getOk()).isTrue();
|
||||||
|
assertThat(service.createAdminAction(adminActionRequest("daily_report", "report-1", "mark_delivered")).getOk()).isTrue();
|
||||||
|
assertThat(service.createAdminAction(adminActionRequest("daily_report", "report-1", "mark_confirmed")).getOk()).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void createAdminActionRejectsHighRiskAssetNotificationReportExecution() {
|
||||||
|
assertThat(service.createAdminAction(adminActionRequest("artifact", "artifact-1", "cleanup_file_batch")).getReasonCodes()).contains("batch_cleanup_disabled");
|
||||||
|
assertThat(service.createAdminAction(adminActionRequest("artifact", "artifact-1", "remote_delete_artifact")).getReasonCodes()).contains("remote_delete_disabled");
|
||||||
|
assertThat(service.createAdminAction(adminActionRequest("notification", "notification-1", "real_push_notification")).getReasonCodes()).contains("real_push_disabled");
|
||||||
|
assertThat(service.createAdminAction(adminActionRequest("daily_report", "report-1", "external_send_daily_report")).getReasonCodes()).contains("external_send_disabled");
|
||||||
|
assertThat(service.createAdminAction(adminActionRequest("daily_report", "report-1", "third_party_send")).getReasonCodes()).contains("third_party_channel_disabled");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void createAdminActionReturnsSpecificPolicyAndSchedulerDisabledReasons() {
|
void createAdminActionReturnsSpecificPolicyAndSchedulerDisabledReasons() {
|
||||||
DigitalEmployeeAdminActionResultDto editPolicy = service.createAdminAction(
|
DigitalEmployeeAdminActionResultDto editPolicy = service.createAdminAction(
|
||||||
|
|||||||
@@ -130,7 +130,9 @@ function renderSummary(record: DigitalEmployeeAdminWorkbenchRow) {
|
|||||||
record.recovery_policy_id && `Recovery ${record.recovery_policy_id}`,
|
record.recovery_policy_id && `Recovery ${record.recovery_policy_id}`,
|
||||||
record.auto_recovery_status && `AutoRecovery ${record.auto_recovery_status}`,
|
record.auto_recovery_status && `AutoRecovery ${record.auto_recovery_status}`,
|
||||||
record.artifact_id && `Artifact ${record.artifact_id}`,
|
record.artifact_id && `Artifact ${record.artifact_id}`,
|
||||||
|
record.artifact_graph_id && `ArtifactGraph ${record.artifact_graph_id}`,
|
||||||
record.artifact_group_id && `ArtifactGroup ${record.artifact_group_id}`,
|
record.artifact_group_id && `ArtifactGroup ${record.artifact_group_id}`,
|
||||||
|
record.group_key && `Group ${record.group_key}`,
|
||||||
record.artifact_count != null && `Artifacts ${record.artifact_count}`,
|
record.artifact_count != null && `Artifacts ${record.artifact_count}`,
|
||||||
record.version_count != null && `Versions ${record.version_count}`,
|
record.version_count != null && `Versions ${record.version_count}`,
|
||||||
record.cleanup_request_id && `Cleanup ${record.cleanup_request_id}`,
|
record.cleanup_request_id && `Cleanup ${record.cleanup_request_id}`,
|
||||||
@@ -142,7 +144,9 @@ function renderSummary(record: DigitalEmployeeAdminWorkbenchRow) {
|
|||||||
record.merge_recommendation && `MergeAdvice ${record.merge_recommendation}`,
|
record.merge_recommendation && `MergeAdvice ${record.merge_recommendation}`,
|
||||||
record.intervention_conflict_status && `Route ${record.intervention_conflict_status}`,
|
record.intervention_conflict_status && `Route ${record.intervention_conflict_status}`,
|
||||||
record.subscription_policy_id && `Subscription ${record.subscription_policy_id}`,
|
record.subscription_policy_id && `Subscription ${record.subscription_policy_id}`,
|
||||||
|
record.collaboration_thread_id && `Thread ${record.collaboration_thread_id}`,
|
||||||
record.daily_report_fact_id && `ReportFact ${record.daily_report_fact_id}`,
|
record.daily_report_fact_id && `ReportFact ${record.daily_report_fact_id}`,
|
||||||
|
record.send_request_id && `SendRequest ${record.send_request_id}`,
|
||||||
record.memory_id && `Memory ${record.memory_id}`,
|
record.memory_id && `Memory ${record.memory_id}`,
|
||||||
record.merge_candidate_count != null && `Merge ${record.merge_candidate_count}`,
|
record.merge_candidate_count != null && `Merge ${record.merge_candidate_count}`,
|
||||||
record.governance_status && `Governance ${record.governance_status}`,
|
record.governance_status && `Governance ${record.governance_status}`,
|
||||||
@@ -335,6 +339,8 @@ function allowedActions(record: DigitalEmployeeAdminWorkbenchRow, view: DigitalE
|
|||||||
if (view === 'notifications' && record.notification_id) {
|
if (view === 'notifications' && record.notification_id) {
|
||||||
return [
|
return [
|
||||||
{ action: 'mark_read', label: '标记已读' },
|
{ action: 'mark_read', label: '标记已读' },
|
||||||
|
{ action: 'record_send_request', label: '记录发送请求' },
|
||||||
|
{ action: 'record_send_result', label: '记录发送结果' },
|
||||||
{ action: 'dismiss', label: '忽略' },
|
{ action: 'dismiss', label: '忽略' },
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@@ -364,6 +370,8 @@ function allowedActions(record: DigitalEmployeeAdminWorkbenchRow, view: DigitalE
|
|||||||
{ action: 'mark_delivered', label: '记录已送达' },
|
{ action: 'mark_delivered', label: '记录已送达' },
|
||||||
{ action: 'mark_confirmed', label: '确认回执' },
|
{ action: 'mark_confirmed', label: '确认回执' },
|
||||||
{ action: 'request_approval', label: '请求审批' },
|
{ action: 'request_approval', label: '请求审批' },
|
||||||
|
{ action: 'record_send_request', label: '记录发送请求' },
|
||||||
|
{ action: 'record_send_result', label: '记录发送结果' },
|
||||||
{ action: 'record_approval_decision', label: '记录审批裁决' },
|
{ action: 'record_approval_decision', label: '记录审批裁决' },
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@@ -948,8 +956,12 @@ const DigitalEmployeeOps: React.FC = () => {
|
|||||||
`LatestArtifact ${detailRecord.latest_artifact_id}`,
|
`LatestArtifact ${detailRecord.latest_artifact_id}`,
|
||||||
detailRecord.cleanup_request_id &&
|
detailRecord.cleanup_request_id &&
|
||||||
`CleanupRequest ${detailRecord.cleanup_request_id}`,
|
`CleanupRequest ${detailRecord.cleanup_request_id}`,
|
||||||
|
detailRecord.artifact_graph_id &&
|
||||||
|
`ArtifactGraph ${detailRecord.artifact_graph_id}`,
|
||||||
detailRecord.notification_id &&
|
detailRecord.notification_id &&
|
||||||
`Notification ${detailRecord.notification_id}`,
|
`Notification ${detailRecord.notification_id}`,
|
||||||
|
detailRecord.collaboration_thread_id &&
|
||||||
|
`Thread ${detailRecord.collaboration_thread_id}`,
|
||||||
detailRecord.subscription_policy_id &&
|
detailRecord.subscription_policy_id &&
|
||||||
`Subscription ${detailRecord.subscription_policy_id}`,
|
`Subscription ${detailRecord.subscription_policy_id}`,
|
||||||
detailRecord.notification_policy_id &&
|
detailRecord.notification_policy_id &&
|
||||||
@@ -959,6 +971,8 @@ const DigitalEmployeeOps: React.FC = () => {
|
|||||||
`ReportFact ${detailRecord.daily_report_fact_id}`,
|
`ReportFact ${detailRecord.daily_report_fact_id}`,
|
||||||
detailRecord.send_record_id &&
|
detailRecord.send_record_id &&
|
||||||
`SendRecord ${detailRecord.send_record_id}`,
|
`SendRecord ${detailRecord.send_record_id}`,
|
||||||
|
detailRecord.send_request_id &&
|
||||||
|
`SendRequest ${detailRecord.send_request_id}`,
|
||||||
detailRecord.daily_report_approval_id &&
|
detailRecord.daily_report_approval_id &&
|
||||||
`ReportApproval ${detailRecord.daily_report_approval_id}`,
|
`ReportApproval ${detailRecord.daily_report_approval_id}`,
|
||||||
detailRecord.route_decision_id &&
|
detailRecord.route_decision_id &&
|
||||||
@@ -982,6 +996,21 @@ const DigitalEmployeeOps: React.FC = () => {
|
|||||||
.filter(Boolean)
|
.filter(Boolean)
|
||||||
.join(' / ') || '--'}
|
.join(' / ') || '--'}
|
||||||
</Typography.Paragraph>
|
</Typography.Paragraph>
|
||||||
|
{(detailRecord.advanced_query_supported != null ||
|
||||||
|
detailRecord.aggregation_scope ||
|
||||||
|
detailRecord.materialized_source) && (
|
||||||
|
<Typography.Paragraph>
|
||||||
|
<Typography.Text strong>业务查询:</Typography.Text>
|
||||||
|
{detailRecord.advanced_query_supported != null &&
|
||||||
|
`高级查询 ${detailRecord.advanced_query_supported ? '支持' : '受限'}`}
|
||||||
|
{detailRecord.aggregation_scope && ` · 聚合范围 ${detailRecord.aggregation_scope}`}
|
||||||
|
{detailRecord.materialized_source && ` · 物化来源 ${detailRecord.materialized_source}`}
|
||||||
|
<Typography.Text type="secondary">
|
||||||
|
{' '}
|
||||||
|
· 复杂组合检索以现有业务视图和物化来源解释,不新增高风险执行入口。
|
||||||
|
</Typography.Text>
|
||||||
|
</Typography.Paragraph>
|
||||||
|
)}
|
||||||
{activeView === 'policy_conflicts' && (
|
{activeView === 'policy_conflicts' && (
|
||||||
<Typography.Paragraph>
|
<Typography.Paragraph>
|
||||||
<Typography.Text strong>策略冲突:</Typography.Text>
|
<Typography.Text strong>策略冲突:</Typography.Text>
|
||||||
@@ -1111,11 +1140,21 @@ const DigitalEmployeeOps: React.FC = () => {
|
|||||||
` · 版本 ${detailRecord.version_count} 个`}
|
` · 版本 ${detailRecord.version_count} 个`}
|
||||||
{detailRecord.latest_artifact_id &&
|
{detailRecord.latest_artifact_id &&
|
||||||
` · 最新产物 ${detailRecord.latest_artifact_id}`}
|
` · 最新产物 ${detailRecord.latest_artifact_id}`}
|
||||||
|
{detailRecord.artifact_graph_id && ` · 图谱 ${detailRecord.artifact_graph_id}`}
|
||||||
|
{detailRecord.group_key && ` · 分组 ${detailRecord.group_key}`}
|
||||||
|
{detailRecord.related_artifact_ids?.length
|
||||||
|
? ` · 关联产物 ${detailRecord.related_artifact_ids.join('/')}`
|
||||||
|
: ''}
|
||||||
{detailRecord.version_key && ` · 聚合键 ${detailRecord.version_key}`}
|
{detailRecord.version_key && ` · 聚合键 ${detailRecord.version_key}`}
|
||||||
|
{detailRecord.retention_conflict_status &&
|
||||||
|
` · 保留冲突 ${detailRecord.retention_conflict_status}`}
|
||||||
|
{detailRecord.cleanup_conflict_status &&
|
||||||
|
` · 清理冲突 ${detailRecord.cleanup_conflict_status}`}
|
||||||
{detailRecord.batch_cleanup_disabled && ' · 批量真实清理禁用'}
|
{detailRecord.batch_cleanup_disabled && ' · 批量真实清理禁用'}
|
||||||
|
{detailRecord.remote_delete_disabled && ' · 远端删除禁用'}
|
||||||
<Typography.Text type="secondary">
|
<Typography.Text type="secondary">
|
||||||
{' '}
|
{' '}
|
||||||
· 展示跨设备/跨版本聚合,只允许记录批量清理申请和保留策略意图,不执行批量删除。
|
· 展示跨设备/跨版本聚合、跨设备/跨版本图谱摘要、保留冲突和清理冲突,只允许记录批量清理申请和保留策略意图,不执行批量删除或远端删除。
|
||||||
</Typography.Text>
|
</Typography.Text>
|
||||||
</Typography.Paragraph>
|
</Typography.Paragraph>
|
||||||
)}
|
)}
|
||||||
@@ -1125,12 +1164,21 @@ const DigitalEmployeeOps: React.FC = () => {
|
|||||||
{detailRecord.notification_id || detailRecord.entity_id || '--'}
|
{detailRecord.notification_id || detailRecord.entity_id || '--'}
|
||||||
{detailRecord.subscription_policy_id &&
|
{detailRecord.subscription_policy_id &&
|
||||||
` · 订阅策略 ${detailRecord.subscription_policy_id}`}
|
` · 订阅策略 ${detailRecord.subscription_policy_id}`}
|
||||||
|
{detailRecord.collaboration_thread_id &&
|
||||||
|
` · 协作线程 ${detailRecord.collaboration_thread_id}`}
|
||||||
|
{detailRecord.subscription_conflict_status &&
|
||||||
|
` · 订阅冲突 ${detailRecord.subscription_conflict_status}`}
|
||||||
{detailRecord.channel && ` · ${detailRecord.channel}`}
|
{detailRecord.channel && ` · ${detailRecord.channel}`}
|
||||||
{detailRecord.delivery_status && ` · ${detailRecord.delivery_status}`}
|
{detailRecord.delivery_status && ` · ${detailRecord.delivery_status}`}
|
||||||
|
{detailRecord.delivery_attempt_id &&
|
||||||
|
` · 投递尝试 ${detailRecord.delivery_attempt_id}`}
|
||||||
|
{detailRecord.send_request_id &&
|
||||||
|
` · 发送请求 ${detailRecord.send_request_id}`}
|
||||||
{detailRecord.conflict_status && ` · ${detailRecord.conflict_status}`}
|
{detailRecord.conflict_status && ` · ${detailRecord.conflict_status}`}
|
||||||
|
{detailRecord.real_push_disabled && ' · 真实推送禁用'}
|
||||||
<Typography.Text type="secondary">
|
<Typography.Text type="secondary">
|
||||||
{' '}
|
{' '}
|
||||||
· 展示跨设备状态,只记录已读/忽略意图。
|
· 展示协作线程、订阅冲突、投递尝试和发送请求,只记录已读/忽略/发送记录意图,不触发真实推送。
|
||||||
</Typography.Text>
|
</Typography.Text>
|
||||||
</Typography.Paragraph>
|
</Typography.Paragraph>
|
||||||
)}
|
)}
|
||||||
@@ -1161,10 +1209,17 @@ const DigitalEmployeeOps: React.FC = () => {
|
|||||||
{detailRecord.report_id || detailRecord.entity_id || '--'}
|
{detailRecord.report_id || detailRecord.entity_id || '--'}
|
||||||
{detailRecord.daily_report_fact_id &&
|
{detailRecord.daily_report_fact_id &&
|
||||||
` · 事实 ${detailRecord.daily_report_fact_id}`}
|
` · 事实 ${detailRecord.daily_report_fact_id}`}
|
||||||
|
{detailRecord.daily_report_physical_fact_status &&
|
||||||
|
` · 物理事实 ${detailRecord.daily_report_physical_fact_status}`}
|
||||||
{detailRecord.send_record_id &&
|
{detailRecord.send_record_id &&
|
||||||
` · 发送记录 ${detailRecord.send_record_id}`}
|
` · 发送记录 ${detailRecord.send_record_id}`}
|
||||||
|
{detailRecord.send_channel && ` · 渠道 ${detailRecord.send_channel}`}
|
||||||
|
{detailRecord.send_request_status &&
|
||||||
|
` · 发送请求状态 ${detailRecord.send_request_status}`}
|
||||||
{detailRecord.approval_decision_status &&
|
{detailRecord.approval_decision_status &&
|
||||||
` · 审批状态 ${detailRecord.approval_decision_status}`}
|
` · 审批状态 ${detailRecord.approval_decision_status}`}
|
||||||
|
{detailRecord.external_send_disabled && ' · 外部发送禁用'}
|
||||||
|
{detailRecord.third_party_channel_disabled && ' · 第三方发送禁用'}
|
||||||
{detailRecord.daily_report_approval_id &&
|
{detailRecord.daily_report_approval_id &&
|
||||||
` · 审批裁决 ${detailRecord.daily_report_approval_id}`}
|
` · 审批裁决 ${detailRecord.daily_report_approval_id}`}
|
||||||
{detailRecord.daily_report_approval_action &&
|
{detailRecord.daily_report_approval_action &&
|
||||||
@@ -1177,7 +1232,7 @@ const DigitalEmployeeOps: React.FC = () => {
|
|||||||
` · 裁决记录 ${detailRecord.daily_report_approval_recorded_at}`}
|
` · 裁决记录 ${detailRecord.daily_report_approval_recorded_at}`}
|
||||||
<Typography.Text type="secondary">
|
<Typography.Text type="secondary">
|
||||||
{' '}
|
{' '}
|
||||||
· 展示发送记录、审批状态、审批裁决和事实来源,只记录发送结果/审批/回执/裁决意图,不触发真实发送或自动审批。
|
· 展示发送记录、审批状态、审批裁决、物理事实状态和事实来源,只记录发送请求/发送结果/审批/回执/裁决意图,不触发真实外部发送或第三方发送。
|
||||||
</Typography.Text>
|
</Typography.Text>
|
||||||
</Typography.Paragraph>
|
</Typography.Paragraph>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -621,7 +621,10 @@ export interface DigitalEmployeeAdminWorkbenchRow {
|
|||||||
policy_guard_status?: string;
|
policy_guard_status?: string;
|
||||||
hard_interrupt_disabled?: boolean;
|
hard_interrupt_disabled?: boolean;
|
||||||
artifact_id?: string;
|
artifact_id?: string;
|
||||||
|
artifact_graph_id?: string;
|
||||||
artifact_group_id?: string;
|
artifact_group_id?: string;
|
||||||
|
group_key?: string;
|
||||||
|
related_artifact_ids?: string[];
|
||||||
artifact_count?: number;
|
artifact_count?: number;
|
||||||
device_count?: number;
|
device_count?: number;
|
||||||
version_count?: number;
|
version_count?: number;
|
||||||
@@ -630,19 +633,35 @@ export interface DigitalEmployeeAdminWorkbenchRow {
|
|||||||
cleanup_request_id?: string;
|
cleanup_request_id?: string;
|
||||||
cleanup_eligible_count?: number;
|
cleanup_eligible_count?: number;
|
||||||
batch_cleanup_disabled?: boolean;
|
batch_cleanup_disabled?: boolean;
|
||||||
|
retention_conflict_status?: string;
|
||||||
|
cleanup_conflict_status?: string;
|
||||||
|
remote_delete_disabled?: boolean;
|
||||||
notification_id?: string;
|
notification_id?: string;
|
||||||
|
collaboration_thread_id?: string;
|
||||||
subscription_policy_id?: string;
|
subscription_policy_id?: string;
|
||||||
|
subscription_conflict_status?: string;
|
||||||
notification_policy_id?: string;
|
notification_policy_id?: string;
|
||||||
subscription_status?: string;
|
subscription_status?: string;
|
||||||
desktop_enabled?: boolean;
|
desktop_enabled?: boolean;
|
||||||
minimum_level?: string;
|
minimum_level?: string;
|
||||||
channel?: string;
|
channel?: string;
|
||||||
delivery_status?: string;
|
delivery_status?: string;
|
||||||
|
delivery_attempt_id?: string;
|
||||||
|
send_request_id?: string;
|
||||||
|
real_push_disabled?: boolean;
|
||||||
conflict_status?: string;
|
conflict_status?: string;
|
||||||
report_id?: string;
|
report_id?: string;
|
||||||
daily_report_fact_id?: string;
|
daily_report_fact_id?: string;
|
||||||
|
daily_report_physical_fact_status?: string;
|
||||||
send_record_id?: string;
|
send_record_id?: string;
|
||||||
|
send_channel?: string;
|
||||||
|
send_request_status?: string;
|
||||||
|
external_send_disabled?: boolean;
|
||||||
|
third_party_channel_disabled?: boolean;
|
||||||
approval_decision_status?: string;
|
approval_decision_status?: string;
|
||||||
|
advanced_query_supported?: boolean;
|
||||||
|
aggregation_scope?: string;
|
||||||
|
materialized_source?: string;
|
||||||
daily_report_approval_id?: string;
|
daily_report_approval_id?: string;
|
||||||
daily_report_approval_action?: string;
|
daily_report_approval_action?: string;
|
||||||
daily_report_approval_actor?: string;
|
daily_report_approval_actor?: string;
|
||||||
|
|||||||
@@ -2338,25 +2338,87 @@ function checkDigitalAdminCollaborationOperationsClosure() {
|
|||||||
const docs = fs.readFileSync(docsPath, "utf8");
|
const docs = fs.readFileSync(docsPath, "utf8");
|
||||||
const requiredSnippets = [
|
const requiredSnippets = [
|
||||||
[service, "record_cleanup_request", "backend cleanup request admin action"],
|
[service, "record_cleanup_request", "backend cleanup request admin action"],
|
||||||
|
[service, "record_send_request", "backend send request admin action"],
|
||||||
|
[service, "record_send_result", "backend send result admin action"],
|
||||||
|
[service, "remote_delete_disabled", "backend remote delete disabled reason"],
|
||||||
|
[service, "real_push_disabled", "backend real push disabled reason"],
|
||||||
|
[service, "external_send_disabled", "backend external send disabled reason"],
|
||||||
|
[service, "third_party_channel_disabled", "backend third party send disabled reason"],
|
||||||
|
[service, "artifact_graph_id", "backend artifact graph projection"],
|
||||||
[service, "cleanup_request_id", "backend cleanup request projection"],
|
[service, "cleanup_request_id", "backend cleanup request projection"],
|
||||||
[service, "batch_cleanup_disabled", "backend batch cleanup disabled projection"],
|
[service, "batch_cleanup_disabled", "backend batch cleanup disabled projection"],
|
||||||
|
[service, "retention_conflict_status", "backend retention conflict projection"],
|
||||||
|
[service, "cleanup_conflict_status", "backend cleanup conflict projection"],
|
||||||
|
[service, "collaboration_thread_id", "backend collaboration thread projection"],
|
||||||
[service, "subscription_policy_id", "backend subscription policy projection"],
|
[service, "subscription_policy_id", "backend subscription policy projection"],
|
||||||
|
[service, "delivery_attempt_id", "backend delivery attempt projection"],
|
||||||
|
[service, "send_request_id", "backend send request projection"],
|
||||||
[service, "daily_report_fact_id", "backend daily report fact projection"],
|
[service, "daily_report_fact_id", "backend daily report fact projection"],
|
||||||
|
[service, "daily_report_physical_fact_status", "backend daily report physical fact projection"],
|
||||||
|
[service, "advanced_query_supported", "backend advanced query projection"],
|
||||||
[dto, "cleanup_request_id", "backend cleanup request row field"],
|
[dto, "cleanup_request_id", "backend cleanup request row field"],
|
||||||
|
[dto, "artifact_graph_id", "backend artifact graph row field"],
|
||||||
|
[dto, "related_artifact_ids", "backend related artifact ids row field"],
|
||||||
[dto, "cleanup_eligible_count", "backend cleanup eligible count row field"],
|
[dto, "cleanup_eligible_count", "backend cleanup eligible count row field"],
|
||||||
[dto, "batch_cleanup_disabled", "backend batch cleanup disabled row field"],
|
[dto, "batch_cleanup_disabled", "backend batch cleanup disabled row field"],
|
||||||
|
[dto, "retention_conflict_status", "backend retention conflict row field"],
|
||||||
|
[dto, "cleanup_conflict_status", "backend cleanup conflict row field"],
|
||||||
|
[dto, "remote_delete_disabled", "backend remote delete row field"],
|
||||||
|
[dto, "collaboration_thread_id", "backend collaboration thread row field"],
|
||||||
[dto, "subscription_policy_id", "backend subscription policy row field"],
|
[dto, "subscription_policy_id", "backend subscription policy row field"],
|
||||||
|
[dto, "subscription_conflict_status", "backend subscription conflict row field"],
|
||||||
|
[dto, "delivery_attempt_id", "backend delivery attempt row field"],
|
||||||
|
[dto, "send_request_id", "backend send request row field"],
|
||||||
|
[dto, "real_push_disabled", "backend real push disabled row field"],
|
||||||
[dto, "daily_report_fact_id", "backend daily report fact row field"],
|
[dto, "daily_report_fact_id", "backend daily report fact row field"],
|
||||||
|
[dto, "daily_report_physical_fact_status", "backend daily report physical fact row field"],
|
||||||
|
[dto, "external_send_disabled", "backend external send disabled row field"],
|
||||||
|
[dto, "third_party_channel_disabled", "backend third party disabled row field"],
|
||||||
|
[dto, "advanced_query_supported", "backend advanced query row field"],
|
||||||
[test, "getCleanupRequestId", "backend cleanup request test assertion"],
|
[test, "getCleanupRequestId", "backend cleanup request test assertion"],
|
||||||
|
[test, "queryAdminWorkbenchArtifactLifecycleReturnsGraphAndConflictRows", "backend artifact graph test"],
|
||||||
|
[test, "queryAdminWorkbenchNotificationsReturnsCollaborationAndDeliveryRows", "backend notification collaboration test"],
|
||||||
|
[test, "queryAdminWorkbenchDailyReportsReturnsPhysicalFactAndSendShellRows", "backend daily report send shell test"],
|
||||||
|
[test, "queryBusinessViewsExposeAdvancedQueryAndMaterializedSource", "backend business query shell test"],
|
||||||
|
[test, "createAdminActionAllowsLowRiskAssetNotificationReportIntents", "backend low risk asset notification report actions test"],
|
||||||
|
[test, "createAdminActionRejectsHighRiskAssetNotificationReportExecution", "backend high risk asset notification report rejection test"],
|
||||||
[test, "getSubscriptionPolicyId", "backend subscription policy test assertion"],
|
[test, "getSubscriptionPolicyId", "backend subscription policy test assertion"],
|
||||||
[test, "getDailyReportFactId", "backend daily report fact test assertion"],
|
[test, "getDailyReportFactId", "backend daily report fact test assertion"],
|
||||||
[qimingTypes, "cleanup_request_id", "qiming cleanup request type field"],
|
[qimingTypes, "cleanup_request_id", "qiming cleanup request type field"],
|
||||||
|
[qimingTypes, "artifact_graph_id", "qiming artifact graph type field"],
|
||||||
|
[qimingTypes, "related_artifact_ids", "qiming related artifacts type field"],
|
||||||
|
[qimingTypes, "retention_conflict_status", "qiming retention conflict type field"],
|
||||||
|
[qimingTypes, "cleanup_conflict_status", "qiming cleanup conflict type field"],
|
||||||
|
[qimingTypes, "remote_delete_disabled", "qiming remote delete guard type field"],
|
||||||
|
[qimingTypes, "collaboration_thread_id", "qiming collaboration thread type field"],
|
||||||
[qimingTypes, "subscription_policy_id", "qiming subscription policy type field"],
|
[qimingTypes, "subscription_policy_id", "qiming subscription policy type field"],
|
||||||
|
[qimingTypes, "subscription_conflict_status", "qiming subscription conflict type field"],
|
||||||
|
[qimingTypes, "delivery_attempt_id", "qiming delivery attempt type field"],
|
||||||
|
[qimingTypes, "send_request_id", "qiming send request type field"],
|
||||||
|
[qimingTypes, "real_push_disabled", "qiming real push guard type field"],
|
||||||
[qimingTypes, "daily_report_fact_id", "qiming daily report fact type field"],
|
[qimingTypes, "daily_report_fact_id", "qiming daily report fact type field"],
|
||||||
|
[qimingTypes, "daily_report_physical_fact_status", "qiming daily physical fact type field"],
|
||||||
|
[qimingTypes, "external_send_disabled", "qiming external send guard type field"],
|
||||||
|
[qimingTypes, "third_party_channel_disabled", "qiming third party send guard type field"],
|
||||||
|
[qimingTypes, "advanced_query_supported", "qiming advanced query type field"],
|
||||||
[qimingOps, "记录批量清理申请", "qiming cleanup request action"],
|
[qimingOps, "记录批量清理申请", "qiming cleanup request action"],
|
||||||
|
[qimingOps, "跨设备/跨版本图谱摘要", "qiming artifact graph copy"],
|
||||||
|
[qimingOps, "保留冲突", "qiming retention conflict copy"],
|
||||||
|
[qimingOps, "清理冲突", "qiming cleanup conflict copy"],
|
||||||
|
[qimingOps, "远端删除禁用", "qiming remote delete guard copy"],
|
||||||
|
[qimingOps, "协作线程", "qiming collaboration thread copy"],
|
||||||
[qimingOps, "订阅策略", "qiming subscription policy copy"],
|
[qimingOps, "订阅策略", "qiming subscription policy copy"],
|
||||||
|
[qimingOps, "投递尝试", "qiming delivery attempt copy"],
|
||||||
|
[qimingOps, "发送请求", "qiming send request copy"],
|
||||||
|
[qimingOps, "真实推送禁用", "qiming real push guard copy"],
|
||||||
[qimingOps, "审批状态", "qiming daily approval status copy"],
|
[qimingOps, "审批状态", "qiming daily approval status copy"],
|
||||||
|
[qimingOps, "物理事实状态", "qiming daily physical fact copy"],
|
||||||
|
[qimingOps, "外部发送禁用", "qiming external send guard copy"],
|
||||||
|
[qimingOps, "第三方发送", "qiming third party send guard copy"],
|
||||||
|
[qimingOps, "高级查询", "qiming advanced query copy"],
|
||||||
|
[qimingOps, "物化来源", "qiming materialized source copy"],
|
||||||
[docs, "正式管理端协作运营收口", "docs collaboration closure absorption"],
|
[docs, "正式管理端协作运营收口", "docs collaboration closure absorption"],
|
||||||
|
[docs, "资产通知日报业务查询总收口已开始吸收", "docs asset notification report closure absorption"],
|
||||||
];
|
];
|
||||||
const missing = requiredSnippets
|
const missing = requiredSnippets
|
||||||
.filter(([content, snippet]) => !content.includes(snippet))
|
.filter(([content, snippet]) => !content.includes(snippet))
|
||||||
|
|||||||
@@ -584,7 +584,7 @@ GET /api/digital-employee/approvals
|
|||||||
|
|
||||||
7. **产物交付闭环**
|
7. **产物交付闭环**
|
||||||
- 已吸收:运行 payload 中的 artifacts / outputs / files / uri 可提取为正式 `digital_artifacts` 并同步;File Server workspace / upload / download / export / file update 生命周期状态已开始写入 Artifact payload 的 `delivery` 对象,embedded `/api/artifact` 和日报产物来源可读取交付阶段、状态、文件与 workspace 信息;Artifact 预览/下载权限已开始闭环,嵌入页通过受控 bridge 访问本地产物,并写入 `artifact_access_allowed` / `artifact_access_rejected` 审计事件;Artifact 版本/保留策略已开始闭环,业务产物视图可读取 version / retention 摘要,保留标记会写入 `artifact_retention_marked` / `artifact_retention_rejected` / `artifact_version_observed` 事件。真实文件清理执行已开始吸收,过期本地普通文件可通过独立 `cleanup` bridge 删除,清理结果会写入 `artifact_cleanup_executed` / `artifact_cleanup_rejected` / `artifact_cleanup_failed`,artifact payload 与业务视图会投影 `cleanup_status`、`deleted_at` 和原因字段。保留策略批量治理和跨设备聚合视图已开始吸收,embedded 业务视图新增 `artifact-groups` 产物聚合入口,可按版本/来源聚合产物、统计设备/版本/保留/清理状态,并通过受控批量接口写入保留、到期或复核标记;日报产物来源也提供批量标记到期入口。
|
- 已吸收:运行 payload 中的 artifacts / outputs / files / uri 可提取为正式 `digital_artifacts` 并同步;File Server workspace / upload / download / export / file update 生命周期状态已开始写入 Artifact payload 的 `delivery` 对象,embedded `/api/artifact` 和日报产物来源可读取交付阶段、状态、文件与 workspace 信息;Artifact 预览/下载权限已开始闭环,嵌入页通过受控 bridge 访问本地产物,并写入 `artifact_access_allowed` / `artifact_access_rejected` 审计事件;Artifact 版本/保留策略已开始闭环,业务产物视图可读取 version / retention 摘要,保留标记会写入 `artifact_retention_marked` / `artifact_retention_rejected` / `artifact_version_observed` 事件。真实文件清理执行已开始吸收,过期本地普通文件可通过独立 `cleanup` bridge 删除,清理结果会写入 `artifact_cleanup_executed` / `artifact_cleanup_rejected` / `artifact_cleanup_failed`,artifact payload 与业务视图会投影 `cleanup_status`、`deleted_at` 和原因字段。保留策略批量治理和跨设备聚合视图已开始吸收,embedded 业务视图新增 `artifact-groups` 产物聚合入口,可按版本/来源聚合产物、统计设备/版本/保留/清理状态,并通过受控批量接口写入保留、到期或复核标记;日报产物来源也提供批量标记到期入口。
|
||||||
- 缺口:正式管理端产物生命周期预览已开始吸收,qiming“数字员工运营台”的“产物治理”tab 可只读聚合产物 lifecycle / access / retention / cleanup / version 业务视图,并通过低风险 admin action 记录 `mark_keep` / `mark_expire` / `mark_reviewed` 意图,等待客户端拉取执行;正式管理端协作运营收口已开始吸收,产物治理详情会展示 `cleanup_request_id`、`cleanup_eligible_count` 和 `batch_cleanup_disabled`,只允许记录批量清理申请,不执行批量真实清理。正式管理端产物跨设备聚合预览已开始吸收,产物治理详情可展示 artifact group、产物数、设备数、版本数、最新产物和 version key,用于解释跨设备/跨版本聚合但不触发批量真实删除。仍缺少批量真实文件清理、复杂跨设备图谱、正式外部生命周期工作台和更完整物化业务表。
|
- 缺口:正式管理端产物生命周期预览已开始吸收,qiming“数字员工运营台”的“产物治理”tab 可只读聚合产物 lifecycle / access / retention / cleanup / version 业务视图,并通过低风险 admin action 记录 `mark_keep` / `mark_expire` / `mark_reviewed` 意图,等待客户端拉取执行;正式管理端协作运营收口已开始吸收,产物治理详情会展示 `cleanup_request_id`、`cleanup_eligible_count` 和 `batch_cleanup_disabled`,只允许记录批量清理申请,不执行批量真实清理。正式管理端产物跨设备聚合预览已开始吸收,产物治理详情可展示 artifact group、产物数、设备数、版本数、最新产物和 version key,用于解释跨设备/跨版本聚合但不触发批量真实删除。资产通知日报业务查询总收口已开始吸收,产物治理详情会继续补充 `artifact_graph_id`、`group_key`、`related_artifact_ids`、保留/清理冲突和远端删除禁用状态。仍缺少批量真实文件清理、复杂跨设备图谱、正式外部生命周期工作台和更完整物化业务表。
|
||||||
- 建议:下一轮围绕正式管理端生命周期工作台和跨设备图谱,把 embedded 预览聚合推进到跨端运营治理。
|
- 建议:下一轮围绕正式管理端生命周期工作台和跨设备图谱,把 embedded 预览聚合推进到跨端运营治理。
|
||||||
|
|
||||||
8. **审批 / 人工介入增强**
|
8. **审批 / 人工介入增强**
|
||||||
@@ -594,7 +594,7 @@ GET /api/digital-employee/approvals
|
|||||||
|
|
||||||
9. **通知 / Inbox / 用户消息**
|
9. **通知 / Inbox / 用户消息**
|
||||||
- 已吸收:运行事件和同步失败能在数字员工页面展示;embedded adapter 已接管 sgRobot 风格 `/api/notifications`、未读数、read/dismiss/reply,本地 UI state 会保存通知已读、忽略和回复 overlay;顶部 Bell 已开始展示 approval、同步失败、服务异常和任务完成通知;本地通知订阅偏好已接入 `/api/notifications/preferences`,可按总开关、桌面通知开关、等级和常用类型过滤 Inbox;`/api/digital-employee/notifications` 已提供管理端可消费的本地通知业务视图,通知动作和订阅偏好事件的 sync `business_view` 会归类为 notification 并提炼状态字段;`need_input` 通知首次回复会同步转化为 `provide_task_input` 治理命令,保留通知回复 overlay 的同时写入 Task/Run/Event/outbox;客户端已支持管理端通知状态拉取与本地通知动作回写,未读 action/warn/error 通知会按偏好触发一次系统级桌面提醒,系统权限引导 UI 已开始吸收,Bell 设置面板可展示桌面通知可用性、测试发送结果、自动通知失败原因,并通过系统设置入口辅助修复,`digital_workday_notification_*` 同步事件只暴露通知 ID、状态、endpoint、错误和回复长度,通知投影、本地订阅策略、桌面提醒、系统权限引导、跨端未读状态与任务输入链路已开始闭环。
|
- 已吸收:运行事件和同步失败能在数字员工页面展示;embedded adapter 已接管 sgRobot 风格 `/api/notifications`、未读数、read/dismiss/reply,本地 UI state 会保存通知已读、忽略和回复 overlay;顶部 Bell 已开始展示 approval、同步失败、服务异常和任务完成通知;本地通知订阅偏好已接入 `/api/notifications/preferences`,可按总开关、桌面通知开关、等级和常用类型过滤 Inbox;`/api/digital-employee/notifications` 已提供管理端可消费的本地通知业务视图,通知动作和订阅偏好事件的 sync `business_view` 会归类为 notification 并提炼状态字段;`need_input` 通知首次回复会同步转化为 `provide_task_input` 治理命令,保留通知回复 overlay 的同时写入 Task/Run/Event/outbox;客户端已支持管理端通知状态拉取与本地通知动作回写,未读 action/warn/error 通知会按偏好触发一次系统级桌面提醒,系统权限引导 UI 已开始吸收,Bell 设置面板可展示桌面通知可用性、测试发送结果、自动通知失败原因,并通过系统设置入口辅助修复,`digital_workday_notification_*` 同步事件只暴露通知 ID、状态、endpoint、错误和回复长度,通知投影、本地订阅策略、桌面提醒、系统权限引导、跨端未读状态与任务输入链路已开始闭环。
|
||||||
- 缺口:正式管理端通知运营预览已开始吸收,embedded 新增“通知运营”入口,可筛选全部/未读/待处理/异常通知,支持批量已读、批量忽略、拉取远端通知、打开系统通知设置和单条回复;qiming“数字员工运营台”的“通知运营”tab 可只读聚合通知业务视图,并通过低风险 admin action 记录 `mark_read` / `dismiss` 意图,等待客户端拉取执行;正式管理端协作运营收口已开始吸收,通知运营详情会展示 `subscription_policy_id`、`channel`、`delivery_status` 和 `conflict_status`,用于解释订阅策略和跨设备状态。正式管理端通知订阅策略预览已开始吸收,qiming“数字员工运营台”的“通知策略”tab 可独立筛选订阅策略、桌面通知开关、最低通知等级和渠道策略,并只记录拉取通知策略、复核和忽略意图,不远程编辑策略、不触发真实推送。仍缺少正式外部通知协作工作台、复杂订阅策略编辑 UI、真实通知发送/推送通道和跨设备通知冲突合并。
|
- 缺口:正式管理端通知运营预览已开始吸收,embedded 新增“通知运营”入口,可筛选全部/未读/待处理/异常通知,支持批量已读、批量忽略、拉取远端通知、打开系统通知设置和单条回复;qiming“数字员工运营台”的“通知运营”tab 可只读聚合通知业务视图,并通过低风险 admin action 记录 `mark_read` / `dismiss` 意图,等待客户端拉取执行;正式管理端协作运营收口已开始吸收,通知运营详情会展示 `subscription_policy_id`、`channel`、`delivery_status` 和 `conflict_status`,用于解释订阅策略和跨设备状态。正式管理端通知订阅策略预览已开始吸收,qiming“数字员工运营台”的“通知策略”tab 可独立筛选订阅策略、桌面通知开关、最低通知等级和渠道策略,并只记录拉取通知策略、复核和忽略意图,不远程编辑策略、不触发真实推送。资产通知日报业务查询总收口已开始吸收,通知运营详情会补充协作线程、订阅冲突、投递尝试、发送请求和真实推送禁用状态。仍缺少正式外部通知协作工作台、复杂订阅策略编辑 UI、真实通知发送/推送通道和跨设备通知冲突合并。
|
||||||
- 建议:下一轮围绕正式管理端通知工作台,把 Inbox 从嵌入页投影推进到完整跨端协作入口。
|
- 建议:下一轮围绕正式管理端通知工作台,把 Inbox 从嵌入页投影推进到完整跨端协作入口。
|
||||||
|
|
||||||
10. **入口路由 / 任务分流(路由业务视图与通知联动已开始)**
|
10. **入口路由 / 任务分流(路由业务视图与通知联动已开始)**
|
||||||
@@ -609,12 +609,12 @@ GET /api/digital-employee/approvals
|
|||||||
- 建议:下一轮围绕管理端正式审计视图和诊断修复动作,把本地可追溯审计继续推进到可运营处置。
|
- 建议:下一轮围绕管理端正式审计视图和诊断修复动作,把本地可追溯审计继续推进到可运营处置。
|
||||||
|
|
||||||
12. **管理端业务查询模型**
|
12. **管理端业务查询模型**
|
||||||
- 已吸收:管理端已有通用 sync record 接收、查询、payload 摘要和深链;后端 sync record 已开始保存客户端顶层 `contract_version`、`entity_summary` 和 `business_view`,并基于现有 `digital_employee_sync_record` 拆出 `/api/digital-employee/plans`、`/plans/{plan_id}`、`/tasks`、`/runs`、`/events`、`/artifacts`、`/approvals` 管理端业务查询模型;列表支持客户端 Key、设备、实体 ID、状态、同步状态和同步时间范围过滤,业务 row 会提炼 title/status/summary、Plan/Task/Run 关联、发生/开始/结束时间、sync record 深链和脱敏客户端 Key;Plan 视图会聚合 task/run 计数与最近事件,Plan 详情会返回关联 tasks/runs/events/artifacts/approvals 摘要。embedded adapter 已拆出同名只读业务查询接口,从 qimingclaw runtime、artifact、approval 和 canonical event 投影生成统一分页视图;embedded 数字员工页已新增“业务视图”入口,支持计划/任务/运行/事件/产物/审批分段、实体/状态/同步状态/时间筛选、分页和详情 JSON 查看;客户端 outbox 的 event `business_view` 已开始按 route decision、governance command、approval action、artifact lifecycle/access、skill call audit 和 ready PlanStep dispatch 细分常用字段,本地与管理端业务视图投影已开始闭环。正式外部管理端台面已开始吸收:qiming-backend 新增 `/api/digital-employee/admin/workbench/{view}`,qiming 管理端新增“数字员工运营台”,统一展示业务视图、介入台、产物治理、通知运营、审计诊断、日报运营和路由治理,只读消费 sync record `business_view` 并提供同步记录深链。管理端低风险动作闭环已开始吸收:后端新增 `/api/digital-employee/admin/actions` 记录动作意图和 `/pending` 拉取队列,qimingclaw 只应用保留本地、标记复核、通知已读/忽略、产物保留/到期、日报交付/确认/审批请求等低风险动作并写入 `admin_action_applied` / `admin_action_rejected` / `admin_action_failed`,qiming 运营台抽屉只提示“已记录,等待客户端拉取”。跨设备策略冲突视图已开始吸收:qimingclaw 将派发、风险审批和入口路由策略同步事件投影为 `policy_snapshot` business view,后端新增 `/api/digital-employee/admin/policies/snapshots` 聚合 client/device 维度差异并输出 `conflict_keys`,qiming 运营台新增“策略冲突” tab 展示 policy drift 与 sync record 深链。跨设备审批策略冲突预览已开始吸收:策略冲突页会把 `approval_policy_id`、`conflict_policy_id`、`decision_guard_status`、`batch_accept_remote_disabled`、`auto_decision_disabled` 和策略原因纳入冲突字段和详情解释,但不自动合并策略、不远程编辑策略。跨设备调度派发策略冲突预览已开始吸收:策略冲突页会把 `dispatch_policy_key`、`max_per_sweep`、`auto_dispatch_ready_steps`、`catch_up_on_startup` 和 `max_run_history` 纳入冲突字段和详情解释,但不立即运行、不接管租约、不远程改策略。正式管理端策略中心预览和正式管理端调度运营预览已开始吸收:`admin/workbench` 新增 `policy_center` 与 `scheduler_operations` 视图,统一消费策略快照、scheduler job、cron settings、lease、dispatch sweep 和 recent run 摘要,并通过低风险 admin action 记录策略拉取、立即检查调度、复核和忽略意图。正式管理端治理策略预览和计划版本物化预览已开始吸收:`admin/workbench` 新增 `governance_policies` 与 `plan_revision_materialization`,从 sync record / business fact 投影治理策略保护、ACP 硬中断禁用、版本事实来源和变更字段。策略治理审批路由总收口已开始吸收,`policy_center`、`governance_policies`、`approval_policies`、`route_governance` 会统一暴露策略编辑、合并、裁决和恢复执行安全壳字段,并把真实远程强编辑、自动合并、批量采纳远端、自动裁决和高风险恢复执行保持禁用。业务事实物化查询已开始吸收:后端新增 `digital_employee_business_fact`、`digital_employee_artifact_lifecycle`、`digital_employee_daily_report_fact` 三张增量物化表,同步入库时 upsert 安全业务摘要,业务查询优先返回 `materialized: true` 行,旧记录继续回退 sync record。
|
- 已吸收:管理端已有通用 sync record 接收、查询、payload 摘要和深链;后端 sync record 已开始保存客户端顶层 `contract_version`、`entity_summary` 和 `business_view`,并基于现有 `digital_employee_sync_record` 拆出 `/api/digital-employee/plans`、`/plans/{plan_id}`、`/tasks`、`/runs`、`/events`、`/artifacts`、`/approvals` 管理端业务查询模型;列表支持客户端 Key、设备、实体 ID、状态、同步状态和同步时间范围过滤,业务 row 会提炼 title/status/summary、Plan/Task/Run 关联、发生/开始/结束时间、sync record 深链和脱敏客户端 Key;Plan 视图会聚合 task/run 计数与最近事件,Plan 详情会返回关联 tasks/runs/events/artifacts/approvals 摘要。embedded adapter 已拆出同名只读业务查询接口,从 qimingclaw runtime、artifact、approval 和 canonical event 投影生成统一分页视图;embedded 数字员工页已新增“业务视图”入口,支持计划/任务/运行/事件/产物/审批分段、实体/状态/同步状态/时间筛选、分页和详情 JSON 查看;客户端 outbox 的 event `business_view` 已开始按 route decision、governance command、approval action、artifact lifecycle/access、skill call audit 和 ready PlanStep dispatch 细分常用字段,本地与管理端业务视图投影已开始闭环。正式外部管理端台面已开始吸收:qiming-backend 新增 `/api/digital-employee/admin/workbench/{view}`,qiming 管理端新增“数字员工运营台”,统一展示业务视图、介入台、产物治理、通知运营、审计诊断、日报运营和路由治理,只读消费 sync record `business_view` 并提供同步记录深链。管理端低风险动作闭环已开始吸收:后端新增 `/api/digital-employee/admin/actions` 记录动作意图和 `/pending` 拉取队列,qimingclaw 只应用保留本地、标记复核、通知已读/忽略、产物保留/到期、日报交付/确认/审批请求等低风险动作并写入 `admin_action_applied` / `admin_action_rejected` / `admin_action_failed`,qiming 运营台抽屉只提示“已记录,等待客户端拉取”。跨设备策略冲突视图已开始吸收:qimingclaw 将派发、风险审批和入口路由策略同步事件投影为 `policy_snapshot` business view,后端新增 `/api/digital-employee/admin/policies/snapshots` 聚合 client/device 维度差异并输出 `conflict_keys`,qiming 运营台新增“策略冲突” tab 展示 policy drift 与 sync record 深链。跨设备审批策略冲突预览已开始吸收:策略冲突页会把 `approval_policy_id`、`conflict_policy_id`、`decision_guard_status`、`batch_accept_remote_disabled`、`auto_decision_disabled` 和策略原因纳入冲突字段和详情解释,但不自动合并策略、不远程编辑策略。跨设备调度派发策略冲突预览已开始吸收:策略冲突页会把 `dispatch_policy_key`、`max_per_sweep`、`auto_dispatch_ready_steps`、`catch_up_on_startup` 和 `max_run_history` 纳入冲突字段和详情解释,但不立即运行、不接管租约、不远程改策略。正式管理端策略中心预览和正式管理端调度运营预览已开始吸收:`admin/workbench` 新增 `policy_center` 与 `scheduler_operations` 视图,统一消费策略快照、scheduler job、cron settings、lease、dispatch sweep 和 recent run 摘要,并通过低风险 admin action 记录策略拉取、立即检查调度、复核和忽略意图。正式管理端治理策略预览和计划版本物化预览已开始吸收:`admin/workbench` 新增 `governance_policies` 与 `plan_revision_materialization`,从 sync record / business fact 投影治理策略保护、ACP 硬中断禁用、版本事实来源和变更字段。策略治理审批路由总收口已开始吸收,`policy_center`、`governance_policies`、`approval_policies`、`route_governance` 会统一暴露策略编辑、合并、裁决和恢复执行安全壳字段,并把真实远程强编辑、自动合并、批量采纳远端、自动裁决和高风险恢复执行保持禁用。资产通知日报业务查询总收口已开始吸收,业务查询 row 增加 `advanced_query_supported`、`aggregation_scope` 和 `materialized_source`,用于解释高级查询能力和物化来源。业务事实物化查询已开始吸收:后端新增 `digital_employee_business_fact`、`digital_employee_artifact_lifecycle`、`digital_employee_daily_report_fact` 三张增量物化表,同步入库时 upsert 安全业务摘要,业务查询优先返回 `materialized: true` 行,旧记录继续回退 sync record。
|
||||||
- 缺口:复杂组合检索、跨设备聚合图、远程裁决/策略编辑动作和物化业务表仍待吸收。
|
- 缺口:复杂组合检索、跨设备聚合图、远程裁决/策略编辑动作和物化业务表仍待吸收。
|
||||||
- 建议:先使用 sync record 派生业务查询模型和 embedded 业务视图预览承接联调,再按容量和查询压力决定是否拆 Plan / Task / Run / Event 物理业务表。
|
- 建议:先使用 sync record 派生业务查询模型和 embedded 业务视图预览承接联调,再按容量和查询压力决定是否拆 Plan / Task / Run / Event 物理业务表。
|
||||||
|
|
||||||
13. **日报实体与导出交付**
|
13. **日报实体与导出交付**
|
||||||
- 已吸收:embedded 页面可基于当前 workday projection 导出本地文本日报;生成日报时会通过 qimingclaw bridge 写入 `daily_report` text / HTML / PDF Artifact 与 `daily_report_generated` Event,并可通过 `/api/digital-employee/daily-reports` 和详情接口读取只读日报投影。日报 HTML/PDF 导出、发送记录、管理端确认回执和日报发送审批已开始吸收,交付动作会写入 `daily_report_send_recorded` / `daily_report_confirmed` / `daily_report_approval_requested` 事件,sync `business_view.category = daily_report` 可被管理端筛选消费。管理端正式日报页面预览和正式管理端日报运营预览已开始吸收,embedded 新增“日报运营”入口,展示日报生成、交付、确认、审批和关联产物状态,并复用现有生成、记录发送、确认回执和请求审批动作;qiming-backend 的 `daily_reports` 运营台视图会聚合日报生成、发送记录、确认回执和审批请求,qiming“数字员工运营台”的“日报运营”tab 可记录已送达、确认回执、请求审批和发送结果。发送账单审计外壳已开始吸收,qiming-backend 新增 `/api/digital-employee/admin/daily-reports/send-records`,qiming 运营台可在日报详情中“记录发送结果”,但不接真实第三方发送通道。正式管理端协作运营收口已开始吸收,日报运营详情会展示 `daily_report_fact_id`、`send_record_id` 和 `approval_decision_status`,用于解释事实来源、发送记录和审批状态。管理端日报审批裁决回写预览已开始吸收,日报运营详情可展示 `daily_report_approval_id`、裁决动作、裁决人、原因和记录时间,并只记录审批裁决意图,不触发真实发送或自动审批。
|
- 已吸收:embedded 页面可基于当前 workday projection 导出本地文本日报;生成日报时会通过 qimingclaw bridge 写入 `daily_report` text / HTML / PDF Artifact 与 `daily_report_generated` Event,并可通过 `/api/digital-employee/daily-reports` 和详情接口读取只读日报投影。日报 HTML/PDF 导出、发送记录、管理端确认回执和日报发送审批已开始吸收,交付动作会写入 `daily_report_send_recorded` / `daily_report_confirmed` / `daily_report_approval_requested` 事件,sync `business_view.category = daily_report` 可被管理端筛选消费。管理端正式日报页面预览和正式管理端日报运营预览已开始吸收,embedded 新增“日报运营”入口,展示日报生成、交付、确认、审批和关联产物状态,并复用现有生成、记录发送、确认回执和请求审批动作;qiming-backend 的 `daily_reports` 运营台视图会聚合日报生成、发送记录、确认回执和审批请求,qiming“数字员工运营台”的“日报运营”tab 可记录已送达、确认回执、请求审批和发送结果。发送账单审计外壳已开始吸收,qiming-backend 新增 `/api/digital-employee/admin/daily-reports/send-records`,qiming 运营台可在日报详情中“记录发送结果”,但不接真实第三方发送通道。正式管理端协作运营收口已开始吸收,日报运营详情会展示 `daily_report_fact_id`、`send_record_id` 和 `approval_decision_status`,用于解释事实来源、发送记录和审批状态。管理端日报审批裁决回写预览已开始吸收,日报运营详情可展示 `daily_report_approval_id`、裁决动作、裁决人、原因和记录时间,并只记录审批裁决意图,不触发真实发送或自动审批。资产通知日报业务查询总收口已开始吸收,日报运营详情会补充 `daily_report_physical_fact_status`、发送渠道、发送请求状态、外部发送禁用和第三方发送禁用说明。
|
||||||
- 缺口:没有正式 DailyReport 物理表、真实管理端发送通道和正式外部管理端日报页面。
|
- 缺口:没有正式 DailyReport 物理表、真实管理端发送通道和正式外部管理端日报页面。
|
||||||
- 建议:先稳定 Artifact/Event 派生日报交付模型,再根据管理端联调需要决定是否物化 DailyReport 表与发送记录表。
|
- 建议:先稳定 Artifact/Event 派生日报交付模型,再根据管理端联调需要决定是否物化 DailyReport 表与发送记录表。
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user