报告模板与文档生成
报告模板用于为指定流程配置 Word 报告模板、字段映射和脚本表达式,并在项目详情页或接口中生成最终文档。
功能概述
- 报告模板管理页负责维护模板文件和字段表达式,页面入口为后台菜单中的
报告模板 - 项目详情页中的
GenerateReport组件负责展示“生成报告”按钮 - 生成后的文档通过下载接口直接返回文件流,而不是 JSON
相关接口:
GET /api/flow_page_template
GET /api/flow_page_template/:id
POST /api/flow_page_template
PUT /api/flow_page_template/:id
DELETE /api/flow_page_template/:id
GET /api/flow_page_template/generate_report?id=<templateId>&projectId=<projectId>前置条件
在开始配置前,需要先明确下面几个参数:
| 参数 | 说明 |
|---|---|
flow_type | 所属流程类型,例如 flow48198545 |
flow_key | 所属环节 key。主流程模板通常为空字符串,子流程模板填写具体环节 key |
templateId | 报告模板 ID,保存模板后可在模板列表中看到 |
projectId | 要生成报告的项目 ID |
这些参数的典型来源如下:
flow_type、flow_key:来自当前流程或项目详情配置templateId:来自报告模板列表projectId:来自项目详情页 URL 或项目数据
模板配置方法
1. 进入模板列表并选择流程
进入后台 报告模板 页面,先在顶部流程选择器中切换到目标流程,例如“合同审批”。

2. 创建模板
点击右上角 创建模板 进入模板编辑页。

