优化前端显示和错误提醒

This commit is contained in:
H3CoF6
2026-04-29 04:38:25 +08:00
parent 1f0b2613bf
commit d27cef6358
3 changed files with 152 additions and 42 deletions

View File

@@ -3957,8 +3957,7 @@ function registerIpcHandlers() {
// 自动下载原图 // 自动下载原图
ipcMain.handle('image:startAutoDownload', async () => { ipcMain.handle('image:startAutoDownload', async () => {
await imageDownloadService.startAutoDownload() return await imageDownloadService.startAutoDownload()
return { success: true }
}) })
ipcMain.handle('image:stopAutoDownload', async () => { ipcMain.handle('image:stopAutoDownload', async () => {

View File

@@ -96,14 +96,16 @@ export class ImageDownloadService {
} }
} }
async startAutoDownload() { async startAutoDownload(): Promise<{ success: boolean; error?: string }> {
if (!await this.ensureInitialized()) return if (!await this.ensureInitialized()) {
return { success: false, error: '核心组件初始化失败,请检查环境' }
}
if (this.pollTimer) return if (this.pollTimer) return { success: true }
this.pollTimer = setInterval(() => this.checkAndHook(), 30000) this.pollTimer = setInterval(() => this.checkAndHook(), 30000)
// Initial check // 首次尝试 Hook并返回结果
await this.checkAndHook() return await this.checkAndHook(true)
} }
async stopAutoDownload() { async stopAutoDownload() {
@@ -114,7 +116,7 @@ export class ImageDownloadService {
await this.unhook() await this.unhook()
} }
private async checkAndHook() { private async checkAndHook(isManualStart = false): Promise<{ success: boolean; error?: string }> {
const pid = await this.findMainWeChatPid() const pid = await this.findMainWeChatPid()
if (!pid) { if (!pid) {
@@ -122,11 +124,12 @@ export class ImageDownloadService {
console.log('[ImageDownloadService] WeChat exited, unhooking') console.log('[ImageDownloadService] WeChat exited, unhooking')
await this.unhook() await this.unhook()
} }
return // 如果是手动开启时没找到进程,不认为是严重错误,只是挂起等待
return { success: true, error: '等待微信启动' }
} }
if (this.isHooked && this.currentPid === pid) { if (this.isHooked && this.currentPid === pid) {
return return { success: true }
} }
if (this.isHooked && this.currentPid !== pid) { if (this.isHooked && this.currentPid !== pid) {
@@ -141,12 +144,24 @@ export class ImageDownloadService {
this.isHooked = true this.isHooked = true
this.currentPid = pid this.currentPid = pid
console.log('[ImageDownloadService] hook successful') console.log('[ImageDownloadService] hook successful')
return { success: true }
} else { } else {
const err = this.getImgHelperError() const err = this.getImgHelperError()
console.error(`[ImageDownloadService] hook failed: ${err}`) console.error(`[ImageDownloadService] hook failed: ${err}`)
// 如果是手动点击开启时失败,停止轮询并向上报错
if (isManualStart && this.pollTimer) {
clearInterval(this.pollTimer)
this.pollTimer = null
} }
} catch (e) { return { success: false, error: err || 'Hook 失败' }
}
} catch (e: any) {
console.error('[ImageDownloadService] InitImgHelper call crashed:', e) console.error('[ImageDownloadService] InitImgHelper call crashed:', e)
if (isManualStart && this.pollTimer) {
clearInterval(this.pollTimer)
this.pollTimer = null
}
return { success: false, error: `调用异常: ${e.message || String(e)}` }
} }
} }

View File

@@ -327,6 +327,7 @@ function SettingsPage({ onClose }: SettingsPageProps = {}) {
const [aiFootprintEnabled, setAiFootprintEnabled] = useState(false) const [aiFootprintEnabled, setAiFootprintEnabled] = useState(false)
const [aiFootprintSystemPrompt, setAiFootprintSystemPrompt] = useState('') const [aiFootprintSystemPrompt, setAiFootprintSystemPrompt] = useState('')
const [aiInsightDebugLogEnabled, setAiInsightDebugLogEnabled] = useState(false) const [aiInsightDebugLogEnabled, setAiInsightDebugLogEnabled] = useState(false)
const [autoDownloadStatus, setAutoDownloadStatus] = useState<{ isHooked: boolean; pid: number | null; supported: boolean } | null>(null)
// 检查 Hello 可用性 // 检查 Hello 可用性
useEffect(() => { useEffect(() => {
@@ -706,6 +707,21 @@ function SettingsPage({ onClose }: SettingsPageProps = {}) {
void refreshWhisperStatus(whisperModelDir) void refreshWhisperStatus(whisperModelDir)
}, [whisperModelDir]) }, [whisperModelDir])
useEffect(() => {
if (activeTab === 'autoDownload') {
fetchAutoDownloadStatus()
let interval: ReturnType<typeof setInterval> | undefined
if (autoDownloadHighRes) {
interval = setInterval(fetchAutoDownloadStatus, 2000)
}
return () => {
if (interval) clearInterval(interval)
}
}
}, [activeTab, autoDownloadHighRes])
const getErrorMessage = (error: any): string => { const getErrorMessage = (error: any): string => {
const raw = typeof error?.message === 'string' ? error.message : String(error ?? '') const raw = typeof error?.message === 'string' ? error.message : String(error ?? '')
const normalized = raw.replace(/^Error:\s*/i, '').trim() const normalized = raw.replace(/^Error:\s*/i, '').trim()
@@ -1600,6 +1616,15 @@ function SettingsPage({ onClose }: SettingsPageProps = {}) {
} }
} }
const fetchAutoDownloadStatus = async () => {
try {
const status = await (window as any).electronAPI.image.getAutoDownloadStatus()
setAutoDownloadStatus(status)
} catch (error) {
console.error('获取自动下载状态失败:', error)
}
}
const renderAppearanceTab = () => ( const renderAppearanceTab = () => (
<div className="tab-content"> <div className="tab-content">
<div className="theme-mode-toggle"> <div className="theme-mode-toggle">
@@ -4672,16 +4697,24 @@ function SettingsPage({ onClose }: SettingsPageProps = {}) {
const renderAutoDownloadTab = () => ( const renderAutoDownloadTab = () => (
<div className="tab-content"> <div className="tab-content">
<div className="form-group"> <div className="updates-hero" style={{ background: 'linear-gradient(110deg, var(--bg-primary) 0%, rgba(245, 158, 11, 0.1) 100%)', borderColor: 'rgba(245, 158, 11, 0.3)' }}>
<label></label> <div className="updates-hero-main">
<span className="form-hint"> <span className="updates-chip" style={{ color: '#f59e0b', background: 'rgba(245, 158, 11, 0.15)' }}></span>
WeFlow Hook <h2></h2>
<br /> <p></p>
<strong></strong>Hook DLL </div>
</span> </div>
<div className="log-toggle-line">
<span className="log-status">{autoDownloadHighRes ? '已开启' : '已关闭'}</span> <div className="form-group" style={{ marginTop: '24px' }}>
<label className="switch" htmlFor="auto-download-high-res-toggle"> <div className="setting-control vertical has-border">
<div className="log-toggle-line" style={{ marginTop: 0, border: 'none', background: 'transparent', padding: 0 }}>
<div>
<span className="log-status" style={{ fontSize: '15px', fontWeight: 600 }}></span>
<div style={{ marginTop: '4px', fontSize: '13px', color: 'var(--text-tertiary)' }}>
WeFlow Hook
</div>
</div>
<label className="switch switch-lg" htmlFor="auto-download-high-res-toggle">
<input <input
id="auto-download-high-res-toggle" id="auto-download-high-res-toggle"
className="switch-input" className="switch-input"
@@ -4694,18 +4727,81 @@ function SettingsPage({ onClose }: SettingsPageProps = {}) {
</div> </div>
</div> </div>
</div> </div>
)
<div className="api-warning-modal" style={{ width: '100%', animation: 'none', boxShadow: 'none', border: '1px solid var(--border-color)', marginTop: '20px' }}>
<div className="modal-header" style={{ padding: '16px 20px', background: 'var(--bg-tertiary)' }}>
<ShieldCheck size={18} />
<h3 style={{ fontSize: '14px' }}></h3>
</div>
<div className="modal-body" style={{ padding: '16px 20px' }}>
{!autoDownloadHighRes ? (
<div className="warning-item"><span style={{ color: 'var(--text-tertiary)' }}></span></div>
) : !autoDownloadStatus ? (
<div className="warning-item"><span>...</span></div>
) : !autoDownloadStatus.supported ? (
<div className="warning-item"><span style={{ color: 'var(--danger)' }}> Win32 x64</span></div>
) : autoDownloadStatus.isHooked ? (
<div className="warning-item">
<span style={{ color: '#10b981', fontWeight: 'bold' }}> </span>
<span style={{ marginLeft: '12px', color: 'var(--text-secondary)' }}> (PID: {autoDownloadStatus.pid})</span>
</div>
) : (
<div className="warning-item">
<span style={{ color: '#f59e0b', fontWeight: 'bold' }}> </span>
<span style={{ marginLeft: '12px', color: 'var(--text-secondary)' }}> (Weixin.exe) </span>
</div>
)}
</div>
</div>
<div className="api-warning-modal" style={{ width: '100%', animation: 'none', boxShadow: 'none', border: '1px solid rgba(239, 68, 68, 0.3)', marginTop: '20px' }}>
<div className="modal-header" style={{ padding: '16px 20px', background: 'rgba(239, 68, 68, 0.05)', borderBottomColor: 'rgba(239, 68, 68, 0.2)' }}>
<ShieldCheck size={18} color="#ef4444" />
<h3 style={{ fontSize: '14px', color: '#ef4444' }}></h3>
</div>
<div className="modal-body" style={{ padding: '16px 20px' }}>
<div className="warning-list">
<div className="warning-item">
<span className="bullet" style={{ color: '#ef4444' }}></span>
<span>hook修改微信进程内存</span>
</div>
<div className="warning-item">
<span className="bullet" style={{ color: '#ef4444' }}></span>
<span> DLL<strong></strong></span>
</div>
<div className="warning-item">
<span className="bullet" style={{ color: '#ef4444' }}></span>
<span>使</span>
</div>
</div>
</div>
</div>
</div>
)
const handleToggleAutoDownload = async () => { const handleToggleAutoDownload = async () => {
const newVal = !autoDownloadHighRes const newVal = !autoDownloadHighRes
setAutoDownloadHighRes(newVal) setAutoDownloadHighRes(newVal)
await configService.setAutoDownloadHighRes(newVal)
try {
if (newVal) { if (newVal) {
await (window as any).electronAPI.image.startAutoDownload() const result = await (window as any).electronAPI.image.startAutoDownload()
if (result && !result.success) {
// 如果底层明确返回了失败
throw new Error(result.error || '启动自动下载服务失败')
}
showMessage('自动下载已开启,正在尝试连接微信', true)
await fetchAutoDownloadStatus()
} else { } else {
await (window as any).electronAPI.image.stopAutoDownload() await (window as any).electronAPI.image.stopAutoDownload()
showMessage('自动下载已关闭', true)
setAutoDownloadStatus(null)
}
await configService.setAutoDownloadHighRes(newVal)
} catch (e: any) {
// 发生错误时,将开关拨回去
setAutoDownloadHighRes(!newVal)
showMessage(`操作失败: ${e.message || String(e)}`, false)
} }
showMessage(newVal ? '自动下载已开启' : '自动下载已关闭', true)
} }
const renderUpdatesTab = () => { const renderUpdatesTab = () => {