apa7 发表于 2023-10-26 11:16

[原创工具] 【永不联网!二维码】本地生成二维码工具

本帖最后由 apa7 于 2023-10-30 17:07 编辑

看到这个哥们分享的生成二维码.exe工具https://www.52pojie.cn/thread-1736287-1-2.html
我也写个HTML的,比较轻量透明,仅供分享学习。

介绍一下功能:
1)【100%保护隐私】永不联网,本地二维码生成器|PC电脑->手机(文本/网址)。
2)点击图片,可保存二维码到本地。
3)轻量化、透明
4)HTML,windows/unux都能运行

-----------------------------
更新(20231030):
fix: 看到有小伙伴说联网问题,我已经把js、css文件放到本地了

hgf7610 发表于 2023-10-26 14:26

试了下不知道怎么用{:1_907:}

邂逅灬偶遇 发表于 2023-10-26 22:35

本帖最后由 邂逅灬偶遇 于 2023-10-26 22:37 编辑

尝试修改成在不联网下可使用,添加使用说明。
<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8">
    <title>本地生成二维码</title>
    <script>
      /*! QRious v4.0.2 | (C) 2017 Alasdair Mercer | GPL v3 License
      Based on jsqrencode | (C) 2010 tz@execpc.com | GPL v3 License
      */
      !function (t, e) { "object" == typeof exports && "undefined" != typeof module ? module.exports = e() : "function" == typeof define && define.amd ? define(e) : t.QRious = e() }(this, function () { "use strict"; function t(t, e) { var n; return "function" == typeof Object.create ? n = Object.create(t) : (s.prototype = t, n = new s, s.prototype = null), e && i(!0, n, e), n } function e(e, n, s, r) { var o = this; return "string" != typeof e && (r = s, s = n, n = e, e = null), "function" != typeof n && (r = s, s = n, n = function () { return o.apply(this, arguments) }), i(!1, n, o, r), n.prototype = t(o.prototype, s), n.prototype.constructor = n, n.class_ = e || o.class_, n.super_ = o, n } function i(t, e, i) { for (var n, s, a = 0, h = (i = o.call(arguments, 2)).length; a < h; a++) { s = i; for (n in s) t && !r.call(s, n) || (e = s) } } function n() { } var s = function () { }, r = Object.prototype.hasOwnProperty, o = Array.prototype.slice, a = e; n.class_ = "Nevis", n.super_ = Object, n.extend = a; var h = n, f = h.extend(function (t, e, i) { this.qrious = t, this.element = e, this.element.qrious = t, this.enabled = Boolean(i) }, { draw: function (t) { }, getElement: function () { return this.enabled || (this.enabled = !0, this.render()), this.element }, getModuleSize: function (t) { var e = this.qrious, i = e.padding || 0, n = Math.floor((e.size - 2 * i) / t.width); return Math.max(1, n) }, getOffset: function (t) { var e = this.qrious, i = e.padding; if (null != i) return i; var n = this.getModuleSize(t), s = Math.floor((e.size - n * t.width) / 2); return Math.max(0, s) }, render: function (t) { this.enabled && (this.resize(), this.reset(), this.draw(t)) }, reset: function () { }, resize: function () { } }), c = f.extend({ draw: function (t) { var e, i, n = this.qrious, s = this.getModuleSize(t), r = this.getOffset(t), o = this.element.getContext("2d"); for (o.fillStyle = n.foreground, o.globalAlpha = n.foregroundAlpha, e = 0; e < t.width; e++)for (i = 0; i < t.width; i++)t.buffer && o.fillRect(s * e + r, s * i + r, s, s) }, reset: function () { var t = this.qrious, e = this.element.getContext("2d"), i = t.size; e.lineWidth = 1, e.clearRect(0, 0, i, i), e.fillStyle = t.background, e.globalAlpha = t.backgroundAlpha, e.fillRect(0, 0, i, i) }, resize: function () { var t = this.element; t.width = t.height = this.qrious.size } }), u = h.extend(null, { BLOCK: }), l = h.extend(null, { BLOCKS: , FINAL_FORMAT: , LEVELS: { L: 1, M: 2, Q: 3, H: 4 } }), _ = h.extend(null, { EXPONENT: , LOG: }), d = h.extend(null, { BLOCK: }), v = h.extend(function (t) { var e, i, n, s, r, o = t.value.length; for (this._badness = [], this._level = l.LEVELS, this._polynomial = [], this._value = t.value, this._version = 0, this._stringBuffer = []; this._version < 40 && (this._version++, n = 4 * (this._level - 1) + 16 * (this._version - 1), s = l.BLOCKS, r = l.BLOCKS, e = l.BLOCKS, i = l.BLOCKS, n = e * (s + r) + r - 3 + (this._version <= 9), !(o <= n));); this._dataBlock = e, this._eccBlock = i, this._neccBlock1 = s, this._neccBlock2 = r; var a = this.width = 17 + 4 * this._version; this.buffer = v._createArray(a * a), this._ecc = v._createArray(e + (e + i) * (s + r) + r), this._mask = v._createArray((a * (a + 1) + 1) / 2), this._insertFinders(), this._insertAlignments(), this.buffer = 1, this._insertTimingGap(), this._reverseMask(), this._insertTimingRowAndColumn(), this._insertVersion(), this._syncMask(), this._convertBitStream(o), this._calculatePolynomial(), this._appendEccToData(), this._interleaveBlocks(), this._pack(), this._finish() }, { _addAlignment: function (t, e) { var i, n = this.buffer, s = this.width; for (n = 1, i = -2; i < 2; i++)n = 1, n = 1, n = 1, n = 1; for (i = 0; i < 2; i++)this._setMask(t - 1, e + i), this._setMask(t + 1, e - i), this._setMask(t - i, e - 1), this._setMask(t + i, e + 1) }, _appendData: function (t, e, i, n) { var s, r, o, a = this._polynomial, h = this._stringBuffer; for (r = 0; r < n; r++)h = 0; for (r = 0; r < e; r++) { if (255 !== (s = _.LOG ^ h])) for (o = 1; o < n; o++)h = h ^ _.EXPONENT)]; else for (o = i; o < i + n; o++)h = h; h = 255 === s ? 0 : _.EXPONENT)] } }, _appendEccToData: function () { var t, e = 0, i = this._dataBlock, n = this._calculateMaxLength(), s = this._eccBlock; for (t = 0; t < this._neccBlock1; t++)this._appendData(e, i, n, s), e += i, n += s; for (t = 0; t < this._neccBlock2; t++)this._appendData(e, i + 1, n, s), e += i + 1, n += s }, _applyMask: function (t) { var e, i, n, s, r = this.buffer, o = this.width; switch (t) { case 0: for (s = 0; s < o; s++)for (n = 0; n < o; n++)n + s & 1 || this._isMasked(n, s) || (r ^= 1); break; case 1: for (s = 0; s < o; s++)for (n = 0; n < o; n++)1 & s || this._isMasked(n, s) || (r ^= 1); break; case 2: for (s = 0; s < o; s++)for (e = 0, n = 0; n < o; n++, e++)3 === e && (e = 0), e || this._isMasked(n, s) || (r ^= 1); break; case 3: for (i = 0, s = 0; s < o; s++, i++)for (3 === i && (i = 0), e = i, n = 0; n < o; n++, e++)3 === e && (e = 0), e || this._isMasked(n, s) || (r ^= 1); break; case 4: for (s = 0; s < o; s++)for (e = 0, i = s >> 1 & 1, n = 0; n < o; n++, e++)3 === e && (e = 0, i = !i), i || this._isMasked(n, s) || (r ^= 1); break; case 5: for (i = 0, s = 0; s < o; s++, i++)for (3 === i && (i = 0), e = 0, n = 0; n < o; n++, e++)3 === e && (e = 0), (n & s & 1) + !(!e | !i) || this._isMasked(n, s) || (r ^= 1); break; case 6: for (i = 0, s = 0; s < o; s++, i++)for (3 === i && (i = 0), e = 0, n = 0; n < o; n++, e++)3 === e && (e = 0), (n & s & 1) + (e && e === i) & 1 || this._isMasked(n, s) || (r ^= 1); break; case 7: for (i = 0, s = 0; s < o; s++, i++)for (3 === i && (i = 0), e = 0, n = 0; n < o; n++, e++)3 === e && (e = 0), (e && e === i) + (n + s & 1) & 1 || this._isMasked(n, s) || (r ^= 1) } }, _calculateMaxLength: function () { return this._dataBlock * (this._neccBlock1 + this._neccBlock2) + this._neccBlock2 }, _calculatePolynomial: function () { var t, e, i = this._eccBlock, n = this._polynomial; for (n = 1, t = 0; t < i; t++) { for (n = 1, e = t; e > 0; e--)n = n ? n ^ _.EXPONENT] + t)] : n; n = _.EXPONENT] + t)] } for (t = 0; t <= i; t++)n = _.LOG] }, _checkBadness: function () { var t, e, i, n, s, r = 0, o = this._badness, a = this.buffer, h = this.width; for (s = 0; s < h - 1; s++)for (n = 0; n < h - 1; n++)(a && a && a && a || !(a || a || a || a)) && (r += v.N2); var f = 0; for (s = 0; s < h; s++) { for (i = 0, o = 0, t = 0, n = 0; n < h; n++)t === (e = a) ? o++ : o[++i] = 1, f += (t = e) ? 1 : -1; r += this._getBadness(i) } f < 0 && (f = -f); var c = 0, u = f; for (u += u << 2, u <<= 1; u > h * h;)u -= h * h, c++; for (r += c * v.N4, n = 0; n < h; n++) { for (i = 0, o = 0, t = 0, s = 0; s < h; s++)t === (e = a) ? o++ : o[++i] = 1, t = e; r += this._getBadness(i) } return r }, _convertBitStream: function (t) { var e, i, n = this._ecc, s = this._version; for (i = 0; i < t; i++)n = this._value.charCodeAt(i); var r = this._stringBuffer = n.slice(), o = this._calculateMaxLength(); t >= o - 2 && (t = o - 2, s > 9 && t--); var a = t; if (s > 9) { for (r = 0, r = 0; a--;)e = r, r |= 255 & e << 4, r = e >> 4; r |= 255 & t << 4, r = t >> 4, r = 64 | t >> 12 } else { for (r = 0, r = 0; a--;)e = r, r |= 255 & e << 4, r = e >> 4; r |= 255 & t << 4, r = 64 | t >> 4 } for (a = t + 3 - (s < 10); a < o;)r = 236, r = 17 }, _getBadness: function (t) { var e, i = 0, n = this._badness; for (e = 0; e <= t; e++)n >= 5 && (i += v.N1 + n - 5); for (e = 3; e < t - 1; e += 2)n === n && n === n && n === n && 3 * n === n && (0 === n || e + 3 > t || 3 * n >= 4 * n || 3 * n >= 4 * n) && (i += v.N3); return i }, _finish: function () { this._stringBuffer = this.buffer.slice(); var t, e, i = 0, n = 3e4; for (e = 0; e < 8 && (this._applyMask(e), (t = this._checkBadness()) < n && (n = t, i = e), 7 !== i); e++)this.buffer = this._stringBuffer.slice(); i !== e && this._applyMask(i), n = l.FINAL_FORMAT; var s = this.buffer, r = this.width; for (e = 0; e < 8; e++, n >>= 1)1 & n && (s = 1, e < 6 ? s = 1 : s = 1); for (e = 0; e < 7; e++, n >>= 1)1 & n && (s = 1, e ? s = 1 : s = 1) }, _interleaveBlocks: function () { var t, e, i = this._dataBlock, n = this._ecc, s = this._eccBlock, r = 0, o = this._calculateMaxLength(), a = this._neccBlock1, h = this._neccBlock2, f = this._stringBuffer; for (t = 0; t < i; t++) { for (e = 0; e < a; e++)n = f; for (e = 0; e < h; e++)n = f } for (e = 0; e < h; e++)n = f; for (t = 0; t < s; t++)for (e = 0; e < a + h; e++)n = f; this._stringBuffer = n }, _insertAlignments: function () { var t, e, i, n = this._version, s = this.width; if (n > 1) for (t = u.BLOCK, i = s - 7; ;) { for (e = s - 7; e > t - 3 && (this._addAlignment(e, i), !(e < t));)e -= t; if (i <= t + 9) break; i -= t, this._addAlignment(6, i), this._addAlignment(i, 6) } }, _insertFinders: function () { var t, e, i, n, s = this.buffer, r = this.width; for (t = 0; t < 3; t++) { for (e = 0, n = 0, 1 === t && (e = r - 7), 2 === t && (n = r - 7), s = 1, i = 0; i < 6; i++)s = 1, s = 1, s = 1, s = 1; for (i = 1; i < 5; i++)this._setMask(n + i, e + 1), this._setMask(n + 1, e + i + 1), this._setMask(n + 5, e + i), this._setMask(n + i + 1, e + 5); for (i = 2; i < 4; i++)s = 1, s = 1, s = 1, s = 1 } }, _insertTimingGap: function () { var t, e, i = this.width; for (e = 0; e < 7; e++)this._setMask(7, e), this._setMask(i - 8, e), this._setMask(7, e + i - 7); for (t = 0; t < 8; t++)this._setMask(t, 7), this._setMask(t + i - 8, 7), this._setMask(t, i - 8) }, _insertTimingRowAndColumn: function () { var t, e = this.buffer, i = this.width; for (t = 0; t < i - 14; t++)1 & t ? (this._setMask(8 + t, 6), this._setMask(6, 8 + t)) : (e = 1, e = 1) }, _insertVersion: function () { var t, e, i, n, s = this.buffer, r = this._version, o = this.width; if (r > 6) for (t = d.BLOCK, e = 17, i = 0; i < 6; i++)for (n = 0; n < 3; n++, e--)1 & (e > 11 ? r >> e - 12 : t >> e) ? (s = 1, s = 1) : (this._setMask(5 - i, 2 - n + o - 11), this._setMask(2 - n + o - 11, 5 - i)) }, _isMasked: function (t, e) { var i = v._getMaskBit(t, e); return 1 === this._mask }, _pack: function () { var t, e, i, n = 1, s = 1, r = this.width, o = r - 1, a = r - 1, h = (this._dataBlock + this._eccBlock) * (this._neccBlock1 + this._neccBlock2) + this._neccBlock2; for (e = 0; e < h; e++)for (t = this._stringBuffer, i = 0; i < 8; i++, t <<= 1) { 128 & t && (this.buffer = 1); do { s ? o-- : (o++, n ? 0 !== a ? a-- : (n = !n, 6 === (o -= 2) && (o--, a = 9)) : a !== r - 1 ? a++ : (n = !n, 6 === (o -= 2) && (o--, a -= 8))), s = !s } while (this._isMasked(o, a)) } }, _reverseMask: function () { var t, e, i = this.width; for (t = 0; t < 9; t++)this._setMask(t, 8); for (t = 0; t < 8; t++)this._setMask(t + i - 8, 8), this._setMask(8, t); for (e = 0; e < 7; e++)this._setMask(8, e + i - 7) }, _setMask: function (t, e) { var i = v._getMaskBit(t, e); this._mask = 1 }, _syncMask: function () { var t, e, i = this.width; for (e = 0; e < i; e++)for (t = 0; t <= e; t++)this.buffer && this._setMask(t, e) } }, { _createArray: function (t) { var e, i = []; for (e = 0; e < t; e++)i = 0; return i }, _getMaskBit: function (t, e) { var i; return t > e && (i = t, t = e, e = i), i = e, i += e * e, i >>= 1, i += t }, _modN: function (t) { for (; t >= 255;)t = ((t -= 255) >> 8) + (255 & t); return t }, N1: 3, N2: 3, N3: 40, N4: 10 }), p = v, m = f.extend({ draw: function () { this.element.src = this.qrious.toDataURL() }, reset: function () { this.element.src = "" }, resize: function () { var t = this.element; t.width = t.height = this.qrious.size } }), g = h.extend(function (t, e, i, n) { this.name = t, this.modifiable = Boolean(e), this.defaultValue = i, this._valueTransformer = n }, { transform: function (t) { var e = this._valueTransformer; return "function" == typeof e ? e(t, this) : t } }), k = h.extend(null, { abs: function (t) { return null != t ? Math.abs(t) : null }, hasOwn: function (t, e) { return Object.prototype.hasOwnProperty.call(t, e) }, noop: function () { }, toUpperCase: function (t) { return null != t ? t.toUpperCase() : null } }), w = h.extend(function (t) { this.options = {}, t.forEach(function (t) { this.options = t }, this) }, { exists: function (t) { return null != this.options }, get: function (t, e) { return w._get(this.options, e) }, getAll: function (t) { var e, i = this.options, n = {}; for (e in i) k.hasOwn(i, e) && (n = w._get(i, t)); return n }, init: function (t, e, i) { "function" != typeof i && (i = k.noop); var n, s; for (n in this.options) k.hasOwn(this.options, n) && (s = this.options, w._set(s, s.defaultValue, e), w._createAccessor(s, e, i)); this._setAll(t, e, !0) }, set: function (t, e, i) { return this._set(t, e, i) }, setAll: function (t, e) { return this._setAll(t, e) }, _set: function (t, e, i, n) { var s = this.options; if (!s) throw new Error("Invalid option: " + t); if (!s.modifiable && !n) throw new Error("Option cannot be modified: " + t); return w._set(s, e, i) }, _setAll: function (t, e, i) { if (!t) return !1; var n, s = !1; for (n in t) k.hasOwn(t, n) && this._set(n, t, e, i) && (s = !0); return s } }, { _createAccessor: function (t, e, i) { var n = { get: function () { return w._get(t, e) } }; t.modifiable && (n.set = function (n) { w._set(t, n, e) && i(n, t) }), Object.defineProperty(e, t.name, n) }, _get: function (t, e) { return e["_" + t.name] }, _set: function (t, e, i) { var n = "_" + t.name, s = i, r = t.transform(null != e ? e : t.defaultValue); return i = r, r !== s } }), M = w, b = h.extend(function () { this._services = {} }, { getService: function (t) { var e = this._services; if (!e) throw new Error("Service is not being managed with name: " + t); return e }, setService: function (t, e) { if (this._services) throw new Error("Service is already managed with name: " + t); e && (this._services = e) } }), B = new M(), y = new b, O = h.extend(function (t) { B.init(t, this, this.update.bind(this)); var e = B.get("element", this), i = y.getService("element"), n = e && i.isCanvas(e) ? e : i.createCanvas(), s = e && i.isImage(e) ? e : i.createImage(); this._canvasRenderer = new c(this, n, !0), this._imageRenderer = new m(this, s, s === e), this.update() }, { get: function () { return B.getAll(this) }, set: function (t) { B.setAll(t, this) && this.update() }, toDataURL: function (t) { return this.canvas.toDataURL(t || this.mime) }, update: function () { var t = new p({ level: this.level, value: this.value }); this._canvasRenderer.render(t), this._imageRenderer.render(t) } }, { use: function (t) { y.setService(t.getName(), t) } }); Object.defineProperties(O.prototype, { canvas: { get: function () { return this._canvasRenderer.getElement() } }, image: { get: function () { return this._imageRenderer.getElement() } } }); var A = O, L = h.extend({ getName: function () { } }).extend({ createCanvas: function () { }, createImage: function () { }, getName: function () { return "element" }, isCanvas: function (t) { }, isImage: function (t) { } }).extend({ createCanvas: function () { return document.createElement("canvas") }, createImage: function () { return document.createElement("img") }, isCanvas: function (t) { return t instanceof HTMLCanvasElement }, isImage: function (t) { return t instanceof HTMLImageElement } }); return A.use(new L), A });

    </script>
    <style>
      body {
            background-color: #f8f9fa;
            font-family: "Arial", sans-serif;
            color: #333;
      }

      .container {
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            height: 100vh;
            padding: 20px;
      }

      .form-group {
            margin-bottom: 20px;
      }

      .form-control {
            width: 100%;
            max-width: 400px;
            height: 40px;
            border-radius: 20px;
            border: none;
            padding: 10px;
            box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.1);
            font-size: 16px;
            outline: none;
      }

      .btn {
            background-color: #007bff;
            color: white;
            border: none;
            border-radius: 20px;
            padding: 10px 20px;
            font-size: 16px;
            cursor: pointer;
            box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.1);
      }

      .btn:hover {
            background-color: #0069d9;
      }

      .qrcode-container {
            margin-top: 40px;
      }

      #qrcode {
            width: 400px;
            height: 400px;
      }

      h2 {
            font-size: 24px;
            margin-bottom: 10px;
      }

      .instructions {
            font-size: 16px;
            color: #007bff;
            /* 更醒目的颜色 */
            margin-bottom: 20px;
            line-height: 1.5;
            text-align: justify;
            text-justify: inter-word;
            font-weight: bold;
            /* 加粗文本 */
      }

      .instructions:before {
            content: "\2192";
            /* 添加右箭头符号作为提示图标 */
            margin-right: 10px;
            color: #007bff;
            font-size: 24px;
      }

      .instructions:hover {
            text-decoration: underline;
            /* 鼠标悬停时添加下划线 */
      }

      #history {
            display: flex;
            flex-wrap: wrap;
            justify-content: center;
      }

      .qrcode-history {
            margin: 10px;
            text-align: center;
      }

      .btn {
            background-color: #007bff;
            color: white;
            border: none;
            border-radius: 20px;
            padding: 10px 20px;
            font-size: 16px;
            cursor: pointer;
            box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.1);
            transition: background-color 0.3s ease;
            /* 添加过渡效果 */
      }

      .btn:hover {
            background-color: #0069d9;
      }

      .qrcode-history {
            margin: 10px;
            text-align: center;
            background-color: #fff;
            border-radius: 10px;
            padding: 10px;
            box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.2);
      }

      .qrcode-history img {
            max-width: 100%;
            height: auto;
      }

      .qrcode-history p {
            margin-top: 10px;
            font-size: 14px;
            color: #555;
      }

      .form-control::placeholder {
            text-align: center;
      }
    </style>