创建页主要分为三块:
基础信息:填写模板名称和简介模板文件配置:上传.docx模板文件,或下载示例 Word 模板参考模板文件占位符配置:为每个占位符配置字段名、说明和表达式
3. 上传模板文件
建议优先上传 .docx 模板文件。
当前页面支持上传:
.docx.doc.html
但正式使用建议统一为 .docx,因为自动提取和生成逻辑都优先围绕 .docx 工作。
4. 编写 Word 模板占位符
报告生成底层使用 Docxtemplater,模板中常见写法如下。
普通文本占位符:
{project_name}列表循环:
{#items}
名称:{name}
值:{value}
{/items}条件块:
{#has_summary}已生成摘要{/has_summary}
{^has_summary}暂无摘要{/has_summary}图片:
{%cover}5. 自动提取或手动添加字段
上传模板后,可以点击 自动提取,页面会扫描模板中的占位符并自动生成字段行。
如果自动提取结果不完整,也可以点击 添加 手动补充字段配置。
每个字段配置包含:
| 字段 | 说明 |
|---|---|
field | 模板中的占位符名称,必须与 Word 模板中的变量名一致 |
desc | 该字段的业务说明,便于维护 |
expression | 生成文档时执行的脚本表达式,返回最终填充值 |
6. 保存模板
点击右上角 保存 后,模板会保存到当前流程范围下。
模板保存后的核心结构如下:
{
"name": "合同审批报告",
"desc": "合同审批流程报告模板",
"flow_type": "flow48198545",
"flow_key": "",
"type": 5,
"content": "{\"fields\":[{\"field\":\"project_name\",\"desc\":\"项目名称\",\"expression\":\"return ctx.$PROJECT?.project_name || ''\"}],\"templateFile\":[{\"name\":\"report-template.docx\",\"url\":\"https://example.com/report-template.docx\"}]}"
}其中:
content.fields保存字段配置content.templateFile保存模板文件地址
字段脚本编写
字段表达式运行在服务端,不是浏览器环境。表达式会被包装成函数体执行,因此通常直接写 return ... 即可。
支持的能力包括:
- 支持
await - 可以读取当前项目上下文
ctx.$PROJECT - 可以使用
ctx.$moment、ctx.$lodash - 可以调用
ctx.$search(...)、ctx.$queryFromEs(...)查询 ES - 可以调用
ctx.$model(...)、ctx.$service(...) - 可以调用
ctx.getContent(...)获取知识库节点内容 - 可以调用
ctx.getSelfContent(ctx, 'field')复用同模板其他字段结果
示例 1:读取项目名称
return ctx.$PROJECT?.project_name || ''示例 2:格式化日期
const start = ctx.$PROJECT?.plan_start_time
if (!start) return ''
return ctx.$moment(start).format('YYYY-MM-DD')示例 3:拼接项目摘要
const project = ctx.$PROJECT || {}
return [
`项目名称:${project.project_name || '-'}`,
`负责人:${project.__project_owner?.name || '-'}`,
`计划完成时间:${project.plan_end_time || '-'}`
].join('\n')示例 4:查询 ES
const result = await ctx.$queryFromEs({
size: 5,
query: {
bool: {
must: [
{ term: { organization_id: ctx.$PROJECT.organization_id } },
{ term: { project_id: ctx.$PROJECT.id } }
]
}
},
sort: [{ create_time: { order: 'desc' } }]
})
const list = result?.hits?.hits || []
return list.map(item => item._source?.content || '').join('\n')示例 5:使用 $search
const res = await ctx.$search({
size: 1,
query: {
term: { project_id: ctx.$PROJECT.id }
}
})
return res?.hits?.hits?.[0]?._source?.title || ''示例 6:查询模型
const project = await ctx.$model('project')
.where({ id: ctx.$PROJECT.id })
.find()
return project?.project_name || ''示例 7:调用服务
const projectService = ctx.$service('project')
const detail = await projectService.getProjectDetail(ctx.$PROJECT.id)
return detail?.project_name || ''示例 8:读取知识库节点内容
return await ctx.getContent({
ctx,
id: 12345,
param: {
keyword: ctx.$PROJECT?.project_name || ''
}
})示例 9:复用模板内其他字段
const base = await ctx.getSelfContent(ctx, 'summary')
return `补充说明:\n${base || ''}`示例 10:返回图片
Word 模板中使用 {%cover} 时,表达式可返回:
return {
type: 'img',
url: 'https://example.com/logo.png'
}示例 11:返回数组给循环块
Word 模板:
{#items}{name}:{value}{/items}表达式:
return [
{ name: '项目名称', value: ctx.$PROJECT?.project_name || '-' },
{ name: '负责人', value: ctx.$PROJECT?.__project_owner?.name || '-' }
]项目详情页挂载方式
如果希望在项目详情页里显示“生成报告”按钮,需要在项目详情模板中添加 generate-report 模块:
{
"type": "generate-report",
"title": "生成报告",
"config": {
"flow_key": "",
"flow_type": "flow48198545"
}
}其中:
flow_type对应流程类型flow_key对应环节 key。主流程模板可为空
项目详情页展示按钮后,会根据当前流程范围查询可用的报告模板,并触发文档下载。
通过接口获取生成好的文档
生成好的 Word 文档通过下载接口直接获取。
请求方式:
GET /api/flow_page_template/generate_report?id=<templateId>&projectId=<projectId>参数说明:
| 参数 | 必填 | 说明 |
|---|---|---|
id | 是 | 报告模板 ID |
projectId | 是 | 项目 ID |
返回结果:
- 成功时直接返回
.docx文件下载流 - 失败时返回错误信息
浏览器直接下载
/api/flow_page_template/generate_report?id=954573724&projectId=123456curl 示例
curl -L \
-H "Authorization: Bearer <token>" \
"https://your-domain/api/flow_page_template/generate_report?id=954573724&projectId=123456" \
-o 合同审批报告.docx前端调用示例
window.location.href =
`${location.origin}/api/flow_page_template/generate_report` +
`?id=${templateId}&projectId=${projectId}`常见问题
自动提取不到字段
优先检查以下几点:
- 是否上传的是
.docx或.html - 模板变量是否写成标准的
{field}或{#list}...{/list} - 自动提取当前只会提取根字段,像
{user.name}、带|的复杂写法不会自动生成字段配置
模板已保存但列表里看不到
通常需要检查:
- 当前列表选择的
flow_type是否和保存时一致 - 主流程模板的
flow_key是否为空 - 是否误把模板保存到了其他环节范围
表达式报错或返回空
优先排查:
- 是否忘了
return - 异步逻辑是否正确使用了
await ctx上访问的字段是否真实存在- ES 或模型查询是否有权限或条件不匹配
图片不显示
需要同时满足:
- Word 模板中使用
{%field} - 脚本返回
{ type: 'img', url: '...' } - 图片 URL 可被服务端访问
生成接口返回的不是 JSON
这是正常行为。/api/flow_page_template/generate_report 成功时返回的是文件下载流,调用方应按文件下载处理。
