吸收数字员工管理端通知订阅策略预览

This commit is contained in:
baiyanyun
2026-06-15 09:45:52 +08:00
parent a62b749ef2
commit b64f8e35c3
7 changed files with 230 additions and 1 deletions

View File

@@ -88,6 +88,14 @@ public class DigitalEmployeeAdminWorkbenchRowDto {
private String notificationId;
@JsonProperty("subscription_policy_id")
private String subscriptionPolicyId;
@JsonProperty("notification_policy_id")
private String notificationPolicyId;
@JsonProperty("subscription_status")
private String subscriptionStatus;
@JsonProperty("desktop_enabled")
private Boolean desktopEnabled;
@JsonProperty("minimum_level")
private String minimumLevel;
private String channel;
@JsonProperty("delivery_status")
private String deliveryStatus;

View File

@@ -69,6 +69,7 @@ public class DigitalEmployeeSyncApplicationServiceImpl implements DigitalEmploye
"route_decision:mark_reviewed", "route_decision:dismiss", "route_decision:retry_policy_check",
"route:mark_reviewed", "route:dismiss", "route:retry_policy_check",
"notification:mark_read", "notification: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",
"daily_report:mark_delivered", "daily_report:mark_confirmed", "daily_report:request_approval",
"memory:archive_memory", "memory:restore_memory", "memory:mark_reviewed",
@@ -1111,6 +1112,10 @@ public class DigitalEmployeeSyncApplicationServiceImpl implements DigitalEmploye
.batchCleanupDisabled(nullableBooleanValue(firstPresent(businessView.get("batch_cleanup_disabled"), businessView.get("batchCleanupDisabled"), payload.get("batch_cleanup_disabled"), payload.get("batchCleanupDisabled"))))
.notificationId(firstString(businessView.get("notification_id"), payload.get("notification_id")))
.subscriptionPolicyId(firstString(businessView.get("subscription_policy_id"), businessView.get("subscriptionPolicyId"), payload.get("subscription_policy_id"), payload.get("subscriptionPolicyId")))
.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")))
.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")))
.channel(firstString(businessView.get("channel"), payload.get("channel")))
.deliveryStatus(firstString(businessView.get("delivery_status"), businessView.get("deliveryStatus"), payload.get("delivery_status"), payload.get("deliveryStatus")))
.conflictStatus(firstString(businessView.get("conflict_status"), businessView.get("conflictStatus"), payload.get("conflict_status"), payload.get("conflictStatus")))
@@ -1185,6 +1190,7 @@ public class DigitalEmployeeSyncApplicationServiceImpl implements DigitalEmploye
case "service_operations" -> isServiceOperationsRow(row);
case "artifact_lifecycle" -> isArtifactLifecycleRow(row);
case "notifications" -> isNotificationRow(row);
case "notification_policies" -> isNotificationPolicyRow(row);
case "audits" -> isAuditRow(row);
case "daily_reports" -> isDailyReportRow(row);
case "governance_commands" -> isGovernanceCommandRow(row);
@@ -1276,6 +1282,20 @@ public class DigitalEmployeeSyncApplicationServiceImpl implements DigitalEmploye
|| StringUtils.isNotBlank(row.getNotificationId());
}
private boolean isNotificationPolicyRow(DigitalEmployeeAdminWorkbenchRowDto row) {
String category = firstString(row.getCategory());
String kind = firstString(row.getKind());
return Set.of("notification_policy", "notification_subscription_policy", "notification_preference_policy", "subscription_policy").contains(category)
|| contains(kind, "notification_policy")
|| contains(kind, "notification_subscription_policy")
|| contains(kind, "notification_preference_policy")
|| contains(kind, "subscription_policy")
|| StringUtils.isNotBlank(row.getNotificationPolicyId())
|| StringUtils.isNotBlank(row.getSubscriptionStatus())
|| row.getDesktopEnabled() != null
|| StringUtils.isNotBlank(row.getMinimumLevel());
}
private boolean isAuditRow(DigitalEmployeeAdminWorkbenchRowDto row) {
return Set.of("sandbox_audit", "token_cost", "tool_call_audit", "governance", "sync_failure", "audit_archive", "billing_estimate").contains(row.getCategory())
|| isDiagnosticRepairRow(row)
@@ -1446,6 +1466,10 @@ public class DigitalEmployeeSyncApplicationServiceImpl implements DigitalEmploye
return contains(kind, "doctor") ? "service_health" : "service_operation";
}
if (contains(kind, "risk_approval")) return "risk_approval";
if (contains(kind, "notification_policy") || contains(kind, "subscription_policy") || contains(kind, "notification_preference_policy")
|| StringUtils.isNotBlank(firstString(businessView.get("notification_policy_id"), payload.get("notification_policy_id")))) {
return "notification_policy";
}
if (contains(kind, "notification") || StringUtils.isNotBlank(firstString(businessView.get("notification_id"), payload.get("notification_id")))) {
String level = firstString(businessView.get("level"), payload.get("level"));
return StringUtils.equals(level, "action") ? "action_notification" : "notification";

View File

@@ -1277,6 +1277,71 @@ class DigitalEmployeeSyncApplicationServiceImplTest {
assertThat(result.getRecords().get(2).getNotificationId()).isEqualTo("notification-preference");
}
@Test
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)))
.thenReturn(page(List.of(
record("outbox-subscription-policy", "event", "event-notification-policy-1", 101L, new Date(10_000),
Map.ofEntries(
Map.entry("entity_type", "event"),
Map.entry("category", "notification_policy"),
Map.entry("kind", "notification_subscription_policy_pulled"),
Map.entry("status", "enabled"),
Map.entry("title", "通知订阅策略"),
Map.entry("notification_policy_id", "notification-policy-1"),
Map.entry("subscription_policy_id", "subscription-policy-1"),
Map.entry("subscription_status", "enabled"),
Map.entry("desktop_enabled", true),
Map.entry("minimum_level", "warn"),
Map.entry("channel", "desktop"),
Map.entry("summary", "桌面通知 warn 以上启用")
),
Map.of("id", "event-notification-policy-1", "kind", "notification_subscription_policy_pulled")),
record("outbox-preference-policy", "event", "event-notification-policy-2", 101L, new Date(11_000),
Map.of(
"entity_type", "event",
"kind", "notification_preference_policy_updated",
"status", "recorded",
"title", "通知偏好策略更新",
"subscription_policy_id", "subscription-policy-2",
"subscription_status", "muted",
"desktop_enabled", false
),
Map.of("id", "event-notification-policy-2", "kind", "notification_preference_policy_updated")),
record("outbox-notification", "notification", "notification-1", 101L, new Date(12_000),
Map.of("entity_type", "notification", "title", "普通通知", "status", "unread", "notification_id", "notification-1"),
Map.of("id", "notification-1", "status", "unread")),
record("outbox-action-notification", "event", "event-notification-action", 101L, new Date(13_000),
Map.of("entity_type", "event", "category", "action_notification", "kind", "digital_workday_notification_reply", "title", "通知回复", "notification_id", "notification-2"),
Map.of("id", "event-notification-action", "status", "recorded")),
record("outbox-approval", "approval", "approval-1", 101L, new Date(14_000),
Map.of("entity_type", "approval", "title", "普通审批", "status", "pending"),
Map.of("id", "approval-1", "status", "pending")),
record("outbox-audit", "event", "event-audit-1", 101L, new Date(15_000),
Map.of("entity_type", "event", "category", "tool_call_audit", "title", "审计", "status", "warn"),
Map.of("id", "event-audit-1", "status", "warn"))
)));
DigitalEmployeeAdminWorkbenchPageDto result = service.queryAdminWorkbench(
"notification_policies", null, null, null, null, null, null, null, null, null, null, null, 1L, 20L
);
assertThat(result.getTotal()).isEqualTo(2);
assertThat(result.getRecords()).extracting(DigitalEmployeeAdminWorkbenchRowDto::getEntityId)
.containsExactly("event-notification-policy-1", "event-notification-policy-2");
assertThat(result.getRecords().get(0).getView()).isEqualTo("notification_policies");
assertThat(result.getRecords().get(0).getCategory()).isEqualTo("notification_policy");
assertThat(result.getRecords().get(0).getNotificationPolicyId()).isEqualTo("notification-policy-1");
assertThat(result.getRecords().get(0).getSubscriptionPolicyId()).isEqualTo("subscription-policy-1");
assertThat(result.getRecords().get(0).getSubscriptionStatus()).isEqualTo("enabled");
assertThat(result.getRecords().get(0).getDesktopEnabled()).isTrue();
assertThat(result.getRecords().get(0).getMinimumLevel()).isEqualTo("warn");
assertThat(result.getRecords().get(0).getChannel()).isEqualTo("desktop");
assertThat(result.getRecords().get(0).getSummary()).isEqualTo("桌面通知 warn 以上启用");
assertThat(result.getRecords().get(1).getSubscriptionPolicyId()).isEqualTo("subscription-policy-2");
assertThat(result.getRecords().get(1).getDesktopEnabled()).isFalse();
}
@Test
void queryAdminWorkbenchArtifactLifecycleReturnsArtifactRowsOnly() {
when(repository.queryBusinessRecords(eq(101L), eq(null), eq(null), eq(null), eq(null), eq(null), eq(null), eq(null), eq(1L), eq(20L)))