更新记录

1.0.0(2026-10-28)

首个版本:结构化生成 docx(标题/信息表/章节/段落/表格/图片/分页/页脚页码)、A4 纵横与页边距参数化、表格列宽按权重分配与表头跨页重复、PNG/JPEG/GIF 像素尺寸解析与等比缩放、docx 模板 ${字段} 填充(缺值返回 missing 清单)、统一错误码与半成品清理;不引任何三方库,零存储权限。UTS→Kotlin 编译通过(index.kt 1938 行),114 项纯逻辑与 python-docx 往返测试全部通过;真机未执行(测试机未连接)。


平台兼容性

uni-app

Vue2 Vue3 Chrome Safari app-vue app-nvue Android iOS 鸿蒙
× √ × × √ × √ × ×
微信小程序 支付宝小程序 抖音小程序 百度小程序 快手小程序 京东小程序 鸿蒙元服务 QQ小程序 飞书小程序 小红书小程序 快应用-华为 快应用-联盟
× × × × × × × × × × × ×

企业 Word 报告生成(零依赖 docx)

给需要在 App 里出检测报告、巡检单、验收单、合同附件的开发者:用几行调用把业务数据写成标准 .docx,用户拿到就能在 WPS / 手机 Office 里打开、盖章、发客户。

不需要引 POI、docx4j 等三方库,安装包不增加体积;默认写到应用私有目录,不需要任何存储权限。

为什么值得用

现场出单时,客户要的是「一份能盖章的 Word」,不是一张截图,也不是一个只能在本 App 里看的页面。自己拼 OOXML 的坑集中在三个地方:表格列宽算不对、图片比例被拉变形、中文特殊字符没转义导致 Word 报「文档已损坏」。这个插件把这三件事做完了,并且把版式参数化:

  • 表格:列宽按权重分配(加总严格等于正文宽度),表头跨页重复、行不跨页,长表格翻页后还能对上列;
  • 图片:读 PNG/JPEG/GIF 文件头拿真实像素尺寸,按目标宽度等比缩放,超过正文宽度自动收窄,不会顶出页边距;
  • 中文:五个预定义实体转义,并丢弃 XML 1.0 不允许的控制字符——这一条不做,客户数据里混进一个不可见字符,文档就打不开了;
  • 模板:客户自己做好的 Word 模板,把 ${字段} 换成业务数据即可,页眉页脚、样式、图片原样保留。

快速开始

import {
  createReport, addHeading, addParagraph, addTable,
  addPageBreak, saveReport, abortReport
} from '@/uni_modules/szhzy-docx-report'

const r = createReport({
  title: 'LED 驱动电源检测报告',
  subtitle: '恒之源检测中心 · 报告编号 SZHZY-2026-1028',
  meta: [
    ['委托单位', '深圳恒之源技术股份有限公司'],
    ['样品编号', 'S-2026-0417'],
    ['检测日期', '2026-10-28']
  ],
  footerText: '本报告仅对本次送检样品负责',
  footerPage: true
})
if (!r.ok) return console.error(r.code, r.message)
const token = r.token

addHeading(token, { text: '一、检测结果', level: 1 })
addTable(token, {
  headers: ['检测项目', '技术要求', '实测值', '判定'],
  rows: [
    ['绝缘电阻', '≥ 2 MΩ', '3.6 MΩ', '合格'],
    ['接地电阻', '≤ 0.1 Ω', '0.06 Ω', '合格']
  ],
  widths: [18, 34, 24, 16],
  aligns: ['left', 'left', 'center', 'center']
})
addHeading(token, { text: '二、结论', level: 1 })
addParagraph(token, { text: '所检项目全部符合 GB 7000.1-2015 要求,判定为合格。', indentCm: 0.74 })
addPageBreak(token)
addParagraph(token, { text: '检测员:陈工 审核:李工', spaceBefore: 12 })

const saved = saveReport(token, { fileName: '检测报告', dateStamp: '20261028' })
if (!saved.ok) abortReport(token)

API

所有接口同步执行,返回统一信封 { ok, code, message, ... },错误用 code 表达,不抛异常给调用方。

