mirror of
https://github.com/hicccc77/WeFlow.git
synced 2026-03-25 15:25:50 +00:00
修复 #389 ;并优化了引导页面
This commit is contained in:
@@ -5202,6 +5202,24 @@ function MessageBubble({
|
||||
const [emojiError, setEmojiError] = useState(false)
|
||||
const [emojiLoading, setEmojiLoading] = useState(false)
|
||||
|
||||
// 缓存相关的 state 必须在所有 Hooks 之前声明
|
||||
const cacheKey = message.emojiMd5 || message.emojiCdnUrl || ''
|
||||
const [emojiLocalPath, setEmojiLocalPath] = useState<string | undefined>(
|
||||
() => emojiDataUrlCache.get(cacheKey) || message.emojiLocalPath
|
||||
)
|
||||
const imageCacheKey = message.imageMd5 || message.imageDatName || `local:${message.localId}`
|
||||
const [imageLocalPath, setImageLocalPath] = useState<string | undefined>(
|
||||
() => imageDataUrlCache.get(imageCacheKey)
|
||||
)
|
||||
const voiceCacheKey = `voice:${message.localId}`
|
||||
const [voiceDataUrl, setVoiceDataUrl] = useState<string | undefined>(
|
||||
() => voiceDataUrlCache.get(voiceCacheKey)
|
||||
)
|
||||
const voiceTranscriptCacheKey = `voice-transcript:${message.localId}`
|
||||
const [voiceTranscript, setVoiceTranscript] = useState<string | undefined>(
|
||||
() => voiceTranscriptCache.get(voiceTranscriptCacheKey)
|
||||
)
|
||||
|
||||
// State variables...
|
||||
const [imageError, setImageError] = useState(false)
|
||||
const [imageLoading, setImageLoading] = useState(false)
|
||||
@@ -5282,24 +5300,6 @@ function MessageBubble({
|
||||
loadConfig()
|
||||
}, [])
|
||||
|
||||
// 从缓存获取表情包 data URL
|
||||
const cacheKey = message.emojiMd5 || message.emojiCdnUrl || ''
|
||||
const [emojiLocalPath, setEmojiLocalPath] = useState<string | undefined>(
|
||||
() => emojiDataUrlCache.get(cacheKey) || message.emojiLocalPath
|
||||
)
|
||||
const imageCacheKey = message.imageMd5 || message.imageDatName || `local:${message.localId}`
|
||||
const [imageLocalPath, setImageLocalPath] = useState<string | undefined>(
|
||||
() => imageDataUrlCache.get(imageCacheKey)
|
||||
)
|
||||
const voiceCacheKey = `voice:${message.localId}`
|
||||
const [voiceDataUrl, setVoiceDataUrl] = useState<string | undefined>(
|
||||
() => voiceDataUrlCache.get(voiceCacheKey)
|
||||
)
|
||||
const voiceTranscriptCacheKey = `voice-transcript:${message.localId}`
|
||||
const [voiceTranscript, setVoiceTranscript] = useState<string | undefined>(
|
||||
() => voiceTranscriptCache.get(voiceTranscriptCacheKey)
|
||||
)
|
||||
|
||||
const formatTime = (timestamp: number): string => {
|
||||
if (!Number.isFinite(timestamp) || timestamp <= 0) return '未知时间'
|
||||
const date = new Date(timestamp * 1000)
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
}
|
||||
|
||||
.settings-page {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: min(1160px, calc(100vw - 96px));
|
||||
|
||||
@@ -557,24 +557,37 @@ function SettingsPage({ onClose }: SettingsPageProps = {}) {
|
||||
}
|
||||
}
|
||||
|
||||
const validatePath = (path: string): string | null => {
|
||||
if (!path) return null
|
||||
if (/[\u4e00-\u9fa5]/.test(path)) {
|
||||
return '路径包含中文字符,请迁移至全英文目录'
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
const handleAutoDetectPath = async () => {
|
||||
if (isDetectingPath) return
|
||||
setIsDetectingPath(true)
|
||||
try {
|
||||
const result = await window.electronAPI.dbPath.autoDetect()
|
||||
if (result.success && result.path) {
|
||||
setDbPath(result.path)
|
||||
await configService.setDbPath(result.path)
|
||||
showMessage(`自动检测成功:${result.path}`, true)
|
||||
const validationError = validatePath(result.path)
|
||||
if (validationError) {
|
||||
showMessage(validationError, false)
|
||||
} else {
|
||||
setDbPath(result.path)
|
||||
await configService.setDbPath(result.path)
|
||||
showMessage(`自动检测成功:${result.path}`, true)
|
||||
|
||||
const wxids = await window.electronAPI.dbPath.scanWxids(result.path)
|
||||
setWxidOptions(wxids)
|
||||
if (wxids.length === 1) {
|
||||
await applyWxidSelection(wxids[0].wxid, {
|
||||
toastText: `已检测到账号:${wxids[0].wxid}`
|
||||
})
|
||||
} else if (wxids.length > 1) {
|
||||
setShowWxidSelect(true)
|
||||
const wxids = await window.electronAPI.dbPath.scanWxids(result.path)
|
||||
setWxidOptions(wxids)
|
||||
if (wxids.length === 1) {
|
||||
await applyWxidSelection(wxids[0].wxid, {
|
||||
toastText: `已检测到账号:${wxids[0].wxid}`
|
||||
})
|
||||
} else if (wxids.length > 1) {
|
||||
setShowWxidSelect(true)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
showMessage(result.error || '未能自动检测到数据库目录', false)
|
||||
@@ -591,9 +604,14 @@ function SettingsPage({ onClose }: SettingsPageProps = {}) {
|
||||
const result = await dialog.openFile({ title: '选择微信数据库根目录', properties: ['openDirectory'] })
|
||||
if (!result.canceled && result.filePaths.length > 0) {
|
||||
const selectedPath = result.filePaths[0]
|
||||
setDbPath(selectedPath)
|
||||
await configService.setDbPath(selectedPath)
|
||||
showMessage('已选择数据库目录', true)
|
||||
const validationError = validatePath(selectedPath)
|
||||
if (validationError) {
|
||||
showMessage(validationError, false)
|
||||
} else {
|
||||
setDbPath(selectedPath)
|
||||
await configService.setDbPath(selectedPath)
|
||||
showMessage('已选择数据库目录', true)
|
||||
}
|
||||
}
|
||||
} catch (e: any) {
|
||||
showMessage('选择目录失败', false)
|
||||
@@ -1287,7 +1305,6 @@ function SettingsPage({ onClose }: SettingsPageProps = {}) {
|
||||
<div className="form-group">
|
||||
<label>数据库根目录</label>
|
||||
<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"
|
||||
|
||||
@@ -77,6 +77,7 @@
|
||||
|
||||
/* Unified Card Container */
|
||||
.welcome-container {
|
||||
position: relative;
|
||||
width: 900px;
|
||||
max-width: 100vw;
|
||||
height: 620px;
|
||||
@@ -543,6 +544,18 @@
|
||||
font-size: 13px;
|
||||
margin-top: 8px;
|
||||
border: 1px solid rgba(0, 0, 0, 0.04);
|
||||
|
||||
&.is-success {
|
||||
background: rgba(34, 197, 94, 0.15);
|
||||
color: rgb(22, 163, 74);
|
||||
border-color: rgba(34, 197, 94, 0.3);
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
background: rgba(34, 197, 94, 0.2);
|
||||
color: rgb(134, 239, 172);
|
||||
border-color: rgba(34, 197, 94, 0.4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.error-message {
|
||||
@@ -878,4 +891,4 @@
|
||||
@keyframes progress-shimmer {
|
||||
0% { transform: translateX(-100%); }
|
||||
100% { transform: translateX(100%); }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
FolderOpen, FolderSearch, KeyRound, ShieldCheck, Sparkles,
|
||||
UserRound, Wand2, Minus, X, HardDrive, RotateCcw
|
||||
} from 'lucide-react'
|
||||
import ConfirmDialog from '../components/ConfirmDialog'
|
||||
import './WelcomePage.scss'
|
||||
|
||||
const steps = [
|
||||
@@ -61,6 +62,7 @@ function WelcomePage({ standalone = false }: WelcomePageProps) {
|
||||
const [imageKeyStatus, setImageKeyStatus] = useState('')
|
||||
const [isManualStartPrompt, setIsManualStartPrompt] = useState(false)
|
||||
const [imageKeyPercent, setImageKeyPercent] = useState<number | null>(null)
|
||||
const [showDbKeyConfirm, setShowDbKeyConfirm] = useState(false)
|
||||
|
||||
// 安全相关 state
|
||||
const [enableAuth, setEnableAuth] = useState(false)
|
||||
@@ -123,6 +125,14 @@ function WelcomePage({ standalone = false }: WelcomePageProps) {
|
||||
useEffect(() => {
|
||||
const removeDb = window.electronAPI.key.onDbKeyStatus((payload: { message: string; level: number }) => {
|
||||
setDbKeyStatus(payload.message)
|
||||
if (payload.message.includes('现在可以登录') || payload.message.includes('Hook安装成功')) {
|
||||
window.electronAPI.notification?.show({
|
||||
title: 'WeFlow 准备就绪',
|
||||
content: '现在可以登录微信了',
|
||||
avatarUrl: './logo.png',
|
||||
sessionId: 'weflow-system'
|
||||
})
|
||||
}
|
||||
})
|
||||
const removeImage = window.electronAPI.key.onImageKeyStatus((payload: { message: string, percent?: number }) => {
|
||||
let msg = payload.message;
|
||||
@@ -187,6 +197,15 @@ function WelcomePage({ standalone = false }: WelcomePageProps) {
|
||||
window.electronAPI.window.close()
|
||||
}
|
||||
|
||||
const validatePath = (path: string): string | null => {
|
||||
if (!path) return null
|
||||
// 检测中文字符和其他可能有问题的特殊字符
|
||||
if (/[\u4e00-\u9fa5]/.test(path)) {
|
||||
return '路径包含中文字符,请迁移至全英文目录'
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
const handleSelectPath = async () => {
|
||||
try {
|
||||
const result = await dialog.openFile({
|
||||
@@ -195,8 +214,14 @@ function WelcomePage({ standalone = false }: WelcomePageProps) {
|
||||
})
|
||||
|
||||
if (!result.canceled && result.filePaths.length > 0) {
|
||||
setDbPath(result.filePaths[0])
|
||||
setError('')
|
||||
const selectedPath = result.filePaths[0]
|
||||
const validationError = validatePath(selectedPath)
|
||||
if (validationError) {
|
||||
setError(validationError)
|
||||
} else {
|
||||
setDbPath(selectedPath)
|
||||
setError('')
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
setError('选择目录失败')
|
||||
@@ -210,8 +235,13 @@ function WelcomePage({ standalone = false }: WelcomePageProps) {
|
||||
try {
|
||||
const result = await window.electronAPI.dbPath.autoDetect()
|
||||
if (result.success && result.path) {
|
||||
setDbPath(result.path)
|
||||
setError('')
|
||||
const validationError = validatePath(result.path)
|
||||
if (validationError) {
|
||||
setError(validationError)
|
||||
} else {
|
||||
setDbPath(result.path)
|
||||
setError('')
|
||||
}
|
||||
} else {
|
||||
setError(result.error || '未能检测到数据库目录')
|
||||
}
|
||||
@@ -287,6 +317,11 @@ function WelcomePage({ standalone = false }: WelcomePageProps) {
|
||||
|
||||
const handleAutoGetDbKey = async () => {
|
||||
if (isFetchingDbKey) return
|
||||
setShowDbKeyConfirm(true)
|
||||
}
|
||||
|
||||
const handleDbKeyConfirm = async () => {
|
||||
setShowDbKeyConfirm(false)
|
||||
setIsFetchingDbKey(true)
|
||||
setError('')
|
||||
setIsManualStartPrompt(false)
|
||||
@@ -297,7 +332,6 @@ function WelcomePage({ standalone = false }: WelcomePageProps) {
|
||||
setDecryptKey(result.key)
|
||||
setDbKeyStatus('密钥获取成功')
|
||||
setError('')
|
||||
// 获取成功后自动扫描并填入 wxid
|
||||
await handleScanWxid(true)
|
||||
} else {
|
||||
if (result.error?.includes('未找到微信安装路径') || result.error?.includes('启动微信失败')) {
|
||||
@@ -613,9 +647,6 @@ function WelcomePage({ standalone = false }: WelcomePageProps) {
|
||||
</div>
|
||||
|
||||
<div className="field-hint">请选择微信-设置-存储位置对应的目录</div>
|
||||
<div className="field-hint warning">
|
||||
目录路径不可包含中文,如有中文请先在微信中迁移至全英文目录
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -705,7 +736,7 @@ function WelcomePage({ standalone = false }: WelcomePageProps) {
|
||||
)}
|
||||
</div>
|
||||
|
||||
{dbKeyStatus && <div className="status-message">{dbKeyStatus}</div>}
|
||||
{dbKeyStatus && <div className={`status-message ${dbKeyStatus.includes('现在可以登录') || dbKeyStatus.includes('Hook安装成功') ? 'is-success' : ''}`}>{dbKeyStatus}</div>}
|
||||
<div className="field-hint">点击自动获取后微信将重启,请留意弹窗提示</div>
|
||||
</div>
|
||||
)}
|
||||
@@ -840,6 +871,16 @@ function WelcomePage({ standalone = false }: WelcomePageProps) {
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ConfirmDialog
|
||||
open={showDbKeyConfirm}
|
||||
title="开始获取数据库密钥"
|
||||
message={`当开始获取后 WeFlow 将会执行准备操作
|
||||
|
||||
当 WeFlow 内的提示条变为绿色显示允许登录或看到来自WeFlow的登录通知时,登录你的微信或退出当前登录并重新登录。`}
|
||||
onConfirm={handleDbKeyConfirm}
|
||||
onCancel={() => setShowDbKeyConfirm(false)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user