吸收数字员工审批冲突与产物业务闭环

This commit is contained in:
baiyanyun
2026-06-12 16:29:01 +08:00
parent fffa0ebe50
commit 81d2797035
26 changed files with 2963 additions and 241 deletions

View File

@@ -392,7 +392,9 @@ function checkDigitalApprovalWorkflowSync() {
[stateService, "applyApprovalWorkflowDecision", "approval workflow decision advancer"],
[stateService, "applyApprovalWorkflowAction", "approval workflow action updater"],
[stateService, "upsertDigitalEmployeeApprovalFromRemote", "remote approval update upsert helper"],
[stateService, "resolveDigitalEmployeeApprovalConflict", "approval conflict resolution helper"],
[stateService, "approval_conflict_detected", "approval conflict runtime event"],
[stateService, "approval_conflict_resolved", "approval conflict resolved event"],
[stateService, "terminal_status_mismatch", "approval terminal conflict reason"],
[stateService, "decision_history", "approval workflow decision history field"],
[syncService, "pullDigitalEmployeeApprovalUpdates", "remote approval updates pull service"],
@@ -403,18 +405,25 @@ function checkDigitalApprovalWorkflowSync() {
[syncService, "approvalUpdatesEndpoint", "approval updates endpoint config"],
[syncService, "approvalDecisionsEndpoint", "approval decisions endpoint config"],
[syncService, "approvalSyncBusinessView", "approval sync business view"],
[syncService, "approvalConflictResolutionBusinessView", "approval conflict resolution business view"],
[syncService, "workflow_id", "approval workflow sync business field"],
[ipcHandlers, "digitalEmployee:pullApprovalUpdates", "IPC approval updates pull handler"],
[ipcHandlers, "digitalEmployee:submitApprovalDecision", "IPC approval decision submit handler"],
[ipcHandlers, "digitalEmployee:resolveApprovalConflict", "IPC approval conflict resolution handler"],
[preload, "pullApprovalUpdates", "preload approval updates bridge"],
[preload, "submitApprovalDecision", "preload approval decision bridge"],
[preload, "resolveApprovalConflict", "preload approval conflict resolution bridge"],
[adapter, "pullApprovalUpdates", "adapter approval updates bridge declaration"],
[adapter, "submitApprovalDecision", "adapter approval decision bridge declaration"],
[adapter, "resolveApprovalConflict", "adapter approval conflict resolution bridge declaration"],
[adapter, "/api/approval/updates/pull", "adapter approval updates pull endpoint"],
[adapter, "conflict\\/resolve", "adapter approval conflict resolution endpoint"],
[adapter, "approvalWorkflowSummary", "adapter approval workflow summary"],
[adapter, "approvalConflictSummary", "adapter approval conflict summary"],
[adapter, "approval_conflict_active", "approval conflict business field"],
[adapter, "approval_conflict_resolution", "approval conflict resolution business field"],
[api, "pullApprovalUpdates", "embedded approval updates API"],
[api, "resolveApprovalConflict", "embedded approval conflict resolution API"],
[types, "conflict?:", "approval decision conflict type field"],
[types, "current_step_label", "approval decision current step type field"],
[types, "approval_step_count", "approval decision step count type field"],
@@ -422,6 +431,9 @@ function checkDigitalApprovalWorkflowSync() {
[commandDeck, "审批更新", "home approval updates pull button"],
[commandDeck, "跨端冲突", "home approval conflict badge"],
[commandDeck, "冲突保护", "home approval conflict protection copy"],
[commandDeck, "保留本地", "home approval keep local conflict action"],
[commandDeck, "采纳管理端", "home approval accept remote conflict action"],
[commandDeck, "标记已复核", "home approval mark reviewed conflict action"],
];
const missing = requiredSnippets
.filter(([content, snippet]) => !content.includes(snippet))
@@ -740,6 +752,146 @@ function checkDigitalRouteDecisionPolicy() {
console.log("[DigitalEmployeeCheck] route decision policy hooks OK");
}
function checkDigitalDailyReportDelivery() {
console.log("\n[DigitalEmployeeCheck] Verify daily report delivery hooks");
const adapterPath = path.join(packageRoot, "embedded", "sgrobot-digital", "src", "lib", "qimingclawAdapter.ts");
const apiPath = path.join(packageRoot, "embedded", "sgrobot-digital", "src", "lib", "api.ts");
const typesPath = path.join(packageRoot, "embedded", "sgrobot-digital", "src", "types", "api.ts");
const pagePath = path.join(packageRoot, "embedded", "sgrobot-digital", "src", "pages", "digital", "DailyReport.tsx");
const stateServicePath = path.join(packageRoot, "src", "main", "services", "digitalEmployee", "stateService.ts");
const syncServicePath = path.join(packageRoot, "src", "main", "services", "digitalEmployee", "syncService.ts");
const ipcHandlersPath = path.join(packageRoot, "src", "main", "ipc", "digitalEmployeeHandlers.ts");
const preloadPath = path.join(packageRoot, "src", "preload", "webviewPerfBridge.ts");
const adapter = fs.readFileSync(adapterPath, "utf8");
const api = fs.readFileSync(apiPath, "utf8");
const types = fs.readFileSync(typesPath, "utf8");
const page = fs.readFileSync(pagePath, "utf8");
const stateService = fs.readFileSync(stateServicePath, "utf8");
const syncService = fs.readFileSync(syncServicePath, "utf8");
const ipcHandlers = fs.readFileSync(ipcHandlersPath, "utf8");
const preload = fs.readFileSync(preloadPath, "utf8");
const requiredSnippets = [
[stateService, "htmlArtifactId", "daily report HTML artifact result"],
[stateService, "pdfArtifactId", "daily report PDF artifact result"],
[stateService, "recordDigitalEmployeeDailyReportDelivery", "daily report delivery recorder"],
[stateService, "daily_report_send_recorded", "daily report send event"],
[stateService, "daily_report_confirmed", "daily report confirm event"],
[stateService, "daily_report_approval_requested", "daily report approval event"],
[syncService, "dailyReportEventBusinessView", "daily report sync business view"],
[syncService, "daily_report", "daily report sync category"],
[ipcHandlers, "digitalEmployee:recordDailyReportDelivery", "IPC daily report delivery handler"],
[preload, "recordDailyReportDelivery", "preload daily report delivery bridge"],
[adapter, "/api/digital-employee/daily-reports/delivery", "adapter daily report delivery endpoint"],
[adapter, "buildDailyReportHtml", "adapter HTML report builder"],
[adapter, "buildDailyReportPdfBase64", "adapter PDF report builder"],
[api, "recordDailyReportDelivery", "embedded daily report delivery API"],
[types, "html_artifact_id", "daily report HTML artifact type"],
[types, "pdf_artifact_id", "daily report PDF artifact type"],
[page, "导出 HTML", "daily report HTML export UI"],
[page, "导出 PDF", "daily report PDF export UI"],
[page, "记录发送", "daily report send UI"],
[page, "确认回执", "daily report confirm UI"],
[page, "发起审批", "daily report approval UI"],
];
const missing = requiredSnippets
.filter(([content, snippet]) => !content.includes(snippet))
.map(([, , label]) => label);
if (missing.length > 0) {
throw new Error(`Missing daily report delivery hooks: ${missing.join(", ")}`);
}
console.log("[DigitalEmployeeCheck] daily report delivery hooks OK");
}
function checkDigitalArtifactCleanup() {
console.log("\n[DigitalEmployeeCheck] Verify artifact cleanup execution hooks");
const adapterPath = path.join(packageRoot, "embedded", "sgrobot-digital", "src", "lib", "qimingclawAdapter.ts");
const apiPath = path.join(packageRoot, "embedded", "sgrobot-digital", "src", "lib", "api.ts");
const typesPath = path.join(packageRoot, "embedded", "sgrobot-digital", "src", "types", "api.ts");
const pagePath = path.join(packageRoot, "embedded", "sgrobot-digital", "src", "pages", "digital", "DailyReport.tsx");
const businessViewPath = path.join(packageRoot, "embedded", "sgrobot-digital", "src", "pages", "digital", "BusinessView.tsx");
const stateServicePath = path.join(packageRoot, "src", "main", "services", "digitalEmployee", "stateService.ts");
const artifactServicePath = path.join(packageRoot, "src", "main", "services", "digitalEmployee", "artifactAccessService.ts");
const syncServicePath = path.join(packageRoot, "src", "main", "services", "digitalEmployee", "syncService.ts");
const ipcHandlersPath = path.join(packageRoot, "src", "main", "ipc", "digitalEmployeeHandlers.ts");
const preloadPath = path.join(packageRoot, "src", "preload", "webviewPerfBridge.ts");
const adapter = fs.readFileSync(adapterPath, "utf8");
const api = fs.readFileSync(apiPath, "utf8");
const types = fs.readFileSync(typesPath, "utf8");
const page = fs.readFileSync(pagePath, "utf8");
const businessView = fs.readFileSync(businessViewPath, "utf8");
const stateService = fs.readFileSync(stateServicePath, "utf8");
const artifactService = fs.readFileSync(artifactServicePath, "utf8");
const syncService = fs.readFileSync(syncServicePath, "utf8");
const ipcHandlers = fs.readFileSync(ipcHandlersPath, "utf8");
const preload = fs.readFileSync(preloadPath, "utf8");
const requiredSnippets = [
[artifactService, "cleanupDigitalEmployeeArtifact", "artifact cleanup service"],
[stateService, "recordDigitalEmployeeArtifactCleanup", "artifact cleanup event recorder"],
[stateService, "artifact_cleanup_executed", "artifact cleanup executed event"],
[stateService, "artifact_cleanup_rejected", "artifact cleanup rejected event"],
[syncService, "cleanup_status", "artifact cleanup sync business field"],
[ipcHandlers, "digitalEmployee:cleanupArtifact", "IPC artifact cleanup handler"],
[preload, "cleanupArtifact", "preload artifact cleanup bridge"],
[adapter, "/cleanup", "adapter artifact cleanup endpoint"],
[adapter, "artifactCleanupRows", "adapter artifact cleanup projection"],
[api, "cleanupArtifact", "embedded artifact cleanup API"],
[types, "cleanup_status", "artifact cleanup type field"],
[page, "清理文件", "daily report cleanup UI"],
[businessView, "cleanup_status", "business view cleanup summary"],
];
const missing = requiredSnippets
.filter(([content, snippet]) => !content.includes(snippet))
.map(([, , label]) => label);
if (missing.length > 0) {
throw new Error(`Missing artifact cleanup execution hooks: ${missing.join(", ")}`);
}
console.log("[DigitalEmployeeCheck] artifact cleanup execution hooks OK");
}
function checkDigitalBusinessViewUi() {
console.log("\n[DigitalEmployeeCheck] Verify management business view UI hooks");
const apiPath = path.join(packageRoot, "embedded", "sgrobot-digital", "src", "lib", "api.ts");
const typesPath = path.join(packageRoot, "embedded", "sgrobot-digital", "src", "types", "api.ts");
const mainPath = path.join(packageRoot, "embedded", "sgrobot-digital", "src", "main.tsx");
const shellPath = path.join(packageRoot, "embedded", "sgrobot-digital", "src", "pages", "digital", "DigitalEmployeeShell.tsx");
const navPath = path.join(packageRoot, "embedded", "sgrobot-digital", "src", "pages", "digital", "navigation.ts");
const businessViewPath = path.join(packageRoot, "embedded", "sgrobot-digital", "src", "pages", "digital", "BusinessView.tsx");
if (!fs.existsSync(businessViewPath)) {
throw new Error("Missing management business view UI: BusinessView.tsx");
}
const api = fs.readFileSync(apiPath, "utf8");
const types = fs.readFileSync(typesPath, "utf8");
const main = fs.readFileSync(mainPath, "utf8");
const shell = fs.readFileSync(shellPath, "utf8");
const nav = fs.readFileSync(navPath, "utf8");
const businessView = fs.readFileSync(businessViewPath, "utf8");
const requiredSnippets = [
[api, "getDigitalEmployeeBusinessView", "embedded business view API helper"],
[api, "/api/digital-employee/plans", "embedded business view plans endpoint"],
[api, "/api/digital-employee/approvals", "embedded business view approvals endpoint"],
[types, "DigitalEmployeeBusinessViewKind", "business view kind type"],
[types, "DigitalEmployeeBusinessViewRow", "business view row type"],
[types, "DigitalEmployeeBusinessViewQuery", "business view query type"],
[main, "path=\"/digital/*\"", "business view deep route"],
[nav, "business", "business navigation tab"],
[nav, "businessKind", "business navigation kind target"],
[nav, "entityId", "business navigation entity target"],
[shell, "BusinessView", "business view shell component"],
[shell, "业务视图", "business view tab label"],
[businessView, "getDigitalEmployeeBusinessView", "business view data loader"],
[businessView, "计划", "business view plans segment"],
[businessView, "审批", "business view approvals segment"],
[businessView, "详情", "business view detail panel"],
];
const missing = requiredSnippets
.filter(([content, snippet]) => !content.includes(snippet))
.map(([, , label]) => label);
if (missing.length > 0) {
throw new Error(`Missing management business view UI hooks: ${missing.join(", ")}`);
}
console.log("[DigitalEmployeeCheck] management business view UI hooks OK");
}
function checkLocalDatabaseSchema() {
console.log("\n[DigitalEmployeeCheck] Verify local SQLite digital schema");
const dbPath = path.join(os.homedir(), ".qimingclaw", "qimingclaw.db");
@@ -790,6 +942,9 @@ function main() {
checkDigitalSkillRemotePolicy();
checkDigitalRiskApprovalPolicy();
checkDigitalRouteDecisionPolicy();
checkDigitalDailyReportDelivery();
checkDigitalArtifactCleanup();
checkDigitalBusinessViewUi();
checkLocalDatabaseSchema();
console.log("\n[DigitalEmployeeCheck] All checks passed");
} catch (error) {