接口 说明
createReport(options) 建文档,返回 token。title / subtitle / meta / landscape / marginCm / fontName / fontSize / footerText / footerPage
addHeading(token, { text, level }) 章节标题,level 1–4,带大纲级别(WPS 导航窗格可见)
addParagraph(token, { text, bold, size, color, align, indentCm, spaceBefore, spaceAfter }) 正文段落,\n 会变成真正的换行
addTable(token, { headers, rows, widths, aligns, headerFill, fontSize }) 数据表;widths 是相对权重,不是绝对宽度
addKeyValue(token, { rows, labelWidthCm, fontSize }) 两列信息表,报告头部的「委托单位 / 样品编号」区域
addImage(token, { path, widthCm, dpi }) 嵌入型图片;widthCm 缺省用原始尺寸,超宽自动收窄
addPageBreak(token) 分页
addSpacer(token, sizePt) 段后留白
saveReport(token, { path, dir, fileName, dateStamp }) 落盘,返回 path / bytes / blocks / images
abortReport(token) 放弃会话,不产生文件
readTemplatePlaceholders({ templatePath }) 列出模板里的 ${字段}
fillTemplate({ templatePath, outPath, data }) 模板填充,返回 replaced 与 missing

模板模式

const keys = readTemplatePlaceholders({ templatePath: '/sdcard/Android/data/<包名>/files/模板.docx' })
const out = fillTemplate({
  templatePath: '/sdcard/Android/data/<包名>/files/模板.docx',
  outPath: '/sdcard/Android/data/<包名>/files/documents/交货单.docx',
  data: { client: '深圳恒之源技术股份有限公司', orderNo: 'PO-2026-0417', amount: '128,600.00' }
})
if (out.code === 'MISSING_FIELD') {
  // missing 里是没给值的字段,按业务决定是补数据还是照常出单
}

模板注意两点:

  1. 数据值必须是字符串,金额、日期请先用 formatFixed 这类方法格式化,否则会出现 1234.0 这种写法;
  2. 占位符要写在同一段文字的同一处。如果客户在 Word 里编辑时把 ${字段} 拆成了两段(比如中间改过字体),Word 会把它存成多个 run,本插件按纯文本匹配,拆开就匹配不到——让客户重新整段输入一次即可。

购买前必读

  • 平台:仅 Android App(uni-app Vue3,APP-PLUS)。iOS、鸿蒙、小程序、H5 未实现,市场声明里已标不支持。
  • 落盘位置:默认 /sdcard/Android/data/<包名>/files/documents,属于应用私有外部目录,卸载 App 时一并删除,不需要存储权限。要写到用户选的目录,请配合文件存取类插件拿到路径或先复制。
  • 大表格:单表上限 20 列 / 5000 行,超出请拆表。生成在调用线程执行,几百行是毫秒级;上千行建议放到 setTimeout 后再执行,避免卡住页面动画。
  • 内容校验:插件只保证「文档结构合法、文字与表格写对」。合同金额、检测结论这类业务判断请在上层做好,插件不做任何业务校验。
  • 图片尺寸:按文件头读像素,DPI 缺省 96。手机相册原图常见 72,如果发现图片偏大,显式传 dpi: 72。

验证状态(如实说明)

  • UTS → Kotlin 编译:通过(HBuilderX 5.33,launch app-android --compile true,产物 index.kt 1938 行,0 error)。
  • 纯逻辑回归测试:114 项全部通过,含用同一份 core 逻辑拼出真实 .docx 后交 python-docx 读取的往返校验(段落、两张表格的单元格、页脚、图片部件、每个 XML 部件良构)。
  • 真机运行:未执行。开发时测试机未连接(adb devices 为空),因此没有真机截图与真机上的落盘验证;市场图为 H5 渲染的真实页面,页面内已标注示例数据与预览环境。
  • 未验证项:Android 平台层的 zip 写盘、图片流复制在真机上的表现(逻辑与结构已在 Node 侧验证,但未经设备执行)。

常见错误码

code 含义与处理
SESSION_NOT_FOUND token 无效或已保存,重新 createReport
SESSION_CLOSED 已保存/已中止,不能再追加
EMPTY_DOCUMENT 一个字都没写就保存,先加内容
ROW_WIDTH_MISMATCH 某行列数与表头不一致,message 里有行号
TOO_MANY_COLUMNS / TOO_MANY_ROWS 超上限,拆表
IMAGE_NOT_FOUND / IMAGE_UNSUPPORTED 图片路径不可读,或不是 PNG/JPEG/GIF
TEMPLATE_INVALID 模板不是有效 docx(缺 word/document.xml)
MISSING_FIELD 模板占位符没给值,missing 里是字段名
IO_ERROR 写盘失败,检查空间与文件占用

隐私、权限声明

1. 本插件需要申请的系统权限列表:

无。默认写入应用外部私有目录(context.getExternalFilesDir),不需要存储权限;写到其它位置需调用方先自行取得该位置的访问权限。

2. 本插件采集的数据、发送的服务器地址、以及数据用途说明:

插件不采集、不上传任何数据,不访问网络。读取的图片与模板、生成的 docx 全部在本机处理,只写入调用方指定的路径或应用私有目录。

3. 本插件是否包含广告,如包含需详细说明广告表达方式、展示频率:

无

暂无用户评论。