From 46a98782fda8b1fc02ef17b2d2311b59c7507c3b Mon Sep 17 00:00:00 2001 From: Your Name Date: Sun, 6 Sep 2026 13:19:45 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D"=E9=80=80=E5=87=BA=E5=BD=93?= =?UTF-8?q?=E5=89=8D=E7=99=BB=E5=BD=95"=E4=BB=8D=E7=94=A8=E5=8E=9F?= =?UTF-8?q?=E7=94=9F=20window.confirm()=EF=BC=8C=E4=B8=8E=E5=85=B6?= =?UTF-8?q?=E4=BD=99=E4=B8=89=E4=B8=AA=E7=A1=AE=E8=AE=A4=E5=BC=B9=E5=B1=82?= =?UTF-8?q?=E4=B8=8D=E4=B8=80=E8=87=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 现象:清除缓存/清除聊天记录/注销账号三处早前已经统一改成组件内 ConfirmSheet 弹层 (本文件其它三处组件自己的注释也在讲这次统一),唯独"退出当前登录"还留着最原始的 window.confirm()。本轮测试发现这在当前浏览器自动化环境下会被判定为"环境不支持同步 弹窗"而直接返回 false(控制台可见"Page dialog suppressed"警告),退出登录点了完全 没反应,且没有任何错误提示——这不只是测试环境的偶然状况:不少内嵌 WebView/嵌入式 容器场景本身就会禁用 confirm()/alert() 这类阻塞式原生对话框,真实用户在这些环境下 点"退出登录"会遇到一模一样的静默无效。 修法:新增 LogoutConfirm 组件,复用同一个 ConfirmSheet(图标 logout,标题"退出登录"), "退出当前登录"按钮改成 setSheet('logout') 打开这个弹层,与 CacheClear/ ClearHistoryConfirm/DeleteAccountConfirm 完全同构,不再依赖浏览器原生对话框。 验证:npm run build:dev 后在浏览器实测,点击"退出当前登录"正确弹出本地弹层(标题/ 文案/确认取消按钮与设计一致,logout 图标正常渲染为图形而非文字),点"确认"后真实 退出登录、回到企业码入口页;点"取消"正确关闭弹层且不登出。 Co-Authored-By: Claude Sonnet 5 --- src/views/personal-settings-view.jsx | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/src/views/personal-settings-view.jsx b/src/views/personal-settings-view.jsx index f0784315..929a62e4 100644 --- a/src/views/personal-settings-view.jsx +++ b/src/views/personal-settings-view.jsx @@ -297,7 +297,7 @@ function SettingsList({onToast, onLogout, tinode, chatList, onDeleteAccount}) { // 但因为底下真的没有任何东西在渲染,视觉上跟直接跳转到一个空白新页面没有区别。改成本组件自己的 // 本地 state,弹层作为兄弟节点叠在列表上方,列表本身不卸载——group-management-view.jsx 的 // OwnerSelect(选择新群主)已经是这个正确模式,这里照抄,不是发明新写法。 - const [sheet, setSheet] = React.useState(null); // null | 'cache' | 'history' | 'delete' + const [sheet, setSheet] = React.useState(null); // null | 'cache' | 'history' | 'delete' | 'logout' React.useEffect(() => { getYouthMode().then(d => { writeCachedData('youth-mode', d); setYouthSettings(d); }).catch(() => {}); getRealnameStatus().then(d => { writeCachedData('me-realname', d); setRealname(d); }).catch(() => {}); @@ -305,11 +305,6 @@ function SettingsList({onToast, onLogout, tinode, chatList, onDeleteAccount}) { const youthEnabled = youthSettings ? youthSettings.enabled : null; const realnameStatus = realname ? realname.status : null; const realnameLabel = {verified: '已认证', pending: '审核中', rejected: '未通过'}[realnameStatus] || '未认证'; - const logout = () => { - if (window.confirm('确定要退出当前登录吗?')) { - onLogout ? onLogout() : onToast('当前环境不支持退出登录'); - } - }; return
setSheet('cache')} /> @@ -329,11 +324,12 @@ function SettingsList({onToast, onLogout, tinode, chatList, onDeleteAccount}) {
setSheet('delete')} danger />
- +
{sheet === 'cache' ? setSheet(null)} /> : null} {sheet === 'history' ? setSheet(null)} /> : null} {sheet === 'delete' ? setSheet(null)} /> : null} + {sheet === 'logout' ? setSheet(null)} /> : null}
; } @@ -346,6 +342,20 @@ function ConfirmSheet({icon, title, body, confirmLabel = '确认', confirmDanger ; } +// Was a bare `window.confirm()` -- the only one of these four confirmation flows not using this +// same ConfirmSheet pattern, an inconsistency with cache/history/delete-account below (their own +// comments describe deliberately moving away from route-per-confirmation dialogs to this in-place +// sheet). A native confirm() is also environment-dependent: some embedded WebViews/kiosk contexts +// disable synchronous dialogs outright (confirm() then returns false unconditionally, silently +// preventing logout with no error shown), which this sheet-based approach doesn't depend on. +function LogoutConfirm({onLogout, onToast, onClose}) { + const confirm = () => { + onClose(); + onLogout ? onLogout() : onToast('当前环境不支持退出登录'); + }; + return ; +} + // No backend endpoint clears cache/history -- both are pure client-side operations (confirmed: // server/main.go's ~74 routes have nothing for either). Cache clearing empties Cache Storage/IDB; // clearing all history calls the native Tinode delMessagesAll(false) per open conversation, same