补上好友申请前后关系状态聊天页的入口,并把验证留言渲染成真实消息气泡

第3章要求pending_inbound/pending_outbound/none/blocked几种关系状态都能在真实聊天
窗口里看到(参考图 个人对话框(对方的状态)/(我的状态).png、开启沟通页面.png)。
messages-view.jsx里对应的横幅逻辑("以上是打招呼的消息"/"好友申请正在等待处理"等)
本身早就是对的,但排查发现两个问题:

1. 全项目没有任何入口能导航进这个视图——"新朋友"列表(FriendRequests)每一行没有
   onClick;好友个人主页(Profile)非好友分支只显示一段cannotAddReason纯文字,没有
   任何可点击进聊天的按钮。发起方和接收方在成为好友之前都完全看不到这个视图。
2. 验证留言原文(发好友申请时填的那段话,存在im_friend_requests表的message字段,
   不是真实Tinode消息,没有走topic.publish())没有被当作消息渲染出来,参考图里
   明确是作为聊天页第一条消息气泡展示的。

修复:
- contact-management-view.jsx: FriendRequests每一行加onClick,用(onCreateTopic||
  onTopicSelected)跳进对应聊天(同一套Profile.openChat已经验证过的冷启动安全写法,
  接受/拒绝按钮补stopPropagation不受影响);Profile非好友分支(blocked_by_peer/
  blocked_by_me/pending_inbound/pending_outbound)补一个"查看聊天"按钮,跟
  cannotAddReason文字并排展示(不复用people-profile-actions的两列grid,那是给
  发消息+音视频通话两个平级按钮设计的)。ContactManagementView/sidepanel-view.jsx
  早前就已经把onCreateTopic透传到位,这次只是多接一层。
- messages-view.jsx: loadRelationshipContext新增loadPendingRequestMessage,
  relationship是pending_inbound/pending_outbound时,用relationshipContext自带的
  request_id去GET /friend-requests换真实留言文本(没有留言用参考图默认文案"请求
  添加你为好友"兜底),渲染成一条合成的消息气泡插在消息列表最前面(不进
  messageNodes、不调用发消息接口)——pending_inbound左对齐、pending_outbound右
  对齐,气泡样式直接复用chat-message.jsx真实消息已经在用的.bubble/.left/.right
  这套CSS(app里"发出的"气泡实际是这套已实现的浅色而非参考图的蓝色,保持跟同一
  会话里其它真实消息一致,不単独改这一条的颜色去凑旧版参考图)。

验证:真实两个新账号(vcm909641发起→hankqa14b接收)走了一遍完整流程——
从"新朋友"列表点击行正确进入聊天页,留言气泡+"以上是打招呼的消息"横幅正确显示;
从Profile页"查看聊天"进入,留言气泡右对齐+"好友申请正在等待处理"横幅正确显示;
点"通过验证"接受申请后正确留在列表页不误触发导航;接受后重新打开同一会话,
合成气泡正确消失,被真实的"你们已成为好友,现在可以开始聊天了。"系统消息取代,
无残留/无重复。
This commit is contained in:
Your Name
2026-09-06 17:24:36 +08:00
parent e4b0868036
commit ac8f0cf315
8 changed files with 189 additions and 23 deletions
+31 -8
View File
@@ -7817,7 +7817,9 @@ function requestStatusLabel(item) {
return null;
}
function FriendRequests({
onToast
onToast,
onTopicSelected,
onCreateTopic
}) {
const [items, setItems] = react__WEBPACK_IMPORTED_MODULE_0___default().useState([]);
const [loading, setLoading] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(true);
@@ -7840,6 +7842,7 @@ function FriendRequests({
onToast(err.message || '操作失败');
});
};
const openChat = item => (onCreateTopic || onTopicSelected) && (onCreateTopic || onTopicSelected)(item.direction === 'inbound' ? item.applicant_id : item.target_user_id);
return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", {
className: "people-page",
children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Header, {
@@ -7854,6 +7857,9 @@ function FriendRequests({
className: "people-empty-hint",
children: loadError ? '加载失败,请重试' : '暂无新朋友申请'
}, void 0, false) : null, items.map(item => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("article", {
role: "button",
tabIndex: 0,
onClick: () => openChat(item),
children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Avatar, {
person: item.peer
}, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", {
@@ -7867,12 +7873,18 @@ function FriendRequests({
}, void 0, true), item.status === 'pending' && item.direction === 'inbound' ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("span", {
children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("button", {
type: "button",
onClick: () => handle(item, false),
onClick: e => {
e.stopPropagation();
handle(item, false);
},
children: "拒绝"
}, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("button", {
type: "button",
className: "primary",
onClick: () => handle(item, true),
onClick: e => {
e.stopPropagation();
handle(item, true);
},
children: "通过验证"
}, void 0, false)]
}, void 0, true) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("em", {
@@ -8385,10 +8397,19 @@ function Profile({
children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Icon, {
children: "person_add_alt"
}, void 0, false), "添加好友"]
}, void 0, true) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("p", {
className: "people-empty-hint",
children: cannotAddReason
}, void 0, false)]
}, void 0, true) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.Fragment, {
children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("p", {
className: "people-empty-hint",
children: cannotAddReason
}, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("button", {
type: "button",
className: "people-primary",
onClick: openChat,
children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Icon, {
children: "chat_bubble_outline"
}, void 0, false), "查看聊天"]
}, void 0, true)]
}, void 0, true)]
}, void 0, true)]
}, void 0, true);
}
@@ -8738,7 +8759,9 @@ function ContactManagementView({
myUserId: myUserId,
onTopicSelected: onTopicSelected
}, void 0, false);else if (view === 'friend-requests') content = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(FriendRequests, {
onToast: setToast
onToast: setToast,
onTopicSelected: onTopicSelected,
onCreateTopic: onCreateTopic
}, void 0, false);else if (view === 'add-friend' || view === 'friend-search-result') content = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(AddFriend, {
result: view === 'friend-search-result',
onToast: setToast,