feat(export): add batch export section titles with info popovers

This commit is contained in:
tisonhuang
2026-03-05 10:13:58 +08:00
parent 0247b02f6e
commit 3c231a7fde
2 changed files with 151 additions and 0 deletions

View File

@@ -20,6 +20,73 @@
flex-shrink: 0; flex-shrink: 0;
} }
.export-section-title-row {
display: flex;
align-items: center;
justify-content: space-between;
gap: 10px;
}
.export-section-title {
margin: 0;
font-size: 15px;
font-weight: 600;
color: var(--text-primary);
}
.section-info-tooltip {
position: relative;
flex-shrink: 0;
}
.section-info-trigger {
width: 24px;
height: 24px;
border-radius: 999px;
border: 1px solid var(--border-color);
background: var(--bg-secondary);
color: var(--text-tertiary);
cursor: pointer;
display: inline-flex;
align-items: center;
justify-content: center;
transition: border-color 0.15s ease, color 0.15s ease, background 0.15s ease;
&:hover,
&.active {
border-color: rgba(var(--primary-rgb), 0.45);
color: var(--primary);
background: rgba(var(--primary-rgb), 0.08);
}
}
.section-info-popover {
position: absolute;
top: calc(100% + 8px);
right: 0;
width: min(340px, calc(100vw - 40px));
border-radius: 10px;
border: 1px solid var(--border-color);
background: var(--bg-primary);
box-shadow: 0 14px 30px rgba(0, 0, 0, 0.2);
padding: 10px 12px;
z-index: 70;
h4 {
margin: 0;
font-size: 13px;
font-weight: 600;
color: var(--text-primary);
}
p {
margin: 6px 0 0;
font-size: 12px;
line-height: 1.55;
color: var(--text-secondary);
}
}
.global-export-controls { .global-export-controls {
background: var(--card-bg); background: var(--card-bg);
border: 1px solid var(--border-color); border: 1px solid var(--border-color);
@@ -2232,6 +2299,10 @@
} }
@media (max-width: 720px) { @media (max-width: 720px) {
.export-section-title {
font-size: 14px;
}
.table-wrap { .table-wrap {
--contacts-message-col-width: 104px; --contacts-message-col-width: 104px;
--contacts-action-col-width: 236px; --contacts-action-col-width: 236px;

View File

@@ -7,6 +7,7 @@ import {
Calendar, Calendar,
Check, Check,
CheckSquare, CheckSquare,
CircleHelp,
Copy, Copy,
Database, Database,
Download, Download,
@@ -801,6 +802,63 @@ const WriteLayoutSelector = memo(function WriteLayoutSelector({
) )
}) })
const SectionInfoTooltip = memo(function SectionInfoTooltip({
label,
heading,
messages
}: {
label: string
heading: string
messages: string[]
}) {
const [isOpen, setIsOpen] = useState(false)
const containerRef = useRef<HTMLDivElement | null>(null)
useEffect(() => {
if (!isOpen) return
const handleOutsideClick = (event: MouseEvent) => {
if (containerRef.current?.contains(event.target as Node)) return
setIsOpen(false)
}
const handleKeyDown = (event: KeyboardEvent) => {
if (event.key === 'Escape') {
setIsOpen(false)
}
}
document.addEventListener('mousedown', handleOutsideClick)
document.addEventListener('keydown', handleKeyDown)
return () => {
document.removeEventListener('mousedown', handleOutsideClick)
document.removeEventListener('keydown', handleKeyDown)
}
}, [isOpen])
return (
<div className="section-info-tooltip" ref={containerRef}>
<button
type="button"
className={`section-info-trigger ${isOpen ? 'active' : ''}`}
onClick={() => setIsOpen(prev => !prev)}
aria-label={`查看${label}说明`}
aria-expanded={isOpen}
>
<CircleHelp size={14} />
</button>
{isOpen && (
<div className="section-info-popover" role="dialog" aria-label={`${label}说明`}>
<h4>{heading}</h4>
{messages.map(message => (
<p key={message}>{message}</p>
))}
</div>
)}
</div>
)
})
interface TaskCenterModalProps { interface TaskCenterModalProps {
isOpen: boolean isOpen: boolean
tasks: ExportTask[] tasks: ExportTask[]
@@ -3700,6 +3758,17 @@ function ExportPage() {
onTogglePerfTask={toggleTaskPerfDetail} onTogglePerfTask={toggleTaskPerfDetail}
/> />
<div className="export-section-title-row">
<h3 className="export-section-title"></h3>
<SectionInfoTooltip
label="按类型批量导出"
heading="按类型批量导出说明"
messages={[
'按数据类型统一导出,适合横向汇总同类内容,比如集中导出图片、语音或视频。',
'发起前可先设置导出时间范围和格式,能减少无关数据,导出结果更聚焦。'
]}
/>
</div>
<div className="content-card-grid"> <div className="content-card-grid">
{contentCards.map(card => { {contentCards.map(card => {
const Icon = card.icon const Icon = card.icon
@@ -3758,6 +3827,17 @@ function ExportPage() {
})} })}
</div> </div>
<div className="export-section-title-row">
<h3 className="export-section-title"></h3>
<SectionInfoTooltip
label="按会话批量导出"
heading="按会话批量导出说明"
messages={[
'按会话维度导出完整上下文,适合按客户、项目或群组进行归档。',
'你可以先在列表中筛选目标会话,再批量导出,结果会保留每个会话的结构与时间线。'
]}
/>
</div>
<div className="session-table-section"> <div className="session-table-section">
<div className="table-toolbar"> <div className="table-toolbar">
<div className="table-tabs" role="tablist" aria-label="会话类型"> <div className="table-tabs" role="tablist" aria-label="会话类型">