jeecg-onlreport について
SQL や自然言語の要件から JeecgBoot Online レポートを作成・照会・編集するスキルです。フィールドとパラメーターの設定を支援し、API 変更の前に内容の提示と確認を求めます。
主な機能
- 01レポート一覧と設定の確認
- 02SQL や要件からのレポート作成
- 03フィールド、パラメーター、SQL の編集
- 04SQL の解析による項目とパラメーターの抽出
- 05フィールド名に基づく設定の推定
活用シーン
- 01既存レポートの項目とパラメーターの確認
- 02読み取り専用 SQL レポートの作成
- 03レポート項目やクエリの調整
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ jeecgboot/ skills --skill jeecg-onlreportインストール後、Claude Code で/jeecg-onlreportを入力して読み込まれたか確認します。
同梱ファイルreferences/api_schema.mdscripts/onlreport_api.py
詳細
JeecgBoot Online レポート AI 自動生成ツール
自然言語で記述されたレポート要件を Online レポート設定に変換し、API を通じて自動的に作成/編集/照会します。
重要:このスキルは「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 操作の前に、
desform_utilsと同様にinit_apiを呼び出す必要があります。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 テーブルが返されます。フィールドは 3 つ(レポート名、レポートコード、レポート 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 テーブルが返されます。フィールドは 3 つ(フィールドコード、フィールドテキスト、フィールドタイプ)のみで、ページネーションも自動的に行われます。
| 字段编码 | 字段文本(显示名) | 字段类型 |
|----------|-----------------|----------|
| 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 の入手方法は 2 通りあります。
- ユーザーが 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 パラメータータブでパラメーター名(例:
${username}に対応するusername)を手動で追加します - 最終保存時には、cgrSql に元の完全な SQL を使用します
3.3 フィールド設定の自動化
フィールド名の意味に基づいて、各フィールドの設定を自動的に推定します。
フィールド共通属性
searchMode の説明:有効な値は
single(単一値検索)とgroup(範囲検索)の2つだけです。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 には、これら2つのフィールドを含めなくてもかまいません。
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 |