mirror of
https://github.com/hicccc77/WeFlow.git
synced 2026-03-24 23:06:51 +00:00
fix:修复了清除缓存功能的缺失
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -56,3 +56,4 @@ Thumbs.db
|
||||
*.aps
|
||||
|
||||
wcdb/
|
||||
*info
|
||||
|
||||
@@ -482,6 +482,40 @@ function registerIpcHandlers() {
|
||||
return analyticsService.getTimeDistribution()
|
||||
})
|
||||
|
||||
// 缓存管理
|
||||
ipcMain.handle('cache:clearAnalytics', async () => {
|
||||
return analyticsService.clearCache()
|
||||
})
|
||||
|
||||
ipcMain.handle('cache:clearImages', async () => {
|
||||
const imageResult = await imageDecryptService.clearCache()
|
||||
const emojiResult = chatService.clearCaches({ includeMessages: false, includeContacts: false, includeEmojis: true })
|
||||
const errors = [imageResult, emojiResult]
|
||||
.filter((result) => !result.success)
|
||||
.map((result) => result.error)
|
||||
.filter(Boolean) as string[]
|
||||
if (errors.length > 0) {
|
||||
return { success: false, error: errors.join('; ') }
|
||||
}
|
||||
return { success: true }
|
||||
})
|
||||
|
||||
ipcMain.handle('cache:clearAll', async () => {
|
||||
const [analyticsResult, imageResult] = await Promise.all([
|
||||
analyticsService.clearCache(),
|
||||
imageDecryptService.clearCache()
|
||||
])
|
||||
const chatResult = chatService.clearCaches()
|
||||
const errors = [analyticsResult, imageResult, chatResult]
|
||||
.filter((result) => !result.success)
|
||||
.map((result) => result.error)
|
||||
.filter(Boolean) as string[]
|
||||
if (errors.length > 0) {
|
||||
return { success: false, error: errors.join('; ') }
|
||||
}
|
||||
return { success: true }
|
||||
})
|
||||
|
||||
// 群聊分析相关
|
||||
ipcMain.handle('groupAnalytics:getGroupChats', async () => {
|
||||
return groupAnalyticsService.getGroupChats()
|
||||
|
||||
@@ -140,6 +140,13 @@ contextBridge.exposeInMainWorld('electronAPI', {
|
||||
}
|
||||
},
|
||||
|
||||
// 缓存管理
|
||||
cache: {
|
||||
clearAnalytics: () => ipcRenderer.invoke('cache:clearAnalytics'),
|
||||
clearImages: () => ipcRenderer.invoke('cache:clearImages'),
|
||||
clearAll: () => ipcRenderer.invoke('cache:clearAll')
|
||||
},
|
||||
|
||||
// 群聊分析
|
||||
groupAnalytics: {
|
||||
getGroupChats: () => ipcRenderer.invoke('groupAnalytics:getGroupChats'),
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { ConfigService } from './config'
|
||||
import { wcdbService } from './wcdbService'
|
||||
import { join } from 'path'
|
||||
import { readFile, writeFile } from 'fs/promises'
|
||||
import { readFile, writeFile, rm } from 'fs/promises'
|
||||
import { app } from 'electron'
|
||||
|
||||
export interface ChatStatistics {
|
||||
@@ -528,6 +528,18 @@ class AnalyticsService {
|
||||
return { success: false, error: String(e) }
|
||||
}
|
||||
}
|
||||
|
||||
async clearCache(): Promise<{ success: boolean; error?: string }> {
|
||||
this.aggregateCache = null
|
||||
this.fallbackAggregateCache = null
|
||||
this.aggregatePromise = null
|
||||
try {
|
||||
await rm(this.getCacheFilePath(), { force: true })
|
||||
return { success: true }
|
||||
} catch (e) {
|
||||
return { success: false, error: String(e) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const analyticsService = new AnalyticsService()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { join, dirname } from 'path'
|
||||
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs'
|
||||
import { existsSync, mkdirSync, readFileSync, writeFileSync, rmSync } from 'fs'
|
||||
import { app } from 'electron'
|
||||
|
||||
export interface ContactCacheEntry {
|
||||
@@ -72,4 +72,13 @@ export class ContactCacheService {
|
||||
console.error('ContactCacheService: 保存缓存失败', error)
|
||||
}
|
||||
}
|
||||
|
||||
clear(): void {
|
||||
this.cache = {}
|
||||
try {
|
||||
rmSync(this.cacheFilePath, { force: true })
|
||||
} catch (error) {
|
||||
console.error('ContactCacheService: 清理缓存失败', error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ import { app, BrowserWindow } from 'electron'
|
||||
import { basename, dirname, extname, join } from 'path'
|
||||
import { pathToFileURL } from 'url'
|
||||
import { existsSync, mkdirSync, readdirSync, readFileSync, statSync, appendFileSync } from 'fs'
|
||||
import { writeFile } from 'fs/promises'
|
||||
import { writeFile, rm, readdir } from 'fs/promises'
|
||||
import crypto from 'crypto'
|
||||
import { Worker } from 'worker_threads'
|
||||
import { ConfigService } from './config'
|
||||
@@ -1646,6 +1646,71 @@ export class ImageDecryptService {
|
||||
|
||||
await writeFile(outputPath, decrypted)
|
||||
}
|
||||
|
||||
async clearCache(): Promise<{ success: boolean; error?: string }> {
|
||||
this.resolvedCache.clear()
|
||||
this.hardlinkCache.clear()
|
||||
this.pending.clear()
|
||||
this.updateFlags.clear()
|
||||
this.cacheIndexed = false
|
||||
this.cacheIndexing = null
|
||||
|
||||
const configured = this.configService.get('cachePath')
|
||||
const root = configured
|
||||
? join(configured, 'Images')
|
||||
: join(app.getPath('documents'), 'WeFlow', 'Images')
|
||||
|
||||
try {
|
||||
if (!existsSync(root)) {
|
||||
return { success: true }
|
||||
}
|
||||
const monthPattern = /^\d{4}-\d{2}$/
|
||||
const clearFilesInDir = async (dirPath: string): Promise<void> => {
|
||||
let entries: Array<{ name: string; isDirectory: () => boolean }>
|
||||
try {
|
||||
entries = await readdir(dirPath, { withFileTypes: true })
|
||||
} catch {
|
||||
return
|
||||
}
|
||||
for (const entry of entries) {
|
||||
const fullPath = join(dirPath, entry.name)
|
||||
if (entry.isDirectory()) {
|
||||
await clearFilesInDir(fullPath)
|
||||
continue
|
||||
}
|
||||
try {
|
||||
await rm(fullPath, { force: true })
|
||||
} catch { }
|
||||
}
|
||||
}
|
||||
const traverse = async (dirPath: string): Promise<void> => {
|
||||
let entries: Array<{ name: string; isDirectory: () => boolean }>
|
||||
try {
|
||||
entries = await readdir(dirPath, { withFileTypes: true })
|
||||
} catch {
|
||||
return
|
||||
}
|
||||
for (const entry of entries) {
|
||||
const fullPath = join(dirPath, entry.name)
|
||||
if (entry.isDirectory()) {
|
||||
if (monthPattern.test(entry.name)) {
|
||||
await clearFilesInDir(fullPath)
|
||||
} else {
|
||||
await traverse(fullPath)
|
||||
}
|
||||
continue
|
||||
}
|
||||
try {
|
||||
await rm(fullPath, { force: true })
|
||||
} catch { }
|
||||
}
|
||||
}
|
||||
await traverse(root)
|
||||
return { success: true }
|
||||
} catch (e) {
|
||||
return { success: false, error: String(e) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const imageDecryptService = new ImageDecryptService()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { join, dirname } from 'path'
|
||||
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs'
|
||||
import { existsSync, mkdirSync, readFileSync, writeFileSync, rmSync } from 'fs'
|
||||
import { app } from 'electron'
|
||||
|
||||
export interface SessionMessageCacheEntry {
|
||||
@@ -65,4 +65,13 @@ export class MessageCacheService {
|
||||
console.error('MessageCacheService: 保存缓存失败', error)
|
||||
}
|
||||
}
|
||||
|
||||
clear(): void {
|
||||
this.cache = {}
|
||||
try {
|
||||
rmSync(this.cacheFilePath, { force: true })
|
||||
} catch (error) {
|
||||
console.error('MessageCacheService: 清理缓存失败', error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { useState, useEffect, useRef } from 'react'
|
||||
import { useAppStore } from '../stores/appStore'
|
||||
import { useThemeStore, themes } from '../stores/themeStore'
|
||||
import { useAnalyticsStore } from '../stores/analyticsStore'
|
||||
import { dialog } from '../services/ipc'
|
||||
import * as configService from '../services/config'
|
||||
import {
|
||||
@@ -27,6 +28,7 @@ interface WxidOption {
|
||||
function SettingsPage() {
|
||||
const { setDbConnected, setLoading, reset } = useAppStore()
|
||||
const { currentTheme, themeMode, setTheme, setThemeMode } = useThemeStore()
|
||||
const clearAnalyticsStoreCache = useAnalyticsStore((state) => state.clearCache)
|
||||
|
||||
const [activeTab, setActiveTab] = useState<SettingsTab>('appearance')
|
||||
const [decryptKey, setDecryptKey] = useState('')
|
||||
@@ -55,6 +57,11 @@ function SettingsPage() {
|
||||
const [dbKeyStatus, setDbKeyStatus] = useState('')
|
||||
const [imageKeyStatus, setImageKeyStatus] = useState('')
|
||||
const [isManualStartPrompt, setIsManualStartPrompt] = useState(false)
|
||||
const [isClearingAnalyticsCache, setIsClearingAnalyticsCache] = useState(false)
|
||||
const [isClearingImageCache, setIsClearingImageCache] = useState(false)
|
||||
const [isClearingAllCache, setIsClearingAllCache] = useState(false)
|
||||
|
||||
const isClearingCache = isClearingAnalyticsCache || isClearingImageCache || isClearingAllCache
|
||||
|
||||
useEffect(() => {
|
||||
loadConfig()
|
||||
@@ -428,6 +435,59 @@ function SettingsPage() {
|
||||
}
|
||||
}
|
||||
|
||||
const handleClearAnalyticsCache = async () => {
|
||||
if (isClearingCache) return
|
||||
setIsClearingAnalyticsCache(true)
|
||||
try {
|
||||
const result = await window.electronAPI.cache.clearAnalytics()
|
||||
if (result.success) {
|
||||
clearAnalyticsStoreCache()
|
||||
showMessage('已清除分析缓存', true)
|
||||
} else {
|
||||
showMessage(`清除分析缓存失败: ${result.error || '未知错误'}`, false)
|
||||
}
|
||||
} catch (e) {
|
||||
showMessage(`清除分析缓存失败: ${e}`, false)
|
||||
} finally {
|
||||
setIsClearingAnalyticsCache(false)
|
||||
}
|
||||
}
|
||||
|
||||
const handleClearImageCache = async () => {
|
||||
if (isClearingCache) return
|
||||
setIsClearingImageCache(true)
|
||||
try {
|
||||
const result = await window.electronAPI.cache.clearImages()
|
||||
if (result.success) {
|
||||
showMessage('已清除图片缓存', true)
|
||||
} else {
|
||||
showMessage(`清除图片缓存失败: ${result.error || '未知错误'}`, false)
|
||||
}
|
||||
} catch (e) {
|
||||
showMessage(`清除图片缓存失败: ${e}`, false)
|
||||
} finally {
|
||||
setIsClearingImageCache(false)
|
||||
}
|
||||
}
|
||||
|
||||
const handleClearAllCache = async () => {
|
||||
if (isClearingCache) return
|
||||
setIsClearingAllCache(true)
|
||||
try {
|
||||
const result = await window.electronAPI.cache.clearAll()
|
||||
if (result.success) {
|
||||
clearAnalyticsStoreCache()
|
||||
showMessage('已清除所有缓存', true)
|
||||
} else {
|
||||
showMessage(`清除所有缓存失败: ${result.error || '未知错误'}`, false)
|
||||
}
|
||||
} catch (e) {
|
||||
showMessage(`清除所有缓存失败: ${e}`, false)
|
||||
} finally {
|
||||
setIsClearingAllCache(false)
|
||||
}
|
||||
}
|
||||
|
||||
const renderAppearanceTab = () => (
|
||||
<div className="tab-content">
|
||||
<div className="theme-mode-toggle">
|
||||
@@ -597,9 +657,15 @@ function SettingsPage() {
|
||||
<div className="tab-content">
|
||||
<p className="section-desc">管理应用缓存数据</p>
|
||||
<div className="btn-row">
|
||||
<button className="btn btn-secondary"><Trash2 size={16} /> 清除分析缓存</button>
|
||||
<button className="btn btn-secondary"><Trash2 size={16} /> 清除图片缓存</button>
|
||||
<button className="btn btn-danger"><Trash2 size={16} /> 清除所有缓存</button>
|
||||
<button className="btn btn-secondary" onClick={handleClearAnalyticsCache} disabled={isClearingCache}>
|
||||
<Trash2 size={16} /> 清除分析缓存
|
||||
</button>
|
||||
<button className="btn btn-secondary" onClick={handleClearImageCache} disabled={isClearingCache}>
|
||||
<Trash2 size={16} /> 清除图片缓存
|
||||
</button>
|
||||
<button className="btn btn-danger" onClick={handleClearAllCache} disabled={isClearingCache}>
|
||||
<Trash2 size={16} /> 清除所有缓存
|
||||
</button>
|
||||
</div>
|
||||
<div className="divider" />
|
||||
<p className="section-desc">清除当前配置并重新开始首次引导</p>
|
||||
|
||||
5
src/types/electron.d.ts
vendored
5
src/types/electron.d.ts
vendored
@@ -148,6 +148,11 @@ export interface ElectronAPI {
|
||||
}>
|
||||
onProgress: (callback: (payload: { status: string; progress: number }) => void) => () => void
|
||||
}
|
||||
cache: {
|
||||
clearAnalytics: () => Promise<{ success: boolean; error?: string }>
|
||||
clearImages: () => Promise<{ success: boolean; error?: string }>
|
||||
clearAll: () => Promise<{ success: boolean; error?: string }>
|
||||
}
|
||||
groupAnalytics: {
|
||||
getGroupChats: () => Promise<{
|
||||
success: boolean
|
||||
|
||||
Reference in New Issue
Block a user