# Scenario Mode - Architecture Diagram ## System Overview ``` ┌─────────────────────────────────────────────────────────────────────┐ │ Qinglong Application │ ├─────────────────────────────────────────────────────────────────────┤ │ │ │ ┌─────────────────────┐ ┌─────────────────────┐ │ │ │ Navigation Menu │ │ API Layer │ │ │ │ ┌──────────────┐ │ │ /api/scenarios/ │ │ │ │ │ 定时任务 │ │ │ - GET (list) │ │ │ │ │ 订阅管理 │ │ │ - POST (create) │ │ │ │ │ 场景管理 ⭐ │◄──┼─────────┤ - PUT (update) │ │ │ │ │ 环境变量 │ │ │ - DELETE (delete) │ │ │ │ │ ... │ │ │ - PUT /enable │ │ │ │ └──────────────┘ │ │ - PUT /disable │ │ │ └─────────────────────┘ │ - GET /:id │ │ │ └─────────────────────┘ │ │ │ │ │ ▼ │ │ ┌──────────────────────────────────────────────────────┐ │ │ │ Scenario Management Page │ │ │ │ /scenario │ │ │ │ ┌────────────────────────────────────────────────┐ │ │ │ │ │ Toolbar: │ │ │ │ │ │ [新建场景] [启用] [禁用] [删除] [搜索] │ │ │ │ │ └────────────────────────────────────────────────┘ │ │ │ │ ┌────────────────────────────────────────────────┐ │ │ │ │ │ Table: │ │ │ │ │ │ ┌─────┬────────┬──────┬──────┬────────────┐ │ │ │ │ │ │ │名称 │描述 │状态 │节点数│操作 │ │ │ │ │ │ │ ├─────┼────────┼──────┼──────┼────────────┤ │ │ │ │ │ │ │场景1│... │启用 │5节点 │[编辑工作流]│ │ │ │ │ │ │ │场景2│... │禁用 │3节点 │[编辑工作流]│ │ │ │ │ │ │ └─────┴────────┴──────┴──────┴────────────┘ │ │ │ │ │ └────────────────────────────────────────────────┘ │ │ │ └──────────────────────────────────────────────────────┘ │ │ │ │ │ │ Click "编辑工作流" │ │ ▼ │ │ ┌──────────────────────────────────────────────────────────────┐ │ │ │ Workflow Editor Modal (Full Screen) │ │ │ │ ┌────────────────────────────────────────────────────────┐ │ │ │ │ │ Canvas Area (Left) │ Edit Panel (Right 400px) │ │ │ │ │ ├─────────────────────────────┼──────────────────────────┤ │ │ │ │ │ Toolbar: │ Node Configuration │ │ │ │ │ │ [+HTTP] [+Script] │ ┌────────────────────┐ │ │ │ │ │ │ [+Condition] [+Delay] │ │ Label: [______] │ │ │ │ │ │ │ [+Loop] [Validate] │ │ Type: [HTTP▼] │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ Nodes Grid: │ │ URL: [______] │ │ │ │ │ │ │ ┌──────┐ ┌──────┐ ┌──────┐ │ │ Method:[GET ▼] │ │ │ │ │ │ │ │Node 1│ │Node 2│ │Node 3│ │ │ Headers:[____] │ │ │ │ │ │ │ │HTTP │ │Script│ │Cond. │ │ │ Body: [____] │ │ │ │ │ │ │ └──────┘ └──────┘ └──────┘ │ │ │ │ │ │ │ │ │ ┌──────┐ ┌──────┐ │ │ [Save] [Delete] │ │ │ │ │ │ │ │Node 4│ │Node 5│ │ └────────────────────┘ │ │ │ │ │ │ │Delay │ │Loop │ │ │ │ │ │ │ │ └──────┘ └──────┘ │ │ │ │ │ │ └─────────────────────────────┴──────────────────────────┘ │ │ │ │ [Cancel] [Save Workflow] │ │ │ └──────────────────────────────────────────────────────────────┘ │ │ │ └─────────────────────────────────────────────────────────────────────┘ ``` ## Data Flow ``` ┌─────────────┐ │ Browser │ └──────┬──────┘ │ │ 1. Navigate to /scenario ▼ ┌─────────────────┐ │ Scenario Page │ │ (React) │ └──────┬──────────┘ │ │ 2. GET /api/scenarios ▼ ┌─────────────────┐ │ Scenario API │ │ (Express) │ └──────┬──────────┘ │ │ 3. Query database ▼ ┌─────────────────┐ │ Scenario Model │ │ (Sequelize) │ └──────┬──────────┘ │ │ 4. Read from SQLite ▼ ┌─────────────────┐ │ Database.db │ │ Scenarios │ │ Table │ └─────────────────┘ ``` ## Workflow Editor Data Flow ``` User Action Flow: ┌──────────────────────────────────────────────────────────────┐ │ │ │ Click "编辑工作流" │ │ │ │ │ ▼ │ │ Open WorkflowEditorModal │ │ │ │ │ ├──► Load existing workflowGraph │ │ │ (if scenario has one) │ │ │ │ │ ▼ │ │ Display Canvas & Edit Panel │ │ │ │ │ ├──► Click [+HTTP] button │ │ │ └──► Create new HTTP node │ │ │ └──► Add to localGraph.nodes │ │ │ │ │ ├──► Click node card │ │ │ └──► Set selectedNodeId │ │ │ └──► Populate form in Edit Panel │ │ │ │ │ ├──► Edit form fields │ │ │ └──► Update node.config │ │ │ └──► Save to localGraph │ │ │ │ │ ├──► Click [Delete] button │ │ │ └──► Remove node from localGraph.nodes │ │ │ │ │ ▼ │ │ Click "保存工作流" │ │ │ │ │ ├──► Validate workflow │ │ │ └──► Check nodes.length > 0 │ │ │ │ │ ▼ │ │ Call onOk(localGraph) │ │ │ │ │ ▼ │ │ PUT /api/scenarios │ │ │ │ │ └──► Update scenario.workflowGraph │ │ └──► Save to database │ │ └──► Success message │ │ └──► Close modal │ │ └──► Refresh list │ │ │ └──────────────────────────────────────────────────────────────┘ ``` ## Node Type Configurations ``` ┌─────────────────────────────────────────────────────────────┐ │ Node Types │ ├─────────────────────────────────────────────────────────────┤ │ │ │ 1. HTTP Request Node │ │ ┌──────────────────────────────────────────┐ │ │ │ type: 'http' │ │ │ │ config: │ │ │ │ - url: string │ │ │ │ - method: GET|POST|PUT|DELETE │ │ │ │ - headers: Record │ │ │ │ - body: string │ │ │ └──────────────────────────────────────────┘ │ │ │ │ 2. Script Execution Node │ │ ┌──────────────────────────────────────────┐ │ │ │ type: 'script' │ │ │ │ config: │ │ │ │ - scriptPath: string │ │ │ │ - scriptContent: string │ │ │ └──────────────────────────────────────────┘ │ │ │ │ 3. Condition Node │ │ ┌──────────────────────────────────────────┐ │ │ │ type: 'condition' │ │ │ │ config: │ │ │ │ - condition: string │ │ │ │ - trueNext: string │ │ │ │ - falseNext: string │ │ │ └──────────────────────────────────────────┘ │ │ │ │ 4. Delay Node │ │ ┌──────────────────────────────────────────┐ │ │ │ type: 'delay' │ │ │ │ config: │ │ │ │ - delayMs: number │ │ │ └──────────────────────────────────────────┘ │ │ │ │ 5. Loop Node │ │ ┌──────────────────────────────────────────┐ │ │ │ type: 'loop' │ │ │ │ config: │ │ │ │ - iterations: number │ │ │ │ - loopBody: string[] │ │ │ └──────────────────────────────────────────┘ │ │ │ └─────────────────────────────────────────────────────────────┘ ``` ## Database Schema ``` Table: Scenarios ┌──────────────┬──────────────┬──────────────┬───────────────┐ │ Column │ Type │ Nullable │ Default │ ├──────────────┼──────────────┼──────────────┼───────────────┤ │ id │ INTEGER │ NO │ AUTO_INCREMENT│ │ name │ STRING │ NO │ - │ │ description │ TEXT │ YES │ NULL │ │ status │ INTEGER │ YES │ 0 │ │ workflowGraph│ JSON │ YES │ NULL │ │ createdAt │ DATETIME │ NO │ NOW() │ │ updatedAt │ DATETIME │ NO │ NOW() │ └──────────────┴──────────────┴──────────────┴───────────────┘ workflowGraph JSON structure: { "nodes": [ { "id": "node_1234567890", "type": "http", "label": "HTTP请求 1", "x": 100, "y": 100, "config": { "url": "https://api.example.com", "method": "GET", "headers": {}, "body": "" }, "next": "node_1234567891" } ], "startNode": "node_1234567890" } ``` ## Component Hierarchy ``` App └── Layout └── Scenario Page (/scenario) ├── Toolbar │ ├── Button (新建场景) │ ├── Button (启用) │ ├── Button (禁用) │ ├── Button (删除) │ └── Search (搜索场景) ├── Table │ └── Columns │ ├── 场景名称 │ ├── 场景描述 │ ├── 状态 │ ├── 工作流 │ ├── 创建时间 │ └── 操作 │ └── Button (编辑工作流) ├── ScenarioModal │ └── Form │ ├── Input (名称) │ └── TextArea (描述) └── WorkflowEditorModal ├── Canvas (Left) │ ├── Toolbar │ │ ├── Button (+ HTTP) │ │ ├── Button (+ Script) │ │ ├── Button (+ Condition) │ │ ├── Button (+ Delay) │ │ ├── Button (+ Loop) │ │ └── Button (Validate) │ └── Nodes Grid │ └── NodeCard (×N) │ ├── Type Badge │ └── Label └── Edit Panel (Right) └── Form (Dynamic) ├── Input (Label) ├── Select (Type) ├── [Node-specific fields] └── Buttons ├── Save └── Delete ``` ## File Organization ``` qinglong/ ├── back/ │ ├── api/ │ │ ├── index.ts (modified: +scenario route) │ │ └── scenario.ts (new: API endpoints) │ ├── data/ │ │ └── scenario.ts (new: Model definition) │ └── services/ │ └── scenario.ts (new: Business logic) ├── src/ │ ├── layouts/ │ │ └── defaultProps.tsx (modified: +scenario nav) │ ├── locales/ │ │ ├── zh-CN.json (modified: +53 keys) │ │ └── en-US.json (modified: +53 keys) │ └── pages/ │ └── scenario/ │ ├── index.tsx (new: Main page) │ ├── index.less (new: Page styles) │ ├── modal.tsx (new: Create/Edit modal) │ ├── workflowEditorModal.tsx (new: Editor) │ ├── workflowEditor.less (new: Editor styles) │ └── type.ts (new: TypeScript types) └── SCENARIO_MODE.md (new: Documentation) ```