feat(export): use window-level detail drawer overlay

This commit is contained in:
tisonhuang
2026-03-02 13:52:54 +08:00
parent 89f0758fbb
commit 1347136b54
3 changed files with 47 additions and 22 deletions

View File

@@ -417,13 +417,13 @@ class SnsService {
) )
let rows = primary.rows let rows = primary.rows
if (!primary.success || !rows) { if (!primary.success || !rows || rows.length === 0) {
const fallback = await wcdbService.execQuery( const fallback = await wcdbService.execQuery(
'sns', 'sns',
null, null,
"SELECT userName AS username, COUNT(1) AS total FROM SnsTimeLine WHERE userName IS NOT NULL AND userName <> '' GROUP BY userName" "SELECT userName AS username, COUNT(1) AS total FROM SnsTimeLine WHERE userName IS NOT NULL AND userName <> '' GROUP BY userName"
) )
if (!fallback.success || !fallback.rows) { if (!fallback.success || !fallback.rows || fallback.rows.length === 0) {
return { success: false, error: primary.error || fallback.error || '获取朋友圈联系人条数失败' } return { success: false, error: primary.error || fallback.error || '获取朋友圈联系人条数失败' }
} }
rows = fallback.rows rows = fallback.rows
@@ -433,7 +433,11 @@ class SnsService {
const usernameRaw = row?.username ?? row?.user_name ?? row?.userName ?? '' const usernameRaw = row?.username ?? row?.user_name ?? row?.userName ?? ''
const username = typeof usernameRaw === 'string' ? usernameRaw.trim() : String(usernameRaw || '').trim() const username = typeof usernameRaw === 'string' ? usernameRaw.trim() : String(usernameRaw || '').trim()
if (!username) continue if (!username) continue
counts[username] = this.parseCountValue(row) const countRaw = row?.total ?? row?.count ?? row?.cnt
const parsedCount = Number(countRaw)
counts[username] = Number.isFinite(parsedCount) && parsedCount > 0
? Math.floor(parsedCount)
: this.parseCountValue(row)
} }
return { success: true, data: counts } return { success: true, data: counts }
} catch (e) { } catch (e) {

View File

@@ -573,7 +573,6 @@
display: flex; display: flex;
flex: 1; flex: 1;
min-height: 0; min-height: 0;
gap: 10px;
.table-wrap { .table-wrap {
flex: 1; flex: 1;
@@ -1015,15 +1014,25 @@
} }
} }
.export-session-detail-overlay {
position: fixed;
inset: 0;
z-index: 1100;
display: flex;
justify-content: flex-end;
background: rgba(15, 23, 42, 0.24);
}
.export-session-detail-panel { .export-session-detail-panel {
width: 300px; width: min(360px, calc(100vw - 16px));
min-width: 300px; height: 100vh;
border: 1px solid var(--border-color); border-left: 1px solid var(--border-color);
border-radius: 10px; border-radius: 0;
background: var(--card-bg); background: var(--card-bg);
display: flex; display: flex;
flex-direction: column; flex-direction: column;
overflow: hidden; overflow: hidden;
box-shadow: -12px 0 30px rgba(0, 0, 0, 0.18);
.detail-header { .detail-header {
display: flex; display: flex;
@@ -1615,16 +1624,6 @@
.media-check-grid { .media-check-grid {
grid-template-columns: repeat(2, minmax(120px, 1fr)); grid-template-columns: repeat(2, minmax(120px, 1fr));
} }
.session-table-layout.with-detail {
flex-direction: column;
}
.export-session-detail-panel {
width: 100%;
min-width: 0;
max-height: 360px;
}
} }
@media (max-width: 720px) { @media (max-width: 720px) {
@@ -1647,6 +1646,6 @@
} }
.export-session-detail-panel { .export-session-detail-panel {
max-height: 320px; width: calc(100vw - 12px);
} }
} }

View File

@@ -2096,6 +2096,17 @@ function ExportPage() {
void loadSessionDetail(sessionId) void loadSessionDetail(sessionId)
}, [loadSessionDetail]) }, [loadSessionDetail])
useEffect(() => {
if (!showSessionDetailPanel) return
const handleKeyDown = (event: KeyboardEvent) => {
if (event.key === 'Escape') {
setShowSessionDetailPanel(false)
}
}
window.addEventListener('keydown', handleKeyDown)
return () => window.removeEventListener('keydown', handleKeyDown)
}, [showSessionDetailPanel])
const handleCopyDetailField = useCallback(async (text: string, field: string) => { const handleCopyDetailField = useCallback(async (text: string, field: string) => {
try { try {
await navigator.clipboard.writeText(text) await navigator.clipboard.writeText(text)
@@ -2581,7 +2592,7 @@ function ExportPage() {
</div> </div>
)} )}
<div className={`session-table-layout ${showSessionDetailPanel ? 'with-detail' : ''}`}> <div className="session-table-layout">
<div className="table-wrap"> <div className="table-wrap">
{contactsList.length === 0 && contactsLoadIssue ? ( {contactsList.length === 0 && contactsLoadIssue ? (
<div className="load-issue-state"> <div className="load-issue-state">
@@ -2698,7 +2709,17 @@ function ExportPage() {
</div> </div>
{showSessionDetailPanel && ( {showSessionDetailPanel && (
<aside className="export-session-detail-panel"> <div
className="export-session-detail-overlay"
onClick={() => setShowSessionDetailPanel(false)}
>
<aside
className="export-session-detail-panel"
role="dialog"
aria-modal="true"
aria-label="会话详情"
onClick={(event) => event.stopPropagation()}
>
<div className="detail-header"> <div className="detail-header">
<h4></h4> <h4></h4>
<button className="close-btn" onClick={() => setShowSessionDetailPanel(false)}> <button className="close-btn" onClick={() => setShowSessionDetailPanel(false)}>
@@ -2884,7 +2905,8 @@ function ExportPage() {
) : ( ) : (
<div className="detail-empty"></div> <div className="detail-empty"></div>
)} )}
</aside> </aside>
</div>
)} )}
</div> </div>
</div> </div>