fix(export): hide duplicate session table scrollbar

This commit is contained in:
aits2026
2026-03-10 14:39:23 +08:00
parent 24c47c3aa3
commit 0f3ecdc4ee
2 changed files with 136 additions and 126 deletions

View File

@@ -1717,6 +1717,7 @@
} }
.table-wrap { .table-wrap {
--contacts-native-scrollbar-compensation: 18px;
--contacts-row-height: 76px; --contacts-row-height: 76px;
--contacts-default-visible-rows: 10; --contacts-default-visible-rows: 10;
--contacts-default-list-height: calc(var(--contacts-row-height) * var(--contacts-default-visible-rows)); --contacts-default-list-height: calc(var(--contacts-row-height) * var(--contacts-default-visible-rows));
@@ -1740,12 +1741,19 @@
} }
.table-wrap { .table-wrap {
.table-scroll-shell {
overflow: hidden;
}
.table-scroll-viewport { .table-scroll-viewport {
min-height: 0; min-height: 0;
overflow-x: auto; overflow-x: auto;
overflow-y: visible; overflow-y: visible;
scrollbar-width: none; scrollbar-width: none;
-ms-overflow-style: none;
background: var(--bg-secondary); background: var(--bg-secondary);
padding-bottom: var(--contacts-native-scrollbar-compensation);
margin-bottom: calc(-1 * var(--contacts-native-scrollbar-compensation));
&::-webkit-scrollbar { &::-webkit-scrollbar {
display: none; display: none;

View File

@@ -6371,137 +6371,139 @@ function ExportPage() {
</div> </div>
</div> </div>
<div <div className="table-scroll-shell">
ref={contactsHorizontalViewportRef} <div
className="table-scroll-viewport" ref={contactsHorizontalViewportRef}
onScroll={handleContactsHorizontalViewportScroll} className="table-scroll-viewport"
> onScroll={handleContactsHorizontalViewportScroll}
<div ref={contactsHorizontalContentRef} className="table-scroll-content"> >
<div className="session-table-sticky"> <div ref={contactsHorizontalContentRef} className="table-scroll-content">
{contactsList.length > 0 && isContactsListLoading && ( <div className="session-table-sticky">
<div className="table-stage-hint"> {contactsList.length > 0 && isContactsListLoading && (
<Loader2 size={14} className="spin" /> <div className="table-stage-hint">
<Loader2 size={14} className="spin" />
</div>
)} </div>
)}
{hasFilteredContacts && ( {hasFilteredContacts && (
<div <div
className={`contacts-list-header ${hasContactsHorizontalOverflow ? 'is-draggable' : ''} ${isContactsHeaderDragging ? 'is-dragging' : ''}`} className={`contacts-list-header ${hasContactsHorizontalOverflow ? 'is-draggable' : ''} ${isContactsHeaderDragging ? 'is-dragging' : ''}`}
onPointerDown={handleContactsHeaderPointerDown} onPointerDown={handleContactsHeaderPointerDown}
onPointerMove={handleContactsHeaderPointerMove} onPointerMove={handleContactsHeaderPointerMove}
onPointerUp={handleContactsHeaderPointerUp} onPointerUp={handleContactsHeaderPointerUp}
onPointerCancel={handleContactsHeaderPointerCancel} onPointerCancel={handleContactsHeaderPointerCancel}
> >
<span className="contacts-list-header-select"> <span className="contacts-list-header-select">
<button <button
className={`select-icon-btn ${isAllVisibleSelected ? 'checked' : ''}`} className={`select-icon-btn ${isAllVisibleSelected ? 'checked' : ''}`}
type="button" type="button"
onClick={toggleSelectAllVisible} onClick={toggleSelectAllVisible}
disabled={visibleSelectableCount === 0} disabled={visibleSelectableCount === 0}
title={isAllVisibleSelected ? '取消全选当前筛选联系人' : '全选当前筛选联系人'} title={isAllVisibleSelected ? '取消全选当前筛选联系人' : '全选当前筛选联系人'}
> >
{isAllVisibleSelected ? <CheckSquare size={16} /> : <Square size={16} />} {isAllVisibleSelected ? <CheckSquare size={16} /> : <Square size={16} />}
</button> </button>
</span> </span>
<span className="contacts-list-header-main"> <span className="contacts-list-header-main">
<span className="contacts-list-header-main-label">{contactsHeaderMainLabel}</span> <span className="contacts-list-header-main-label">{contactsHeaderMainLabel}</span>
</span> </span>
<span className="contacts-list-header-count"></span> <span className="contacts-list-header-count"></span>
<span className="contacts-list-header-media"></span> <span className="contacts-list-header-media"></span>
<span className="contacts-list-header-media"></span> <span className="contacts-list-header-media"></span>
<span className="contacts-list-header-media"></span> <span className="contacts-list-header-media"></span>
<span className="contacts-list-header-media"></span> <span className="contacts-list-header-media"></span>
{shouldShowSnsColumn && ( {shouldShowSnsColumn && (
<span className="contacts-list-header-media"></span> <span className="contacts-list-header-media"></span>
)}
{shouldShowMutualFriendsColumn && (
<span className="contacts-list-header-media"></span>
)}
<span className="contacts-list-header-actions">
{selectedCount > 0 && (
<>
<button
className="selection-clear-btn"
type="button"
onClick={clearSelection}
>
</button>
<button
className="selection-export-btn"
type="button"
onClick={openBatchExport}
>
<span></span>
<span className="selection-export-count">{selectedCount}</span>
</button>
</>
)} )}
</span> {shouldShowMutualFriendsColumn && (
<span className="contacts-list-header-media"></span>
)}
<span className="contacts-list-header-actions">
{selectedCount > 0 && (
<>
<button
className="selection-clear-btn"
type="button"
onClick={clearSelection}
>
</button>
<button
className="selection-export-btn"
type="button"
onClick={openBatchExport}
>
<span></span>
<span className="selection-export-count">{selectedCount}</span>
</button>
</>
)}
</span>
</div>
)}
</div>
{contactsList.length === 0 && contactsLoadIssue ? (
<div className="load-issue-state">
<div className="issue-card">
<div className="issue-title">
<AlertTriangle size={18} />
<span>{contactsLoadIssue.title}</span>
</div>
<p className="issue-message">{contactsLoadIssue.message}</p>
<p className="issue-reason">{contactsLoadIssue.reason}</p>
<ul className="issue-hints">
<li>1</li>
<li>2contact.db </li>
<li>3 IPC </li>
</ul>
<div className="issue-actions">
<button className="issue-btn primary" onClick={() => void loadContactsList()}>
<RefreshCw size={14} />
<span></span>
</button>
<button className="issue-btn" onClick={() => setShowContactsDiagnostics(prev => !prev)}>
<ClipboardList size={14} />
<span>{showContactsDiagnostics ? '收起诊断详情' : '查看诊断详情'}</span>
</button>
<button className="issue-btn" onClick={copyContactsDiagnostics}>
<span></span>
</button>
</div>
{showContactsDiagnostics && (
<pre className="issue-diagnostics">{contactsDiagnosticsText}</pre>
)}
</div>
</div>
) : isContactsListLoading && contactsList.length === 0 ? (
<div className="loading-state">
<Loader2 size={32} className="spin" />
<span>...</span>
</div>
) : !hasFilteredContacts ? (
<div className="empty-state">
<span></span>
</div>
) : (
<div
className="contacts-list"
onWheelCapture={handleContactsListWheelCapture}
>
<Virtuoso
ref={contactsVirtuosoRef}
className="contacts-virtuoso"
data={filteredContacts}
computeItemKey={(_, contact) => contact.username}
fixedItemHeight={76}
itemContent={renderContactRow}
rangeChanged={handleContactsRangeChanged}
atTopStateChange={setIsContactsListAtTop}
overscan={420}
/>
</div> </div>
)} )}
</div> </div>
{contactsList.length === 0 && contactsLoadIssue ? (
<div className="load-issue-state">
<div className="issue-card">
<div className="issue-title">
<AlertTriangle size={18} />
<span>{contactsLoadIssue.title}</span>
</div>
<p className="issue-message">{contactsLoadIssue.message}</p>
<p className="issue-reason">{contactsLoadIssue.reason}</p>
<ul className="issue-hints">
<li>1</li>
<li>2contact.db </li>
<li>3 IPC </li>
</ul>
<div className="issue-actions">
<button className="issue-btn primary" onClick={() => void loadContactsList()}>
<RefreshCw size={14} />
<span></span>
</button>
<button className="issue-btn" onClick={() => setShowContactsDiagnostics(prev => !prev)}>
<ClipboardList size={14} />
<span>{showContactsDiagnostics ? '收起诊断详情' : '查看诊断详情'}</span>
</button>
<button className="issue-btn" onClick={copyContactsDiagnostics}>
<span></span>
</button>
</div>
{showContactsDiagnostics && (
<pre className="issue-diagnostics">{contactsDiagnosticsText}</pre>
)}
</div>
</div>
) : isContactsListLoading && contactsList.length === 0 ? (
<div className="loading-state">
<Loader2 size={32} className="spin" />
<span>...</span>
</div>
) : !hasFilteredContacts ? (
<div className="empty-state">
<span></span>
</div>
) : (
<div
className="contacts-list"
onWheelCapture={handleContactsListWheelCapture}
>
<Virtuoso
ref={contactsVirtuosoRef}
className="contacts-virtuoso"
data={filteredContacts}
computeItemKey={(_, contact) => contact.username}
fixedItemHeight={76}
itemContent={renderContactRow}
rangeChanged={handleContactsRangeChanged}
atTopStateChange={setIsContactsListAtTop}
overscan={420}
/>
</div>
)}
</div> </div>
</div> </div>