329 lines
9.4 KiB
Markdown
329 lines
9.4 KiB
Markdown
# 报表组件参考
|
||
|
||
积木报表支持 4 种图层组件(Layer),它们以独立数组存储在 jsonStr 顶层,与 rows/cols 平级。
|
||
|
||
## 组件类型总览
|
||
|
||
| 组件 | jsonStr 字段 | 类型标识 | 用途 |
|
||
|------|-------------|---------|------|
|
||
| 图片 | `imgList` | `img` | 外部图片/Logo/背景图 |
|
||
| 图表 | `chartList` | `chart` | ECharts 可视化图表 |
|
||
| 条形码 | `barcodeList` | `barcode` | CODE128/EAN 等一维码 |
|
||
| 二维码 | `qrcodeList` | `qrcode` | QR Code 二维码 |
|
||
|
||
所有组件共享以下基础属性:
|
||
|
||
```python
|
||
{
|
||
"row": 0, # 起始行号(从0开始)
|
||
"col": 0, # 起始列号(从0开始)
|
||
"colspan": 0, # 列跨度
|
||
"rowspan": 0, # 行跨度
|
||
"width": 300, # 宽度(像素,图表必须是字符串如"300")
|
||
"height": 200, # 高度(像素,图表必须是字符串如"200")
|
||
"layer_id": "唯一ID", # 唯一标识,对应 virtual cell
|
||
"offsetX": 0, # X偏移
|
||
"offsetY": 0, # Y偏移
|
||
"virtualCellRange": [[row,col], ...] # 占据的所有单元格坐标
|
||
}
|
||
```
|
||
|
||
## 1. 图片组件 (imgList)
|
||
|
||
### JSON 结构
|
||
|
||
```python
|
||
img_item = {
|
||
"row": 0,
|
||
"col": 1,
|
||
"colspan": 0,
|
||
"rowspan": 0,
|
||
"width": 315, # 数字
|
||
"height": 151, # 数字
|
||
"src": "/jmreport/img/upload/xxx.png", # 图片路径(相对或绝对)
|
||
"isBackend": False, # 是否作为前置遮罩
|
||
"isBackendImg": False, # 是否作为背景图
|
||
"commonBackend": None, # 共享遮罩/背景属性
|
||
"layer_id": "img_xxx",
|
||
"offsetX": 0,
|
||
"offsetY": 0,
|
||
"virtualCellRange": [[0,1],[0,2],[1,1],[1,2]]
|
||
}
|
||
```
|
||
|
||
### 图片路径说明
|
||
|
||
| 类型 | 示例 |
|
||
|------|------|
|
||
| 上传图片 | `/jmreport/img/upload/xxx.png` |
|
||
| 外部URL | `https://example.com/logo.png` |
|
||
| 数据绑定 | `${dbCode.imgField}` — 字段值为图片URL |
|
||
|
||
## 2. 图表组件 (chartList)
|
||
|
||
详见 `chart-config.md`,这里列出关键结构。
|
||
|
||
### JSON 结构
|
||
|
||
```python
|
||
chart_item = {
|
||
"row": 5,
|
||
"col": 1,
|
||
"colspan": 0,
|
||
"rowspan": 0,
|
||
"width": "650", # 必须是字符串!
|
||
"height": "350", # 必须是字符串!
|
||
"config": json.dumps(echarts_option), # ECharts 配置 JSON 字符串
|
||
"url": "", # 外部数据 URL(通常为空)
|
||
"extData": {
|
||
"chartType": "bar.simple", # 图表类型
|
||
"dataType": "sql", # 数据来源: "sql"/"api"/"json"/"javabean"/"files"
|
||
"dataId": "数据集ID", # saveDb 返回的 id
|
||
"dbCode": "数据集编码", # 数据集编码
|
||
"axisX": "name", # 固定值
|
||
"axisY": "value", # 固定值
|
||
"series": "type", # 固定值
|
||
"xText": "",
|
||
"yText": "",
|
||
"apiStatus": "1"
|
||
},
|
||
"layer_id": "chart_xxx",
|
||
"offsetX": 0,
|
||
"offsetY": 0,
|
||
"backgroud": {"enabled": False, "color": "#fff", "image": ""},
|
||
"virtualCellRange": [[5,1],[5,2],...]
|
||
}
|
||
```
|
||
|
||
## 3. 条形码组件 (barcodeList)
|
||
|
||
### JSON 结构
|
||
|
||
```python
|
||
barcode_item = {
|
||
"row": 3,
|
||
"col": 0,
|
||
"colspan": 0,
|
||
"rowspan": 0,
|
||
"width": 300,
|
||
"height": 200,
|
||
"layer_id": "barcode_xxx",
|
||
"offsetX": 0,
|
||
"offsetY": 0,
|
||
"jsonString": json.dumps({
|
||
"barcodeContent": "jmreport", # 条码内容(支持 ${dbCode.field} 动态绑定)
|
||
"format": "CODE128", # 条码格式
|
||
"width": 2, # 条线宽度
|
||
"height": 100, # 条码高度
|
||
"displayValue": False, # 是否显示文字
|
||
"text": "jmreport", # 显示文字内容
|
||
"fontOptions": "", # 字体选项(bold/italic)
|
||
"font": "monospace", # 字体
|
||
"textAlign": "center", # 文字对齐
|
||
"textPosition": "bottom", # 文字位置
|
||
"textMargin": 2, # 文字间距
|
||
"fontSize": 20, # 字体大小
|
||
"background": "#fff", # 背景色
|
||
"lineColor": "#000", # 条线颜色
|
||
"margin": 10 # 边距
|
||
}),
|
||
"virtualCellRange": [[3,0],[3,1],[4,0],[4,1]]
|
||
}
|
||
```
|
||
|
||
### 支持的条码格式
|
||
|
||
| format | 说明 |
|
||
|--------|------|
|
||
| `CODE128` | Code 128(默认,最常用) |
|
||
| `CODE39` | Code 39 |
|
||
| `EAN13` | EAN-13 |
|
||
| `EAN8` | EAN-8 |
|
||
| `UPC` | UPC-A |
|
||
| `ITF14` | ITF-14 |
|
||
|
||
### 动态数据绑定
|
||
|
||
条码内容支持表达式:`${dbCode.fieldName}`,运行时替换为数据集字段值。
|
||
|
||
## 4. 二维码组件 (qrcodeList)
|
||
|
||
### JSON 结构
|
||
|
||
```python
|
||
qrcode_item = {
|
||
"row": 5,
|
||
"col": 0,
|
||
"colspan": 0,
|
||
"rowspan": 0,
|
||
"width": 128,
|
||
"height": 128,
|
||
"layer_id": "qrcode_xxx",
|
||
"offsetX": 0,
|
||
"offsetY": 0,
|
||
"jsonString": json.dumps({
|
||
"text": "http://jimureport.com/", # 二维码内容(支持 ${dbCode.field})
|
||
"width": 128,
|
||
"height": 128,
|
||
"colorDark": "#000000", # 前景色
|
||
"colorLight": "#ffffff" # 背景色
|
||
}),
|
||
"virtualCellRange": [[5,0],[5,1],[6,0],[6,1]]
|
||
}
|
||
```
|
||
|
||
## 5. 单元格内嵌组件 (displayConfig)
|
||
|
||
除了图层组件,单元格本身也可以通过 `display` 属性渲染为特殊组件:
|
||
|
||
```python
|
||
# 在 rows 的 cell 中设置
|
||
cell = {
|
||
"text": "#{dbCode.imgUrl}",
|
||
"display": "img" # 渲染为图片
|
||
}
|
||
|
||
# 或
|
||
cell = {
|
||
"text": "#{dbCode.code}",
|
||
"display": "barcode" # 渲染为条形码
|
||
}
|
||
|
||
# 或
|
||
cell = {
|
||
"text": "#{dbCode.url}",
|
||
"display": "qrcode" # 渲染为二维码
|
||
}
|
||
```
|
||
|
||
**display 可选值:**
|
||
|
||
| 值 | 说明 |
|
||
|----|------|
|
||
| `normal` | 普通文本(默认) |
|
||
| `img` | 图片(text 为图片 URL) |
|
||
| `barcode` | 条形码(text 为条码内容) |
|
||
| `qrcode` | 二维码(text 为二维码内容) |
|
||
| `base64Img` | Base64 图片 |
|
||
| `richText` | 富文本/HTML |
|
||
|
||
## Virtual Cell 占位规则
|
||
|
||
所有图层组件都需要在 `rows` 中声明 virtual 占位:
|
||
|
||
```python
|
||
# 1. 确定组件占据的行列范围
|
||
row_start, row_end = 5, 8
|
||
col_start, col_end = 1, 4
|
||
layer_id = "chart_xxx"
|
||
|
||
# 2. 构造 virtualCellRange
|
||
virtual_cells = []
|
||
for r in range(row_start, row_end + 1):
|
||
for c in range(col_start, col_end + 1):
|
||
virtual_cells.append([r, c])
|
||
|
||
# 3. 在 rows 中添加 virtual 占位
|
||
for r in range(row_start, row_end + 1):
|
||
cells = {}
|
||
for c in range(col_start, col_end + 1):
|
||
cells[str(c)] = {"text": " ", "virtual": layer_id}
|
||
rows_data[str(r)] = {"cells": cells}
|
||
|
||
# 4. 组件中设置 virtualCellRange
|
||
component["virtualCellRange"] = virtual_cells
|
||
```
|
||
|
||
**注意事项:**
|
||
- `virtual` 值必须和组件的 `layer_id` 一致
|
||
- `text` 必须为 `" "`(一个空格),不能为空
|
||
- 组件区域不能和数据绑定行重叠
|
||
- 一个组件的 virtual cells 不能和其他组件重叠
|
||
|
||
## Python 构造完整示例
|
||
|
||
```python
|
||
# 构造一个包含 表格 + 柱状图 + 二维码 的报表
|
||
|
||
layer_chart_id = "chart_" + gen_id()
|
||
layer_qr_id = "qrcode_" + gen_id()
|
||
|
||
rows_data = {
|
||
# 标题行
|
||
"1": {"cells": {"1": {"text": "销售报表", "style": 5}}, "height": 40},
|
||
# 表头
|
||
"2": {"cells": {
|
||
"1": {"text": "产品", "style": 4},
|
||
"2": {"text": "销量", "style": 4},
|
||
"3": {"text": "金额", "style": 4}
|
||
}, "height": 34},
|
||
# 数据行
|
||
"3": {"cells": {
|
||
"1": {"text": "#{ds.name}", "style": 2},
|
||
"2": {"text": "#{ds.qty}", "style": 2},
|
||
"3": {"text": "#{ds.amount}", "style": 2}
|
||
}},
|
||
# 空行
|
||
"4": {"cells": {}, "height": 15},
|
||
"len": 200
|
||
}
|
||
|
||
# 柱状图占位 (row 5-12, col 1-5)
|
||
for r in range(5, 13):
|
||
cells = {}
|
||
for c in range(1, 6):
|
||
cells[str(c)] = {"text": " ", "virtual": layer_chart_id}
|
||
rows_data[str(r)] = {"cells": cells}
|
||
|
||
# 二维码占位 (row 5-8, col 6-7)
|
||
for r in range(5, 9):
|
||
cells = rows_data.get(str(r), {"cells": {}})["cells"]
|
||
for c in range(6, 8):
|
||
cells[str(c)] = {"text": " ", "virtual": layer_qr_id}
|
||
rows_data[str(r)] = {"cells": cells}
|
||
|
||
# 柱状图
|
||
chart_config = {
|
||
"title": {"text": "销量统计", "left": "center"},
|
||
"tooltip": {"trigger": "axis"},
|
||
"xAxis": [{"type": "category", "data": []}],
|
||
"yAxis": [{"type": "value"}],
|
||
"series": [{"type": "bar", "data": [], "itemStyle": {"color": "#01b0f1"}}]
|
||
}
|
||
|
||
chart_list = [{
|
||
"row": 5, "col": 1, "colspan": 0, "rowspan": 0,
|
||
"width": "500", "height": "300",
|
||
"config": json.dumps(chart_config, ensure_ascii=False),
|
||
"url": "",
|
||
"extData": {
|
||
"chartType": "bar.simple", "dataType": "sql",
|
||
"dataId": chart_db_id, "dbCode": "saleschart",
|
||
"axisX": "name", "axisY": "value", "series": "type",
|
||
"xText": "", "yText": "", "apiStatus": "1"
|
||
},
|
||
"layer_id": layer_chart_id,
|
||
"offsetX": 0, "offsetY": 0,
|
||
"backgroud": {"enabled": False, "color": "#fff", "image": ""},
|
||
"virtualCellRange": [[r,c] for r in range(5,13) for c in range(1,6)]
|
||
}]
|
||
|
||
# 二维码
|
||
qrcode_list = [{
|
||
"row": 5, "col": 6, "colspan": 0, "rowspan": 0,
|
||
"width": 128, "height": 128,
|
||
"layer_id": layer_qr_id,
|
||
"offsetX": 0, "offsetY": 0,
|
||
"jsonString": json.dumps({"text": "https://example.com", "width": 128, "height": 128, "colorDark": "#000000", "colorLight": "#ffffff"}),
|
||
"virtualCellRange": [[r,c] for r in range(5,9) for c in range(6,8)]
|
||
}]
|
||
|
||
# 最终保存数据中包含
|
||
save_data = {
|
||
# ... 其他字段
|
||
"chartList": chart_list,
|
||
"qrcodeList": qrcode_list,
|
||
# imgList 和 barcodeList 为空时可省略或传 []
|
||
}
|
||
```
|