吸收数字员工管理端审批裁决策略预览
This commit is contained in:
@@ -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")
|
||||
|
||||
@@ -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"))))
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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 && ' · 自动裁决禁用'}
|
||||
<Typography.Text type="secondary">
|
||||
{' '}
|
||||
· 批量/高风险裁决不开放,动作等待客户端拉取执行。
|
||||
· 展示裁决策略和保护状态,批量/高风险裁决不开放,动作等待客户端拉取执行。
|
||||
</Typography.Text>
|
||||
</Typography.Paragraph>
|
||||
)}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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 介入台预览推进到外部管理端批量排查和策略化回写。
|
||||
|
||||
|
||||
Reference in New Issue
Block a user