吸收数字员工管理端日报运营预览
This commit is contained in:
@@ -735,6 +735,74 @@ class DigitalEmployeeSyncApplicationServiceImplTest {
|
||||
assertThat(row.getPayload()).containsEntry("tool_name", "shell");
|
||||
}
|
||||
|
||||
@Test
|
||||
void queryAdminWorkbenchDailyReportsReturnsDailyReportRowsOnly() {
|
||||
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-daily-report", "daily_report", "report-1", 101L, new Date(10_000),
|
||||
Map.of(
|
||||
"entity_type", "daily_report",
|
||||
"category", "daily_report",
|
||||
"kind", "daily_report_generated",
|
||||
"status", "generated",
|
||||
"title", "6 月 13 日日报",
|
||||
"report_id", "report-1",
|
||||
"summary", "日报已生成",
|
||||
"artifact_id", "artifact-report-1"
|
||||
),
|
||||
Map.of("id", "report-1", "kind", "daily_report_generated")),
|
||||
record("outbox-daily-report-delivered", "event", "event-daily-report-1", 101L, new Date(11_000),
|
||||
Map.of(
|
||||
"entity_type", "event",
|
||||
"category", "daily_report",
|
||||
"kind", "daily_report_send_recorded",
|
||||
"status", "delivered",
|
||||
"title", "日报发送已记录",
|
||||
"report_id", "report-2",
|
||||
"delivery_status", "delivered"
|
||||
),
|
||||
Map.of("id", "event-daily-report-1", "kind", "daily_report_send_recorded")),
|
||||
record("outbox-daily-report-confirmed", "event", "event-daily-report-2", 101L, new Date(12_000),
|
||||
Map.of(
|
||||
"entity_type", "event",
|
||||
"kind", "daily_report_confirmed",
|
||||
"status", "confirmed",
|
||||
"title", "日报确认回执",
|
||||
"report_id", "report-3",
|
||||
"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),
|
||||
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),
|
||||
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),
|
||||
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),
|
||||
Map.of("entity_type", "event", "category", "tool_call_audit", "title", "审计", "status", "warn"),
|
||||
Map.of("id", "event-audit-1", "status", "warn"))
|
||||
)));
|
||||
|
||||
DigitalEmployeeAdminWorkbenchPageDto result = service.queryAdminWorkbench(
|
||||
"daily_reports", null, null, null, null, null, null, null, null, null, null, null, 1L, 20L
|
||||
);
|
||||
|
||||
assertThat(result.getTotal()).isEqualTo(3);
|
||||
assertThat(result.getRecords()).extracting(DigitalEmployeeAdminWorkbenchRowDto::getEntityId)
|
||||
.containsExactly("report-1", "event-daily-report-1", "event-daily-report-2");
|
||||
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");
|
||||
assertThat(result.getRecords().get(0).getStatus()).isEqualTo("generated");
|
||||
assertThat(result.getRecords().get(0).getSummary()).isEqualTo("日报已生成");
|
||||
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");
|
||||
}
|
||||
|
||||
@Test
|
||||
void createAdminActionRecordsLowRiskActionAsPending() {
|
||||
DigitalEmployeeAdminActionRequestDto request = adminActionRequest("approval", "approval-1", "keep_local");
|
||||
|
||||
@@ -1839,6 +1839,91 @@ function checkDigitalAdminAuditDiagnosticsWorkbench() {
|
||||
console.log("[DigitalEmployeeCheck] admin audit diagnostics workbench hooks OK");
|
||||
}
|
||||
|
||||
function checkDigitalAdminDailyReportWorkbench() {
|
||||
console.log("\n[DigitalEmployeeCheck] Verify admin daily report workbench hooks");
|
||||
const backendRoot = path.resolve(packageRoot, "..", "..", "..", "qiming-backend");
|
||||
const qimingRoot = path.resolve(packageRoot, "..", "..", "..", "qiming");
|
||||
const servicePath = path.join(
|
||||
backendRoot,
|
||||
"app-platform-modules",
|
||||
"app-platform-agent",
|
||||
"app-platform-agent-core-application",
|
||||
"src",
|
||||
"main",
|
||||
"java",
|
||||
"com",
|
||||
"xspaceagi",
|
||||
"agent",
|
||||
"core",
|
||||
"application",
|
||||
"service",
|
||||
"DigitalEmployeeSyncApplicationServiceImpl.java",
|
||||
);
|
||||
const dtoPath = path.join(
|
||||
backendRoot,
|
||||
"app-platform-modules",
|
||||
"app-platform-agent",
|
||||
"app-platform-agent-core-adapter",
|
||||
"src",
|
||||
"main",
|
||||
"java",
|
||||
"com",
|
||||
"xspaceagi",
|
||||
"agent",
|
||||
"core",
|
||||
"adapter",
|
||||
"dto",
|
||||
"digital",
|
||||
"DigitalEmployeeAdminWorkbenchRowDto.java",
|
||||
);
|
||||
const testPath = path.join(
|
||||
backendRoot,
|
||||
"app-platform-modules",
|
||||
"app-platform-agent",
|
||||
"app-platform-agent-core-application",
|
||||
"src",
|
||||
"test",
|
||||
"java",
|
||||
"com",
|
||||
"xspaceagi",
|
||||
"agent",
|
||||
"core",
|
||||
"application",
|
||||
"service",
|
||||
"DigitalEmployeeSyncApplicationServiceImplTest.java",
|
||||
);
|
||||
const qimingOpsPath = path.join(qimingRoot, "src", "pages", "SystemManagement", "Content", "DigitalEmployeeOps", "index.tsx");
|
||||
const qimingTypesPath = path.join(qimingRoot, "src", "types", "interfaces", "systemManage.ts");
|
||||
const docsPath = path.resolve(packageRoot, "..", "..", "docs", "digital-employee-frontend-integration-plan.md");
|
||||
const service = fs.readFileSync(servicePath, "utf8");
|
||||
const dto = fs.readFileSync(dtoPath, "utf8");
|
||||
const test = fs.readFileSync(testPath, "utf8");
|
||||
const qimingOps = fs.readFileSync(qimingOpsPath, "utf8");
|
||||
const qimingTypes = fs.readFileSync(qimingTypesPath, "utf8");
|
||||
const docs = fs.readFileSync(docsPath, "utf8");
|
||||
const requiredSnippets = [
|
||||
[service, "daily_reports", "backend daily report view"],
|
||||
[service, "isDailyReportRow", "backend daily report matcher"],
|
||||
[service, "daily_report", "backend daily report category"],
|
||||
[dto, "report_id", "backend report id row field"],
|
||||
[test, "queryAdminWorkbenchDailyReportsReturnsDailyReportRowsOnly", "backend daily report workbench test"],
|
||||
[qimingTypes, "daily_reports", "qiming daily report view type"],
|
||||
[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 send record action"],
|
||||
[docs, "正式管理端日报运营预览", "docs daily report absorption"],
|
||||
];
|
||||
const missing = requiredSnippets
|
||||
.filter(([content, snippet]) => !content.includes(snippet))
|
||||
.map(([, , label]) => label);
|
||||
if (missing.length > 0) {
|
||||
throw new Error(`Missing admin daily report workbench hooks: ${missing.join(", ")}`);
|
||||
}
|
||||
console.log("[DigitalEmployeeCheck] admin daily report workbench hooks OK");
|
||||
}
|
||||
|
||||
function checkLocalDatabaseSchema() {
|
||||
console.log("\n[DigitalEmployeeCheck] Verify local SQLite digital schema");
|
||||
const dbPath = path.join(os.homedir(), ".qimingclaw", "qimingclaw.db");
|
||||
@@ -1907,6 +1992,7 @@ function main() {
|
||||
checkDigitalAdminNotificationWorkbench();
|
||||
checkDigitalAdminArtifactLifecycleWorkbench();
|
||||
checkDigitalAdminAuditDiagnosticsWorkbench();
|
||||
checkDigitalAdminDailyReportWorkbench();
|
||||
checkLocalDatabaseSchema();
|
||||
console.log("\n[DigitalEmployeeCheck] All checks passed");
|
||||
} catch (error) {
|
||||
|
||||
@@ -614,7 +614,7 @@ 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 新增 `/api/digital-employee/admin/daily-reports/send-records`,qiming 运营台可在日报详情中“记录发送结果”,但不接真实第三方发送通道。
|
||||
- 已吸收: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 运营台可在日报详情中“记录发送结果”,但不接真实第三方发送通道。
|
||||
- 缺口:没有正式 DailyReport 物理表、真实管理端发送通道、正式外部管理端日报页面和审批裁决回写闭环。
|
||||
- 建议:先稳定 Artifact/Event 派生日报交付模型,再根据管理端联调需要决定是否物化 DailyReport 表与发送记录表。
|
||||
|
||||
|
||||
Reference in New Issue
Block a user