mirror of
https://github.com/hicccc77/WeFlow.git
synced 2026-03-25 15:25:50 +00:00
Add export defaults and compact Excel columns
This commit is contained in:
@@ -71,6 +71,7 @@ export interface ExportOptions {
|
|||||||
exportVoices?: boolean
|
exportVoices?: boolean
|
||||||
exportEmojis?: boolean
|
exportEmojis?: boolean
|
||||||
exportVoiceAsText?: boolean
|
exportVoiceAsText?: boolean
|
||||||
|
excelCompactColumns?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
interface MediaExportItem {
|
interface MediaExportItem {
|
||||||
@@ -1250,13 +1251,18 @@ class ExportService {
|
|||||||
const sourceMatch = /<msgsource>[\s\S]*?<\/msgsource>/i.exec(msg.content || '')
|
const sourceMatch = /<msgsource>[\s\S]*?<\/msgsource>/i.exec(msg.content || '')
|
||||||
const source = sourceMatch ? sourceMatch[0] : ''
|
const source = sourceMatch ? sourceMatch[0] : ''
|
||||||
|
|
||||||
|
let content = this.parseMessageContent(msg.content, msg.localType)
|
||||||
|
if (msg.localType === 34 && options.exportVoiceAsText) {
|
||||||
|
content = await this.transcribeVoice(sessionId, String(msg.localId))
|
||||||
|
}
|
||||||
|
|
||||||
allMessages.push({
|
allMessages.push({
|
||||||
localId: allMessages.length + 1,
|
localId: allMessages.length + 1,
|
||||||
createTime: msg.createTime,
|
createTime: msg.createTime,
|
||||||
formattedTime: this.formatTimestamp(msg.createTime),
|
formattedTime: this.formatTimestamp(msg.createTime),
|
||||||
type: this.getMessageTypeName(msg.localType),
|
type: this.getMessageTypeName(msg.localType),
|
||||||
localType: msg.localType,
|
localType: msg.localType,
|
||||||
content: this.parseMessageContent(msg.content, msg.localType),
|
content,
|
||||||
isSend: msg.isSend ? 1 : 0,
|
isSend: msg.isSend ? 1 : 0,
|
||||||
senderUsername: msg.senderUsername,
|
senderUsername: msg.senderUsername,
|
||||||
senderDisplayName: senderInfo.displayName,
|
senderDisplayName: senderInfo.displayName,
|
||||||
@@ -1379,8 +1385,9 @@ class ExportService {
|
|||||||
|
|
||||||
let currentRow = 1
|
let currentRow = 1
|
||||||
|
|
||||||
|
const useCompactColumns = options.excelCompactColumns === true
|
||||||
|
|
||||||
// 第一行:会话信息标题
|
// 第一行:会话信息标题
|
||||||
worksheet.mergeCells(currentRow, 1, currentRow, 8)
|
|
||||||
const titleCell = worksheet.getCell(currentRow, 1)
|
const titleCell = worksheet.getCell(currentRow, 1)
|
||||||
titleCell.value = '会话信息'
|
titleCell.value = '会话信息'
|
||||||
titleCell.font = { name: 'Calibri', bold: true, size: 11 }
|
titleCell.font = { name: 'Calibri', bold: true, size: 11 }
|
||||||
@@ -1436,7 +1443,9 @@ class ExportService {
|
|||||||
currentRow++
|
currentRow++
|
||||||
|
|
||||||
// 表头行
|
// 表头行
|
||||||
const headers = ['序号', '时间', '发送者昵称', '发送者微信ID', '发送者备注', '发送者身份', '消息类型', '内容']
|
const headers = useCompactColumns
|
||||||
|
? ['序号', '时间', '发送者身份', '消息类型', '内容']
|
||||||
|
: ['序号', '时间', '发送者昵称', '发送者微信ID', '发送者备注', '发送者身份', '消息类型', '内容']
|
||||||
const headerRow = worksheet.getRow(currentRow)
|
const headerRow = worksheet.getRow(currentRow)
|
||||||
headerRow.height = 22
|
headerRow.height = 22
|
||||||
|
|
||||||
@@ -1456,12 +1465,18 @@ class ExportService {
|
|||||||
// 设置列宽
|
// 设置列宽
|
||||||
worksheet.getColumn(1).width = 8 // 序号
|
worksheet.getColumn(1).width = 8 // 序号
|
||||||
worksheet.getColumn(2).width = 20 // 时间
|
worksheet.getColumn(2).width = 20 // 时间
|
||||||
worksheet.getColumn(3).width = 18 // 发送者昵称
|
if (useCompactColumns) {
|
||||||
worksheet.getColumn(4).width = 25 // 发送者微信ID
|
worksheet.getColumn(3).width = 18 // 发送者身份
|
||||||
worksheet.getColumn(5).width = 18 // 发送者备注
|
worksheet.getColumn(4).width = 12 // 消息类型
|
||||||
worksheet.getColumn(6).width = 15 // 发送者身份
|
worksheet.getColumn(5).width = 50 // 内容
|
||||||
worksheet.getColumn(7).width = 12 // 消息类型
|
} else {
|
||||||
worksheet.getColumn(8).width = 50 // 内容
|
worksheet.getColumn(3).width = 18 // 发送者昵称
|
||||||
|
worksheet.getColumn(4).width = 25 // 发送者微信ID
|
||||||
|
worksheet.getColumn(5).width = 18 // 发送者备注
|
||||||
|
worksheet.getColumn(6).width = 15 // 发送者身份
|
||||||
|
worksheet.getColumn(7).width = 12 // 消息类型
|
||||||
|
worksheet.getColumn(8).width = 50 // 内容
|
||||||
|
}
|
||||||
|
|
||||||
// 填充数据
|
// 填充数据
|
||||||
const sortedMessages = collected.rows.sort((a, b) => a.createTime - b.createTime)
|
const sortedMessages = collected.rows.sort((a, b) => a.createTime - b.createTime)
|
||||||
@@ -1541,9 +1556,12 @@ class ExportService {
|
|||||||
row.height = 24
|
row.height = 24
|
||||||
|
|
||||||
// 确定内容:如果有媒体文件导出成功则显示相对路径,否则显示解析后的内容
|
// 确定内容:如果有媒体文件导出成功则显示相对路径,否则显示解析后的内容
|
||||||
const contentValue = mediaItem
|
let contentValue = mediaItem
|
||||||
? mediaItem.relativePath
|
? mediaItem.relativePath
|
||||||
: (this.parseMessageContent(msg.content, msg.localType) || '')
|
: (this.parseMessageContent(msg.content, msg.localType) || '')
|
||||||
|
if (!mediaItem && msg.localType === 34 && options.exportVoiceAsText) {
|
||||||
|
contentValue = await this.transcribeVoice(sessionId, String(msg.localId))
|
||||||
|
}
|
||||||
|
|
||||||
// 调试日志
|
// 调试日志
|
||||||
if (msg.localType === 3 || msg.localType === 47) {
|
if (msg.localType === 3 || msg.localType === 47) {
|
||||||
@@ -1551,15 +1569,22 @@ class ExportService {
|
|||||||
|
|
||||||
worksheet.getCell(currentRow, 1).value = i + 1
|
worksheet.getCell(currentRow, 1).value = i + 1
|
||||||
worksheet.getCell(currentRow, 2).value = this.formatTimestamp(msg.createTime)
|
worksheet.getCell(currentRow, 2).value = this.formatTimestamp(msg.createTime)
|
||||||
worksheet.getCell(currentRow, 3).value = senderNickname
|
if (useCompactColumns) {
|
||||||
worksheet.getCell(currentRow, 4).value = senderWxid
|
worksheet.getCell(currentRow, 3).value = senderRole
|
||||||
worksheet.getCell(currentRow, 5).value = senderRemark
|
worksheet.getCell(currentRow, 4).value = this.getMessageTypeName(msg.localType)
|
||||||
worksheet.getCell(currentRow, 6).value = senderRole
|
worksheet.getCell(currentRow, 5).value = contentValue
|
||||||
worksheet.getCell(currentRow, 7).value = this.getMessageTypeName(msg.localType)
|
} else {
|
||||||
worksheet.getCell(currentRow, 8).value = contentValue
|
worksheet.getCell(currentRow, 3).value = senderNickname
|
||||||
|
worksheet.getCell(currentRow, 4).value = senderWxid
|
||||||
|
worksheet.getCell(currentRow, 5).value = senderRemark
|
||||||
|
worksheet.getCell(currentRow, 6).value = senderRole
|
||||||
|
worksheet.getCell(currentRow, 7).value = this.getMessageTypeName(msg.localType)
|
||||||
|
worksheet.getCell(currentRow, 8).value = contentValue
|
||||||
|
}
|
||||||
|
|
||||||
// 设置每个单元格的样式
|
// 设置每个单元格的样式
|
||||||
for (let col = 1; col <= 8; col++) {
|
const maxColumns = useCompactColumns ? 5 : 8
|
||||||
|
for (let col = 1; col <= maxColumns; col++) {
|
||||||
const cell = worksheet.getCell(currentRow, col)
|
const cell = worksheet.getCell(currentRow, col)
|
||||||
cell.font = { name: 'Calibri', size: 11 }
|
cell.font = { name: 'Calibri', size: 11 }
|
||||||
cell.alignment = { vertical: 'middle', wrapText: false }
|
cell.alignment = { vertical: 'middle', wrapText: false }
|
||||||
@@ -1689,4 +1714,3 @@ class ExportService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const exportService = new ExportService()
|
export const exportService = new ExportService()
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ interface ExportOptions {
|
|||||||
exportVoices: boolean
|
exportVoices: boolean
|
||||||
exportEmojis: boolean
|
exportEmojis: boolean
|
||||||
exportVoiceAsText: boolean
|
exportVoiceAsText: boolean
|
||||||
|
excelCompactColumns: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ExportResult {
|
interface ExportResult {
|
||||||
@@ -45,20 +46,40 @@ function ExportPage() {
|
|||||||
const [selectingStart, setSelectingStart] = useState(true)
|
const [selectingStart, setSelectingStart] = useState(true)
|
||||||
|
|
||||||
const [options, setOptions] = useState<ExportOptions>({
|
const [options, setOptions] = useState<ExportOptions>({
|
||||||
format: 'chatlab',
|
format: 'excel',
|
||||||
dateRange: {
|
dateRange: {
|
||||||
start: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000),
|
start: new Date(new Date().setHours(0, 0, 0, 0)),
|
||||||
end: new Date()
|
end: new Date()
|
||||||
},
|
},
|
||||||
useAllTime: true,
|
useAllTime: false,
|
||||||
exportAvatars: true,
|
exportAvatars: true,
|
||||||
exportMedia: false,
|
exportMedia: false,
|
||||||
exportImages: true,
|
exportImages: true,
|
||||||
exportVoices: true,
|
exportVoices: true,
|
||||||
exportEmojis: true,
|
exportEmojis: true,
|
||||||
exportVoiceAsText: false
|
exportVoiceAsText: true,
|
||||||
|
excelCompactColumns: true
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const buildDateRangeFromPreset = (preset: string) => {
|
||||||
|
const now = new Date()
|
||||||
|
if (preset === 'all') {
|
||||||
|
return { useAllTime: true, dateRange: { start: now, end: now } }
|
||||||
|
}
|
||||||
|
let rangeMs = 0
|
||||||
|
if (preset === '7d') rangeMs = 7 * 24 * 60 * 60 * 1000
|
||||||
|
if (preset === '30d') rangeMs = 30 * 24 * 60 * 60 * 1000
|
||||||
|
if (preset === '90d') rangeMs = 90 * 24 * 60 * 60 * 1000
|
||||||
|
if (preset === 'today' || rangeMs === 0) {
|
||||||
|
const start = new Date(now)
|
||||||
|
start.setHours(0, 0, 0, 0)
|
||||||
|
return { useAllTime: false, dateRange: { start, end: now } }
|
||||||
|
}
|
||||||
|
const start = new Date(now.getTime() - rangeMs)
|
||||||
|
start.setHours(0, 0, 0, 0)
|
||||||
|
return { useAllTime: false, dateRange: { start, end: now } }
|
||||||
|
}
|
||||||
|
|
||||||
const loadSessions = useCallback(async () => {
|
const loadSessions = useCallback(async () => {
|
||||||
setIsLoading(true)
|
setIsLoading(true)
|
||||||
try {
|
try {
|
||||||
@@ -94,10 +115,44 @@ function ExportPage() {
|
|||||||
}
|
}
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
|
const loadExportDefaults = useCallback(async () => {
|
||||||
|
try {
|
||||||
|
const [
|
||||||
|
savedFormat,
|
||||||
|
savedRange,
|
||||||
|
savedMedia,
|
||||||
|
savedVoiceAsText,
|
||||||
|
savedExcelCompactColumns
|
||||||
|
] = await Promise.all([
|
||||||
|
configService.getExportDefaultFormat(),
|
||||||
|
configService.getExportDefaultDateRange(),
|
||||||
|
configService.getExportDefaultMedia(),
|
||||||
|
configService.getExportDefaultVoiceAsText(),
|
||||||
|
configService.getExportDefaultExcelCompactColumns()
|
||||||
|
])
|
||||||
|
|
||||||
|
const preset = savedRange || 'today'
|
||||||
|
const rangeDefaults = buildDateRangeFromPreset(preset)
|
||||||
|
|
||||||
|
setOptions((prev) => ({
|
||||||
|
...prev,
|
||||||
|
format: (savedFormat as ExportOptions['format']) || 'excel',
|
||||||
|
useAllTime: rangeDefaults.useAllTime,
|
||||||
|
dateRange: rangeDefaults.dateRange,
|
||||||
|
exportMedia: savedMedia ?? false,
|
||||||
|
exportVoiceAsText: savedVoiceAsText ?? true,
|
||||||
|
excelCompactColumns: savedExcelCompactColumns ?? true
|
||||||
|
}))
|
||||||
|
} catch (e) {
|
||||||
|
console.error('加载导出默认设置失败:', e)
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
loadSessions()
|
loadSessions()
|
||||||
loadExportPath()
|
loadExportPath()
|
||||||
}, [loadSessions, loadExportPath])
|
loadExportDefaults()
|
||||||
|
}, [loadSessions, loadExportPath, loadExportDefaults])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!searchKeyword.trim()) {
|
if (!searchKeyword.trim()) {
|
||||||
@@ -161,6 +216,7 @@ function ExportPage() {
|
|||||||
exportVoices: options.exportMedia && options.exportVoices,
|
exportVoices: options.exportMedia && options.exportVoices,
|
||||||
exportEmojis: options.exportMedia && options.exportEmojis,
|
exportEmojis: options.exportMedia && options.exportEmojis,
|
||||||
exportVoiceAsText: options.exportVoiceAsText, // 独立于 exportMedia
|
exportVoiceAsText: options.exportVoiceAsText, // 独立于 exportMedia
|
||||||
|
excelCompactColumns: options.excelCompactColumns,
|
||||||
dateRange: options.useAllTime ? null : options.dateRange ? {
|
dateRange: options.useAllTime ? null : options.dateRange ? {
|
||||||
start: Math.floor(options.dateRange.start.getTime() / 1000),
|
start: Math.floor(options.dateRange.start.getTime() / 1000),
|
||||||
// 将结束日期设置为当天的 23:59:59,以包含当天的所有消息
|
// 将结束日期设置为当天的 23:59:59,以包含当天的所有消息
|
||||||
|
|||||||
@@ -11,12 +11,13 @@ import {
|
|||||||
} from 'lucide-react'
|
} from 'lucide-react'
|
||||||
import './SettingsPage.scss'
|
import './SettingsPage.scss'
|
||||||
|
|
||||||
type SettingsTab = 'appearance' | 'database' | 'whisper' | 'cache' | 'about'
|
type SettingsTab = 'appearance' | 'database' | 'whisper' | 'export' | 'cache' | 'about'
|
||||||
|
|
||||||
const tabs: { id: SettingsTab; label: string; icon: React.ElementType }[] = [
|
const tabs: { id: SettingsTab; label: string; icon: React.ElementType }[] = [
|
||||||
{ id: 'appearance', label: '外观', icon: Palette },
|
{ id: 'appearance', label: '外观', icon: Palette },
|
||||||
{ id: 'database', label: '数据库连接', icon: Database },
|
{ id: 'database', label: '数据库连接', icon: Database },
|
||||||
{ id: 'whisper', label: '语音识别模型', icon: Mic },
|
{ id: 'whisper', label: '语音识别模型', icon: Mic },
|
||||||
|
{ id: 'export', label: '导出', icon: Download },
|
||||||
{ id: 'cache', label: '缓存', icon: HardDrive },
|
{ id: 'cache', label: '缓存', icon: HardDrive },
|
||||||
{ id: 'about', label: '关于', icon: Info }
|
{ id: 'about', label: '关于', icon: Info }
|
||||||
]
|
]
|
||||||
@@ -49,6 +50,11 @@ function SettingsPage() {
|
|||||||
const [whisperModelStatus, setWhisperModelStatus] = useState<{ exists: boolean; modelPath?: string; tokensPath?: string } | null>(null)
|
const [whisperModelStatus, setWhisperModelStatus] = useState<{ exists: boolean; modelPath?: string; tokensPath?: string } | null>(null)
|
||||||
const [autoTranscribeVoice, setAutoTranscribeVoice] = useState(false)
|
const [autoTranscribeVoice, setAutoTranscribeVoice] = useState(false)
|
||||||
const [transcribeLanguages, setTranscribeLanguages] = useState<string[]>(['zh'])
|
const [transcribeLanguages, setTranscribeLanguages] = useState<string[]>(['zh'])
|
||||||
|
const [exportDefaultFormat, setExportDefaultFormat] = useState('excel')
|
||||||
|
const [exportDefaultDateRange, setExportDefaultDateRange] = useState('today')
|
||||||
|
const [exportDefaultMedia, setExportDefaultMedia] = useState(false)
|
||||||
|
const [exportDefaultVoiceAsText, setExportDefaultVoiceAsText] = useState(true)
|
||||||
|
const [exportDefaultExcelCompactColumns, setExportDefaultExcelCompactColumns] = useState(true)
|
||||||
|
|
||||||
const [isLoading, setIsLoadingState] = useState(false)
|
const [isLoading, setIsLoadingState] = useState(false)
|
||||||
const [isTesting, setIsTesting] = useState(false)
|
const [isTesting, setIsTesting] = useState(false)
|
||||||
@@ -114,6 +120,11 @@ function SettingsPage() {
|
|||||||
const savedWhisperModelDir = await configService.getWhisperModelDir()
|
const savedWhisperModelDir = await configService.getWhisperModelDir()
|
||||||
const savedAutoTranscribe = await configService.getAutoTranscribeVoice()
|
const savedAutoTranscribe = await configService.getAutoTranscribeVoice()
|
||||||
const savedTranscribeLanguages = await configService.getTranscribeLanguages()
|
const savedTranscribeLanguages = await configService.getTranscribeLanguages()
|
||||||
|
const savedExportDefaultFormat = await configService.getExportDefaultFormat()
|
||||||
|
const savedExportDefaultDateRange = await configService.getExportDefaultDateRange()
|
||||||
|
const savedExportDefaultMedia = await configService.getExportDefaultMedia()
|
||||||
|
const savedExportDefaultVoiceAsText = await configService.getExportDefaultVoiceAsText()
|
||||||
|
const savedExportDefaultExcelCompactColumns = await configService.getExportDefaultExcelCompactColumns()
|
||||||
|
|
||||||
if (savedKey) setDecryptKey(savedKey)
|
if (savedKey) setDecryptKey(savedKey)
|
||||||
if (savedPath) setDbPath(savedPath)
|
if (savedPath) setDbPath(savedPath)
|
||||||
@@ -126,6 +137,11 @@ function SettingsPage() {
|
|||||||
setLogEnabled(savedLogEnabled)
|
setLogEnabled(savedLogEnabled)
|
||||||
setAutoTranscribeVoice(savedAutoTranscribe)
|
setAutoTranscribeVoice(savedAutoTranscribe)
|
||||||
setTranscribeLanguages(savedTranscribeLanguages)
|
setTranscribeLanguages(savedTranscribeLanguages)
|
||||||
|
setExportDefaultFormat(savedExportDefaultFormat || 'excel')
|
||||||
|
setExportDefaultDateRange(savedExportDefaultDateRange || 'today')
|
||||||
|
setExportDefaultMedia(savedExportDefaultMedia ?? false)
|
||||||
|
setExportDefaultVoiceAsText(savedExportDefaultVoiceAsText ?? true)
|
||||||
|
setExportDefaultExcelCompactColumns(savedExportDefaultExcelCompactColumns ?? true)
|
||||||
|
|
||||||
// 如果语言列表为空,保存默认值
|
// 如果语言列表为空,保存默认值
|
||||||
if (!savedTranscribeLanguages || savedTranscribeLanguages.length === 0) {
|
if (!savedTranscribeLanguages || savedTranscribeLanguages.length === 0) {
|
||||||
@@ -853,6 +869,115 @@ function SettingsPage() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const renderExportTab = () => (
|
||||||
|
<div className="tab-content">
|
||||||
|
<div className="form-group">
|
||||||
|
<label>默认导出格式</label>
|
||||||
|
<span className="form-hint">导出页面默认选中的格式</span>
|
||||||
|
<select
|
||||||
|
value={exportDefaultFormat}
|
||||||
|
onChange={async (e) => {
|
||||||
|
const value = e.target.value
|
||||||
|
setExportDefaultFormat(value)
|
||||||
|
await configService.setExportDefaultFormat(value)
|
||||||
|
showMessage('已更新导出格式默认值', true)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<option value="excel">Excel</option>
|
||||||
|
<option value="chatlab">ChatLab</option>
|
||||||
|
<option value="chatlab-jsonl">ChatLab JSONL</option>
|
||||||
|
<option value="json">JSON</option>
|
||||||
|
<option value="html">HTML</option>
|
||||||
|
<option value="txt">TXT</option>
|
||||||
|
<option value="sql">PostgreSQL</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="form-group">
|
||||||
|
<label>默认导出时间范围</label>
|
||||||
|
<span className="form-hint">控制导出页面的默认时间选择</span>
|
||||||
|
<select
|
||||||
|
value={exportDefaultDateRange}
|
||||||
|
onChange={async (e) => {
|
||||||
|
const value = e.target.value
|
||||||
|
setExportDefaultDateRange(value)
|
||||||
|
await configService.setExportDefaultDateRange(value)
|
||||||
|
showMessage('已更新默认导出时间范围', true)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<option value="today">今天</option>
|
||||||
|
<option value="7d">最近7天</option>
|
||||||
|
<option value="30d">最近30天</option>
|
||||||
|
<option value="90d">最近90天</option>
|
||||||
|
<option value="all">全部时间</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="form-group">
|
||||||
|
<label>默认导出媒体文件</label>
|
||||||
|
<span className="form-hint">控制图片/语音/表情的默认导出开关</span>
|
||||||
|
<div className="log-toggle-line">
|
||||||
|
<span className="log-status">{exportDefaultMedia ? '已开启' : '已关闭'}</span>
|
||||||
|
<label className="switch" htmlFor="export-default-media">
|
||||||
|
<input
|
||||||
|
id="export-default-media"
|
||||||
|
className="switch-input"
|
||||||
|
type="checkbox"
|
||||||
|
checked={exportDefaultMedia}
|
||||||
|
onChange={async (e) => {
|
||||||
|
const enabled = e.target.checked
|
||||||
|
setExportDefaultMedia(enabled)
|
||||||
|
await configService.setExportDefaultMedia(enabled)
|
||||||
|
showMessage(enabled ? '已开启默认媒体导出' : '已关闭默认媒体导出', true)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<span className="switch-slider" />
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="form-group">
|
||||||
|
<label>默认语音转文字</label>
|
||||||
|
<span className="form-hint">导出时默认将语音转写为文字</span>
|
||||||
|
<div className="log-toggle-line">
|
||||||
|
<span className="log-status">{exportDefaultVoiceAsText ? '已开启' : '已关闭'}</span>
|
||||||
|
<label className="switch" htmlFor="export-default-voice-as-text">
|
||||||
|
<input
|
||||||
|
id="export-default-voice-as-text"
|
||||||
|
className="switch-input"
|
||||||
|
type="checkbox"
|
||||||
|
checked={exportDefaultVoiceAsText}
|
||||||
|
onChange={async (e) => {
|
||||||
|
const enabled = e.target.checked
|
||||||
|
setExportDefaultVoiceAsText(enabled)
|
||||||
|
await configService.setExportDefaultVoiceAsText(enabled)
|
||||||
|
showMessage(enabled ? '已开启默认语音转文字' : '已关闭默认语音转文字', true)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<span className="switch-slider" />
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="form-group">
|
||||||
|
<label>Excel 列显示</label>
|
||||||
|
<span className="form-hint">控制 Excel 导出的列字段</span>
|
||||||
|
<select
|
||||||
|
value={exportDefaultExcelCompactColumns ? 'compact' : 'full'}
|
||||||
|
onChange={async (e) => {
|
||||||
|
const compact = e.target.value === 'compact'
|
||||||
|
setExportDefaultExcelCompactColumns(compact)
|
||||||
|
await configService.setExportDefaultExcelCompactColumns(compact)
|
||||||
|
showMessage(compact ? '已启用精简列' : '已启用完整列', true)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<option value="compact">精简列(序号、时间、发送者身份、消息类型、内容)</option>
|
||||||
|
<option value="full">完整列(含发送者昵称/微信ID/备注)</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
const renderCacheTab = () => (
|
const renderCacheTab = () => (
|
||||||
<div className="tab-content">
|
<div className="tab-content">
|
||||||
<p className="section-desc">管理应用缓存数据</p>
|
<p className="section-desc">管理应用缓存数据</p>
|
||||||
@@ -992,6 +1117,7 @@ function SettingsPage() {
|
|||||||
{activeTab === 'appearance' && renderAppearanceTab()}
|
{activeTab === 'appearance' && renderAppearanceTab()}
|
||||||
{activeTab === 'database' && renderDatabaseTab()}
|
{activeTab === 'database' && renderDatabaseTab()}
|
||||||
{activeTab === 'whisper' && renderWhisperTab()}
|
{activeTab === 'whisper' && renderWhisperTab()}
|
||||||
|
{activeTab === 'export' && renderExportTab()}
|
||||||
{activeTab === 'cache' && renderCacheTab()}
|
{activeTab === 'cache' && renderCacheTab()}
|
||||||
{activeTab === 'about' && renderAboutTab()}
|
{activeTab === 'about' && renderAboutTab()}
|
||||||
</div>
|
</div>
|
||||||
@@ -1001,4 +1127,3 @@ function SettingsPage() {
|
|||||||
|
|
||||||
export default SettingsPage
|
export default SettingsPage
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,12 @@ export const CONFIG_KEYS = {
|
|||||||
WHISPER_MODEL_DIR: 'whisperModelDir',
|
WHISPER_MODEL_DIR: 'whisperModelDir',
|
||||||
WHISPER_DOWNLOAD_SOURCE: 'whisperDownloadSource',
|
WHISPER_DOWNLOAD_SOURCE: 'whisperDownloadSource',
|
||||||
AUTO_TRANSCRIBE_VOICE: 'autoTranscribeVoice',
|
AUTO_TRANSCRIBE_VOICE: 'autoTranscribeVoice',
|
||||||
TRANSCRIBE_LANGUAGES: 'transcribeLanguages'
|
TRANSCRIBE_LANGUAGES: 'transcribeLanguages',
|
||||||
|
EXPORT_DEFAULT_FORMAT: 'exportDefaultFormat',
|
||||||
|
EXPORT_DEFAULT_DATE_RANGE: 'exportDefaultDateRange',
|
||||||
|
EXPORT_DEFAULT_MEDIA: 'exportDefaultMedia',
|
||||||
|
EXPORT_DEFAULT_VOICE_AS_TEXT: 'exportDefaultVoiceAsText',
|
||||||
|
EXPORT_DEFAULT_EXCEL_COMPACT_COLUMNS: 'exportDefaultExcelCompactColumns'
|
||||||
} as const
|
} as const
|
||||||
|
|
||||||
// 获取解密密钥
|
// 获取解密密钥
|
||||||
@@ -243,3 +248,61 @@ export async function getTranscribeLanguages(): Promise<string[]> {
|
|||||||
export async function setTranscribeLanguages(languages: string[]): Promise<void> {
|
export async function setTranscribeLanguages(languages: string[]): Promise<void> {
|
||||||
await config.set(CONFIG_KEYS.TRANSCRIBE_LANGUAGES, languages)
|
await config.set(CONFIG_KEYS.TRANSCRIBE_LANGUAGES, languages)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 获取导出默认格式
|
||||||
|
export async function getExportDefaultFormat(): Promise<string | null> {
|
||||||
|
const value = await config.get(CONFIG_KEYS.EXPORT_DEFAULT_FORMAT)
|
||||||
|
return (value as string) || null
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置导出默认格式
|
||||||
|
export async function setExportDefaultFormat(format: string): Promise<void> {
|
||||||
|
await config.set(CONFIG_KEYS.EXPORT_DEFAULT_FORMAT, format)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取导出默认时间范围
|
||||||
|
export async function getExportDefaultDateRange(): Promise<string | null> {
|
||||||
|
const value = await config.get(CONFIG_KEYS.EXPORT_DEFAULT_DATE_RANGE)
|
||||||
|
return (value as string) || null
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置导出默认时间范围
|
||||||
|
export async function setExportDefaultDateRange(range: string): Promise<void> {
|
||||||
|
await config.set(CONFIG_KEYS.EXPORT_DEFAULT_DATE_RANGE, range)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取导出默认媒体设置
|
||||||
|
export async function getExportDefaultMedia(): Promise<boolean | null> {
|
||||||
|
const value = await config.get(CONFIG_KEYS.EXPORT_DEFAULT_MEDIA)
|
||||||
|
if (typeof value === 'boolean') return value
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置导出默认媒体设置
|
||||||
|
export async function setExportDefaultMedia(enabled: boolean): Promise<void> {
|
||||||
|
await config.set(CONFIG_KEYS.EXPORT_DEFAULT_MEDIA, enabled)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取导出默认语音转文字
|
||||||
|
export async function getExportDefaultVoiceAsText(): Promise<boolean | null> {
|
||||||
|
const value = await config.get(CONFIG_KEYS.EXPORT_DEFAULT_VOICE_AS_TEXT)
|
||||||
|
if (typeof value === 'boolean') return value
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置导出默认语音转文字
|
||||||
|
export async function setExportDefaultVoiceAsText(enabled: boolean): Promise<void> {
|
||||||
|
await config.set(CONFIG_KEYS.EXPORT_DEFAULT_VOICE_AS_TEXT, enabled)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取导出默认 Excel 列模式
|
||||||
|
export async function getExportDefaultExcelCompactColumns(): Promise<boolean | null> {
|
||||||
|
const value = await config.get(CONFIG_KEYS.EXPORT_DEFAULT_EXCEL_COMPACT_COLUMNS)
|
||||||
|
if (typeof value === 'boolean') return value
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置导出默认 Excel 列模式
|
||||||
|
export async function setExportDefaultExcelCompactColumns(enabled: boolean): Promise<void> {
|
||||||
|
await config.set(CONFIG_KEYS.EXPORT_DEFAULT_EXCEL_COMPACT_COLUMNS, enabled)
|
||||||
|
}
|
||||||
|
|||||||
5
src/types/electron.d.ts
vendored
5
src/types/electron.d.ts
vendored
@@ -327,6 +327,11 @@ export interface ExportOptions {
|
|||||||
dateRange?: { start: number; end: number } | null
|
dateRange?: { start: number; end: number } | null
|
||||||
exportMedia?: boolean
|
exportMedia?: boolean
|
||||||
exportAvatars?: boolean
|
exportAvatars?: boolean
|
||||||
|
exportImages?: boolean
|
||||||
|
exportVoices?: boolean
|
||||||
|
exportEmojis?: boolean
|
||||||
|
exportVoiceAsText?: boolean
|
||||||
|
excelCompactColumns?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface WxidInfo {
|
export interface WxidInfo {
|
||||||
|
|||||||
Reference in New Issue
Block a user