From 37f2c8977bd9fe7d1eccbc660c3fbd97d72d3809 Mon Sep 17 00:00:00 2001 From: yu <191972707@qq.com> Date: Wed, 28 Oct 2026 16:37:25 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=96=B0=E5=BB=BA=E6=B5=81=E7=A8=8B?= =?UTF-8?q?=E9=A6=96=E6=AC=A1=E8=BF=9B=E5=85=A5=E5=B1=95=E7=A4=BA=E5=BC=95?= =?UTF-8?q?=E5=AF=BC=E6=8F=90=E7=A4=BA=EF=BC=8C5=20=E7=A7=92=E5=90=8E?= =?UTF-8?q?=E8=87=AA=E5=8A=A8=E5=85=B3=E9=97=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/renderer/src/pages/EditorPage.tsx | 29 ++++++++++++- src/renderer/src/styles/app.css | 60 +++++++++++++++++++++++++++ 2 files changed, 88 insertions(+), 1 deletion(-) diff --git a/src/renderer/src/pages/EditorPage.tsx b/src/renderer/src/pages/EditorPage.tsx index b687909..8b43417 100644 --- a/src/renderer/src/pages/EditorPage.tsx +++ b/src/renderer/src/pages/EditorPage.tsx @@ -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(null); const [validationIssues, setValidationIssues] = useState(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) { addNode(componentId, position)} /> + {showGuide && ( +
+ +
+ 从左侧「组件库」拖入能力节点,开始搭建流程 + 拖拽到画布任意位置,或单击组件快速追加;支持按名称 / ID / 标签搜索。 +
+
+ )} +
可执行 {catalog.components.filter((item) => item.implemented).length} / {catalog.counts.total} 项 diff --git a/src/renderer/src/styles/app.css b/src/renderer/src/styles/app.css index cee8628..8edf309 100644 --- a/src/renderer/src/styles/app.css +++ b/src/renderer/src/styles/app.css @@ -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); }