feat(charts): manage investigation charts in a scrolling workspace
Generic Container CI/CD / test-build-publish (push) Successful in 2m7s
Frontend CI/CD / build-test-publish-and-deploy (push) Successful in 2m8s

This commit is contained in:
2026-11-10 17:56:23 +08:00
parent 865491cb23
commit 0ae0a41e61
80 changed files with 4672 additions and 470 deletions
+10 -2
View File
@@ -78,7 +78,15 @@ Agent 选择组件、内容顺序与受控语义,前端负责实际视觉、
短结果及说明直接在对话内阅读;包含表格、图表、补充表单或长正文的回答提供展开入口。窗口尺寸、滚动与放大由宿主管理,不作为模型输出样式。
`Chart` 的页签、图例、区间摘要与数据点详情由前端固定实现,Agent 只提供标题、初始图形类型、类别、序列和来源。鼠标切换折线、柱状和数据表时使用 180ms Motion 滑块与内容过渡;键盘操作与减少动态效果模式即时完成。数据点详情只在点击图中数据点,或聚焦图形后按回车、方向键、Home/End 选点时出现,关闭后焦点回到图形;数据表页签不重复展示区间摘要和点详情,搜索与排序在视图切换后保留。
`Chart` 的页签、位于绘图区下方的图例、区间摘要与数据点详情由前端固定实现,Agent 只提供标题、初始图形类型、类别、序列和来源。鼠标切换折线、柱状和数据表时使用 180ms Motion 滑块与内容过渡;键盘操作与减少动态效果模式即时完成。数据点详情只在点击图中数据点,或聚焦图形后按回车、方向键、Home/End 选点时出现,关闭后焦点回到图形;数据表页签不重复展示区间摘要和点详情,搜索与排序在视图切换后保留。
SCADA 的压力、水头(m)及流量、管流(m³/h)数值轴使用对齐的整数上下界与整数刻度,不直接显示数据极值外加余量的小数端点。序列、数据表与点详情保持原始读数精度;其他单位及通用小量程图沿用原有刻度,不自动换算单位。
图表发布及 Dev 示例的对象聚合、同期校验和历史读取边界统一见 [调查展示 Dev 测试](investigation-dev-tools.md#对象复合图与验证规则)。结构化 Chart 保持单图语义,对象聚合通过 open_chart 的独立对象数据集实现。
[图表和窗口管理](investigation-dev-tools.md#图表和窗口管理)由浏览器宿主负责:总窗口收纳过程图组与报告 Chart,子图表保留独立弹窗放大。总窗口提供单图、左右、四宫格固定槽位,全部图表沿纵向连续排列,末行按列数补齐空槽;整条位置栏提供拖拽和悬停反馈,拖放到目标位置交换内容。窄窗口使用单图,快速定位会滚动到目标位置。同一图表更新保留位置,删图留空,新图先填空槽。顶部窗口列表可定位、置顶已打开的总窗口、子图表和表格,并统一关闭。窗口缩放期间,图表按窗口实际尺寸适配并保留图表实例与筛选状态;松开后确认最终尺寸,Escape 或指针取消恢复原尺寸。
任务打开、切换、刷新、已完成任务载入和历史恢复只更新内容,不弹窗;运行中新收到的 open_chart 由总窗口统一处理,关闭后的实时更新不重新弹出。排列、布局和窗口操作不新增模型输出或 wire 协议字段,也不改变图表校验与证据规则。具体自动弹出与关闭边界以上述管理说明为准。
其余组件使用 `answer-motion.tsx` 统一交互过渡,沿用现有实体面板、字体、语义颜色和圆角。首次加载即时显示;鼠标展开、收起使用 180ms 透明度和位移,键盘与减少动态效果模式即时完成。折叠中的内容立即设为 `inert` 并退出无障碍树,动画结束后隐藏;保留原 React 内容实例,反向操作中断旧动画,避免旧退出回调隐藏重新展开的表单。
@@ -87,7 +95,7 @@ Agent 选择组件、内容顺序与受控语义,前端负责实际视觉、
| `Stack`、`Section` | 保留既有布局,不为静态分区附加动画 |
| `Text`、`Result` | 静态说明和已有结果直接阅读,不反复播放入场或宣告历史状态 |
| `Metric` | 直接展示原始数值、单位与来源 |
| `Table` | 搜索排序即时响应;无勾选列、选行提示或操作栏 |
| `Table` | 搜索排序即时响应;表头悬停与排序点击覆盖整列宽度;仅当前排序列显示升序或降序箭头,未排序时不显示;无勾选列、选行提示或操作栏 |
| `Evidence` | 正文展开收起和箭头转动使用统一过渡;保留来源、记录时间与资料编号 |
| `MapLocation` | 关联要素详情使用统一折叠;定位中的反馈及结果短时淡入 |
| `FollowUpForm` | 精简与外层重复的补充提示;保留标题、说明、校验及草稿,提交反馈短时淡入 |
+43 -8
View File
@@ -20,13 +20,31 @@ Dev 分为“调查测试”“通知测试”和“地图调试”三个页签
Dev 与工况详情共用右侧工具位置,切换调查时先关闭 Dev 回到任务列表,再打开 Dev 检查新的选择。实时展示面板位于地图左下方,打开 Dev 后仍可看见。新图表进入其滚动区时会滚动到图表,保留标题;手动收起面板后仍接收指令,展开再查看。切换项目、调查或执行代次会清理临时效果并取消未完成的本地预览。上述清理保留本次页面会话内的动作快照,只有切换项目会同时清空历史。已绑定调查时关闭跟随也会清理该调查的当前临时展示;未选择调查的本地预览不受跟随开关影响。面板外仍可操作地图,手动拖拽或滚轮暂停镜头自动跟随。
调查与本地预览在展示分析图表时自动打开可拖动、缩放和最大化的独立窗口,覆盖 `open_chart` 指令和结构化界面中的 `Chart`。自动打开不抢走键盘焦点;关闭窗口仅收起放大视图,卡片中的图表和放大入口继续保留。同一图表内容未变化时,其他地图动作不会使已关闭的窗口再次弹出;图表内容更新或进入、退出历史回看时可再次自动打开。回放窗口随所选快照更新,保留已有窗口的位置和尺寸,期间收到的实时数据不替换历史图表。关闭图表指令或切换任务时移除对应窗口;普通对话图表仍由用户手动放大。
## 图表和窗口管理
调查、本地预览与对话展示面板提供“图表窗口”入口,在一个可拖动、缩放、最大化的总窗口中集中查看所有子图表,包括 open_chart 形成的对象图组与报告中的 Chart。每张子图表保留自身的独立弹窗放大入口,可同时打开多个放大窗口;关闭总窗口收起其内部开启的放大窗口,关闭子窗口只收起该放大视图。普通趋势总览、柱状图和报告 Chart 保持各自的图表语义。
总窗口使用固定槽位布局,提供“单图布局”“左右布局”“四宫格布局”,每行分别显示 1、2、2 个固定位置,单图与左右布局每行约占一个可视区高度,四宫格每个可视区约显示两行。全部图表沿纵向连续排列,通过滚动查看;图表随槽位尺寸适配,末行按列数补齐空槽。窄窗口使用单图布局,调宽后恢复先前选择的布局。头部定位、布局和重置控件置于同一条浅底工具栏,控件保持等高,窄窗口允许自然换行。“快速定位图表”列出全部图表,选择后滚动到对应位置并聚焦目标;目标的位置栏短暂显示淡色背景和“已定位”,不使用整卡外框,避免高亮被滚动区域裁切。
槽内图表使用紧凑控件,绘图区下方的图例独立滚动,筛选、详情与依据通过入口展开。多对象图在宽槽右侧显示对象按钮,窄槽使用对象选择器;独立放大后使用完整控件。
整条图表位置栏均为拖拽手柄,悬停反馈覆盖整栏;在目标位置释放后交换两处内容,拖到空槽则移动到空槽,其他位置不推移。悬停时整张卡片显示轻量浅色高亮,拖动源与目标位置保留整卡浅色提示;位置栏使用柔和浅底和深色文字,不使用深色横幅。图表保持原有清晰度,目标位置使用细线提示,轻量标题预览沿用中性边框。原图表留在原位,不克隆或随指针重绘。不再提供“移动到”下拉菜单,下方图表通过纵向滚动和快速定位查看。
槽位映射依据稳定的子图表标识:同一图表实时更新时保留位置,删除图表后保留中间空槽并移除末尾空行,新图优先填补空槽,再追加位置与行。同一次任务查看期间,关闭并重新打开总窗口保留槽位与布局;任务、项目或执行代次切换后重新建立当前内容。交换位置不改变图表数据、对象选择或服务端的展示事件顺序。
工作台顶部的窗口列表入口列出已打开的总图表窗口、独立子图表和表格窗口,选择条目可将对应窗口置顶并定位到标题栏。列表中的“关闭全部窗口”统一收起当前打开的窗口,不删除已加载的图表、表格或任务结果;图表窗口可从原展示入口重新打开。
总窗口与子图表使用同一缩放交互:指针拖动窗口边缘时,图表按窗口实际尺寸适配,保持已有图表实例与筛选、序列显隐和对象选择;松开后确认最终尺寸。拖动期间按 Escape 或发生 pointercancel 时取消调整、恢复原尺寸;标题栏的 Shift 加方向键继续用于逐步调整大小。
只有正在跟随的运行中调查新收到 open_chart 时,才自动弹出一次总窗口,不自动弹出各子图表,不抢走键盘焦点;后续指令按 chart_id 更新其中的数据。打开、切换、刷新任务、SSE 重连补载、历史回看和回到当前都只恢复内容,已完成任务也不弹窗。用户关闭总窗口后,本次任务查看期间的后续更新不使其再次弹出;手动收起展示面板期间的新指令也不请求弹窗。总窗口已经打开时,历史回看只更新其中的快照,实时数据不覆盖正在查看的历史。切换任务、项目或执行代次关闭原窗口并重新静默载入,返回之前看过的任务也不重放自动弹出意图。Chat 与本地 Dev 预览使用手动入口。
open_chart 仍只提交 chart_id/chart/evidence_refs,close_chart 仍按 chart_id 移除对象;不新增 display 或 objects 字段。排列、布局与窗口打开意图仅存在当前浏览器中,不进入保存的展示快照或事件。displayed 回执表示展示内容已加载,不保证弹出了独立窗口。
## 本地测试步骤
1. 在默认展开的“调查测试”页签准备数据。“载入合成样例”在当前地图中心生成合成空间展示、压力曲线、候选表格和一条候选数据;所选调查进度存在地图目标时,另加入该目标的高亮测试。所有合成结果均有明确标记。
2. 可选:点击“校验 JSONL”单独查看识别出的展示指令、界面块、调查数据数量。也可直接执行本地预览,执行入口会自动校验当前全部内容。
3. 点击“执行本地预览”,自动校验通过后对照地图和左下展示面板中的图表、结构化界面与数据摘要;Dev 的“原始数据检查”可点击对象查看原始行内容。动作记录区分“实时指令”和“本地测试”,显示应用或失败结果。
3. 点击“执行本地预览”,自动校验通过后对照地图和左下展示面板中的图表、结构化界面与数据摘要;手动打开“图表窗口”,核对单图、左右、四宫格的固定槽位、拖放交换、末行空槽与纵向滚动,再检查快速定位和子图表独立放大,并从顶部窗口列表切换已打开的窗口。Dev 的“原始数据检查”可点击对象查看原始行内容。动作记录区分“实时指令”和“本地测试”,显示应用或失败结果。
4. 按需“下载测试 JSONL”保存当前已校验输入;“清除临时展示”清除当前浏览器的高亮、图表和覆盖层。测试不改变服务端事件游标,不发起调查、审批、工单或设备写入。
样例与导出仅存在当前页面或用户下载的文件中,不写 Agent 工作区,不伪造已保存证据。Dev 不会自动枚举 Agent 生成的本地文件;要检查已有 JSONL,可将通过受控入口取得的文件内容粘贴到编辑区。当前最多 200 KB、40 行、8 个界面块;地图与图表继续遵守原展示协议的数量、几何及序列约束。
@@ -37,8 +55,10 @@ Dev 与工况详情共用右侧工具位置,切换调查时先关闭 Dev 回
| 案例 | 核对内容 |
| --- | --- |
| 组合联动 | 地图点、调查现有目标高亮、压力曲线、候选表格与数据 |
| 地图定位与高亮 | 有目标时高亮真实关联目标;无目标时只显示合成点,不虚构资产查询编号 |
| 组合联动 | 合成空间点、压力曲线、候选表格与数据;定位和高亮在地图调试页签操作 |
| 复杂调查:多图多表联动 | 8 个压力点、4 个管段的同期复合图聚合为 2 个子图表,另有方案柱状图、2 个表格与合成覆盖面 |
| 复杂图表:多测点与长时序 | 每个对象包含 96 个时刻、1 条当前曲线和 7 组稀疏历史散点;右侧切换对象,下方显隐序列 |
| 复杂表格:宽表、长文本与边界数据 | 50 行 8 列宽表、空结果、零值、负数、重复值及缺口 |
| 压力趋势对比 | 两条合成压力曲线、时间轴、单位与图例 |
| 影响用户统计 | 合成用户数柱状图,不作为真实停水统计 |
| 合成影响范围 | 当前地图中心附近的合成 Polygon |
@@ -49,6 +69,7 @@ Dev 与工况详情共用右侧工具位置,切换调查时先关闭 Dev 回
| 错误:JSON 语法 | 第二行语法错误时整批拒绝,不执行第一行合法动作 |
| 错误:不支持的动作 | 拒绝协议未支持的动作 |
| 错误:图表数据不齐 | 拒绝时间轴和序列长度不一致的图表 |
| 错误:同期时刻错位 | 拒绝历史时间与横轴槽位不一致的复合图,整批不执行 |
切换前若执行过本地预览,会先清除它的当前临时地图、图表和业务结果,保留动作历史供回看;仅选择或编辑 JSONL 不执行新指令。有内容时即可点击“执行本地预览”,无需先点单独校验;每次执行都会重新校验当前全部输入。任何一行错误都会拦截整批,显示具体错误,不执行部分指令;地图尚未就绪时也显示原因。仅空输入或正在执行时禁用按钮,不以调查选择或实时跟随作为本地执行前提。测试不会写入 Server、重启调查或发送 Agent 对话。案例定义位于 [investigation-dev-cases.ts](../src/features/workbench/utils/investigation-dev-cases.ts)。
@@ -62,7 +83,7 @@ Dev 与工况详情共用右侧工具位置,切换调查时先关闭 Dev 回
{"record_type":"candidate","origin":"synthetic","source_evidence_refs":[],"element_id":"DEMO-PIPE-01","status":"example_only"}
```
仓库内的可复制数据示例为 [unified-presentation.jsonl](../tests/fixtures/unified-presentation.jsonl),覆盖十种 command、一个 `phase: final` 界面块和带来源的普通数据行;`P1` 是浏览器测试夹具中的测点,业务项目应使用已核实的实际编号。内置案例从同一个记录生成器输出,并在生成时通过当前校验器。错误案例单独保留,专门验证拒绝行为。
仓库内的可复制数据示例为 [unified-presentation.jsonl](../tests/fixtures/unified-presentation.jsonl),覆盖十种 command、两个可聚合的对象复合图、一个 `phase: final` 界面块和带来源的普通数据行;`P1` 是浏览器测试夹具中的测点,业务项目应使用已核实的实际编号。内置案例从同一个记录生成器输出,并在生成时通过当前校验器。错误案例单独保留,专门验证拒绝行为。
每行必须显式使用 `record_type: presentation`、`record_type: ui_block`,或带来源的调查数据类型。裸 command、裸 `answer-ui@1` block 和旧 chat 的 name/params 格式均拒绝。展示指令统一接受 `locate_features/zoom_to_map/highlight_features/clear_highlights/open_chart/close_chart/set_overlay/clear_overlay/render_scada_analysis/clear_scada_analysis`,不能加入项目、运行身份、URL、脚本或任意命令。Dev 的覆盖层样例直接提供合成几何,仅用于本地渲染测试;任务 Agent 的 `set_overlay` 可只传证据编号,由 Server 提取几何;传入 data 时必须与保存的证据快照一致。Chat 和 Dev 执行已提供并校验的 data。不能把 Dev 格式当成 Server 写入接口。
@@ -75,15 +96,16 @@ Dev 与工况详情共用右侧工具位置,切换调查时先关闭 Dev 回
```bash
pnpm exec vitest run src/features/workbench/utils/investigation-dev-preview.test.ts src/features/workbench/components/map-dev-panel.test.tsx src/features/workbench/hooks/investigation-presentation-follower.test.ts
PLAYWRIGHT_PORT=5194 pnpm exec playwright test tests/browser/investigation-dev-tools.e2e.ts tests/browser/floating-panel-pointer.e2e.ts --workers=1 --reporter=line
PLAYWRIGHT_PORT=5195 pnpm exec playwright test tests/browser/investigation-chart-manager.e2e.ts tests/browser/investigation-chart-groups.e2e.ts tests/browser/investigation-chart-layout.e2e.ts tests/browser/investigation-chart-resize.e2e.ts --workers=1 --reporter=line
```
浏览器用隔离 API/SSE fixture 验证所选任务到真实 MapLibre/React 展示的消费链、Dev 开启与收起、JSONL 校验和下载、任务切换清理、紧凑窗口及面板外地图输入;不调用付费模型或真实工单、设备接口。真实 Agent 是否发布了正确的事件、报告或 JSONL 文件,仍需按实际项目运行记录核对。
浏览器用隔离 API/SSE fixture 验证所选任务到真实 MapLibre/React 展示的消费链、Dev 开启与收起、JSONL 校验和下载、任务静默恢复、任务切换清理、子图表管理、紧凑窗口、实际尺寸适配及面板外地图输入;不调用付费模型或真实工单、设备接口。真实 Agent 是否发布了正确的事件、报告或 JSONL 文件,仍需按实际项目运行记录核对。
## 统一展示动作
Chat 使用 `present_view({command, reason})`,在线通过 SSE 的 `tjwater.frontend_action` 承载 `frontend-action@2`,动作字段为 command,不再接收 name/params。浏览器回传 `frontend-action-result@2`。任务事件和 Dev JSONL 的 command 使用相同结构,并进入同一执行器。Chat、调查和 Dev 预览分别拥有地图源、SCADA 图层及图表状态;清理、切换会话和切换任务不会误清其他入口。Chat 动作按接收顺序执行,切换会话取消正在执行及排队动作;过期动作不会执行。任务仍只记录发布状态,不等待浏览器。查看历史回答不会重放动作。
动作 schema 的维护源是 `src/features/agent/presentation/command-schema.ts`。修改后在前端仓库运行 `node scripts/export-view-command-contract.mjs`,同步 Agent 主机/原生工具共用的 TypeScript schema 和 Agent/Server JSON Schema;运行同一命令加 `--check` 检查一致性。Server 任务入口继续执行证据归属和快照校验。
动作 schema 的维护源是 `src/features/agent/presentation/command-schema.ts`。修改后在前端仓库运行 `node scripts/export-view-command-contract.mjs`,同步 Agent 主机/原生工具共用的 TypeScript schema、Agent/Server JSON Schema,以及两端 tests/fixtures 下的统一 JSONL 示例与图表正反例;运行同一命令加 `--check` 检查内容一致性。JSON Schema 表达字段和数量约束,跨字段的时间语义由运行时校验和共享测试矩阵保证。Server 任务入口继续执行证据归属和快照校验。
## 已有案例与示例迁移
@@ -97,7 +119,20 @@ Chat 使用 `present_view({command, reason})`,在线通过 SSE 的 `tjwater.fr
| 调查数据 | 保留 `record_type/origin/source_evidence_refs`,不把内嵌 action 提升为指令 |
| Chat 调用 | `present_view({command, reason})`,不再调用旧的独立展示工具 |
本轮迁移只覆盖仓库内的内置案例、夹具和文档示例,未修改历史会话、数据库或外部下载文件。没有增加运行时旧格式转换。
迁移覆盖内置复杂案例、可复制 JSONL、跨端校验夹具及文档,不修改历史会话、数据库或外部下载文件。旧的已保存图表仍按结构校验读取;新输入与发布按下述规则校验。
## 对象复合图与验证规则
协议继续使用 `open_chart`,每个对象有独立稳定的 `chart_id`;不增加 `objects` 字段。多对象同期对比使用 `chart_type: time_comparison`。标题写为 `<对象ID> <同组标题>`,每条序列名以同一 `<对象ID> ` 开头,建议后接 `当前 YYYY-MM-DD` 或历史日期。对象 ID 以字母或数字开头,仅使用字母、数字、下划线、点或短横线。图例显示在绘图区下方;宽槽右侧的对象按钮单选切换数据集,窄槽使用对象选择器;独立放大的窄窗口把对象按钮移到下方。
仅 `open_chart` 中带历史 scatter 的明确对象图自动聚合。同组标题、chart_type、横纵轴名称、横轴槽位及当前序列名称去掉对象前缀后的部分、当前 sample_times 必须完全一致;不同单位或窗口分开。普通 line/bar 图和结构化回答中的独立 Chart 保持各自图表,统一在总窗口管理。关闭子窗口只收起放大视图,关闭聚合卡片移除组内所有对象;按原 chart_id 的 close_chart 仅移除该对象。
历史读取还兼容已保存的 `测点 <对象ID> <同组标题>`、`压力测点 <对象ID> <描述>` 和 `流量测点 <对象ID> <描述>` 标题;后两种以指标名称连接描述作为同组标题,压力和流量分开。对象归属仍要求序列名带同一对象前缀。历史 scatter 仅写 `MM-DD` 的旧图,只有在标题与唯一当前 line 明确指向同一对象,且每条日期序列至少有一个有效采样时间、有效值与时间一一对应、时间换算为 UTC+8 后均为同一完整日期并与日期名相符时,才兼容日期型历史图例;缺失时间、日期不符、跨对象序列或歧义标题保持单图。这些兼容只影响显示聚合,保留原指令、标题、序列、采样时间和证据,不修改保存的数据,也不放宽新发布的同期规则。
当前与历史共用 UTC+8 的 HH:mm 或 HH:mm:ss 槽位,时刻精度一致,窗口按顺序且短于一天,允许跨午夜。每对象最多 100 个槽位、8 组序列,包含当前 line 和历史 scatter,不能混入 bar。每组 sample_times 与 data 等长,有效值保留带时区的真实采样时间;缺测值和时间均为 null,零值保留。采样时间换算为 UTC+8 后须落在对应槽位;当前曲线共享同一窗口,每组历史来自此前某个对应日期,不能混入当天、未来或不同日期。普通 line/bar 不套用这些同期语义,但不能用 line 冒充 line 与历史 scatter 复合图。
Dev 的 presentation 与 ui_block.Chart、新的 Chat open_chart(Agent 主机与原生工具)及任务图表发布使用相同的同期规则。历史读取的结构校验不追溯拒绝旧混合图。Server 在任务展示和报告发布时另外校验证据归属与同期语义,错误码为 TIME_COMPARISON_INVALID;本地预览不证明证据有效或业务发布成功。共享正反例的维护源为 [chart-publication-cases.json](../tests/fixtures/chart-publication-cases.json),随导出脚本同步到 Agent 与 Server,并在各仓库独立运行测试。
## 展示动作历史
+4
View File
@@ -194,6 +194,10 @@ Agent 与主工作区、地图与报告使用共享 `Resizable` 分栏;连续
每个业务区最多一个醒目的主操作。按钮覆盖默认、hover、按压、焦点、禁用和加载态;hover 仅用于支持 hover 的设备,加载时阻止重复提交并保留可读状态。地图与业务控件沿用共享按压反馈,Agent 控件保留本地 shadcn/ui 交互状态;具有专用资源交互的 `AgentPersona` 保留原版悬停,不额外缩放或变暗。
MapTool、地名搜索候选项、Header 普通菜单与窗口列表通过 `mapOptionInteractionVariants` 统一交互。普通项仅在支持 hover 的设备上切换为 `surface-reading` 底色、`surface-border` 边框与 `action-blue-hover` 标题及操作图标;键盘 `focus-visible`、菜单 `data-highlighted` 使用相同反馈并保留焦点提示。说明文字保持 muted,图层示意图保留业务颜色。整行、整张卡片响应,边框预留空间;行和卡片使用 12px 圆角,紧凑工具保持原有尺寸与圆角。颜色过渡为 150ms,减少动态效果时关闭,不增加缩放或位移。 标注工具切换选项时,图标继承按钮实时文字颜色;图标容器仅对底色做同周期过渡,避免按钮底色仍在渐变时图标先切白色。
选中项保留底色、文字和状态标识,悬停及键盘高亮仅加深边框;主操作使用蓝底白字并在高亮时加深,危险操作统一使用 `status-danger-soft/border/foreground`。禁用项不响应 hover 或按压;危险语义由业务显式声明,不按文案推断。`MAP_ACTION_ROW_INTERACTION_CLASS_NAME` 为普通菜单提供布局之外的默认底色、圆角与上述交互组合。此规则仅用于地图和工作台入口;Agent、调查展示等面板及共享 DropdownMenu 保留本地 shadcn/ui 主题,业务状态色继续独立表达。
地图与业务表单字段复用 `.form-field`,聚焦只改变原有 1px 边框;组合输入由外层承担焦点边界,无边框输入使用内描边。Agent 字段保留本地 shadcn/ui 输入组件的边框、焦点和错误样式。错误通过文字、`aria-invalid` 和关联说明表达,失败后保留输入。选中与焦点不改变控件尺寸,底图选择卡片使用主题边框和勾选标记,键盘焦点使用共享内描边。
弹层保留标题、关闭入口、焦点管理及触发控件的焦点返回。表单弹窗显式将初始焦点放在首要业务字段,选择框获焦不自动展开。Esc 从内到外处理,外层尊重已消费事件;弹窗容器可承接程序焦点,业务控件仍保留可见焦点。模态遮罩阻断底层地图操作。