setShowDatePicker(false)}>
+
{ setShowDatePicker(false); setShowYearMonthPicker(false) }}>
e.stopPropagation()}>
选择时间范围
@@ -1122,7 +1123,7 @@ function ExportPage() {
>
-
+ setShowYearMonthPicker(!showYearMonthPicker)}>
{calendarDate.getFullYear()}年{calendarDate.getMonth() + 1}月
+ {showYearMonthPicker ? (
+
+
+
+ {calendarDate.getFullYear()}年
+
+
+
+ {['一月','二月','三月','四月','五月','六月','七月','八月','九月','十月','十一月','十二月'].map((name, i) => (
+
+ ))}
+
+
+ ) : (
+ <>
{['日', '一', '二', '三', '四', '五', '六'].map(day => (
{day}
@@ -1163,12 +1190,14 @@ function ExportPage() {
)
})}
+ >
+ )}
-
diff --git a/src/pages/SettingsPage.tsx b/src/pages/SettingsPage.tsx
index 1911acd..83d3c66 100644
--- a/src/pages/SettingsPage.tsx
+++ b/src/pages/SettingsPage.tsx
@@ -7,7 +7,7 @@ import { dialog } from '../services/ipc'
import * as configService from '../services/config'
import {
Eye, EyeOff, FolderSearch, FolderOpen, Search, Copy,
- RotateCcw, Trash2, Plug, Check, Sun, Moon,
+ RotateCcw, Trash2, Plug, Check, Sun, Moon, Monitor,
Palette, Database, Download, HardDrive, Info, RefreshCw, ChevronDown, Mic,
ShieldCheck, Fingerprint, Lock, KeyRound, Bell, Globe, BarChart2
} from 'lucide-react'
@@ -55,6 +55,14 @@ function SettingsPage() {
const resetChatStore = useChatStore((state) => state.reset)
const { currentTheme, themeMode, setTheme, setThemeMode } = useThemeStore()
+ const [systemDark, setSystemDark] = useState(() => window.matchMedia('(prefers-color-scheme: dark)').matches)
+ useEffect(() => {
+ const mq = window.matchMedia('(prefers-color-scheme: dark)')
+ const handler = (e: MediaQueryListEvent) => setSystemDark(e.matches)
+ mq.addEventListener('change', handler)
+ return () => mq.removeEventListener('change', handler)
+ }, [])
+ const effectiveMode = themeMode === 'system' ? (systemDark ? 'dark' : 'light') : themeMode
const clearAnalyticsStoreCache = useAnalyticsStore((state) => state.clearCache)
const [activeTab, setActiveTab] = useState
('appearance')
@@ -82,10 +90,6 @@ function SettingsPage() {
const [whisperDownloadProgress, setWhisperDownloadProgress] = useState(0)
const [whisperProgressData, setWhisperProgressData] = useState<{ downloaded: number; total: number; speed: number }>({ downloaded: 0, total: 0, speed: 0 })
const [whisperModelStatus, setWhisperModelStatus] = useState<{ exists: boolean; modelPath?: string; tokensPath?: string } | null>(null)
- const [llamaModelStatus, setLlamaModelStatus] = useState<{ exists: boolean; path?: string; size?: number } | null>(null)
- const [isLlamaDownloading, setIsLlamaDownloading] = useState(false)
- const [llamaDownloadProgress, setLlamaDownloadProgress] = useState(0)
- const [llamaProgressData, setLlamaProgressData] = useState<{ downloaded: number; total: number; speed: number }>({ downloaded: 0, total: 0, speed: 0 })
const formatBytes = (bytes: number) => {
if (bytes === 0) return '0 B';
@@ -328,8 +332,7 @@ function SettingsPage() {
if (savedWhisperModelDir) setWhisperModelDir(savedWhisperModelDir)
- // Load Llama status after config
- void checkLlamaModelStatus()
+
} catch (e: any) {
console.error('加载配置失败:', e)
}
@@ -645,7 +648,6 @@ function SettingsPage() {
setWhisperModelDir(dir)
await configService.setWhisperModelDir(dir)
showMessage('已选择 Whisper 模型目录', true)
- await checkLlamaModelStatus()
}
} catch (e: any) {
showMessage('选择目录失败', false)
@@ -681,68 +683,6 @@ function SettingsPage() {
const handleResetWhisperModelDir = async () => {
setWhisperModelDir('')
await configService.setWhisperModelDir('')
- await checkLlamaModelStatus()
- }
-
- const checkLlamaModelStatus = async () => {
- try {
- // @ts-ignore
- const modelsPath = await window.electronAPI.llama?.getModelsPath()
- if (!modelsPath) return
- const modelName = "Qwen3-4B-Q4_K_M.gguf" // Hardcoded preset for now
- const fullPath = `${modelsPath}\\${modelName}`
- // @ts-ignore
- const status = await window.electronAPI.llama?.getModelStatus(fullPath)
- if (status) {
- setLlamaModelStatus({
- exists: status.exists,
- path: status.path,
- size: status.size
- })
- }
- } catch (e) {
- console.error("Check llama model status failed", e)
- }
- }
-
- useEffect(() => {
- const handleLlamaProgress = (payload: { downloaded: number; total: number; speed: number }) => {
- setLlamaProgressData(payload)
- if (payload.total > 0) {
- setLlamaDownloadProgress((payload.downloaded / payload.total) * 100)
- }
- }
- // @ts-ignore
- const removeListener = window.electronAPI.llama?.onDownloadProgress(handleLlamaProgress)
- return () => {
- if (typeof removeListener === 'function') removeListener()
- }
- }, [])
-
- const handleDownloadLlamaModel = async () => {
- if (isLlamaDownloading) return
- setIsLlamaDownloading(true)
- setLlamaDownloadProgress(0)
- try {
- const modelUrl = "https://www.modelscope.cn/models/Qwen/Qwen3-4B-GGUF/resolve/master/Qwen3-4B-Q4_K_M.gguf"
- // @ts-ignore
- const modelsPath = await window.electronAPI.llama?.getModelsPath()
- const modelName = "Qwen3-4B-Q4_K_M.gguf"
- const fullPath = `${modelsPath}\\${modelName}`
-
- // @ts-ignore
- const result = await window.electronAPI.llama?.downloadModel(modelUrl, fullPath)
- if (result?.success) {
- showMessage('Qwen3 模型下载完成', true)
- await checkLlamaModelStatus()
- } else {
- showMessage(`模型下载失败: ${result?.error || '未知错误'}`, false)
- }
- } catch (e: any) {
- showMessage(`模型下载失败: ${e}`, false)
- } finally {
- setIsLlamaDownloading(false)
- }
}
const handleAutoGetDbKey = async () => {
@@ -993,11 +933,14 @@ function SettingsPage() {
setThemeMode('dark')}>
深色
+ setThemeMode('system')}>
+ 跟随系统
+