ai_member_xiaobian/.agents/skills/lark-whiteboard/scenes/flowchart.md
2026-05-15 10:57:05 +08:00

11 KiB
Raw Permalink Blame History

流程图 (Flowchart)

适用于:各种业务流转图、决策树、审批流、时序控制逻辑、带条件判断的链路、系统架构拓扑等。

通用字段语义详见 references/schema.md,通用布局原则详见 references/layout.md;本文件只描述流程图场景下的选型边界与范式。

Important

流程图必须走 DSL 路径,不再使用 Mermaid 复杂分支、判断、回路、跳级关系优先使用 layout: "dagre" 计算拓扑;如果只是规整的单线流水线,且卡片强对齐比自动拓扑更重要,也可以使用 Flex + 顶层 connector 组合实现。

美学规范

  • 摒弃简陋节点,推崇全卡片化:核心业务节点不要只用一个纯文本 rect应优先采用 Flex 组合卡片(如:在 vertical frame 内上下组合【Emoji 标题项】和【补充说明项】),使得节点信息结构化、层级分明。
  • 语义化色彩编排:节点底色严禁随机分配。必须按状态语义映射:常规链路用浅蓝/浅紫、核心风控/检查用预警黄、成功通过用生命绿、失败熔断用危险红。边框颜色可同色系加深,以凸显卡片边缘。
  • 统一判定逻辑:条件分支必须使用 diamond 菱形节点,并且严禁漏掉 layoutOptions.edges 边定义里的第三个标签参数(必须清晰写明"是/否"、"通过/拒绝")。
  • 形状多样化:合理搭配不同形状来表达语义 —— ellipse 用于外部实体/起终点、diamond 用于判断路由、rect 用于业务处理节点、cylinder 用于持久化存储。

Layout 选型

模式 适用条件 核心配置
主体用 Dagre 有判断、分支、回路、回退、跳级关系的标准流程图 主体 frame 设定 layout: "dagre",按需配置 rankdir: "TB"rankdir: "LR"
局部复合节点 流程中的某一步本身是一个小型 UI 组合体 外层仍用 dagre,复合步骤内部改用 layout: "vertical" / "horizontal"。此类节点为不透明节点,外层连线只能连到外壳。
透明子图 需按业务区域分组,且连线穿越区域边界 子容器声明 layout: "dagre" + layoutOptions: { isCluster: true },成为透明子图。内部节点直接参与外层拓扑运算。
规整流水线 基本是单线 A → B → C → D且卡片对齐要求极高 主体可用 Flex 排版,连线改用顶层 connector;不要为了"自动"而硬上 Dagre。

