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 3b9c57f2..f06af44e 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
@@ -202,6 +202,16 @@ public class DigitalEmployeeAdminWorkbenchRowDto {
private String policyKind;
@JsonProperty("policy_key")
private String policyKey;
+ @JsonProperty("policy_edit_request_id")
+ private String policyEditRequestId;
+ @JsonProperty("policy_edit_status")
+ private String policyEditStatus;
+ @JsonProperty("policy_edit_reason")
+ private String policyEditReason;
+ @JsonProperty("remote_policy_edit_disabled")
+ private Boolean remotePolicyEditDisabled;
+ @JsonProperty("auto_merge_disabled")
+ private Boolean autoMergeDisabled;
@JsonProperty("schedule_id")
private String scheduleId;
@JsonProperty("job_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 de21545a..eeb3c996 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
@@ -1170,6 +1170,11 @@ public class DigitalEmployeeSyncApplicationServiceImpl implements DigitalEmploye
.recommendedAction(firstString(businessView.get("recommended_action"), businessView.get("recommendedAction"), payload.get("recommended_action"), payload.get("recommendedAction")))
.policyKind(firstString(businessView.get("policy_kind"), businessView.get("policyKind"), payload.get("policy_kind"), payload.get("policyKind")))
.policyKey(firstString(businessView.get("policy_key"), businessView.get("policyKey"), payload.get("policy_key"), payload.get("policyKey")))
+ .policyEditRequestId(firstString(businessView.get("policy_edit_request_id"), businessView.get("policyEditRequestId"), payload.get("policy_edit_request_id"), payload.get("policyEditRequestId")))
+ .policyEditStatus(firstString(businessView.get("policy_edit_status"), businessView.get("policyEditStatus"), payload.get("policy_edit_status"), payload.get("policyEditStatus")))
+ .policyEditReason(firstString(businessView.get("policy_edit_reason"), businessView.get("policyEditReason"), payload.get("policy_edit_reason"), payload.get("policyEditReason")))
+ .remotePolicyEditDisabled(nullableBooleanValue(firstPresent(businessView.get("remote_policy_edit_disabled"), businessView.get("remotePolicyEditDisabled"), payload.get("remote_policy_edit_disabled"), payload.get("remotePolicyEditDisabled"))))
+ .autoMergeDisabled(nullableBooleanValue(firstPresent(businessView.get("auto_merge_disabled"), businessView.get("autoMergeDisabled"), payload.get("auto_merge_disabled"), payload.get("autoMergeDisabled"))))
.scheduleId(firstString(businessView.get("schedule_id"), businessView.get("scheduleId"), payload.get("schedule_id"), payload.get("scheduleId")))
.jobId(firstString(businessView.get("job_id"), businessView.get("jobId"), payload.get("job_id"), payload.get("jobId")))
.revisionId(firstString(businessView.get("revision_id"), businessView.get("revisionId"), payload.get("revision_id"), payload.get("revisionId")))
@@ -1386,7 +1391,10 @@ public class DigitalEmployeeSyncApplicationServiceImpl implements DigitalEmploye
|| StringUtils.equals(category, "policy_center")
|| startsWithAny(kind, "policy_", "skill_policy_", "risk_approval_policy", "route_decision_policy", "plan_step_dispatch_policy")
|| StringUtils.isNotBlank(row.getPolicyKind())
- || StringUtils.isNotBlank(row.getPolicyKey());
+ || StringUtils.isNotBlank(row.getPolicyKey())
+ || StringUtils.isNotBlank(row.getPolicyEditRequestId())
+ || row.getRemotePolicyEditDisabled() != null
+ || row.getAutoMergeDisabled() != null;
}
private boolean isSchedulerOperationsRow(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 38f13a9c..cf7ab16f 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
@@ -660,6 +660,22 @@ class DigitalEmployeeSyncApplicationServiceImplTest {
"max_per_sweep", 3
),
Map.of("id", "event-policy-2", "kind", "plan_step_dispatch_policy_pulled")),
+ record("outbox-policy-edit", "event", "event-policy-edit-1", 101L, new Date(11_500),
+ Map.ofEntries(
+ Map.entry("entity_type", "event"),
+ Map.entry("category", "policy_center"),
+ Map.entry("kind", "remote_policy_edit_requested"),
+ Map.entry("status", "blocked"),
+ Map.entry("title", "远程策略编辑请求"),
+ Map.entry("policy_kind", "route_decision"),
+ Map.entry("policy_key", "route_decision"),
+ Map.entry("policy_edit_request_id", "policy-edit-1"),
+ Map.entry("policy_edit_status", "rejected"),
+ Map.entry("policy_edit_reason", "manual_review_required"),
+ Map.entry("remote_policy_edit_disabled", true),
+ Map.entry("auto_merge_disabled", true)
+ ),
+ Map.of("id", "event-policy-edit-1", "kind", "remote_policy_edit_requested")),
record("outbox-scheduler", "event", "event-scheduler-1", 101L, new Date(12_000),
Map.of("entity_type", "event", "category", "scheduler", "title", "调度", "status", "ready", "job_id", "job-1"),
Map.of("id", "event-scheduler-1", "status", "ready")),
@@ -672,14 +688,19 @@ class DigitalEmployeeSyncApplicationServiceImplTest {
"policy_center", null, null, null, null, null, null, null, null, null, null, null, 1L, 20L
);
- assertThat(result.getTotal()).isEqualTo(2);
+ assertThat(result.getTotal()).isEqualTo(3);
assertThat(result.getRecords()).extracting(DigitalEmployeeAdminWorkbenchRowDto::getEntityId)
- .containsExactly("event-policy-1", "event-policy-2");
+ .containsExactly("event-policy-1", "event-policy-2", "event-policy-edit-1");
assertThat(result.getRecords().get(0).getView()).isEqualTo("policy_center");
assertThat(result.getRecords().get(0).getPolicyKind()).isEqualTo("route_decision");
assertThat(result.getRecords().get(0).getPolicyKey()).isEqualTo("route_decision");
assertThat(result.getRecords().get(0).getBusinessView()).containsEntry("auto_create_governance_commands", false);
assertThat(result.getRecords().get(1).getPolicyKind()).isEqualTo("dispatch");
+ assertThat(result.getRecords().get(2).getPolicyEditRequestId()).isEqualTo("policy-edit-1");
+ assertThat(result.getRecords().get(2).getPolicyEditStatus()).isEqualTo("rejected");
+ assertThat(result.getRecords().get(2).getPolicyEditReason()).isEqualTo("manual_review_required");
+ assertThat(result.getRecords().get(2).getRemotePolicyEditDisabled()).isTrue();
+ assertThat(result.getRecords().get(2).getAutoMergeDisabled()).isTrue();
}
@Test
diff --git a/qiming/src/pages/SystemManagement/Content/DigitalEmployeeOps/index.tsx b/qiming/src/pages/SystemManagement/Content/DigitalEmployeeOps/index.tsx
index 9bb8711d..def81a03 100644
--- a/qiming/src/pages/SystemManagement/Content/DigitalEmployeeOps/index.tsx
+++ b/qiming/src/pages/SystemManagement/Content/DigitalEmployeeOps/index.tsx
@@ -131,6 +131,8 @@ function renderSummary(record: DigitalEmployeeAdminWorkbenchRow) {
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}`,
+ record.policy_edit_request_id && `PolicyEdit ${record.policy_edit_request_id}`,
+ record.policy_edit_status && `PolicyEditStatus ${record.policy_edit_status}`,
record.intervention_conflict_status && `Route ${record.intervention_conflict_status}`,
record.subscription_policy_id && `Subscription ${record.subscription_policy_id}`,
record.daily_report_fact_id && `ReportFact ${record.daily_report_fact_id}`,
@@ -921,6 +923,7 @@ const DigitalEmployeeOps: React.FC = () => {
detailRecord.skill_id && `Skill ${detailRecord.skill_id}`,
detailRecord.skill_version && `Version ${detailRecord.skill_version}`,
detailRecord.policy_source && `PolicySource ${detailRecord.policy_source}`,
+ detailRecord.policy_edit_request_id && `PolicyEdit ${detailRecord.policy_edit_request_id}`,
detailRecord.tool_name && `Tool ${detailRecord.tool_name}`,
detailRecord.server_id && `Server ${detailRecord.server_id}`,
detailRecord.schedule_id && `Schedule ${detailRecord.schedule_id}`,
@@ -1196,9 +1199,14 @@ const DigitalEmployeeOps: React.FC = () => {
策略中心:
{detailRecord.policy_kind || detailRecord.policy_key || detailRecord.entity_id || '--'}
{detailRecord.status && ` · ${detailRecord.status}`}
+ {detailRecord.policy_edit_request_id && ` · 远程策略编辑请求 ${detailRecord.policy_edit_request_id}`}
+ {detailRecord.policy_edit_status && ` · 编辑状态 ${detailRecord.policy_edit_status}`}
+ {detailRecord.policy_edit_reason && ` · 编辑原因 ${detailRecord.policy_edit_reason}`}
+ {detailRecord.remote_policy_edit_disabled && ' · 远程策略编辑禁用'}
+ {detailRecord.auto_merge_disabled && ' · 自动合并禁用'}
{' '}
- · 支持批量拉取策略和复核标记,不开放远程策略编辑。
+ · 支持批量拉取策略和复核标记,不开放远程策略编辑,不自动合并策略。
)}
diff --git a/qiming/src/types/interfaces/systemManage.ts b/qiming/src/types/interfaces/systemManage.ts
index 470e6fc4..12d8b226 100644
--- a/qiming/src/types/interfaces/systemManage.ts
+++ b/qiming/src/types/interfaces/systemManage.ts
@@ -684,6 +684,11 @@ export interface DigitalEmployeeAdminWorkbenchRow {
recommended_action?: string;
policy_kind?: string;
policy_key?: string;
+ policy_edit_request_id?: string;
+ policy_edit_status?: string;
+ policy_edit_reason?: string;
+ remote_policy_edit_disabled?: boolean;
+ auto_merge_disabled?: boolean;
schedule_id?: string;
job_id?: string;
revision_id?: string;
@@ -750,6 +755,11 @@ export interface DigitalEmployeePolicySnapshotRow {
batch_accept_remote_disabled?: boolean;
auto_decision_disabled?: boolean;
policy_reason?: string;
+ policy_edit_request_id?: string;
+ policy_edit_status?: string;
+ policy_edit_reason?: string;
+ remote_policy_edit_disabled?: boolean;
+ auto_merge_disabled?: boolean;
dispatch_policy_key?: string;
max_per_sweep?: number;
auto_dispatch_ready_steps?: 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 77dbc8ec..32a7545a 100644
--- a/qimingclaw/crates/agent-electron-client/scripts/check-digital-employee.js
+++ b/qimingclaw/crates/agent-electron-client/scripts/check-digital-employee.js
@@ -1590,6 +1590,9 @@ function checkDigitalAdminApprovalPoliciesWorkbench() {
[service, "approval_policy_id", "backend approval policy id projection"],
[service, "conflict_policy_id", "backend conflict policy id projection"],
[service, "decision_guard_status", "backend decision guard projection"],
+ [service, "policy_edit_request_id", "backend policy edit request projection"],
+ [service, "remotePolicyEditDisabled", "backend remote policy edit projection"],
+ [service, "autoMergeDisabled", "backend auto merge projection"],
[test, "queryAdminWorkbenchApprovalPoliciesReturnsPolicyRowsOnly", "backend approval policies test"],
[qimingTypes, "approval_policies", "qiming approval policies view type"],
[qimingOps, "审批策略", "qiming approval policies tab"],
@@ -1597,6 +1600,7 @@ function checkDigitalAdminApprovalPoliciesWorkbench() {
[qimingOps, "不自动裁决", "qiming no auto decision copy"],
[qimingOps, "不批量采纳远端", "qiming no batch remote accept copy"],
[docs, "正式管理端审批策略预览", "docs approval policy absorption"],
+ [docs, "远程策略编辑安全壳预览", "docs remote policy edit shell absorption"],
];
const missing = requiredSnippets
.filter(([content, snippet]) => !content.includes(snippet))
@@ -1789,25 +1793,39 @@ function checkDigitalAdminPolicySchedulerWorkbenches() {
[service, "isPolicyCenterRow", "backend policy center matcher"],
[service, "isSchedulerOperationsRow", "backend scheduler operations matcher"],
[service, "edit_policy_remote_disabled", "backend policy edit disabled reason"],
+ [service, "remote_policy_edit_disabled", "backend remote policy edit disabled reason"],
+ [service, "policy_edit_request_id", "backend policy edit request projection"],
+ [service, "auto_merge_disabled", "backend policy auto merge guard projection"],
[service, "run_schedule_now_disabled", "backend scheduler run disabled reason"],
[service, "start_scheduler_disabled", "backend scheduler start disabled reason"],
[dto, "policy_kind", "backend policy kind row field"],
[dto, "policy_key", "backend policy key row field"],
+ [dto, "policy_edit_request_id", "backend policy edit request row field"],
+ [dto, "remote_policy_edit_disabled", "backend remote policy edit disabled row field"],
+ [dto, "auto_merge_disabled", "backend auto merge disabled row field"],
[dto, "schedule_id", "backend schedule id row field"],
[dto, "job_id", "backend job id row field"],
[test, "queryAdminWorkbenchPolicyCenterReturnsPolicySnapshotRowsOnly", "backend policy center test"],
+ [test, "getPolicyEditRequestId", "backend policy edit request assertion"],
+ [test, "getAutoMergeDisabled", "backend auto merge disabled assertion"],
[test, "queryAdminWorkbenchSchedulerOperationsReturnsSchedulerRowsOnly", "backend scheduler operations test"],
[test, "createAdminActionReturnsSpecificPolicyAndSchedulerDisabledReasons", "backend disabled reason test"],
[qimingTypes, "policy_center", "qiming policy center view type"],
[qimingTypes, "scheduler_operations", "qiming scheduler operations view type"],
+ [qimingTypes, "policy_edit_request_id", "qiming policy edit request field"],
+ [qimingTypes, "auto_merge_disabled", "qiming policy auto merge guard field"],
[qimingTypes, "schedule_id", "qiming schedule id field"],
[qimingOps, "策略中心", "qiming policy center tab"],
[qimingOps, "调度运营", "qiming scheduler operations tab"],
[qimingOps, "批量拉取策略", "qiming policy pull action"],
+ [qimingOps, "远程策略编辑请求", "qiming policy edit request detail"],
+ [qimingOps, "自动合并禁用", "qiming policy auto merge guard copy"],
[qimingOps, "立即检查调度", "qiming scheduler check action"],
[qimingOps, "不开放远程策略编辑", "qiming policy edit guard copy"],
+ [qimingOps, "不自动合并策略", "qiming policy auto merge safety copy"],
[qimingOps, "不开放 start/stop", "qiming scheduler start stop guard copy"],
[docs, "正式管理端策略中心预览", "docs policy center absorption"],
+ [docs, "远程策略编辑安全壳预览", "docs remote policy edit shell absorption"],
[docs, "正式管理端调度运营预览", "docs scheduler operations absorption"],
];
const missing = requiredSnippets
diff --git a/qimingclaw/docs/digital-employee-frontend-integration-plan.md b/qimingclaw/docs/digital-employee-frontend-integration-plan.md
index 906833bb..3775899e 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_policy_id`、`conflict_policy_id`、`decision_guard_status`、`batch_accept_remote_disabled`、`auto_decision_disabled` 和策略原因,用于解释为什么只允许低风险复核或保留本地。正式管理端审批策略预览已开始吸收,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` 和策略原因,用于解释为什么只允许低风险复核或保留本地。正式管理端审批策略预览已开始吸收,qiming“数字员工运营台”的“审批策略”tab 可独立筛选审批策略、冲突策略、风险审批策略和裁决保护快照,只记录批量拉取策略、标记已看和忽略意图,不远程编辑策略、不自动裁决、不批量采纳远端。远程策略编辑安全壳预览已开始吸收,qiming“数字员工运营台”的“策略中心”会显示远程策略编辑请求、安全禁用和自动合并禁用状态,只记录远程策略编辑请求、标记已看和忽略意图,不开放真实远程编辑或自动合并。
- 缺口:仍缺少管理端可编辑裁决策略 UI、批量采纳远端和高风险审批自动执行。
- 建议:下一轮围绕正式管理端审批工作台,把 embedded 介入台预览推进到外部管理端批量排查和策略化回写。