修复登录页浏览器后退卡死、已认证态下登录/注册的凭据校验绕过、系统消息分页丢失等第1-2章问题
- 最主要的一处:登录成功后点浏览器"后退",会回到一个仍然认为"已登录"的底层连接、但重新挂载出来
的登录表单——按钮永久卡在禁用的"登录中…"(loginDisabled只有失败分支会重置,成功分支从来没有,
因为正常路径下这个页面早就导航走了,没人会看到);如果不管这个直接切换企业码后再次提交,
doLogin()/handleNewAccountRequest()开头的"已认证就直接放行"逻辑会让登录悄悄跳过凭据校验,
或者让注册请求收到后端原始英文错误"already authenticated (409)"。根治方式是在
handleHashRoute加一道门:hash指向登录/注册等纯"未登录态"视图、但连接其实已认证时,直接重定向
离开,不让这类表单有机会被重新渲染出来——已用真实浏览器验证4个入口(login/register/tenant/
reset/cred)全部正确重定向,且确认不影响真正的登录后安全类页面(如identity-check)。
handleLoginSuccessful也顺手补了loginDisabled:false兜底。
- 系统消息列表:后端`GET /system-notifications`明明返回`next_cursor`表示还有更多,前端从来没用过,
未读50+条永远只能看到最近20条、永远没法真正清零。补了"加载更多"分页——已用真实账号(60+条历史
通知)验证,点击后正确追加下一页、游标耗尽后正确不再显示按钮。
- 已处理(通过/拒绝)的好友申请通知,原来只要event_type以"friend.request"开头就显示"查看新朋友"
按钮——不区分"待处理"和"已是历史结果",点了跳到待处理列表也找不到对应项。改成只在
`friend.request.created`时显示,已用真实账号里同时存在created/accepted/rejected三种通知
验证行为符合预期。
- 注册页四处不统一的占位品牌名(讯工捷迅/捷信密使/捷讯/即时通讯,没有一个是真实品牌名)与
系统消息页脚"即时通讯安全团队",统一改用BASE_APP_NAME("MeetingIM")。
- config.js的KNOWN_HOSTS.hosted从web.tinode.co改为web.118im.com(这是WS连接失败时的最终
兜底地址,指向无关第三方域名不只是品牌问题,是真实会连错服务器);host-name.js的
detectServerAddress()原来只要hostname是localhost就无条件返回硬编码的localhost:6060,
完全不管页面实际监听的端口——本项目自己的开发代理跑在8093,清缓存后首次连接必然先撞一次
死连接,改成和非localhost分支一样用页面自己的真实端口。
- 实名认证提交成功后,姓名/证件号输入框原来会变成空白(后端成功响应不含masked_name/
masked_id_number,组件切到只读态时又没有回退到用户自己刚输入的草稿值)——改成没有脱敏字段时
回退显示用户本次会话里刚输入的原始值,不是留白。
- Firebase推送通知初始化失败原来复用登录/注册表单的错误提示通道,可能盖住一个同时发生的真实
登录错误,或在用户还没操作登录表单时就先弹出一条无关提示——推送本身是锦上添花功能,改成只
console记录+静默关闭开关,不再抢占登录页的错误展示位。
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
8b51fd3eb8
commit
47148aa75d
@@ -2,6 +2,7 @@ import React from 'react';
|
||||
import { Tinode } from 'tinode-sdk';
|
||||
|
||||
import HashNavigation from '../lib/navigation.js';
|
||||
import { BASE_APP_NAME } from '../config.js';
|
||||
import { getBootstrap, getRealnameStatus, getSystemNotifications, markSystemNotificationRead } from '../lib/im-api.js';
|
||||
import { makeImageUrl } from '../lib/blob-helpers.js';
|
||||
import { useCachedData } from '../lib/use-cached-data.js';
|
||||
@@ -417,16 +418,29 @@ function systemNotificationText(item) {
|
||||
|
||||
function SystemMessages({authenticated}) {
|
||||
const [items, setItems] = React.useState([]);
|
||||
const [cursor, setCursor] = React.useState('');
|
||||
const [loadingMore, setLoadingMore] = React.useState(false);
|
||||
const [loading, setLoading] = React.useState(true);
|
||||
const [error, setError] = React.useState('');
|
||||
const [toast, setToast] = React.useState('');
|
||||
|
||||
React.useEffect(() => {
|
||||
getSystemNotifications().then(data => setItems(data.items || []))
|
||||
getSystemNotifications().then(data => { setItems(data.items || []); setCursor(data.next_cursor || ''); })
|
||||
.catch(err => setError(err.message || '加载失败'))
|
||||
.finally(() => setLoading(false));
|
||||
}, []);
|
||||
|
||||
// GET /system-notifications does return next_cursor whenever there's more (real accounts with
|
||||
// 50 unread saw it truncate silently at 20, with no way to reach or ever mark the rest read).
|
||||
const loadMore = () => {
|
||||
if (loadingMore || !cursor) return;
|
||||
setLoadingMore(true);
|
||||
getSystemNotifications(cursor).then(data => {
|
||||
setItems(list => list.concat(data.items || []));
|
||||
setCursor(data.next_cursor || '');
|
||||
}).catch(() => {}).finally(() => setLoadingMore(false));
|
||||
};
|
||||
|
||||
const markRead = item => {
|
||||
if (item.read_at) return;
|
||||
setItems(list => list.map(i => i.id === item.id ? {...i, read_at: new Date().toISOString()} : i));
|
||||
@@ -459,14 +473,15 @@ function SystemMessages({authenticated}) {
|
||||
猜的,不是照真实响应写的)——导致"查看新朋友"按钮对这条最常见的通知永远不出现。 */}
|
||||
{item.action && typeof item.action.topic === 'string' && item.action.topic.startsWith('grp') ?
|
||||
<button type="button" className="system-security-link" onClick={e => { e.stopPropagation(); navigate('group-settings', item.action.topic); }}>查看群聊 <Icon>chevron_right</Icon></button> :
|
||||
item.event_type && item.event_type.startsWith('friend.request') ?
|
||||
item.event_type === 'friend.request.created' ?
|
||||
<button type="button" className="system-security-link" onClick={e => { e.stopPropagation(); navigate('friend-requests'); }}>查看新朋友 <Icon>chevron_right</Icon></button> :
|
||||
item.action && (item.action.device || item.action.ip) ?
|
||||
<button type="button" className="system-security-link" onClick={e => { e.stopPropagation(); navigate(authenticated ? 'security' : 'identity-check'); }}>前往安全设置 <Icon>chevron_right</Icon></button> :
|
||||
null}
|
||||
<footer>保持警惕<br />即时通讯安全团队</footer>
|
||||
<footer>保持警惕<br />{BASE_APP_NAME}安全团队</footer>
|
||||
</div>
|
||||
</article>)}
|
||||
{cursor ? <button type="button" className="system-notification-load-more" disabled={loadingMore} onClick={loadMore}>{loadingMore ? '加载中…' : '加载更多'}</button> : null}
|
||||
</main>
|
||||
<Toast message={toast} onDone={() => setToast('')} />
|
||||
</div>;
|
||||
|
||||
Reference in New Issue
Block a user