name: jeecg-onlreport description: Use when user asks to create/edit/query Online reports, SQL reports, data reports, or says "创建报表", "生成报表", "新建报表", "查询报表", "online报表", "SQL报表", "数据报表", "统计报表", "create report", "generate report", "data report". Also triggers when user describes report requirements like "做一个销售统计报表", mentions JeecgBoot cgreport/online report, or says "查看现有报表" / "列出所有报表". This skill handles Online 报表 (SQL-driven data display/reports), not Online forms (cgform) or designer forms (desform).
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_report
- 报表名称:销售统计报表
- 数据源:默认
- 目标环境:https://boot3.jeecg.com/jeecgboot
### SQL 语句
SELECT s.id, s.name, s.amount, s.sale_date, s.status
FROM biz_sales s WHERE 1=1
### 字段配置
| 序号 | 字段名 | 显示名称 | 类型 | 显示 | 查询 | 排序 | 合计 |
|------|--------|---------|------|------|------|------|------|
| 0 | id | ID | String | 否 | 否 | 否 | - |
| 1 | name | 名称 | String | 是 | 单值 | 否 | - |
| 2 | amount | 金额 | BigDecimal | 是 | 否 | 是 | 是 |
| 3 | sale_date | 销售日期 | Date | 是 | 范围 | 是 | - |
| 4 | status | 状态 | String | 是 | 单值 | 否 | - |
### 参数
| 参数名 | 显示名称 | 默认值 |
|--------|---------|--------|
| (无) | | |
确认以上配置?(y/n)
Step 6: 调用 API
用户确认后执行。使用 Python 调用 API(Windows 环境下 curl 中文会出错):
Windows 执行环境(强制规则,违反会让用户吐槽"执行太慢")
现象:Windows 的 Bash tool 会把 python / python -c / skill 脚本当作长命令自动 run_in_background,tool 立即返回 background ID,真正输出要等完成通知——把毫秒级调用放大到数秒。
规则:
- Windows(platform=win32) → 用 Bash tool 调用
powershell -Command "python xxx.py",同步返回。 - Linux / macOS → 用 Bash tool 直接调用
python xxx.py。 - 任何平台都不用
curl:跨平台不一致,Windows Bash 下同样被后台化。
脚本执行前强制检查(3 项,缺一不可):
- ✅ Windows 下用
powershell -Command "python xxx.py",不是直接python xxx.py - ✅ 脚本已写入
.py文件(禁止python -c内联代码) - ✅ 脚本第一行已加编码声明:
import sys; sys.stdout.reconfigure(encoding='utf-8')(防 GBK 崩溃重试)
Windows 正确示例:
Bash: powershell -Command "python <skill_base_dir>/scripts/onlreport_api.py --api-base ... --token ..."
<skill_base_dir>是本 SKILL.md 所在目录,运行时用实际路径替换。
Windows 错误示例(会被后台化,用户立即感知到"卡"):
Bash: python onlreport_api.py ... ← 返回 "Command running in background with ID: xxx"
Bash: python -c "..." ← 同上
Bash: curl -X POST ... ← 同上
调用方式:import onlreport_api,调用 init_api 初始化后直接使用封装函数,无需修改脚本文件。
import sys
sys.path.insert(0, r'<skill目录>/scripts')
from onlreport_api import init_api, parse_sql, create_report, gen_id
init_api('<api_base>', '<token>')
脚本中封装了以下操作:
查询类
list_reports()— 查询报表列表list_all_reports_table()— 查询所有报表(Markdown 表格,自动分页)list_fields_by_code_table(code)— 按编码查字段(Markdown 表格)query_report(head_id)— 查询报表头list_fields(head_id)— 查询字段列表list_params(head_id)— 查询参数列表get_report_id_by_code(code)— 按编码获取报表 IDparse_sql(sql, db_key)— 解析 SQL 字段
创建 / 编辑
create_report(code, name, sql, db_source, items, params)— 创建报表,返回含head_id的 dictedit_report(...)— 编辑报表(PUT editAll)
发布流程(高级语法糖,推荐优先使用)
validate_report(head_id)— 验证 SQL 是否可执行,返回 True/Falsepublish_report(head_id, name, role_code='admin', parent_id='')— 验证 SQL + 创建菜单 + 授权角色,三步合一create_and_publish(code, name, sql, items, params=[], db_source='', role_code='admin', parent_id='')— 全流程一键完成:创建报表 + 验证 + 建菜单 + 授权
字段构建辅助
build_item(field_name, field_txt, ...)— 按字段名语义自动推断类型/查询/显示,支持手动覆盖任意属性
菜单 & 权限
create_menu(head_id, name, parent_id='')— 创建报表菜单get_role_id_by_code(role_code)— 按角色编码获取角色 IDgrant_menu_to_role(role_id, menu_id)— 追加授权菜单给角色add_data_rule(menu_id, role_id, rule_name, rule_column, rule_conditions, rule_value)— 完整四步数据规则配置
build_item 用法示例(推荐,替代手写 dict)
from onlreport_api import init_api, build_item, create_and_publish
init_api('<api_base>', '<token>')
items = [
build_item('id', 'ID', order_num=0), # 自动隐藏
build_item('username', '用户名', order_num=1), # 自动单值查询
build_item('status', '状态', order_num=2), # 自动 dictCode=valid_status
build_item('amount', '金额', order_num=3), # 自动 BigDecimal + 合计
build_item('create_time', '创建时间', order_num=4), # 自动 Datetime + 可排序
# 手动覆盖
build_item('email', '邮箱', order_num=5, field_href='mailto:${email}'),
build_item('sex', '性别', order_num=6, dict_code='sex'),
]
# 一键:建报表 + 验证 SQL + 建菜单 + 授权 admin
head_id = create_and_publish('my_report', '我的报表', 'SELECT ... FROM ...', items)
build_item 自动推断规则
| 字段名关键词 | 自动推断结果 |
|---|---|
id |
隐藏(isShow=0) |
create_by / update_by / sys_org_code / org_code |
隐藏 |
avatar / photo / image / pic / img |
Image 类型 |
amount / money / price / fee / cost |
BigDecimal,isTotal='1' |
count / qty / num / quantity |
Integer,isTotal='1' |
birthday / *_date |
Date,范围查询(group) |
*_time / *_datetime |
Datetime,可排序 |
create_time / update_time |
Datetime,可排序,不查询 |
sex |
dictCode=sex |
status |
dictCode=valid_status |
name / title / code / no |
单值查询(single) |
所有推断值均可通过参数覆盖,例:
build_item('status', '状态', dict_code='my_dict')
# 手动构造 items 原始写法(不推荐,优先使用 build_item)
items = [
{
"id": gen_id(), # 雪花 ID,19位数字字符串
"headId": None,
"fieldName": "name",
"fieldTxt": "名称",
"fieldWidth": None,
"fieldType": "String",
"searchMode": "single", # 单值查询;范围查询用 "group"
"isOrder": None, # 不排序用 null,排序用 1
"isSearch": 1,
"dictCode": None,
"fieldHref": None,
"isShow": 1,
"orderNum": 1,
"replaceVal": None,
"isTotal": None, # 不合计用 null,合计用 "1"(字符串)
"groupTitle": None,
"createBy": None,
"createTime": None,
"updateBy": None,
"updateTime": None
}
]
关键约束:
- Windows 必须用
powershell -Command "python xxx.py",不要用python xxx.py或curl - 写临时
.py脚本时用Write工具,脚本首行加import sys; sys.stdout.reconfigure(encoding='utf-8'),执行后删除临时文件 - 字段 ID 用
gen_id()生成(雪花格式 19 位数字字符串) - parseSql 返回的 fieldType 全是 String,需根据上表语义修正(或直接用
build_item自动推断) isOrder/isSearch的"否"值为null,不要用0isTotal的"是"值为字符串"1",不是数字1- 合计行仅在表内有数据时才显示;表内无数据时合计行不出现,属正常现象,录入数据后即可看到
- 合计只统计数字值;字段含空值/null/非数字内容时会显示"包含非数字内容"提示
Step 7: 验证报表 SQL 可用性
报表创建成功后,必须立即调用以下接口验证 SQL 执行正常,否则报表预览会出现 500 错误:
GET /online/cgreport/api/getColumnsAndData/{headId}
url = f'{base}/online/cgreport/api/getColumnsAndData/{head_id}'
req = urllib.request.Request(url, headers={'X-Access-Token': token})
with urllib.request.urlopen(req, timeout=10) as resp:
data = json.loads(resp.read())
if data.get('success'):
result = data.get('result', {})
columns = result.get('columns', [])
rows = result.get('rows', [])
print(f'验证通过:{len(columns)} 个字段,{len(rows)} 行数据')
else:
print('验证失败:', data.get('message'))
常见失败原因及修复:
| 错误信息 | 原因 | 修复方式 |
|---|---|---|
Unknown column 'xxx' in 'field list' |
SQL 引用了表中不存在的字段(如多租户字段 tenant_id 在非多租户版本中不存在) |
从 SQL 和字段配置中删除该字段,用 editAll 更新 |
Table 'xxx' doesn't exist |
表名错误或数据源配置有误 | 检查 SQL 中的表名和 dbSource |
syntax error |
SQL 语法错误 | 修正 SQL 语句 |
验证失败时,用 editAll(PUT)修复 SQL 和字段配置后,再次调用验证,直到返回 success: true。
Step 8: 生成菜单 SQL
报表创建成功后,脚本会自动调用 print_menu_sql(head_id, name) 输出菜单 SQL。
本地环境自动执行规则:如果 API_BASE 以 http://127.0.0.1 或 http://localhost 开头(不区分大小写),自动执行 MySQL 插入菜单:
mysql -h127.0.0.1 -P3306 -uroot -proot jeecgboot3 -e "INSERT INTO sys_permission (...) VALUES (...);"
- 如果 MySQL 失败,回退为输出 SQL 让用户手动执行
- 数据库参数默认
mysql -h127.0.0.1 -P3306 -uroot -proot jeecgboot3
菜单配置说明:
- 前端组件固定为:
modules/online/cgreport/auto/OnlCgreportAutoMain - 报表访问路径:
/online/cgreport/{headId} - 也可在「系统管理 → 菜单管理」手工新增菜单,粘贴上述配置地址,「是否是路由菜单」设为否
输出结果模板
## Online 报表操作成功
- 报表编码:{code}
- 报表名称:{name}
- 字段数量:{N} 个
- 参数数量:{M} 个
- 目标环境:{API_BASE}
- 菜单 SQL:{已自动执行 ✓ / 需手动执行}
### 菜单 SQL
INSERT INTO sys_permission (...) VALUES (...);
### 后续操作
1. ✅ 调用 `/online/cgreport/api/getColumnsAndData/{headId}` 验证 SQL 执行正常
2. 打开 JeecgBoot 后台 → Online报表
3. 找到该报表,点击「功能测试」预览效果
4. 如菜单未自动执行,手动执行上方 SQL 或在后台手动添加
5. 可在「编辑」中调整字段显示/查询/排序等配置
SQL 高级特性
参数化查询(Velocity 模板)
在 SQL 中使用 Velocity 模板语法定义参数(parseSql 会自动解析 ${paramName} 为参数列表):
SELECT * FROM biz_sales
WHERE 1=1
${#if($startDate != '')} AND sale_date >= '$startDate' ${#end}
${#if($endDate != '')} AND sale_date <= '$endDate' ${#end}
${#if($status != '')} AND status = '$status' ${#end}
对应的 params 配置(新增时可不带 id/headId,editAll 编辑时必须带):
[
{"paramName": "startDate", "paramTxt": "开始日期", "paramValue": "", "orderNum": 1},
{"paramName": "endDate", "paramTxt": "结束日期", "paramValue": "", "orderNum": 2},
{"paramName": "status", "paramTxt": "状态", "paramValue": "", "orderNum": 3}
]
editAll 编辑时的完整格式(需加 id 和 headId):
{"id": gen_id(), "headId": head_id, "paramName": "status", "paramTxt": "状态", "paramValue": "", "orderNum": 1}
URL 带参访问:获取报表配置地址后,将 ${sex} 替换为实际值访问:
/online/cgreport/{headId}?sex=1
系统变量
在 SQL 中用 #{变量名} 引用当前登录用户信息,实现数据隔离:
SELECT * FROM sys_user WHERE username = '#{sys_user_code}'
| 变量 | 说明 |
|---|---|
#{sys_user_code} |
当前登录用户账号 |
#{sys_user_name} |
当前登录用户真实姓名 |
#{sys_date} |
当前系统日期 |
#{sys_time} |
当前系统时间 |
#{sys_org_code} |
当前登录用户部门编号 |
#{sys_base_path} |
当前 Java 服务 basePath |
排序配置
- MySQL 及非 SQL Server 数据库:直接在 SQL 中添加
ORDER BY即可 - SQL Server 数据库:不允许 SQL 内含
ORDER BY,必须通过 URL 参数传递:
/online/cgreport/{headId}?column=age,name&order=desc
| URL 参数 | 说明 |
|---|---|
column |
排序字段,多个用逗号分隔 |
order |
排序方式:desc(倒序)/ asc(正序) |
菜单创建与角色授权
报表创建后,通过 API 完成菜单注册和角色授权的完整流程:
1. 创建菜单
POST /sys/permission/add
{
"id": "{headId}",
"name": "报表名称",
"parentId": "",
"url": "/online/cgreport/{headId}",
"component": "modules/online/cgreport/auto/OnlCgreportAutoMain",
"isRoute": 1,
"isLeaf": "1",
"keepAlive": 0,
"hidden": 0,
"hideTab": 0,
"status": "1",
"menuType": 1,
"sortNo": 1.0,
"alwaysShow": 0,
"internalOrExternal": false,
"permsType": "0",
"ruleFlag": 0
}
2. 查找角色 ID
GET /sys/role/list?pageNo=1&pageSize=50
返回 records[],找到目标角色的 id(管理员 roleCode=admin)。
3. 查询角色已有权限
GET /sys/permission/queryRolePermission?roleId={roleId}
返回权限 ID 数组(可能高达千条)。
4. 追加权限并保存
POST /sys/permission/saveRolePermission
Content-Type: application/json
{
"roleId": "{roleId}",
"permissionIds": "id1,id2,...,{新菜单headId}",
"lastPermissionIds": "id1,id2,..."
}
注意:必须用 JSON body(
application/json)发送,不支持 form 表单或 URL 参数。权限 ID 列表可能很长(>1000),不能放 URL。
数据权限配置
Online 报表支持通过「数据规则」过滤报表数据,仅展示符合条件的数据。
配置路径:菜单管理 → 找到报表菜单 → 更多 → 数据规则
注意事项:
- 规则字段不限于报表查询字段,表中任意字段均可使用
- 字符串参数必须用单引号引起来(例如:
'admin'),否则视为数字 - 支持系统上下文变量,需加单引号(例如:
'#{sys_user_code}') - 不支持带
?参数的菜单配置数据规则;如有需要,单独创建一个不带参数的隐藏菜单用于数据规则配置
通过 API 配置数据规则
前提:角色必须先有该菜单的权限,否则授权数据规则时会报"请先保存角色菜单权限!"。先调用 grant_menu_to_role(role_id, menu_id) 或手动授权菜单。
Step 1:创建规则(默认未启用)
POST /sys/permission/addPermissionRule
{"permissionId":"{menuId}","ruleName":"规则名称","ruleColumn":"sex","ruleConditions":"!=","ruleValue":"'1'"}
⚠️
addPermissionRule返回的result为null,不含规则 ID! 创建后必须调用以下接口查询刚创建的规则 ID:GET /sys/permission/queryPermissionRule?permissionId={menuId}按
ruleName匹配且status == null找到目标规则,取其id。add_data_rule()函数已内置此逻辑,直接调用函数即可。
Step 2:启用规则(status:"1" 才生效,缺少此步规则不生效)
POST /sys/permission/editPermissionRule
{"id":"{ruleId}","permissionId":"{menuId}","ruleName":"规则名称","ruleColumn":"sex","ruleConditions":"!=","ruleValue":"'1'","status":"1"}
Step 3:将规则授权给指定角色(此步骤才真正让规则对角色生效)
POST /sys/role/datarule
{"permissionId":"{menuId}","roleId":"{roleId}","dataRuleIds":"{ruleId1},{ruleId2}"}
多个规则 ID 用逗号分隔。缺少此步骤,规则虽已创建并启用,但不会对任何角色生效。
Step 4:验证规则已对角色生效
GET /sys/role/datarule/{menuId}/{roleId}
返回结构:
datarule[]:该菜单下配置的所有数据规则列表drChecked:已授权给该角色的规则 ID,逗号分隔
drChecked 中包含规则 ID 说明授权成功。
完整流程小结
0. grant_menu_to_role(role_id, menu_id) → 前提:确保角色有菜单权限
1. POST /sys/permission/addPermissionRule → 创建规则(默认未启用,result 为 null)
GET /sys/permission/queryPermissionRule → 查询列表获取真实规则 ID
2. POST /sys/permission/editPermissionRule → 启用规则(status:"1")
3. POST /sys/role/datarule → 授权给角色(才真正生效)
4. GET /sys/role/datarule/{menuId}/{roleId} → 验证授权结果
修改已有数据规则
使用 editPermissionRule 可修改规则名称、字段、条件、值(保持 status:"1"):
POST /sys/permission/editPermissionRule
{"id":"{ruleId}","permissionId":"{menuId}","ruleName":"新名称","ruleColumn":"birthday","ruleConditions":"=","ruleValue":"'2024-04-11'","status":"1"}
删除数据规则
DELETE /sys/permission/deletePermissionRule?id={ruleId}
ruleConditions 条件值
条件选项来自系统字典 rule_conditions,可通过 GET /sys/dict/getDictItems/rule_conditions 查询完整列表。
常用条件示例:
| 条件 | ruleValue 示例 | 说明 |
|---|---|---|
= |
'2024-04-11' |
等于(字符串必须加单引号) |
!= |
'1' |
不等于 |
>= |
'2024-01-01' |
大于等于 |
<= |
'2024-12-31' |
小于等于 |
like |
'%admin%' |
模糊匹配 |
in |
'1','2','3' |
包含多值 |
USE_SQL_RULES |
username != 'admin' |
自定义 SQL 表达式,ruleColumn 无需填写,ruleValue 直接写 WHERE 子句(不含 WHERE 关键字) |
ruleValue 系统变量
ruleValue 支持以下系统上下文变量(自动替换为当前登录用户信息):
| 变量 | 说明 |
|---|---|
#{sys_user_code} |
登录用户账号 |
#{sys_user_name} |
登录用户名称 |
#{sys_date} |
当前日期 |
#{sys_time} |
当前时间 |
#{sys_org_code} |
登录用户部门编码 |
#{sys_multi_org_code} |
用户拥有的所有部门编码 |
#{tenant_id} |
登录用户所属租户 |
字符串类型的系统变量需加单引号:
'#{sys_user_code}'
数据导出
Online 报表支持导出功能,默认分 sheet 导出,每个 sheet 最多 1 万条数据。
错误处理
| 错误 | 原因 | 解决方案 |
|---|---|---|
| 401 / 认证失败 | Token 过期 | 重新从浏览器 F12 获取 X-Access-Token |
| 报表编码已存在 | code 重复 | 换一个 code,或用 editAll 编辑 |
| parseSql 失败 | SQL 含复杂函数或语法问题 | 去掉问题条件后解析,再手工添加参数 |
| SQL 注入风险 | 包含危险语句 | 不要在 SQL 中使用 DROP/DELETE/UPDATE |
| 禁止 select * | 系统开启了 disableSelectAll | 改为指定具体字段 |
| 中文乱码 | 用了 curl | 必须用 Python urllib |
与其他 Skill 的区别
| Skill | 产出物 | 适用场景 |
|---|---|---|
jeecg-onlreport |
Online 报表(SQL 驱动,只读数据展示) | 数据查询、统计分析、数据导出 |
jeecg-onlform |
Online 表单(元数据驱动,CRUD) | 数据录入管理 |
jeecg-codegen |
Java + Vue3 代码 | 需要自定义业务逻辑的模块 |
jeecg-desform |
设计器表单 JSON | 数据采集、审批表单 |
API 快速参考
详细 API schema 参见 references/api_schema.md。
| 操作 | API |
|---|---|
| 列出报表 | GET /online/cgreport/head/list |
| 查报表详情 | GET /online/cgreport/head/queryById?id={id} |
| 查字段列表 | GET /online/cgreport/item/listByHeadId?headId={id} |
| 按编码查字段 | GET /online/cgreport/item/listByHeadCode?headCode={code} |
| 查参数列表 | GET /online/cgreport/param/listByHeadId?headId={headId} |
| 解析 SQL | GET /online/cgreport/head/parseSql?sql={sql}&dbKey={key} |
| 创建报表 | POST /online/cgreport/head/add |
| 编辑报表 | PUT /online/cgreport/head/editAll |