朋友圈导出页新增多选功能

This commit is contained in:
xuncha
2026-04-07 19:09:01 +08:00
parent 2db8af3668
commit ec9c1bbbba
3 changed files with 91 additions and 0 deletions

View File

@@ -29,6 +29,7 @@ interface SnsFilterPanelProps {
activeContactUsername?: string
onOpenContactTimeline: (contact: Contact) => void
onToggleContactSelected: (contact: Contact) => void
onToggleFilteredContacts: (usernames: string[], shouldSelect: boolean) => void
onClearSelectedContacts: () => void
onExportSelectedContacts: () => void
}
@@ -46,6 +47,7 @@ export const SnsFilterPanel: React.FC<SnsFilterPanelProps> = ({
activeContactUsername,
onOpenContactTimeline,
onToggleContactSelected,
onToggleFilteredContacts,
onClearSelectedContacts,
onExportSelectedContacts
}) => {
@@ -57,6 +59,16 @@ export const SnsFilterPanel: React.FC<SnsFilterPanelProps> = ({
() => new Set(selectedContactUsernames),
[selectedContactUsernames]
)
const filteredContactUsernames = React.useMemo(
() => filteredContacts.map((contact) => contact.username),
[filteredContacts]
)
const selectedFilteredCount = React.useMemo(
() => filteredContactUsernames.filter((username) => selectedContactLookup.has(username)).length,
[filteredContactUsernames, selectedContactLookup]
)
const hasFilteredContacts = filteredContactUsernames.length > 0
const allFilteredSelected = hasFilteredContacts && selectedFilteredCount === filteredContactUsernames.length
const clearFilters = () => {
setSearchKeyword('')
@@ -128,6 +140,20 @@ export const SnsFilterPanel: React.FC<SnsFilterPanelProps> = ({
)}
</div>
<div className="contact-selection-toolbar">
<span className="contact-selection-summary">
{filteredContactUsernames.length} {selectedFilteredCount}
</span>
<button
type="button"
className={`contact-selection-toggle${allFilteredSelected ? ' active' : ''}`}
onClick={() => onToggleFilteredContacts(filteredContactUsernames, !allFilteredSelected)}
disabled={!hasFilteredContacts}
>
{allFilteredSelected ? '取消全选' : '全选'}
</button>
</div>
{contactsCountProgress && contactsCountProgress.total > 0 && (
<div className="contact-count-progress">
{contactsCountProgress.running

View File

@@ -1265,6 +1265,52 @@
}
}
.contact-selection-toolbar {
display: flex;
align-items: center;
justify-content: space-between;
gap: 10px;
padding: 10px 16px;
border-bottom: 1px dashed color-mix(in srgb, var(--border-color) 72%, transparent);
}
.contact-selection-summary {
min-width: 0;
font-size: 11px;
color: var(--text-tertiary);
font-variant-numeric: tabular-nums;
}
.contact-selection-toggle {
flex-shrink: 0;
border: 1px solid color-mix(in srgb, var(--primary) 16%, var(--border-color));
background: color-mix(in srgb, var(--bg-primary) 84%, rgba(var(--primary-rgb), 0.08));
color: var(--text-secondary);
border-radius: 999px;
padding: 5px 10px;
font-size: 12px;
font-weight: 600;
line-height: 1.2;
cursor: pointer;
transition: border-color 0.2s ease, background 0.2s ease, color 0.2s ease;
&:hover:not(:disabled) {
border-color: color-mix(in srgb, var(--primary) 40%, var(--border-color));
color: var(--primary);
}
&.active {
border-color: color-mix(in srgb, var(--primary) 40%, var(--border-color));
background: rgba(var(--primary-rgb), 0.12);
color: var(--primary);
}
&:disabled {
opacity: 0.45;
cursor: not-allowed;
}
}
.contact-count-progress {
padding: 8px 16px 10px;
font-size: 11px;

View File

@@ -1398,6 +1398,24 @@ export default function SnsPage() {
setSelectedContactUsernames([])
}, [])
const toggleSelectFilteredContacts = useCallback((usernames: string[], shouldSelect: boolean) => {
const normalizedTargets = Array.from(new Set(
usernames
.map((username) => String(username || '').trim())
.filter(Boolean)
))
if (normalizedTargets.length === 0) return
setSelectedContactUsernames((prev) => {
if (shouldSelect) {
const next = new Set(prev)
normalizedTargets.forEach((username) => next.add(username))
return Array.from(next)
}
return prev.filter((username) => !normalizedTargets.includes(username))
})
}, [])
const openSelectedContactsExport = useCallback(() => {
if (selectedContactUsernames.length === 0) return
openExportDialog({ kind: 'selected', usernames: [...selectedContactUsernames] })
@@ -1783,6 +1801,7 @@ export default function SnsPage() {
activeContactUsername={authorTimelineTarget?.username}
onOpenContactTimeline={openContactTimeline}
onToggleContactSelected={toggleContactSelected}
onToggleFilteredContacts={toggleSelectFilteredContacts}
onClearSelectedContacts={clearSelectedContacts}
onExportSelectedContacts={openSelectedContactsExport}
/>