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

757 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# 后台配置 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 配置平台。`