Prechádzať zdrojové kódy

docs: complete P0 client interaction flow

wangkangyjy 1 deň pred
rodič
commit
cc59103791

+ 283 - 0
docs/p0-mobile/07-client-total-interaction-flow.md

@@ -0,0 +1,283 @@
+# 07|P0 客户端总交互流程
+
+> 产品:医梦患者智能服务门户(内部代号 Adjutant)
+>
+> 范围:单医院、固定 Mock 患者、三个智能体、语音优先。
+>
+> 本图目的:让产品、设计、FastGPT、MCP 与测试人员对“患者从哪里进入、如何完成任务、结果回到哪里”形成同一理解。
+
+![医梦患者智能服务门户 P0 客户端总交互流程](./医梦患者智能服务门户_P0客户端总交互流程.png)
+
+## 1. 一张图看懂完整闭环
+
+```mermaid
+flowchart LR
+    subgraph ENTRY["① 发现与唤起"]
+        E1["首页统一语音入口<br/>不知道用什么服务"]
+        E2["首页 / 服务中心卡片<br/>明确选择某项服务"]
+        E3["患者状态与待办<br/>继续未完成任务"]
+        E4["健康记录 / 业务内嵌<br/>查看结果或再次办理"]
+    end
+
+    subgraph START["② 路由与任务启动"]
+        G["统一助手 / 任务启动器<br/>识别意图 · 加载医院和患者上下文<br/>医疗安全前置判断"]
+        D{"如何进入任务?"}
+        D1["明确能力<br/>直接创建任务"]
+        D2["自然语言诉求<br/>确认目标服务后创建任务"]
+        D3["已有 taskId<br/>恢复原任务状态"]
+    end
+
+    subgraph SHELL["③ 统一对话式任务界面"]
+        S1["最近 1–2 轮对话<br/>患者原话 + 助手理解"]
+        S2["已收集信息<br/>显示完整度、缺失项和修改入口"]
+        S3["当前唯一任务<br/>一次只追问或处理一件事"]
+        S4["语音主输入<br/>文字备选 + 快捷选项"]
+        S5["完整性与安全检查<br/>通过后才查询或执行"]
+        S6["操作记录<br/>可展开查看转写、规则和工具调用"]
+    end
+
+    subgraph AGENTS["④ 三个 P0 智能体"]
+        R["智能分诊挂号<br/>急诊门禁 → 挂号补槽<br/>号源选择 → 独立确认<br/>Mock 锁号 / 挂号 / 支付"]
+        P["报告智能解读<br/>选择或上传 → 归属确认<br/>质量 / 风险检查<br/>结构化解读"]
+        T["中医舌诊<br/>体质症候问答 → 舌象采集<br/>调用现有舌诊 MCP<br/>融合评估结果"]
+    end
+
+    X["共同异常与恢复<br/>信息不足继续追问 · 图片重传 · 工具重试<br/>医疗风险中止普通流程 · 必要时转人工"]
+
+    subgraph RETURN["⑤ 结果与患者状态回流"]
+        U["统一结果组件<br/>成功、风险、失败和行动建议"]
+        H["健康记录<br/>保存完成结果与未完成任务"]
+        W["首页状态与待办<br/>预约、新报告、继续舌诊、失败重试"]
+    end
+
+    E1 --> G
+    E2 --> G
+    E3 --> G
+    E4 --> G
+    G --> D
+    D --> D1
+    D --> D2
+    D --> D3
+    D1 --> S1
+    D2 --> S1
+    D3 --> S1
+    S1 --> S2 --> S3 --> S4 --> S5
+    S6 -.过程留痕.-> S5
+    S5 --> R
+    S5 --> P
+    S5 --> T
+    R --> U
+    P --> U
+    T --> U
+    R -.异常.-> X
+    P -.异常.-> X
+    T -.异常.-> X
+    X -.恢复任务.-> S3
+    U --> H --> W
+    W -.继续或发起新任务.-> G
+```
+
+## 2. 五段交互分别解决什么问题
+
+| 阶段 | 患者看到什么 | 产品需要保证什么 |
+|---|---|---|
+| 发现与唤起 | 语音入口、服务卡、待办、健康记录 | 三项服务可发现,但患者不需要理解“智能体” |
+| 路由与启动 | 系统确认准备办理的事情 | 多个入口调用同一能力;风险信号优先于普通业务 |
+| 对话式任务界面 | 最近对话、已收集信息、当前追问 | 语音负责表达和补槽,卡片负责检查、修改与确认 |
+| 三智能体任务 | 挂号、报告、舌诊各自的专业流程 | 共享任务壳,但不把三种业务混在一个大对话线程里 |
+| 结果与回流 | 结果详情、健康记录、首页待办 | 完成结果可回看,未完成或失败任务可继续 |
+
+## 3. 三类入口如何进入同一任务
+
+### 3.1 统一语音入口
+
+适合患者不知道该选择什么服务。
+
+```text
+患者说出诉求
+→ 语音转文字并回显
+→ 识别挂号 / 报告 / 舌诊意图
+→ 医疗风险前置判断
+→ 告知准备进入的服务
+→ 患者确认
+→ 创建具体任务并带入已识别信息
+```
+
+例如:
+
+> “我头疼,帮我挂神经内科明天早上九点的专家号。”
+
+系统进入挂号任务,并直接展示已得到的科室、日期、时间、号别;只追问缺失的医生信息。
+
+### 3.2 服务卡片入口
+
+适合患者已经知道要使用哪项服务。
+
+```text
+点击服务卡
+→ capabilityCode 已确定
+→ 进入该智能体的语音任务起点
+→ 患者用一句话表达完整或部分诉求
+```
+
+服务卡不会跳过对话式任务壳,也不会直接进入一组静态表单。
+
+### 3.3 状态、待办与健康记录入口
+
+适合恢复任务或查看结果。
+
+| 记录状态 | 点击后的动作 |
+|---|---|
+| `WAITING_USER` | 恢复最近对话、已收集信息和当前缺失项 |
+| `PROCESSING` | 回到分析或执行进度页 |
+| `COMPLETED` | 打开业务结果详情 |
+| `FAILED` | 展示失败原因,允许保留上下文重试 |
+| `TRANSFERRED` | 展示急诊、人工或线下处理指引 |
+
+## 4. 统一对话式任务界面
+
+三个智能体共用六个区域:
+
+1. **任务标题**:明确当前正在办理挂号、报告解读或舌诊;
+2. **最近对话**:保留最近 1–2 轮患者原话和助手理解;
+3. **已收集信息**:持续显示业务字段、完整度和缺失项;
+4. **当前任务**:一次只追问一个问题,或要求患者完成一个动作;
+5. **输入与操作**:语音为主,文字、快捷选项、上传和标准卡片为辅;
+6. **操作记录**:默认折叠,患者可查看转写、规则判断和工具步骤。
+
+```text
+语音表达
+→ 回显患者原话
+→ 展示助手理解
+→ 更新已收集信息
+→ 高亮当前缺失项
+→ 语音 / 文字 / 选项补充
+→ 完整性与安全检查
+→ 进入查询、分析或确认
+```
+
+关键原则:
+
+- 不做只有聊天气泡的无限对话;
+- 不隐藏患者已经说过什么;
+- 已收集信息在补槽过程中持续可见;
+- 患者可以修改识别错误的字段;
+- 具有副作用的操作必须使用独立确认卡;
+- 完成后保存业务记录,不建立“机器人会话列表”。
+
+## 5. 三个智能体的主路径
+
+### 5.1 智能分诊挂号
+
+```text
+语音描述挂号需求
+→ 急诊安全门禁
+→ 显示已收集的挂号条件
+→ 逐项补齐缺失信息
+→ 查询医生和号源
+→ 选择具体号源
+→ 独立确认挂号信息
+→ Mock 锁号、挂号和支付
+→ 挂号结果
+```
+
+必须演示:
+
+- 一句话提供多个条件,只追问医生;
+- 修改科室、日期、时间或号别;
+- 胸痛和呼吸困难中止普通挂号;
+- 无号源或锁号失败后保留已收集信息重新选择。
+
+### 5.2 检验检查报告解读
+
+```text
+语音说明解读诉求
+→ 展示患者和目标报告类型
+→ 选择院内报告或上传文件
+→ 确认归属、来源和报告状态
+→ 文件质量、OCR 和风险检查
+→ 生成结构化解读
+→ 保存报告解读记录
+```
+
+必须演示:
+
+- 从首页待办直接进入指定报告;
+- 从语音入口进入后再选择报告;
+- 图片模糊时重传;
+- 风险提示优先于普通指标解释。
+
+### 5.3 中医舌诊
+
+```text
+语音说明健康诉求
+→ 展示已识别诉求
+→ 完成体质与症候问答
+→ 保存阶段进度
+→ 舌象拍摄和图片质控
+→ 调用现有舌诊 MCP
+→ 融合问答与舌象结果
+→ 保存中医评估记录
+```
+
+必须演示:
+
+- 问答中断后继续;
+- 图片模糊后重新拍摄;
+- MCP 失败后保留问答和图片重试;
+- 输出辅助评估和健康建议,不输出确诊或处方。
+
+## 6. 结果如何回到门户
+
+任务完成后不能只停留在对话页面:
+
+```text
+任务结果
+→ 保存到健康记录
+→ 首页生成或更新状态卡
+→ 患者从待办、最近记录或健康记录再次进入
+```
+
+典型回流:
+
+| 任务结果 | 健康记录 | 首页变化 |
+|---|---|---|
+| 挂号成功 | 新增挂号记录 | 展示明日预约和就诊提醒 |
+| 报告解读完成 | 新增报告解读记录 | “待解读”变为“解读已完成” |
+| 舌诊问答未完成 | 保存进行中评估 | 展示“继续完成舌诊” |
+| 工具调用失败 | 保存失败原因与上下文 | 展示“任务未完成,可重试” |
+| 急诊风险 | 保存分流结果和依据 | 不生成普通预约,保留急诊提示 |
+
+## 7. P0 固定边界
+
+- 单家指定医院;
+- 固定 Mock 患者本人,不提供登录和家庭成员切换;
+- 三个能力固定开通;
+- 语音使用演示转写;
+- 挂号与报告使用 Mock MCP;
+- 舌诊调用现有 MCP;
+- 不接真实 HIS、LIS、支付和消息系统;
+- 所有结果和风险规则明确标记为演示数据;
+- 客户端使用稳定能力编码,不直接绑定 FastGPT App ID。
+
+能力编码:
+
+- `SMART_REGISTRATION`
+- `REPORT_INTERPRETATION`
+- `TCM_TONGUE_ASSESSMENT`
+
+## 8. 原型评审顺序
+
+评审时按以下顺序完整演示:
+
+1. 首页统一语音入口识别挂号诉求;
+2. 挂号任务展示 5/6 已收集信息并补齐医生;
+3. 查询号源、独立确认并完成 Mock 挂号;
+4. 返回首页查看预约状态,再进入健康记录;
+5. 从首页新报告待办进入报告解读;
+6. 从服务卡进入中医舌诊并演示任务中断与恢复;
+7. 演示急诊打断、报告模糊和舌诊分析失败三个异常场景。
+
+可编辑视觉源:
+
+- `医梦患者智能服务门户_P0客户端总交互流程.excalidraw`

