更新记录

1.0.0(2026-10-27)

首个版本:内置 70+ 条常用 AI(GTIN/SSCC/批号/效期/生产包装日期/序列号/数量/GLN/净重毛重/金额/GRAI/GIAI/GSRN 等),支持带 FNC1、无分隔符、括号三种输入形态并自动清理 AIM 前缀;校验模 10 校验位(含 GTIN-8/12/13/14、SSCC-18、GLN-13)、GS1 日期世纪推断与闰年、数值型、长度越界、重复 AI,逐条产出具名 issue 并给出正确校验位;UDI-DI/UDI-PI 拆分;反向由字段生成元素串(变长自动补 GS、日期自动转、校验位自动补);效期判断与剩余天数自算序日不受时区影响;UTS→Kotlin 编译通过,126 项核心逻辑测试通过。


平台兼容性

uni-app

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

szhzy-gs1-barcode

把 GS1 条码内容(GS1-128 / GS1 DataMatrix / GS1 QR / DataBar 解出来的文本)按应用标识符(AI) 拆成结构化字段,并把 GTIN/SSCC/GLN 的校验位、日期合法性、长度、重复项一并校验。

给谁用:用 PDA 或扫码枪做仓库收货、产线追溯、医疗器械 UDI 的 uni-app(Vue3)Android 项目。

验证状态

项目 结果 说明
UTS → Kotlin 编译 通过 Project demo-gs1 compiled successfully.(HBuilderX 5.33,kotlin 级编译,非仅语法转写)
纯逻辑回归测试 通过 126 项,失败 0 项
真机运行验证 未执行 cli launch 编译通过后 Stopped running...,标准基座未切换到本工程,设备未能操作
真机截图 未取得 市场图来自 H5 渲染,非真机截图
iOS / 鸿蒙 未实现 平台声明已标不支持

编译期真实修掉的问题(每条都是 Kotlin 编译器报的,不是猜的):

  1. String.substring 在 Kotlin 侧只接受 Int,而 .length 与算术结果是 Number → 统一走内部 substr2/substr1(内部 .toInt());
  2. let valueEnd = s.length 被推断成 Int,后面赋 Number 报 Assignment type mismatch → 显式声明 let valueEnd: number = s.length;
  3. charCodeAt(i) 同样要 Int → s.charCodeAt(i.toInt())。

它不做什么

本插件不做图像识别。条码怎么扫出来的(系统扫码、uni.scanCode、HMS Scan Kit、PDA 广播) 不归它管,它只处理已经解出来的那串文本。这样定位的好处是:不占相机、不要权限、不吃安装包体积。

快速开始

import { parseBarcode, parseUdiCode, buildBarcode } from '@/uni_modules/szhzy-gs1-barcode'

// 1) 解析(传扫码拿到的字符串)
const r = parseBarcode({ code: scanText })
if (r.ok) {
  r.fields.gtin     // '06901234567892'
  r.fields.lot      // 'L2026A'
  r.fields.expiry   // '2026-12-31'
  r.fields.quantity // '120'
  r.readable        // '(01)06901234567892 (17)2026-12-31 (10)L2026A (30)120'
} else {
  r.code            // 'CHECK_DIGIT' / 'AI_UNKNOWN' / 'DATE_INVALID' ...
  r.issues          // ['(01) 校验位应为 2,实际是末位 3']
}

// 2) 医疗器械 UDI
const udi = parseUdiCode({ code: scanText })
udi.di        // UDI-DI
udi.diType    // 'GTIN' | 'GIAI'
udi.pi        // [{ ai: '17', title: '有效期', text: '2027-03-15' }, ...]

// 3) 反向生成(做标签、写二维码)
const b = buildBarcode({
  items: [
    { ai: '01', value: '0690123456789' },   // 少一位校验位会自动补,并记一条说明
    { ai: '17', value: '2026-12-31' },      // 日期自动转 YYMMDD
    { ai: '10', value: 'L2026A' }           // 变长字段后自动补 FNC1(0x1D)
  ]
})
b.elementString // '01069012345678921726123110L2026A'(末尾变长字段不补分隔符)

API

