diff --git a/qiming-backend/app-platform-modules/app-platform-agent/app-platform-agent-core-adapter/src/main/java/com/xspaceagi/agent/core/adapter/dto/digital/DigitalEmployeeAdminWorkbenchRowDto.java b/qiming-backend/app-platform-modules/app-platform-agent/app-platform-agent-core-adapter/src/main/java/com/xspaceagi/agent/core/adapter/dto/digital/DigitalEmployeeAdminWorkbenchRowDto.java index 91970abd..7aa86e03 100644 --- a/qiming-backend/app-platform-modules/app-platform-agent/app-platform-agent-core-adapter/src/main/java/com/xspaceagi/agent/core/adapter/dto/digital/DigitalEmployeeAdminWorkbenchRowDto.java +++ b/qiming-backend/app-platform-modules/app-platform-agent/app-platform-agent-core-adapter/src/main/java/com/xspaceagi/agent/core/adapter/dto/digital/DigitalEmployeeAdminWorkbenchRowDto.java @@ -54,6 +54,18 @@ public class DigitalEmployeeAdminWorkbenchRowDto { private String approvalId; @JsonProperty("artifact_id") private String artifactId; + @JsonProperty("artifact_group_id") + private String artifactGroupId; + @JsonProperty("artifact_count") + private Long artifactCount; + @JsonProperty("device_count") + private Long deviceCount; + @JsonProperty("version_count") + private Long versionCount; + @JsonProperty("latest_artifact_id") + private String latestArtifactId; + @JsonProperty("version_key") + private String versionKey; @JsonProperty("cleanup_request_id") private String cleanupRequestId; @JsonProperty("cleanup_eligible_count") diff --git a/qiming-backend/app-platform-modules/app-platform-agent/app-platform-agent-core-application/src/main/java/com/xspaceagi/agent/core/application/service/DigitalEmployeeSyncApplicationServiceImpl.java b/qiming-backend/app-platform-modules/app-platform-agent/app-platform-agent-core-application/src/main/java/com/xspaceagi/agent/core/application/service/DigitalEmployeeSyncApplicationServiceImpl.java index 1cf6cc3e..f5455099 100644 --- a/qiming-backend/app-platform-modules/app-platform-agent/app-platform-agent-core-application/src/main/java/com/xspaceagi/agent/core/application/service/DigitalEmployeeSyncApplicationServiceImpl.java +++ b/qiming-backend/app-platform-modules/app-platform-agent/app-platform-agent-core-application/src/main/java/com/xspaceagi/agent/core/application/service/DigitalEmployeeSyncApplicationServiceImpl.java @@ -1069,6 +1069,12 @@ public class DigitalEmployeeSyncApplicationServiceImpl implements DigitalEmploye .triggerSource(firstString(businessView.get("trigger_source"), businessView.get("triggerSource"), payload.get("trigger_source"), payload.get("triggerSource"))) .approvalId(firstString(businessView.get("approval_id"), payload.get("approval_id"), "approval".equals(record.getEntityType()) ? record.getEntityId() : null)) .artifactId(firstString(businessView.get("artifact_id"), payload.get("artifact_id"), "artifact".equals(record.getEntityType()) ? record.getEntityId() : null)) + .artifactGroupId(firstString(businessView.get("artifact_group_id"), businessView.get("artifactGroupId"), payload.get("artifact_group_id"), payload.get("artifactGroupId"))) + .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")))) + .versionCount(numberValue(firstPresent(businessView.get("version_count"), businessView.get("versionCount"), payload.get("version_count"), payload.get("versionCount")))) + .latestArtifactId(firstString(businessView.get("latest_artifact_id"), businessView.get("latestArtifactId"), payload.get("latest_artifact_id"), payload.get("latestArtifactId"))) + .versionKey(firstString(businessView.get("version_key"), businessView.get("versionKey"), payload.get("version_key"), payload.get("versionKey"))) .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")))) .batchCleanupDisabled(nullableBooleanValue(firstPresent(businessView.get("batch_cleanup_disabled"), businessView.get("batchCleanupDisabled"), payload.get("batch_cleanup_disabled"), payload.get("batchCleanupDisabled")))) @@ -1176,7 +1182,10 @@ public class DigitalEmployeeSyncApplicationServiceImpl implements DigitalEmploye private boolean isArtifactLifecycleRow(DigitalEmployeeAdminWorkbenchRowDto row) { return StringUtils.equals(row.getEntityType(), "artifact") || startsWithAny(row.getKind(), "artifact_") - || StringUtils.equals(row.getCategory(), "artifact_lifecycle"); + || StringUtils.equals(row.getCategory(), "artifact_lifecycle") + || StringUtils.isNotBlank(row.getArtifactGroupId()) + || StringUtils.isNotBlank(row.getLatestArtifactId()) + || row.getArtifactCount() != null; } private boolean isServiceOperationsRow(DigitalEmployeeAdminWorkbenchRowDto row) { diff --git a/qiming-backend/app-platform-modules/app-platform-agent/app-platform-agent-core-application/src/test/java/com/xspaceagi/agent/core/application/service/DigitalEmployeeSyncApplicationServiceImplTest.java b/qiming-backend/app-platform-modules/app-platform-agent/app-platform-agent-core-application/src/test/java/com/xspaceagi/agent/core/application/service/DigitalEmployeeSyncApplicationServiceImplTest.java index fbe21c43..f77287b8 100644 --- a/qiming-backend/app-platform-modules/app-platform-agent/app-platform-agent-core-application/src/test/java/com/xspaceagi/agent/core/application/service/DigitalEmployeeSyncApplicationServiceImplTest.java +++ b/qiming-backend/app-platform-modules/app-platform-agent/app-platform-agent-core-application/src/test/java/com/xspaceagi/agent/core/application/service/DigitalEmployeeSyncApplicationServiceImplTest.java @@ -1188,6 +1188,12 @@ class DigitalEmployeeSyncApplicationServiceImplTest { "cleanup_request_id", "cleanup-request-1", "cleanup_eligible_count", 3, "batch_cleanup_disabled", true, + "artifact_group_id", "daily-report-2026-06-13", + "artifact_count", 4, + "device_count", 2, + "version_count", 3, + "latest_artifact_id", "artifact-4", + "version_key", "daily-report:2026-06-13", "summary", "等待清理" ), Map.of("id", "artifact-1", "status", "available")), @@ -1245,6 +1251,12 @@ class DigitalEmployeeSyncApplicationServiceImplTest { assertThat(result.getRecords().get(0).getCleanupRequestId()).isEqualTo("cleanup-request-1"); assertThat(result.getRecords().get(0).getCleanupEligibleCount()).isEqualTo(3L); assertThat(result.getRecords().get(0).getBatchCleanupDisabled()).isTrue(); + assertThat(result.getRecords().get(0).getArtifactGroupId()).isEqualTo("daily-report-2026-06-13"); + assertThat(result.getRecords().get(0).getArtifactCount()).isEqualTo(4L); + assertThat(result.getRecords().get(0).getDeviceCount()).isEqualTo(2L); + assertThat(result.getRecords().get(0).getVersionCount()).isEqualTo(3L); + 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).getBusinessView()).containsEntry("retention_status", "expired"); assertThat(result.getRecords().get(1).getArtifactId()).isEqualTo("artifact-2"); assertThat(result.getRecords().get(2).getBusinessView()).containsEntry("cleanup_status", "deleted"); diff --git a/qiming/src/pages/SystemManagement/Content/DigitalEmployeeOps/index.tsx b/qiming/src/pages/SystemManagement/Content/DigitalEmployeeOps/index.tsx index 3fb3e4b4..4628b498 100644 --- a/qiming/src/pages/SystemManagement/Content/DigitalEmployeeOps/index.tsx +++ b/qiming/src/pages/SystemManagement/Content/DigitalEmployeeOps/index.tsx @@ -120,6 +120,9 @@ function renderSummary(record: DigitalEmployeeAdminWorkbenchRow) { record.recovery_policy_id && `Recovery ${record.recovery_policy_id}`, record.auto_recovery_status && `AutoRecovery ${record.auto_recovery_status}`, record.artifact_id && `Artifact ${record.artifact_id}`, + record.artifact_group_id && `ArtifactGroup ${record.artifact_group_id}`, + record.artifact_count != null && `Artifacts ${record.artifact_count}`, + record.version_count != null && `Versions ${record.version_count}`, record.cleanup_request_id && `Cleanup ${record.cleanup_request_id}`, record.route_decision_id && `Route ${record.route_decision_id}`, record.policy_kind && `Policy ${record.policy_kind}`, @@ -824,6 +827,10 @@ const DigitalEmployeeOps: React.FC = () => { detailRecord.recovery_policy_id && `RecoveryPolicy ${detailRecord.recovery_policy_id}`, detailRecord.artifact_id && `Artifact ${detailRecord.artifact_id}`, + detailRecord.artifact_group_id && + `ArtifactGroup ${detailRecord.artifact_group_id}`, + detailRecord.latest_artifact_id && + `LatestArtifact ${detailRecord.latest_artifact_id}`, detailRecord.cleanup_request_id && `CleanupRequest ${detailRecord.cleanup_request_id}`, detailRecord.notification_id && @@ -922,10 +929,19 @@ const DigitalEmployeeOps: React.FC = () => { {detailRecord.artifact_id || detailRecord.entity_id || '--'} {detailRecord.cleanup_eligible_count != null && ` · 可清理 ${detailRecord.cleanup_eligible_count} 项`} + {detailRecord.artifact_count != null && + ` · 产物 ${detailRecord.artifact_count} 项`} + {detailRecord.device_count != null && + ` · 设备 ${detailRecord.device_count} 台`} + {detailRecord.version_count != null && + ` · 版本 ${detailRecord.version_count} 个`} + {detailRecord.latest_artifact_id && + ` · 最新产物 ${detailRecord.latest_artifact_id}`} + {detailRecord.version_key && ` · 聚合键 ${detailRecord.version_key}`} {detailRecord.batch_cleanup_disabled && ' · 批量真实清理禁用'} {' '} - · 只允许记录批量清理申请和保留策略意图,不执行批量删除。 + · 展示跨设备/跨版本聚合,只允许记录批量清理申请和保留策略意图,不执行批量删除。 )} diff --git a/qiming/src/types/interfaces/systemManage.ts b/qiming/src/types/interfaces/systemManage.ts index 98850fb6..f9acd6ce 100644 --- a/qiming/src/types/interfaces/systemManage.ts +++ b/qiming/src/types/interfaces/systemManage.ts @@ -603,6 +603,12 @@ export interface DigitalEmployeeAdminWorkbenchRow { trigger_source?: string; approval_id?: string; artifact_id?: string; + artifact_group_id?: string; + artifact_count?: number; + device_count?: number; + version_count?: number; + latest_artifact_id?: string; + version_key?: string; cleanup_request_id?: string; cleanup_eligible_count?: number; batch_cleanup_disabled?: boolean; diff --git a/qimingclaw/crates/agent-electron-client/scripts/check-digital-employee.js b/qimingclaw/crates/agent-electron-client/scripts/check-digital-employee.js index 447a29f5..7308223e 100644 --- a/qimingclaw/crates/agent-electron-client/scripts/check-digital-employee.js +++ b/qimingclaw/crates/agent-electron-client/scripts/check-digital-employee.js @@ -2323,13 +2323,22 @@ function checkDigitalAdminArtifactLifecycleWorkbench() { [service, "isArtifactLifecycleRow", "backend artifact lifecycle matcher"], [service, "artifact_", "backend artifact event classifier"], [dto, "artifact_id", "backend artifact id row field"], + [dto, "artifact_group_id", "backend artifact group id row field"], + [dto, "artifact_count", "backend artifact count row field"], + [dto, "version_count", "backend artifact version count row field"], + [dto, "latest_artifact_id", "backend latest artifact id row field"], [test, "queryAdminWorkbenchArtifactLifecycleReturnsArtifactRowsOnly", "backend artifact lifecycle test"], + [test, "getArtifactGroupId", "backend artifact group assertion"], [qimingTypes, "artifact_lifecycle", "qiming artifact lifecycle view type"], + [qimingTypes, "artifact_group_id", "qiming artifact group id field"], + [qimingTypes, "version_count", "qiming artifact version count field"], [qimingOps, "产物治理", "qiming artifact lifecycle tab"], + [qimingOps, "跨设备/跨版本聚合", "qiming artifact aggregate copy"], [qimingOps, "标记保留", "qiming artifact keep action"], [qimingOps, "标记到期", "qiming artifact expire action"], [qimingOps, "标记复核", "qiming artifact reviewed action"], [docs, "正式管理端产物生命周期预览", "docs artifact lifecycle absorption"], + [docs, "正式管理端产物跨设备聚合预览", "docs artifact aggregate absorption"], ]; const missing = requiredSnippets .filter(([content, snippet]) => !content.includes(snippet)) diff --git a/qimingclaw/docs/digital-employee-frontend-integration-plan.md b/qimingclaw/docs/digital-employee-frontend-integration-plan.md index f52fa70f..9621cf61 100644 --- a/qimingclaw/docs/digital-employee-frontend-integration-plan.md +++ b/qimingclaw/docs/digital-employee-frontend-integration-plan.md @@ -584,7 +584,7 @@ GET /api/digital-employee/approvals 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` 产物聚合入口,可按版本/来源聚合产物、统计设备/版本/保留/清理状态,并通过受控批量接口写入保留、到期或复核标记;日报产物来源也提供批量标记到期入口。 - - 缺口:正式管理端产物生命周期预览已开始吸收,qiming“数字员工运营台”的“产物治理”tab 可只读聚合产物 lifecycle / access / retention / cleanup / version 业务视图,并通过低风险 admin action 记录 `mark_keep` / `mark_expire` / `mark_reviewed` 意图,等待客户端拉取执行;正式管理端协作运营收口已开始吸收,产物治理详情会展示 `cleanup_request_id`、`cleanup_eligible_count` 和 `batch_cleanup_disabled`,只允许记录批量清理申请,不执行批量真实清理。仍缺少批量真实文件清理、复杂跨设备图谱、正式外部生命周期工作台和更完整物化业务表。 + - 缺口:正式管理端产物生命周期预览已开始吸收,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,用于解释跨设备/跨版本聚合但不触发批量真实删除。仍缺少批量真实文件清理、复杂跨设备图谱、正式外部生命周期工作台和更完整物化业务表。 - 建议:下一轮围绕正式管理端生命周期工作台和跨设备图谱,把 embedded 预览聚合推进到跨端运营治理。 8. **审批 / 人工介入增强**