+ 417 - 0
docs/p0-mobile/build_client_interaction_flow.py

@@ -0,0 +1,417 @@
+"""Build the editable Excalidraw overview for the P0 patient portal."""
+
+from __future__ import annotations
+
+import copy
+import json
+from pathlib import Path
+
+
+ROOT = Path(__file__).resolve().parent
+TEMPLATE = Path(
+    "/Users/destiny/.agents/skills/excalidraw-diagram-generator/templates/"
+    "relationship-template.excalidraw"
+)
+OUTPUT = ROOT / "医梦患者智能服务门户_P0客户端总交互流程.excalidraw"
+
+template = json.loads(TEMPLATE.read_text(encoding="utf-8"))
+rect_template = next(e for e in template["elements"] if e["type"] == "rectangle")
+text_template = next(e for e in template["elements"] if e["type"] == "text")
+arrow_template = next(e for e in template["elements"] if e["type"] == "arrow")
+
+counter = 2000
+
+
+def next_id(prefix: str) -> str:
+    global counter
+    counter += 1
+    return f"{prefix}-{counter}"
+
+
+def bound_box(
+    x: int,
+    y: int,
+    width: int,
+    height: int,
+    text: str,
+    *,
+    fill: str,
+    stroke: str,
+    color: str = "#16133a",
+    font_size: int = 18,
+    stroke_width: int = 2,
+    roughness: int = 1,
+) -> list[dict]:
+    rect = copy.deepcopy(rect_template)
+    label = copy.deepcopy(text_template)
+    rect_id = next_id("box")
+    text_id = next_id("text")
+    group_id = next_id("group")
+    seed = counter * 7919
+
+    rect.update(
+        {
+            "id": rect_id,
+            "x": x,
+            "y": y,
+            "width": width,
+            "height": height,
+            "strokeColor": stroke,
+            "backgroundColor": fill,
+            "strokeWidth": stroke_width,
+            "roughness": roughness,
+            "groupIds": [group_id],
+            "boundElements": [{"type": "text", "id": text_id}],
+            "text": None,
+            "fontSize": None,
+            "fontFamily": None,
+            "textAlign": None,
+            "verticalAlign": None,
+            "seed": seed,
+            "versionNonce": seed + 1,
+        }
+    )
+
+    line_count = text.count("\n") + 1
+    text_height = min(int(line_count * font_size * 1.35 + 8), height - 16)
+    label.update(
+        {
+            "id": text_id,
+            "x": x + 14,
+            "y": y + (height - text_height) / 2,
+            "width": width - 28,
+            "height": text_height,
+            "strokeColor": color,
+            "text": text,
+            "fontSize": font_size,
+            "fontFamily": 5,
+            "textAlign": "center",
+            "verticalAlign": "middle",
+            "containerId": rect_id,
+            "groupIds": [group_id],
+            "seed": seed + 2,
+            "versionNonce": seed + 3,
+        }
+    )
+    return [rect, label]
+
+
+def free_text(
+    x: int,
+    y: int,
+    width: int,
+    height: int,
+    text: str,
+    *,
+    size: int,
+    color: str = "#16133a",
+    align: str = "left",
+) -> dict:
+    label = copy.deepcopy(text_template)
+    seed = counter * 6151
+    label.update(
+        {
+            "id": next_id("label"),
+            "x": x,
+            "y": y,
+            "width": width,
+            "height": height,
+            "strokeColor": color,
+            "text": text,
+            "fontSize": size,
+            "fontFamily": 5,
+            "textAlign": align,
+            "verticalAlign": "top",
+            "containerId": None,
+            "groupIds": [],
+            "seed": seed,
+            "versionNonce": seed + 1,
+        }
+    )
+    return label
+
+
+def arrow(
+    x: int,
+    y: int,
+    points: list[list[int]],
+    *,
+    color: str = "#69708a",
+    stroke_width: int = 2,
+    dashed: bool = False,
+) -> dict:
+    element = copy.deepcopy(arrow_template)
+    xs = [point[0] for point in points]
+    ys = [point[1] for point in points]
+    seed = counter * 4271
+    element.update(
+        {
+            "id": next_id("arrow"),
+            "x": x,
+            "y": y,
+            "width": max(xs) - min(xs),
+            "height": max(ys) - min(ys),
+            "points": points,
+            "strokeColor": color,
+            "strokeWidth": stroke_width,
+            "strokeStyle": "dashed" if dashed else "solid",
+            "groupIds": [],
+            "startBinding": None,
+            "endBinding": None,
+            "seed": seed,
+            "versionNonce": seed + 1,
+        }
+    )
+    return element
+
+
+elements: list[dict | list[dict]] = [
+    free_text(
+        70,
+        35,
+        2100,
+        60,
+        "医梦患者智能服务门户|P0 客户端总交互流程",
+        size=34,
+        color="#21147d",
+    ),
+    free_text(
+        70,
+        98,
+        2400,
+        42,
+        "单医院 · 固定 Mock 患者 · 语音优先 · 对话式任务界面 · 三智能体 · 结果回到健康记录与首页",
+        size=18,
+        color="#69708a",
+    ),
+    free_text(70, 165, 340, 36, "① 发现与唤起", size=20, color="#21147d"),
+    free_text(500, 165, 380, 36, "② 路由与任务启动", size=20, color="#21147d"),
+    free_text(990, 165, 440, 36, "③ 对话式任务界面", size=20, color="#21147d"),
+    free_text(1550, 110, 560, 36, "④ 三个 P0 智能体", size=20, color="#21147d"),
+    free_text(2250, 350, 860, 36, "⑤ 结果与患者状态回流", size=20, color="#21147d"),
+    bound_box(
+        70,
+        230,
+        340,
+        120,
+        "首页统一语音入口\n不知道使用哪项服务",
+        fill="#f1f0ff",
+        stroke="#2b1f99",
+        color="#21147d",
+        font_size=19,
+    ),
+    bound_box(
+        70,
+        405,
+        340,
+        120,
+        "首页 / 服务中心卡片\n明确选择挂号、报告或舌诊",
+        fill="#ffffff",
+        stroke="#9ea9cc",
+        font_size=18,
+    ),
+    bound_box(
+        70,
+        580,
+        340,
+        120,
+        "患者状态与待办\n预约、新报告、继续舌诊、失败重试",
+        fill="#e9fbfc",
+        stroke="#2fc9d2",
+        color="#115e64",
+        font_size=18,
+    ),
+    bound_box(
+        70,
+        755,
+        340,
+        120,
+        "健康记录 / 业务内嵌\n查看结果、恢复任务、再次办理",
+        fill="#ffffff",
+        stroke="#9ea9cc",
+        font_size=18,
+    ),
+    bound_box(
+        500,
+        300,
+        380,
+        530,
+        "统一助手 / 任务启动器\n\n① 判断入口来源\n② 识别自然语言意图\n③ 加载医院与患者上下文\n④ 医疗安全前置判断\n⑤ 确认目标服务\n\n明确能力:直接创建任务\n自然语言:确认后创建任务\n已有 taskId:恢复原任务状态",
+        fill="#2b1f99",
+        stroke="#21147d",
+        color="#ffffff",
+        font_size=18,
+        roughness=0,
+    ),
+    bound_box(
+        990,
+        245,
+        440,
+        640,
+        "统一对话式任务界面\n\n最近对话\n患者原话 + 助手理解\n\n已收集信息\n完整度 · 缺失项 · 修改入口\n\n当前唯一任务\n一次只追问或处理一件事\n\n语音主输入\n文字备选 · 快捷选项 · 上传\n\n完整性与安全检查\n通过后才查询、分析或执行\n\n操作记录\n转写、规则与工具步骤可展开",
+        fill="#f7f8ff",
+        stroke="#2b1f99",
+        color="#21147d",
+        font_size=18,
+        roughness=0,
+    ),
+    bound_box(
+        990,
+        970,
+        440,
+        185,
+        "P0 固定运行上下文\n\n单家指定医院|固定本人 Mock 患者\n演示语音转写|FastGPT Workflow\n挂号与报告 Mock MCP|现有舌诊 MCP",
+        fill="#f7fbff",
+        stroke="#9ea9cc",
+        font_size=16,
+    ),
+    bound_box(
+        1550,
+        165,
+        560,
+        250,
+        "智能分诊挂号|SMART_REGISTRATION\n\n急诊安全门禁 → 挂号条件补槽\n→ 医生与号源选择 → 独立确认\n→ Mock 锁号 / 挂号 / 支付\n→ 挂号结果",
+        fill="#f1f0ff",
+        stroke="#2b1f99",
+        color="#21147d",
+        font_size=18,
+    ),
+    bound_box(
+        1550,
+        485,
+        560,
+        250,
+        "报告智能解读|REPORT_INTERPRETATION\n\n选择院内报告或上传 → 归属确认\n→ 文件质量 / OCR / 风险检查\n→ 指标与术语标准化\n→ 结构化解读结果",
+        fill="#eef5ff",
+        stroke="#4f7fdb",
+        color="#163d78",
+        font_size=18,
+    ),
+    bound_box(
+        1550,
+        805,
+        560,
+        250,
+        "中医舌诊|TCM_TONGUE_ASSESSMENT\n\n体质症候问答 → 阶段性保存\n→ 舌象拍摄与图片质控\n→ 调用现有舌诊 MCP\n→ 问答与舌象融合结果",
+        fill="#fff2f1",
+        stroke="#d45b61",
+        color="#7c3036",
+        font_size=18,
+    ),
+    bound_box(
+        1550,
+        1120,
+        560,
+        175,
+        "共同异常与恢复\n信息不足:继续追问|图片问题:重新上传\n工具失败:保留上下文重试|医疗风险:中止普通流程\n必要时转急诊、人工或线下处理",
+        fill="#fff4e8",
+        stroke="#f0a020",
+        color="#754500",
+        font_size=16,
+    ),
+    bound_box(
+        2250,
+        430,
+        390,
+        330,
+        "统一结果与 UI 组件\n\n挂号确认与结果卡\n报告风险与指标卡\n舌诊特征与建议卡\n失败 / 重试 / 转人工状态\n\n任务结果不只保留在对话中",
+        fill="#e9fbfc",
+        stroke="#2fc9d2",
+        color="#115e64",
+        font_size=18,
+    ),
+    bound_box(
+        2750,
+        430,
+        360,
+        220,
+        "健康记录\n\n保存完成结果\n保存未完成任务\n按挂号 / 报告 / 中医分类\n支持查看与继续",
+        fill="#ffffff",
+        stroke="#2b1f99",
+        color="#21147d",
+        font_size=18,
+    ),
+    bound_box(
+        2750,
+        760,
+        360,
+        220,
+        "首页状态与待办\n\n明日预约\n新报告或解读结果\n继续未完成舌诊\n失败任务重试",
+        fill="#f1f0ff",
+        stroke="#2b1f99",
+        color="#21147d",
+        font_size=18,
+    ),
+    free_text(
+        2225,
+        1080,
+        800,
+        60,
+        "结果回流后,患者可从首页待办或健康记录继续原任务,也可以重新发起服务。",
+        size=17,
+        color="#69708a",
+        align="center",
+    ),
+    arrow(410, 290, [[0, 0], [90, 180]], color="#2b1f99"),
+    arrow(410, 465, [[0, 0], [90, 60]], color="#69708a"),
+    arrow(410, 640, [[0, 0], [90, -60]], color="#2fc9d2"),
+    arrow(410, 815, [[0, 0], [90, -180]], color="#69708a"),
+    arrow(880, 565, [[0, 0], [110, 0]], color="#2b1f99", stroke_width=3),
+    arrow(1430, 430, [[0, 0], [120, -140]], color="#2b1f99"),
+    arrow(1430, 565, [[0, 0], [120, 45]], color="#4f7fdb"),
+    arrow(1430, 700, [[0, 0], [120, 230]], color="#d45b61"),
+    arrow(2110, 290, [[0, 0], [140, 240]], color="#2b1f99"),
+    arrow(2110, 610, [[0, 0], [140, 0]], color="#4f7fdb"),
+    arrow(2110, 930, [[0, 0], [140, -240]], color="#d45b61"),
+    arrow(1825, 415, [[0, 0], [0, 705]], color="#f0a020", dashed=True),
+    arrow(1825, 735, [[0, 0], [0, 385]], color="#f0a020", dashed=True),
+    arrow(1825, 1055, [[0, 0], [0, 65]], color="#f0a020", dashed=True),
+    arrow(1550, 1210, [[0, 0], [-120, 0], [-120, -325]], color="#f0a020", dashed=True),
+    arrow(2640, 595, [[0, 0], [110, -55]], color="#2fc9d2", stroke_width=3),
+    arrow(2930, 650, [[0, 0], [0, 110]], color="#2b1f99", stroke_width=3),
+    arrow(
+        2930,
+        980,
+        [[0, 0], [0, 390], [-2690, 390], [-2690, -105]],
+        color="#2b1f99",
+        dashed=True,
+    ),
+]
+
+flattened: list[dict] = []
+for element in elements:
+    if isinstance(element, (tuple, list)):
+        flattened.extend(element)
+    else:
+        flattened.append(element)
+
+result = {
+    "type": "excalidraw",
+    "version": 2,
+    "source": "https://excalidraw.com",
+    "elements": flattened,
+    "appState": {
+        "viewBackgroundColor": "#f7fbff",
+        "gridSize": 20,
+    },
+    "files": {},
+}
+
+assert all(isinstance(element, dict) for element in flattened)
+assert len({element["id"] for element in flattened}) == len(flattened)
+assert all(
+    element.get("fontFamily") == 5
+    for element in flattened
+    if element.get("type") == "text"
+)
+for element in flattened:
+    if element.get("type") == "rectangle":
+        assert element.get("boundElements"), f"Unbound rectangle: {element['id']}"
+        text_id = element["boundElements"][0]["id"]
+        child = next(item for item in flattened if item["id"] == text_id)
+        assert child.get("containerId") == element["id"]
+        assert child.get("groupIds") == element.get("groupIds")
+
+OUTPUT.write_text(json.dumps(result, ensure_ascii=False, indent=2), encoding="utf-8")
+json.loads(OUTPUT.read_text(encoding="utf-8"))
+print(OUTPUT)

