更新记录
1.0.0(2026-10-27)
首个版本:流式读取 xlsx/xlsm(内存与行数无关)、取值还原(共享字符串/内联字符串/富文本/公式缓存值/布尔/日期含 1900 闰年偏差/数值浮点尾巴)、表头别名映射、逐行校验(必填/类型/长度/范围/枚举/唯一)、错误行 CSV 回执(行号为 Excel 真实行号)、统一错误码;UTS→Kotlin 编译通过,75 项核心逻辑测试通过(含 openpyxl 产出文件、共享字符串合成包、1/2/3/7/61 字节切块流式一致性、3001 行大表)。
平台兼容性
uni-app
| Vue2 | Vue3 | Chrome | Safari | app-vue | app-nvue | Android | iOS | 鸿蒙 |
|---|---|---|---|---|---|---|---|---|
| × | √ | - | - | √ | × | √ | - | - |
| 微信小程序 | 支付宝小程序 | 抖音小程序 | 百度小程序 | 快手小程序 | 京东小程序 | 鸿蒙元服务 | QQ小程序 | 飞书小程序 | 小红书小程序 | 快应用-华为 | 快应用-联盟 |
|---|---|---|---|---|---|---|---|---|---|---|---|
| - | - | - | - | - | - | - | - | - | - | - | - |
企业报表 Excel 导入(映射 · 校验)
让员工把 Excel 台账直接导进 App:读表 → 对字段 → 逐行校验 → 错误行回执,一条链路走完。
这个插件解决什么问题
做过 App 端导入的都遇到过这几件事:
- 前端库解 xlsx,几万行就把页面卡死,最后只能规定"最多导入 5000 条";
- 客户表格的表头年年变:今年叫「料号」,明年叫「物料编码」,代码里写死的列序一改就崩;
- 日期读出来是
46296这种序列号,金额读出来是15.500000000000002; - 校验只报一句"导入失败",用户不知道是哪一行哪一列错了,最后还是要人工对表;
- 表格中间有空行,报错行号整体偏移,用户按行号去改,改错了地方。
本插件针对的正是这五件事:
| 老问题 | 本插件的做法 |
|---|---|
| 大表卡死 | 工作表按 16K 字符分块喂进解析器,行数据边解析边交回,内存占用与总行数无关 |
| 表头漂移 | 字段与表头按「别名 → 完全相等 → 前缀 → 包含」四级匹配,同一列不会被两个字段抢走 |
| 日期变数字 | 按样式表识别日期格式,统一还原成 yyyy-MM-dd[ HH:mm:ss],含 1900 闰年历史偏差处理 |
| 报错说不清 | 每个错误带 Excel 真实行号、字段中文名、原值、中文原因,可一键导出 CSV 回执 |
| 行号偏移 | 行号取自 row 节点的 r 属性,表格中间空行、跳行都不会错位 |
适用场景
- 入库单 / 发货单 / 盘点表的批量导入:仓管在电脑上填表,业务员用手机导进系统;
- 客户、供应商、物料主数据的初始化与增量维护;
- 现场盘点结果回传:离线填表,回办公室导入;
- 任何"甲方给一张 Excel,要求 App 能读"的项目。
主要能力
- 流式读取:
maxRows控制读取上限,超限返回truncated: true,不会静默截断; - 取值还原:共享字符串、内联字符串、富文本、公式缓存值、布尔、日期、数值浮点尾巴;
- 表头映射:字段定义带别名数组,
mapColumns返回每个字段命中第几列,缺列时列出缺失字段; - 逐行校验:必填、整数 / 数字 / 日期 / 布尔 / 枚举、最大长度、最小值 / 最大值、跨行唯一;
- 错误回执:
errorsToCsv生成带 BOM 的 CSV,Excel 双击不乱码; - 零三方依赖:手写 OOXML 解析 +
java.util.zip,不引 POI、不引 sheetjs,不与其它插件抢同名类。
快速上手
import { readWorkbook, importSheet, writeErrorReport } from '@/uni_modules/szhzy-xlsx-import'
// 1. 先看有哪些工作表(多表时让用户选)
const wb = readWorkbook({ path: '/sdcard/Android/data/<包名>/files/入库单.xlsx' })
// wb.sheets → [{ name: '入库明细', index: 0 }, { name: '说明', index: 1 }]
// 2. 读表 + 映射 + 校验,一次调用拿回全部结果
const res = importSheet({
path: '/sdcard/Android/data/<包名>/files/入库单.xlsx',
sheet: '入库明细',
headerRow: 1,
fields: [
{ key: 'code', label: '物料编码', aliases: ['料号', '物料号'], required: true, type: 'text', maxLength: 20, unique: true },
{ key: 'qty', label: '数量', aliases: ['入库数量'], required: true, type: 'int', min: 1 },
{ key: 'price', label: '单价', aliases: ['含税单价'], required: true, type: 'number', min: 0 },
{ key: 'date', label: '入库日期', aliases: ['到货日期'], required: true, type: 'date' }
]
})
// res.headers → ['物料编码', '物料名称', '数量', '单价', '入库日期', '备注']
// res.rows → 二维数组,已按"人看到的文本"还原
// res.rowNumbers → 每行对应的 Excel 真实行号
// res.mapping.indexes→ 每个字段命中的列下标,-1 表示未找到
// res.errors → [{ row: 5, key: 'qty', label: '数量', value: '一百二十', code: 'TYPE', message: '数量必须是整数' }]
// res.validCount / res.errorCount / res.truncated
// 3. 有错误就把回执导出来,直接发给填表人
if (res.errorCount > 0) {
const out = writeErrorReport({ errors: res.errors, prefix: '入库单导入错误', stamp: '20261027-0912' })
// out.path → 生成的文件路径
}
只要原始数据、不做映射校验时,importSheet 不传 fields 即可,返回的 rows 就是纯二维文本。
API
| 方法 | 说明 |
|---|---|
readWorkbook({ path }) |
读工作表清单:{ ok, sheets: [{ name, index }] } |
importSheet({ path, sheet?, headerRow?, maxRows?, fields?, previewRows? }) |
读表 + 映射 + 校验,统一信封 |
writeErrorReport({ errors, dir?, path?, prefix?, stamp? }) |
错误行写成 CSV 回执 |
getPrivateDir() |
应用外部私有目录(读写都不需要存储权限) |
getCodeText(code) / getVersion() / getDefaultMaxRows() |
错误码中文说明、版本号、默认读取上限 |
统一错误码:ARG_INVALID、ZIP_INVALID、PART_MISSING、XML_INVALID、SHEET_NOT_FOUND、HEADER_ROW_INVALID、FIELD_NOT_MATCHED、IO_FAILED。
校验错误码:REQUIRED、TYPE、LENGTH、RANGE、ENUM、DUPLICATE。
常见问题
支持 .xls 吗?
不支持。.xls 是 97-2003 的二进制格式,与 xlsx 完全两套结构。请让填表人用 Excel/WPS 另存为 .xlsx(2007 及以上),插件会在 .xls 上直接返回 ARG_INVALID,不会静默读出错数据。
公式单元格读到什么? 读 Excel 保存时写入的缓存值(也就是打开文件时看到的结果)。如果第三方工具生成的 xlsx 只写了公式没写缓存值,这里会是空——Excel 手工另存一次就会补上。
能读多大的表?
默认上限 5000 行(getDefaultMaxRows()),可通过 maxRows 调整。行数上限的作用是防止误选百万行的表把设备内存吃满;超过上限会返回 truncated: true,不会静默截断。
需要存储权限吗?
不需要。读取应用私有目录、应用外部私有目录(getPrivateDir())都不声明任何权限。读取其它位置的文件时,由调用方先用系统文件选择器取得授权,把路径交给插件。
购买前必读
- 仅支持 Android App(uni-app Vue3 / Vue2)。iOS、鸿蒙、小程序、H5 端不支持,代码里也没有对应实现。
- 需要 HBuilderX 3.99 及以上,Android 6.0 及以上。
- UTS 插件不在标准基座内,真机调试请使用自定义基座。
- 读取在调用线程执行。十万行级别的表建议先用小
maxRows做预览,确认无误再全量读取。 - 本插件只做"读 + 校验",不做文件选择、不做上传、不做数据库写入——这些请配合你现有的文件选择器与接口层使用。
验证状态(如实说明)
| 项目 | 状态 |
|---|---|
| UTS → Kotlin 编译 | 通过(HBuilderX 5.26,产物 index.kt 2120 行) |
| 核心逻辑测试 | 75 项全部通过(Node 真实执行,含 openpyxl 产出文件的往返验证、共享字符串/公式缓存/日期样式的合成包验证、1/2/3/7/61 字节切块流式一致性验证、3001 行大表、跳号行编号) |
| 真机运行验证 | 未执行。发布当晚 HBuilderX 命令行运行会话启动即退出(Stopped running),标准基座未切换到本工程,无法在真机上跑通读取链路 |
| 真机截图 | 未取得。市场截图为 H5 构建产物在浏览器中的真实渲染,页面已标注示例数据 |
也就是说:表格解析与校验逻辑是被真实测试覆盖的,Android 平台层的 zip 读取与文件流在真机上还没有跑过。
如果你在真机上遇到 ZIP_INVALID 或 IO_FAILED,请把文件与错误码反馈给作者,优先修。

收藏人数:
购买源码授权版(
试用
赞赏(0)
下载 13
赞赏 0
下载 12718207
赞赏 1958
赞赏
京公网安备:11010802035340号