吸收数字员工管理端产物跨设备聚合预览

This commit is contained in:
baiyanyun
2026-06-14 11:53:16 +08:00
parent 797ffeee82
commit dd6c10f44b
7 changed files with 67 additions and 3 deletions

View File

@@ -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")

View File

@@ -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) {

View File

@@ -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");

View File

@@ -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 && ' · 批量真实清理禁用'}
<Typography.Text type="secondary">
{' '}
·
· /
</Typography.Text>
</Typography.Paragraph>
)}

View File

@@ -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;

View File

@@ -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))

View File

@@ -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. **审批 / 人工介入增强**