fix: 扫码取码兼容带域名的完整 URL 二维码

二维码内容有两种可能,旧逻辑只做「去掉非字母数字后截前 16 位」,扫到带域名
的 URL 时会把 "https"、主机名一起当成 SN 的前半段,截出来是个完全不存在的
号,永远提示「未找到该产品」。

- 先把 "协议://主机名" 整段剥掉,否则域名会被当成候选 SN
  (如 trackbackirisrscn 这类 17 位串,恰好能通过长度校验)
- 在剩余内容里找长度 >= 8 的连续字母数字串,取最长的一段;
  等长时取靠后的 —— URL 里 SN 通常在路径末尾
This commit is contained in:
2026-09-15 15:52:02 +08:00
parent a7d1c53b1f
commit 5cd08b551a

View File

@ -75,13 +75,44 @@ export default {
},
handleSearch() { this.doQuery(this.serialNumber.trim()); },
// 📷 从扫码原始文本中提取设备身份证(SN)
// 二维码内容有两种可能,必须都兼容:
// ① 裸 SN → ABC1234567890DEF
// ② 带域名的完整 URL → https://track.iris-rs.cn/sn/ABC1234567890DEF?from=label
// 旧逻辑只是「去掉非字母数字后截前 16 位」,扫到 ② 时会把 "https"、域名
// 一起当成 SN 的前半段,截出来是个完全不存在的号,永远提示"未找到该产品"。
extractSerial(raw) {
const text = String(raw || "").trim();
if (!text) return "";
// 关键一步:先把 "协议://主机名" 整段剥掉,否则域名会被当成候选 SN
// (如 trackbackirisrscn 这种 17 位串,恰好能通过长度校验)。
let body = text;
const origin = text.match(/^[a-z][a-z0-9+.-]*:\/\/[^/?#]+/i);
if (origin) body = text.slice(origin[0].length);
// 在剩余内容里找长度 >= 8 的连续字母数字串(身份证至少 8 位)。
// 取最长的一段;等长时取靠后的 —— URL 里 SN 通常在路径末尾。
const runs = body.match(/[a-zA-Z0-9]{8,}/g) || [];
if (!runs.length) return "";
let best = runs[0];
for (const run of runs) {
if (run.length >= best.length) best = run;
}
return best.slice(0, 16);
},
// 📷 全屏相机扫码
handleScanCamera() {
uni.scanCode({
onlyFromCamera: true,
scanType: ["qrCode", "barCode"],
success: (res) => {
const sn = (res.result || "").replace(/[^a-zA-Z0-9]/g, "").slice(0, 16);
const sn = this.extractSerial(res.result);
if (!sn) {
uni.showToast({ title: "无法识别二维码内容,请确认扫的是设备标签", icon: "none", duration: 2500 });
return;
}
this.doQuery(sn);
},
fail: (err) => {