核心属性

  • rankdir: TB(上下)或 LR(左右)。强烈推荐优先使用 LR,充分利用宽屏横向空间。
  • edges: 在根 Dagre 的 layoutOptions.edges 中按 [fromId, toId, "标签"] 声明。支持反向连接实现闭环。所有 edges 统一写在最外层根 Dagre,不要写在 cluster 内部。
  • ranksep 与边文本: 若边上标注了说明文字,必须根据字数调大间距ranksep = max(60, 字数 × 16)
  • 自适应尺寸: dagre 容器必须设定 width: "fit-content"height: "fit-content"
  • clusterTitle: 透明子图可通过 clusterTitle 声明悬浮标题(自动吸附左上角、加粗 14px搭配 clusterTitleColor 指定标题颜色。

两种嵌套模式

不透明节点Opaque Node

Dagre 内的子容器,只要未声明 isCluster: true,对外层 Dagre 就是具有确定宽高的原子节点。外层连线无法寻址其内部子节点。适合封装复杂的组合卡片(如带图标、版本号、多行描述的业务模块)。

透明子图Compound Cluster

子容器同时声明 layout: "dagre"layoutOptions: { isCluster: true } 时,成为外层 Dagre 的复合子图。其内部子节点直接参与外层拓扑运算,连线可穿越子图边界。适合划分网络区域、功能层级、命名空间等边界容器。推荐搭配 borderDash: "dashed" 虚线边框 + 淡色背景。

骨架示例(推荐范本)

以下是一个混合架构拓扑的完整示例。它同时展示了透明子图Kubernetes Zone连线可穿透不透明复合节点DB 集群、AI 引擎连线只能连外壳的标准写法以及多种形状ellipse / diamond / rect / cylinder和语义化配色规范。

{
  "version": 2,
  "nodes": [
    {
      "type": "frame",
      "id": "root",
      "x": 20, "y": 20,
      "layout": "dagre",
      "width": "fit-content", "height": "fit-content",
      "padding": 60,
      "fillColor": "#F8FAFC",
      "borderColor": "#CBD5E1",
      "borderWidth": 1,
      "borderRadius": 16,
      "layoutOptions": {
        "rankdir": "LR",
        "nodesep": 60,
        "ranksep": 120,
        "edges": [
          ["user", "k8s_ingress", "HTTPS request"],
          ["k8s_ingress", "web_pod", "Route UI"],
          ["k8s_ingress", "api_pod", "Route API"],
          ["web_pod", "api_pod", "Internal REST"],
          ["api_pod", "db_cluster", "SQL Query"],
          ["api_pod", "ai_service", "gRPC Stream"]
        ]
      },
      "children": [
        {
          "type": "ellipse", "id": "user", "text": "Global Users",
          "width": 110, "height": 60,
          "fillColor": "#E2E8F0", "borderColor": "#64748B", "borderWidth": 1,
          "fontSize": 14, "textColor": "#334155"
        },
        {
          "type": "frame", "id": "zone_k8s",
          "layout": "dagre",
          "layoutOptions": {
            "isCluster": true,
            "clusterTitle": "☸️ Kubernetes Zone (isCluster)",
            "clusterTitleColor": "#2563EB"
          },
          "fillColor": "#EFF6FF", "borderColor": "#60A5FA",
          "borderWidth": 2, "borderDash": "dashed", "borderRadius": 24,
          "children": [
            {
              "type": "diamond", "id": "k8s_ingress", "text": "Nginx Ingress",
              "width": 130, "height": 70,
              "fillColor": "#DBEAFE", "borderColor": "#3B82F6", "borderWidth": 2,
              "textColor": "#1E40AF"
            },
            {
              "type": "rect", "id": "web_pod", "text": "Next.js SSR Pod",
              "width": 140, "height": 48,
              "fillColor": "#BFDBFE", "borderColor": "#2563EB", "borderWidth": 2,
              "borderRadius": 8, "textColor": "#1E3A8A"
            },
            {
              "type": "rect", "id": "api_pod", "text": "Go Lang API Pod",
              "width": 140, "height": 48,
              "fillColor": "#BFDBFE", "borderColor": "#2563EB", "borderWidth": 2,
              "borderRadius": 8, "textColor": "#1E3A8A"
            }
          ]
        },
        {
          "type": "frame", "id": "db_cluster",
          "layout": "vertical", "gap": 16, "padding": [20, 24],
          "alignItems": "center",
          "fillColor": "#F0FDF4", "borderColor": "#22C55E",
          "borderWidth": 2, "borderRadius": 16,
          "children": [
            {
              "type": "text", "id": "db_title",
              "text": "🗄️ Highly Available DB (不透明)", "fontSize": 14, "textColor": "#14532D"
            },
            {
              "type": "frame", "id": "db_row", "layout": "horizontal", "gap": 20,
              "children": [
                {
                  "type": "cylinder", "id": "db_master", "text": "Master",
                  "width": 80, "height": 50,
                  "fillColor": "#DCFCE7", "borderColor": "#16A34A", "borderWidth": 1,
                  "textColor": "#166534"
                },
                {
                  "type": "cylinder", "id": "db_replica", "text": "Replica",
                  "width": 80, "height": 50,
                  "fillColor": "#DCFCE7", "borderColor": "#16A34A", "borderWidth": 1,
                  "textColor": "#166534"
                }
              ]
            }
          ]
        },
        {
          "type": "frame", "id": "ai_service",
          "layout": "vertical", "gap": 10, "padding": [16, 20],
          "alignItems": "center",
          "fillColor": "#FAF5FF", "borderColor": "#A855F7",
          "borderWidth": 2, "borderRadius": 12,
          "children": [
            {
              "type": "text", "id": "ai_title",
              "text": "🧠 Multi-Modal Engine (不透明)", "fontSize": 14, "textColor": "#6B21A8"
            },
            {
              "type": "rect", "id": "ai_version",
              "text": "v4.2.1-beta", "width": 90, "height": 22,
              "fillColor": "#E9D5FF", "borderColor": "#C084FC", "borderWidth": 1,
              "borderRadius": 4, "fontSize": 11, "textColor": "#581C87"
            },
            {
              "type": "text", "id": "ai_desc",
              "text": "Includes Vector Store\n& Transformer Blocks",
              "fontSize": 12, "textColor": "#7E22CE", "textAlign": "center"
            }
          ]
        }
      ]
    }
  ]
}

范本要点

  • zone_k8s透明子图isCluster: true + clusterTitle),外部连线穿越虚线边界直达 k8s_ingressweb_podapi_pod
  • db_clusterai_service不透明节点layout: "vertical"),内部用 Flex 组合了多行结构化信息,对外层 Dagre 是固定宽高的原子。连线只能连到外壳 ID。
  • 所有 edges 统一写在最外层根 Dagre 的 layoutOptions 中。
  • 本范本中用到了 ellipse(外部实体)、diamond(路由判断)、rect(业务节点)、cylinder(数据库存储)四种形状。

陷阱与常见报错防范

  • 误用 Mermaid:只要用户没有带 mermaid 具体语法代码,哪怕描述明确是"流程图",也强制使用 DSL 框架下的 Dagre 模式
  • 重复画线dagre 里的所有子节点关系通过 edges 定义,引擎会自动生成连线。绝对不要再去外层用 connector 节点重复连一次
  • 穿透黑盒:普通子容器是不透明节点,外部连线无法直接寻址其内部子节点(引擎会自动重定向至外壳)。若需穿透,必须声明 layout: "dagre"layoutOptions: { isCluster: true }
  • id 缺失:只要是在 edges 里出现的标识符,children 里一定能找到同名 id 的节点对应,拼写必须完全一致。
  • 宽度灾难Dagre 内容器禁止子框使用 fill-container,因为 dagre 父容器本身是被内容撑开的。