feat(client): show digital employee sync status
This commit is contained in:
@@ -71,6 +71,7 @@ interface QimingclawSnapshot {
|
|||||||
active: number;
|
active: number;
|
||||||
items: Array<{ id: string; title?: string; status?: string; engineType?: string; projectId?: string }>;
|
items: Array<{ id: string; title?: string; status?: string; engineType?: string; projectId?: string }>;
|
||||||
};
|
};
|
||||||
|
sync?: QimingclawSyncStatus | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const SKILLS: SkillSpec[] = [
|
const SKILLS: SkillSpec[] = [
|
||||||
@@ -283,7 +284,10 @@ function writeState(state: AdapterState): void {
|
|||||||
|
|
||||||
async function readQimingclawSnapshot(): Promise<QimingclawSnapshot | null> {
|
async function readQimingclawSnapshot(): Promise<QimingclawSnapshot | null> {
|
||||||
try {
|
try {
|
||||||
return await window.QimingClawBridge?.digital?.getSnapshot?.() ?? null;
|
const snapshot = await window.QimingClawBridge?.digital?.getSnapshot?.() ?? null;
|
||||||
|
if (!snapshot) return null;
|
||||||
|
const sync = await window.QimingClawBridge?.digital?.getSyncStatus?.().catch(() => null) ?? null;
|
||||||
|
return { ...snapshot, sync };
|
||||||
} catch {
|
} catch {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -357,6 +361,17 @@ function serviceLine(snapshot: QimingclawSnapshot | null, key: string, label: st
|
|||||||
return `${label}:未运行${service.error ? `,${service.error}` : ''}`;
|
return `${label}:未运行${service.error ? `,${service.error}` : ''}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function syncLine(snapshot: QimingclawSnapshot | null): string {
|
||||||
|
const sync = snapshot?.sync;
|
||||||
|
if (!sync) return '管理端同步:未连接';
|
||||||
|
if (!sync.enabled) return '管理端同步:已停用';
|
||||||
|
if (!sync.endpoint) return '管理端同步:未配置地址';
|
||||||
|
if (sync.syncing) return `管理端同步:同步中,待同步 ${sync.pending} 条`;
|
||||||
|
if (sync.failed > 0) return `管理端同步:${sync.failed} 条失败,待同步 ${sync.pending} 条`;
|
||||||
|
if (sync.pending > 0) return `管理端同步:待同步 ${sync.pending} 条`;
|
||||||
|
return sync.lastSyncAt ? `管理端同步:已同步,最近 ${sync.lastSyncAt}` : '管理端同步:等待本地数据';
|
||||||
|
}
|
||||||
|
|
||||||
function withRuntimePlan(plan: DebugPlan, snapshot: QimingclawSnapshot | null): DebugPlan {
|
function withRuntimePlan(plan: DebugPlan, snapshot: QimingclawSnapshot | null): DebugPlan {
|
||||||
return { ...plan, status: runtimeStatusForPlan(plan, snapshot) };
|
return { ...plan, status: runtimeStatusForPlan(plan, snapshot) };
|
||||||
}
|
}
|
||||||
@@ -511,7 +526,7 @@ function buildEvents(duties: DigitalEmployeeDuty[], confirmed: boolean, snapshot
|
|||||||
}
|
}
|
||||||
|
|
||||||
const selectedDuties = duties.filter((duty) => duty.selected);
|
const selectedDuties = duties.filter((duty) => duty.selected);
|
||||||
return selectedDuties.map((duty) => ({
|
const events = selectedDuties.map((duty) => ({
|
||||||
id: `event-${duty.id}`,
|
id: `event-${duty.id}`,
|
||||||
time: duty.status === 'running' ? '实时' : '待执行',
|
time: duty.status === 'running' ? '实时' : '待执行',
|
||||||
plan_title: duty.title,
|
plan_title: duty.title,
|
||||||
@@ -526,6 +541,23 @@ function buildEvents(duties: DigitalEmployeeDuty[], confirmed: boolean, snapshot
|
|||||||
updated_at: new Date().toISOString(),
|
updated_at: new Date().toISOString(),
|
||||||
conversation_id: duty.conversation_id,
|
conversation_id: duty.conversation_id,
|
||||||
}));
|
}));
|
||||||
|
const sync = snapshot?.sync;
|
||||||
|
if (sync && (sync.pending > 0 || sync.failed > 0 || sync.lastSyncAt)) {
|
||||||
|
events.push({
|
||||||
|
id: 'event-management-sync',
|
||||||
|
time: sync.syncing ? '实时' : '同步',
|
||||||
|
plan_title: '管理端联动',
|
||||||
|
task_title: '同步数字员工本地状态',
|
||||||
|
step_title: sync.failed > 0 ? '同步补偿' : 'outbox 推送',
|
||||||
|
detail: `${syncLine(snapshot)}${sync.lastSyncError ? `。错误:${sync.lastSyncError}` : ''}`,
|
||||||
|
status: sync.failed > 0 ? 'failed' : sync.syncing || sync.pending > 0 ? 'running' : 'completed',
|
||||||
|
status_label: sync.failed > 0 ? '异常' : sync.syncing || sync.pending > 0 ? '同步中' : '已同步',
|
||||||
|
status_tone: sync.failed > 0 ? 'danger' : sync.syncing || sync.pending > 0 ? 'running' : 'success',
|
||||||
|
updated_at: sync.lastSyncAt ?? new Date().toISOString(),
|
||||||
|
conversation_id: 'qimingclaw-management-sync',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return events;
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildExecutionSummaries(duties: DigitalEmployeeDuty[], events: DigitalEmployeeWorkEvent[]): DigitalEmployeeTaskExecutionSummary[] {
|
function buildExecutionSummaries(duties: DigitalEmployeeDuty[], events: DigitalEmployeeWorkEvent[]): DigitalEmployeeTaskExecutionSummary[] {
|
||||||
@@ -578,6 +610,7 @@ function buildWorkday(date: string, snapshot: QimingclawSnapshot | null): Digita
|
|||||||
const generatedAt = state.reportGeneratedAtByDate[date] ?? null;
|
const generatedAt = state.reportGeneratedAtByDate[date] ?? null;
|
||||||
const selectedCount = duties.filter((duty) => duty.selected).length;
|
const selectedCount = duties.filter((duty) => duty.selected).length;
|
||||||
const runningCount = events.filter((event) => event.status === 'running').length;
|
const runningCount = events.filter((event) => event.status === 'running').length;
|
||||||
|
const sync = snapshot?.sync;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
source: 'live',
|
source: 'live',
|
||||||
@@ -614,7 +647,8 @@ function buildWorkday(date: string, snapshot: QimingclawSnapshot | null): Digita
|
|||||||
{ label: '已选任务', value: String(selectedCount) },
|
{ label: '已选任务', value: String(selectedCount) },
|
||||||
{ label: '运行记录', value: String(events.length) },
|
{ label: '运行记录', value: String(events.length) },
|
||||||
{ label: '执行中', value: String(runningCount) },
|
{ label: '执行中', value: String(runningCount) },
|
||||||
{ label: '异常', value: '0' },
|
{ label: '待同步', value: String(sync?.pending ?? 0) },
|
||||||
|
{ label: '同步异常', value: String(sync?.failed ?? 0) },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
duties,
|
duties,
|
||||||
@@ -631,6 +665,7 @@ function buildWorkday(date: string, snapshot: QimingclawSnapshot | null): Digita
|
|||||||
serviceLine(snapshot, 'agent', 'Agent'),
|
serviceLine(snapshot, 'agent', 'Agent'),
|
||||||
serviceLine(snapshot, 'mcp', 'MCP'),
|
serviceLine(snapshot, 'mcp', 'MCP'),
|
||||||
serviceLine(snapshot, 'computerServer', 'Computer Server'),
|
serviceLine(snapshot, 'computerServer', 'Computer Server'),
|
||||||
|
syncLine(snapshot),
|
||||||
`活跃会话:${snapshot?.sessions.active ?? 0} / ${snapshot?.sessions.total ?? 0}`,
|
`活跃会话:${snapshot?.sessions.active ?? 0} / ${snapshot?.sessions.total ?? 0}`,
|
||||||
],
|
],
|
||||||
artifacts: [
|
artifacts: [
|
||||||
@@ -647,7 +682,7 @@ function buildWorkday(date: string, snapshot: QimingclawSnapshot | null): Digita
|
|||||||
model: 'qimingclaw-adapter',
|
model: 'qimingclaw-adapter',
|
||||||
source: 'qimingclaw',
|
source: 'qimingclaw',
|
||||||
summary: generatedAt
|
summary: generatedAt
|
||||||
? '今日已完成数字员工页面到 qimingclaw adapter 的接入,并读取了 qimingclaw 服务状态。'
|
? `今日已完成数字员工页面到 qimingclaw adapter 的接入,并读取了 qimingclaw 服务状态。${syncLine(snapshot)}。`
|
||||||
: '日报将在生成后汇总任务选择、运行明细和后续接入建议。',
|
: '日报将在生成后汇总任务选择、运行明细和后续接入建议。',
|
||||||
totals: {
|
totals: {
|
||||||
task_count: selectedCount,
|
task_count: selectedCount,
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -13,7 +13,7 @@
|
|||||||
console.warn("[qimingclaw] digital employee auth bootstrap skipped", error);
|
console.warn("[qimingclaw] digital employee auth bootstrap skipped", error);
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<script type="module" crossorigin src="./assets/index-DcEd9LJg.js"></script>
|
<script type="module" crossorigin src="./assets/index-CCHg55lx.js"></script>
|
||||||
<link rel="stylesheet" crossorigin href="./assets/index-DqV9Vw1H.css">
|
<link rel="stylesheet" crossorigin href="./assets/index-DqV9Vw1H.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|||||||
Reference in New Issue
Block a user