This commit is contained in:
cc
2026-01-17 14:19:34 +08:00
4 changed files with 67 additions and 10 deletions

View File

@@ -7,6 +7,7 @@ import { getEmojiPath } from 'wechat-emojis'
import { ImagePreview } from '../components/ImagePreview' import { ImagePreview } from '../components/ImagePreview'
import { VoiceTranscribeDialog } from '../components/VoiceTranscribeDialog' import { VoiceTranscribeDialog } from '../components/VoiceTranscribeDialog'
import { AnimatedStreamingText } from '../components/AnimatedStreamingText' import { AnimatedStreamingText } from '../components/AnimatedStreamingText'
import * as configService from '../services/config'
import './ChatPage.scss' import './ChatPage.scss'
// 系统消息类型常量 // 系统消息类型常量
@@ -1361,6 +1362,16 @@ function MessageBubble({ message, session, showTime, myAvatarUrl, isGroupChat }:
const [voiceTranscriptError, setVoiceTranscriptError] = useState(false) const [voiceTranscriptError, setVoiceTranscriptError] = useState(false)
const voiceTranscriptRequestedRef = useRef(false) const voiceTranscriptRequestedRef = useRef(false)
const [showImagePreview, setShowImagePreview] = useState(false) const [showImagePreview, setShowImagePreview] = useState(false)
const [autoTranscribeVoice, setAutoTranscribeVoice] = useState(true)
// 加载自动转文字配置
useEffect(() => {
const loadConfig = async () => {
const enabled = await configService.getAutoTranscribeVoice()
setAutoTranscribeVoice(enabled)
}
loadConfig()
}, [])
// 从缓存获取表情包 data URL // 从缓存获取表情包 data URL
const cacheKey = message.emojiMd5 || message.emojiCdnUrl || '' const cacheKey = message.emojiMd5 || message.emojiCdnUrl || ''
@@ -1722,6 +1733,7 @@ function MessageBubble({ message, session, showTime, myAvatarUrl, isGroupChat }:
if (!autoTranscribeEnabled) return if (!autoTranscribeEnabled) return
if (!isVoice) return if (!isVoice) return
if (!voiceDataUrl) return if (!voiceDataUrl) return
if (!autoTranscribeVoice) return // 如果自动转文字已关闭,不自动转文字
if (voiceTranscriptError) return if (voiceTranscriptError) return
if (voiceTranscriptLoading || voiceTranscript !== undefined || voiceTranscriptRequestedRef.current) return if (voiceTranscriptLoading || voiceTranscript !== undefined || voiceTranscriptRequestedRef.current) return
void requestVoiceTranscript() void requestVoiceTranscript()

View File

@@ -218,18 +218,54 @@ function ExportPage() {
const year = calendarDate.getFullYear() const year = calendarDate.getFullYear()
const month = calendarDate.getMonth() const month = calendarDate.getMonth()
const selectedDate = new Date(year, month, day) const selectedDate = new Date(year, month, day)
// 设置时间为当天的开始或结束
selectedDate.setHours(selectingStart ? 0 : 23, selectingStart ? 0 : 59, selectingStart ? 0 : 59, selectingStart ? 0 : 999)
const now = new Date()
// 如果选择的日期晚于当前时间,限制为当前时间
if (selectedDate > now) {
selectedDate.setTime(now.getTime())
}
if (selectingStart) { if (selectingStart) {
setOptions({ // 选择开始日期
...options, const currentEnd = options.dateRange?.end || new Date()
dateRange: options.dateRange ? { ...options.dateRange, start: selectedDate } : { start: selectedDate, end: new Date() } // 如果选择的开始日期晚于结束日期,则同时更新结束日期
}) if (selectedDate > currentEnd) {
const newEnd = new Date(selectedDate)
newEnd.setHours(23, 59, 59, 999)
// 确保结束日期也不晚于当前时间
if (newEnd > now) {
newEnd.setTime(now.getTime())
}
setOptions({
...options,
dateRange: { start: selectedDate, end: newEnd }
})
} else {
setOptions({
...options,
dateRange: options.dateRange ? { ...options.dateRange, start: selectedDate } : { start: selectedDate, end: new Date() }
})
}
setSelectingStart(false) setSelectingStart(false)
} else { } else {
setOptions({ // 选择结束日期
...options, const currentStart = options.dateRange?.start || new Date(Date.now() - 7 * 24 * 60 * 60 * 1000)
dateRange: options.dateRange ? { ...options.dateRange, end: selectedDate } : { start: new Date(), end: selectedDate } // 如果选择的结束日期早于开始日期,则同时更新开始日期
}) if (selectedDate < currentStart) {
const newStart = new Date(selectedDate)
newStart.setHours(0, 0, 0, 0)
setOptions({
...options,
dateRange: { start: newStart, end: selectedDate }
})
} else {
setOptions({
...options,
dateRange: options.dateRange ? { ...options.dateRange, end: selectedDate } : { start: new Date(), end: selectedDate }
})
}
setSelectingStart(true) setSelectingStart(true)
} }
} }
@@ -565,6 +601,9 @@ function ExportPage() {
<div className="export-overlay" onClick={() => setShowDatePicker(false)}> <div className="export-overlay" onClick={() => setShowDatePicker(false)}>
<div className="date-picker-modal" onClick={e => e.stopPropagation()}> <div className="date-picker-modal" onClick={e => e.stopPropagation()}>
<h3></h3> <h3></h3>
<p style={{ fontSize: '13px', color: 'var(--text-secondary)', margin: '8px 0 16px 0' }}>
</p>
<div className="quick-select"> <div className="quick-select">
<button <button
className="quick-btn" className="quick-btn"
@@ -659,12 +698,16 @@ function ExportPage() {
const isStart = options.dateRange?.start.toDateString() === currentDate.toDateString() const isStart = options.dateRange?.start.toDateString() === currentDate.toDateString()
const isEnd = options.dateRange?.end.toDateString() === currentDate.toDateString() const isEnd = options.dateRange?.end.toDateString() === currentDate.toDateString()
const isInRange = options.dateRange && currentDate >= options.dateRange.start && currentDate <= options.dateRange.end const isInRange = options.dateRange && currentDate >= options.dateRange.start && currentDate <= options.dateRange.end
const today = new Date()
today.setHours(0, 0, 0, 0)
const isFuture = currentDate > today
return ( return (
<div <div
key={day} key={day}
className={`calendar-day ${isStart ? 'start' : ''} ${isEnd ? 'end' : ''} ${isInRange ? 'in-range' : ''}`} className={`calendar-day ${isStart ? 'start' : ''} ${isEnd ? 'end' : ''} ${isInRange ? 'in-range' : ''} ${isFuture ? 'disabled' : ''}`}
onClick={() => handleDateSelect(day)} onClick={() => !isFuture && handleDateSelect(day)}
style={{ cursor: isFuture ? 'not-allowed' : 'pointer', opacity: isFuture ? 0.3 : 1 }}
> >
{day} {day}
</div> </div>

View File

@@ -636,6 +636,7 @@ function SettingsPage() {
<div className="form-group"> <div className="form-group">
<label></label> <label></label>
<span className="form-hint">xwechat_files </span> <span className="form-hint">xwechat_files </span>
<span className="form-hint" style={{ color: '#ff6b6b' }}> --</span>
<input type="text" placeholder="例如: C:\Users\xxx\Documents\xwechat_files" value={dbPath} onChange={(e) => setDbPath(e.target.value)} /> <input type="text" placeholder="例如: C:\Users\xxx\Documents\xwechat_files" value={dbPath} onChange={(e) => setDbPath(e.target.value)} />
<div className="btn-row"> <div className="btn-row">
<button className="btn btn-primary" onClick={handleAutoDetectPath} disabled={isDetectingPath}> <button className="btn btn-primary" onClick={handleAutoDetectPath} disabled={isDetectingPath}>

View File

@@ -442,6 +442,7 @@ function WelcomePage({ standalone = false }: WelcomePageProps) {
</button> </button>
</div> </div>
<div className="field-hint"> xwechat_files </div> <div className="field-hint"> xwechat_files </div>
<div className="field-hint" style={{ color: '#ff6b6b', marginTop: '4px' }}> --</div>
</div> </div>
)} )}