补上组织架构部门蓝色高亮修复遗漏的CSS改动(.expanded重命名为.me)

上一个commit(1d47c586)只提交了JSX那部分(DeptRow/DeptNode改用containsMe),
对应的CSS改名(.organization-department.expanded → .me)当时被同一文件里
其他并发改动的暂存操作顶掉了,没有一起进去,导致上一commit单看JSX是完整的,
但CSS选择器名字还没改,实际不生效。这里补上,两个commit合起来才是完整修复。

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Your Name
2026-09-06 13:36:27 +08:00
co-authored by Claude Sonnet 5
parent 1d47c586d3
commit 1228d6a534
2 changed files with 87 additions and 17 deletions
+9 -2
View File
@@ -1590,11 +1590,18 @@
font-size: 1.3rem; font-size: 1.3rem;
} }
.organization-department.expanded { /* Renamed from .expanded -- this rule drives the blue "this is my department" highlight from
docs/images/部门组织框架.png (only the department the current user directly belongs to, e.g.
"技术4人" in the reference, not every expanded node -- the reference's always-expanded root
"总裁办50人" stays plain black). Was keyed off the same class as the expand/collapse chevron
state, which colored ANY expanded department blue including the root, on every page load, with
nothing to do with where the current user actually is -- see workplace-collaboration-view.jsx's
DeptRow/DeptNode comments for the live repro (via stub data, this tenant's real org tree is empty). */
.organization-department.me {
color: #2094f3; color: #2094f3;
} }
.organization-department.expanded > .material-icons:first-child { .organization-department.me > .material-icons:first-child {
color: #2094f3; color: #2094f3;
} }
+78 -15
View File
@@ -69,6 +69,7 @@ class CallPanel extends React.PureComponent {
this.isOutgoingCall = props.callState == CALL_STATE_OUTGOING_INITATED; this.isOutgoingCall = props.callState == CALL_STATE_OUTGOING_INITATED;
this.containerRef = React.createRef(); this.containerRef = React.createRef();
this.selfBoxRef = React.createRef();
this.localRef = React.createRef(); this.localRef = React.createRef();
this.remoteRef = React.createRef(); this.remoteRef = React.createRef();
@@ -125,6 +126,10 @@ class CallPanel extends React.PureComponent {
this.handleDataChannelClose = this.handleDataChannelClose.bind(this); this.handleDataChannelClose = this.handleDataChannelClose.bind(this);
this.bounds = {}; this.bounds = {};
// Which element the in-progress drag is moving: 'container' for the whole minimized bubble,
// 'self' for just the local self-view preview box inside a fullscreen connected video call.
// Null when no drag is in progress (also doubles as the pointermove/pointerup no-op guard).
this.dragTarget = null;
this.dragStart = (event) => { this.dragStart = (event) => {
if (!event.target.closest('.draggable')) { if (!event.target.closest('.draggable')) {
@@ -152,28 +157,73 @@ class CallPanel extends React.PureComponent {
const parent = el.offsetParent; const parent = el.offsetParent;
this.bounds.maxX = parent.offsetWidth; this.bounds.maxX = parent.offsetWidth;
this.bounds.maxY = parent.offsetHeight; this.bounds.maxY = parent.offsetHeight;
this.dragTarget = 'container';
return;
}
// Fullscreen connected video call: let the user drag their own small self-view preview
// out of the way instead of it being stuck wherever it defaults to (spec 8.9 "双方视频
// 通话中": "小窗应支持拖动且不能遮挡关键按钮"). Only relevant when the box actually exists
// (base.css hides it entirely for audio-only calls / while minimized via
// .call-party.self[disabled]) and only when the drag actually starts on that box, not on
// the peer's video/avatar card behind it.
if (!this.props.minimized && !this.state.audioOnly && this.selfBoxRef.current &&
event.target.closest('.call-party.self')) {
event.stopPropagation();
const el = this.selfBoxRef.current;
// Pointer events are captured on the outer container (same element the listeners below
// are attached to) rather than the box itself, purely so drag()/dragEnd() below have one
// consistent place to check hasPointerCapture() regardless of which element is moving.
this.containerRef.current.setPointerCapture(event.pointerId);
el.style.cursor = 'grabbing';
this.bounds.left = el.offsetLeft;
this.bounds.top = el.offsetTop;
this.bounds.width = el.offsetWidth;
this.bounds.height = el.offsetHeight;
// Switch from right/bottom CSS positioning to explicit left/top so drag() can move it freely.
el.style.right = 'auto';
el.style.bottom = 'auto';
el.style.left = `${this.bounds.left}px`;
el.style.top = `${this.bounds.top}px`;
const parent = el.offsetParent;
this.bounds.maxX = parent.offsetWidth;
this.bounds.maxY = parent.offsetHeight;
this.dragTarget = 'self';
} }
}; };
this.drag = (event) => { this.drag = (event) => {
event.stopPropagation(); event.stopPropagation();
const el = this.containerRef.current; const container = this.containerRef.current;
if (this.props.minimized && this.containerRef && el.hasPointerCapture(event.pointerId)) { if (!this.dragTarget || !container.hasPointerCapture(event.pointerId)) {
// Calculate new position. Restrict to the visible area of the parent element. return;
this.bounds.left = Math.min(Math.max(this.bounds.left + event.movementX, 0),
this.bounds.maxX - this.bounds.width);
this.bounds.top = Math.min(Math.max(this.bounds.top + event.movementY, 0),
this.bounds.maxY - this.bounds.height);
el.style.left = `${this.bounds.left}px`;
el.style.top = `${this.bounds.top}px`;
} }
const el = this.dragTarget == 'self' ? this.selfBoxRef.current : container;
if (!el) {
return;
}
// Calculate new position. Restrict to the visible area of the parent element.
this.bounds.left = Math.min(Math.max(this.bounds.left + event.movementX, 0),
this.bounds.maxX - this.bounds.width);
this.bounds.top = Math.min(Math.max(this.bounds.top + event.movementY, 0),
this.bounds.maxY - this.bounds.height);
el.style.left = `${this.bounds.left}px`;
el.style.top = `${this.bounds.top}px`;
}; };
this.dragEnd = (event) => { this.dragEnd = (event) => {
event.stopPropagation(); event.stopPropagation();
if (this.props.minimized && this.containerRef) { const container = this.containerRef.current;
this.containerRef.current.releasePointerCapture(event.pointerId); if (!this.dragTarget) {
this.containerRef.current.style.cursor = 'grab'; return;
} }
const el = this.dragTarget == 'self' ? this.selfBoxRef.current : container;
if (container && container.hasPointerCapture(event.pointerId)) {
container.releasePointerCapture(event.pointerId);
}
if (el) {
el.style.cursor = 'grab';
}
this.dragTarget = null;
}; };
// dragStart's inline left/top/right (set the first time the minimized bubble is dragged, see // dragStart's inline left/top/right (set the first time the minimized bubble is dragged, see
// above) always win over base.css's #video-container.minimized:not(.audio-minimized) mobile // above) always win over base.css's #video-container.minimized:not(.audio-minimized) mobile
@@ -183,14 +233,26 @@ class CallPanel extends React.PureComponent {
// bubble pinned at its old desktop-width position/size instead of docking as the intended // bubble pinned at its old desktop-width position/size instead of docking as the intended
// mobile full-width strip. Clearing the manual offsets once the mobile breakpoint applies lets // mobile full-width strip. Clearing the manual offsets once the mobile breakpoint applies lets
// the stylesheet rule take back over; harmless (a no-op) whenever nothing was ever dragged. // the stylesheet rule take back over; harmless (a no-op) whenever nothing was ever dragged.
// Same idea for the self-view box's own drag above, keyed off its own (768px) breakpoint
// (base.css ".call-party.self" mobile rule only ever touches `bottom`, but a stale inline
// left/top from a desktop-width drag would still leave it sitting at the wrong height once
// that rule's extra bottom clearance was meant to apply).
this.handleWindowResize = () => { this.handleWindowResize = () => {
if (this.props.minimized && this.containerRef && this.containerRef.current && if (this.props.minimized && this.containerRef.current &&
window.matchMedia('(width<=640px)').matches) { window.matchMedia('(width<=640px)').matches) {
const el = this.containerRef.current; const el = this.containerRef.current;
el.style.removeProperty('left'); el.style.removeProperty('left');
el.style.removeProperty('right'); el.style.removeProperty('right');
el.style.removeProperty('top'); el.style.removeProperty('top');
} }
if (!this.props.minimized && this.selfBoxRef.current &&
window.matchMedia('(width<=768px)').matches) {
const el = this.selfBoxRef.current;
el.style.removeProperty('left');
el.style.removeProperty('right');
el.style.removeProperty('top');
el.style.removeProperty('bottom');
}
}; };
} }
@@ -893,7 +955,8 @@ class CallPanel extends React.PureComponent {
{connected && {connected &&
<div className="call-duration">{formatElapsedTime(this.state.elapsedSeconds)}</div>} <div className="call-duration">{formatElapsedTime(this.state.elapsedSeconds)}</div>}
<div id="video-container-panel" className="draggable"> <div id="video-container-panel" className="draggable">
<div className="call-party self" disabled={this.state.audioOnly || this.props.minimized}> <div className="call-party self" ref={this.selfBoxRef}
disabled={this.state.audioOnly || this.props.minimized}>
<video ref={this.localRef} autoPlay muted playsInline /> <video ref={this.localRef} autoPlay muted playsInline />
<div className="caller-name inactive"> <div className="caller-name inactive">
<FormattedMessage id="calls_you_label" <FormattedMessage id="calls_you_label"