mcpField
J
jeecg-onlchart

jeecg-onlchart

github.com/jeecgbootデータ・データベース24440 回インストール2 週間前に更新
リポジトリ

jeecg-onlchart について

jeecg-onlchartは、チャートの要望をJeecgBootのOnlineチャート設定に変換し、API経由で作成・編集するスキルです。SQL、JSON、APIのデータ形式に対応し、変更の実行前にユーザー確認を求めます。

主な機能

  1. 01チャート要望を設定に変換
  2. 02SQL・JSON・APIの項目解析
  3. 03項目の表示・検索設定を推定
  4. 04棒・折れ線・円グラフの選択
  5. 05API経由でチャートを作成・編集
  6. 06必要に応じてメニューと権限を設定

活用シーン

  1. 01自然言語の要望からデータチャートを作成
  2. 02既存チャートの項目や種類を変更
  3. 03SQL検索結果を可視化用に設定
  4. 04確認後にチャートを公開しメニューを生成

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/jeecgboot/skills --skill jeecg-onlchart

インストール後、Claude Code で/jeecg-onlchartを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

docs/
skill-usage-guide.md
scripts/
onlchart_api.py
yapi_mock.py

詳細

JeecgBoot Online グラフ AI 自動生成ツール

自然言語によるグラフ要件の説明を Online グラフの設定に変換し、API 経由で JeecgBoot システム内にグラフを自動作成/編集します。

重要:このスキルは「Online グラフ」(SQL 駆動のデータ可視化グラフ)を扱います。「Online レポート」(cgreport データ一覧)や「Online フォーム」(cgform)は対象外です。

前提条件

