P2 Foundry
可视化仪表盘:看数一页统览
图表直接绑定本体对象(订单、客户),栅格拖排成仪表盘,Y 轴聚合实时出数,再按用户 / 角色分享给团队。看完这 4 个故事,你就能自己建图、拼盘、分享,并知道哪些边界还没到。(登录 admin / admin1,端口 18081,演示数据源 foundry_demo_warehouse。)
业务分析师
运营人员
仪表盘
图表聚合
分享
栅格布局
共 4 个故事
能 / 不能速览
✅ 这个主题能做
- 图表绑定本体对象类型,字段即本体属性(业务名),天然防注入
- Y 轴声明聚合(sum / avg / count / min / max)时按 X / 分组轴生成 GROUP BY,聚合实时生效
- POST /charts/preview 未保存也能预览数据(含聚合),配置即所见
- 仪表盘栅格编排(位置 / 宽高)、整体布局更新(事务原子);图表可被多个仪表盘复用
- 按用户(user)或角色(role)分享,列表只返回"本人拥有 + 被分享"的可见集
- 数据读取带 RLS / CLS 行 / 列级保护与编辑态叠加
⛔ 这个主题做不了
- 前端当前所有图表类型统一按表格渲染(bar / line / pie 图形化待 ECharts 接入)
- 仪表盘详情 / 取数端点不校验访问权——知道 id 即可读(数据仍受 RLS / CLS 保护)
- 无血缘写入(图表创建不打点)、无缓存、无下钻交互
- 仪表盘级全局筛选器 UI 未真正联动(前端传空 filters)
- RefreshIntervalSec 字段存储但无自动刷新调度;分享目标不校验真实存在
适用角色
本主题面向三个角色:
- 业务分析师 / 运营人员:建图表、拼仪表盘、看数据、分享给团队——是核心使用者。
- 数据工程师:确认对象与属性映射,协助配置 Y 轴聚合字段。
- 业务决策者:通过被分享的仪表盘消费洞察,不直接操作。
能力速览(能做什么)
本体绑定图表
图表数据源是对象类型 + 属性轴映射(x / y / group_by),非任意 SQL;字段经语义层白名单校验。
Y 轴聚合
轴声明 Aggregation 时按 X / 分组维度生成 GROUP BY 聚合列,bar 图表直接拿汇总值而非明细。
配置预览
POST /charts/preview 未保存图表也能按配置查数据,改完轴 / 筛选先看效果再保存。
栅格编排与复用
仪表盘添加图表(位置 / 宽高),整体布局事务更新;删仪表盘图表保留可复用。
用户 / 角色分享
分享给 user 或 role;可见集 = 拥有者 ∪ 直接分享 ∪ 角色分享,列表层过滤。
调整指南(怎么调整)
- 想加聚合:图表编辑里给 Y 轴填 aggregation=sum(或 avg / count / min / max),X 轴填分组维度。
- 想改布局:仪表盘页拖排或 PUT /dashboards/:id/layout 整体覆盖位置 / 尺寸。
- 想分享:分享弹窗选 user(填用户 id)或 role(填角色名);取消分享后被分享方列表立即不可见。
- 想复用图表:同一图表可添加到多个仪表盘;删除图表会级联移除全部仪表盘上的关联。
- 想限制取数范围:图表默认筛选(charts.filters)与请求级筛选 AND 合并,数据量上限缺省 1000 行。
做得好的场景
图表绑定本体语义 + 聚合查询,让"看数"快速且口径清晰,特别适合以下场景:
- 经营看板自助搭建:分析师几分钟把订单状态、金额分布拼成周报,替代提报表工单等 1~2 天。
- 口径一致:图表字段即本体属性,展示的就是对象语义,不会出现字段名对不上。
- 团队共享:分享给角色后,同组同事打开仪表盘即可看,不用逐个转发截图。
- 配置即所见:preview 先看效果再保存,减少"保存了发现不对"的返工。
限制与不足
以下是明确的边界,使用前先知道:
- 渲染依赖前端:后端支持 bar / line / pie / table 四类,前端当前统一按表格渲染,图形化待 ECharts 接入。
- 权限是"列表过滤":详情 / 更新 / 取数端点不校验访问权,知道 id 即可读取(数据仍受 RLS / CLS 保护),需后续补 403。
- 无血缘 / 缓存 / 下钻:图表创建不写血缘,无 TTL 缓存,无基于本体关系的下钻交互。
- 全局筛选器未联动:仪表盘级筛选器 UI 未真正生效,前端传空 filters。
- 分享目标无校验:分享 user / role 为自由文本,不校验真实存在。
场景故事
故事 1
张工建"按状态销售额"bar 图表,验证 Y 轴聚合真的生效
场景:图表聚合
角色:数据工程师
耗时:约 6 分钟
- 背景
- 张工要做一张"各状态销售额"图。他知道图表绑定的是 order 对象,order 有 amount(金额)与 status(状态)属性。他要验证:Y 轴声明聚合 sum 后,取数返回的是按状态分组的汇总值,而不是逐单明细。
- 传统做法对比
- 以前要么写 SQL 手算 GROUP BY 再粘到 Excel,要么等数据团队排期出一张临时报表。现在页面建图表、配轴、保存,一次 POST /charts/:id/data 就拿到聚合结果,还能反复调整。
- 角色
- 数据工程师(建图 + 验证聚合),业务分析师(后续消费这张图)。
- 操作步骤
-
- 打开"仪表盘"→"图表"→"+ 新建图表":名称=按状态销售额、类型=bar、对象=order
- X 轴填 property=status;Y 轴填 property=amount、aggregation=sum
- 保存,点图表"加载数据"
- 系统响应
- 取数返回三行聚合值:
{"columns":["status","amount"],"rows":[["shipped",4477.5],["pending",995],["cancelled",998]]}。4477.5 = 995 + 1990 + 1492.5(三单已发货),正是 GROUP BY status 后的 SUM(amount)。
- 结果洞察
- Y 轴聚合是真实生效的:轴声明 aggregation=sum 后走分组聚合查询(AGG + GROUP BY),不再是 v2 时期"只当 select 字段、返回明细"的假聚合。同一张图,取消 aggregation 则返回逐单明细——聚合 / 明细一张图切换。
- 调整建议
- 想看平均单价把 aggregation 改 avg;想按区域维度先确认 region 落在订单对象属性上;数据量超 1000 行会被截断,聚合图建议用维度分组而非明细。
- 动手试一试
- 登录:admin / admin1。页面路径:仪表盘 → 图表 → 新建图表。输入内容:名称=按状态销售额、类型=bar、对象=order、X=status、Y=amount(aggregation=sum)。预期结果:加载数据返回 shipped 4477.5 / pending 995 / cancelled 998 三行聚合值。
- 限制提示
- 前端当前统一按表格渲染,bar 图暂无柱状图形(ECharts 待接入);聚合字段无读权限时聚合查询直接报"禁止聚合";demo 数据每次启动重建,数值会重置。
故事 2
王姐把三张图拼成"销售周报",拖排布局一页统览
场景:仪表盘编排
角色:业务分析师
耗时:约 8 分钟
- 背景
- 王姐每天要看的数散在各处:订单状态、金额走势、客户分布。她在图表列表建了三张图,现在要把它们拼成一个"销售周报"仪表盘,按栅格拖排位置、调宽高,一次性看全。
- 传统做法对比
- 以前要么开三个报表页来回切,要么截图拼一张长图发群里,改一次数据全重截。现在一张仪表盘、三张图、固定布局,打开就加载全部图表数据,一页统览。
- 角色
- 业务分析师(建盘 + 编排布局),数据工程师(预建图表)。
- 操作步骤
-
- "仪表盘"→"+ 新建仪表盘":名称=销售周报、布局=grid
- 点"添加图表",依次选已建的三张图,位置 / 宽高先按默认 6x4 放
- 在布局编辑里把"按状态销售额"放左上(0,0)、"金额走势"放右上(6,0)、"客户分布"放下方(0,4)
- 保存布局,打开仪表盘看整体
- 系统响应
- 添加返回
{"code":0,"data":{"id":N}};保存布局返回 {"updated":true};打开仪表盘自动并行加载全部图表数据,每张图返回各自 columns + rows。布局项若含不在盘上的 chart_id,整体回滚并报 NotFound。
- 结果洞察
- 栅格布局(position_x / position_y / width / height)把散图变成一页看板,布局更新是事务原子的——要么全成功要么全失败。图表与仪表盘是多对多:同一张图可以出现在多个盘上,删除仪表盘不影响图表,改图一次全盘生效。
- 调整建议
- 布局用 12 列栅格规划(width 默认 6 即半屏);新增图表先加进来再整体 PUT layout 一次到位;图表数多时注意每张图 1000 行上限,聚合图更省位。
- 动手试一试
- 登录:admin / admin1。页面路径:仪表盘 → 新建仪表盘 → 添加图表 → 调整布局。输入内容:名称=销售周报,添加 2~3 张已建图表并摆位。预期结果:打开仪表盘同时加载全部图表数据,布局按设定栅格显示。
- 限制提示
- 前端布局为静态栅格展示,无真正拖拽交互与响应式排版;RefreshIntervalSec 字段存储但无自动刷新调度;图表无版本管理,修改即覆盖。
故事 3
销售周报分享给"运营组",同组同事列表可见、未分享不可见
场景:角色分享
角色:业务分析师 + 运营人员
耗时:约 5 分钟
- 背景
- 王姐把"销售周报"盘好了,要分享给整个运营组,而不是一个个转发截图。她用角色分享(share_type=role, role=运营组),验证组内成员在列表能看到、组外看不到,并顺带摸清权限边界。
- 传统做法对比
- 以前建个共享 Excel,改的人多了互相覆盖;或群里发截图,过期即失效。现在分享一次、所有人看同一份最新数据,取消分享立刻不可见。
- 角色
- 业务分析师(分享方)、运营组同事(被分享方)、数据工程师(了解权限模型)。
- 操作步骤
-
- 打开销售周报仪表盘 →"分享"→ share_type=role、role=运营组
- 查看分享列表,确认"运营组"记录出现
- 用组内成员登录,看"我的仪表盘"列表是否出现销售周报
- 系统响应
- 分享返回
{"code":0,"data":{"id":N}};成员列表查询 GET /dashboards 返回 owner 或被分享的可见集(owner ∪ 直接分享 user ∪ 角色分享),按更新时间倒序;未分享用户列表层看不到该盘。
- 结果洞察
- 可见集过滤是分享治理的唯一生效点:列表层清晰隔离"谁能看到"。但要注意权限模型是"列表过滤"而非"访问控制"——知道仪表盘 id 的人仍可直接 GET /dashboards/:id 读详情与取数(数据行本身仍受 RLS / CLS 保护),这是当前明确的边界。
- 调整建议
- 分享目标先确认真实存在(系统不校验,分享给不存在的角色会产生无效记录);敏感数据不要靠"列表过滤"兜底,要配合对象级 RLS;取消分享后对方列表立即不可见。
- 动手试一试
- 登录:admin / admin1。页面路径:仪表盘 → 销售周报 → 分享。输入内容:share_type=role、role=运营组。预期结果:分享列表出现该记录;取消分享后列表立即移除。
- 限制提示
- 详情 / 取数端点不校验访问权(id 即通行证,数据仍受 RLS / CLS 保护);分享 user / role 自由文本不校验存在性;重复分享同一目标返回重复冲突。
故事 4
先预览再保存:李总用 /charts/preview 现场调"客单价"图
场景:配置预览
角色:业务决策者 + 业务分析师
耗时:约 5 分钟
- 背景
- 李总想要一张"每月客单价"图。王姐不敢一次成型——她把 Y 轴先配成 sum 想先看效果,发现那不是均价;改用 avg 后先用"图表数据预览"(未保存)确认数据,再落库保存。
- 传统做法对比
- 以前配错口径只能保存后再改,要么先导数据到本地算一遍;一来一回小半天。现在 POST /charts/preview 直接带上未保存的图表配置查数据,改聚合算子、改筛选,实时看返回,满意再保存。
- 角色
- 业务分析师(调配置 + 预览)、业务决策者(提需求 + 确认口径)。
- 操作步骤
-
- 新建图表:名称=每月客单价、类型=table、对象=order
- X 轴=created_at、Y 轴=amount,aggregation 先填 sum,点"预览"
- 发现返回是金额合计而非均价,把 aggregation 改成 avg 再预览
- 确认数字后保存,图表落到图表列表
- 系统响应
- 预览请求体为
{"chart":{...},"data":{"filters":[],"limit":100}};聚合改为 avg 后返回按 created_at 分组的平均金额行。预览只校验对象存在,不要求 Name 完整创建语义。
- 结果洞察
- 预览复用与正式取数完全相同的查询路径(含 Y 轴聚合、RLS / CLS),所以"预览看到的 = 保存后看到的"。avg 与 sum 一改一刷,口径问题当场发现,不再有"保存后才发现配错"的返工。
- 调整建议
- 预览时同时加几条全局筛选验证筛选合并;预览确认后保存;要按日 / 月 / 年粒度,靠维度与时间字段配合,图表本身暂无时间粒度自动折叠。
- 动手试一试
- 登录:admin / admin1。页面路径:仪表盘 → 新建图表 → 预览。输入内容:Y 轴 amount 依次用 aggregation=sum 与 avg 预览。预期结果:sum 返回金额合计、avg 返回平均金额,改完再保存。
- 限制提示
- 预览不校验完整创建语义(仅需对象存在);前端仍按表格渲染,图形化待接入;图表无版本管理与发布审批,保存即覆盖。
常见问题
图表为什么返回的是明细而不是汇总?
看 Y 轴有没有声明聚合算子:X / Y 轴 Aggregation 为空时按明细直出(选中的字段原样返回);任一轴填了 aggregation=sum / avg / count / min / max,就按分组维度生成 GROUP BY 聚合查询。
分享后对方看不到?
可见集 = 拥有者 ∪ 直接分享 user ∪ 分享给用户任一角色。确认 share_type 与目标填对:share_type=user 要填 user_id、share_type=role 要填角色名;角色分享时对方须拥有该角色。
仪表盘权限安全吗?
数据行本身受 RLS / CLS 行 / 列级保护,字段走语义层白名单。但仪表盘级可见性目前是"列表过滤"——知道 id 可直接读详情与取数,生产使用前建议补 403 访问控制(已列入待补齐)。
图表能复用吗?
能。同一图表可添加到多个仪表盘;删除仪表盘图表保留;删除图表会级联移除所有仪表盘上的关联。
为什么没有柱状图?
后端支持 bar / line / pie / table 四类,前端当前统一按表格渲染(MVP),柱状 / 折线图形化待 ECharts 接入——数据与聚合都已就绪,缺的是渲染层。
主题小结
一句话:仪表盘把"本体绑定的图表 + Y 轴聚合 + 栅格编排 + 角色分享"串成一页统览,预览 / 保存同一套查询路径。记住边界:前端表格渲染、权限是列表过滤、无血缘 / 缓存 / 下钻、全局筛选器未联动。