仅覆盖 Go 后端:Meta(模板控制面)+ Worker(渲染/导出运行时)。不含前端编辑器说明。
| 进程 | 入口 | 职责 |
|---|---|---|
| Meta | backend/cmd/meta(默认 :3010) |
模板 CRUD、Excel→DSL、runtime 下发;type=html 时 HTML 存 OSS |
| Worker | backend/worker SDK / examples/worker-example(默认 :3011) |
拉 runtime → 进程内 DSL→HTML → PDF/Excel/Word |
客户端 / 业务系统
│
├─ CRUD / import-excel ──────────────► Meta (Postgres + 可选 S3)
│
└─ invoke / render ──────────────────► Worker
│
├─ GET Meta /runtime
├─ dslrender.Render(DSL, data) → HTML
└─ export.* → pdf | excel | word
原则
type=report:模板唯一可信源是dslJson;HTML 只是运行时产物,不回写库。- Worker 不访问 S3;
type=html时 Meta 返回templateUrl,Worker 用 HTTP GET。 - 导出格式在请求时指定,不存模板上。
cp .env.example .env
make docker-up # Postgres + rustfs(S3)
make run-meta # :3010
make run-worker # :3011| 变量 | 用途 | 默认 |
|---|---|---|
PORT |
Meta 端口 | 3010 |
LOWCODE_EXPORT_POSTGRES_DSN |
Meta DB | 见 .env.example |
LOWCODE_EXPORT_S3_* |
Meta 存 type=html 模板体 |
rustfs 本地默认 |
LOWCODE_EXPORT_META_URL |
Worker → Meta | http://127.0.0.1:3010 |
LOWCODE_EXPORT_WORKER_LISTEN |
Worker 监听 | :3011 |
LOWCODE_EXPORT_LOG_LEVEL |
Worker 日志 | info |
PDF_FONT_FILE |
PDF 中文 .ttf(可选) |
macOS 可自动找 Arial Unicode |
Base:http://127.0.0.1:3010
| 方法 | 路径 | 说明 |
|---|---|---|
| GET | /healthz |
{ ok, role: "meta" } |
| GET | /api/formats |
{ formats: ["pdf","excel","word"] } |
| GET | /api/templates |
模板列表 |
| GET | /api/templates/get?id= |
模板详情(含 dslJson / html) |
| POST/PUT | /api/templates/save |
保存;name 必填;report 用 dslJson |
| DELETE | /api/templates/delete?id= |
删除 |
| GET | /api/templates/{id}/runtime |
Worker 用:DSL 或 templateUrl + etag |
| POST | /api/templates/import-excel |
multipart file → { dsl, name, sheetNames }(不落库) |
| POST | /api/preview |
兼容预览(HTML Mustache 或透传) |
{
"id": "optional-uuid",
"name": "report_{{year}}_{{month}}",
"type": "report",
"group": "household",
"dslJson": { "id": "page_1", "type": "page", "props": {}, "children": [] }
}name可含 Mustache 变量;导出文件名在 Worker 侧用业务data解析(如report_2016_08.pdf)。- 入站仍可接受遗留字段
fields作为dslJson别名;响应不再回写fields。
{
"id": "...",
"name": "...",
"type": "report",
"etag": "...",
"dslJson": { },
"templateUrl": ""
}type=html 时主要用 templateUrl(或偶发 inline html)。
Base:http://127.0.0.1:3011
| 方法 | 路径 | 说明 |
|---|---|---|
| GET | /healthz |
{ ok, role: "worker" } |
| GET | /api/formats |
同 Meta |
| POST | /api/render/html |
DSL + bizData → HTML(JSON) |
| POST | /api/render/pdf |
已渲染 HTML → PDF 文件流 |
| POST | /api/templates/{id}/invoke |
完整导出(推荐) |
| POST | /api/export |
{ templateId, format, data },等同 invoke |
POST /api/render/html
Content-Type: application/json
{ "templateDsl": { ... }, "bizData": { ... } }{ "code": 0, "data": { "html": "<!DOCTYPE html>..." } }实现:internal/dslrender.Render。
POST /api/templates/{id}/invoke
Content-Type: application/json
{ "format": "pdf", "data": { "person": { "name": "张三" }, "year": "2016", "month": "08" } }响应:文件字节流。
| Header | 含义 |
|---|---|
Content-Type |
pdf / xlsx / docx MIME |
Content-Disposition |
attachment; filename="..."(名称已解析变量) |
X-Export-Etag |
模板 etag |
X-Export-Template |
模板 id |
X-Export-Duration-Ms |
耗时 |
流水线
GET {META}/api/templates/{id}/runtimetype=report|tmagic:dslrender.Render(dslJson, data)→ HTML
type=html:拉取templateUrl/ Mustache 渲染 → HTMLexport.ExportRenderedHTML(format, html, data)→ 文件
curl -X POST "http://127.0.0.1:3011/api/templates/<id>/invoke" \
-H 'Content-Type: application/json' \
-d '{"format":"excel","data":{"year":"2016","month":"08","person":{"name":"张三"}}}' \
-o out.xlsx包:backend/internal/dslrender
顶层 page(建议 A4:794×1123),子节点 children + layout{left,top,width,height}。
| type | 说明 |
|---|---|
text |
文案;props.text 支持 {{a.b}};fontSize / fontWeight / color / textAlign |
image |
props.src / url,可变量 |
divider |
分割线;长度=layout.width,粗细=layout.height,props.color |
report-sheet |
网格;sheetData + loops |
sheetData:LuckySheet 兼容
row/column/celldata/merge/columnlen/rowlen/borderInfo/images/hyperlinkloops[]:source、itemName、startRow、rowCount(按数组展开原型行)- 单元格:文本 /
{{item.x}};图片 URL、{{logoUrl}}、tp:"img"、→<img> - 单元格样式:
bl加粗、fc颜色、bg背景;borderInfo→ td 边框
包:backend/internal/export
| format | 引擎 | 行为摘要 |
|---|---|---|
pdf |
gofpdf + UTF-8 中文字体 | 按文档块输出文本/表格/分割线/图片;保留加粗与颜色、单元格边框 |
excel |
excelize | 文本块 + 表格(样式/边框);图片尽量嵌入 |
word |
简易 OOXML | 由 HTML 结构生成 |
公共步骤:
- 从 HTML 抽文档块(
report-text、table、report-divider)与图片 - 解析内联
color/font-weight/border-* ResolveExportFilename(template.Name, data)→ 安全文件名
PDF 字体:AddUTF8FontFromBytes;候选路径含 PDF_FONT_FILE、系统 Arial Unicode / Noto Sans SC。缺字体会直接报错(避免中文乱码静默失败)。
import "github.com/solat/lowcode-export/worker"
w, err := worker.New(worker.ConfigFromEnv())
// 或 worker.New(cfg, worker.WithLogger(log))
_ = w.Run(ctx)
// 或 mux.Handle("/", w.Handler())环境:至少配置 LOWCODE_EXPORT_META_URL。详见 backend/examples/worker-example。
| 路径 | 职责 |
|---|---|
backend/cmd/meta |
Meta 进程 |
backend/worker |
可嵌入 Worker SDK |
backend/internal/dslrender |
DSL → HTML |
backend/internal/export |
HTML → PDF/Excel/Word |
backend/internal/excelimport |
Excel → DSL(Meta) |
backend/internal/store |
Postgres 模板 + OSS HTML |
backend/internal/handlers |
Meta / Worker HTTP |
backend/internal/metaclient |
Worker 调 Meta |
backend/internal/models |
DTO / 格式常量 |
整体产品边界、DSL 与旧 tmagic 差异见 prd-architecture.md。本文只展开 后端导出调用方式与实现落点。