Add configurable TXT export

This commit is contained in:
QingXiao
2026-01-23 13:52:47 +08:00
parent 6436c39c90
commit b47007ea0c
5 changed files with 301 additions and 7 deletions

View File

@@ -22,6 +22,7 @@ interface ExportOptions {
exportEmojis: boolean
exportVoiceAsText: boolean
excelCompactColumns: boolean
txtColumns: string[]
}
interface ExportResult {
@@ -34,6 +35,7 @@ interface ExportResult {
type SessionLayout = 'shared' | 'per-session'
function ExportPage() {
const defaultTxtColumns = ['index', 'time', 'senderRole', 'messageType', 'content']
const [sessions, setSessions] = useState<ChatSession[]>([])
const [filteredSessions, setFilteredSessions] = useState<ChatSession[]>([])
const [selectedSessions, setSelectedSessions] = useState<Set<string>>(new Set())
@@ -61,7 +63,8 @@ function ExportPage() {
exportVoices: true,
exportEmojis: true,
exportVoiceAsText: true,
excelCompactColumns: true
excelCompactColumns: true,
txtColumns: defaultTxtColumns
})
const buildDateRangeFromPreset = (preset: string) => {
@@ -125,17 +128,20 @@ function ExportPage() {
savedRange,
savedMedia,
savedVoiceAsText,
savedExcelCompactColumns
savedExcelCompactColumns,
savedTxtColumns
] = await Promise.all([
configService.getExportDefaultFormat(),
configService.getExportDefaultDateRange(),
configService.getExportDefaultMedia(),
configService.getExportDefaultVoiceAsText(),
configService.getExportDefaultExcelCompactColumns()
configService.getExportDefaultExcelCompactColumns(),
configService.getExportDefaultTxtColumns()
])
const preset = savedRange || 'today'
const rangeDefaults = buildDateRangeFromPreset(preset)
const txtColumns = savedTxtColumns && savedTxtColumns.length > 0 ? savedTxtColumns : defaultTxtColumns
setOptions((prev) => ({
...prev,
@@ -144,7 +150,8 @@ function ExportPage() {
dateRange: rangeDefaults.dateRange,
exportMedia: savedMedia ?? false,
exportVoiceAsText: savedVoiceAsText ?? true,
excelCompactColumns: savedExcelCompactColumns ?? true
excelCompactColumns: savedExcelCompactColumns ?? true,
txtColumns
}))
} catch (e) {
console.error('加载导出默认设置失败:', e)
@@ -233,6 +240,7 @@ function ExportPage() {
exportEmojis: options.exportMedia && options.exportEmojis,
exportVoiceAsText: options.exportVoiceAsText, // 即使不导出媒体,也可以导出语音转文字内容
excelCompactColumns: options.excelCompactColumns,
txtColumns: options.txtColumns,
sessionLayout,
dateRange: options.useAllTime ? null : options.dateRange ? {
start: Math.floor(options.dateRange.start.getTime() / 1000),
@@ -241,7 +249,7 @@ function ExportPage() {
} : null
}
if (options.format === 'chatlab' || options.format === 'chatlab-jsonl' || options.format === 'json' || options.format === 'excel') {
if (options.format === 'chatlab' || options.format === 'chatlab-jsonl' || options.format === 'json' || options.format === 'excel' || options.format === 'txt') {
const result = await window.electronAPI.export.exportSessions(
sessionList,
exportFolder,

View File

@@ -61,6 +61,7 @@ function SettingsPage() {
const [exportDefaultMedia, setExportDefaultMedia] = useState(false)
const [exportDefaultVoiceAsText, setExportDefaultVoiceAsText] = useState(true)
const [exportDefaultExcelCompactColumns, setExportDefaultExcelCompactColumns] = useState(true)
const [exportDefaultTxtColumns, setExportDefaultTxtColumns] = useState<string[]>(['index', 'time', 'senderRole', 'messageType', 'content'])
const [isLoading, setIsLoadingState] = useState(false)
const [isTesting, setIsTesting] = useState(false)
@@ -141,6 +142,8 @@ function SettingsPage() {
const savedExportDefaultMedia = await configService.getExportDefaultMedia()
const savedExportDefaultVoiceAsText = await configService.getExportDefaultVoiceAsText()
const savedExportDefaultExcelCompactColumns = await configService.getExportDefaultExcelCompactColumns()
const savedExportDefaultTxtColumns = await configService.getExportDefaultTxtColumns()
const defaultTxtColumns = ['index', 'time', 'senderRole', 'messageType', 'content']
if (savedKey) setDecryptKey(savedKey)
if (savedPath) setDbPath(savedPath)
@@ -158,6 +161,11 @@ function SettingsPage() {
setExportDefaultMedia(savedExportDefaultMedia ?? false)
setExportDefaultVoiceAsText(savedExportDefaultVoiceAsText ?? true)
setExportDefaultExcelCompactColumns(savedExportDefaultExcelCompactColumns ?? true)
setExportDefaultTxtColumns(
savedExportDefaultTxtColumns && savedExportDefaultTxtColumns.length > 0
? savedExportDefaultTxtColumns
: defaultTxtColumns
)
// 如果语言列表为空,保存默认值
if (!savedTranscribeLanguages || savedTranscribeLanguages.length === 0) {
@@ -166,6 +174,10 @@ function SettingsPage() {
await configService.setTranscribeLanguages(defaultLanguages)
}
if (!savedExportDefaultTxtColumns || savedExportDefaultTxtColumns.length === 0) {
await configService.setExportDefaultTxtColumns(defaultTxtColumns)
}
if (savedWhisperModelDir) setWhisperModelDir(savedWhisperModelDir)
} catch (e) {
console.error('加载配置失败:', e)
@@ -899,6 +911,16 @@ function SettingsPage() {
{ value: 'compact', label: '精简列', desc: '序号、时间、发送者身份、消息类型、内容' },
{ value: 'full', label: '完整列', desc: '含发送者昵称/微信ID/备注' }
]
const exportTxtColumnOptions = [
{ value: 'index', label: '序号' },
{ value: 'time', label: '时间' },
{ value: 'senderRole', label: '发送者身份' },
{ value: 'messageType', label: '消息类型' },
{ value: 'content', label: '内容' },
{ value: 'senderNickname', label: '发送者昵称' },
{ value: 'senderWxid', label: '发送者微信ID' },
{ value: 'senderRemark', label: '发送者备注' }
]
const getOptionLabel = (options: { value: string; label: string }[], value: string) => {
return options.find((option) => option.value === value)?.label ?? value
@@ -1074,6 +1096,41 @@ function SettingsPage() {
)}
</div>
</div>
<div className="form-group">
<label>TXT </label>
<span className="form-hint"> Excel </span>
<div className="language-checkboxes">
{exportTxtColumnOptions.map((column) => {
const checked = exportDefaultTxtColumns.includes(column.value)
return (
<label key={column.value} className="language-checkbox">
<input
type="checkbox"
checked={checked}
onChange={async (e) => {
const enabled = e.target.checked
const nextColumns = enabled
? [...exportDefaultTxtColumns, column.value]
: exportDefaultTxtColumns.filter((value) => value !== column.value)
if (nextColumns.length === 0) {
showMessage('至少选择一个 TXT 导出栏目', false)
return
}
setExportDefaultTxtColumns(nextColumns)
await configService.setExportDefaultTxtColumns(nextColumns)
showMessage('已更新 TXT 导出栏目', true)
}}
/>
<div className="checkbox-custom">
<Check size={14} />
<span>{column.label}</span>
</div>
</label>
)
})}
</div>
</div>
</div>
)
}
@@ -1225,4 +1282,3 @@ function SettingsPage() {
}
export default SettingsPage

View File

@@ -27,7 +27,8 @@ export const CONFIG_KEYS = {
EXPORT_DEFAULT_DATE_RANGE: 'exportDefaultDateRange',
EXPORT_DEFAULT_MEDIA: 'exportDefaultMedia',
EXPORT_DEFAULT_VOICE_AS_TEXT: 'exportDefaultVoiceAsText',
EXPORT_DEFAULT_EXCEL_COMPACT_COLUMNS: 'exportDefaultExcelCompactColumns'
EXPORT_DEFAULT_EXCEL_COMPACT_COLUMNS: 'exportDefaultExcelCompactColumns',
EXPORT_DEFAULT_TXT_COLUMNS: 'exportDefaultTxtColumns'
} as const
// 获取解密密钥
@@ -306,3 +307,14 @@ export async function getExportDefaultExcelCompactColumns(): Promise<boolean | n
export async function setExportDefaultExcelCompactColumns(enabled: boolean): Promise<void> {
await config.set(CONFIG_KEYS.EXPORT_DEFAULT_EXCEL_COMPACT_COLUMNS, enabled)
}
// 获取导出默认 TXT 列配置
export async function getExportDefaultTxtColumns(): Promise<string[] | null> {
const value = await config.get(CONFIG_KEYS.EXPORT_DEFAULT_TXT_COLUMNS)
return Array.isArray(value) ? (value as string[]) : null
}
// 设置导出默认 TXT 列配置
export async function setExportDefaultTxtColumns(columns: string[]): Promise<void> {
await config.set(CONFIG_KEYS.EXPORT_DEFAULT_TXT_COLUMNS, columns)
}

View File

@@ -351,6 +351,7 @@ export interface ExportOptions {
exportEmojis?: boolean
exportVoiceAsText?: boolean
excelCompactColumns?: boolean
txtColumns?: string[]
sessionLayout?: 'shared' | 'per-session'
}