群昵称改用专门的接口读取,修好读不回已保存值的问题
上一个commit修好了"群资料"页把群名称当成个人群昵称显示的问题,但实机验证发现改完仍然显示"未设置"。
抓包确认根因:GET /groups/{topic}/members 列表接口的每一项里压根没有 group_nickname 字段(只有
acs/display_name/mentionable/role/user_id),所以任何从成员列表里读昵称的写法,不管代码逻辑对不对,
都永远拿不到值——这个文件里原有的 MyNicknameEditor 也是同样的写法,同样存在这个问题(打开编辑器时
不会回填已保存的昵称)。
真正能读到昵称的是保存用的那个路径上对应的 GET:GET /groups/{topic}/members/me/profile,返回
{nickname, version, updated_at}(server/im_http.go:4776-4782)。im-api.js 里之前只封装了 PUT,
补上了对应的 getMyGroupProfile,两处读取(群资料页预览行、昵称编辑器回填)都改成用它。
实机验证:保存"测试昵称A"后重新打开群资料页,"群昵称"正确显示"测试昵称A","群名称"独立显示
"扫码测试群"。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
e4c6e1b246
commit
3bdb0bf40f
@@ -561,6 +561,11 @@ export const updateGroupMemberSettings = (topic, {pinned, mute_notifications}) =
|
|||||||
imPatch('/groups/' + encodeURIComponent(topic) + '/member-settings', {pinned, mute_notifications});
|
imPatch('/groups/' + encodeURIComponent(topic) + '/member-settings', {pinned, mute_notifications});
|
||||||
export const updateMyGroupProfile = (topic, nickname, version) =>
|
export const updateMyGroupProfile = (topic, nickname, version) =>
|
||||||
imPut('/groups/' + encodeURIComponent(topic) + '/members/me/profile', {nickname, version});
|
imPut('/groups/' + encodeURIComponent(topic) + '/members/me/profile', {nickname, version});
|
||||||
|
// GET .../members/me/profile is the only endpoint that actually returns the saved nickname --
|
||||||
|
// confirmed live that GET .../members (getGroupMembers below) never includes group_nickname on any
|
||||||
|
// item, so anything reading the nickname from that list (as this file's own callers used to) will
|
||||||
|
// always see it as unset even right after a successful save.
|
||||||
|
export const getMyGroupProfile = topic => imGet('/groups/' + encodeURIComponent(topic) + '/members/me/profile');
|
||||||
export const leaveGroup = topic => imPost('/groups/' + encodeURIComponent(topic) + '/leave', {});
|
export const leaveGroup = topic => imPost('/groups/' + encodeURIComponent(topic) + '/leave', {});
|
||||||
export const getGroupMembers = (topic, {query = '', cursor = '', role = '', eligibleRole = '', mentionable, muteEligible} = {}) =>
|
export const getGroupMembers = (topic, {query = '', cursor = '', role = '', eligibleRole = '', mentionable, muteEligible} = {}) =>
|
||||||
imGet('/groups/' + encodeURIComponent(topic) + '/members' +
|
imGet('/groups/' + encodeURIComponent(topic) + '/members' +
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { pinyin } from 'pinyin-pro';
|
|||||||
import HashNavigation from '../lib/navigation.js';
|
import HashNavigation from '../lib/navigation.js';
|
||||||
import {
|
import {
|
||||||
getGroups, createGroup, getGroup, updateGroup, getGroupSettings, updateGroupMemberSettings,
|
getGroups, createGroup, getGroup, updateGroup, getGroupSettings, updateGroupMemberSettings,
|
||||||
updateMyGroupProfile, leaveGroup, getGroupMembers, createGroupQRCode, getGroupJoinRequests,
|
updateMyGroupProfile, getMyGroupProfile, leaveGroup, getGroupMembers, createGroupQRCode, getGroupJoinRequests,
|
||||||
acceptGroupJoinRequest, rejectGroupJoinRequest, getLatestGroupAnnouncement,
|
acceptGroupJoinRequest, rejectGroupJoinRequest, getLatestGroupAnnouncement,
|
||||||
updateCurrentGroupAnnouncement, getGroupGovernance, updateGroupGovernance, addGroupAdmins,
|
updateCurrentGroupAnnouncement, getGroupGovernance, updateGroupGovernance, addGroupAdmins,
|
||||||
deleteGroupAdmin, muteGroupMembers, getGroupMutes, unmuteGroupMember, transferGroupOwner,
|
deleteGroupAdmin, muteGroupMembers, getGroupMutes, unmuteGroupMember, transferGroupOwner,
|
||||||
@@ -400,8 +400,10 @@ function GroupProfile({topic, myUserId, onToast}) {
|
|||||||
const [loadError, setLoadError] = React.useState(false);
|
const [loadError, setLoadError] = React.useState(false);
|
||||||
// "群昵称" here means "my nickname within this group" (see MyNicknameEditor below), not the group's
|
// "群昵称" here means "my nickname within this group" (see MyNicknameEditor below), not the group's
|
||||||
// own name -- confirmed live this preview row was showing group.name instead, since it's easy to
|
// own name -- confirmed live this preview row was showing group.name instead, since it's easy to
|
||||||
// conflate the two. Reuses the same getGroupMembers+filter approach MyNicknameEditor already uses
|
// conflate the two. GET .../members/me/profile is the only endpoint that actually returns this --
|
||||||
// (there's no working "me" shortcut on the member-profile-by-id endpoint to fetch this more directly).
|
// confirmed live that the member list endpoint (getGroupMembers) never includes group_nickname on
|
||||||
|
// any item, so a version of this fix that read it from there (like MyNicknameEditor below does)
|
||||||
|
// would always show "未设置" even right after a successful save.
|
||||||
const [myNickname, setMyNickname] = React.useState('');
|
const [myNickname, setMyNickname] = React.useState('');
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (!topic) return;
|
if (!topic) return;
|
||||||
@@ -409,12 +411,11 @@ function GroupProfile({topic, myUserId, onToast}) {
|
|||||||
getGroup(topic).then(g => { writeCachedData('group:' + topic, g); setGroup(g); }).catch(() => { onToast('加载失败'); setLoadError(true); });
|
getGroup(topic).then(g => { writeCachedData('group:' + topic, g); setGroup(g); }).catch(() => { onToast('加载失败'); setLoadError(true); });
|
||||||
}, [topic]);
|
}, [topic]);
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (!topic || !myUserId) return;
|
if (!topic) return;
|
||||||
getGroupMembers(topic, {query: ''}).then(data => {
|
getMyGroupProfile(topic).then(data => {
|
||||||
const me = (data.items || []).find(m => m.user_id === myUserId);
|
setMyNickname(data.nickname || '');
|
||||||
if (me) setMyNickname(me.group_nickname || '');
|
|
||||||
}).catch(() => {});
|
}).catch(() => {});
|
||||||
}, [topic, myUserId]);
|
}, [topic]);
|
||||||
if (!group) return <div className="group-page"><Header title="群资料" back="group-settings" backTopic={topic} /><main className="group-profile"><p className="group-inline-empty">{loadError ? '群组信息加载失败' : '加载中…'}</p></main></div>;
|
if (!group) return <div className="group-page"><Header title="群资料" back="group-settings" backTopic={topic} /><main className="group-profile"><p className="group-inline-empty">{loadError ? '群组信息加载失败' : '加载中…'}</p></main></div>;
|
||||||
const canEdit = group.permissions && group.permissions.can_edit_profile;
|
const canEdit = group.permissions && group.permissions.can_edit_profile;
|
||||||
const nicknameLabel = myNickname || '未设置';
|
const nicknameLabel = myNickname || '未设置';
|
||||||
@@ -865,15 +866,14 @@ function GroupDescriptionEditor({topic, onToast}) {
|
|||||||
// "我在本群的昵称" has no dedicated reference screenshot (see plan notes) -- placed in GroupSettings,
|
// "我在本群的昵称" has no dedicated reference screenshot (see plan notes) -- placed in GroupSettings,
|
||||||
// governed by the real member_invite... no, by the group_nickname field on groupMemberPayload, gated by
|
// governed by the real member_invite... no, by the group_nickname field on groupMemberPayload, gated by
|
||||||
// the "群成员修改昵称" concept the images described (server-side enforcement, not re-checked client-side).
|
// the "群成员修改昵称" concept the images described (server-side enforcement, not re-checked client-side).
|
||||||
function MyNicknameEditor({topic, myUserId, onToast}) {
|
function MyNicknameEditor({topic, onToast}) {
|
||||||
const [value, setValue] = React.useState('');
|
const [value, setValue] = React.useState('');
|
||||||
|
// getGroupMembers' list items never include group_nickname (confirmed live) -- only
|
||||||
|
// GET .../members/me/profile actually returns it, same fix as GroupProfile's preview row above.
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (!topic || !myUserId) return;
|
if (!topic) return;
|
||||||
getGroupMembers(topic, {query: ''}).then(data => {
|
getMyGroupProfile(topic).then(data => setValue(data.nickname || '')).catch(() => {});
|
||||||
const me = (data.items || []).find(m => m.user_id === myUserId);
|
}, [topic]);
|
||||||
if (me) setValue(me.group_nickname || '');
|
|
||||||
}).catch(() => {});
|
|
||||||
}, [topic, myUserId]);
|
|
||||||
const save = () => {
|
const save = () => {
|
||||||
updateMyGroupProfile(topic, value.trim(), 0).then(() => {
|
updateMyGroupProfile(topic, value.trim(), 0).then(() => {
|
||||||
onToast('保存成功'); window.setTimeout(() => navigate('group-settings', topic), 600);
|
onToast('保存成功'); window.setTimeout(() => navigate('group-settings', topic), 600);
|
||||||
|
|||||||
+29
-11
@@ -3426,6 +3426,7 @@ __webpack_require__.r(__webpack_exports__);
|
|||||||
/* harmony export */ getMonthlyReport: function() { return /* binding */ getMonthlyReport; },
|
/* harmony export */ getMonthlyReport: function() { return /* binding */ getMonthlyReport; },
|
||||||
/* harmony export */ getMonthlyReports: function() { return /* binding */ getMonthlyReports; },
|
/* harmony export */ getMonthlyReports: function() { return /* binding */ getMonthlyReports; },
|
||||||
/* harmony export */ getMonthlyStatistics: function() { return /* binding */ getMonthlyStatistics; },
|
/* harmony export */ getMonthlyStatistics: function() { return /* binding */ getMonthlyStatistics; },
|
||||||
|
/* harmony export */ getMyGroupProfile: function() { return /* binding */ getMyGroupProfile; },
|
||||||
/* harmony export */ getOrganizationDepartmentMembers: function() { return /* binding */ getOrganizationDepartmentMembers; },
|
/* harmony export */ getOrganizationDepartmentMembers: function() { return /* binding */ getOrganizationDepartmentMembers; },
|
||||||
/* harmony export */ getOrganizationDepartments: function() { return /* binding */ getOrganizationDepartments; },
|
/* harmony export */ getOrganizationDepartments: function() { return /* binding */ getOrganizationDepartments; },
|
||||||
/* harmony export */ getOrganizationMembers: function() { return /* binding */ getOrganizationMembers; },
|
/* harmony export */ getOrganizationMembers: function() { return /* binding */ getOrganizationMembers; },
|
||||||
@@ -4176,6 +4177,7 @@ const updateMyGroupProfile = (topic, nickname, version) => imPut('/groups/' + en
|
|||||||
nickname,
|
nickname,
|
||||||
version
|
version
|
||||||
});
|
});
|
||||||
|
const getMyGroupProfile = topic => imGet('/groups/' + encodeURIComponent(topic) + '/members/me/profile');
|
||||||
const leaveGroup = topic => imPost('/groups/' + encodeURIComponent(topic) + '/leave', {});
|
const leaveGroup = topic => imPost('/groups/' + encodeURIComponent(topic) + '/leave', {});
|
||||||
const getGroupMembers = (topic, {
|
const getGroupMembers = (topic, {
|
||||||
query = '',
|
query = '',
|
||||||
@@ -11154,10 +11156,12 @@ function GroupSettings({
|
|||||||
}
|
}
|
||||||
function GroupProfile({
|
function GroupProfile({
|
||||||
topic,
|
topic,
|
||||||
|
myUserId,
|
||||||
onToast
|
onToast
|
||||||
}) {
|
}) {
|
||||||
const [group, setGroup] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(() => topic && (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_5__.readCachedData)('group:' + topic) || null);
|
const [group, setGroup] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(() => topic && (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_5__.readCachedData)('group:' + topic) || null);
|
||||||
const [loadError, setLoadError] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(false);
|
const [loadError, setLoadError] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(false);
|
||||||
|
const [myNickname, setMyNickname] = react__WEBPACK_IMPORTED_MODULE_0___default().useState('');
|
||||||
react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => {
|
react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => {
|
||||||
if (!topic) return;
|
if (!topic) return;
|
||||||
setGroup((0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_5__.readCachedData)('group:' + topic) || null);
|
setGroup((0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_5__.readCachedData)('group:' + topic) || null);
|
||||||
@@ -11169,6 +11173,12 @@ function GroupProfile({
|
|||||||
setLoadError(true);
|
setLoadError(true);
|
||||||
});
|
});
|
||||||
}, [topic]);
|
}, [topic]);
|
||||||
|
react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => {
|
||||||
|
if (!topic) return;
|
||||||
|
(0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.getMyGroupProfile)(topic).then(data => {
|
||||||
|
setMyNickname(data.nickname || '');
|
||||||
|
}).catch(() => {});
|
||||||
|
}, [topic]);
|
||||||
if (!group) return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", {
|
if (!group) return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", {
|
||||||
className: "group-page",
|
className: "group-page",
|
||||||
children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Header, {
|
children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Header, {
|
||||||
@@ -11184,6 +11194,7 @@ function GroupProfile({
|
|||||||
}, void 0, false)]
|
}, void 0, false)]
|
||||||
}, void 0, true);
|
}, void 0, true);
|
||||||
const canEdit = group.permissions && group.permissions.can_edit_profile;
|
const canEdit = group.permissions && group.permissions.can_edit_profile;
|
||||||
|
const nicknameLabel = myNickname || '未设置';
|
||||||
return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", {
|
return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", {
|
||||||
className: "group-page",
|
className: "group-page",
|
||||||
children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Header, {
|
children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Header, {
|
||||||
@@ -11204,11 +11215,21 @@ function GroupProfile({
|
|||||||
}, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Icon, {
|
}, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Icon, {
|
||||||
children: "chevron_right"
|
children: "chevron_right"
|
||||||
}, void 0, false)]
|
}, void 0, false)]
|
||||||
|
}, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("button", {
|
||||||
|
type: "button",
|
||||||
|
onClick: () => navigate('group-my-nickname', topic),
|
||||||
|
children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("span", {
|
||||||
|
children: "群昵称"
|
||||||
|
}, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("small", {
|
||||||
|
children: nicknameLabel
|
||||||
|
}, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Icon, {
|
||||||
|
children: "chevron_right"
|
||||||
|
}, void 0, false)]
|
||||||
}, void 0, true), canEdit ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("button", {
|
}, void 0, true), canEdit ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("button", {
|
||||||
type: "button",
|
type: "button",
|
||||||
onClick: () => navigate('group-nickname', topic),
|
onClick: () => navigate('group-nickname', topic),
|
||||||
children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("span", {
|
children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("span", {
|
||||||
children: "群昵称"
|
children: "群名称"
|
||||||
}, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("small", {
|
}, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("small", {
|
||||||
children: group.name
|
children: group.name
|
||||||
}, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Icon, {
|
}, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Icon, {
|
||||||
@@ -11216,7 +11237,7 @@ function GroupProfile({
|
|||||||
}, void 0, false)]
|
}, void 0, false)]
|
||||||
}, void 0, true) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", {
|
}, void 0, true) : (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("div", {
|
||||||
children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("span", {
|
children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("span", {
|
||||||
children: "群昵称"
|
children: "群名称"
|
||||||
}, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("small", {
|
}, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("small", {
|
||||||
children: group.name
|
children: group.name
|
||||||
}, void 0, false)]
|
}, void 0, false)]
|
||||||
@@ -11254,6 +11275,7 @@ function GroupProfile({
|
|||||||
}
|
}
|
||||||
function AvatarSheet({
|
function AvatarSheet({
|
||||||
topic,
|
topic,
|
||||||
|
myUserId,
|
||||||
tinode,
|
tinode,
|
||||||
onToast
|
onToast
|
||||||
}) {
|
}) {
|
||||||
@@ -12155,19 +12177,13 @@ function GroupDescriptionEditor({
|
|||||||
}
|
}
|
||||||
function MyNicknameEditor({
|
function MyNicknameEditor({
|
||||||
topic,
|
topic,
|
||||||
myUserId,
|
|
||||||
onToast
|
onToast
|
||||||
}) {
|
}) {
|
||||||
const [value, setValue] = react__WEBPACK_IMPORTED_MODULE_0___default().useState('');
|
const [value, setValue] = react__WEBPACK_IMPORTED_MODULE_0___default().useState('');
|
||||||
react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => {
|
react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => {
|
||||||
if (!topic || !myUserId) return;
|
if (!topic) return;
|
||||||
(0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.getGroupMembers)(topic, {
|
(0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.getMyGroupProfile)(topic).then(data => setValue(data.nickname || '')).catch(() => {});
|
||||||
query: ''
|
}, [topic]);
|
||||||
}).then(data => {
|
|
||||||
const me = (data.items || []).find(m => m.user_id === myUserId);
|
|
||||||
if (me) setValue(me.group_nickname || '');
|
|
||||||
}).catch(() => {});
|
|
||||||
}, [topic, myUserId]);
|
|
||||||
const save = () => {
|
const save = () => {
|
||||||
(0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.updateMyGroupProfile)(topic, value.trim(), 0).then(() => {
|
(0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.updateMyGroupProfile)(topic, value.trim(), 0).then(() => {
|
||||||
onToast('保存成功');
|
onToast('保存成功');
|
||||||
@@ -12243,9 +12259,11 @@ function GroupManagementView({
|
|||||||
onToast: setToast
|
onToast: setToast
|
||||||
}, void 0, false);else if (view === 'group-profile') content = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(GroupProfile, {
|
}, void 0, false);else if (view === 'group-profile') content = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(GroupProfile, {
|
||||||
topic: topic,
|
topic: topic,
|
||||||
|
myUserId: myUserId,
|
||||||
onToast: setToast
|
onToast: setToast
|
||||||
}, void 0, false);else if (view === 'group-avatar') content = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(AvatarSheet, {
|
}, void 0, false);else if (view === 'group-avatar') content = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(AvatarSheet, {
|
||||||
topic: topic,
|
topic: topic,
|
||||||
|
myUserId: myUserId,
|
||||||
tinode: tinode,
|
tinode: tinode,
|
||||||
onToast: setToast
|
onToast: setToast
|
||||||
}, void 0, false);else if (view === 'group-nickname') content = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(GroupNameEditor, {
|
}, void 0, false);else if (view === 'group-nickname') content = (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(GroupNameEditor, {
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user