ユーザーは以下の情報を提供する必要があります(または AI が案内して確認します)。

  1. API アドレス:JeecgBoot バックエンドのアドレス(例:https://boot3.jeecg.com/jeecgboot)
  2. X-Access-Token:JWT ログイントークン(ブラウザーの F12 から取得)

ユーザーが提供していない場合は、次のように案内します。

JeecgBoot バックエンドのアドレスと X-Access-Token(ブラウザーで F12 → Network → 任意のリクエストの Request Headers からコピー)を提供してください。


対話フロー

Step 0: 操作タイプを判断する
ユーザーの意図を示すキーワード操作タイプ
作成/新規作成/作って/グラフを生成グラフの新規作成 → Step 1A
グラフを変更/フィールドを変更/グラフタイプを変更グラフの編集 → Step 1B
Step 1A: グラフの新規作成 — 要件を解析する

ユーザーの説明から以下の情報を抽出します。

情報必須デフォルト値例
グラフコード (code)はいsnake_case で自動生成tj_user_sex
グラフ名 (name)はいユーザーが指定"男女比を集計"
SQL 文 (cgrSql)はい要件から推測するか、ユーザーが指定select count(*) cout, sex from sys_user group by sex
X 軸フィールド (xaxisField)はいSQL から推測sex
Y 軸フィールド (yaxisField)はいSQL から推測cout
グラフタイプ (graphType)はいbarbar、line、pie、line,bar
表示テンプレート (displayTemplate)いいえtabtab、single、double
データソース (dbSource)いいえ空(デフォルトのデータソース)second_db
データタイプ (dataType)いいえsqlsql

X/Y 軸の推測ルール:

  • X 軸 (xaxisField):通常は分類/ディメンションフィールドです(例:sex、dept、month、category)
  • Y 軸 (yaxisField):通常はメジャー/集計フィールドです(例:count、sum、avg の結果)
Step 1B: グラフの編集 — 既存の設定を取得する
  1. ユーザーからグラフ ID またはコードを受け取ります
  2. API 経由で既存のグラフ設定を取得します(API 一覧を参照)
  3. 既存の設定を表示し、ユーザーの要件に応じて変更します
Step 2: フィールドを解析する(dataType に応じてインターフェースを選択)
2A. SQL タイプ — parseSql インターフェースを再利用
GET /online/cgreport/head/parseSql?sql={urlEncodedSql}&dbKey={dbKey}
  • sql:URL エンコードされた SQL 文
  • dbKey:データソースコード。デフォルトのデータソースの場合は省略できます

戻り値の構造:

{
  "success": true,
  "result": {
    "fields": [
      { "fieldName": "cout", "fieldTxt": "cout", "fieldType": "String", "isShow": 1, "orderNum": 1 }
    ],
    "params": []
  }
}

注意:parseSql が返す isShow は数値(0/1)ですが、グラフインターフェースでは文字列 "Y"/"N" が必要なため、変換する必要があります。

2B. JSON/API タイプ — parseField インターフェースを使用
POST /online/graphreport/head/parseField?type=JSON
POST /online/graphreport/head/parseField?type=API

リクエストボディ(JSON タイプでは JSON 文字列を、API タイプではインターフェース URL を渡します):

{ "data": "[{\"month\":\"01\",\"amount\":1000}]" }

戻り値の構造(parseSql と同じ形式):

{
  "success": true,
  "result": {
    "fields": [
      { "fieldName": "month", "fieldTxt": "month", "fieldType": "String", "isShow": 1 },
      { "fieldName": "amount", "fieldTxt": "amount", "fieldType": "Integer", "isShow": 1 }
    ],
    "params": []
  }
}

JSON/API タイプでは dbSource の設定は不要です。cgrSql フィールドには JSON 文字列または API URL を格納します。

API データ形式の要件

API インターフェースの戻り値データは、{"data": [...]} 構造で必ずラップする必要があります。そうしないとグラフを解析できません。

// ✓ 正确
{"data": [{"name": "一月", "value": 120}, {"name": "二月", "value": 200}]}

// ✗ 错误(裸数组,图表无法识别)
[{"name": "一月", "value": 120}]
parseField が失敗した場合の処理

parseField?type=API を使用するには、JeecgBoot サーバーからその URL にアクセスできる必要があります。サーバーが外部ネットワークにアクセスできず失敗する場合は、parseField をスキップして items を手動で構築します(フィールドが既知であれば直接定義できます)。

YApi Mock を使用して API データソースを作成する

プロジェクトには YApi Mock プラットフォーム(https://api.jeecg.com)が組み込まれており、API データソースとして使用するモックインターフェースをすばやく作成できます。 scripts/yapi_mock.py スクリプトを使用して操作します。認証情報は以下のルールに従って取得し、ハードコードは禁止です。

  • まず、現在のコンテキスト(システムプロンプト、memory、グローバル設定など、任意の情報源)から YApi のメールアドレスとパスワードを探します
  • コンテキスト内で見つからない場合は、必ずユーザーに尋ねます。

    データソースの作成に YApi Mock を使用するため、ログイン用のメールアドレスとパスワードを提供してください(プラットフォームのアドレス:https://api.jeecg.com)。

yapi_mock.py は内部で http.cookiejar.CookieJar + build_opener を使用してセッションを管理しており、Python 3.6 / 3.9 / 3.12 以降のすべてのバージョンに対応しています。init_yapi(email, password) を直接呼び出してください。

import sys
sys.path.insert(0, '<skill目录>/scripts')
from yapi_mock import init_yapi, create_mock

# 凭证由 Claude 从 memory 读取后注入,不得硬编码
init_yapi(email='<email>', password='<password>')

# 创建 mock 接口并写入数据,返回完整 mock URL
mock_url = create_mock(
    path='/staff',        # 路径后缀,不含 basepath(/claude)
    title='职员信息',
    data=[
        {"name": "张三", "salary": 18000},
        {"name": "李四", "salary": 15000},
    ]
)
print(mock_url)  # https://api.jeecg.com/mock/57/claude/staff

パスのルール(重要):プロジェクトの basepath は /claude です。インターフェースパスには末尾部分のみを指定します。

指定する path完全な mock URL
/staffhttps://api.jeecg.com/mock/57/claude/staff
/linehttps://api.jeecg.com/mock/57/claude/line
Step 3: フィールドを自動設定する
3.1 フィールド属性のマッピング(グラフとレポートの違い)

重要な違い:グラフのフィールドでは、数値の 0/1 ではなく文字列 "Y"/"N" を使用します。

属性グラフ (graphreport)レポート (cgreport)説明
関連するヘッダー IDgraphreportHeadIdcgrheadIdフィールド名が異なります
表示するかどうかisShow: "Y"/"N"isShow: 0/1型が異なります
合計するかどうかisTotal: "Y"/"N"isTotal: "0"/"1" または null型が異なります
検索するかどうかsearchFlag: "Y"/"N"isSearch: 0/1フィールド名と型が異なります
検索モードsearchModesearchMode同じです
辞書dictCodedictCode同じです
並び順orderNumorderNum同じです
3.2 フィールド表示名 (fieldTxt)

parseSql が返す fieldTxt はデフォルトで fieldName と同じです。AI は意味に基づいて中国語に翻訳する必要があります。

フィールド名のパターン推測される中国語名
count / cout / cnt数量/人数/回数
sum / total / amount合計/総額
avg / average平均値
sex性別
dept / department部門
statusステータス
type / categoryタイプ/分類
month / year / date月/年/日付
name / title名前
age年齢
salary給与
3.3 表示するかどうか (isShow)
ルールisShow
すべてのフィールド(デフォルト)"Y"(グラフのフィールドは通常少ないため、すべて表示します)
id/主キー項目"N"
3.4 検索するかどうか (searchFlag) + 検索モード (searchMode)
フィールドタイプsearchFlagsearchMode
分類/ディメンションフィールド"Y"single
日付/時刻フィールド"Y"group
メジャー/集計フィールド"N"null
3.5 是否合计 (isTotal)
规则isTotal
度量/聚合字段"Y"
维度/分类字段"N"
3.6 字典配置 (dictCode) — 列表数据值替换显示

作用:列表(明细表格区域)中,将数据库存储的原始值替换为可读文本显示。

例:性别字段数据库存 1/2,配置字典后显示为"男"/"女"。

支持两种方式:

方式一:系统字典编码

填写系统字典的 dictCode,由系统字典表自动解析值 → 文本。

"dictCode": "sex"

常用系统字典编码:

dictCode说明
sex性别(1=男,2=女)
priority优先级
valid_status有效状态
yn是/否

方式二:字典 SQL

在 dictCode 处直接写一条 SELECT 语句,动态替换显示值。SQL 必须返回两列:value(数据库存的值)和 text(展示的文本)。

"dictCode": "SELECT id as value, name as text FROM sys_category WHERE pid = '1'"
"dictCode": "SELECT code as value, name as text FROM sys_depart ORDER BY depart_order"

注意:字典 SQL 每次渲染都会执行查询,数据量大时建议加 WHERE 条件限制范围。

Step 4: 图表类型选择

根据数据特征推荐图表类型:

数据场景推荐 graphType说明
分类对比(如男女人数)bar柱状图
趋势变化(如月度销售)line折线图
占比分布(如部门比例)pie饼图
趋势+对比(如月度销售对比)line,bar组合图表
纯数据明细table数据表格(只渲染在底部明细区,不占图表位)

graphType 支持逗号分隔多种类型,如 "bar,pie" 会同时生成柱状图和饼图两个区域。

组合图表配置(折线+柱状同坐标系):

  • graphType: "line,bar"(逗号分隔多种类型)
  • isCombination: "combination"(标记为组合图表)
  • 非组合图表 isCombination 为 null 或不传
Step 5: 展示摘要并确认

必须展示以下内容,等待用户确认后再执行:

## Online 图表配置摘要

- 图表编码:tj_user_sex
- 图表名称:统计男女比例
- 图表类型:bar(柱状图)
- X 轴字段:sex(性别)
- Y 轴字段:cout(人数)
- 数据源:默认
- 目标环境:https://boot3.jeecg.com/jeecgboot

### SQL 语句
select count(*) cout, sex from sys_user group by sex

### 字段配置

| 序号 | 字段名 | 显示名称 | 类型 | 显示 | 查询 | 字典 | 合计 |
|------|--------|---------|------|------|------|------|------|
| 0 | cout | 人数 | String | Y | N | - | Y |
| 1 | sex | 性别 | String | Y | N | sex | N |

### 参数
(无)

确认以上配置?(y/n)
Step 6: 校验编码可用性(仅新增时)

用户确认后,新增图表前必须先校验 code 是否已被占用:

GET /sys/duplicate/check?tableName=onl_graphreport_head&fieldName=code&fieldVal={code}

返回结构:

{ "success": true, "result": true }   // true = 可用(未重复)
{ "success": true, "result": false }  // false = 已存在,需换一个 code

若 result 为 false,提示用户更换编码,不继续执行创建。

Python 示例:

encoded_code = urllib.parse.quote(report_code)
check = api_request(f'/sys/duplicate/check?tableName=onl_graphreport_head&fieldName=code&fieldVal={encoded_code}')
if not check.get('result'):
    print(f'图表编码 "{report_code}" 已存在,请换一个编码')
    exit(1)
print(f'编码 "{report_code}" 可用,继续创建...')
Step 7: 调用 API 创建/编辑图表

用户确认且编码校验通过后执行。

6.1 新增图表 — 请求结构

POST /online/graphreport/head/add

{
    "dbSource": "",
    "name": "统计男女比例",
    "code": "tj_user_sex",
    "displayTemplate": "tab",
    "xaxisField": "sex",
    "yaxisField": "cout",
    "dataType": "sql",
    "graphType": "bar",
    "cgrSql": "select count(*) cout, sex from sys_user group by sex",
    "onlGraphreportItemList": [
        {
            "id": "前端生成的长数字ID",
            "cgrheadId": null,
            "fieldName": "cout",
            "fieldTxt": "人数",
            "fieldWidth": null,
            "fieldType": "String",
            "searchMode": null,
            "isOrder": null,
            "isSearch": null,
            "dictCode": null,
            "fieldHref": null,
            "isShow": "Y",
            "orderNum": 0,
            "replaceVal": null,
            "isTotal": null,
            "createBy": null,
            "createTime": null,
            "updateBy": null,
            "updateTime": null,
            "groupTitle": null
        }
    ],
    "paramsList": []
}

注意(add 接口):add 时 items 中的关联ID字段名为 cgrheadId(值为 null),虽然查询/编辑时返回的是 graphreportHeadId。

6.2 编辑图表 — 请求结构

PUT /online/graphreport/head/edit

{
    "id": "1290934362649460737",
    "name": "统计男女比例",
    "code": "tj_user_bysex",
    "cgrSql": "select count(*) cout, sex from sys_user group by sex",
    "xaxisField": "sex",
    "yaxisField": "cout",
    "yaxisText": "yaxis_text",
    "content": null,
    "extendJs": null,
    "graphType": "line,bar",
    "isCombination": "combination",
    "displayTemplate": "tab",
    "dataType": "sql",
    "dbSource": "",
    "tenantId": 0,
    "lowAppId": null,
    "onlGraphreportItemList": [
        {
            "id": "1290934166687383554",
            "graphreportHeadId": "1290934362649460737",
            "fieldName": "cout",
            "fieldTxt": "人数",
            "isShow": "Y",
            "isTotal": "N",
            "searchFlag": "N",
            "searchMode": null,
            "dictCode": "",
            "fieldHref": null,
            "fieldType": "String",
            "orderNum": 0,
            "replaceVal": null,
            "createBy": "admin",
            "createTime": "2020-08-05 17:03:06",
            "updateBy": null,
            "updateTime": null
        }
    ],
    "paramsList": []
}

add 与 edit 字段差异:

字段addedit说明
id (head)不传必传图表头ID
yaxisText不传可选Y轴标签文字
content不传可选自定义内容
extendJs不传可选扩展JS
isCombination不传可选组合图表标记
tenantId不传传回原值租户ID
Item 关联ID字段cgrheadId: nullgraphreportHeadId: headId字段名不同
Item isShow"Y"/"N""Y"/"N"一致
Item searchFlag不存在,用 isSearchsearchFlag: "Y"/"N"add 和 edit 可能不同
6.3 字段 ID 生成规则
  • add 时使用雪花ID格式(19位数字字符串),如 "2033369959277633538"
  • 可用 Python 的 str(int(time.time() * 1000) * 1000000 + random.randint(100000, 999999)) 近似生成
6.4 使用 Python 调用 API

重要限制:

  1. Windows 环境下 curl 发送中文/长 JSON 会出错,必须使用 Python
  2. 禁止使用 python3 -c "..." 内联方式
  3. 必须先用 Write 工具写入 .py 临时文件,再用 Bash 执行,最后删除临时文件

推荐方式:使用 onlchart_api.py 封装脚本(与 jeecg-onlreport 的 onlreport_api.py 同模式)

脚本路径: skill 加载时开头已提供 Base directory for this skill: <skill_base_dir>,scripts 目录即 <skill_base_dir>\scripts。

import sys
sys.path.insert(0, r'<skill_base_dir>\scripts')
from onlchart_api import init_api, build_item, build_param, create_chart

init_api('<api_base>', '<token>')

items = [
    build_item('sex',    '性别',  search_flag='Y', search_mode='single', dict_code='sex', order_num=0),
    build_item('cout',   '人数',  is_total='Y', order_num=1),
]

# 默认只创建图表,不挂菜单、不授权
# 如需发布,改用 create_and_publish() 或单独调用 publish_chart()
result = create_chart(
    code='tj_user_sex',
    name='用户性别分布',
    sql='SELECT sex, count(*) cout FROM sys_user GROUP BY sex',
    x='sex', y='cout',
    graph_type='bar',
    items=items,
)

可用函数一览:

函数说明
init_api(api_base, token)初始化连接(必须最先调用)
build_item(field_name, ...)构建字段配置
build_param(param_name, ...)构建自定义参数
parse_sql(sql, db_key)解析 SQL 字段
check_code_available(code)校验编码是否可用
create_chart(code, name, sql, x, y, items, ...)创建图表
edit_chart(head_id, ...)编辑图表
publish_chart(head_id, name, role_code)挂载菜单 + 授权角色
create_and_publish(code, name, sql, x, y, items, ...)一键全流程
list_charts()查询图表列表
query_chart(head_id)查询图表详情
get_chart_id_by_code(code)按编码查 head_id

低级手写脚本模板(不推荐,优先使用上方封装):

import urllib.request
import json
import time
import random
import ssl
import urllib.parse

API_BASE = '{用户提供的后端地址}'
TOKEN = '{用户提供的 X-Access-Token}'

# 忽略SSL验证(开发环境)
ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE

def api_request(path, data=None, method=None):
    """发送 API 请求"""
    url = f'{API_BASE}{path}'
    headers = {
        'X-Access-Token': TOKEN,
        'Content-Type': 'application/json; charset=UTF-8'
    }
    if data is not None:
        json_data = json.dumps(data, ensure_ascii=False).encode('utf-8')
        if method is None:
            method = 'POST'
        req = urllib.request.Request(url, data=json_data, headers=headers, method=method)
    else:
        if method is None:
            method = 'GET'
        req = urllib.request.Request(url, headers=headers, method=method)
    resp = urllib.request.urlopen(req, context=ctx)
    return json.loads(resp.read().decode('utf-8'))

def gen_id():
    """生成雪花ID格式的字符串(19位数字)"""
    return str(int(time.time() * 1000) * 1000000 + random.randint(100000, 999999))

# ====== Step 1: 调用 parseSql 解析字段 ======
sql = "select count(*) cout, sex from sys_user group by sex"
encoded_sql = urllib.parse.quote(sql, safe='')
parse_result = api_request(f'/online/cgreport/head/parseSql?sql={encoded_sql}')
print('解析结果:', json.dumps(parse_result, ensure_ascii=False, indent=2))

if not parse_result.get('success'):
    print('SQL 解析失败:', parse_result.get('message'))
    exit(1)

# ====== Step 2: 构造字段配置 ======
items = [
    {
        "id": gen_id(), "cgrheadId": None,
        "fieldName": "cout", "fieldTxt": "人数",
        "fieldWidth": None, "fieldType": "String",
        "searchMode": None, "isOrder": None, "isSearch": None,
        "dictCode": None, "fieldHref": None,
        "isShow": "Y", "orderNum": 0,
        "replaceVal": None, "isTotal": None,
        "createBy": None, "createTime": None,
        "updateBy": None, "updateTime": None, "groupTitle": None
    },
    {
        "id": gen_id(), "cgrheadId": None,
        "fieldName": "sex", "fieldTxt": "性别",
        "fieldWidth": None, "fieldType": "String",
        "searchMode": None, "isOrder": None, "isSearch": None,
        "dictCode": "sex", "fieldHref": None,
        "isShow": "Y", "orderNum": 1,
        "replaceVal": None, "isTotal": None,
        "createBy": None, "createTime": None,
        "updateBy": None, "updateTime": None, "groupTitle": None
    }
]

# ====== Step 3: 构造请求 ======
graph_data = {
    "dbSource": "",
    "name": "统计男女比例",
    "code": "tj_user_sex",
    "displayTemplate": "tab",
    "xaxisField": "sex",
    "yaxisField": "cout",
    "dataType": "sql",
    "graphType": "bar",
    "cgrSql": sql,
    "onlGraphreportItemList": items,
    "paramsList": []
}

# ====== Step 4: 调用 add API 创建图表 ======
result = api_request('/online/graphreport/head/add', graph_data)
print('创建结果:', json.dumps(result, ensure_ascii=False, indent=2))

if result.get('success'):
    print('\n图表创建成功!')
else:
    print('\n创建失败:', result.get('message'))

编辑图表脚本差异:

# 编辑时用 PUT 方法,且 items 使用 graphreportHeadId
graph_data = {
    "id": "existing_head_id",
    "name": "统计男女比例",
    "code": "tj_user_bysex",
    "cgrSql": sql,
    "xaxisField": "sex",
    "yaxisField": "cout",
    "yaxisText": "",
    "content": None,
    "extendJs": None,
    "graphType": "line,bar",
    "isCombination": "combination",
    "displayTemplate": "tab",
    "dataType": "sql",
    "dbSource": "",
    "tenantId": 0,
    "lowAppId": None,
    "onlGraphreportItemList": [
        {
            "id": "existing_item_id",
            "graphreportHeadId": "existing_head_id",
            "fieldName": "cout", "fieldTxt": "人数",
            "isShow": "Y", "isTotal": "N",
            "searchFlag": "N", "searchMode": None,
            "dictCode": "", "fieldHref": None,
            "fieldType": "String", "orderNum": 0,
            "replaceVal": None
        }
    ],
    "paramsList": []
}
result = api_request('/online/graphreport/head/edit', graph_data, method='PUT')
Step 8: 生成菜单 SQL(可选)

默认不创建菜单、不授权。 只有用户明确说「挂菜单」「授权」「发布」时才执行此步骤。

图表创建成功后,可生成菜单 SQL:

重要:菜单 URL 使用图表的 head_id,不是 code。 路由格式:/online/graphreport/chart/{head_id}

# 查询刚创建的图表,获取 head_id
list_result = api_request(f'/online/graphreport/head/list?code={urllib.parse.quote(report_code)}')
if list_result.get('success') and list_result['result']['records']:
    head_id = list_result['result']['records'][0]['id']
    report_name = list_result['result']['records'][0]['name']
    print(f'\n图表 ID: {head_id}')
    print(f'\n### 菜单 SQL(可选执行)')
    print(f"""
INSERT INTO sys_permission (
  id, parent_id, name, url, component, component_name,
  is_route, is_leaf, keep_alive, hidden, hide_tab, description,
  del_flag, rule_flag, status, internal_or_external,
  perms_type, sort_no, menu_type, route_redirect
) VALUES (
  '{head_id}', NULL, '{report_name}',
  '/online/graphreport/chart/{head_id}',
  'super/online/graphreport/auto/GraphreportAutoChart',
  NULL,
  1, 1, 0, 0, 0, NULL,
  0, 0, '1', 0,
  '0', 1.0, 1, NULL
);
""")
Step 9: 输出结果

本地环境自动执行菜单 SQL 规则: 如果 API_BASE 以 http://127.0.0.1 或 http://localhost 开头(不区分大小写),在生成菜单 SQL 后,自动通过 Bash 工具执行 MySQL 命令插入菜单:

# 先检查是否已存在,避免重复插入
mysql -h127.0.0.1 -P3306 -uroot -proot jeecgboot3 -e "SELECT id FROM sys_permission WHERE id='{head_id}'"
# 不存在则执行插入
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,与 jeecg-codegen 保持一致
## Online 图表创建成功

- 图表编码:{code}
- 图表名称:{name}
- 图表类型:{graphType}
- X 轴:{xaxisField}
- Y 轴:{yaxisField}
- 字段数量:{N} 个
- 目标环境:{API_BASE}
- 菜单 SQL:{已自动执行 ✓ / 需手动执行}

### 菜单 SQL
INSERT INTO sys_permission (...) VALUES (...);

### 后续操作
1. 打开 JeecgBoot 后台 → Online图表
2. 找到该图表,点击「功能测试」预览效果
3. 如菜单未自动执行,手动执行上方 SQL 或在后台手动添加
4. 可在「编辑」中调整图表类型、字段等配置

高级功能

组合图表

支持在同一图表中展示多种图表类型:

{
    "graphType": "line,bar",
    "isCombination": "combination"
}

组合图表会在同一坐标系中同时展示折线和柱状图。

Y 轴标签 (yaxisText)

自定义 Y 轴显示文字:

{
    "yaxisText": "人数(单位:人)"
}
JS 增强 (extendJs)
全局变量
变量说明
headId当前图表的 ID
onClick用于添加点击事件的全局对象
添加点击事件

通过 onClick.图表类型 = function(event) {} 的方式挂载,不同图表类型分别定义:

// 柱状图点击
onClick.bar = function(event) {
    this.$message.success('点击了柱状图!')
}

// 折线图点击
onClick.line = function(event) {
    this.$message.info('点击了折线图!')
}

// 饼图点击
onClick.pie = function(event) {
    this.$message.info('点击了饼图!')
}
this 上下文(可用 API)

extendJs 中函数体的 this 指向一个固定对象(源码 onClickThis),包含以下可用属性:

属性类型说明
this.$messageAnt Design Message轻提示(顶部小条,自动消失)
this.$confirmModal confirm确认对话框(需传入 options 对象)
this.$infoModal.info信息对话框
this.$successModal.success成功对话框
this.$errorModal.error错误对话框
this.$warningModal.warning警告对话框
this.$routerVue Router路由跳转
this.$httpdefHttp (Axios)HTTP 请求

$message — 轻提示(最常用):

this.$message.success('操作成功')   // 绿色
this.$message.info('提示信息')      // 蓝色
this.$message.warning('注意!')     // 黄色
this.$message.error('发生错误')     // 红色
this.$message.loading('加载中...')  // 转圈

$confirm / $info / $success / $error / $warning — 模态对话框:

// $confirm:带确认/取消按钮的对话框
this.$confirm({
    iconType: 'warning',
    title: '确认操作',
    content: '职业:' + event.name + ',确认查看详情?',
    onOk: () => {
        this.$router.push('/detail?occupation=' + event.name)
    },
    onCancel: () => {}
})

// $info / $success / $error / $warning:纯展示对话框(只有关闭按钮)
this.$success({ title: '成功', content: '数值:' + event.value })
this.$info({ title: '信息', content: event.name + ' 的平均薪资:' + event.value })

$router — 路由跳转:

// 跳转到系统内部页面
this.$router.push('/system/user')
// 带参数跳转
this.$router.push({ path: '/online/cgreport/xxx', query: { occupation: event.name } })

$http — HTTP 请求(defHttp,Axios 封装):

onClick.bar = function(event) {
    var self = this  // 保存 this 引用,供回调中使用
    self.$message.loading('查询中...')
    self.$http.get({
        url: '/sys/user/list',
        params: { occupation: event.name }
    }).then(function(res) {
        self.$message.success('查到 ' + res.total + ' 条记录')
    })
}

⚠️ 注意:$http 回调(.then/.catch)中 this 已不是 onClickThis,必须提前用 var self = this 保存引用,或改用箭头函数。

事件参数 (event)

Online 图表底层使用 ECharts,event 是标准 ECharts 事件对象(不是自定义对象)。 直接打印 event 会看到 [object Object],需要读取具体属性。

通用参数(柱状图 / 折线图 / 饼图均有):

参数类型说明
event.namestringX 轴类目值(柱/线)或扇区名称(饼)
event.valuenumberY 轴数值(柱/线)或扇区数值(饼)
event.seriesNamestring系列名称(Y 轴字段的 fieldTxt)
event.seriesTypestring系列类型:'bar'、'line'、'pie'
event.dataIndexnumber数据在数组中的索引(从 0 开始)
event.colorstring当前元素颜色(十六进制)

饼图额外参数:

参数类型说明
event.percentnumberECharts 自动计算的百分比(如 66.7),可直接使用
onClick.bar = function(event) {
    // event.name = X轴类目,event.value = Y轴值,event.seriesName = 系列名
    this.$message.info('X轴: ' + event.name + ',值: ' + event.value)
}
onClick.line = function(event) {
    // ECharts 折线图:只有点击数据点才触发,点击连接线不触发事件
    this.$router.push('/detail?name=' + event.name)
}
onClick.pie = function(event) {
    // event.name = 扇区名称(字典翻译后的文本,如"男"/"女")
    // event.percent = ECharts 自动计算的百分比
    this.$message.info(
        '点击了:' + event.name
        + ',值:' + event.value
        + ',占比:' + event.percent.toFixed(1) + '%'
    )
}

组合图(line,bar)区分系列:

// 组合图注册两个事件,通过 event.seriesName 区分点击的是哪条系列
onClick.bar = function(event) {
    this.$message.success('[柱] ' + event.name + ':' + event.value)
}
onClick.line = function(event) {
    this.$message.info('[线] ' + event.name + ':' + event.value)
}
自定义内容 (content)

用于自定义渲染模板或说明内容。

AIGC — AI 自动生成图表

系统内置 AI 生成能力,可基于已有的 Online 表单(cgform)表,通过自然语言描述需求自动生成图表配置:

POST /online/graphreport/head/api/aigc?cgformTableName={表名}&prompt={需求描述}
  • cgformTableName:Online 表单的数据库表名(如 oa_leave)
  • prompt:用自然语言描述图表需求(如 "统计各部门请假次数")
  • 超时建议设为 60000ms

返回结构:

{
  "success": true,
  "result": {
    "code": "dept_leave_count",
    "name": "各部门请假次数",
    "cgrSql": "SELECT dept, COUNT(*) as cnt FROM oa_leave GROUP BY dept",
    "graphType": "bar",
    "xaxisField": "dept",
    "yaxisField": "cnt",
    "displayTemplate": "tab",
    "onlGraphreportItemList": [...]
  }
}

AIGC 返回的配置可直接作为 add 接口的请求体使用,通常无需修改即可创建。

参数化查询

图表支持两种参数语法,注意区分:

自定义参数:${参数名}

在 SQL 中用 ${} 拼接 WHERE 条件,{} 内的文本就是参数名,需与 paramsList 中配置的 paramName 完全一致。

文本类型参数必须加引号:

-- 文本字段加引号
SELECT count(*) cnt, dept FROM sys_user
WHERE status = '${status}' AND dept = '${dept}'
GROUP BY dept

-- 数字字段不加引号
SELECT * FROM order WHERE amount > ${min_amount}

对应的 paramsList 配置:

[
    {"paramName": "status",     "paramTxt": "状态",   "paramValue": "1",  "orderNum": 1},
    {"paramName": "dept",       "paramTxt": "部门",   "paramValue": "",   "orderNum": 2},
    {"paramName": "min_amount", "paramTxt": "最低金额", "paramValue": "0", "orderNum": 3}
]

使用方式:

  • URL 传参:/online/graphreport/chart/{head_id}?status=1&dept=研发部
  • 菜单配置时直接在 URL 上设置固定值
  • 未传参则使用 paramValue 中配置的默认值
系统变量:#{变量名}

系统变量用 #{} 语法(不是 ${}),由系统自动注入当前登录用户信息,无需配置到 paramsList:

SELECT * FROM sys_user
WHERE org_code = '#{sys_org_code}'
  AND create_by = '#{sys_user_code}'
  AND create_time >= '#{sys_date}'

可用系统变量:

变量名说明版本要求
sys_user_code当前登录用户账号-
sys_user_name当前登录用户真实姓名-
sys_date当前系统日期-
sys_time当前系统时间-
sys_org_code当前登录用户部门编号-
tenant_id当前登录用户租户 IDv3.4.5+
sys_base_pathJava 服务 basePath(仅 API 模式支持)v2.4.4+

混用示例(自定义参数 + 系统变量):

SELECT dept, count(*) cnt FROM sys_user
WHERE org_code = '#{sys_org_code}'
  AND status = '${status}'
GROUP BY dept
动态数据源

查询非默认数据源的数据:

{
    "dbSource": "second_db"
}

API の完全な一覧

操作方法パス説明
SQL 解析(レポートを再利用)GET/online/cgreport/head/parseSql?sql={encodedSql}&dbKey={dbKey}SQL の型フィールドを解析
JSON/API フィールド解析POST/online/graphreport/head/parseField?type=JSON|APIJSON または API URL のフィールドを解析
コードの重複チェックGET/sys/duplicate/check?tableName=onl_graphreport_head&fieldName=code&fieldVal={code}result=true は使用可能、false は既存
グラフの追加POST/online/graphreport/head/addグラフを作成
グラフの編集PUT/online/graphreport/head/editグラフを変更
一覧の検索GET/online/graphreport/head/list?code={code}グラフ一覧を検索(ページネーション)
詳細の検索GET/online/graphreport/head/queryById?id={headId}ID でグラフヘッダーを検索
フィールド一覧の検索GET/online/graphreport/head/queryOnlGraphreportItemByMainId?headId={headId}グラフに関連付けられたフィールドを検索
単体削除DELETE/online/graphreport/head/delete?id={id}グラフを削除
一括削除DELETE/online/graphreport/head/deleteBatch?ids={id1,id2}複数のグラフを削除
グラフデータの取得GET/online/graphreport/api/getChartsData?id={id}&params={json}グラフ表示時にレンダリングデータを取得
パラメーター設定の取得GET/online/graphreport/params/listByHeadId?headId={id}グラフ表示時にパラメーター一覧を取得
AI によるグラフ生成POST/online/graphreport/head/api/aigc?cgformTableName={表名}&prompt={需求}AIGC で設定を自動生成。タイムアウトは 60 秒
Excel のエクスポートGET/online/graphreport/head/exportXlsグラフ設定をエクスポート
Excel のインポートPOST/online/graphreport/head/importExcelグラフ設定をインポート

他の Skill との違い

Skill成果物適用シーン
jeecg-graphreportOnline グラフ設定(SQL 駆動、データ可視化)棒グラフ、折れ線グラフ、円グラフなどのデータ可視化
jeecg-onlreportOnline レポート設定(SQL 駆動、データ一覧)データ検索レポート、統計一覧、データエクスポート
jeecg-onlformOnline フォーム設定(メタデータ駆動、CRUD)データ入力管理フォーム
jeecg-codegenJava + Vue3 コード + SQLカスタムビジネスロジックが必要なモジュール
jeecg-desformデザイナーフォーム JSONデータ収集、承認フォーム

よくある質問

Q1:Y 軸のデータが乱れる/グラフの表示に異常がある

現象:棒グラフや折れ線グラフの Y 軸の値の順序が乱れたり、正しく表示されなかったりします。

原因:Y 軸フィールドの fieldType が数値型ではありません。parseSql はデフォルトですべてのフィールドを String として解析するため、レンダリング時に文字列として並べ替えられ(例:"10" < "9")、表示が乱れます。

解決策:Y 軸フィールドの fieldType を適切な数値型に変更します。

フィールド値の特徴設定する fieldType
整数(count、人数、数量)Integer
小数/金額/平均値BigDecimal
長整数Long

例:

# 错误:Y 轴字段 fieldType 是 String,图表会乱序
build_item('monthly_salary', '月薪', field_type='String', ...)

# 正确:数值字段必须用数值类型
build_item('monthly_salary', '月薪', field_type='BigDecimal', ...)
build_item('cnt',            '数量', field_type='Integer',    ...)
build_item('avg_age',        '平均年龄', field_type='BigDecimal', ...)

注意:build_item() のデフォルトは field_type='String' です。Y 軸の数値フィールドには、正しい型を手動で指定する必要があります。


Q2:YApi Mock の作成後、後続リクエストで「ログインしてください」と表示される

現象:init_yapi() の呼び出しは成功しますが、直後の create_mock() で「ログインしてください...」と表示されます。

原因:旧バージョンの init_yapi() は resp.headers.get('Set-Cookie') でレスポンスヘッダーを手動で解析していました。Python 3.12 では、この方法は最初の Set-Cookie 値しか返しません。YApi のログインには _yapi_token と _yapi_uid の 2 つの cookie が必要なため、手動解析では片方が失われます。

解決策:yapi_mock.py は CookieJar + build_opener 方式にリファクタリング済みです。標準ライブラリがすべての Set-Cookie レスポンスヘッダーを自動で処理するため、init_yapi(email, password) を直接呼び出せばよく、追加の処理は不要です。Python 3.6/3.9/3.12 以降に対応しています。


エラー処理

エラー解決策
トークンの期限切れ(401/認証失敗)X-Access-Token を再取得するようユーザーに案内します
图表编码已存在/duplicate check の戻り値が false別の code に変更するか、edit を使って編集します
parseSql の失敗SQL 構文が正しいか、テーブルが存在するか確認します
Y 軸のデータが乱れるY 軸フィールドの fieldType は数値型(Integer/BigDecimal/Long)である必要があります。String は指定できません
SQL注入风险SQL で DROP/DELETE/UPDATE などの危険なステートメントを使用しないでください
文字化けPython urllib を使用していることを確認します(curl は使用しないでください)

実測記録

実測 1:グラフの追加(2026-03-16 検証済み)

テストシーン:「システムログインユーザー統計分析」グラフを作成し、sys_user テーブルのユーザー数を性別ごとに集計します。

設定パラメーター:

  • グラフコード:tj_login_user
  • グラフ名:システムログインユーザー統計分析
  • グラフの種類:bar(棒グラフ)
  • X 軸:sex(性別)
  • Y 軸:cout(人数)

SQL:

select count(*) cout, sex from sys_user group by sex

Step 1 — parseSql による解析:

リクエスト:

GET /online/cgreport/head/parseSql?sql=select%20count(*)%20cout%2C%20sex%20from%20sys_user%20group%20by%20sex

戻り値(成功):

{
  "success": true,
  "code": 200,
  "result": {
    "fields": [
      {
        "id": "2033372375880409089",
        "fieldName": "cout",
        "fieldTxt": "cout",
        "fieldType": "String",
        "isShow": 1,
        "orderNum": 1
      },
      {
        "id": "2033372375880409090",
        "fieldName": "sex",
        "fieldTxt": "sex",
        "fieldType": "String",
        "isShow": 1,
        "orderNum": 2
      }
    ],
    "params": []
  }
}

Step 2 — add によるグラフの作成:

リクエスト:

POST /online/graphreport/head/add

リクエストボディ:

{
    "dbSource": "",
    "name": "系统登录用户统计分析",
    "code": "tj_login_user",
    "displayTemplate": "tab",
    "xaxisField": "sex",
    "yaxisField": "cout",
    "dataType": "sql",
    "graphType": "bar",
    "cgrSql": "select count(*) cout, sex from sys_user group by sex",
    "onlGraphreportItemList": [
        {
            "id": "1773628737000000123456",
            "cgrheadId": null,
            "fieldName": "cout",
            "fieldTxt": "人数",
            "fieldWidth": null,
            "fieldType": "String",
            "searchMode": null,
            "isOrder": null,
            "isSearch": null,
            "dictCode": null,
            "fieldHref": null,
            "isShow": "Y",
            "orderNum": 0,
            "replaceVal": null,
            "isTotal": null,
            "createBy": null,
            "createTime": null,
            "updateBy": null,
            "updateTime": null,
            "groupTitle": null
        },
        {
            "id": "1773628737000000654321",
            "cgrheadId": null,
            "fieldName": "sex",
            "fieldTxt": "性别",
            "fieldWidth": null,
            "fieldType": "String",
            "searchMode": null,
            "isOrder": null,
            "isSearch": null,
            "dictCode": "sex",
            "fieldHref": null,
            "isShow": "Y",
            "orderNum": 1,
            "replaceVal": null,
            "isTotal": null,
            "createBy": null,
            "createTime": null,
            "updateBy": null,
            "updateTime": null,
            "groupTitle": null
        }
    ],
    "paramsList": []
}

戻り値(成功):

{
  "success": true,
  "message": "添加成功!",
  "code": 200,
  "result": null,
  "timestamp": 1773628737956
}

主な確認事項:

  1. parseSql が返す fieldTxt はデフォルトで fieldName と同じ値(例:"cout")です。AI で中国語に翻訳する必要があります(例:「人数」)
  2. parseSql が返す isShow は数値の 1 です。add 時に文字列 "Y" に変換する必要があります
  3. parseSql が返す fieldType はすべて "String" です。意味に応じて修正する必要があります
  4. add 時、items の orderNum は 0 から始めても正常に動作します
  5. add 時、items 内の関連 ID フィールド名は cgrheadId(値は null)であり、graphreportHeadId ではありません
  6. gen_id() で生成された 19 桁の数値文字列は、API で正常に受け付けられます
  7. dictCode: "sex" でシステム辞書を正しく関連付け、値を変換できます
  8. 不要なフィールド値は null を渡せばよく、空文字列を渡す必要はありません
実測 2:グラフの編集(ユーザー提供のインターフェースデータで検証済み)

テストシナリオ:既存のグラフを変更し、単一の棒グラフを複合グラフ(折れ線+棒グラフ)に変更します。

リクエスト:

PUT /online/graphreport/head/edit

主なフィールドの変更点:

  • graphType を "bar" から "line,bar" に変更します
  • isCombination: "combination" を追加します
  • items 内の関連 ID のフィールド名が graphreportHeadId になります(add 時の cgrheadId とは異なります)
  • items 内では isSearch の代わりに searchFlag("Y"/"N")を使用します

レスポンス:

{
  "success": true,
  "message": "修改成功!",
  "code": 200,
  "result": null,
  "timestamp": 1773628040311
}

主な発見:

  1. edit では PUT メソッドを使用します(POST ではありません)
  2. edit 時の items の関連フィールド名は graphreportHeadId、add 時は cgrheadId です — 最も間違えやすい点です
  3. edit 時の検索フィールドには searchFlag("Y"/"N")を使用し、add 時には isSearch を使用します
  4. 複合グラフでは graphType: "line,bar" と isCombination: "combination" の両方を設定する必要があります
  5. edit 時には tenantId、createTime、createBy などのシステムフィールドに元の値を渡す必要があります
実測 3:API タイプのグラフと YApi Mock の連携作成(2026-04-16 検証済み)

テストシナリオ:データソースに YApi Mock API を使用し、グラフタイプを bar,table(棒グラフ+データ一覧)とする「人物情報グラフ」を作成します。

一連の手順:

  1. init_yapi(email, password) を呼び出して YApi にログインします(CookieJar 方式。すべての Python バージョンで使用できます)
  2. create_mock('/person_info', '人物信息', [...]) を呼び出して mock インターフェースを作成し、mock URL を取得します
  3. create_chart(... data_type='api', sql=mock_url ...) を呼び出してグラフを作成します

主な設定:

  • dataType: api
  • cgrSql: mock URL を指定します(https://api.jeecg.com/mock/57/claude/person_info)
  • graphType: bar,table(棒グラフとデータ一覧を同時に出力)
  • mock データは {"data": [...]} の形式でラップする必要があります。yapi_mock.py の create_mock() が自動的に処理します

主な発見:

  1. yapi_mock.py の init_yapi() は CookieJar 方式に変更済みのため、呼び出しスクリプト内で opener を自分で作成する必要はありません。from yapi_mock import init_yapi, create_mock と直接インポートできます
  2. API タイプのグラフでは、cgrSql フィールドに格納されるのは SQL 文ではなく API URL です
  3. graphType: "bar,table" を指定すると、グラフ領域とデータ一覧領域を同時に表示でき、「グラフと表の両方が必要」という要件を満たせます
  4. parseField?type=API は省略できます。フィールドが分かっている場合は、build_item() を使用して items を手動で構築しても同様に機能します
  5. 認証情報をスクリプトにハードコードしてはいけません。現在のコンテキストから探し、見つからない場合はユーザーに尋ねてから、パラメーターとして渡します

コメント