解决年度报告导出失败 #252;集成WechatVisualization的功能并支持词云排除 #259

This commit is contained in:
cc
2026-02-16 10:23:33 +08:00
parent 6394384be0
commit 28e38f73f8
15 changed files with 360 additions and 26 deletions

View File

@@ -9,12 +9,12 @@ import {
Eye, EyeOff, FolderSearch, FolderOpen, Search, Copy,
RotateCcw, Trash2, Plug, Check, Sun, Moon,
Palette, Database, Download, HardDrive, Info, RefreshCw, ChevronDown, Mic,
ShieldCheck, Fingerprint, Lock, KeyRound, Bell, Globe
ShieldCheck, Fingerprint, Lock, KeyRound, Bell, Globe, BarChart2
} from 'lucide-react'
import { Avatar } from '../components/Avatar'
import './SettingsPage.scss'
type SettingsTab = 'appearance' | 'notification' | 'database' | 'models' | 'export' | 'cache' | 'api' | 'security' | 'about'
type SettingsTab = 'appearance' | 'notification' | 'database' | 'models' | 'export' | 'cache' | 'api' | 'security' | 'about' | 'analytics'
const tabs: { id: SettingsTab; label: string; icon: React.ElementType }[] = [
{ id: 'appearance', label: '外观', icon: Palette },
@@ -24,6 +24,8 @@ const tabs: { id: SettingsTab; label: string; icon: React.ElementType }[] = [
{ id: 'export', label: '导出', icon: Download },
{ id: 'cache', label: '缓存', icon: HardDrive },
{ id: 'api', label: 'API 服务', icon: Globe },
{ id: 'analytics', label: '分析', icon: BarChart2 },
{ id: 'security', label: '安全', icon: ShieldCheck },
{ id: 'about', label: '关于', icon: Info }
]
@@ -109,6 +111,9 @@ function SettingsPage() {
const [filterModeDropdownOpen, setFilterModeDropdownOpen] = useState(false)
const [positionDropdownOpen, setPositionDropdownOpen] = useState(false)
const [wordCloudExcludeWords, setWordCloudExcludeWords] = useState<string[]>([])
const [excludeWordsInput, setExcludeWordsInput] = useState('')
@@ -302,6 +307,10 @@ function SettingsPage() {
setNotificationFilterMode(savedNotificationFilterMode)
setNotificationFilterList(savedNotificationFilterList)
const savedExcludeWords = await configService.getWordCloudExcludeWords()
setWordCloudExcludeWords(savedExcludeWords)
setExcludeWordsInput(savedExcludeWords.join('\n'))
// 如果语言列表为空,保存默认值
if (!savedTranscribeLanguages || savedTranscribeLanguages.length === 0) {
const defaultLanguages = ['zh']
@@ -1863,13 +1872,13 @@ function SettingsPage() {
// HTTP API 服务控制
const handleToggleApi = async () => {
if (isTogglingApi) return
// 启动时显示警告弹窗
if (!httpApiRunning) {
setShowApiWarning(true)
return
}
setIsTogglingApi(true)
try {
await window.electronAPI.http.stop()
@@ -2053,6 +2062,56 @@ function SettingsPage() {
}
}
const renderAnalyticsTab = () => (
<div className="tab-content">
<div className="settings-section">
<h2></h2>
<div className="setting-item">
<div className="setting-label">
<span></span>
<span className="setting-desc"></span>
</div>
<div className="setting-control" style={{ flexDirection: 'column', alignItems: 'flex-start', gap: '8px' }}>
<textarea
className="form-input"
style={{ width: '100%', height: '200px', fontFamily: 'monospace' }}
value={excludeWordsInput}
onChange={(e) => setExcludeWordsInput(e.target.value)}
placeholder="例如:
第一个词
第二个词
第三个词"
/>
<div className="button-group">
<button
className="btn btn-primary"
onClick={async () => {
const words = excludeWordsInput.split('\n').map(w => w.trim()).filter(w => w.length > 0)
// 去重
const uniqueWords = Array.from(new Set(words))
await configService.setWordCloudExcludeWords(uniqueWords)
setWordCloudExcludeWords(uniqueWords)
setExcludeWordsInput(uniqueWords.join('\n'))
// Show success toast or feedback if needed (optional)
}}
>
</button>
<button
className="btn btn-secondary"
onClick={() => {
setExcludeWordsInput(wordCloudExcludeWords.join('\n'))
}}
>
</button>
</div>
</div>
</div>
</div>
</div>
)
const renderSecurityTab = () => (
<div className="tab-content">
<div className="form-group">
@@ -2242,6 +2301,7 @@ function SettingsPage() {
{activeTab === 'export' && renderExportTab()}
{activeTab === 'cache' && renderCacheTab()}
{activeTab === 'api' && renderApiTab()}
{activeTab === 'analytics' && renderAnalyticsTab()}
{activeTab === 'security' && renderSecurityTab()}
{activeTab === 'about' && renderAboutTab()}
</div>