JeecgBoot Online 报表 AI 自动生成器
将自然语言描述的报表需求,转换为 Online 报表配置,并通过 API 自动创建/编辑/查询。
重要:本 skill 处理「Online 报表」(SQL 驱动的只读数据报表),不涉及 Online 表单(cgform)或设计器表单(desform)。
核心能力
| 操作 | 说明 |
|---|---|
| 查询报表 | 列出系统中所有 Online 报表,查看字段和参数配置 |
| 新增报表 | 从自然语言需求或 SQL 创建报表 |
| 编辑报表 | 修改现有报表的字段、参数、SQL |
Step 0: 收集凭证
每次操作前必须收集以下信息(如果用户已提供则跳过):
- API 地址 — JeecgBoot 后端地址,如
https://boot3.jeecg.com/jeecgboot - X-Access-Token — JWT 令牌,从浏览器 F12 → Network → 任意请求的 Request Headers 中复制
用户未提供时提示:
请提供 JeecgBoot 后端地址和 X-Access-Token。
Step 1: 判断操作类型
根据用户意图判断操作类型:
| 用户意图关键词 | 操作 |
|---|---|
| 列出报表 / 查询报表 / 查看所有报表 / 有哪些报表 | 查询报表 → Step 2 |
| 创建 / 新建 / 做一个 / 生成报表 | 新增报表 → Step 3 |
| 修改 / 编辑 / 改字段 / 加字段 / 删除字段 | 编辑报表 → Step 4 |
⚠️ 菜单挂载与角色授权为可选操作,不得默认执行:
- 用户只说"创建报表"→ 仅执行
create_report+validate_report,不挂载菜单,不授权角色- 用户明确说"挂载到菜单"、"绑定菜单"、"授权给 xxx 角色"等关键词 → 才调用
publish_report或create_and_publish- 违反此规则会导致:超出用户意图、产生不必要的菜单记录、因全量拉取权限列表而显著增加耗时
Step 2: 查询报表
API 初始化(统一入口):所有 Python 操作前必须先调用
init_api,与desform_utils保持一致:import sys sys.path.insert(0, r'<skill目录>/scripts') from onlreport_api import init_api init_api('<api_base>', '<token>')后续按需导入:
list_all_reports_table,list_fields_by_code_table,list_reports,query_report,list_fields,list_params,parse_sql,create_report,edit_report,gen_id,create_menu,get_role_id_by_code,grant_menu_to_role,add_data_rule,query_data_rules
2.1 快速列表(语法糖)
首选方式,调用 list_all_reports_table() 一次返回所有报表的名称/编码/SQL 表格,自动分页遍历:
from onlreport_api import init_api, list_all_reports_table
init_api('<api_base>', '<token>')
list_all_reports_table()
返回 Markdown 表格,仅含三个字段(报表名称、报表编码、报表 SQL),方便 AI 直接使用:
| 报表名称 | 报表编码 | 报表 SQL |
|----------|----------|----------|
| 关联报表查询 | fz_sql | SELECT u.id, u.username ... |
| ... | ... | ... |
或通过 CLI:
python "<skill目录>/scripts/onlreport_api.py" \
--api-base <URL> --token <TOKEN> -a list-table
2.2 按编码查字段(语法糖)
首选方式,调用 list_fields_by_code_table(code) 直接通过报表编码查字段:
from onlreport_api import init_api, list_fields_by_code_table
init_api('<api_base>', '<token>')
list_fields_by_code_table('fz_sql')
返回 Markdown 表格,仅含三个字段(字段编码、字段文本、字段类型),自动分页:
| 字段编码 | 字段文本(显示名) | 字段类型 |
|----------|-----------------|----------|
| id | ID | String |
| username | username | String |
| realname | realname | String |
或通过 CLI:
python "<skill目录>/scripts/onlreport_api.py" \
--api-base <URL> --token <TOKEN> -a fields-table --code fz_sql
底层 API:GET /online/cgreport/item/listByHeadCode?headCode={code}
2.3 查询报表详情
用户指定报表 ID 或编码后,依次查询:
GET /online/cgreport/head/queryById?id={headId} # 报表头配置
GET /online/cgreport/item/listByHeadId?headId={headId} # 字段列表
GET /online/cgreport/param/listByHeadId?headId={headId} # 参数列表
展示完整配置供用户参考,询问是否需要修改。
Step 3: 新增报表
3.1 收集需求
从用户描述中提取:
| 信息 | 来源 | 示例 |
|---|---|---|
| 报表编码 (code) | 自动生成 snake_case | sales_report |
| 报表名称 (name) | 用户指定 | "销售统计报表" |
| SQL 语句 (cgrSql) | 用户提供 SQL 或描述需求 | SELECT ... FROM ... |
| 数据源 (dbSource) | 用户指定,空=默认 | second_db |
创建前必须校验报表编码唯一性,调用 check_code_available(code) 或直接调用接口:
GET /sys/duplicate/check?tableName=onl_cgreport_head&fieldName=code&fieldVal={code}
返回 success: true 表示编码可用,false 表示已被占用,需换一个。create_report() 内部已自动调用此校验。
SQL 有两种来源:
- 用户直接提供 SQL → 直接使用
- 用户描述需求 → 需要用户确认表名和字段(调用 parseSql 验证)
3.2 调用 parseSql 解析字段
必须先调用 parseSql 获取字段和参数列表:
GET /online/cgreport/head/parseSql?sql={urlEncodedSql}&dbKey={dbKey}
返回结构:字段列表 fields[] 和参数列表 params[]。
为什么必须先调用 parseSql? 因为 SQL 中的
${paramName}会被解析为参数列表,字段列表是后续构造 items 配置的依据。
parseSql 失败处理
SQL 包含复杂函数(如 name like concat('%','${username}','%'))时会解析失败。解决方案:
- 先将问题条件去掉,用简化 SQL 解析
- 解析成功后,在 SQL 参数 tab 手工新增参数名(如
username,对应${username}) - 最终保存时 cgrSql 使用完整的原始 SQL
3.3 智能字段配置
根据字段名语义,自动推导每个字段的配置。
字段通用属性
searchMode 说明:有效值只有
single(单值查询)和group(范围查询)两种。String 类型的single查询在后端会自动执行 LIKE 模糊匹配;Date/Datetime 类型用group实现范围选择。有字典配置时下拉选择自动生效。
| 字段名模式 | fieldTxt(中文名) | fieldType | isShow | isSearch | searchMode | isOrder | isTotal |
|---|---|---|---|---|---|---|---|
| id / 主键 | ID | String | 0(隐藏) | null | - | null | - |
| name / title | 名称/标题 | String | 1 | 1 | single | null | - |
| code / no | 编码/编号 | String | 1 | 1 | single | null | - |
| status | 状态 | String | 1 | 1 | single | null | - |
| type / category | 类型/分类 | String | 1 | 1 | single | null | - |
| amount / money / price / fee | 金额/费用/价格 | BigDecimal | 1 | null | - | 1 | "1" |
| count / qty / num / number | 数量 | Integer | 1 | null | - | 1 | "1" |
| date / sale_date | 日期 | Date | 1 | 1 | group | 1 | - |
| time / datetime | 时间 | Datetime | 1 | 1 | group | 1 | - |
| create_by / update_by | 创建人/更新人 | String | 0(隐藏) | null | - | null | - |
| create_time / update_time | 创建时间/更新时间 | Datetime | 1 | null | - | 1 | - |
| sex | 性别 | String | 1 | 1 | single | null | - |
| age | 年龄 | Integer | 1 | null | - | null | - |
| 邮箱 | String | 1 | null | - | null | - | |
| phone / mobile / tel | 电话/手机号 | String | 1 | null | - | null | - |
| address | 地址 | String | 1 | null | - | null | - |
| remark / description / content | 备注/描述 | String | 1 | null | - | null | - |
| dept / org | 部门/组织 | String | 1 | 1 | single | null | - |
| sys_org_code / tenant_id | 系统字段 | String | 0(隐藏) | null | - | null | - |
| 图片/附件字段 | 图片 | Image | 1 | null | - | null | - |
parseSql 返回的 fieldType 通常是 String,AI 必须根据字段名语义修正为正确的类型(Date/Datetime/BigDecimal/Integer/Long/Image 等)。
isOrder/isSearch 为 null 表示"否",不要用
0,否则可能影响前端展示。
字典配置 (dictCode)
普通字典(输入字典 code):
- 常用系统字典:
sex、priority、valid_status、urgent_level、yn
SQL 字典(查另一张表):格式固定为 SELECT id 'value', name 'text' FROM table_name,字段别名必须是 value 和 text:
SELECT username AS value, realname AS text FROM sys_user
replaceVal 格式(导出时文本替换):显示文本_数据库值 逗号分隔,例如 男_1,女_2
分组表头 (groupTitle)
同一分组的多个字段设置相同的 groupTitle,可实现多级表头:
{"fieldName": "q1_amount", "groupTitle": "第一季度"}
{"fieldName": "q1_count", "groupTitle": "第一季度"}
字段跳转 (fieldHref)
支持以下语法:
| 用法 | 示例 |
|---|---|
| 跳转到菜单路径 | /system/user 或 /system/user?sex=1 |
| 跳转到 Vue 组件 | /jeecg/helloworld.vue?id=${id} |
| 跳转到外部链接 | http://jeecg.com?id=${id} |
| 动态参数(当前行字段值) | http://jeecg.com?sex=${sex} |
| JS 表达式(双花括号) | /account/center?name=${name}&age={{${age} + 100}} |
| 获取当前登录 Token | http://api.example.com?token={{ACCESS_TOKEN}} |
Step 4: 编辑报表
4.1 查询现有配置
- 用户提供报表 ID 或编码
- 依次调用 queryById、listByHeadId(字段)、listByHeadId(参数)
- 展示现有配置
4.2 确认修改需求
根据用户需求,确定:
- 哪些字段需要修改 isShow/isSearch/orderNum 等
- 哪些字段需要新增或删除
- SQL 是否需要调整
4.3 构造 editAll 请求
editAll 使用 PUT 方法(非 POST)。
与新增类似,但需注意:
head.id= 现有报表 ID(必填)deleteItemIds= 要删除的字段 ID 逗号拼接deleteParamIds= 要删除的参数 ID 逗号拼接
替换参数的完整流程
编辑时若需要替换参数(如从无参改为有参,或修改参数配置),步骤:
- 查询旧参数列表,收集所有旧参数 ID
- 新参数对象必须包含
id(gen_id()生成)和headId(报表 ID) - 在 payload 中设置
deleteParamIds删除旧参数,params传入新参数
old_params = api_request(f'/online/cgreport/param/listByHeadId?headId={head_id}')['result']
delete_param_ids = ','.join(p['id'] for p in old_params) if old_params else None
new_params = [
{"id": gen_id(), "headId": head_id, "paramName": "log_type", "paramTxt": "日志类型", "paramValue": "1", "orderNum": 1}
]
payload = {
"head": {...},
"items": items,
"params": new_params,
"deleteParamIds": delete_param_ids # 有旧参数时必传,否则会重复
}
注意:editAll 的 params 中每条记录必须有
id和headId,否则保存后参数不生效。新增时(create_report)的 params 可以不带这两个字段。
Step 5: 展示摘要并确认
在执行 API 前必须展示以下摘要,等待用户确认:
## Online 报表配置摘要
- 报表编码:sales_repor