批量优化功能

This commit is contained in:
2026-09-30 00:57:36 +08:00
parent ca4220f92c
commit e3db229f41
43 changed files with 2959 additions and 207 deletions
+132 -2
View File
@@ -324,6 +324,26 @@
.back { text-align: center; margin-top: 22px; font-size: 13px; }
/* 微信扫码登录 */
.scan-flex { display: flex; justify-content: center; }
.scan-qr {
width: 180px; height: 180px; flex: 0 0 180px;
border: 1px solid var(--border); border-radius: 10px;
display: flex; align-items: center; justify-content: center;
overflow: hidden; background: #fff;
}
.scan-qr .qr-img { width: 100%; height: 100%; object-fit: contain; }
.scan-qr .qr-mask {
display: flex; flex-direction: column; align-items: center; gap: 8px;
font-size: 12px; color: var(--muted); text-align: center; padding: 8px;
white-space: pre-line;
}
.scan-btn {
border: none; background: var(--primary); color: #fff;
border-radius: 8px; padding: 6px 16px; font-size: 12px; cursor: pointer;
}
.scan-right { display: none; }
.foot-tip {
margin-top: 26px;
padding-top: 18px;
@@ -485,6 +505,30 @@
<div class="divider"><span>其他登录方式</span></div>
<div class="third-list" id="thirdList"></div>
</div>
<!-- 微信扫码登录(未认证公众号:服务号二维码 + 登录码,公众号内确认后自动登录) -->
<div class="divider"><span>其他登录方式</span></div>
<div class="third-list" style="justify-content:flex-start">
<button class="third-btn" type="button" id="wechatScanEntry" onclick="showWechatScan()">
<svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
<path d="M4 4h16v12H8l-4 4z"/><path d="M8.5 9.5h.01M12 9.5h.01M15.5 9.5h.01"/>
</svg>
微信登录
</button>
</div>
<div id="wechatScanArea" style="display:none; margin-top:18px;">
<div class="scan-flex">
<div class="scan-qr">
<img id="scanQrImg" class="qr-img" alt="微信扫码登录" style="display:none" />
<div class="qr-mask" id="scanQrMask">
<span id="scanQrMaskText">正在获取二维码…</span>
<button class="scan-btn" onclick="restartWechatScan()" style="display:none" id="scanQrRefreshBtn">刷新</button>
</div>
</div>
</div>
<div class="back"><a class="link" onclick="hideWechatScan()">返回账号密码登录</a></div>
</div>
{{end}}
<div class="foot-tip">
@@ -617,9 +661,11 @@
.then(function (r) { return r.json(); })
.then(function (res) {
var list = (res && res.data) || [];
var enabled = list.filter(function (i) { return i.enabled; });
if (!enabled.length) return;
// 微信走「公众号扫码登录」独立入口,第三方列表里不再重复展示
var enabled = list.filter(function (i) { return i.enabled && i.provider !== 'wechat'; });
var box = document.getElementById('thirdList');
box.innerHTML = ''; // 防止重复渲染
if (!enabled.length) return;
enabled.forEach(function (item) {
var btn = document.createElement('button');
btn.className = 'third-btn';
@@ -793,6 +839,90 @@
window.location.href = '/auth/login?client_id=' + encodeURIComponent(CLIENT_ID) + '&redirect=' + encodeURIComponent(REDIRECT);
});
}
// ==================== 微信扫码登录(未认证公众号:服务号二维码 + 登录码) ====================
var scanScene = '';
var scanExpireAt = 0;
var scanPollTimer = null;
function showWechatScan() {
hideError();
document.getElementById('loginForm').style.display = 'none';
document.getElementById('thirdArea').style.display = 'none';
document.getElementById('wechatScanEntry').parentElement.style.display = 'none';
document.getElementById('wechatScanArea').style.display = 'block';
restartWechatScan();
}
function hideWechatScan() {
stopWechatScan();
document.getElementById('wechatScanArea').style.display = 'none';
document.getElementById('loginForm').style.display = 'block';
document.getElementById('wechatScanEntry').parentElement.style.display = 'flex';
loadThirdProviders();
}
function stopWechatScan() {
if (scanPollTimer) { clearInterval(scanPollTimer); scanPollTimer = null; }
}
function setScanQrMask(text, showRefresh) {
var img = document.getElementById('scanQrImg');
var mask = document.getElementById('scanQrMask');
img.style.display = 'none';
mask.style.display = 'flex';
document.getElementById('scanQrMaskText').textContent = text || '';
document.getElementById('scanQrRefreshBtn').style.display = showRefresh ? 'block' : 'none';
}
function restartWechatScan() {
stopWechatScan();
setScanQrMask('获取中…', false);
fetch('/auth/wechat/scan/start', { method: 'POST' })
.then(function (r) { return r.json(); })
.then(function (res) {
if (res.code !== 200) {
setScanQrMask('获取失败', true);
return;
}
var d = res.data || {};
scanScene = d.scene || '';
var qr = d.qrcode_url || d.follow_qrcode || '';
if (qr) {
var img = document.getElementById('scanQrImg');
img.src = qr;
img.style.display = 'block';
document.getElementById('scanQrMask').style.display = 'none';
} else {
setScanQrMask('暂无二维码', true);
}
// 回退原因只写控制台,不在页面展示
if (d.notice && window.console) console.warn('[wechat-scan]', d.notice);
scanPollTimer = setInterval(pollWechatScan, 3000);
})
.catch(function () {
setScanQrMask('网络异常', true);
});
}
function pollWechatScan() {
if (!scanScene) return;
fetch('/auth/wechat/scan/status?scene=' + encodeURIComponent(scanScene) +
'&client_id=' + encodeURIComponent(CLIENT_ID) +
'&redirect=' + encodeURIComponent(REDIRECT))
.then(function (r) { return r.json(); })
.then(function (res) {
var d = (res && res.data) || {};
if (Number(d.status) === 1) {
stopWechatScan();
window.location.href = d.redirect || ('/auth/login?client_id=' + encodeURIComponent(CLIENT_ID));
} else if (Number(d.status) === 2) {
stopWechatScan();
setScanQrMask('已过期', true);
}
})
.catch(function () { /* 下个周期重试 */ });
}
</script>
</body>
</html>