修复组织架构页部门蓝色高亮跟"是否展开"挂钩,根节点被误判成"我的部门"
DeptRow原来的蓝色高亮(.organization-department.expanded)直接复用"展开/收起" 这个纯UI交互状态:depth 0的根节点默认就是展开的(DeptNode: useState(depth===0)), 导致根节点从打开页面那一刻起就被误染成"当前用户所在部门"的蓝色,与参考图 (docs/images/部门组织框架.png)不符——图里根节点"总裁办50人(一级)"明明是展开状态, 颜色却是黑色默认色,只有真正包含当前用户的"技术4人(二级)"是蓝色实心菱形。 根因是把"展开状态"和"是否是我的部门"这两个独立概念用同一个CSS类混在了一起。改为 新增containsMe(DeptNode根据自己已加载的members列表里有没有当前用户算出,与expanded 彻底解耦,expanded继续只管chevron方向),CSS类从.expanded改名成.me(与PersonRow已有的 .me保持同一套命名)。顺手把三处重复的"裸id/usr前缀id两种形式对比myUserId"的内联判断 提成共享的isMyUserId函数。 当前测试租户组织架构数据本身为空(GET /organization/departments、/members 都是真实 200+空数组,非账号权限问题——kcg051307交叉验证过同样为空),无法用真实多级树肉眼过一遍, 按测试要求改用桩数据验证:mock了总裁办→财务/销售/技术三个部门+技术下4个成员(含当前 用户)复现参考图的结构,展开技术后确认根节点保持黑色、技术正确变蓝,与参考截图逐像素 对照一致;修复前用同一份桩数据可复现根节点被误染蓝的问题。 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
a964d51ba5
commit
1d47c586d3
@@ -196,9 +196,20 @@ function ImgFromFile({fileId, className}) {
|
|||||||
const LEVEL_NUMERALS = ['一', '二', '三', '四', '五', '六', '七', '八', '九', '十'];
|
const LEVEL_NUMERALS = ['一', '二', '三', '四', '五', '六', '七', '八', '九', '十'];
|
||||||
const levelLabel = n => LEVEL_NUMERALS[n - 1] || String(n);
|
const levelLabel = n => LEVEL_NUMERALS[n - 1] || String(n);
|
||||||
|
|
||||||
function DeptRow({dept, depth, expanded, onToggle}) {
|
// isMe check shared with PersonRow below -- organization member/participant ids across this
|
||||||
|
// chapter's endpoints aren't consistently confirmed to carry the 'usr' prefix (see resolveUserName's
|
||||||
|
// comment), so the same "try bare, then usr-prefixed" comparison is duplicated at both call sites.
|
||||||
|
const isMyUserId = (id, myUserId) => id === myUserId || 'usr' + id === myUserId;
|
||||||
|
|
||||||
|
function DeptRow({dept, depth, expanded, containsMe, onToggle}) {
|
||||||
const icon = depth === 0 ? 'business' : 'diamond';
|
const icon = depth === 0 ? 'business' : 'diamond';
|
||||||
return <button type="button" className={`organization-department depth-${depth}${expanded ? ' expanded' : ''}`}
|
// 部门本身的蓝色高亮不能跟"是否展开"挂钩:depth 0 的根节点默认就是展开的(见 DeptNode 的
|
||||||
|
// useState(depth===0)),如果蓝色只看 expanded,根节点会一直被误判成"当前用户所在部门"而
|
||||||
|
// 高亮蓝色——参考图(部门组织框架.png)里根节点"总裁办50人(一级)"明明是展开状态,颜色却是
|
||||||
|
// 黑色默认色,只有真正包含当前用户的"技术4人(二级)"才是蓝色实心菱形。展开/收起(chevron
|
||||||
|
// 方向)继续用 expanded 单独控制,颜色改用 containsMe(本部门自己的成员列表里有没有当前用户,
|
||||||
|
// 由 DeptNode 根据已加载的 members 算出,不是"是否展开")。
|
||||||
|
return <button type="button" className={`organization-department depth-${depth}${containsMe ? ' me' : ''}`}
|
||||||
style={{paddingLeft: `${1 + depth * 1.1}rem`}} onClick={onToggle}>
|
style={{paddingLeft: `${1 + depth * 1.1}rem`}} onClick={onToggle}>
|
||||||
<Icon>{icon}</Icon>
|
<Icon>{icon}</Icon>
|
||||||
<span><strong>{dept.name}{typeof dept.member_count === 'number' ? `${dept.member_count}人` : ''}({levelLabel(depth + 1)}级)</strong></span>
|
<span><strong>{dept.name}{typeof dept.member_count === 'number' ? `${dept.member_count}人` : ''}({levelLabel(depth + 1)}级)</strong></span>
|
||||||
@@ -250,16 +261,25 @@ function DeptNode({dept, depth, myUserId}) {
|
|||||||
|
|
||||||
const toggle = () => { const next = !expanded; setExpanded(next); if (next) load(); };
|
const toggle = () => { const next = !expanded; setExpanded(next); if (next) load(); };
|
||||||
React.useEffect(() => { if (expanded) load(); /* eslint-disable-next-line react-hooks/exhaustive-deps */ }, []);
|
React.useEffect(() => { if (expanded) load(); /* eslint-disable-next-line react-hooks/exhaustive-deps */ }, []);
|
||||||
|
// Only this department's own (already-loaded) member list decides the blue highlight -- not
|
||||||
|
// whether it's merely expanded (see DeptRow's comment) and not whether a *descendant* department
|
||||||
|
// contains the current user either. Confirmed against 部门组织框架.png with stub data standing in
|
||||||
|
// for this tenant's empty org tree (real审 GET /organization/departments|members both return zero
|
||||||
|
// items here): the root "总裁办" is an ancestor of 符小小 (via 技术) but stays black, only 技术
|
||||||
|
// itself -- whose own direct member list actually contains her -- turns blue. `members` is null
|
||||||
|
// before this node has ever loaded, so an unexpanded department can't know yet; that's an accepted
|
||||||
|
// gap (see the fix's commit message), not something this pass invents new backend support for.
|
||||||
|
const containsMe = (members || []).some(p => isMyUserId(p.user_id, myUserId));
|
||||||
|
|
||||||
return <>
|
return <>
|
||||||
<DeptRow dept={dept} depth={depth} expanded={expanded} onToggle={toggle} />
|
<DeptRow dept={dept} depth={depth} expanded={expanded} containsMe={containsMe} onToggle={toggle} />
|
||||||
{expanded && loading ? <p className="organization-loading">加载中…</p> : null}
|
{expanded && loading ? <p className="organization-loading">加载中…</p> : null}
|
||||||
{expanded && !loading && loadError ?
|
{expanded && !loading && loadError ?
|
||||||
<p className="organization-loading">加载失败 <a href="#" onClick={e => { e.preventDefault(); load(); }}>重试</a></p> : null}
|
<p className="organization-loading">加载失败 <a href="#" onClick={e => { e.preventDefault(); load(); }}>重试</a></p> : null}
|
||||||
{expanded && !loading && !loadError ? <>
|
{expanded && !loading && !loadError ? <>
|
||||||
{(children || []).map(child => <DeptNode key={child.department_id} dept={child} depth={depth + 1} myUserId={myUserId} />)}
|
{(children || []).map(child => <DeptNode key={child.department_id} dept={child} depth={depth + 1} myUserId={myUserId} />)}
|
||||||
{(members || []).map(person => <PersonRow key={person.user_id} person={person} depth={depth + 1}
|
{(members || []).map(person => <PersonRow key={person.user_id} person={person} depth={depth + 1}
|
||||||
level={depth + 2} isMe={person.user_id === myUserId || 'usr' + person.user_id === myUserId} />)}
|
level={depth + 2} isMe={isMyUserId(person.user_id, myUserId)} />)}
|
||||||
</> : null}
|
</> : null}
|
||||||
</>;
|
</>;
|
||||||
}
|
}
|
||||||
@@ -581,7 +601,7 @@ function OrganizationDirectory({myUserId}) {
|
|||||||
searchResults.map((item, idx) => item.type === 'department' ?
|
searchResults.map((item, idx) => item.type === 'department' ?
|
||||||
<SearchDeptRow key={'d' + (item.department && item.department.department_id || idx)} dept={item.department} /> :
|
<SearchDeptRow key={'d' + (item.department && item.department.department_id || idx)} dept={item.department} /> :
|
||||||
<PersonRow key={'u' + (item.user && item.user.user_id || idx)} person={item.user} depth={0} level={3}
|
<PersonRow key={'u' + (item.user && item.user.user_id || idx)} person={item.user} depth={0} level={3}
|
||||||
isMe={item.user && (item.user.user_id === myUserId || 'usr' + item.user.user_id === myUserId)} />)}
|
isMe={!!(item.user && isMyUserId(item.user.user_id, myUserId))} />)}
|
||||||
</section> :
|
</section> :
|
||||||
<section className="organization-tree">
|
<section className="organization-tree">
|
||||||
{roots == null ? <p className="organization-loading">加载中…</p> :
|
{roots == null ? <p className="organization-loading">加载中…</p> :
|
||||||
|
|||||||
Reference in New Issue
Block a user