fix(workbench): hold refresh feedback

This commit is contained in:
2026-09-24 12:57:16 +08:00
parent 0a53e665eb
commit 2191efab2f
2 changed files with 28 additions and 5 deletions
@@ -10,7 +10,7 @@ import {
XCircle XCircle
} from "lucide-react"; } from "lucide-react";
import { AnimatePresence, motion } from "motion/react"; import { AnimatePresence, motion } from "motion/react";
import { useCallback, useEffect, useMemo, useState } from "react"; import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { MAP_TOOL_PANEL_SURFACE_CLASS_NAME, showMapNotice } from "@/features/map/core"; import { MAP_TOOL_PANEL_SURFACE_CLASS_NAME, showMapNotice } from "@/features/map/core";
import { isGeneratedScheduledConditionSessionId } from "../data/scheduled-conditions"; import { isGeneratedScheduledConditionSessionId } from "../data/scheduled-conditions";
import type { import type {
@@ -62,6 +62,7 @@ const CONDITION_CONTENT_SURFACE_CLASS_NAME =
"surface-reading rounded-xl border border-slate-200/70"; "surface-reading rounded-xl border border-slate-200/70";
const CONDITION_CONTROL_SURFACE_CLASS_NAME = const CONDITION_CONTROL_SURFACE_CLASS_NAME =
"surface-control rounded-xl border border-slate-200/70"; "surface-control rounded-xl border border-slate-200/70";
const MINIMUM_REFRESH_FEEDBACK_MS = 3_000;
export type ScheduledConditionFeedPresentation = export type ScheduledConditionFeedPresentation =
| "desktop-dock" | "desktop-dock"
@@ -156,6 +157,7 @@ export function ScheduledConditionFeed({
const [scheduleSubmitting, setScheduleSubmitting] = useState(false); const [scheduleSubmitting, setScheduleSubmitting] = useState(false);
const [scheduleError, setScheduleError] = useState<string | null>(null); const [scheduleError, setScheduleError] = useState<string | null>(null);
const [refreshing, setRefreshing] = useState(false); const [refreshing, setRefreshing] = useState(false);
const refreshingRef = useRef(false);
const mobileSheet = presentation === "mobile-sheet"; const mobileSheet = presentation === "mobile-sheet";
const desktopDock = presentation === "desktop-dock"; const desktopDock = presentation === "desktop-dock";
const compactPresentation = mobileSheet || desktopDock; const compactPresentation = mobileSheet || desktopDock;
@@ -335,19 +337,32 @@ export function ScheduledConditionFeed({
} }
async function handleRefresh() { async function handleRefresh() {
if (!onRefresh || refreshing) return; if (!onRefresh || refreshingRef.current) return;
refreshingRef.current = true;
setRefreshing(true); setRefreshing(true);
const startedAt = Date.now();
let refreshError: unknown = null;
try { try {
await onRefresh(); await onRefresh();
} catch (error) { } catch (error) {
refreshError = error;
} finally {
const remainingFeedbackMs = MINIMUM_REFRESH_FEEDBACK_MS - (Date.now() - startedAt);
if (remainingFeedbackMs > 0) {
await new Promise((resolve) => window.setTimeout(resolve, remainingFeedbackMs));
}
refreshingRef.current = false;
setRefreshing(false);
}
if (refreshError) {
showMapNotice({ showMapNotice({
id: "scheduled-condition-refresh", id: "scheduled-condition-refresh",
tone: "error", tone: "error",
title: "工况任务刷新失败", title: "工况任务刷新失败",
message: error instanceof Error ? error.message : "暂时无法重新获取工况任务。" message: refreshError instanceof Error
? refreshError.message
: "暂时无法重新获取工况任务。"
}); });
} finally {
setRefreshing(false);
} }
} }
@@ -271,8 +271,16 @@ test("审批动作展示中文参数和证据,viewer 不可审批,冲突后
await expect(conditionPanel.getByRole("button", { name: /预约任务/ })).toContainText("后端"); await expect(conditionPanel.getByRole("button", { name: /预约任务/ })).toContainText("后端");
const conditionRefreshButton = conditionPanel.getByRole("button", { name: "刷新工况任务" }); const conditionRefreshButton = conditionPanel.getByRole("button", { name: "刷新工况任务" });
await expect(conditionRefreshButton).toBeVisible(); await expect(conditionRefreshButton).toBeVisible();
const refreshStartedAt = Date.now();
await conditionRefreshButton.click(); await conditionRefreshButton.click();
await expect.poll(() => snapshotRequests).toBe(2); await expect.poll(() => snapshotRequests).toBe(2);
const refreshingButton = conditionPanel.getByRole("button", { name: "正在刷新工况任务" });
await expect(refreshingButton).toBeDisabled();
await refreshingButton.evaluate((button: HTMLButtonElement) => button.click());
await page.waitForTimeout(500);
expect(snapshotRequests).toBe(2);
await expect(conditionRefreshButton).toBeEnabled({ timeout: 4_000 });
expect(Date.now() - refreshStartedAt).toBeGreaterThanOrEqual(2_900);
await conditionPanel.getByRole("button", { name: "配置定时流程" }).click(); await conditionPanel.getByRole("button", { name: "配置定时流程" }).click();
await conditionPanel.getByLabel("定时流程名称").fill("夜间阀门巡检"); await conditionPanel.getByLabel("定时流程名称").fill("夜间阀门巡检");
await conditionPanel.getByLabel("任务说明").fill("每十五分钟检查预约维修涉及的边界阀门。"); await conditionPanel.getByLabel("任务说明").fill("每十五分钟检查预约维修涉及的边界阀门。");