5 changed files with 262 additions and 68 deletions
@ -0,0 +1,114 @@ |
|||||
|
import React, { useState } from 'react'; |
||||
|
import { Card, Input, Button, message } from 'antd'; |
||||
|
import { LockOutlined } from '@ant-design/icons'; |
||||
|
|
||||
|
/** |
||||
|
* 高级配置密码验证组件 |
||||
|
*/ |
||||
|
const AdvancedConfigAuth = ({ verifyPassword, onUnlock }) => { |
||||
|
const [password, setPassword] = useState(''); |
||||
|
const [loading, setLoading] = useState(false); |
||||
|
|
||||
|
const handleVerify = async () => { |
||||
|
if (!password) { |
||||
|
message.warning('请输入密码'); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
setLoading(true); |
||||
|
try { |
||||
|
const isValid = await verifyPassword(password); |
||||
|
|
||||
|
if (isValid) { |
||||
|
message.success('密码正确,已解锁高级配置'); |
||||
|
onUnlock && onUnlock(); |
||||
|
} else { |
||||
|
message.error('密码错误,请重试'); |
||||
|
setPassword(''); |
||||
|
} |
||||
|
} catch (error) { |
||||
|
console.error('密码验证失败:', error); |
||||
|
message.error('验证过程出错,请重试'); |
||||
|
} finally { |
||||
|
setLoading(false); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
const handleKeyPress = (e) => { |
||||
|
if (e.key === 'Enter') { |
||||
|
handleVerify(); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
return ( |
||||
|
<div |
||||
|
style={{ |
||||
|
display: 'flex', |
||||
|
alignItems: 'center', |
||||
|
justifyContent: 'center', |
||||
|
minHeight: 'calc(100vh - 92px)', |
||||
|
padding: '24px', |
||||
|
}} |
||||
|
> |
||||
|
<Card |
||||
|
style={{ |
||||
|
width: 400, |
||||
|
textAlign: 'center', |
||||
|
boxShadow: '0 2px 8px rgba(0,0,0,0.1)', |
||||
|
}} |
||||
|
> |
||||
|
<div |
||||
|
style={{ |
||||
|
width: 64, |
||||
|
height: 64, |
||||
|
borderRadius: '50%', |
||||
|
backgroundColor: '#e6f4ff', |
||||
|
display: 'flex', |
||||
|
alignItems: 'center', |
||||
|
justifyContent: 'center', |
||||
|
margin: '0 auto 24px', |
||||
|
}} |
||||
|
> |
||||
|
<LockOutlined style={{ fontSize: 32, color: '#1890ff' }} /> |
||||
|
</div> |
||||
|
|
||||
|
<h2 style={{ marginBottom: 8 }}>内部高级配置</h2> |
||||
|
<p style={{ color: '#999', marginBottom: 24 }}> |
||||
|
请输入管理员访问密码以继续 |
||||
|
</p> |
||||
|
|
||||
|
<Input.Password |
||||
|
size="large" |
||||
|
placeholder="请输入密码" |
||||
|
value={password} |
||||
|
onChange={(e) => setPassword(e.target.value)} |
||||
|
onKeyPress={handleKeyPress} |
||||
|
prefix={<LockOutlined style={{ color: '#999' }} />} |
||||
|
style={{ marginBottom: 16 }} |
||||
|
/> |
||||
|
|
||||
|
<Button |
||||
|
type="primary" |
||||
|
size="large" |
||||
|
block |
||||
|
loading={loading} |
||||
|
onClick={handleVerify} |
||||
|
> |
||||
|
解锁配置 |
||||
|
</Button> |
||||
|
|
||||
|
<div |
||||
|
style={{ |
||||
|
marginTop: 24, |
||||
|
fontSize: 12, |
||||
|
color: '#999', |
||||
|
}} |
||||
|
> |
||||
|
视觉位移计配置工具 v{window.env?.FS_VERSION || ''} Build {new Date().getFullYear()} |
||||
|
</div> |
||||
|
</Card> |
||||
|
</div> |
||||
|
); |
||||
|
}; |
||||
|
|
||||
|
export default AdvancedConfigAuth; |
||||
@ -0,0 +1 @@ |
|||||
|
import { useState, useEffect, useCallback } from "react"; const CORRECT_PASSWORD_HASH = "77796ac7e66ecc44954287ed7de7096c4016dd6ffb2763091c4eb3bc4d28b6dc", AUTH_STATUS_KEY = "advanced_config_unlocked"; async function generatePasswordHash(e) { try { var t = (new TextEncoder).encode(e), c = await crypto.subtle.digest("SHA-256", t); return Array.from(new Uint8Array(c)).map(e => e.toString(16).padStart(2, "0")).join("") } catch (e) { throw console.error("密码哈希生成失败:", e), e } } function checkUnlockStatus() { return "true" === sessionStorage.getItem(AUTH_STATUS_KEY) } function setUnlockStatus(e) { e ? sessionStorage.setItem(AUTH_STATUS_KEY, "true") : sessionStorage.removeItem(AUTH_STATUS_KEY) } function useAuth() { let [e, t] = useState(checkUnlockStatus); return useEffect(() => { t(checkUnlockStatus()) }, []), { isUnlocked: e, verifyPassword: useCallback(async e => { try { return e ? await generatePasswordHash(e) === CORRECT_PASSWORD_HASH && (setUnlockStatus(!0), t(!0), !0) : !1 } catch (e) { return console.error("密码验证失败:", e), !1 } }, []), logout: useCallback(() => { setUnlockStatus(!1), t(!1) }, []) } } export { useAuth, generatePasswordHash, checkUnlockStatus }; |
||||
Loading…
Reference in new issue