unis_crm/docs/后台配置SQL驱动的经营分析方案.md

757 lines
13 KiB
Markdown
Raw Normal View History

2026-04-30 07:06:53 +00:00
# 后台配置 SQL 驱动的经营分析方案
## 1. 目标
本方案满足你明确提出的目标:
- 统计定义在后台管理配置
- H5 端直接按配置展示
- 取数 SQL 也可以在后台管理配置
- 后续口径变化时,尽量不改前端代码
- 同时兼顾 PC 端与 H5 / 企业微信端
这套方案的核心思想是:
- `前端不写死报表`
- `后台管理端维护报表定义`
- `后端读取配置 SQL 执行`
- `H5 / PC 统一走配置渲染`
## 2. 结论先说
这个方案是可行的,但建议不要做“完全无限制的任意 SQL 执行”,而要做:
- `后台可配置 SQL`
- `后端受控执行 SQL`
- `带参数模板`
- `带权限注入`
- `带版本管理`
- `带审核发布`
也就是说,不是直接把数据库裸露给后台管理员,而是做一个“`可配置 SQL 报表平台`”。
## 3. 适合你的整体架构
建议拆成 4 个部分:
### 3.1 报表定义后台
给管理员使用,用于配置:
- 报表名称
- 适用端
- 筛选条件
- 图表类型
- 指标字段
- 维度字段
- SQL 模板
- 参数说明
- 发布版本
### 3.2 报表执行引擎
后端新增一个报表引擎服务,职责是:
- 读取报表配置
- 校验参数
- 替换 SQL 模板变量
- 自动追加权限条件
- 执行 SQL
- 返回统一结果结构
### 3.3 H5 / PC 动态渲染层
前端不再写死每个图表,而是:
- 先请求报表页面配置
- 再请求每个组件的数据
- 根据配置渲染 KPI、柱状图、折线图、饼图、表格
### 3.4 配置治理层
用于保证 SQL 配置安全可控:
- 草稿/已发布版本
- 审核流
- 执行日志
- 回滚版本
- 性能限制
## 4. 最推荐的实现模式
你要的是“SQL 可配置”,这里推荐两个级别。
### 4.1 级别一SQL 模板可配置
这是最推荐的。
后台配置的不是完全自由 SQL而是带占位符的模板 SQL例如
```sql
select
owner_user_id as ownerUserId,
sum(amount) as actualAmount
from crm_opportunity
where status = 'won'
and won_at between ${startDate} and ${endDate}
${dataScopeClause}
${orgFilterClause}
group by owner_user_id
order by actualAmount desc
```
特点:
- 可配灵活
- 后端可控
- 容易注入权限
- 易于参数校验
### 4.2 级别二:完全自由 SQL
不建议默认开放。
如果一定要支持,也建议:
- 仅超级管理员可用
- 仅允许 `select`
- 禁止 `update/delete/insert/drop`
- 禁止多语句
- 禁止访问敏感表
- 强制走只读数据源
- 强制超时和行数限制
## 5. 业务上如何满足“销售完成业绩”和“区域业绩”
这两个场景很适合做成后台配置化报表。
### 5.1 销售完成业绩
建议报表结构:
- KPI
- 销售目标
- 实际完成
- 完成率
- 同比/环比
- 图表:
- 销售排行
- 趋势图
- 部门分布
- 明细:
- 销售员、目标值、完成值、完成率、区域、趋势
### 5.2 区域业绩
建议报表结构:
- KPI
- 区域目标
- 区域实际
- 区域完成率
- 图表:
- 区域排名
- 区域趋势
- 区域构成
- 明细:
- 大区、省区、城市、销售数、目标、实际、完成率
这两类都可以通过后台 SQL 配置实现。
## 6. 推荐的数据模型
建议新增以下表。
### 6.1 `analytics_report`
存报表主定义。
建议字段:
- `id`
- `report_code`
- `report_name`
- `report_category`
- `description`
- `status`
- `terminal_scope`
- `default_time_granularity`
- `visible`
- `created_by`
- `updated_by`
- `created_at`
- `updated_at`
说明:
- `terminal_scope` 用于区分 `pc / h5 / both`
### 6.2 `analytics_report_version`
存报表版本。
建议字段:
- `id`
- `report_id`
- `version_no`
- `version_status`
- `change_log`
- `published_by`
- `published_at`
- `config_json`
- `created_at`
说明:
- 一个报表允许多个版本
- H5 默认读已发布版本
### 6.3 `analytics_widget`
存一个报表下的组件定义。
建议字段:
- `id`
- `report_version_id`
- `widget_code`
- `widget_name`
- `widget_type`
- `title`
- `subtitle`
- `layout_json`
- `props_json`
- `data_source_id`
- `sort_order`
- `visible`
### 6.4 `analytics_data_source`
存数据源定义,也就是 SQL 配置核心。
建议字段:
- `id`
- `source_code`
- `source_name`
- `source_type`
- `dataset_code`
- `query_sql`
- `count_sql`
- `parameter_schema_json`
- `result_schema_json`
- `timeout_ms`
- `max_rows`
- `cache_ttl_seconds`
- `enabled`
- `created_at`
- `updated_at`
### 6.5 `analytics_filter_def`
存筛选器定义。
建议字段:
- `id`
- `report_version_id`
- `filter_code`
- `filter_name`
- `filter_type`
- `data_type`
- `default_value_json`
- `options_source_type`
- `options_source_config`
- `sort_order`
- `visible`
### 6.6 `analytics_sql_publish_log`
存 SQL 发布日志。
建议字段:
- `id`
- `data_source_id`
- `version_no`
- `old_sql`
- `new_sql`
- `change_summary`
- `operator_id`
- `created_at`
### 6.7 `analytics_query_log`
存执行日志。
建议字段:
- `id`
- `report_code`
- `widget_code`
- `data_source_id`
- `request_user_id`
- `request_params_json`
- `final_sql_preview`
- `duration_ms`
- `row_count`
- `success`
- `error_message`
- `created_at`
## 7. 配置中心怎么设计
后台建议做成 5 个页面。
### 7.1 报表管理
配置:
- 报表基本信息
- 展示端
- 菜单归属
- 是否发布
### 7.2 页面布局管理
配置:
- KPI 卡片
- 图表组件
- 表格组件
- H5 是否显示
- PC 是否显示
- 顺序与显隐
### 7.3 SQL 数据源管理
配置:
- SQL 模板
- 参数定义
- 字段映射
- 结果预览
- 缓存策略
- 执行限制
### 7.4 筛选器管理
配置:
- 时间筛选
- 区域筛选
- 销售筛选
- 部门筛选
- 自定义枚举
### 7.5 发布与回滚
配置:
- 草稿
- 预览
- 发布
- 回滚历史版本
## 8. SQL 配置方式建议
这是关键设计点。
### 8.1 SQL 模板结构
建议使用模板 SQL不要直接存“拼好的最终 SQL”。
示例:
```sql
select
region_code as regionCode,
region_name as regionName,
sum(actual_amount) as actualAmount,
sum(target_amount) as targetAmount,
case when sum(target_amount) = 0 then 0
else round(sum(actual_amount) / sum(target_amount) * 100, 2)
end as completionRate
from analytics_sales_performance_fact
where stat_date between ${startDate} and ${endDate}
${orgFilterClause}
${regionFilterClause}
${salesFilterClause}
${dataScopeClause}
group by region_code, region_name
order by actualAmount desc
limit ${limit}
```
### 8.2 参数定义
每条 SQL 必须配参数定义。
示例:
```json
[
{ "name": "startDate", "type": "date", "required": true },
{ "name": "endDate", "type": "date", "required": true },
{ "name": "orgId", "type": "long", "required": false },
{ "name": "regionCode", "type": "string", "required": false },
{ "name": "salesUserId", "type": "long", "required": false },
{ "name": "limit", "type": "int", "required": false, "defaultValue": 50 }
]
```
### 8.3 建议支持的占位符
后端统一支持如下占位符:
- `${startDate}`
- `${endDate}`
- `${limit}`
- `${offset}`
- `${dataScopeClause}`
- `${orgFilterClause}`
- `${regionFilterClause}`
- `${salesFilterClause}`
### 8.4 动态条件注入方式
例如 `regionCode` 为空时,不拼条件;
有值时自动生成:
```sql
and region_code = :regionCode
```
不建议把这种逻辑写死在前端。
## 9. 前端展示怎么实现
虽然 SQL 在后台配置,但前端还是要有统一协议。
### 9.1 H5 与 PC 共用配置协议
前端请求:
- 页面定义
- 筛选器定义
- Widget 定义
- Widget 数据
### 9.2 Widget 类型建议
支持以下组件:
- `kpi`
- `line`
- `bar`
- `stack-bar`
- `pie`
- `table`
- `rank-list`
### 9.3 H5 展示规则
建议在配置里加上:
- `showOnPc`
- `showOnH5`
- `h5SortOrder`
- `pcSortOrder`
- `h5ChartType`
- `pcChartType`
这样同一个报表可以:
- PC 显示表格 + 图表
- H5 只显示 KPI + Top10
### 9.4 H5 页面渲染流程
1. 获取报表定义
2. 获取筛选项定义
3. 渲染页面骨架
4. 请求组件数据
5. 渲染图表
## 10. 后端执行引擎设计
建议新增一个 `AnalyticsQueryService`
职责:
- 加载已发布报表版本
- 解析筛选条件
- 校验参数类型
- 生成最终 SQL
- 注入权限条件
- 执行查询
- 做缓存
- 记录日志
### 10.1 执行流程
1. 读取报表配置
2. 读取组件配置
3. 读取数据源 SQL 模板
4. 根据请求参数构造过滤条件
5. 自动注入数据权限
6. 生成最终 SQL
7. 执行查询
8. 转成统一结果结构
### 10.2 统一返回结构
建议:
```json
{
"reportCode": "sales-performance",
"title": "销售完成业绩",
"filters": [],
"widgets": [
{
"widgetCode": "sales-rank",
"widgetType": "bar",
"title": "销售业绩排名",
"columns": ["ownerName", "actualAmount"],
"rows": []
}
]
}
```
## 11. 权限与安全控制
这是这个方案能不能上线的关键。
### 11.1 禁止直接执行危险 SQL
必须限制:
- 只允许 `select`
- 禁止 `insert`
- 禁止 `update`
- 禁止 `delete`
- 禁止 `drop`
- 禁止 `alter`
- 禁止多语句执行
### 11.2 必须强制数据权限注入
即使后台配置 SQL也不能信任配置人手动写权限条件。
必须由后端统一追加:
- 当前租户过滤
- 当前用户数据范围
- 组织权限范围
### 11.3 建议使用只读数据源
报表执行引擎单独使用只读数据库账号。
### 11.4 超时与数据量限制
每条数据源定义都要支持:
- 最大执行时长
- 最大返回行数
- 最大导出行数
### 11.5 SQL 审核
建议发布前做 SQL 检查:
- 关键词校验
- 表白名单校验
- 字段白名单校验
- explain 成本校验
## 12. 针对“销售完成业绩”和“区域业绩”的配置方式
### 12.1 销售完成业绩推荐做法
建议先沉淀一个业绩事实层表或视图:
- `analytics_sales_performance_fact`
字段建议:
- `stat_date`
- `sales_user_id`
- `sales_user_name`
- `org_id`
- `org_name`
- `region_code`
- `region_name`
- `target_amount`
- `actual_amount`
- `won_amount`
- `contract_amount`
- `payment_amount`
- `adjust_amount`
好处:
- 前端怎么展示都行
- 后台 SQL 简单很多
- 口径变更时只改事实层生成逻辑或切换版本
### 12.2 区域业绩推荐做法
建议同样通过事实层统一:
- 客户区域
- 项目区域
- 销售归属区域
如果口径会改,可以做多个字段:
- `customer_region_code`
- `project_region_code`
- `owner_region_code`
后台 SQL 通过配置选择用哪个字段聚合。
## 13. 推荐的“SQL 可配置”分层
为了避免后期越来越乱,建议把 SQL 分成两层。
### 13.1 第一层:事实层 SQL
由研发维护。
职责:
- 把复杂业务逻辑沉淀成事实表或视图
- 处理复杂口径、去重、归属、调整项
### 13.2 第二层:展示层 SQL
由后台管理配置。
职责:
- 从事实层表/视图做汇总
- 做 KPI、排行、趋势、区域分组
这是最适合你的方案。
原因:
- 真正复杂的口径不适合完全交给后台人员写
- 但展示层统计完全可以后台配置
- H5 端可以完全动态渲染
## 14. 如果你坚持“所有 SQL 都后台可配”
也可以做,但我建议加 3 个保护措施。
### 14.1 只允许访问白名单对象
例如只允许查:
- `analytics_*`
- `crm_*`
- `work_*`
- 部分 `sys_*` 维表
### 14.2 强制 SQL 发布审核
流程建议:
- 编辑草稿
- 测试预览
- 提交审核
- 审核通过后发布
### 14.3 强制版本切换
H5 / PC 永远只读“已发布版本”,不读草稿。
## 15. API 设计建议
### 15.1 后台管理端
- `GET /api/admin/analytics/reports`
- `POST /api/admin/analytics/reports`
- `PUT /api/admin/analytics/reports/{id}`
- `GET /api/admin/analytics/reports/{id}/versions`
- `POST /api/admin/analytics/data-sources`
- `PUT /api/admin/analytics/data-sources/{id}`
- `POST /api/admin/analytics/data-sources/{id}/preview`
- `POST /api/admin/analytics/reports/{id}/publish`
### 15.2 前台 H5 / PC
- `GET /api/analytics/reports/{reportCode}`
- `POST /api/analytics/reports/{reportCode}/query`
## 16. 实施步骤建议
### 第一阶段
目标:
- 先把基础平台搭起来
内容:
- 报表定义表
- 数据源定义表
- Widget 定义表
- H5 动态渲染页
- PC 动态渲染页
- SQL 安全校验
### 第二阶段
目标:
- 上线销售完成业绩、区域业绩
内容:
- 销售业绩事实表
- 区域业绩事实表
- 报表管理页
- SQL 配置预览
- 发布与回滚
### 第三阶段
目标:
- 真正进入“后台可运营”
内容:
- 版本对比
- 审核流
- 执行监控
- 性能报警
- 缓存策略
## 17. 最终建议
如果你想实现:
- 后台管理定义
- H5 自动展示
- SQL 可配置
- 后期口径频繁修改
那么我最推荐的是:
1. 做一个 `报表定义 + SQL 数据源 + Widget 配置` 的后台管理平台
2. H5 与 PC 统一走动态渲染
3. SQL 采用“模板化 + 参数化 + 权限注入 + 发布审核”
4. 真正复杂的业绩口径优先沉淀为事实层视图或事实表
5. 展示层 SQL 再交给后台配置
一句话总结:
`这个方案完全可以做而且很适合你当前“口径复杂、变化频繁、H5要快速展示”的场景但最佳实践不是裸放任意 SQL而是做受控的后台 SQL 配置平台。`