函数 说明
parseBarcode({ code }) 解析。返回 { ok, code, message, source, hasFnc1, readable, elements[], fields{}, issues[] }
parseUdiCode({ code }) UDI 拆分。返回 { ok, code, message, diType, di, pi[], readable, fields, issues }
buildBarcode({ items }) 由字段生成。返回 { ok, code, message, elementString, readable, issues }
checkCode({ value }) 校验位计算/校验。返回 { ok, length, checkDigit, valid, fixed }
convertDate({ value, to }) yyyy-MM-dd ↔ YYMMDD(to 取 gs1 或 text)
checkExpiry({ expiry, today, warnDays }) { expired, days, level: expired/warning/ok/unknown }
listAiTable() 内置 AI 表全集,用于做"支持字段"页
getSeparator() / getCodeText(code) / getVersion() 分隔符常量 / 错误码中文 / 版本

所有函数返回统一信封 { ok, code, message, ... },不抛异常;code 取值见下表。

支持的输入形态

形态 例子 说明
带 FNC1 0106901234567892 + 17 + 261231 + 10 + L2026A + \x1D + 30 + 120 原生扫描串,变长字段以 GS 结尾
无分隔符 01069012345678921726123110L2026A 部分解码器会吃掉 GS,靠 AI 定长规则推算
括号格式 (01)06901234567892(17)261231(10)L2026A 人眼可见的标签文本
带 AIM 前缀 ]C10106901234567892… 自动清掉 ]C1 / ]Q3

错误码

code 含义 建议处理
OK 成功 —
EMPTY 输入为空 检查扫码回调是否拿到内容
AI_UNKNOWN 含未收录的 AI 核对码制;需要时联系作者补 AI 表
VALUE_LENGTH 值长度不符 通常是码被截断或拼接口径不对
CHECK_DIGIT 校验位不通过 码磨损、重复拼接,或根本不是 GS1 码
DATE_INVALID 日期不是合法年月日 拒绝入库,让人工核对
NOT_NUMERIC 该是数字的位置有字母 码制选错(例如把普通 Code128 当 GS1-128 扫)
DUPLICATE_AI 同一 AI 出现两次 常见于扫码枪双触发,去重即可
PAREN_UNBALANCED 括号格式不闭合 标签文本被破坏了
NO_DEVICE_ID 不是 UDI 载体 缺少 (01) 或 (8004),按普通条码处理

内置 AI(节选)

标识类:00 SSCC、01 GTIN、02 内含 GTIN、10 批号、11 生产日期、12 到期日期、 13 包装日期、15 最佳食用日期、16 销售截止、17 有效期、20 产品变体、21 序列号、22 HIBCC。

追溯与单据:240 附加产品标识、241 客户物料号、242 定制加工号、250 二级序列号、400 客户订单号。

位置类:410–417 各类 GLN、420 邮编、421 行政区划、422 原产国、423–426 加工国。

资产类:7001 NSN、8003 GRAI、8004 GIAI、8006 ITIP、8010 CPID、8013 GMN、8017/8018 GSRN。

计量类(族,第 4 位是小数位数):310x 净重 kg、320x 净重 lb、330x 毛重 kg、340x 毛重 lb、 350x 面积、360x 体积、390x/392x/393x 金额。

90–99 为厂商内部 AI;完整清单用 listAiTable() 取。

几个容易踩的坑(本插件已处理)

  • FNC1 会被吃掉:不少 PDA 广播或 uni.scanCode 返回的串里 0x1D 丢了,靠"变长 AI 一直取到结尾"猜会错位。 插件按 AI 定长表推算,只有最后一个变长字段才吃到结尾。
  • GS1 日期的世纪:YY 不是直接 20YY。按规范 00–49 → 20xx,50–99 → 19xx,否则 1999 年的效期会被算成 2099。
  • 校验位权重:从最右位起 3/1 交替,不是从最左位。
  • 同一串里 GTIN 和 SSCC 都带校验位,但 GLN 是 13 位、GTIN 是 14 位、SSCC 是 18 位,长度不能混用。
  • 310x 的值没有小数点,3103 + 001250 是 1.250 kg;直接当整数会错 1000 倍。

演示工程

demo-gs1/ 是"仓库收货 + UDI 追溯"演示页面:三个示例码(整箱收货 / UDI 器械 / 校验位错), 点一下就出字段、问题和 UDI 拆分。真机运行需自定义基座(标准基座不含第三方 UTS 插件)。

授权

普通授权 / 源码授权双档,见 license.md。插件不包含任何第三方库。

隐私、权限声明

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

无。不涉及相机、存储、定位、网络等任何系统权限。

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

插件不采集、不上传任何数据,不访问网络,不读写文件。输入是调用方传入的字符串,输出是解析结果对象,全部在本机内存内完成。

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

无

暂无用户评论。