From 16f96f47b20b381d7ba055fc7e8c78da9a5b2684 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E9=B9=8F?= Date: Fri, 19 Jun 2026 23:01:09 +0800 Subject: [PATCH] Design admin chart business blocks --- ...6-19-admin-chart-business-blocks-design.md | 531 ++++++++++++++++++ 1 file changed, 531 insertions(+) create mode 100644 RuoYi-Vue/docs/superpowers/specs/2026-06-19-admin-chart-business-blocks-design.md diff --git a/RuoYi-Vue/docs/superpowers/specs/2026-06-19-admin-chart-business-blocks-design.md b/RuoYi-Vue/docs/superpowers/specs/2026-06-19-admin-chart-business-blocks-design.md new file mode 100644 index 0000000..94e5251 --- /dev/null +++ b/RuoYi-Vue/docs/superpowers/specs/2026-06-19-admin-chart-business-blocks-design.md @@ -0,0 +1,531 @@ +# 后台图表业务块设计 + +## 目标 + +在现有页面设计器和业务块体系上增加后台业务块能力,并首批提供四个仅后台可用的图表业务块: + +- 指标卡 +- 折线图 +- 柱状图 +- 饼图 + +方案沿用现有业务块注册、布局保存、字段校验和代码生成链路,不建设第二套后台业务块系统,也不升级为通用 BI 或自由大屏设计器。 + +## 已确认的产品边界 + +- 采用统一业务块协议扩展方案。 +- 图表业务块一期仅用于后台页面。 +- 数据源仅支持单表聚合。 +- 支持维度、计数、求和、平均值和固定筛选条件。 +- 不支持关联表、自定义 SQL、公式脚本、运行时数据源切换和任意 ECharts JSON。 +- 首批只实现指标卡、折线图、柱状图和饼图。 +- 布局继续使用现有业务块页面和普通页面嵌入区,不增加自由栅格编辑器。 +- 每个块只提供整行、半行、三分之一三种宽度。 + +## 当前基础 + +项目已有以下可复用能力: + +- `FrontendPageDesigner.vue` 同时支持前台和后台页面设计模式。 +- 页面布局保存在 `front_project_page_design.layout_json`。 +- 业务块定义位于 `business-blocks/*/block.json`。 +- `BusinessBlockRegistryService` 负责定义加载、表字段校验和布局校验。 +- `BusinessBlockGenerationService` 按业务块实例生成前端组件、API 和后端文件。 +- `business-blocks-v1` 支持业务块页面,普通页面支持 `embeddedBlocks.top` 和 `embeddedBlocks.bottom`。 +- 后台页面类型已经允许选择业务块页面,但页面入口当前没有向后台设计器传入业务块定义。 + +因此,本需求的核心不是新增一条独立链路,而是把现有链路扩展为可按使用端和块类型工作。 + +## 总体架构 + +```text +后台页面设计器 + | + | 选择 admin 图表块并配置单表聚合 DSL + v +front_project_page_design.layout_json + | + | 保存时校验表、字段、字段类型、聚合和筛选 + v +BusinessBlockRegistryService + | + | 生成 Vue/ECharts、API、Controller、Service、Mapper + v +BusinessBlockGenerationService + | + v +生成后的 Qing 后台运行页面 +``` + +前后台共用业务块注册和生成基础设施,但定义通过 `surfaces` 限制可见范围,模板通过类型区分生成目标。 + +## 业务块协议 2.0 + +### 定义扩展 + +业务块定义增加以下字段: + +```json +{ + "code": "admin_line_chart", + "name": "折线图", + "category": "数据图表", + "kind": "chart", + "surfaces": ["admin"], + "placements": ["embedded", "page"], + "chartType": "line", + "datasetSchema": "single-table-aggregate-v1", + "version": 2, + "defaultSpan": 12, + "templates": [] +} +``` + +字段含义: + +- `kind`:块类型。已有业务块归一化为 `business`,图表块为 `chart`。 +- `surfaces`:适用端,支持 `frontend`、`admin`。 +- `placements`:允许放置到普通页面嵌入区或业务块页面。 +- `chartType`:`metric`、`line`、`bar`、`pie`。 +- `datasetSchema`:图表使用的数据配置协议。 +- `defaultSpan`:默认宽度,取值为 `12`、`6`、`4`。 + +兼容规则: + +- 老定义缺少 `kind` 时按 `business` 处理。 +- 老定义缺少 `surfaces` 时按 `["frontend"]` 处理。 +- 老定义的单值 `placement` 归一化为 `placements` 数组。 +- 老页面和老业务块实例不要求迁移。 + +### 实例扩展 + +图表块实例保存在现有页面布局 JSON 中: + +```json +{ + "id": "admin_line_chart_001", + "blockCode": "admin_line_chart", + "name": "近 30 天销售趋势", + "span": 12, + "dataset": { + "schema": "single-table-aggregate-v1", + "table": "shop_order", + "dimension": { + "field": "create_time", + "timeUnit": "day" + }, + "metrics": [ + { + "field": "amount", + "aggregate": "sum", + "alias": "salesAmount", + "label": "销售额" + } + ], + "filters": [ + { + "field": "status", + "operator": "eq", + "value": "PAID" + } + ], + "dateRange": { + "field": "create_time", + "preset": "last_30_days" + }, + "sort": { + "by": "dimension", + "order": "asc" + }, + "limit": 100 + }, + "display": { + "showTitle": true, + "showLegend": true, + "smooth": true, + "numberFormat": "decimal", + "emptyText": "暂无数据" + } +} +``` + +现有 `config` 字段继续服务于购物车、公告、轮播等老业务块。图表使用结构化的 `dataset` 和 `display`,避免把嵌套配置塞入 `Map`。 + +## 单表聚合 DSL + +### 支持能力 + +- 一张数据表。 +- 最多一个维度字段。 +- 一个到三个指标。 +- 聚合函数:`count`、`sum`、`avg`。 +- 静态筛选条件。 +- 日期范围预设。 +- 按维度或指标排序。 +- 限制返回分组数量。 + +### 字段类型约束 + +- `count` 可用于整表或任意字段。 +- `sum`、`avg` 只能用于数值字段。 +- 普通维度支持文本、枚举、数字和日期时间字段。 +- `timeUnit` 只能用于日期时间字段。 +- 时间粒度一期支持 `day`、`week`、`month`。 +- 指标别名在同一块内必须唯一。 + +### 筛选运算符 + +一期支持: + +- `eq` +- `ne` +- `gt` +- `gte` +- `lt` +- `lte` +- `between` +- `in` +- `is_null` +- `is_not_null` + +筛选值必须与字段类型兼容。单个块最多配置十个筛选条件。 + +### 日期范围 + +一期提供以下预设: + +- 今天 +- 最近 7 天 +- 最近 30 天 +- 本月 +- 本年 +- 固定起止日期 + +日期预设在生成后的服务端计算,避免依赖浏览器时间拼接 SQL。 + +### 数量限制 + +- 全局最大分组数为 500。 +- 折线图默认 100 个分组。 +- 柱状图默认 20 个分组。 +- 饼图默认 10 个分组,最大 20 个。 +- 指标卡不返回维度分组。 + +## 四种图表块 + +### 指标卡 + +- 不要求维度。 +- 只允许一个指标。 +- 支持前缀、后缀、小数位、标题和辅助说明。 +- 一期不计算同比、环比;辅助说明为静态文案。 + +### 折线图 + +- 必须配置一个维度。 +- 支持一个到三个指标。 +- 时间维度可配置日、周、月粒度。 +- 展示配置支持平滑曲线、面积填充和图例。 + +### 柱状图 + +- 必须配置一个维度。 +- 支持一个到三个指标。 +- 展示配置支持横向、纵向、堆叠和 Top N。 + +### 饼图 + +- 必须配置一个分类维度。 +- 只允许一个指标。 +- 展示配置支持实心、环形、标签和“其他”分组。 + +## 页面设计器 + +### 素材面板 + +后台模式请求 `scope=admin` 的业务块定义,只展示 `surfaces` 包含 `admin` 的定义。 + +图表块归入“数据图表”分类: + +- 指标卡 +- 折线图 +- 柱状图 +- 饼图 + +前台模式不显示这四个块。现有前台业务块也不会因为本需求自动出现在后台素材池。 + +### 放置方式 + +图表块支持: + +- 普通后台页面顶部业务块区。 +- 普通后台页面底部业务块区。 +- 后台业务块页面。 + +块实例支持拖拽排序和三档宽度: + +- `span=12`:整行。 +- `span=6`:半行。 +- `span=4`:三分之一。 + +画布使用 12 列 CSS Grid 自动换行,不提供任意坐标、任意缩放和断点级布局编辑。 + +### 属性面板 + +选中图表块后,右侧分为三个页签。 + +“数据”页签: + +- 标题 +- 数据表 +- 维度字段 +- 时间粒度 +- 指标字段 +- 聚合方式 +- 筛选条件 +- 日期范围 +- 排序 +- Top N 或分组上限 + +“展示”页签: + +- 图例 +- 颜色主题 +- 数值格式 +- 图表类型特有选项 +- 空数据文案 + +“权限”页签: + +- 显示“继承所在后台页面”。 +- 一期不允许单个块覆盖页面权限。 +- 当前生成目标若只有后台登录保护,则块继承该登录保护;本需求不额外建设块级 RBAC。 + +### 预览 + +设计器内的即时预览使用稳定的样例数据,只验证图形、标题、图例、格式和布局。 + +配置变化后 400 毫秒防抖刷新当前块。真实数据库结果在保存并生成运行预览后验证。本期不增加设计器直接执行聚合 SQL 的接口。 + +这样可以避免设计阶段访问未初始化的数据源,也减少预览查询对数据库的压力。 + +## API 调整 + +### 业务块定义 + +现有接口调整为: + +```text +GET /front/project/{projectId}/business-blocks?scope=admin +``` + +行为: + +- 校验项目归属。 +- `scope` 归一化为 `frontend` 或 `admin`。 +- 只返回 `surfaces` 包含当前 scope 的定义。 +- 前端 `listBusinessBlocks(projectId, scope)` 显式传入当前页面设计范围。 + +`PageDesignerView.vue` 不再通过“后台传空数组”隐藏业务块,而是传入后端过滤后的定义。 + +### 页面保存 + +继续使用现有页面设计保存接口,不新增业务块实例表: + +```text +PUT /front/project/{projectId}/page-designs/{designId}?scope=admin +``` + +保存时增加图表 DSL 校验。任一图表块无效时,整个页面设计保存失败,并返回块名称和具体配置项。 + +### 运行时数据接口 + +每个生成的图表块实例提供只读接口: + +```text +GET /business-blocks/{instanceCode}/data +``` + +响应协议: + +```json +{ + "dimensions": [ + { + "key": "2026-06-01", + "label": "06-01" + } + ], + "series": [ + { + "key": "salesAmount", + "name": "销售额", + "values": [12800.5] + } + ], + "summary": { + "value": 86420, + "count": 328 + } +} +``` + +指标卡读取 `summary`;折线图和柱状图读取 `dimensions` 与 `series`;饼图把维度和第一组指标映射为分类占比。 + +## 后端校验 + +`BusinessBlockRegistryService` 增加以下职责: + +- 按 `surface` 过滤定义。 +- 归一化协议 1.0 和 2.0 定义。 +- 校验图表块只能出现在后台页面。 +- 校验数据表存在于项目数据库设计。 +- 校验维度、指标、筛选和日期字段存在。 +- 校验聚合函数与字段类型匹配。 +- 校验图表类型需要的维度和指标数量。 +- 校验运算符、筛选值、排序字段和 limit。 +- 校验 `span` 只能为 `12`、`6`、`4`。 + +错误消息包含业务块名称和配置项,例如: + +```text +折线图“近 30 天销售趋势”的指标字段 amount 不是数值类型,不能使用 SUM +``` + +## 代码生成 + +### 前端 + +生成项目增加 ECharts 依赖,并提供共享图表工具: + +- 图表初始化与销毁。 +- 窗口尺寸变化时 resize。 +- 统一加载、空数据和错误状态。 +- 统一主题颜色与数值格式。 + +每个图表块仍按现有业务块模式生成独立 Vue 组件和 API 文件。该方式会增加文件数量,但与当前生成机制一致,实例隔离清楚,也便于预览单个生成文件。 + +### 后端 + +每个实例生成只读的 Controller、Service 和 Mapper 文件。 + +生成 SQL 规则: + +- 表名和字段名只能来自已校验的项目数据库元数据。 +- 聚合函数只能来自固定枚举。 +- MySQL 时间维度使用固定的 `DATE_FORMAT` 模板。 +- 筛选值通过 MyBatis 参数绑定。 +- 排序只能引用生成后的维度或指标别名。 +- 不接受客户端传入表名、字段名、SQL 片段、聚合函数或排序表达式。 + +生成的接口位于后台认证保护范围内,并继承所在页面当前具备的后台访问边界。 + +## 权限与安全 + +- 图表块不能放入前台页面。 +- 块不拥有独立权限,继承后台页面和后台登录态。 +- 设计器保存前做元数据白名单校验。 +- 生成阶段再次校验,防止绕过页面保存直接生成。 +- 运行时只接受生成代码中预定义的查询,不接受动态查询结构。 +- 最大分组数和筛选数量受限。 +- 空值和数值聚合使用安全的默认处理,避免前端出现 `NaN`。 + +块级 RBAC、部门数据权限和用户可编辑筛选器不属于一期。后续若项目增加稳定的页面权限模型,再由图表块继承该模型,不单独发明另一套权限协议。 + +## 错误处理 + +### 设计时 + +- 必填配置缺失时在右侧表单直接标红。 +- 字段被删除或类型发生变化时,页面标记为“需要修复”。 +- 无效页面不能保存,也不能生成预览。 +- 错误定位到具体块和具体字段。 + +### 运行时 + +- 空结果展示块级空状态。 +- 当前接口失败时只让当前块显示错误和重试按钮。 +- 一个图表块失败不影响同页其他块。 +- 组件卸载时销毁 ECharts 实例和 resize 监听。 + +## 数据库与兼容性 + +- 不新增数据库表。 +- 不修改 `front_project_page_design` 表结构。 +- 新配置继续存入 `layout_json`。 +- 老页面布局保持原样可读。 +- 老业务块定义通过归一化逻辑继续工作。 +- 前台业务块生成结果不因本需求改变。 + +## 测试 + +### 前端 + +- 后台页面能获取并展示四个图表块。 +- 前台页面不展示后台图表块。 +- 拖入、选择、删除、排序和宽度切换正确更新布局 JSON。 +- 图表配置面板按图表类型显示正确字段。 +- 类型不匹配和必填缺失显示块级错误。 +- 样例数据预览支持加载、空数据和错误状态。 +- 旧业务块页面和普通页面嵌入块行为不回归。 + +### 后端 + +- 业务块定义能按 scope 过滤。 +- 老定义能被正确归一化。 +- 表、字段、字段类型、聚合、筛选、时间粒度、排序和 limit 校验完整。 +- 后台图表块不能保存到前台页面。 +- 无效布局不能进入代码生成。 + +### 生成器 + +- 四种图表生成正确的 Vue、API、Controller、Service 和 Mapper。 +- 生成项目包含 ECharts 依赖。 +- SQL 只包含白名单标识符和固定函数。 +- 筛选值使用参数绑定。 +- 统一响应能被四种组件正确消费。 +- 多块页面按 `span` 正确排列。 +- 单块接口失败不会影响其他组件。 + +## 分阶段落地 + +### 第一阶段:协议和可见范围 + +- 扩展业务块定义 DTO。 +- 增加定义归一化和 scope 过滤。 +- 修改业务块列表 API 和后台设计器传参。 +- 保证旧定义与旧页面测试通过。 + +### 第二阶段:图表设计器 + +- 增加图表块实例模型和单表聚合 DSL。 +- 增加专用图表配置面板。 +- 增加三档宽度和 12 列布局。 +- 增加样例数据即时预览。 + +### 第三阶段:校验和代码生成 + +- 完成 DSL 后端校验。 +- 增加 ECharts 共享运行组件。 +- 增加四个图表块定义和生成模板。 +- 生成只读聚合接口。 + +### 第四阶段:验证和发布 + +- 前后端自动化测试。 +- 使用包含数值、枚举、日期字段的订单表做运行预览。 +- 验证前台业务块、后台 CRUD 页面和老项目兼容性。 +- 文档中说明一期限制和后续扩展边界。 + +## 后续扩展 + +协议稳定后可以逐项增加: + +- 表格统计块。 +- 排行榜块。 +- 待办列表块。 +- 审核工作台块。 +- 页面级公共筛选器。 +- 关联表数据集。 + +这些能力不进入本期,也不预留可执行 SQL 或脚本入口。