feat: 新建流程首次进入展示引导提示,5 秒后自动关闭

This commit is contained in:
yu 2026-10-28 16:37:25 +08:00
parent 3a1c176f4d
commit 37f2c8977b
2 changed files with 88 additions and 1 deletions

View File

@ -1,5 +1,5 @@
import { useCallback, useEffect, useState } from "react";
import { ArrowLeft, Check, CircleAlert, CirclePlay, Loader2, Redo2, Save, Square, Undo2, X } from "lucide-react";
import { ArrowLeft, Check, CircleAlert, CirclePlay, Lightbulb, Loader2, Redo2, Save, Square, Undo2, X } from "lucide-react";
import type { Catalog } from "@shared/types";
import { useEditorStore } from "../store/editorStore";
import { useRunStore } from "../store/runStore";
@ -37,6 +37,23 @@ export function EditorPage({ catalog, onToast, onBack }: EditorPageProps) {
const [saveConflict, setSaveConflict] = useState(false);
const [savedAt, setSavedAt] = useState<string | null>(null);
const [validationIssues, setValidationIssues] = useState<FlowValidationIssue[] | null>(null);
// 新建流程首访引导:仅第一次进入空流程页面时展示,5 秒后自动关闭
const [showGuide, setShowGuide] = useState(false);
useEffect(() => {
if (!flow || flow.nodes.length > 1) return;
const seen = window.localStorage.getItem("rpa.editor.guide.seen");
if (seen) return;
setShowGuide(true);
window.localStorage.setItem("rpa.editor.guide.seen", "1");
const timer = window.setTimeout(() => setShowGuide(false), 5000);
return () => window.clearTimeout(timer);
}, [flow?.id]);
useEffect(() => {
// 引导展示期间用户已拖入节点(不再是空流程)则立即收起
if (showGuide && flow && flow.nodes.length > 1) setShowGuide(false);
}, [flow?.nodes.length, showGuide]);
const save = useCallback(async (opts?: { interactive?: boolean }) => {
const current = useEditorStore.getState().flow;
@ -213,6 +230,16 @@ export function EditorPage({ catalog, onToast, onBack }: EditorPageProps) {
<FlowCanvas catalog={catalog} onAddAt={(componentId, position) => addNode(componentId, position)} />
{showGuide && (
<div className="editor-guide" role="status">
<span className="editor-guide-icon"><Lightbulb className="icon" /></span>
<div className="editor-guide-text">
<strong>从左侧「组件库」拖入能力节点,开始搭建流程</strong>
<span>拖拽到画布任意位置,或单击组件快速追加;支持按名称 / ID / 标签搜索。</span>
</div>
</div>
)}
<div className="canvas-badge">
<Check className="icon" />
可执行 {catalog.components.filter((item) => item.implemented).length} / {catalog.counts.total} 项

View File

@ -2257,6 +2257,66 @@ textarea:focus-visible {
margin-top: 2px;
}
/* 新建流程首访引导:顶部浮出,5 秒后自动淡出,不接收鼠标事件 */
.editor-guide {
position: absolute;
left: 50%;
top: 52px;
transform: translateX(-50%);
z-index: 5;
max-width: 460px;
padding: 11px 16px;
display: flex;
gap: 11px;
align-items: center;
border: 1px solid var(--line);
border-radius: 13px;
background: rgba(255, 255, 255, 0.94);
box-shadow: var(--shadow-panel);
backdrop-filter: blur(8px);
pointer-events: none;
animation: guide-life 5s ease forwards;
}
.editor-guide-icon {
width: 30px;
height: 30px;
flex: none;
display: grid;
place-items: center;
border-radius: 9px;
background: var(--blue-soft);
color: var(--blue-dark);
}
.editor-guide-icon .icon {
width: 16px;
height: 16px;
}
.editor-guide-text strong {
display: block;
font-size: 12.5px;
font-weight: 700;
color: var(--ink);
line-height: 18px;
}
.editor-guide-text span {
display: block;
font-size: 11px;
color: var(--muted);
line-height: 16px;
margin-top: 2px;
}
@keyframes guide-life {
0% { opacity: 0; transform: translateX(-50%) translateY(-10px); }
6% { opacity: 1; transform: translateX(-50%) translateY(0); }
90% { opacity: 1; }
100% { opacity: 0; transform: translateX(-50%) translateY(-6px); }
}
.mono {
font-family: var(--mono);
}