吸收数字员工管理端日报审批裁决回写预览
This commit is contained in:
@@ -109,6 +109,16 @@ public class DigitalEmployeeAdminWorkbenchRowDto {
|
||||
private String sendRecordId;
|
||||
@JsonProperty("approval_decision_status")
|
||||
private String approvalDecisionStatus;
|
||||
@JsonProperty("daily_report_approval_id")
|
||||
private String dailyReportApprovalId;
|
||||
@JsonProperty("daily_report_approval_action")
|
||||
private String dailyReportApprovalAction;
|
||||
@JsonProperty("daily_report_approval_actor")
|
||||
private String dailyReportApprovalActor;
|
||||
@JsonProperty("daily_report_approval_reason")
|
||||
private String dailyReportApprovalReason;
|
||||
@JsonProperty("daily_report_approval_recorded_at")
|
||||
private String dailyReportApprovalRecordedAt;
|
||||
@JsonProperty("route_decision_id")
|
||||
private String routeDecisionId;
|
||||
@JsonProperty("service_id")
|
||||
|
||||
@@ -71,7 +71,7 @@ public class DigitalEmployeeSyncApplicationServiceImpl implements DigitalEmploye
|
||||
"notification:mark_read", "notification:dismiss",
|
||||
"notification_policy:pull_policy", "notification_policy:mark_reviewed", "notification_policy:dismiss",
|
||||
"artifact:mark_keep", "artifact:mark_expire", "artifact:mark_reviewed", "artifact:record_cleanup_request",
|
||||
"daily_report:mark_delivered", "daily_report:mark_confirmed", "daily_report:request_approval",
|
||||
"daily_report:mark_delivered", "daily_report:mark_confirmed", "daily_report:request_approval", "daily_report:record_approval_decision",
|
||||
"memory:archive_memory", "memory:restore_memory", "memory:mark_reviewed",
|
||||
"skill:mark_reviewed", "skill:dismiss",
|
||||
"policy_snapshot:pull_policy", "policy_snapshot:mark_reviewed", "policy_snapshot:dismiss",
|
||||
@@ -1123,6 +1123,11 @@ public class DigitalEmployeeSyncApplicationServiceImpl implements DigitalEmploye
|
||||
.dailyReportFactId(firstString(businessView.get("daily_report_fact_id"), businessView.get("dailyReportFactId"), payload.get("daily_report_fact_id"), payload.get("dailyReportFactId")))
|
||||
.sendRecordId(firstString(businessView.get("send_record_id"), businessView.get("sendRecordId"), payload.get("send_record_id"), payload.get("sendRecordId")))
|
||||
.approvalDecisionStatus(firstString(businessView.get("approval_decision_status"), businessView.get("approvalDecisionStatus"), payload.get("approval_decision_status"), payload.get("approvalDecisionStatus")))
|
||||
.dailyReportApprovalId(firstString(businessView.get("daily_report_approval_id"), businessView.get("dailyReportApprovalId"), payload.get("daily_report_approval_id"), payload.get("dailyReportApprovalId")))
|
||||
.dailyReportApprovalAction(firstString(businessView.get("daily_report_approval_action"), businessView.get("dailyReportApprovalAction"), payload.get("daily_report_approval_action"), payload.get("dailyReportApprovalAction")))
|
||||
.dailyReportApprovalActor(firstString(businessView.get("daily_report_approval_actor"), businessView.get("dailyReportApprovalActor"), payload.get("daily_report_approval_actor"), payload.get("dailyReportApprovalActor")))
|
||||
.dailyReportApprovalReason(firstString(businessView.get("daily_report_approval_reason"), businessView.get("dailyReportApprovalReason"), payload.get("daily_report_approval_reason"), payload.get("dailyReportApprovalReason")))
|
||||
.dailyReportApprovalRecordedAt(firstString(businessView.get("daily_report_approval_recorded_at"), businessView.get("dailyReportApprovalRecordedAt"), payload.get("daily_report_approval_recorded_at"), payload.get("dailyReportApprovalRecordedAt")))
|
||||
.routeDecisionId(firstString(businessView.get("route_decision_id"), payload.get("route_decision_id")))
|
||||
.serviceId(firstString(businessView.get("service_id"), businessView.get("serviceId"), payload.get("service_id"), payload.get("serviceId")))
|
||||
.serviceLeaseId(firstString(businessView.get("service_lease_id"), businessView.get("serviceLeaseId"), payload.get("service_lease_id"), payload.get("serviceLeaseId")))
|
||||
@@ -1321,7 +1326,9 @@ public class DigitalEmployeeSyncApplicationServiceImpl implements DigitalEmploye
|
||||
private boolean isDailyReportRow(DigitalEmployeeAdminWorkbenchRowDto row) {
|
||||
return StringUtils.equals(row.getCategory(), "daily_report")
|
||||
|| startsWithAny(row.getKind(), "daily_report")
|
||||
|| StringUtils.isNotBlank(row.getReportId());
|
||||
|| StringUtils.isNotBlank(row.getReportId())
|
||||
|| StringUtils.isNotBlank(row.getDailyReportApprovalId())
|
||||
|| StringUtils.isNotBlank(row.getDailyReportApprovalAction());
|
||||
}
|
||||
|
||||
private boolean isGovernanceCommandRow(DigitalEmployeeAdminWorkbenchRowDto row) {
|
||||
|
||||
@@ -1719,16 +1719,32 @@ class DigitalEmployeeSyncApplicationServiceImplTest {
|
||||
"confirmed_at", "2026-06-13T10:00:00+08:00"
|
||||
),
|
||||
Map.of("id", "event-daily-report-2", "kind", "daily_report_confirmed")),
|
||||
record("outbox-task", "task", "task-1", 101L, new Date(13_000),
|
||||
record("outbox-daily-report-approval", "event", "event-daily-report-3", 101L, new Date(13_000),
|
||||
Map.ofEntries(
|
||||
Map.entry("entity_type", "event"),
|
||||
Map.entry("category", "daily_report"),
|
||||
Map.entry("kind", "daily_report_approval_decision_recorded"),
|
||||
Map.entry("status", "approved"),
|
||||
Map.entry("title", "日报审批裁决已记录"),
|
||||
Map.entry("report_id", "report-4"),
|
||||
Map.entry("daily_report_approval_id", "daily-report-approval-1"),
|
||||
Map.entry("daily_report_approval_action", "approved"),
|
||||
Map.entry("daily_report_approval_actor", "operator-1"),
|
||||
Map.entry("daily_report_approval_reason", "content_reviewed"),
|
||||
Map.entry("daily_report_approval_recorded_at", "2026-06-13T10:30:00+08:00"),
|
||||
Map.entry("approval_decision_status", "approved")
|
||||
),
|
||||
Map.of("id", "event-daily-report-3", "kind", "daily_report_approval_decision_recorded")),
|
||||
record("outbox-task", "task", "task-1", 101L, new Date(14_000),
|
||||
Map.of("entity_type", "task", "title", "普通任务", "status", "running"),
|
||||
Map.of("id", "task-1", "status", "running")),
|
||||
record("outbox-approval", "approval", "approval-1", 101L, new Date(14_000),
|
||||
record("outbox-approval", "approval", "approval-1", 101L, new Date(15_000),
|
||||
Map.of("entity_type", "approval", "title", "普通审批", "status", "pending"),
|
||||
Map.of("id", "approval-1", "status", "pending")),
|
||||
record("outbox-notification", "notification", "notification-1", 101L, new Date(15_000),
|
||||
record("outbox-notification", "notification", "notification-1", 101L, new Date(16_000),
|
||||
Map.of("entity_type", "notification", "title", "普通通知", "status", "unread"),
|
||||
Map.of("id", "notification-1", "status", "unread")),
|
||||
record("outbox-audit", "event", "event-audit-1", 101L, new Date(16_000),
|
||||
record("outbox-audit", "event", "event-audit-1", 101L, new Date(17_000),
|
||||
Map.of("entity_type", "event", "category", "tool_call_audit", "title", "审计", "status", "warn"),
|
||||
Map.of("id", "event-audit-1", "status", "warn"))
|
||||
)));
|
||||
@@ -1737,9 +1753,9 @@ class DigitalEmployeeSyncApplicationServiceImplTest {
|
||||
"daily_reports", null, null, null, null, null, null, null, null, null, null, null, 1L, 20L
|
||||
);
|
||||
|
||||
assertThat(result.getTotal()).isEqualTo(3);
|
||||
assertThat(result.getTotal()).isEqualTo(4);
|
||||
assertThat(result.getRecords()).extracting(DigitalEmployeeAdminWorkbenchRowDto::getEntityId)
|
||||
.containsExactly("report-1", "event-daily-report-1", "event-daily-report-2");
|
||||
.containsExactly("report-1", "event-daily-report-1", "event-daily-report-2", "event-daily-report-3");
|
||||
assertThat(result.getRecords().get(0).getView()).isEqualTo("daily_reports");
|
||||
assertThat(result.getRecords().get(0).getReportId()).isEqualTo("report-1");
|
||||
assertThat(result.getRecords().get(0).getCategory()).isEqualTo("daily_report");
|
||||
@@ -1751,6 +1767,11 @@ class DigitalEmployeeSyncApplicationServiceImplTest {
|
||||
assertThat(result.getRecords().get(1).getReportId()).isEqualTo("report-2");
|
||||
assertThat(result.getRecords().get(1).getBusinessView()).containsEntry("delivery_status", "delivered");
|
||||
assertThat(result.getRecords().get(2).getBusinessView()).containsEntry("confirmed_at", "2026-06-13T10:00:00+08:00");
|
||||
assertThat(result.getRecords().get(3).getDailyReportApprovalId()).isEqualTo("daily-report-approval-1");
|
||||
assertThat(result.getRecords().get(3).getDailyReportApprovalAction()).isEqualTo("approved");
|
||||
assertThat(result.getRecords().get(3).getDailyReportApprovalActor()).isEqualTo("operator-1");
|
||||
assertThat(result.getRecords().get(3).getDailyReportApprovalReason()).isEqualTo("content_reviewed");
|
||||
assertThat(result.getRecords().get(3).getDailyReportApprovalRecordedAt()).isEqualTo("2026-06-13T10:30:00+08:00");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -339,6 +339,7 @@ function allowedActions(record: DigitalEmployeeAdminWorkbenchRow, view: DigitalE
|
||||
{ action: 'mark_delivered', label: '记录已送达' },
|
||||
{ action: 'mark_confirmed', label: '确认回执' },
|
||||
{ action: 'request_approval', label: '请求审批' },
|
||||
{ action: 'record_approval_decision', label: '记录审批裁决' },
|
||||
];
|
||||
}
|
||||
if (view === 'audits') {
|
||||
@@ -908,6 +909,8 @@ const DigitalEmployeeOps: React.FC = () => {
|
||||
`ReportFact ${detailRecord.daily_report_fact_id}`,
|
||||
detailRecord.send_record_id &&
|
||||
`SendRecord ${detailRecord.send_record_id}`,
|
||||
detailRecord.daily_report_approval_id &&
|
||||
`ReportApproval ${detailRecord.daily_report_approval_id}`,
|
||||
detailRecord.route_decision_id &&
|
||||
`Route ${detailRecord.route_decision_id}`,
|
||||
detailRecord.policy_kind && `Policy ${detailRecord.policy_kind}`,
|
||||
@@ -1104,9 +1107,19 @@ const DigitalEmployeeOps: React.FC = () => {
|
||||
` · 发送记录 ${detailRecord.send_record_id}`}
|
||||
{detailRecord.approval_decision_status &&
|
||||
` · 审批状态 ${detailRecord.approval_decision_status}`}
|
||||
{detailRecord.daily_report_approval_id &&
|
||||
` · 审批裁决 ${detailRecord.daily_report_approval_id}`}
|
||||
{detailRecord.daily_report_approval_action &&
|
||||
` · 裁决动作 ${detailRecord.daily_report_approval_action}`}
|
||||
{detailRecord.daily_report_approval_actor &&
|
||||
` · 裁决人 ${detailRecord.daily_report_approval_actor}`}
|
||||
{detailRecord.daily_report_approval_reason &&
|
||||
` · 裁决原因 ${detailRecord.daily_report_approval_reason}`}
|
||||
{detailRecord.daily_report_approval_recorded_at &&
|
||||
` · 裁决记录 ${detailRecord.daily_report_approval_recorded_at}`}
|
||||
<Typography.Text type="secondary">
|
||||
{' '}
|
||||
· 展示发送记录、审批状态和事实来源,只记录发送结果/审批/回执意图。
|
||||
· 展示发送记录、审批状态、审批裁决和事实来源,只记录发送结果/审批/回执/裁决意图,不触发真实发送或自动审批。
|
||||
</Typography.Text>
|
||||
</Typography.Paragraph>
|
||||
)}
|
||||
|
||||
@@ -637,6 +637,11 @@ export interface DigitalEmployeeAdminWorkbenchRow {
|
||||
daily_report_fact_id?: string;
|
||||
send_record_id?: string;
|
||||
approval_decision_status?: string;
|
||||
daily_report_approval_id?: string;
|
||||
daily_report_approval_action?: string;
|
||||
daily_report_approval_actor?: string;
|
||||
daily_report_approval_reason?: string;
|
||||
daily_report_approval_recorded_at?: string;
|
||||
route_decision_id?: string;
|
||||
service_id?: string;
|
||||
service_lease_id?: string;
|
||||
|
||||
@@ -2791,15 +2791,23 @@ function checkDigitalAdminDailyReportWorkbench() {
|
||||
[service, "daily_reports", "backend daily report view"],
|
||||
[service, "isDailyReportRow", "backend daily report matcher"],
|
||||
[service, "daily_report", "backend daily report category"],
|
||||
[service, "daily_report:record_approval_decision", "backend daily report approval decision action"],
|
||||
[dto, "report_id", "backend report id row field"],
|
||||
[dto, "daily_report_approval_id", "backend daily report approval id row field"],
|
||||
[dto, "daily_report_approval_action", "backend daily report approval action row field"],
|
||||
[dto, "daily_report_approval_recorded_at", "backend daily report approval recorded at row field"],
|
||||
[test, "queryAdminWorkbenchDailyReportsReturnsDailyReportRowsOnly", "backend daily report workbench test"],
|
||||
[test, "getDailyReportApprovalId", "backend daily report approval assertion"],
|
||||
[qimingTypes, "daily_reports", "qiming daily report view type"],
|
||||
[qimingTypes, "daily_report_approval_id", "qiming daily report approval id type field"],
|
||||
[qimingOps, "日报运营", "qiming daily report tab"],
|
||||
[qimingOps, "记录已送达", "qiming daily report delivered action"],
|
||||
[qimingOps, "确认回执", "qiming daily report confirmed action"],
|
||||
[qimingOps, "请求审批", "qiming daily report approval action"],
|
||||
[qimingOps, "记录审批裁决", "qiming daily report approval decision action"],
|
||||
[qimingOps, "记录发送结果", "qiming daily report send record action"],
|
||||
[docs, "正式管理端日报运营预览", "docs daily report absorption"],
|
||||
[docs, "管理端日报审批裁决回写预览", "docs daily report approval decision absorption"],
|
||||
];
|
||||
const missing = requiredSnippets
|
||||
.filter(([content, snippet]) => !content.includes(snippet))
|
||||
|
||||
@@ -614,8 +614,8 @@ GET /api/digital-employee/approvals
|
||||
- 建议:先使用 sync record 派生业务查询模型和 embedded 业务视图预览承接联调,再按容量和查询压力决定是否拆 Plan / Task / Run / Event 物理业务表。
|
||||
|
||||
13. **日报实体与导出交付**
|
||||
- 已吸收:embedded 页面可基于当前 workday projection 导出本地文本日报;生成日报时会通过 qimingclaw bridge 写入 `daily_report` text / HTML / PDF Artifact 与 `daily_report_generated` Event,并可通过 `/api/digital-employee/daily-reports` 和详情接口读取只读日报投影。日报 HTML/PDF 导出、发送记录、管理端确认回执和日报发送审批已开始吸收,交付动作会写入 `daily_report_send_recorded` / `daily_report_confirmed` / `daily_report_approval_requested` 事件,sync `business_view.category = daily_report` 可被管理端筛选消费。管理端正式日报页面预览和正式管理端日报运营预览已开始吸收,embedded 新增“日报运营”入口,展示日报生成、交付、确认、审批和关联产物状态,并复用现有生成、记录发送、确认回执和请求审批动作;qiming-backend 的 `daily_reports` 运营台视图会聚合日报生成、发送记录、确认回执和审批请求,qiming“数字员工运营台”的“日报运营”tab 可记录已送达、确认回执、请求审批和发送结果。发送账单审计外壳已开始吸收,qiming-backend 新增 `/api/digital-employee/admin/daily-reports/send-records`,qiming 运营台可在日报详情中“记录发送结果”,但不接真实第三方发送通道。正式管理端协作运营收口已开始吸收,日报运营详情会展示 `daily_report_fact_id`、`send_record_id` 和 `approval_decision_status`,用于解释事实来源、发送记录和审批状态。
|
||||
- 缺口:没有正式 DailyReport 物理表、真实管理端发送通道、正式外部管理端日报页面和审批裁决回写闭环。
|
||||
- 已吸收:embedded 页面可基于当前 workday projection 导出本地文本日报;生成日报时会通过 qimingclaw bridge 写入 `daily_report` text / HTML / PDF Artifact 与 `daily_report_generated` Event,并可通过 `/api/digital-employee/daily-reports` 和详情接口读取只读日报投影。日报 HTML/PDF 导出、发送记录、管理端确认回执和日报发送审批已开始吸收,交付动作会写入 `daily_report_send_recorded` / `daily_report_confirmed` / `daily_report_approval_requested` 事件,sync `business_view.category = daily_report` 可被管理端筛选消费。管理端正式日报页面预览和正式管理端日报运营预览已开始吸收,embedded 新增“日报运营”入口,展示日报生成、交付、确认、审批和关联产物状态,并复用现有生成、记录发送、确认回执和请求审批动作;qiming-backend 的 `daily_reports` 运营台视图会聚合日报生成、发送记录、确认回执和审批请求,qiming“数字员工运营台”的“日报运营”tab 可记录已送达、确认回执、请求审批和发送结果。发送账单审计外壳已开始吸收,qiming-backend 新增 `/api/digital-employee/admin/daily-reports/send-records`,qiming 运营台可在日报详情中“记录发送结果”,但不接真实第三方发送通道。正式管理端协作运营收口已开始吸收,日报运营详情会展示 `daily_report_fact_id`、`send_record_id` 和 `approval_decision_status`,用于解释事实来源、发送记录和审批状态。管理端日报审批裁决回写预览已开始吸收,日报运营详情可展示 `daily_report_approval_id`、裁决动作、裁决人、原因和记录时间,并只记录审批裁决意图,不触发真实发送或自动审批。
|
||||
- 缺口:没有正式 DailyReport 物理表、真实管理端发送通道和正式外部管理端日报页面。
|
||||
- 建议:先稳定 Artifact/Event 派生日报交付模型,再根据管理端联调需要决定是否物化 DailyReport 表与发送记录表。
|
||||
|
||||
## 管理端联动原则
|
||||
|
||||
Reference in New Issue
Block a user