From 8c7c22369e45735613daebd848813e6e6211bf4e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=85=AC=E6=98=8E?=
<83812544+Ed1s0nZ@users.noreply.github.com>
Date: Wed, 17 Jun 2026 12:30:20 +0800
Subject: [PATCH] Add files via upload
---
web/static/css/style.css | 57 +++++++++++++++++++++++++
web/static/i18n/en-US.json | 1 +
web/static/i18n/zh-CN.json | 1 +
web/static/js/wechat-robot.js | 79 ++++++++++++++++++++++++++++++-----
web/templates/index.html | 7 ++++
5 files changed, 135 insertions(+), 10 deletions(-)
diff --git a/web/static/css/style.css b/web/static/css/style.css
index 055b59fa..cc9ef7fe 100644
--- a/web/static/css/style.css
+++ b/web/static/css/style.css
@@ -22734,6 +22734,58 @@ button.chat-files-dropdown-item:hover:not(:disabled) {
display: none;
}
+.robot-wechat-bound-flash {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ margin: 12px 0 0;
+ padding: 10px 14px;
+ border-radius: 8px;
+ background: rgba(40, 167, 69, 0.1);
+ border: 1px solid rgba(40, 167, 69, 0.35);
+ color: var(--success-color);
+ font-size: 0.875rem;
+ font-weight: 500;
+ line-height: 1.45;
+ opacity: 0;
+ transform: translateY(-4px);
+ transition: opacity 0.25s ease, transform 0.25s ease;
+}
+
+.robot-wechat-bound-flash[hidden] {
+ display: none !important;
+}
+
+.robot-wechat-bound-flash.is-visible {
+ opacity: 1;
+ transform: translateY(0);
+}
+
+.robot-wechat-bound-flash-icon {
+ flex-shrink: 0;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.robot-wechat-bound-summary {
+ margin: 10px 0 0;
+ font-size: 0.8125rem;
+ color: var(--text-secondary);
+ line-height: 1.45;
+}
+
+.robot-wechat-bound-summary code {
+ font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
+ font-size: 0.75rem;
+ padding: 2px 6px;
+ border-radius: 4px;
+ background: var(--bg-tertiary);
+ border: 1px solid var(--border-color);
+ color: var(--text-primary);
+ word-break: break-all;
+}
+
.robot-wechat-panel {
margin-top: 16px;
padding: 20px;
@@ -22751,6 +22803,11 @@ button.chat-files-dropdown-item:hover:not(:disabled) {
gap: 10px;
}
+/* display:flex 会覆盖 [hidden] 默认 display:none,须显式隐藏 */
+.robot-wechat-bound-panel[hidden] {
+ display: none !important;
+}
+
.robot-wechat-bound-icon {
width: 56px;
height: 56px;
diff --git a/web/static/i18n/en-US.json b/web/static/i18n/en-US.json
index 891ea4d4..d9774a19 100644
--- a/web/static/i18n/en-US.json
+++ b/web/static/i18n/en-US.json
@@ -1083,6 +1083,7 @@
"botAgent": "Bot Agent",
"ilinkBotId": "iLink Bot ID (filled after bind)",
"boundSuccess": "Binding successful. WeChat bot is enabled.",
+ "alreadyBound": "This WeChat account is already bound.",
"openLink": "QR not showing? Open link in WeChat on your phone"
},
"wecom": {
diff --git a/web/static/i18n/zh-CN.json b/web/static/i18n/zh-CN.json
index 2f08f2b8..dc914bb5 100644
--- a/web/static/i18n/zh-CN.json
+++ b/web/static/i18n/zh-CN.json
@@ -1071,6 +1071,7 @@
"botAgent": "Bot Agent",
"ilinkBotId": "iLink Bot ID(绑定后自动填充)",
"boundSuccess": "绑定成功,微信机器人已启用。",
+ "alreadyBound": "该微信已绑定过,无需重复绑定。",
"openLink": "无法显示二维码?点击用手机微信打开链接"
},
"wecom": {
diff --git a/web/static/js/wechat-robot.js b/web/static/js/wechat-robot.js
index 2446f317..d1ee42e1 100644
--- a/web/static/js/wechat-robot.js
+++ b/web/static/js/wechat-robot.js
@@ -2,6 +2,7 @@
let wechatBindSessionKey = null;
let wechatBindPollTimer = null;
+let wechatBindFlashTimer = null;
function wechatT(key, fallback) {
return typeof t === 'function' ? t(key) : fallback;
@@ -88,13 +89,50 @@ function stopWechatBindPoll() {
}
}
-/** 已绑定:仅展示成功状态,不显示二维码/配对码 */
+function clearWechatBindSuccessNotice() {
+ if (wechatBindFlashTimer) {
+ clearTimeout(wechatBindFlashTimer);
+ wechatBindFlashTimer = null;
+ }
+ const flash = document.getElementById('robot-wechat-bound-flash');
+ if (flash) {
+ flash.classList.remove('is-visible');
+ flash.hidden = true;
+ }
+}
+
+/** 绑定成功后的内联提示(约 4.5 秒后自动淡出) */
+function showWechatBindSuccessNotice(message) {
+ const text = message || wechatT('settings.robots.wechat.boundSuccess', '绑定成功,微信机器人已启用。');
+ const flash = document.getElementById('robot-wechat-bound-flash');
+ const flashText = document.getElementById('robot-wechat-bound-flash-text');
+
+ if (flash) {
+ if (flashText) flashText.textContent = text;
+ flash.hidden = false;
+ requestAnimationFrame(() => flash.classList.add('is-visible'));
+ if (wechatBindFlashTimer) clearTimeout(wechatBindFlashTimer);
+ wechatBindFlashTimer = setTimeout(() => {
+ flash.classList.remove('is-visible');
+ wechatBindFlashTimer = setTimeout(() => {
+ flash.hidden = true;
+ wechatBindFlashTimer = null;
+ }, 300);
+ }, 4500);
+ }
+
+ if (typeof window.showChatToast === 'function') {
+ window.showChatToast(text, 'success');
+ }
+}
+
+/** 已绑定:收起二维码区,仅展示紧凑摘要 */
function showWechatBoundUI(wechat) {
const wc = wechat || {};
const wrap = document.getElementById('robot-wechat-qr-wrap');
const boundPanel = document.getElementById('robot-wechat-bound-panel');
const scanPanel = document.getElementById('robot-wechat-scan-panel');
- const boundId = document.getElementById('robot-wechat-bound-id');
+ const summary = document.getElementById('robot-wechat-bound-summary');
const btn = document.getElementById('robot-wechat-bind-btn');
stopWechatBindPoll();
@@ -102,8 +140,8 @@ function showWechatBoundUI(wechat) {
setWechatBadge('bound');
setWechatCardBound(true);
- if (wrap) wrap.hidden = false;
- if (boundPanel) boundPanel.hidden = false;
+ if (wrap) wrap.hidden = true;
+ if (boundPanel) boundPanel.hidden = true;
if (scanPanel) scanPanel.hidden = true;
const verifyWrap = document.getElementById('robot-wechat-verify-wrap');
@@ -117,14 +155,15 @@ function showWechatBoundUI(wechat) {
}
if (ph) ph.hidden = false;
- if (boundId) {
- const id = wc.ilink_bot_id || document.getElementById('robot-wechat-ilink-bot-id')?.value?.trim() || '';
+ const id = wc.ilink_bot_id || document.getElementById('robot-wechat-ilink-bot-id')?.value?.trim() || '';
+ if (summary) {
if (id) {
- boundId.textContent = wechatT('settings.robots.wechat.boundBotId', '已绑定 Bot ID:') + id;
- boundId.hidden = false;
+ const prefix = wechatT('settings.robots.wechat.boundBotId', '已绑定 Bot ID:');
+ summary.innerHTML = `${prefix}${escapeHtml(id)}`;
+ summary.hidden = false;
} else {
- boundId.textContent = '';
- boundId.hidden = true;
+ summary.textContent = '';
+ summary.hidden = true;
}
}
@@ -133,21 +172,32 @@ function showWechatBoundUI(wechat) {
}
}
+function escapeHtml(text) {
+ return String(text)
+ .replace(/&/g, '&')
+ .replace(//g, '>')
+ .replace(/"/g, '"');
+}
+
/** 扫码绑定进行中 */
function showWechatScanUI() {
const wrap = document.getElementById('robot-wechat-qr-wrap');
const boundPanel = document.getElementById('robot-wechat-bound-panel');
const scanPanel = document.getElementById('robot-wechat-scan-panel');
+ const summary = document.getElementById('robot-wechat-bound-summary');
const btn = document.getElementById('robot-wechat-bind-btn');
setWechatBadge('scanning');
setWechatCardBound(false);
+ clearWechatBindSuccessNotice();
ensureWechatSteps();
updateWechatSteps('generate');
if (wrap) wrap.hidden = false;
if (boundPanel) boundPanel.hidden = true;
if (scanPanel) scanPanel.hidden = false;
+ if (summary) summary.hidden = true;
const verifyWrap = document.getElementById('robot-wechat-verify-wrap');
if (verifyWrap) verifyWrap.hidden = true;
@@ -163,7 +213,10 @@ function showWechatScanUI() {
/** 未绑定且未在扫码:隐藏面板 */
function hideWechatQrWrap() {
const wrap = document.getElementById('robot-wechat-qr-wrap');
+ const summary = document.getElementById('robot-wechat-bound-summary');
if (wrap) wrap.hidden = true;
+ if (summary) summary.hidden = true;
+ clearWechatBindSuccessNotice();
setWechatBadge('idle');
setWechatCardBound(false);
}
@@ -278,6 +331,9 @@ async function pollWechatBindStatus() {
const idEl = document.getElementById('robot-wechat-ilink-bot-id');
if (idEl) idEl.value = data.ilink_bot_id;
}
+ showWechatBindSuccessNotice(
+ data.message || wechatT('settings.robots.wechat.boundSuccess', '绑定成功,微信机器人已启用。')
+ );
if (typeof loadConfig === 'function') {
await loadConfig(false);
} else {
@@ -299,6 +355,9 @@ async function pollWechatBindStatus() {
break;
case 'binded_redirect':
stopWechatBindPoll();
+ showWechatBindSuccessNotice(
+ data.message || wechatT('settings.robots.wechat.alreadyBound', '该微信已绑定过,无需重复绑定。')
+ );
showWechatBoundUI({ bound: true });
return;
case 'expired':
diff --git a/web/templates/index.html b/web/templates/index.html
index 56467593..d5a6b334 100644
--- a/web/templates/index.html
+++ b/web/templates/index.html
@@ -2817,6 +2817,13 @@
用微信扫码确认后会自动保存并启用。
+