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 1b65b9e8..4c74cd4b 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 @@ -52,6 +52,18 @@ public class DigitalEmployeeAdminWorkbenchRowDto { private String triggerSource; @JsonProperty("approval_id") private String approvalId; + @JsonProperty("approval_policy_id") + private String approvalPolicyId; + @JsonProperty("conflict_policy_id") + private String conflictPolicyId; + @JsonProperty("decision_guard_status") + private String decisionGuardStatus; + @JsonProperty("batch_accept_remote_disabled") + private Boolean batchAcceptRemoteDisabled; + @JsonProperty("auto_decision_disabled") + private Boolean autoDecisionDisabled; + @JsonProperty("policy_reason") + private String policyReason; @JsonProperty("artifact_id") private String artifactId; @JsonProperty("artifact_group_id") 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 44255f21..333812ef 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 @@ -1068,6 +1068,12 @@ public class DigitalEmployeeSyncApplicationServiceImpl implements DigitalEmploye .orchestrationId(firstString(businessView.get("orchestration_id"), businessView.get("orchestrationId"), payload.get("orchestration_id"), payload.get("orchestrationId"))) .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)) + .approvalPolicyId(firstString(businessView.get("approval_policy_id"), businessView.get("approvalPolicyId"), payload.get("approval_policy_id"), payload.get("approvalPolicyId"))) + .conflictPolicyId(firstString(businessView.get("conflict_policy_id"), businessView.get("conflictPolicyId"), payload.get("conflict_policy_id"), payload.get("conflictPolicyId"))) + .decisionGuardStatus(firstString(businessView.get("decision_guard_status"), businessView.get("decisionGuardStatus"), payload.get("decision_guard_status"), payload.get("decisionGuardStatus"))) + .batchAcceptRemoteDisabled(nullableBooleanValue(firstPresent(businessView.get("batch_accept_remote_disabled"), businessView.get("batchAcceptRemoteDisabled"), payload.get("batch_accept_remote_disabled"), payload.get("batchAcceptRemoteDisabled")))) + .autoDecisionDisabled(nullableBooleanValue(firstPresent(businessView.get("auto_decision_disabled"), businessView.get("autoDecisionDisabled"), payload.get("auto_decision_disabled"), payload.get("autoDecisionDisabled")))) + .policyReason(firstString(businessView.get("policy_reason"), businessView.get("policyReason"), payload.get("policy_reason"), payload.get("policyReason"))) .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")))) 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 dd732e9c..aabce53b 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 @@ -283,16 +283,22 @@ class DigitalEmployeeSyncApplicationServiceImplTest { 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-approval-conflict", "approval", "approval-1", 101L, new Date(10_000), - Map.of( - "entity_type", "approval", - "title", "远端审批冲突", - "status", "pending", - "approval_conflict_active", true, - "approval_conflict_reason", "terminal_status_mismatch", - "approval_id", "approval-1", - "plan_id", "plan-1", - "task_id", "task-1", - "priority", "high" + Map.ofEntries( + Map.entry("entity_type", "approval"), + Map.entry("title", "远端审批冲突"), + Map.entry("status", "pending"), + Map.entry("approval_conflict_active", true), + Map.entry("approval_conflict_reason", "terminal_status_mismatch"), + Map.entry("approval_id", "approval-1"), + Map.entry("plan_id", "plan-1"), + Map.entry("task_id", "task-1"), + Map.entry("priority", "high"), + Map.entry("approval_policy_id", "approval-policy-1"), + Map.entry("conflict_policy_id", "conflict-policy-1"), + Map.entry("decision_guard_status", "protected"), + Map.entry("batch_accept_remote_disabled", true), + Map.entry("auto_decision_disabled", true), + Map.entry("policy_reason", "manual_review_required") ), Map.of("id", "approval-1", "status", "pending")), record("outbox-risk-approval", "event", "event-risk-1", 101L, new Date(11_000), @@ -344,6 +350,12 @@ class DigitalEmployeeSyncApplicationServiceImplTest { assertThat(result.getRecords().get(0).getView()).isEqualTo("approval_governance"); assertThat(result.getRecords().get(0).getApprovalId()).isEqualTo("approval-1"); assertThat(result.getRecords().get(0).getCategory()).isEqualTo("approval_conflict"); + assertThat(result.getRecords().get(0).getApprovalPolicyId()).isEqualTo("approval-policy-1"); + assertThat(result.getRecords().get(0).getConflictPolicyId()).isEqualTo("conflict-policy-1"); + assertThat(result.getRecords().get(0).getDecisionGuardStatus()).isEqualTo("protected"); + assertThat(result.getRecords().get(0).getBatchAcceptRemoteDisabled()).isTrue(); + assertThat(result.getRecords().get(0).getAutoDecisionDisabled()).isTrue(); + assertThat(result.getRecords().get(0).getPolicyReason()).isEqualTo("manual_review_required"); assertThat(result.getRecords().get(1).getCategory()).isEqualTo("risk_approval"); assertThat(result.getRecords().get(2).getRouteDecisionId()).isEqualTo("route-1"); assertThat(result.getRecords().get(3).getApprovalId()).isEqualTo("approval-1"); diff --git a/qiming/src/pages/SystemManagement/Content/DigitalEmployeeOps/index.tsx b/qiming/src/pages/SystemManagement/Content/DigitalEmployeeOps/index.tsx index 060d1a2e..42921d3b 100644 --- a/qiming/src/pages/SystemManagement/Content/DigitalEmployeeOps/index.tsx +++ b/qiming/src/pages/SystemManagement/Content/DigitalEmployeeOps/index.tsx @@ -114,6 +114,9 @@ function renderSummary(record: DigitalEmployeeAdminWorkbenchRow) { record.task_id && `Task ${record.task_id}`, record.run_id && `Run ${record.run_id}`, record.approval_id && `Approval ${record.approval_id}`, + record.approval_policy_id && `ApprovalPolicy ${record.approval_policy_id}`, + record.conflict_policy_id && `ConflictPolicy ${record.conflict_policy_id}`, + record.decision_guard_status && `DecisionGuard ${record.decision_guard_status}`, record.service_id && `Service ${record.service_id}`, record.service_lease_id && `Lease ${record.service_lease_id}`, record.restart_record_id && `Restart ${record.restart_record_id}`, @@ -903,9 +906,15 @@ const DigitalEmployeeOps: React.FC = () => { : '审批相关事件'} {detailRecord.category && ` · ${detailRecord.category}`} {detailRecord.priority && ` · 优先级 ${detailRecord.priority}`} + {detailRecord.approval_policy_id && ` · 审批策略 ${detailRecord.approval_policy_id}`} + {detailRecord.conflict_policy_id && ` · 冲突策略 ${detailRecord.conflict_policy_id}`} + {detailRecord.decision_guard_status && ` · 裁决保护 ${detailRecord.decision_guard_status}`} + {detailRecord.policy_reason && ` · 策略原因 ${detailRecord.policy_reason}`} + {detailRecord.batch_accept_remote_disabled && ' · 批量采纳远端禁用'} + {detailRecord.auto_decision_disabled && ' · 自动裁决禁用'} {' '} - · 批量/高风险裁决不开放,动作等待客户端拉取执行。 + · 展示裁决策略和保护状态,批量/高风险裁决不开放,动作等待客户端拉取执行。 )} diff --git a/qiming/src/types/interfaces/systemManage.ts b/qiming/src/types/interfaces/systemManage.ts index 554dec27..970bfcbc 100644 --- a/qiming/src/types/interfaces/systemManage.ts +++ b/qiming/src/types/interfaces/systemManage.ts @@ -602,6 +602,12 @@ export interface DigitalEmployeeAdminWorkbenchRow { orchestration_id?: string; trigger_source?: string; approval_id?: string; + approval_policy_id?: string; + conflict_policy_id?: string; + decision_guard_status?: string; + batch_accept_remote_disabled?: boolean; + auto_decision_disabled?: boolean; + policy_reason?: string; artifact_id?: string; artifact_group_id?: string; artifact_count?: number; 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 e72371d2..2d6087ff 100644 --- a/qimingclaw/crates/agent-electron-client/scripts/check-digital-employee.js +++ b/qimingclaw/crates/agent-electron-client/scripts/check-digital-employee.js @@ -1495,13 +1495,24 @@ function checkDigitalAdminApprovalGovernanceWorkbench() { [service, "approval_conflict_active", "backend approval conflict classifier"], [service, "risk_approval", "backend risk approval classifier"], [service, "approval_action_recorded", "backend approval action history classifier"], + [service, "approval_policy_id", "backend approval policy field extraction"], + [service, "batch_accept_remote_disabled", "backend batch accept remote guard field"], + [service, "auto_decision_disabled", "backend auto decision guard field"], [test, "queryAdminWorkbenchApprovalGovernanceReturnsApprovalConflictRiskAndHistoryRowsOnly", "backend approval governance test"], + [test, "getApprovalPolicyId", "backend approval policy assertion"], + [test, "getBatchAcceptRemoteDisabled", "backend batch accept disabled assertion"], [qimingTypes, "approval_governance", "qiming approval governance view type"], + [qimingTypes, "approval_policy_id", "qiming approval policy field"], + [qimingTypes, "decision_guard_status", "qiming decision guard field"], [qimingOps, "审批治理", "qiming approval governance tab"], [qimingOps, "保留本地", "qiming approval keep local action"], [qimingOps, "标记复核", "qiming approval mark reviewed action"], + [qimingOps, "裁决保护", "qiming decision guard copy"], + [qimingOps, "批量采纳远端禁用", "qiming batch accept remote guard copy"], + [qimingOps, "自动裁决禁用", "qiming auto decision guard copy"], [qimingOps, "批量/高风险裁决不开放", "qiming approval governance safety copy"], [docs, "正式管理端审批工作台预览", "docs approval governance absorption"], + [docs, "正式管理端审批裁决策略预览", "docs approval decision policy 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 f9ab9262..c2b84cf6 100644 --- a/qimingclaw/docs/digital-employee-frontend-integration-plan.md +++ b/qimingclaw/docs/digital-employee-frontend-integration-plan.md @@ -588,7 +588,7 @@ GET /api/digital-employee/approvals - 建议:下一轮围绕正式管理端生命周期工作台和跨设备图谱,把 embedded 预览聚合推进到跨端运营治理。 8. **审批 / 人工介入增强** - - 已吸收:approval 记录、workday decision、ACP permission 响应桥已有雏形;用户处理审批时会写入 `approval_decision` runtime event;评论、转交、超时、风险标记会写入 `approval_action_recorded` / `approval_action_rejected`,并联动 embedded `/api/approval/:approvalId/timeline`、审批列表摘要、管理端 `/api/digital-employee/approval-history` 历史视图、`/api/approval/subscriptions` 订阅策略和 notification 投影;风险审批策略已支持管理端远端下发、手动拉取、本地策略评估、高风险动作前置拦截和本地设置页管理,`/api/risk-approval/policy` 可读写本地策略并记录 `update_risk_approval_policy`;多步审批 workflow 已复用 `digital_approvals.payload`,支持步骤推进、转交/超时/风险动作更新当前步骤、管理端审批更新拉取和审批处理回写,审批动作历史、风险策略、多步流程与通知联动已开始闭环;跨端审批冲突可视化已开始吸收,管理端远端更新与本地终态/更新时间/current step 不一致时会保留本地状态、记录 `approval_conflict_detected`、在业务视图投影 `approval_conflict_*` 字段,并在首页审批卡暂停直接同意/驳回;冲突解决动作闭环已开始吸收,客户端可通过独立 `resolveApprovalConflict` bridge 选择保留本地、采纳管理端或标记已复核,裁决会写入 `approval_conflict_resolved` / `approval_conflict_resolution_rejected`,并在审批业务视图投影 `approval_conflict_resolution`、`approval_conflict_resolved_at` 和裁决人摘要。跨设备批量冲突排查已开始吸收,embedded 新增“介入台”聚合审批冲突、风险审批、路由干预和待处理通知,支持筛选、分页、批量保留本地和批量标记复核;批量采纳管理端被 `batch_accept_remote_disabled` 保护,避免扩大状态分叉。正式管理端审批工作台预览已开始吸收,qiming-backend 新增 `approval_governance` 运营台视图聚合审批冲突、风险审批、路由待审和审批动作历史,qiming“数字员工运营台”新增“审批治理” tab,并只开放保留本地、标记复核、标记已看、忽略和重试策略检查等低风险动作意图。 + - 已吸收:approval 记录、workday decision、ACP permission 响应桥已有雏形;用户处理审批时会写入 `approval_decision` runtime event;评论、转交、超时、风险标记会写入 `approval_action_recorded` / `approval_action_rejected`,并联动 embedded `/api/approval/:approvalId/timeline`、审批列表摘要、管理端 `/api/digital-employee/approval-history` 历史视图、`/api/approval/subscriptions` 订阅策略和 notification 投影;风险审批策略已支持管理端远端下发、手动拉取、本地策略评估、高风险动作前置拦截和本地设置页管理,`/api/risk-approval/policy` 可读写本地策略并记录 `update_risk_approval_policy`;多步审批 workflow 已复用 `digital_approvals.payload`,支持步骤推进、转交/超时/风险动作更新当前步骤、管理端审批更新拉取和审批处理回写,审批动作历史、风险策略、多步流程与通知联动已开始闭环;跨端审批冲突可视化已开始吸收,管理端远端更新与本地终态/更新时间/current step 不一致时会保留本地状态、记录 `approval_conflict_detected`、在业务视图投影 `approval_conflict_*` 字段,并在首页审批卡暂停直接同意/驳回;冲突解决动作闭环已开始吸收,客户端可通过独立 `resolveApprovalConflict` bridge 选择保留本地、采纳管理端或标记已复核,裁决会写入 `approval_conflict_resolved` / `approval_conflict_resolution_rejected`,并在审批业务视图投影 `approval_conflict_resolution`、`approval_conflict_resolved_at` 和裁决人摘要。跨设备批量冲突排查已开始吸收,embedded 新增“介入台”聚合审批冲突、风险审批、路由干预和待处理通知,支持筛选、分页、批量保留本地和批量标记复核;批量采纳管理端被 `batch_accept_remote_disabled` 保护,避免扩大状态分叉。正式管理端审批工作台预览已开始吸收,qiming-backend 新增 `approval_governance` 运营台视图聚合审批冲突、风险审批、路由待审和审批动作历史,qiming“数字员工运营台”新增“审批治理” tab,并只开放保留本地、标记复核、标记已看、忽略和重试策略检查等低风险动作意图。正式管理端审批裁决策略预览已开始吸收,审批治理详情可展示 `approval_policy_id`、`conflict_policy_id`、`decision_guard_status`、`batch_accept_remote_disabled`、`auto_decision_disabled` 和策略原因,用于解释为什么只允许低风险复核或保留本地。 - 缺口:仍缺少管理端裁决策略 UI、批量采纳远端和高风险审批自动执行。 - 建议:下一轮围绕正式管理端审批工作台,把 embedded 介入台预览推进到外部管理端批量排查和策略化回写。