修复会议详情页显示裸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: '待定'};
|
const RESPONSE_LABEL = {accepted: '已接受', declined: '已拒绝', tentative: '待定'};
|
||||||
|
|
||||||
// Meeting responses already come back with names resolved server-side (organizer.display_name,
|
// 这条只对 GET /meetings(列表)成立——实测确认只有列表接口会解析真实姓名,MeetingCard 只在
|
||||||
// participant.display_name/participant_names[]) -- confirmed against a real created meeting's
|
// 列表页使用,不需要额外查询。**创建/详情/更新/取消/我的回应这5个接口不会**(display_name
|
||||||
// response payload, so no separate getUserProfile lookups are needed here (unlike org-tree/report
|
// 恒等于裸 user_id,第一次记录这条时误以为"响应已带姓名解析"对所有会议接口都成立,被这次复测
|
||||||
// authors, which only ever return bare ids).
|
// 用真实创建的会议证伪)——MeetingDetail 复用的是这5个接口之一,接了 useUserNames 兜底。
|
||||||
function MeetingCard({meeting, myUserId, onRespond, onToast}) {
|
function MeetingCard({meeting, myUserId, onRespond, onToast}) {
|
||||||
const organizerName = (meeting.organizer && meeting.organizer.display_name) || meeting.organizer_display_name || meeting.organizer_id;
|
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('、');
|
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 myUserId = me && me.user_id;
|
||||||
const [busy, setBusy] = React.useState(false);
|
const [busy, setBusy] = React.useState(false);
|
||||||
const [loadError, setLoadError] = 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); });
|
const load = () => meetingId && getMeeting(meetingId).then(m => { writeCachedData('meeting:' + meetingId, m); setMeeting(m); }).catch(err => { onToast(err.message || '加载失败'); setLoadError(true); });
|
||||||
React.useEffect(() => {
|
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>
|
<header><span><small>{formatMeetingDate(new Date(meeting.start_at))} {formatTime(new Date(meeting.start_at))}</small>
|
||||||
<strong>会议主题:{meeting.title}</strong></span></header>
|
<strong>会议主题:{meeting.title}</strong></span></header>
|
||||||
<dl>
|
<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>
|
<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}
|
{meeting.location ? <div><dt>地点</dt><dd>{meeting.location}</dd></div> : null}
|
||||||
<div><dt>会议时间</dt><dd>{durationLabel(meeting.start_at, meeting.end_at)}</dd></div>
|
<div><dt>会议时间</dt><dd>{durationLabel(meeting.start_at, meeting.end_at)}</dd></div>
|
||||||
</dl>
|
</dl>
|
||||||
<ul className="meeting-participant-list">
|
<ul className="meeting-participant-list">
|
||||||
{(meeting.participants || []).map(p => <li key={p.user_id}>
|
{(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>
|
<em className={p.response}>{RESPONSE_LABEL[p.response] || '待确认'}</em>
|
||||||
</li>)}
|
</li>)}
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
+9
-2
@@ -20349,6 +20349,13 @@ function MeetingDetail({
|
|||||||
const myUserId = me && me.user_id;
|
const myUserId = me && me.user_id;
|
||||||
const [busy, setBusy] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(false);
|
const [busy, setBusy] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(false);
|
||||||
const [loadError, setLoadError] = 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 => {
|
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);
|
(0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_4__.writeCachedData)('meeting:' + meetingId, m);
|
||||||
setMeeting(m);
|
setMeeting(m);
|
||||||
@@ -20422,7 +20429,7 @@ function MeetingDetail({
|
|||||||
children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("dt", {
|
children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("dt", {
|
||||||
children: "发起人"
|
children: "发起人"
|
||||||
}, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("dd", {
|
}, 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, false)]
|
||||||
}, void 0, true), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("div", {
|
}, 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", {
|
children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("dt", {
|
||||||
@@ -20447,7 +20454,7 @@ function MeetingDetail({
|
|||||||
className: "meeting-participant-list",
|
className: "meeting-participant-list",
|
||||||
children: (meeting.participants || []).map(p => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("li", {
|
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: [(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", {
|
}, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxDEV)("em", {
|
||||||
className: p.response,
|
className: p.response,
|
||||||
children: RESPONSE_LABEL[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