From 5ddace97f483d71035dfb7224bdfa6ce44ac1ff6 Mon Sep 17 00:00:00 2001 From: Your Name Date: Sun, 6 Sep 2026 15:41:36 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=A5=BD=E5=8F=8B=E8=B5=84?= =?UTF-8?q?=E6=96=99/=E9=AA=8C=E8=AF=81=E9=A1=B5=E5=AF=B9"=E5=BD=93?= =?UTF-8?q?=E5=89=8D=E5=85=B3=E7=B3=BB"=E7=9A=84=E4=B8=A4=E5=A4=84?= =?UTF-8?q?=E5=88=A4=E6=96=AD=E9=81=97=E6=BC=8F=EF=BC=8C=E4=B8=8E=E5=B7=B2?= =?UTF-8?q?=E6=9C=89=E7=9A=84=E5=A5=BD=E5=8F=8B=E7=94=B3=E8=AF=B7=E7=8A=B6?= =?UTF-8?q?=E6=80=81=E6=9C=BA=E4=BF=AE=E5=A4=8D=E5=BD=A2=E6=88=90=E5=AE=8C?= =?UTF-8?q?=E6=95=B4=E9=97=AD=E7=8E=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 现象一:Profile 组件(好友/陌生人资料页)在 getConversationContext 回来后只合并了 relationship 字段,没有一并合并 capabilities——这个组件判断"能否显示添加好友按钮" 用的是 profile.capabilities.can_add_friend,不是 relationship 本身。已实测复现: 刚发送好友申请、relationship 已经变成 pending_outbound 时,若走的是"直接刷新这个 资料页"而不是 Verification 组件自己的发送成功回调(该回调已由另一处提交单独修复), canAdd 依然读到发送前搜索结果种子里的 can_add_friend:true,"添加好友"按钮继续可点, 可再次触发一次好友申请(配合后端不去重的缺口——新增44)。 现象二:Verification 组件(好友验证/发送申请页)完全没有用 getConversationContext 校正过 relationship,只依赖 getUserProfile——但该接口对非好友直接 403,403 时的 catch 分支什么都不做。真实复现:本次会话内先成为好友、再解除好友关系后,若该好友的 profile-seed 缓存还留着"好友"时期的旧数据,重新打开验证页会一直显示"你们已经是 好友了",且不提供发送框,除非整页刷新清掉内存缓存,否则无法向这个人重新发起好友申请。 修复:两处都在 getConversationContext 成功回调里,把它返回的字段当作当前关系的权威 来源合并进本地 profile 状态——Profile 一并合并 capabilities(而不只是 relationship), Verification 补上原本没有的 getConversationContext 调用去合并 relationship。 验证:真实浏览器操作,两个全新注册账号之间反复走查——(1) 发送好友申请后直接刷新 资料页,"添加好友"按钮正确消失、显示"好友申请正在等待验证";(2) 成为好友后互相 删除好友关系,立刻重新打开验证页,正确显示可发送的验证留言表单,不再卡在"你们已经 是好友了"。 Co-Authored-By: Claude Sonnet 5 --- src/views/contact-management-view.jsx | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/src/views/contact-management-view.jsx b/src/views/contact-management-view.jsx index 3578c44e..6285f29b 100644 --- a/src/views/contact-management-view.jsx +++ b/src/views/contact-management-view.jsx @@ -356,6 +356,20 @@ function Verification({uid, onToast}) { React.useEffect(() => { if (!uid) return; getUserProfile(uid).then(data => { writeCachedData('profile-seed:' + uid, data); setProfile(data); }).catch(() => {}); + // getUserProfile 403s for anyone who isn't currently a friend (server privacy default) -- same + // gap Profile already works around below. Without this, a `profile-seed` left over from *earlier + // in the same session* (e.g. this pair really were friends before one side unfriended them, or a + // request was sent and then rejected) stayed on screen forever: alreadyFriend/alreadyPending read + // straight off `profile.relationship`, and the 403 catch above has nothing to correct it with. + // Confirmed live: unfriend someone, then re-open this exact page for them (still reachable via + // their still-cached, now-stale seed) -- it kept claiming "你们已经是好友了" and hid the compose + // box entirely, with no way to send a new request short of a full page reload to drop the cache. + // getConversationContext isn't gated on friendship and reports the true current relationship. + getConversationContext(uid).then(ctx => { + if (ctx && ctx.relationship) { + setProfile(current => current ? {...current, relationship: ctx.relationship} : current); + } + }).catch(() => {}); }, [uid]); const alreadyPending = profile && (profile.relationship === 'pending_outbound' || profile.relationship === 'pending_inbound'); const alreadyFriend = profile && profile.relationship === 'friend'; @@ -420,9 +434,19 @@ function Profile({uid, friend, onTopicSelected, onToast}) { // handles below. getConversationContext resolves for a P2P conversation regardless of block // status and correctly reports the real relationship, so it's used here purely to refresh that // one field on top of whatever getUserProfile/the seed cache already provided for the rest. + // + // 同时必须把 ctx.capabilities 一起合并进去,不能只更新 relationship:canAdd 这个渲染判断读的是 + // profile.capabilities.can_add_friend,不是 relationship 本身。实测复现:从陌生人搜索结果进来的 + // seed 一直带着 capabilities.can_add_friend=true(搜索时 can_add 确实是 true),发送好友申请后 + // relationship 变成 pending_outbound,可这里原来只覆盖 relationship 字段,capabilities 原样保留 + // 着申请前的 can_add_friend:true——canAdd 分支判断不看 relationship,于是"添加好友"按钮在申请 + // 已发出后继续显示、可以重复点击再次发起申请(配合后端不去重的缺口——新增44——实际造成重复申请)。 + // ctx.capabilities 本身就是服务端针对当前 relationship 算出来的权威值(此时 can_add_friend 已经 + // 是 false),直接一起合并即可,不需要在前端另外推导一套"这些 relationship 不能加好友"的规则。 getConversationContext(uid).then(ctx => { if (ctx && ctx.relationship) { - setProfile(current => current ? {...current, relationship: ctx.relationship} : current); + setProfile(current => current ? {...current, relationship: ctx.relationship, + capabilities: ctx.capabilities || current.capabilities} : current); } }).catch(() => {}); }, [uid]);