feat: update welcome page and fix handle error

This commit is contained in:
H3CoF6
2026-02-28 05:37:19 +08:00
parent 5b3b8b5bc3
commit 0d33fe8fe4
3 changed files with 146 additions and 35 deletions

View File

@@ -146,10 +146,11 @@ export class KeyService {
this.koffi = require('koffi') this.koffi = require('koffi')
this.kernel32 = this.koffi.load('kernel32.dll') this.kernel32 = this.koffi.load('kernel32.dll')
this.OpenProcess = this.kernel32.func('OpenProcess', 'HANDLE', ['uint32', 'bool', 'uint32']) // 直接使用原生支持的 'void*' 替换 'HANDLE',绝对不会再报类型错误
this.CloseHandle = this.kernel32.func('CloseHandle', 'bool', ['HANDLE']) this.OpenProcess = this.kernel32.func('OpenProcess', 'void*', ['uint32', 'bool', 'uint32'])
this.TerminateProcess = this.kernel32.func('TerminateProcess', 'bool', ['HANDLE', 'uint32']) this.CloseHandle = this.kernel32.func('CloseHandle', 'bool', ['void*'])
this.QueryFullProcessImageNameW = this.kernel32.func('QueryFullProcessImageNameW', 'bool', ['HANDLE', 'uint32', this.koffi.out('uint16*'), this.koffi.out('uint32*')]) this.TerminateProcess = this.kernel32.func('TerminateProcess', 'bool', ['void*', 'uint32'])
this.QueryFullProcessImageNameW = this.kernel32.func('QueryFullProcessImageNameW', 'bool', ['void*', 'uint32', this.koffi.out('uint16*'), this.koffi.out('uint32*')])
return true return true
} catch (e) { } catch (e) {

View File

@@ -803,3 +803,79 @@
opacity: 1; opacity: 1;
} }
} }
.brute-force-progress {
margin-top: 16px;
padding: 14px 16px;
background: var(--bg-tertiary);
border: 1px solid var(--border-color);
border-radius: 12px;
animation: slideUp 0.3s ease;
.status-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
.status-text {
font-size: 13px;
color: var(--text-primary);
font-weight: 500;
margin: 0;
animation: pulse 2s ease-in-out infinite;
}
.percent {
font-size: 14px;
color: var(--primary);
font-weight: 700;
font-family: var(--font-mono);
}
}
.progress-bar-container {
width: 100%;
height: 8px;
background: var(--bg-primary);
border-radius: 4px;
overflow: hidden;
border: 1px solid var(--border-color);
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.05);
.fill {
height: 100%;
background: linear-gradient(90deg, var(--primary) 0%, color-mix(in srgb, var(--primary) 60%, white) 100%);
border-radius: 4px;
transition: width 0.3s cubic-bezier(0.4, 0, 0.2, 1);
position: relative;
&::after {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: linear-gradient(
90deg,
transparent,
rgba(255, 255, 255, 0.3),
transparent
);
animation: progress-shimmer 1.5s infinite linear;
}
}
}
}
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.7; }
}
@keyframes progress-shimmer {
0% { transform: translateX(-100%); }
100% { transform: translateX(100%); }
}

View File

@@ -48,6 +48,7 @@ function WelcomePage({ standalone = false }: WelcomePageProps) {
const [dbKeyStatus, setDbKeyStatus] = useState('') const [dbKeyStatus, setDbKeyStatus] = useState('')
const [imageKeyStatus, setImageKeyStatus] = useState('') const [imageKeyStatus, setImageKeyStatus] = useState('')
const [isManualStartPrompt, setIsManualStartPrompt] = useState(false) const [isManualStartPrompt, setIsManualStartPrompt] = useState(false)
const [imageKeyPercent, setImageKeyPercent] = useState<number | null>(null)
// 安全相关 state // 安全相关 state
const [enableAuth, setEnableAuth] = useState(false) const [enableAuth, setEnableAuth] = useState(false)
@@ -111,8 +112,25 @@ function WelcomePage({ standalone = false }: WelcomePageProps) {
const removeDb = window.electronAPI.key.onDbKeyStatus((payload: { message: string; level: number }) => { const removeDb = window.electronAPI.key.onDbKeyStatus((payload: { message: string; level: number }) => {
setDbKeyStatus(payload.message) setDbKeyStatus(payload.message)
}) })
const removeImage = window.electronAPI.key.onImageKeyStatus((payload: { message: string }) => { const removeImage = window.electronAPI.key.onImageKeyStatus((payload: { message: string, percent?: number }) => {
setImageKeyStatus(payload.message) let msg = payload.message;
let pct = payload.percent;
// 解析文本中的百分比
if (pct === undefined) {
const match = msg.match(/\(([\d.]+)%\)/);
if (match) {
pct = parseFloat(match[1]);
msg = msg.replace(/\s*\([\d.]+%\)/, '');
}
}
setImageKeyStatus(msg);
if (pct !== undefined) {
setImageKeyPercent(pct);
} else if (msg.includes('启动多核') || msg.includes('定位') || msg.includes('准备')) {
setImageKeyPercent(0);
}
}) })
return () => { return () => {
removeDb?.() removeDb?.()
@@ -297,6 +315,7 @@ function WelcomePage({ standalone = false }: WelcomePageProps) {
} }
setIsFetchingImageKey(true) setIsFetchingImageKey(true)
setError('') setError('')
setImageKeyPercent(0)
setImageKeyStatus('正在准备获取图片密钥...') setImageKeyStatus('正在准备获取图片密钥...')
try { try {
// 拼接完整的账号目录,确保 KeyService 能准确找到模板文件 // 拼接完整的账号目录,确保 KeyService 能准确找到模板文件
@@ -752,10 +771,25 @@ function WelcomePage({ standalone = false }: WelcomePageProps) {
</div> </div>
<button className="btn btn-secondary btn-block mt-4" onClick={handleAutoGetImageKey} disabled={isFetchingImageKey}> <button className="btn btn-secondary btn-block mt-4" onClick={handleAutoGetImageKey} disabled={isFetchingImageKey}>
{isFetchingImageKey ? '扫描中...' : '自动获取图片密钥'} {isFetchingImageKey ? '获取中...' : '自动获取图片密钥'}
</button> </button>
{imageKeyStatus && <div className="status-message">{imageKeyStatus}</div>} {isFetchingImageKey ? (
<div className="brute-force-progress">
<div className="status-header">
<span className="status-text">{imageKeyStatus || '正在启动多核爆破引擎...'}</span>
{imageKeyPercent !== null && <span className="percent">{imageKeyPercent.toFixed(1)}%</span>}
</div>
{imageKeyPercent !== null && (
<div className="progress-bar-container">
<div className="fill" style={{ width: `${imageKeyPercent}%` }}></div>
</div>
)}
</div>
) : (
imageKeyStatus && <div className="status-message" style={{ marginTop: '12px' }}>{imageKeyStatus}</div>
)}
<div className="field-hint"></div> <div className="field-hint"></div>
</div> </div>
)} )}