feat(client): remove demo mission fallback
This commit is contained in:
@@ -1,11 +1,4 @@
|
|||||||
import { useEffect, useMemo, useState } from 'react';
|
import { useEffect, useMemo, useState } from 'react';
|
||||||
import {
|
|
||||||
buildDemoFlowEvents,
|
|
||||||
buildDemoPlanMessages,
|
|
||||||
buildDemoRuns,
|
|
||||||
buildDemoTasks,
|
|
||||||
getDemoMissions,
|
|
||||||
} from '@/pages/digital/demoScenario';
|
|
||||||
import {
|
import {
|
||||||
displayBackendMessage,
|
displayBackendMessage,
|
||||||
displayBusinessText,
|
displayBusinessText,
|
||||||
@@ -310,25 +303,20 @@ export default function FlowDetailPanel({ mission, onClose }: FlowDetailPanelPro
|
|||||||
getPlanMessages(planId),
|
getPlanMessages(planId),
|
||||||
]).then(([tasksResult, flowResult, messagesResult]) => {
|
]).then(([tasksResult, flowResult, messagesResult]) => {
|
||||||
if (cancelled) return;
|
if (cancelled) return;
|
||||||
const demoMission = getDemoMissions().find((item) => item.id === planId);
|
|
||||||
const fallbackTasks = demoMission ? buildDemoTasks([demoMission]) : [];
|
|
||||||
const fallbackRuns = fallbackTasks.length > 0 ? buildDemoRuns(fallbackTasks) : [];
|
|
||||||
if (tasksResult.status === 'fulfilled') {
|
if (tasksResult.status === 'fulfilled') {
|
||||||
setTasks(tasksResult.value.tasks && tasksResult.value.tasks.length > 0 ? tasksResult.value.tasks : fallbackTasks);
|
setTasks(tasksResult.value.tasks ?? []);
|
||||||
setRuns(tasksResult.value.runs && tasksResult.value.runs.length > 0 ? tasksResult.value.runs : fallbackRuns);
|
setRuns(tasksResult.value.runs ?? []);
|
||||||
} else {
|
} else {
|
||||||
setTasks(fallbackTasks);
|
setTasks([]);
|
||||||
setRuns(fallbackRuns);
|
setRuns([]);
|
||||||
}
|
}
|
||||||
if (flowResult.status === 'fulfilled' && flowResult.value?.events && flowResult.value.events.length > 0) {
|
if (flowResult.status === 'fulfilled' && flowResult.value?.events && flowResult.value.events.length > 0) {
|
||||||
setFlow(flowResult.value);
|
setFlow(flowResult.value);
|
||||||
} else {
|
} else {
|
||||||
setFlow(demoMission ? { events: buildDemoFlowEvents(demoMission) } as FlowResponse : null);
|
setFlow(null);
|
||||||
}
|
}
|
||||||
if (messagesResult.status === 'fulfilled' && messagesResult.value.messages.length > 0) {
|
if (messagesResult.status === 'fulfilled' && messagesResult.value.messages.length > 0) {
|
||||||
setSessionMessages(messagesResult.value.messages);
|
setSessionMessages(messagesResult.value.messages);
|
||||||
} else if (demoMission) {
|
|
||||||
setSessionMessages(buildDemoPlanMessages(demoMission));
|
|
||||||
} else {
|
} else {
|
||||||
setSessionMessages([]);
|
setSessionMessages([]);
|
||||||
}
|
}
|
||||||
@@ -361,18 +349,11 @@ export default function FlowDetailPanel({ mission, onClose }: FlowDetailPanelPro
|
|||||||
if (data.messages && data.messages.length > 0) {
|
if (data.messages && data.messages.length > 0) {
|
||||||
setSessionMessages(data.messages);
|
setSessionMessages(data.messages);
|
||||||
} else {
|
} else {
|
||||||
const demoMission = getDemoMissions().find((item) => item.id === planId);
|
setSessionMessages([]);
|
||||||
setSessionMessages(demoMission ? buildDemoPlanMessages(demoMission) : []);
|
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
const demoMission = getDemoMissions().find((item) => item.id === planId);
|
setSessionMessages([]);
|
||||||
if (demoMission) {
|
setSessionError(err instanceof Error ? err.message : '读取会话失败');
|
||||||
setSessionMessages(buildDemoPlanMessages(demoMission));
|
|
||||||
setSessionError(null);
|
|
||||||
} else {
|
|
||||||
setSessionMessages([]);
|
|
||||||
setSessionError(err instanceof Error ? err.message : '读取会话失败');
|
|
||||||
}
|
|
||||||
} finally {
|
} finally {
|
||||||
setSessionLoading(false);
|
setSessionLoading(false);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,11 +7,6 @@ import { adaptMissions, type Mission } from '@/lib/consoleDataAdapter';
|
|||||||
import { getDebugPlans, governanceCommand, searchDebugPlans } from '@/lib/api';
|
import { getDebugPlans, governanceCommand, searchDebugPlans } from '@/lib/api';
|
||||||
import type { GovernanceCommandKind, GovernanceCommandResponse } from '@/types/api';
|
import type { GovernanceCommandKind, GovernanceCommandResponse } from '@/types/api';
|
||||||
import { t } from '@/lib/i18n';
|
import { t } from '@/lib/i18n';
|
||||||
import {
|
|
||||||
completeDemoMissionOnce,
|
|
||||||
getDemoMissions,
|
|
||||||
runDemoMissionOnce,
|
|
||||||
} from './demoScenario';
|
|
||||||
import { domSafeId } from './navigation';
|
import { domSafeId } from './navigation';
|
||||||
|
|
||||||
const REQUIRED_MISSION_IDS = [
|
const REQUIRED_MISSION_IDS = [
|
||||||
@@ -275,7 +270,6 @@ export default function MissionCenter({
|
|||||||
const [showAllDates, setShowAllDates] = useState(false);
|
const [showAllDates, setShowAllDates] = useState(false);
|
||||||
const [runningMissionId, setRunningMissionId] = useState<string | null>(null);
|
const [runningMissionId, setRunningMissionId] = useState<string | null>(null);
|
||||||
const [runningAll, setRunningAll] = useState(false);
|
const [runningAll, setRunningAll] = useState(false);
|
||||||
const [demoMode, setDemoMode] = useState(false);
|
|
||||||
const [actionError, setActionError] = useState<string | null>(null);
|
const [actionError, setActionError] = useState<string | null>(null);
|
||||||
const [recentMissionId, setRecentMissionId] = useState<string | null>(null);
|
const [recentMissionId, setRecentMissionId] = useState<string | null>(null);
|
||||||
const [missionNotice, setMissionNotice] = useState<MissionNotice | null>(null);
|
const [missionNotice, setMissionNotice] = useState<MissionNotice | null>(null);
|
||||||
@@ -324,23 +318,17 @@ export default function MissionCenter({
|
|||||||
const orderedPlans = [...recentPlans, ...requiredPlans];
|
const orderedPlans = [...recentPlans, ...requiredPlans];
|
||||||
if (orderedPlans.length > 0) {
|
if (orderedPlans.length > 0) {
|
||||||
const nextMissions = adaptMissions(orderedPlans);
|
const nextMissions = adaptMissions(orderedPlans);
|
||||||
setDemoMode(false);
|
|
||||||
setMissions(nextMissions);
|
setMissions(nextMissions);
|
||||||
return nextMissions;
|
return nextMissions;
|
||||||
} else {
|
|
||||||
const demoMissions = getDemoMissions();
|
|
||||||
setDemoMode(true);
|
|
||||||
setMissions(demoMissions);
|
|
||||||
return demoMissions;
|
|
||||||
}
|
}
|
||||||
|
setMissions([]);
|
||||||
|
return [];
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (!mountedRef.current) return [];
|
if (!mountedRef.current) return [];
|
||||||
console.error('[MissionCenter] fetch failed:', err);
|
console.error('[MissionCenter] fetch failed:', err);
|
||||||
const demoMissions = getDemoMissions();
|
setMissions([]);
|
||||||
setDemoMode(true);
|
setError(true);
|
||||||
setMissions(demoMissions);
|
return [];
|
||||||
setError(false);
|
|
||||||
return demoMissions;
|
|
||||||
} finally {
|
} finally {
|
||||||
if (mountedRef.current) setLoading(false);
|
if (mountedRef.current) setLoading(false);
|
||||||
}
|
}
|
||||||
@@ -393,23 +381,9 @@ export default function MissionCenter({
|
|||||||
setRunningMissionId(mission.id);
|
setRunningMissionId(mission.id);
|
||||||
setError(false);
|
setError(false);
|
||||||
setActionError(null);
|
setActionError(null);
|
||||||
if (demoMode || !mission.sourceIds.planId) {
|
if (!mission.sourceIds.planId) {
|
||||||
setMissions((current) => runDemoMissionOnce(current, mission.id));
|
setActionError('当前任务没有 qimingclaw Plan 记录,无法委托执行。');
|
||||||
setSelected((current) => {
|
setRunningMissionId(null);
|
||||||
if (current?.id !== mission.id) return current;
|
|
||||||
const next = runDemoMissionOnce([current], mission.id);
|
|
||||||
return next[0] ?? current;
|
|
||||||
});
|
|
||||||
window.setTimeout(() => {
|
|
||||||
if (!mountedRef.current) return;
|
|
||||||
setMissions((current) => completeDemoMissionOnce(current, mission.id));
|
|
||||||
setSelected((current) => {
|
|
||||||
if (current?.id !== mission.id) return current;
|
|
||||||
const next = completeDemoMissionOnce([current], mission.id);
|
|
||||||
return next[0] ?? current;
|
|
||||||
});
|
|
||||||
setRunningMissionId(null);
|
|
||||||
}, 1200);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
@@ -450,14 +424,15 @@ export default function MissionCenter({
|
|||||||
} finally {
|
} finally {
|
||||||
setRunningMissionId(null);
|
setRunningMissionId(null);
|
||||||
}
|
}
|
||||||
}, [demoMode, fetchMissions, focusMission]);
|
}, [fetchMissions, focusMission]);
|
||||||
|
|
||||||
const restartMission = useCallback(async (mission: Mission) => {
|
const restartMission = useCallback(async (mission: Mission) => {
|
||||||
setRunningMissionId(mission.id);
|
setRunningMissionId(mission.id);
|
||||||
setError(false);
|
setError(false);
|
||||||
setActionError(null);
|
setActionError(null);
|
||||||
if (demoMode || !mission.sourceIds.planId) {
|
if (!mission.sourceIds.planId) {
|
||||||
await runMission(mission);
|
setActionError('当前任务没有 qimingclaw Plan 记录,无法重新执行。');
|
||||||
|
setRunningMissionId(null);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
@@ -489,7 +464,7 @@ export default function MissionCenter({
|
|||||||
} finally {
|
} finally {
|
||||||
setRunningMissionId(null);
|
setRunningMissionId(null);
|
||||||
}
|
}
|
||||||
}, [demoMode, fetchMissions, focusMission, runMission]);
|
}, [fetchMissions, focusMission]);
|
||||||
|
|
||||||
const selectedDate = dateFilter || todayDateKey();
|
const selectedDate = dateFilter || todayDateKey();
|
||||||
const filteredByDate = dedupeMissionsForDate(
|
const filteredByDate = dedupeMissionsForDate(
|
||||||
@@ -506,27 +481,6 @@ export default function MissionCenter({
|
|||||||
if (runnableMissions.length === 0) return;
|
if (runnableMissions.length === 0) return;
|
||||||
setRunningAll(true);
|
setRunningAll(true);
|
||||||
setError(false);
|
setError(false);
|
||||||
if (demoMode) {
|
|
||||||
let delay = 0;
|
|
||||||
for (const mission of runnableMissions.slice(0, 4)) {
|
|
||||||
window.setTimeout(() => {
|
|
||||||
if (!mountedRef.current) return;
|
|
||||||
setRunningMissionId(mission.id);
|
|
||||||
setMissions((current) => runDemoMissionOnce(current, mission.id));
|
|
||||||
}, delay);
|
|
||||||
delay += 400;
|
|
||||||
window.setTimeout(() => {
|
|
||||||
if (!mountedRef.current) return;
|
|
||||||
setMissions((current) => completeDemoMissionOnce(current, mission.id));
|
|
||||||
}, delay + 900);
|
|
||||||
}
|
|
||||||
window.setTimeout(() => {
|
|
||||||
if (!mountedRef.current) return;
|
|
||||||
setRunningMissionId(null);
|
|
||||||
setRunningAll(false);
|
|
||||||
}, delay + 1200);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
try {
|
||||||
for (const mission of runnableMissions) {
|
for (const mission of runnableMissions) {
|
||||||
setRunningMissionId(mission.id);
|
setRunningMissionId(mission.id);
|
||||||
@@ -542,7 +496,7 @@ export default function MissionCenter({
|
|||||||
setRunningMissionId(null);
|
setRunningMissionId(null);
|
||||||
setRunningAll(false);
|
setRunningAll(false);
|
||||||
}
|
}
|
||||||
}, [demoMode, fetchMissions, runnableMissions]);
|
}, [fetchMissions, runnableMissions]);
|
||||||
|
|
||||||
const filtered = filter === 'all'
|
const filtered = filter === 'all'
|
||||||
? filteredByDate
|
? filteredByDate
|
||||||
@@ -587,11 +541,6 @@ export default function MissionCenter({
|
|||||||
<button onClick={fetchMissions} className="de-btn-secondary de-btn-sm">{t('console.action.refresh')}</button>
|
<button onClick={fetchMissions} className="de-btn-secondary de-btn-sm">{t('console.action.refresh')}</button>
|
||||||
</CardTitleBar>
|
</CardTitleBar>
|
||||||
<div className="de-card-body">
|
<div className="de-card-body">
|
||||||
{demoMode && (
|
|
||||||
<div className="de-schedule-result de-schedule-result--success" style={{ marginBottom: 12 }}>
|
|
||||||
当前没有加载到 qimingclaw 任务记录,页面暂时展示本地示例数据。
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{actionError && (
|
{actionError && (
|
||||||
<div className="de-schedule-result de-schedule-result--error" style={{ marginBottom: 12 }}>
|
<div className="de-schedule-result de-schedule-result--error" style={{ marginBottom: 12 }}>
|
||||||
{actionError}
|
{actionError}
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -16,7 +16,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-BBxsxEp7.js"></script>
|
<script type="module" crossorigin src="./assets/index-B-gnIbwp.js"></script>
|
||||||
<link rel="stylesheet" crossorigin href="./assets/index-CKIQdvco.css">
|
<link rel="stylesheet" crossorigin href="./assets/index-CKIQdvco.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|||||||
@@ -453,7 +453,7 @@ crates/agent-electron-client/src/preload/webviewPerfBridge.ts
|
|||||||
- `digital_approvals` 会投射为数字员工 workday 的 `decisions`;首页待解决事项按钮会调用本地 `decide_approval` action,把处理结果写入 SQLite UI state,回写正式 approval 状态并进入 approval outbox,同时生成 `digital_workday_decide_approval` runtime event。同步失败 review 只保留在 dashboard/同步诊断中,不作为可审批 workday decision。
|
- `digital_approvals` 会投射为数字员工 workday 的 `decisions`;首页待解决事项按钮会调用本地 `decide_approval` action,把处理结果写入 SQLite UI state,回写正式 approval 状态并进入 approval outbox,同时生成 `digital_workday_decide_approval` runtime event。同步失败 review 只保留在 dashboard/同步诊断中,不作为可审批 workday decision。
|
||||||
- 任务中心的 `/api/governance/command` 已接入 qimingclaw 兼容层:`create_plan`、`submit_plan`、`approve_plan`、`activate_plan`、`create_schedule`、`run_schedule_now` 等命令返回本地可解释结果,其中激活/立即运行会映射到 adapter 的 dispatch/workday 状态。
|
- 任务中心的 `/api/governance/command` 已接入 qimingclaw 兼容层:`create_plan`、`submit_plan`、`approve_plan`、`activate_plan`、`create_schedule`、`run_schedule_now` 等命令返回本地可解释结果,其中激活/立即运行会映射到 adapter 的 dispatch/workday 状态。
|
||||||
- 日报下载不再打开 sgRobot 风格 PDF 后端直链;生成日报后会基于当前 qimingclaw workday 投影在浏览器内导出本地文本日报。
|
- 日报下载不再打开 sgRobot 风格 PDF 后端直链;生成日报后会基于当前 qimingclaw workday 投影在浏览器内导出本地文本日报。
|
||||||
- 任务中心在加载到 qimingclaw 真实计划时不再混入示例 supplement;只有没有任何真实计划或请求失败时才使用 qimingclaw 客户端职责语义的本地示例兜底。
|
- 任务中心和委托详情不再使用 sgRobot demo mission fallback;没有 qimingclaw Plan / Task / Run / Event 时展示真实空态或错误态,避免示例任务冒充本地任务记录。
|
||||||
- 嵌入页 localStorage/sessionStorage 的运行态 key 已切换到 `qimingclaw:*` / `qimingclaw_digital_*` 命名;旧 sgRobot/zeroclaw key 仅作为迁移读取或清理,不再作为新状态写入目标。
|
- 嵌入页 localStorage/sessionStorage 的运行态 key 已切换到 `qimingclaw:*` / `qimingclaw_digital_*` 命名;旧 sgRobot/zeroclaw key 仅作为迁移读取或清理,不再作为新状态写入目标。
|
||||||
- 数字员工本地表不另建 sgRobot SQLite;统一建在 qimingclaw 主进程数据库 `~/.qimingclaw/qimingclaw.db` 内,作为 qimingclaw 客户端本地事实缓存与 outbox;表结构在主进程启动时创建,数字员工 runtime/sync 服务读写前也会按需自修复执行 `CREATE TABLE IF NOT EXISTS`。
|
- 数字员工本地表不另建 sgRobot SQLite;统一建在 qimingclaw 主进程数据库 `~/.qimingclaw/qimingclaw.db` 内,作为 qimingclaw 客户端本地事实缓存与 outbox;表结构在主进程启动时创建,数字员工 runtime/sync 服务读写前也会按需自修复执行 `CREATE TABLE IF NOT EXISTS`。
|
||||||
- 同步状态通过 bridge 返回最近失败 outbox 明细,首页可直接看到实体类型、outbox ID、操作类型、重试次数、失败时间和下次自动重试时间。
|
- 同步状态通过 bridge 返回最近失败 outbox 明细,首页可直接看到实体类型、outbox ID、操作类型、重试次数、失败时间和下次自动重试时间。
|
||||||
|
|||||||
Reference in New Issue
Block a user