修复会议详情页显示裸user_id的问题(第9章复测发现)
创建/详情/更新/取消/我的回应这5个会议接口的 organizer.display_name/participants[].display_name 实测恒等于裸 user_id,只有列表接口 GET /meetings 会真的解析姓名。之前的注释误以为"响应已带 姓名解析"对所有会议接口都成立(可能是当时只测过列表接口就下了结论),这次复测用真实创建的 会议逐个接口验证,证伪了这个假设。 MeetingDetail 接入已有的 useUserNames(日报/月报详情页已经在用同一套机制),发起人和参会人 姓名解析不出来时不再显示裸 uid。同时更正了 MeetingCard 上那条误导性注释,说清楚它只对列表 接口成立。 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
1d51e53a46
commit
d3d7e11b08
@@ -257,10 +257,10 @@ function durationLabel(startAt, endAt) {
|
||||
|
||||
const RESPONSE_LABEL = {accepted: '已接受', declined: '已拒绝', tentative: '待定'};
|
||||
|
||||
// Meeting responses already come back with names resolved server-side (organizer.display_name,
|
||||
// participant.display_name/participant_names[]) -- confirmed against a real created meeting's
|
||||
// response payload, so no separate getUserProfile lookups are needed here (unlike org-tree/report
|
||||
// authors, which only ever return bare ids).
|
||||
// 这条只对 GET /meetings(列表)成立——实测确认只有列表接口会解析真实姓名,MeetingCard 只在
|
||||
// 列表页使用,不需要额外查询。**创建/详情/更新/取消/我的回应这5个接口不会**(display_name
|
||||
// 恒等于裸 user_id,第一次记录这条时误以为"响应已带姓名解析"对所有会议接口都成立,被这次复测
|
||||
// 用真实创建的会议证伪)——MeetingDetail 复用的是这5个接口之一,接了 useUserNames 兜底。
|
||||
function MeetingCard({meeting, myUserId, onRespond, onToast}) {
|
||||
const organizerName = (meeting.organizer && meeting.organizer.display_name) || meeting.organizer_display_name || meeting.organizer_id;
|
||||
const attendeeNames = (meeting.participants || []).map(p => p.display_name || p.user_id).join('、');
|
||||
@@ -331,6 +331,17 @@ function MeetingDetail({hashParams, onToast}) {
|
||||
const myUserId = me && me.user_id;
|
||||
const [busy, setBusy] = React.useState(false);
|
||||
const [loadError, setLoadError] = React.useState(false);
|
||||
// 详情/创建/更新/取消/我的回应这5个接口的 organizer.display_name / participants[].display_name
|
||||
// 实测就是裸 user_id 本身(只有列表接口 GET /meetings 真的解析姓名)——上面 MeetingCard 那段
|
||||
// "响应已带姓名解析、不需要额外查询"的注释只对列表成立,本页面复用同一份 useUserNames 兜底
|
||||
// (日报/月报详情页已经在用同一套机制)。
|
||||
const participantIds = (meeting && meeting.participants || []).map(p => p.user_id);
|
||||
const nameIds = meeting ? [meeting.organizer_id, ...participantIds] : [];
|
||||
const resolvedNames = useUserNames(nameIds, myUserId);
|
||||
const nameFor = (id, fallback) => {
|
||||
if (fallback && fallback !== id) return fallback;
|
||||
return (id && resolvedNames[id]) || fallback || id;
|
||||
};
|
||||
|
||||
const load = () => meetingId && getMeeting(meetingId).then(m => { writeCachedData('meeting:' + meetingId, m); setMeeting(m); }).catch(err => { onToast(err.message || '加载失败'); setLoadError(true); });
|
||||
React.useEffect(() => {
|
||||
@@ -372,14 +383,14 @@ function MeetingDetail({hashParams, onToast}) {
|
||||
<header><span><small>{formatMeetingDate(new Date(meeting.start_at))} {formatTime(new Date(meeting.start_at))}</small>
|
||||
<strong>会议主题:{meeting.title}</strong></span></header>
|
||||
<dl>
|
||||
<div><dt>发起人</dt><dd>{(meeting.organizer && meeting.organizer.display_name) || meeting.organizer_display_name || meeting.organizer_id}</dd></div>
|
||||
<div><dt>发起人</dt><dd>{nameFor(meeting.organizer_id, (meeting.organizer && meeting.organizer.display_name) || meeting.organizer_display_name)}</dd></div>
|
||||
<div><dt>时间</dt><dd>{formatMeetingDate(new Date(meeting.start_at))} {formatTime(new Date(meeting.start_at))} - {formatTime(new Date(meeting.end_at))}</dd></div>
|
||||
{meeting.location ? <div><dt>地点</dt><dd>{meeting.location}</dd></div> : null}
|
||||
<div><dt>会议时间</dt><dd>{durationLabel(meeting.start_at, meeting.end_at)}</dd></div>
|
||||
</dl>
|
||||
<ul className="meeting-participant-list">
|
||||
{(meeting.participants || []).map(p => <li key={p.user_id}>
|
||||
<span>{p.display_name || p.user_id}</span>
|
||||
<span>{nameFor(p.user_id, p.display_name)}</span>
|
||||
<em className={p.response}>{RESPONSE_LABEL[p.response] || '待确认'}</em>
|
||||
</li>)}
|
||||
</ul>
|
||||
|
||||
+9
-2
@@ -20349,6 +20349,13 @@ function MeetingDetail({
|
||||
const myUserId = me && me.user_id;
|
||||
const [busy, setBusy] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(false);
|
||||
const [loadError, setLoadError] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(false);
|
||||
const participantIds = (meeting && meeting.participants || []).map(p => p.user_id);
|
||||
const nameIds = meeting ? [meeting.organizer_id, ...participantIds] : [];
|
||||
const resolvedNames = useUserNames(nameIds, myUserId);
|
||||
const nameFor = (id, fallback) => {
|
||||
if (fallback && fallback !== id) return fallback;
|
||||
return id && resolvedNames[id] || fallback || id;
|
||||
};
|
||||
const load = () => meetingId && (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_3__.getMeeting)(meetingId).then(m => {
|
||||
(0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_4__.writeCachedData)('meeting:' + meetingId, m);
|
||||
setMeeting(m);
|
||||
@@ -20422,7 +20429,7 @@ function MeetingDetail({
|
||||
children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("dt", {
|
||||
children: "发起人"
|
||||
}, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("dd", {
|
||||
children: meeting.organizer && meeting.organizer.display_name || meeting.organizer_display_name || meeting.organizer_id
|
||||
children: nameFor(meeting.organizer_id, meeting.organizer && meeting.organizer.display_name || meeting.organizer_display_name)
|
||||
}, void 0, false)]
|
||||
}, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("div", {
|
||||
children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("dt", {
|
||||
@@ -20447,7 +20454,7 @@ function MeetingDetail({
|
||||
className: "meeting-participant-list",
|
||||
children: (meeting.participants || []).map(p => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("li", {
|
||||
children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("span", {
|
||||
children: p.display_name || p.user_id
|
||||
children: nameFor(p.user_id, p.display_name)
|
||||
}, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("em", {
|
||||
className: p.response,
|
||||
children: RESPONSE_LABEL[p.response] || '待确认'
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user