feat(export): add more defaults modal

This commit is contained in:
aits2026
2026-03-06 13:36:25 +08:00
parent 3fa0b36426
commit 90b33ef444
5 changed files with 758 additions and 215 deletions

View File

@@ -41,6 +41,7 @@ import { useContactTypeCountsStore } from '../stores/contactTypeCountsStore'
import { SnsPostItem } from '../components/Sns/SnsPostItem'
import { ContactSnsTimelineDialog } from '../components/Sns/ContactSnsTimelineDialog'
import { ExportDateRangeDialog } from '../components/Export/ExportDateRangeDialog'
import { ExportDefaultsSettingsForm, type ExportDefaultsSettingsPatch } from '../components/Export/ExportDefaultsSettingsForm'
import type { SnsPost } from '../types/sns'
import {
cloneExportDateRange,
@@ -1282,8 +1283,14 @@ function ExportPage() {
const [snsExportLivePhotos, setSnsExportLivePhotos] = useState(false)
const [snsExportVideos, setSnsExportVideos] = useState(false)
const [isTimeRangeDialogOpen, setIsTimeRangeDialogOpen] = useState(false)
const [isExportDefaultsModalOpen, setIsExportDefaultsModalOpen] = useState(false)
const [timeRangeSelection, setTimeRangeSelection] = useState<ExportDateRangeSelection>(() => createDefaultExportDateRangeSelection())
const [exportDefaultFormat, setExportDefaultFormat] = useState<TextExportFormat>('excel')
const [exportDefaultDateRangeSelection, setExportDefaultDateRangeSelection] = useState<ExportDateRangeSelection>(() => createDefaultExportDateRangeSelection())
const [exportDefaultMedia, setExportDefaultMedia] = useState(false)
const [exportDefaultVoiceAsText, setExportDefaultVoiceAsText] = useState(false)
const [exportDefaultExcelCompactColumns, setExportDefaultExcelCompactColumns] = useState(true)
const [exportDefaultConcurrency, setExportDefaultConcurrency] = useState(2)
const [options, setOptions] = useState<ExportOptions>({
format: 'json',
@@ -1785,8 +1792,9 @@ function ExportPage() {
setIsBaseConfigLoading(true)
let isReady = true
try {
const [savedPath, savedMedia, savedVoiceAsText, savedExcelCompactColumns, savedTxtColumns, savedConcurrency, savedSessionMap, savedContentMap, savedSessionRecordMap, savedSnsPostCount, savedWriteLayout, savedSessionNameWithTypePrefix, savedDefaultDateRange, exportCacheScope] = await Promise.all([
const [savedPath, savedFormat, savedMedia, savedVoiceAsText, savedExcelCompactColumns, savedTxtColumns, savedConcurrency, savedSessionMap, savedContentMap, savedSessionRecordMap, savedSnsPostCount, savedWriteLayout, savedSessionNameWithTypePrefix, savedDefaultDateRange, exportCacheScope] = await Promise.all([
configService.getExportPath(),
configService.getExportDefaultFormat(),
configService.getExportDefaultMedia(),
configService.getExportDefaultVoiceAsText(),
configService.getExportDefaultExcelCompactColumns(),
@@ -1817,10 +1825,14 @@ function ExportPage() {
setLastExportByContent(savedContentMap)
setExportRecordsBySession(savedSessionRecordMap)
setLastSnsExportPostCount(savedSnsPostCount)
setExportDefaultFormat((savedFormat as TextExportFormat) || 'excel')
setExportDefaultMedia(savedMedia ?? false)
setExportDefaultVoiceAsText(savedVoiceAsText ?? false)
setExportDefaultExcelCompactColumns(savedExcelCompactColumns ?? true)
setExportDefaultConcurrency(savedConcurrency ?? 2)
const resolvedDefaultDateRange = resolveExportDateRangeConfig(savedDefaultDateRange)
setExportDefaultDateRangeSelection(resolvedDefaultDateRange)
setTimeRangeSelection(resolvedDefaultDateRange)
await configService.setExportDefaultFormat('json')
if (cachedSnsStats && Date.now() - cachedSnsStats.updatedAt <= EXPORT_SNS_STATS_CACHE_STALE_MS) {
setSnsStats({
@@ -1835,7 +1847,7 @@ function ExportPage() {
const txtColumns = savedTxtColumns && savedTxtColumns.length > 0 ? savedTxtColumns : defaultTxtColumns
setOptions(prev => ({
...prev,
format: 'json',
format: ((savedFormat as TextExportFormat) || 'excel'),
exportMedia: savedMedia ?? prev.exportMedia,
exportVoiceAsText: savedVoiceAsText ?? prev.exportVoiceAsText,
excelCompactColumns: savedExcelCompactColumns ?? prev.excelCompactColumns,
@@ -3192,8 +3204,13 @@ function ExportPage() {
const next: ExportOptions = {
...prev,
format: exportDefaultFormat,
useAllTime: exportDefaultDateRangeSelection.useAllTime,
dateRange: nextDateRange
dateRange: nextDateRange,
exportMedia: exportDefaultMedia,
exportVoiceAsText: exportDefaultVoiceAsText,
excelCompactColumns: exportDefaultExcelCompactColumns,
exportConcurrency: exportDefaultConcurrency
}
if (payload.scope === 'sns') {
@@ -3220,7 +3237,14 @@ function ExportPage() {
return next
})
}, [exportDefaultDateRangeSelection])
}, [
exportDefaultDateRangeSelection,
exportDefaultExcelCompactColumns,
exportDefaultFormat,
exportDefaultMedia,
exportDefaultVoiceAsText,
exportDefaultConcurrency
])
const closeExportDialog = useCallback(() => {
setExportDialog(prev => ({ ...prev, open: false }))
@@ -5147,6 +5171,27 @@ function ExportPage() {
}
}, [])
const handleExportDefaultsChanged = useCallback((patch: ExportDefaultsSettingsPatch) => {
if (patch.format) {
setExportDefaultFormat(patch.format as TextExportFormat)
}
if (patch.dateRange) {
setExportDefaultDateRangeSelection(patch.dateRange)
}
if (typeof patch.media === 'boolean') {
setExportDefaultMedia(patch.media)
}
if (typeof patch.voiceAsText === 'boolean') {
setExportDefaultVoiceAsText(patch.voiceAsText)
}
if (typeof patch.excelCompactColumns === 'boolean') {
setExportDefaultExcelCompactColumns(patch.excelCompactColumns)
}
if (typeof patch.concurrency === 'number') {
setExportDefaultConcurrency(patch.concurrency)
}
}, [])
return (
<div className="export-board-page">
<div className="export-top-panel">
@@ -5186,6 +5231,16 @@ function ExportPage() {
await configService.setExportSessionNamePrefixEnabled(enabled)
}}
/>
<div className="more-export-settings-control">
<button
className="more-export-settings-btn"
type="button"
onClick={() => setIsExportDefaultsModalOpen(true)}
>
</button>
</div>
</div>
<button
@@ -5212,6 +5267,48 @@ function ExportPage() {
onTogglePerfTask={toggleTaskPerfDetail}
/>
{isExportDefaultsModalOpen && (
<div
className="export-defaults-modal-overlay"
onClick={() => setIsExportDefaultsModalOpen(false)}
>
<div
className="export-defaults-modal"
role="dialog"
aria-modal="true"
aria-label="更多导出设置"
onClick={(event) => event.stopPropagation()}
>
<div className="export-defaults-modal-header">
<div>
<h3></h3>
<p></p>
</div>
<button
className="close-icon-btn"
type="button"
onClick={() => setIsExportDefaultsModalOpen(false)}
aria-label="关闭更多导出设置"
>
<X size={16} />
</button>
</div>
<div className="export-defaults-modal-body">
<ExportDefaultsSettingsForm onDefaultsChanged={handleExportDefaultsChanged} />
</div>
<div className="export-defaults-modal-actions">
<button
type="button"
className="secondary-btn"
onClick={() => setIsExportDefaultsModalOpen(false)}
>
</button>
</div>
</div>
</div>
)}
<div className="export-section-title-row">
<h3 className="export-section-title"></h3>
<SectionInfoTooltip