</head>

<body>
    <div class="container">
      <h2>生成二维码</h2>
      <p class="instructions">请在文本框中输入文本或网址(网址格式应以http://或https://开头),然后单击“生成二维码”按钮。<br>
            将鼠标悬停在二维码上方,二维码下方将显示二维码内容。单击鼠标右键可复制二维码,或将其另存为图片以进行下载保存。</p>
      <div class="form-group">
            <input type="text" class="form-control" id="textInput" placeholder="输入文本或网址">
      </div>
      <div class="text-center">
            <button class="btn btn-primary">生成二维码</button>
            <button class="btn btn-danger">清空</button>
      </div>
      <div id="history">
            <!-- 历史记录将在这里显示 -->
      </div>
    </div>
    <script>
      var historyCount = 0;

      function generateQRCode() {
            var text = document.getElementById("textInput").value;
            var canvas = document.getElementById("qrcode");
            var qr = new QRious({
                element: canvas,
                value: text,
                size: 400
            });

            // 将生成的二维码添加到历史记录
            addToHistory(qr.toDataURL("image/png"));
      }

      function addToHistory(qrImage) {
            var historyDiv = document.getElementById("history");
            var qrHistoryDiv = document.createElement("div");
            qrHistoryDiv.classList.add("qrcode-history");

            var img = document.createElement("img");
            img.src = qrImage;
            qrHistoryDiv.appendChild(img);

            var content = document.createElement("p");
            content.textContent = document.getElementById("textInput").value;
            content.style.display = "none"; // 初始时隐藏内容
            qrHistoryDiv.appendChild(content);

            // 添加鼠标悬停事件处理程序
            qrHistoryDiv.addEventListener("mouseover", function () {
                content.style.display = "block";
            });

            // 添加鼠标离开事件处理程序
            qrHistoryDiv.addEventListener("mouseout", function () {
                content.style.display = "none";
            });

            historyDiv.appendChild(qrHistoryDiv);

            historyCount++;
      }

      function clearAll() {
            document.getElementById("textInput").value = "";
            document.getElementById("history").innerHTML = "";
            historyCount = 0;
      }
    </script>
</body>

</html>

xk1539287520 发表于 2023-10-26 13:39

能不能做个多样化的带颜色的那种

Patches 发表于 2023-10-26 13:47

感谢楼主分享 不过现在流行那种艺术二维码 有机会可以试试做那种二维码生成工具

aqdy2021 发表于 2023-10-26 14:05

感谢分享。

PaulJob 发表于 2023-10-26 14:17

感谢分享,马上用到内网上去

rhci 发表于 2023-10-26 14:18

看见HTML,我就进来了,感谢分享。

vipzzc 发表于 2023-10-26 14:45

感谢分享啊

wushishen 发表于 2023-10-26 15:17

感谢分享啊~

yyb1813 发表于 2023-10-26 15:53

页: [1] 2 3 4 5
查看完整版本: [原创工具] 【永不联网!二维码】本地生成二维码工具