+ 2144 - 0
docs/p0-mobile/医梦患者智能服务门户_P0客户端总交互流程.excalidraw

@@ -0,0 +1,2144 @@
+{
+  "type": "excalidraw",
+  "version": 2,
+  "source": "https://excalidraw.com",
+  "elements": [
+    {
+      "id": "label-2001",
+      "type": "text",
+      "x": 70,
+      "y": 35,
+      "width": 2100,
+      "height": 60,
+      "angle": 0,
+      "strokeColor": "#21147d",
+      "backgroundColor": "transparent",
+      "fillStyle": "solid",
+      "strokeWidth": 2,
+      "strokeStyle": "solid",
+      "roughness": 1,
+      "opacity": 100,
+      "groupIds": [],
+      "frameId": null,
+      "index": "a3",
+      "roundness": null,
+      "seed": 12302000,
+      "version": 1,
+      "versionNonce": 12302001,
+      "isDeleted": false,
+      "boundElements": null,
+      "updated": 1706659200000,
+      "link": null,
+      "locked": false,
+      "text": "医梦患者智能服务门户|P0 客户端总交互流程",
+      "fontSize": 34,
+      "fontFamily": 5,
+      "textAlign": "left",
+      "verticalAlign": "top",
+      "containerId": null
+    },
+    {
+      "id": "label-2002",
+      "type": "text",
+      "x": 70,
+      "y": 98,
+      "width": 2400,
+      "height": 42,
+      "angle": 0,
+      "strokeColor": "#69708a",
+      "backgroundColor": "transparent",
+      "fillStyle": "solid",
+      "strokeWidth": 2,
+      "strokeStyle": "solid",
+      "roughness": 1,
+      "opacity": 100,
+      "groupIds": [],
+      "frameId": null,
+      "index": "a3",
+      "roundness": null,
+      "seed": 12308151,
+      "version": 1,
+      "versionNonce": 12308152,
+      "isDeleted": false,
+      "boundElements": null,
+      "updated": 1706659200000,
+      "link": null,
+      "locked": false,
+      "text": "单医院 · 固定 Mock 患者 · 语音优先 · 对话式任务界面 · 三智能体 · 结果回到健康记录与首页",
+      "fontSize": 18,
+      "fontFamily": 5,
+      "textAlign": "left",
+      "verticalAlign": "top",
+      "containerId": null
+    },
+    {
+      "id": "label-2003",
+      "type": "text",
+      "x": 70,
+      "y": 165,
+      "width": 340,
+      "height": 36,
+      "angle": 0,
+      "strokeColor": "#21147d",
+      "backgroundColor": "transparent",
+      "fillStyle": "solid",
+      "strokeWidth": 2,
+      "strokeStyle": "solid",
+      "roughness": 1,
+      "opacity": 100,
+      "groupIds": [],
+      "frameId": null,
+      "index": "a3",
+      "roundness": null,
+      "seed": 12314302,
+      "version": 1,
+      "versionNonce": 12314303,
+      "isDeleted": false,
+      "boundElements": null,
+      "updated": 1706659200000,
+      "link": null,
+      "locked": false,
+      "text": "① 发现与唤起",
+      "fontSize": 20,
+      "fontFamily": 5,
+      "textAlign": "left",
+      "verticalAlign": "top",
+      "containerId": null
+    },
+    {
+      "id": "label-2004",
+      "type": "text",
+      "x": 500,
+      "y": 165,
+      "width": 380,
+      "height": 36,
+      "angle": 0,
+      "strokeColor": "#21147d",
+      "backgroundColor": "transparent",
+      "fillStyle": "solid",
+      "strokeWidth": 2,
+      "strokeStyle": "solid",
+      "roughness": 1,
+      "opacity": 100,
+      "groupIds": [],
+      "frameId": null,
+      "index": "a3",
+      "roundness": null,
+      "seed": 12320453,
+      "version": 1,
+      "versionNonce": 12320454,
+      "isDeleted": false,
+      "boundElements": null,
+      "updated": 1706659200000,
+      "link": null,
+      "locked": false,
+      "text": "② 路由与任务启动",
+      "fontSize": 20,
+      "fontFamily": 5,
+      "textAlign": "left",
+      "verticalAlign": "top",
+      "containerId": null
+    },
+    {
+      "id": "label-2005",
+      "type": "text",
+      "x": 990,
+      "y": 165,
+      "width": 440,
+      "height": 36,
+      "angle": 0,
+      "strokeColor": "#21147d",
+      "backgroundColor": "transparent",
+      "fillStyle": "solid",
+      "strokeWidth": 2,
+      "strokeStyle": "solid",
+      "roughness": 1,
+      "opacity": 100,
+      "groupIds": [],
+      "frameId": null,
+      "index": "a3",
+      "roundness": null,
+      "seed": 12326604,
+      "version": 1,
+      "versionNonce": 12326605,
+      "isDeleted": false,
+      "boundElements": null,
+      "updated": 1706659200000,
+      "link": null,
+      "locked": false,
+      "text": "③ 对话式任务界面",
+      "fontSize": 20,
+      "fontFamily": 5,
+      "textAlign": "left",
+      "verticalAlign": "top",
+      "containerId": null
+    },
+    {
+      "id": "label-2006",
+      "type": "text",
+      "x": 1550,
+      "y": 110,
+      "width": 560,
+      "height": 36,
+      "angle": 0,
+      "strokeColor": "#21147d",
+      "backgroundColor": "transparent",
+      "fillStyle": "solid",
+      "strokeWidth": 2,
+      "strokeStyle": "solid",
+      "roughness": 1,
+      "opacity": 100,
+      "groupIds": [],
+      "frameId": null,
+      "index": "a3",
+      "roundness": null,
+      "seed": 12332755,
+      "version": 1,
+      "versionNonce": 12332756,
+      "isDeleted": false,
+      "boundElements": null,
+      "updated": 1706659200000,
+      "link": null,
+      "locked": false,
+      "text": "④ 三个 P0 智能体",
+      "fontSize": 20,
+      "fontFamily": 5,
+      "textAlign": "left",
+      "verticalAlign": "top",
+      "containerId": null
+    },
+    {
+      "id": "label-2007",
+      "type": "text",
+      "x": 2250,
+      "y": 350,
+      "width": 860,
+      "height": 36,
+      "angle": 0,
+      "strokeColor": "#21147d",
+      "backgroundColor": "transparent",
+      "fillStyle": "solid",
+      "strokeWidth": 2,
+      "strokeStyle": "solid",
+      "roughness": 1,
+      "opacity": 100,
+      "groupIds": [],
+      "frameId": null,
+      "index": "a3",
+      "roundness": null,
+      "seed": 12338906,
+      "version": 1,
+      "versionNonce": 12338907,
+      "isDeleted": false,
+      "boundElements": null,
+      "updated": 1706659200000,
+      "link": null,
+      "locked": false,
+      "text": "⑤ 结果与患者状态回流",
+      "fontSize": 20,
+      "fontFamily": 5,
+      "textAlign": "left",
+      "verticalAlign": "top",
+      "containerId": null
+    },
+    {
+      "id": "box-2008",
+      "type": "rectangle",
+      "x": 70,
+      "y": 230,
+      "width": 340,
+      "height": 120,
+      "angle": 0,
+      "strokeColor": "#2b1f99",
+      "backgroundColor": "#f1f0ff",
+      "fillStyle": "solid",
+      "strokeWidth": 2,
+      "strokeStyle": "solid",
+      "roughness": 1,
+      "opacity": 100,
+      "groupIds": [
+        "group-2010"
+      ],
+      "frameId": null,
+      "index": "a0",
+      "roundness": {
+        "type": 3
+      },
+      "seed": 15917190,
+      "version": 1,
+      "versionNonce": 15917191,
+      "isDeleted": false,
+      "boundElements": [
+        {
+          "type": "text",
+          "id": "text-2009"
+        }
+      ],
+      "updated": 1706659200000,
+      "link": null,
+      "locked": false,
+      "text": null,
+      "fontSize": null,
+      "fontFamily": null,
+      "textAlign": null,
+      "verticalAlign": null
+    },
+    {
+      "id": "text-2009",
+      "type": "text",
+      "x": 84,
+      "y": 260.5,
+      "width": 312,
+      "height": 59,
+      "angle": 0,
+      "strokeColor": "#21147d",
+      "backgroundColor": "transparent",
+      "fillStyle": "solid",
+      "strokeWidth": 2,
+      "strokeStyle": "solid",
+      "roughness": 1,
+      "opacity": 100,
+      "groupIds": [
+        "group-2010"
+      ],
+      "frameId": null,
+      "index": "a3",
+      "roundness": null,
+      "seed": 15917192,
+      "version": 1,
+      "versionNonce": 15917193,
+      "isDeleted": false,
+      "boundElements": null,
+      "updated": 1706659200000,
+      "link": null,
+      "locked": false,
+      "text": "首页统一语音入口\n不知道使用哪项服务",
+      "fontSize": 19,
+      "fontFamily": 5,
+      "textAlign": "center",
+      "verticalAlign": "middle",
+      "containerId": "box-2008"
+    },
+    {
+      "id": "box-2011",
+      "type": "rectangle",
+      "x": 70,
+      "y": 405,
+      "width": 340,
+      "height": 120,
+      "angle": 0,
+      "strokeColor": "#9ea9cc",
+      "backgroundColor": "#ffffff",
+      "fillStyle": "solid",
+      "strokeWidth": 2,
+      "strokeStyle": "solid",
+      "roughness": 1,
+      "opacity": 100,
+      "groupIds": [
+        "group-2013"
+      ],
+      "frameId": null,
+      "index": "a0",
+      "roundness": {
+        "type": 3
+      },
+      "seed": 15940947,
+      "version": 1,
+      "versionNonce": 15940948,
+      "isDeleted": false,
+      "boundElements": [
+        {
+          "type": "text",
+          "id": "text-2012"
+        }
+      ],
+      "updated": 1706659200000,
+      "link": null,
+      "locked": false,
+      "text": null,
+      "fontSize": null,
+      "fontFamily": null,
+      "textAlign": null,
+      "verticalAlign": null
+    },
+    {
+      "id": "text-2012",
+      "type": "text",
+      "x": 84,
+      "y": 437.0,
+      "width": 312,
+      "height": 56,
+      "angle": 0,
+      "strokeColor": "#16133a",
+      "backgroundColor": "transparent",
+      "fillStyle": "solid",
+      "strokeWidth": 2,
+      "strokeStyle": "solid",
+      "roughness": 1,
+      "opacity": 100,
+      "groupIds": [
+        "group-2013"
+      ],
+      "frameId": null,
+      "index": "a3",
+      "roundness": null,
+      "seed": 15940949,
+      "version": 1,
+      "versionNonce": 15940950,
+      "isDeleted": false,
+      "boundElements": null,
+      "updated": 1706659200000,
+      "link": null,
+      "locked": false,
+      "text": "首页 / 服务中心卡片\n明确选择挂号、报告或舌诊",
+      "fontSize": 18,
+      "fontFamily": 5,
+      "textAlign": "center",
+      "verticalAlign": "middle",
+      "containerId": "box-2011"
+    },
+    {
+      "id": "box-2014",
+      "type": "rectangle",
+      "x": 70,
+      "y": 580,
+      "width": 340,
+      "height": 120,
+      "angle": 0,
+      "strokeColor": "#2fc9d2",
+      "backgroundColor": "#e9fbfc",
+      "fillStyle": "solid",
+      "strokeWidth": 2,
+      "strokeStyle": "solid",
+      "roughness": 1,
+      "opacity": 100,
+      "groupIds": [
+        "group-2016"
+      ],
+      "frameId": null,
+      "index": "a0",
+      "roundness": {
+        "type": 3
+      },
+      "seed": 15964704,
+      "version": 1,
+      "versionNonce": 15964705,
+      "isDeleted": false,
+      "boundElements": [
+        {
+          "type": "text",
+          "id": "text-2015"
+        }
+      ],
+      "updated": 1706659200000,
+      "link": null,
+      "locked": false,
+      "text": null,
+      "fontSize": null,
+      "fontFamily": null,
+      "textAlign": null,
+      "verticalAlign": null
+    },
+    {
+      "id": "text-2015",
+      "type": "text",
+      "x": 84,
+      "y": 612.0,
+      "width": 312,
+      "height": 56,
+      "angle": 0,
+      "strokeColor": "#115e64",
+      "backgroundColor": "transparent",
+      "fillStyle": "solid",
+      "strokeWidth": 2,
+      "strokeStyle": "solid",
+      "roughness": 1,
+      "opacity": 100,
+      "groupIds": [
+        "group-2016"
+      ],
+      "frameId": null,
+      "index": "a3",
+      "roundness": null,
+      "seed": 15964706,
+      "version": 1,
+      "versionNonce": 15964707,
+      "isDeleted": false,
+      "boundElements": null,
+      "updated": 1706659200000,
+      "link": null,
+      "locked": false,
+      "text": "患者状态与待办\n预约、新报告、继续舌诊、失败重试",
+      "fontSize": 18,
+      "fontFamily": 5,
+      "textAlign": "center",
+      "verticalAlign": "middle",
+      "containerId": "box-2014"
+    },
+    {
+      "id": "box-2017",
+      "type": "rectangle",
+      "x": 70,
+      "y": 755,
+      "width": 340,
+      "height": 120,
+      "angle": 0,
+      "strokeColor": "#9ea9cc",
+      "backgroundColor": "#ffffff",
+      "fillStyle": "solid",
+      "strokeWidth": 2,
+      "strokeStyle": "solid",
+      "roughness": 1,
+      "opacity": 100,
+      "groupIds": [
+        "group-2019"
+      ],
+      "frameId": null,
+      "index": "a0",
+      "roundness": {
+        "type": 3
+      },
+      "seed": 15988461,
+      "version": 1,
+      "versionNonce": 15988462,
+      "isDeleted": false,
+      "boundElements": [
+        {
+          "type": "text",
+          "id": "text-2018"
+        }
+      ],
+      "updated": 1706659200000,
+      "link": null,
+      "locked": false,
+      "text": null,
+      "fontSize": null,
+      "fontFamily": null,
+      "textAlign": null,
+      "verticalAlign": null
+    },
+    {
+      "id": "text-2018",
+      "type": "text",
+      "x": 84,
+      "y": 787.0,
+      "width": 312,
+      "height": 56,
+      "angle": 0,
+      "strokeColor": "#16133a",
+      "backgroundColor": "transparent",
+      "fillStyle": "solid",
+      "strokeWidth": 2,
+      "strokeStyle": "solid",
+      "roughness": 1,
+      "opacity": 100,
+      "groupIds": [
+        "group-2019"
+      ],
+      "frameId": null,
+      "index": "a3",
+      "roundness": null,
+      "seed": 15988463,
+      "version": 1,
+      "versionNonce": 15988464,
+      "isDeleted": false,
+      "boundElements": null,
+      "updated": 1706659200000,
+      "link": null,
+      "locked": false,
+      "text": "健康记录 / 业务内嵌\n查看结果、恢复任务、再次办理",
+      "fontSize": 18,
+      "fontFamily": 5,
+      "textAlign": "center",
+      "verticalAlign": "middle",
+      "containerId": "box-2017"
+    },
+    {
+      "id": "box-2020",
+      "type": "rectangle",
+      "x": 500,
+      "y": 300,
+      "width": 380,
+      "height": 530,
+      "angle": 0,
+      "strokeColor": "#21147d",
+      "backgroundColor": "#2b1f99",
+      "fillStyle": "solid",
+      "strokeWidth": 2,
+      "strokeStyle": "solid",
+      "roughness": 0,
+      "opacity": 100,
+      "groupIds": [
+        "group-2022"
+      ],
+      "frameId": null,
+      "index": "a0",
+      "roundness": {
+        "type": 3
+      },
+      "seed": 16012218,
+      "version": 1,
+      "versionNonce": 16012219,
+      "isDeleted": false,
+      "boundElements": [
+        {
+          "type": "text",
+          "id": "text-2021"
+        }
+      ],
+      "updated": 1706659200000,
+      "link": null,
+      "locked": false,
+      "text": null,
+      "fontSize": null,
+      "fontFamily": null,
+      "textAlign": null,
+      "verticalAlign": null
+    },
+    {
+      "id": "text-2021",
+      "type": "text",
+      "x": 514,
+      "y": 427.5,
+      "width": 352,
+      "height": 275,
+      "angle": 0,
+      "strokeColor": "#ffffff",
+      "backgroundColor": "transparent",
+      "fillStyle": "solid",
+      "strokeWidth": 2,
+      "strokeStyle": "solid",
+      "roughness": 1,
+      "opacity": 100,
+      "groupIds": [
+        "group-2022"
+      ],
+      "frameId": null,
+      "index": "a3",
+      "roundness": null,
+      "seed": 16012220,
+      "version": 1,
+      "versionNonce": 16012221,
+      "isDeleted": false,
+      "boundElements": null,
+      "updated": 1706659200000,
+      "link": null,
+      "locked": false,
+      "text": "统一助手 / 任务启动器\n\n① 判断入口来源\n② 识别自然语言意图\n③ 加载医院与患者上下文\n④ 医疗安全前置判断\n⑤ 确认目标服务\n\n明确能力:直接创建任务\n自然语言:确认后创建任务\n已有 taskId:恢复原任务状态",
+      "fontSize": 18,
+      "fontFamily": 5,
+      "textAlign": "center",
+      "verticalAlign": "middle",
+      "containerId": "box-2020"
+    },
+    {
+      "id": "box-2023",
+      "type": "rectangle",
+      "x": 990,
+      "y": 245,
+      "width": 440,
+      "height": 640,
+      "angle": 0,
+      "strokeColor": "#2b1f99",
+      "backgroundColor": "#f7f8ff",
+      "fillStyle": "solid",
+      "strokeWidth": 2,
+      "strokeStyle": "solid",
+      "roughness": 0,
+      "opacity": 100,
+      "groupIds": [
+        "group-2025"
+      ],
+      "frameId": null,
+      "index": "a0",
+      "roundness": {
+        "type": 3
+      },
+      "seed": 16035975,
+      "version": 1,
+      "versionNonce": 16035976,
+      "isDeleted": false,
+      "boundElements": [
+        {
+          "type": "text",
+          "id": "text-2024"
+        }
+      ],
+      "updated": 1706659200000,
+      "link": null,
+      "locked": false,
+      "text": null,
+      "fontSize": null,
+      "fontFamily": null,
+      "textAlign": null,
+      "verticalAlign": null
+    },
+    {
+      "id": "text-2024",
+      "type": "text",
+      "x": 1004,
+      "y": 330.5,
+      "width": 412,
+      "height": 469,
+      "angle": 0,
+      "strokeColor": "#21147d",
+      "backgroundColor": "transparent",
+      "fillStyle": "solid",
+      "strokeWidth": 2,
+      "strokeStyle": "solid",
+      "roughness": 1,
+      "opacity": 100,
+      "groupIds": [
+        "group-2025"
+      ],
+      "frameId": null,
+      "index": "a3",
+      "roundness": null,
+      "seed": 16035977,
+      "version": 1,
+      "versionNonce": 16035978,
+      "isDeleted": false,
+      "boundElements": null,
+      "updated": 1706659200000,
+      "link": null,
+      "locked": false,
+      "text": "统一对话式任务界面\n\n最近对话\n患者原话 + 助手理解\n\n已收集信息\n完整度 · 缺失项 · 修改入口\n\n当前唯一任务\n一次只追问或处理一件事\n\n语音主输入\n文字备选 · 快捷选项 · 上传\n\n完整性与安全检查\n通过后才查询、分析或执行\n\n操作记录\n转写、规则与工具步骤可展开",
+      "fontSize": 18,
+      "fontFamily": 5,
+      "textAlign": "center",
+      "verticalAlign": "middle",
+      "containerId": "box-2023"
+    },
+    {
+      "id": "box-2026",
+      "type": "rectangle",
+      "x": 990,
+      "y": 970,
+      "width": 440,
+      "height": 185,
+      "angle": 0,
+      "strokeColor": "#9ea9cc",
+      "backgroundColor": "#f7fbff",
+      "fillStyle": "solid",
+      "strokeWidth": 2,
+      "strokeStyle": "solid",
+      "roughness": 1,
+      "opacity": 100,
+      "groupIds": [
+        "group-2028"
+      ],
+      "frameId": null,
+      "index": "a0",
+      "roundness": {
+        "type": 3
+      },
+      "seed": 16059732,
+      "version": 1,
+      "versionNonce": 16059733,
+      "isDeleted": false,
+      "boundElements": [
+        {
+          "type": "text",
+          "id": "text-2027"
+        }
+      ],
+      "updated": 1706659200000,
+      "link": null,
+      "locked": false,
+      "text": null,
+      "fontSize": null,
+      "fontFamily": null,
+      "textAlign": null,
+      "verticalAlign": null
+    },
+    {
+      "id": "text-2027",
+      "type": "text",
+      "x": 1004,
+      "y": 1004.5,
+      "width": 412,
+      "height": 116,
+      "angle": 0,
+      "strokeColor": "#16133a",
+      "backgroundColor": "transparent",
+      "fillStyle": "solid",
+      "strokeWidth": 2,
+      "strokeStyle": "solid",
+      "roughness": 1,
+      "opacity": 100,
+      "groupIds": [
+        "group-2028"
+      ],
+      "frameId": null,
+      "index": "a3",
+      "roundness": null,
+      "seed": 16059734,
+      "version": 1,
+      "versionNonce": 16059735,
+      "isDeleted": false,
+      "boundElements": null,
+      "updated": 1706659200000,
+      "link": null,
+      "locked": false,
+      "text": "P0 固定运行上下文\n\n单家指定医院|固定本人 Mock 患者\n演示语音转写|FastGPT Workflow\n挂号与报告 Mock MCP|现有舌诊 MCP",
+      "fontSize": 16,
+      "fontFamily": 5,
+      "textAlign": "center",
+      "verticalAlign": "middle",
+      "containerId": "box-2026"
+    },
+    {
+      "id": "box-2029",
+      "type": "rectangle",
+      "x": 1550,
+      "y": 165,
+      "width": 560,
+      "height": 250,
+      "angle": 0,
+      "strokeColor": "#2b1f99",
+      "backgroundColor": "#f1f0ff",
+      "fillStyle": "solid",
+      "strokeWidth": 2,
+      "strokeStyle": "solid",
+      "roughness": 1,
+      "opacity": 100,
+      "groupIds": [
+        "group-2031"
+      ],
+      "frameId": null,
+      "index": "a0",
+      "roundness": {
+        "type": 3
+      },
+      "seed": 16083489,
+      "version": 1,
+      "versionNonce": 16083490,
+      "isDeleted": false,
+      "boundElements": [
+        {
+          "type": "text",
+          "id": "text-2030"
+        }
+      ],
+      "updated": 1706659200000,
+      "link": null,
+      "locked": false,
+      "text": null,
+      "fontSize": null,
+      "fontFamily": null,
+      "textAlign": null,
+      "verticalAlign": null
+    },
+    {
+      "id": "text-2030",
+      "type": "text",
+      "x": 1564,
+      "y": 213.5,
+      "width": 532,
+      "height": 153,
+      "angle": 0,
+      "strokeColor": "#21147d",
+      "backgroundColor": "transparent",
+      "fillStyle": "solid",
+      "strokeWidth": 2,
+      "strokeStyle": "solid",
+      "roughness": 1,
+      "opacity": 100,
+      "groupIds": [
+        "group-2031"
+      ],
+      "frameId": null,
+      "index": "a3",
+      "roundness": null,
+      "seed": 16083491,
+      "version": 1,
+      "versionNonce": 16083492,
+      "isDeleted": false,
+      "boundElements": null,
+      "updated": 1706659200000,
+      "link": null,
+      "locked": false,
+      "text": "智能分诊挂号|SMART_REGISTRATION\n\n急诊安全门禁 → 挂号条件补槽\n→ 医生与号源选择 → 独立确认\n→ Mock 锁号 / 挂号 / 支付\n→ 挂号结果",
+      "fontSize": 18,
+      "fontFamily": 5,
+      "textAlign": "center",
+      "verticalAlign": "middle",
+      "containerId": "box-2029"
+    },
+    {
+      "id": "box-2032",
+      "type": "rectangle",
+      "x": 1550,
+      "y": 485,
+      "width": 560,
+      "height": 250,
+      "angle": 0,
+      "strokeColor": "#4f7fdb",
+      "backgroundColor": "#eef5ff",
+      "fillStyle": "solid",
+      "strokeWidth": 2,
+      "strokeStyle": "solid",
+      "roughness": 1,
+      "opacity": 100,
+      "groupIds": [
+        "group-2034"
+      ],
+      "frameId": null,
+      "index": "a0",
+      "roundness": {
+        "type": 3
+      },
+      "seed": 16107246,
+      "version": 1,
+      "versionNonce": 16107247,
+      "isDeleted": false,
+      "boundElements": [
+        {
+          "type": "text",
+          "id": "text-2033"
+        }
+      ],
+      "updated": 1706659200000,
+      "link": null,
+      "locked": false,
+      "text": null,
+      "fontSize": null,
+      "fontFamily": null,
+      "textAlign": null,
+      "verticalAlign": null
+    },
+    {
+      "id": "text-2033",
+      "type": "text",
+      "x": 1564,
+      "y": 533.5,
+      "width": 532,
+      "height": 153,
+      "angle": 0,
+      "strokeColor": "#163d78",
+      "backgroundColor": "transparent",
+      "fillStyle": "solid",
+      "strokeWidth": 2,
+      "strokeStyle": "solid",
+      "roughness": 1,
+      "opacity": 100,
+      "groupIds": [
+        "group-2034"
+      ],
+      "frameId": null,
+      "index": "a3",
+      "roundness": null,
+      "seed": 16107248,
+      "version": 1,
+      "versionNonce": 16107249,
+      "isDeleted": false,
+      "boundElements": null,
+      "updated": 1706659200000,
+      "link": null,
+      "locked": false,
+      "text": "报告智能解读|REPORT_INTERPRETATION\n\n选择院内报告或上传 → 归属确认\n→ 文件质量 / OCR / 风险检查\n→ 指标与术语标准化\n→ 结构化解读结果",
+      "fontSize": 18,
+      "fontFamily": 5,
+      "textAlign": "center",
+      "verticalAlign": "middle",
+      "containerId": "box-2032"
+    },
+    {
+      "id": "box-2035",
+      "type": "rectangle",
+      "x": 1550,
+      "y": 805,
+      "width": 560,
+      "height": 250,
+      "angle": 0,
+      "strokeColor": "#d45b61",
+      "backgroundColor": "#fff2f1",
+      "fillStyle": "solid",
+      "strokeWidth": 2,
+      "strokeStyle": "solid",
+      "roughness": 1,
+      "opacity": 100,
+      "groupIds": [
+        "group-2037"
+      ],
+      "frameId": null,
+      "index": "a0",
+      "roundness": {
+        "type": 3
+      },
+      "seed": 16131003,
+      "version": 1,
+      "versionNonce": 16131004,
+      "isDeleted": false,
+      "boundElements": [
+        {
+          "type": "text",
+          "id": "text-2036"
+        }
+      ],
+      "updated": 1706659200000,
+      "link": null,
+      "locked": false,
+      "text": null,
+      "fontSize": null,
+      "fontFamily": null,
+      "textAlign": null,
+      "verticalAlign": null
+    },
+    {
+      "id": "text-2036",
+      "type": "text",
+      "x": 1564,
+      "y": 853.5,
+      "width": 532,
+      "height": 153,
+      "angle": 0,
+      "strokeColor": "#7c3036",
+      "backgroundColor": "transparent",
+      "fillStyle": "solid",
+      "strokeWidth": 2,
+      "strokeStyle": "solid",
+      "roughness": 1,
+      "opacity": 100,
+      "groupIds": [
+        "group-2037"
+      ],
+      "frameId": null,
+      "index": "a3",
+      "roundness": null,
+      "seed": 16131005,
+      "version": 1,
+      "versionNonce": 16131006,
+      "isDeleted": false,
+      "boundElements": null,
+      "updated": 1706659200000,
+      "link": null,
+      "locked": false,
+      "text": "中医舌诊|TCM_TONGUE_ASSESSMENT\n\n体质症候问答 → 阶段性保存\n→ 舌象拍摄与图片质控\n→ 调用现有舌诊 MCP\n→ 问答与舌象融合结果",
+      "fontSize": 18,
+      "fontFamily": 5,
+      "textAlign": "center",
+      "verticalAlign": "middle",
+      "containerId": "box-2035"
+    },
+    {
+      "id": "box-2038",
+      "type": "rectangle",
+      "x": 1550,
+      "y": 1120,
+      "width": 560,
+      "height": 175,
+      "angle": 0,
+      "strokeColor": "#f0a020",
+      "backgroundColor": "#fff4e8",
+      "fillStyle": "solid",
+      "strokeWidth": 2,
+      "strokeStyle": "solid",
+      "roughness": 1,
+      "opacity": 100,
+      "groupIds": [
+        "group-2040"
+      ],
+      "frameId": null,
+      "index": "a0",
+      "roundness": {
+        "type": 3
+      },
+      "seed": 16154760,
+      "version": 1,
+      "versionNonce": 16154761,
+      "isDeleted": false,
+      "boundElements": [
+        {
+          "type": "text",
+          "id": "text-2039"
+        }
+      ],
+      "updated": 1706659200000,
+      "link": null,
+      "locked": false,
+      "text": null,
+      "fontSize": null,
+      "fontFamily": null,
+      "textAlign": null,
+      "verticalAlign": null
+    },
+    {
+      "id": "text-2039",
+      "type": "text",
+      "x": 1564,
+      "y": 1160.5,
+      "width": 532,
+      "height": 94,
+      "angle": 0,
+      "strokeColor": "#754500",
+      "backgroundColor": "transparent",
+      "fillStyle": "solid",
+      "strokeWidth": 2,
+      "strokeStyle": "solid",
+      "roughness": 1,
+      "opacity": 100,
+      "groupIds": [
+        "group-2040"
+      ],
+      "frameId": null,
+      "index": "a3",
+      "roundness": null,
+      "seed": 16154762,
+      "version": 1,
+      "versionNonce": 16154763,
+      "isDeleted": false,
+      "boundElements": null,
+      "updated": 1706659200000,
+      "link": null,
+      "locked": false,
+      "text": "共同异常与恢复\n信息不足:继续追问|图片问题:重新上传\n工具失败:保留上下文重试|医疗风险:中止普通流程\n必要时转急诊、人工或线下处理",
+      "fontSize": 16,
+      "fontFamily": 5,
+      "textAlign": "center",
+      "verticalAlign": "middle",
+      "containerId": "box-2038"
+    },
+    {
+      "id": "box-2041",
+      "type": "rectangle",
+      "x": 2250,
+      "y": 430,
+      "width": 390,
+      "height": 330,
+      "angle": 0,
+      "strokeColor": "#2fc9d2",
+      "backgroundColor": "#e9fbfc",
+      "fillStyle": "solid",
+      "strokeWidth": 2,
+      "strokeStyle": "solid",
+      "roughness": 1,
+      "opacity": 100,
+      "groupIds": [
+        "group-2043"
+      ],
+      "frameId": null,
+      "index": "a0",
+      "roundness": {
+        "type": 3
+      },
+      "seed": 16178517,
+      "version": 1,
+      "versionNonce": 16178518,
+      "isDeleted": false,
+      "boundElements": [
+        {
+          "type": "text",
+          "id": "text-2042"
+        }
+      ],
+      "updated": 1706659200000,
+      "link": null,
+      "locked": false,
+      "text": null,
+      "fontSize": null,
+      "fontFamily": null,
+      "textAlign": null,
+      "verticalAlign": null
+    },
+    {
+      "id": "text-2042",
+      "type": "text",
+      "x": 2264,
+      "y": 494.0,
+      "width": 362,
+      "height": 202,
+      "angle": 0,
+      "strokeColor": "#115e64",
+      "backgroundColor": "transparent",
+      "fillStyle": "solid",
+      "strokeWidth": 2,
+      "strokeStyle": "solid",
+      "roughness": 1,
+      "opacity": 100,
+      "groupIds": [
+        "group-2043"
+      ],
+      "frameId": null,
+      "index": "a3",
+      "roundness": null,
+      "seed": 16178519,
+      "version": 1,
+      "versionNonce": 16178520,
+      "isDeleted": false,
+      "boundElements": null,
+      "updated": 1706659200000,
+      "link": null,
+      "locked": false,
+      "text": "统一结果与 UI 组件\n\n挂号确认与结果卡\n报告风险与指标卡\n舌诊特征与建议卡\n失败 / 重试 / 转人工状态\n\n任务结果不只保留在对话中",
+      "fontSize": 18,
+      "fontFamily": 5,
+      "textAlign": "center",
+      "verticalAlign": "middle",
+      "containerId": "box-2041"
+    },
+    {
+      "id": "box-2044",
+      "type": "rectangle",
+      "x": 2750,
+      "y": 430,
+      "width": 360,
+      "height": 220,
+      "angle": 0,
+      "strokeColor": "#2b1f99",
+      "backgroundColor": "#ffffff",
+      "fillStyle": "solid",
+      "strokeWidth": 2,
+      "strokeStyle": "solid",
+      "roughness": 1,
+      "opacity": 100,
+      "groupIds": [
+        "group-2046"
+      ],
+      "frameId": null,
+      "index": "a0",
+      "roundness": {
+        "type": 3
+      },
+      "seed": 16202274,
+      "version": 1,
+      "versionNonce": 16202275,
+      "isDeleted": false,
+      "boundElements": [
+        {
+          "type": "text",
+          "id": "text-2045"
+        }
+      ],
+      "updated": 1706659200000,
+      "link": null,
+      "locked": false,
+      "text": null,
+      "fontSize": null,
+      "fontFamily": null,
+      "textAlign": null,
+      "verticalAlign": null
+    },
+    {
+      "id": "text-2045",
+      "type": "text",
+      "x": 2764,
+      "y": 463.5,
+      "width": 332,
+      "height": 153,
+      "angle": 0,
+      "strokeColor": "#21147d",
+      "backgroundColor": "transparent",
+      "fillStyle": "solid",
+      "strokeWidth": 2,
+      "strokeStyle": "solid",
+      "roughness": 1,
+      "opacity": 100,
+      "groupIds": [
+        "group-2046"
+      ],
+      "frameId": null,
+      "index": "a3",
+      "roundness": null,
+      "seed": 16202276,
+      "version": 1,
+      "versionNonce": 16202277,
+      "isDeleted": false,
+      "boundElements": null,
+      "updated": 1706659200000,
+      "link": null,
+      "locked": false,
+      "text": "健康记录\n\n保存完成结果\n保存未完成任务\n按挂号 / 报告 / 中医分类\n支持查看与继续",
+      "fontSize": 18,
+      "fontFamily": 5,
+      "textAlign": "center",
+      "verticalAlign": "middle",
+      "containerId": "box-2044"
+    },
+    {
+      "id": "box-2047",
+      "type": "rectangle",
+      "x": 2750,
+      "y": 760,
+      "width": 360,
+      "height": 220,
+      "angle": 0,
+      "strokeColor": "#2b1f99",
+      "backgroundColor": "#f1f0ff",
+      "fillStyle": "solid",
+      "strokeWidth": 2,
+      "strokeStyle": "solid",
+      "roughness": 1,
+      "opacity": 100,
+      "groupIds": [
+        "group-2049"
+      ],
+      "frameId": null,
+      "index": "a0",
+      "roundness": {
+        "type": 3
+      },
+      "seed": 16226031,
+      "version": 1,
+      "versionNonce": 16226032,
+      "isDeleted": false,
+      "boundElements": [
+        {
+          "type": "text",
+          "id": "text-2048"
+        }
+      ],
+      "updated": 1706659200000,
+      "link": null,
+      "locked": false,
+      "text": null,
+      "fontSize": null,
+      "fontFamily": null,
+      "textAlign": null,
+      "verticalAlign": null
+    },
+    {
+      "id": "text-2048",
+      "type": "text",
+      "x": 2764,
+      "y": 793.5,
+      "width": 332,
+      "height": 153,
+      "angle": 0,
+      "strokeColor": "#21147d",
+      "backgroundColor": "transparent",
+      "fillStyle": "solid",
+      "strokeWidth": 2,
+      "strokeStyle": "solid",
+      "roughness": 1,
+      "opacity": 100,
+      "groupIds": [
+        "group-2049"
+      ],
+      "frameId": null,
+      "index": "a3",
+      "roundness": null,
+      "seed": 16226033,
+      "version": 1,
+      "versionNonce": 16226034,
+      "isDeleted": false,
+      "boundElements": null,
+      "updated": 1706659200000,
+      "link": null,
+      "locked": false,
+      "text": "首页状态与待办\n\n明日预约\n新报告或解读结果\n继续未完成舌诊\n失败任务重试",
+      "fontSize": 18,
+      "fontFamily": 5,
+      "textAlign": "center",
+      "verticalAlign": "middle",
+      "containerId": "box-2047"
+    },
+    {
+      "id": "label-2050",
+      "type": "text",
+      "x": 2225,
+      "y": 1080,
+      "width": 800,
+      "height": 60,
+      "angle": 0,
+      "strokeColor": "#69708a",
+      "backgroundColor": "transparent",
+      "fillStyle": "solid",
+      "strokeWidth": 2,
+      "strokeStyle": "solid",
+      "roughness": 1,
+      "opacity": 100,
+      "groupIds": [],
+      "frameId": null,
+      "index": "a3",
+      "roundness": null,
+      "seed": 12603399,
+      "version": 1,
+      "versionNonce": 12603400,
+      "isDeleted": false,
+      "boundElements": null,
+      "updated": 1706659200000,
+      "link": null,
+      "locked": false,
+      "text": "结果回流后,患者可从首页待办或健康记录继续原任务,也可以重新发起服务。",
+      "fontSize": 17,
+      "fontFamily": 5,
+      "textAlign": "center",
+      "verticalAlign": "top",
+      "containerId": null
+    },
+    {
+      "id": "arrow-2051",
+      "type": "arrow",
+      "x": 410,
+      "y": 290,
+      "width": 90,
+      "height": 180,
+      "angle": 0,
+      "strokeColor": "#2b1f99",
+      "backgroundColor": "transparent",
+      "fillStyle": "solid",
+      "strokeWidth": 2,
+      "strokeStyle": "solid",
+      "roughness": 1,
+      "opacity": 100,
+      "groupIds": [],
+      "frameId": null,
+      "index": "a2",
+      "roundness": {
+        "type": 2
+      },
+      "seed": 8755550,
+      "version": 1,
+      "versionNonce": 8755551,
+      "isDeleted": false,
+      "boundElements": null,
+      "updated": 1706659200000,
+      "link": null,
+      "locked": false,
+      "points": [
+        [
+          0,
+          0
+        ],
+        [
+          90,
+          180
+        ]
+      ],
+      "startBinding": null,
+      "endBinding": null
+    },
+    {
+      "id": "arrow-2052",
+      "type": "arrow",
+      "x": 410,
+      "y": 465,
+      "width": 90,
+      "height": 60,
+      "angle": 0,
+      "strokeColor": "#69708a",
+      "backgroundColor": "transparent",
+      "fillStyle": "solid",
+      "strokeWidth": 2,
+      "strokeStyle": "solid",
+      "roughness": 1,
+      "opacity": 100,
+      "groupIds": [],
+      "frameId": null,
+      "index": "a2",
+      "roundness": {
+        "type": 2
+      },
+      "seed": 8759821,
+      "version": 1,
+      "versionNonce": 8759822,
+      "isDeleted": false,
+      "boundElements": null,
+      "updated": 1706659200000,
+      "link": null,
+      "locked": false,
+      "points": [
+        [
+          0,
+          0
+        ],
+        [
+          90,
+          60
+        ]
+      ],
+      "startBinding": null,
+      "endBinding": null
+    },
+    {
+      "id": "arrow-2053",
+      "type": "arrow",
+      "x": 410,
+      "y": 640,
+      "width": 90,
+      "height": 60,
+      "angle": 0,
+      "strokeColor": "#2fc9d2",
+      "backgroundColor": "transparent",
+      "fillStyle": "solid",
+      "strokeWidth": 2,
+      "strokeStyle": "solid",
+      "roughness": 1,
+      "opacity": 100,
+      "groupIds": [],
+      "frameId": null,
+      "index": "a2",
+      "roundness": {
+        "type": 2
+      },
+      "seed": 8764092,
+      "version": 1,
+      "versionNonce": 8764093,
+      "isDeleted": false,
+      "boundElements": null,
+      "updated": 1706659200000,
+      "link": null,
+      "locked": false,
+      "points": [
+        [
+          0,
+          0
+        ],
+        [
+          90,
+          -60
+        ]
+      ],
+      "startBinding": null,
+      "endBinding": null
+    },
+    {
+      "id": "arrow-2054",
+      "type": "arrow",
+      "x": 410,
+      "y": 815,
+      "width": 90,
+      "height": 180,
+      "angle": 0,
+      "strokeColor": "#69708a",
+      "backgroundColor": "transparent",
+      "fillStyle": "solid",
+      "strokeWidth": 2,
+      "strokeStyle": "solid",
+      "roughness": 1,
+      "opacity": 100,
+      "groupIds": [],
+      "frameId": null,
+      "index": "a2",
+      "roundness": {
+        "type": 2
+      },
+      "seed": 8768363,
+      "version": 1,
+      "versionNonce": 8768364,
+      "isDeleted": false,
+      "boundElements": null,
+      "updated": 1706659200000,
+      "link": null,
+      "locked": false,
+      "points": [
+        [
+          0,
+          0
+        ],
+        [
+          90,
+          -180
+        ]
+      ],
+      "startBinding": null,
+      "endBinding": null
+    },
+    {
+      "id": "arrow-2055",
+      "type": "arrow",
+      "x": 880,
+      "y": 565,
+      "width": 110,
+      "height": 0,
+      "angle": 0,
+      "strokeColor": "#2b1f99",
+      "backgroundColor": "transparent",
+      "fillStyle": "solid",
+      "strokeWidth": 3,
+      "strokeStyle": "solid",
+      "roughness": 1,
+      "opacity": 100,
+      "groupIds": [],
+      "frameId": null,
+      "index": "a2",
+      "roundness": {
+        "type": 2
+      },
+      "seed": 8772634,
+      "version": 1,
+      "versionNonce": 8772635,
+      "isDeleted": false,
+      "boundElements": null,
+      "updated": 1706659200000,
+      "link": null,
+      "locked": false,
+      "points": [
+        [
+          0,
+          0
+        ],
+        [
+          110,
+          0
+        ]
+      ],
+      "startBinding": null,
+      "endBinding": null
+    },
+    {
+      "id": "arrow-2056",
+      "type": "arrow",
+      "x": 1430,
+      "y": 430,
+      "width": 120,
+      "height": 140,
+      "angle": 0,
+      "strokeColor": "#2b1f99",
+      "backgroundColor": "transparent",
+      "fillStyle": "solid",
+      "strokeWidth": 2,
+      "strokeStyle": "solid",
+      "roughness": 1,
+      "opacity": 100,
+      "groupIds": [],
+      "frameId": null,
+      "index": "a2",
+      "roundness": {
+        "type": 2
+      },
+      "seed": 8776905,
+      "version": 1,
+      "versionNonce": 8776906,
+      "isDeleted": false,
+      "boundElements": null,
+      "updated": 1706659200000,
+      "link": null,
+      "locked": false,
+      "points": [
+        [
+          0,
+          0
+        ],
+        [
+          120,
+          -140
+        ]
+      ],
+      "startBinding": null,
+      "endBinding": null
+    },
+    {
+      "id": "arrow-2057",
+      "type": "arrow",
+      "x": 1430,
+      "y": 565,
+      "width": 120,
+      "height": 45,
+      "angle": 0,
+      "strokeColor": "#4f7fdb",
+      "backgroundColor": "transparent",
+      "fillStyle": "solid",
+      "strokeWidth": 2,
+      "strokeStyle": "solid",
+      "roughness": 1,
+      "opacity": 100,
+      "groupIds": [],
+      "frameId": null,
+      "index": "a2",
+      "roundness": {
+        "type": 2
+      },
+      "seed": 8781176,
+      "version": 1,
+      "versionNonce": 8781177,
+      "isDeleted": false,
+      "boundElements": null,
+      "updated": 1706659200000,
+      "link": null,
+      "locked": false,
+      "points": [
+        [
+          0,
+          0
+        ],
+        [
+          120,
+          45
+        ]
+      ],
+      "startBinding": null,
+      "endBinding": null
+    },
+    {
+      "id": "arrow-2058",
+      "type": "arrow",
+      "x": 1430,
+      "y": 700,
+      "width": 120,
+      "height": 230,
+      "angle": 0,
+      "strokeColor": "#d45b61",
+      "backgroundColor": "transparent",
+      "fillStyle": "solid",
+      "strokeWidth": 2,
+      "strokeStyle": "solid",
+      "roughness": 1,
+      "opacity": 100,
+      "groupIds": [],
+      "frameId": null,
+      "index": "a2",
+      "roundness": {
+        "type": 2
+      },
+      "seed": 8785447,
+      "version": 1,
+      "versionNonce": 8785448,
+      "isDeleted": false,
+      "boundElements": null,
+      "updated": 1706659200000,
+      "link": null,
+      "locked": false,
+      "points": [
+        [
+          0,
+          0
+        ],
+        [
+          120,
+          230
+        ]
+      ],
+      "startBinding": null,
+      "endBinding": null
+    },
+    {
+      "id": "arrow-2059",
+      "type": "arrow",
+      "x": 2110,
+      "y": 290,
+      "width": 140,
+      "height": 240,
+      "angle": 0,
+      "strokeColor": "#2b1f99",
+      "backgroundColor": "transparent",
+      "fillStyle": "solid",
+      "strokeWidth": 2,
+      "strokeStyle": "solid",
+      "roughness": 1,
+      "opacity": 100,
+      "groupIds": [],
+      "frameId": null,
+      "index": "a2",
+      "roundness": {
+        "type": 2
+      },
+      "seed": 8789718,
+      "version": 1,
+      "versionNonce": 8789719,
+      "isDeleted": false,
+      "boundElements": null,
+      "updated": 1706659200000,
+      "link": null,
+      "locked": false,
+      "points": [
+        [
+          0,
+          0
+        ],
+        [
+          140,
+          240
+        ]
+      ],
+      "startBinding": null,
+      "endBinding": null
+    },
+    {
+      "id": "arrow-2060",
+      "type": "arrow",
+      "x": 2110,
+      "y": 610,
+      "width": 140,
+      "height": 0,
+      "angle": 0,
+      "strokeColor": "#4f7fdb",
+      "backgroundColor": "transparent",
+      "fillStyle": "solid",
+      "strokeWidth": 2,
+      "strokeStyle": "solid",
+      "roughness": 1,
+      "opacity": 100,
+      "groupIds": [],
+      "frameId": null,
+      "index": "a2",
+      "roundness": {
+        "type": 2
+      },
+      "seed": 8793989,
+      "version": 1,
+      "versionNonce": 8793990,
+      "isDeleted": false,
+      "boundElements": null,
+      "updated": 1706659200000,
+      "link": null,
+      "locked": false,
+      "points": [
+        [
+          0,
+          0
+        ],
+        [
+          140,
+          0
+        ]
+      ],
+      "startBinding": null,
+      "endBinding": null
+    },
+    {
+      "id": "arrow-2061",
+      "type": "arrow",
+      "x": 2110,
+      "y": 930,
+      "width": 140,
+      "height": 240,
+      "angle": 0,
+      "strokeColor": "#d45b61",
+      "backgroundColor": "transparent",
+      "fillStyle": "solid",
+      "strokeWidth": 2,
+      "strokeStyle": "solid",
+      "roughness": 1,
+      "opacity": 100,
+      "groupIds": [],
+      "frameId": null,
+      "index": "a2",
+      "roundness": {
+        "type": 2
+      },
+      "seed": 8798260,
+      "version": 1,
+      "versionNonce": 8798261,
+      "isDeleted": false,
+      "boundElements": null,
+      "updated": 1706659200000,
+      "link": null,
+      "locked": false,
+      "points": [
+        [
+          0,
+          0
+        ],
+        [
+          140,
+          -240
+        ]
+      ],
+      "startBinding": null,
+      "endBinding": null
+    },
+    {
+      "id": "arrow-2062",
+      "type": "arrow",
+      "x": 1825,
+      "y": 415,
+      "width": 0,
+      "height": 705,
+      "angle": 0,
+      "strokeColor": "#f0a020",
+      "backgroundColor": "transparent",
+      "fillStyle": "solid",
+      "strokeWidth": 2,
+      "strokeStyle": "dashed",
+      "roughness": 1,
+      "opacity": 100,
+      "groupIds": [],
+      "frameId": null,
+      "index": "a2",
+      "roundness": {
+        "type": 2
+      },
+      "seed": 8802531,
+      "version": 1,
+      "versionNonce": 8802532,
+      "isDeleted": false,
+      "boundElements": null,
+      "updated": 1706659200000,
+      "link": null,
+      "locked": false,
+      "points": [
+        [
+          0,
+          0
+        ],
+        [
+          0,
+          705
+        ]
+      ],
+      "startBinding": null,
+      "endBinding": null
+    },
+    {
+      "id": "arrow-2063",
+      "type": "arrow",
+      "x": 1825,
+      "y": 735,
+      "width": 0,
+      "height": 385,
+      "angle": 0,
+      "strokeColor": "#f0a020",
+      "backgroundColor": "transparent",
+      "fillStyle": "solid",
+      "strokeWidth": 2,
+      "strokeStyle": "dashed",
+      "roughness": 1,
+      "opacity": 100,
+      "groupIds": [],
+      "frameId": null,
+      "index": "a2",
+      "roundness": {
+        "type": 2
+      },
+      "seed": 8806802,
+      "version": 1,
+      "versionNonce": 8806803,
+      "isDeleted": false,
+      "boundElements": null,
+      "updated": 1706659200000,
+      "link": null,
+      "locked": false,
+      "points": [
+        [
+          0,
+          0
+        ],
+        [
+          0,
+          385
+        ]
+      ],
+      "startBinding": null,
+      "endBinding": null
+    },
+    {
+      "id": "arrow-2064",
+      "type": "arrow",
+      "x": 1825,
+      "y": 1055,
+      "width": 0,
+      "height": 65,
+      "angle": 0,
+      "strokeColor": "#f0a020",
+      "backgroundColor": "transparent",
+      "fillStyle": "solid",
+      "strokeWidth": 2,
+      "strokeStyle": "dashed",
+      "roughness": 1,
+      "opacity": 100,
+      "groupIds": [],
+      "frameId": null,
+      "index": "a2",
+      "roundness": {
+        "type": 2
+      },
+      "seed": 8811073,
+      "version": 1,
+      "versionNonce": 8811074,
+      "isDeleted": false,
+      "boundElements": null,
+      "updated": 1706659200000,
+      "link": null,
+      "locked": false,
+      "points": [
+        [
+          0,
+          0
+        ],
+        [
+          0,
+          65
+        ]
+      ],
+      "startBinding": null,
+      "endBinding": null
+    },
+    {
+      "id": "arrow-2065",
+      "type": "arrow",
+      "x": 1550,
+      "y": 1210,
+      "width": 120,
+      "height": 325,
+      "angle": 0,
+      "strokeColor": "#f0a020",
+      "backgroundColor": "transparent",
+      "fillStyle": "solid",
+      "strokeWidth": 2,
+      "strokeStyle": "dashed",
+      "roughness": 1,
+      "opacity": 100,
+      "groupIds": [],
+      "frameId": null,
+      "index": "a2",
+      "roundness": {
+        "type": 2
+      },
+      "seed": 8815344,
+      "version": 1,
+      "versionNonce": 8815345,
+      "isDeleted": false,
+      "boundElements": null,
+      "updated": 1706659200000,
+      "link": null,
+      "locked": false,
+      "points": [
+        [
+          0,
+          0
+        ],
+        [
+          -120,
+          0
+        ],
+        [
+          -120,
+          -325
+        ]
+      ],
+      "startBinding": null,
+      "endBinding": null
+    },
+    {
+      "id": "arrow-2066",
+      "type": "arrow",
+      "x": 2640,
+      "y": 595,
+      "width": 110,
+      "height": 55,
+      "angle": 0,
+      "strokeColor": "#2fc9d2",
+      "backgroundColor": "transparent",
+      "fillStyle": "solid",
+      "strokeWidth": 3,
+      "strokeStyle": "solid",
+      "roughness": 1,
+      "opacity": 100,
+      "groupIds": [],
+      "frameId": null,
+      "index": "a2",
+      "roundness": {
+        "type": 2
+      },
+      "seed": 8819615,
+      "version": 1,
+      "versionNonce": 8819616,
+      "isDeleted": false,
+      "boundElements": null,
+      "updated": 1706659200000,
+      "link": null,
+      "locked": false,
+      "points": [
+        [
+          0,
+          0
+        ],
+        [
+          110,
+          -55
+        ]
+      ],
+      "startBinding": null,
+      "endBinding": null
+    },
+    {
+      "id": "arrow-2067",
+      "type": "arrow",
+      "x": 2930,
+      "y": 650,
+      "width": 0,
+      "height": 110,
+      "angle": 0,
+      "strokeColor": "#2b1f99",
+      "backgroundColor": "transparent",
+      "fillStyle": "solid",
+      "strokeWidth": 3,
+      "strokeStyle": "solid",
+      "roughness": 1,
+      "opacity": 100,
+      "groupIds": [],
+      "frameId": null,
+      "index": "a2",
+      "roundness": {
+        "type": 2
+      },
+      "seed": 8823886,
+      "version": 1,
+      "versionNonce": 8823887,
+      "isDeleted": false,
+      "boundElements": null,
+      "updated": 1706659200000,
+      "link": null,
+      "locked": false,
+      "points": [
+        [
+          0,
+          0
+        ],
+        [
+          0,
+          110
+        ]
+      ],
+      "startBinding": null,
+      "endBinding": null
+    },
+    {
+      "id": "arrow-2068",
+      "type": "arrow",
+      "x": 2930,
+      "y": 980,
+      "width": 2690,
+      "height": 495,
+      "angle": 0,
+      "strokeColor": "#2b1f99",
+      "backgroundColor": "transparent",
+      "fillStyle": "solid",
+      "strokeWidth": 2,
+      "strokeStyle": "dashed",
+      "roughness": 1,
+      "opacity": 100,
+      "groupIds": [],
+      "frameId": null,
+      "index": "a2",
+      "roundness": {
+        "type": 2
+      },
+      "seed": 8828157,
+      "version": 1,
+      "versionNonce": 8828158,
+      "isDeleted": false,
+      "boundElements": null,
+      "updated": 1706659200000,
+      "link": null,
+      "locked": false,
+      "points": [
+        [
+          0,
+          0
+        ],
+        [
+          0,
+          390
+        ],
+        [
+          -2690,
+          390
+        ],
+        [
+          -2690,
+          -105
+        ]
+      ],
+      "startBinding": null,
+      "endBinding": null
+    }
+  ],
+  "appState": {
+    "viewBackgroundColor": "#f7fbff",
+    "gridSize": 20
+  },
+  "files": {}
+}

BIN
docs/p0-mobile/医梦患者智能服务门户_P0客户端总交互流程.png