更新 UI

This commit is contained in:
cheney 2026-04-17 13:34:35 +08:00
parent 826419fdbc
commit 9f6df6bbd8
3 changed files with 401 additions and 78 deletions

View File

@ -1,4 +1,5 @@
# TODO
- [ ] CI 集成,将 dist 传输到指定服务器指定目录。
- [x] CI 集成,将 dist 传输到指定服务器指定目录。
- [x] 添加 SM2 算法

View File

@ -1,4 +1,4 @@
import { useState } from 'react'
import { useState, useEffect } from 'react'
import { VERSION } from './version'
import { sm3Digest, sm3Hmac } from './utils/algorithm/sm3'
@ -7,6 +7,33 @@ import { hexToUtf8, utf8ToHex } from './utils/convert'
function App() {
const [activeTab, setActiveTab] = useState('sm3')
const [isMobile, setIsMobile] = useState(false)
const [mobileTab, setMobileTab] = useState('sm3')
// 检测是否为移动设备
useEffect(() => {
const checkMobile = () => {
setIsMobile(window.innerWidth < 768)
}
checkMobile()
window.addEventListener('resize', checkMobile)
return () => {
window.removeEventListener('resize', checkMobile)
}
}, [])
// 处理移动设备的 tab 切换
const handleMobileTabChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
setMobileTab(e.target.value)
setActiveTab(e.target.value)
}
// 处理桌面端的 tab 切换
const handleTabChange = (tab: string) => {
setActiveTab(tab)
}
@ -92,113 +119,280 @@ function App() {
}
return (
<div className="app">
<h1></h1>
<div className="app" style={{ maxWidth: '800px', margin: '0 auto', padding: '20px', fontFamily: 'Arial, sans-serif', backgroundColor: '#121212', color: '#e0e0e0', minHeight: '100vh' }}>
<h1 style={{ textAlign: 'center', color: '#f59e0b' }}></h1>
<div className="tabs">
{/* 桌面端 Tab 选择 */}
{!isMobile && (
<div className="tabs" style={{ display: 'flex', borderBottom: '1px solid #333', marginBottom: '20px', backgroundColor: '#1e1e1e', borderRadius: '8px 8px 0 0', overflow: 'hidden' }}>
<button
className={`tab ${activeTab === 'sm3' ? 'active' : ''}`}
onClick={() => setActiveTab('sm3')}
onClick={() => handleTabChange('sm3')}
style={{
padding: '12px 24px',
border: 'none',
background: activeTab === 'sm3' ? '#333' : '#1e1e1e',
cursor: 'pointer',
fontSize: '16px',
fontWeight: activeTab === 'sm3' ? 'bold' : 'normal',
color: activeTab === 'sm3' ? '#f59e0b' : '#e0e0e0',
outline: 'none',
transition: 'all 0.3s ease',
borderBottom: activeTab === 'sm3' ? '3px solid #f59e0b' : 'none'
}}
>
SM3
</button>
<button
className={`tab ${activeTab === 'sm4' ? 'active' : ''}`}
onClick={() => setActiveTab('sm4')}
onClick={() => handleTabChange('sm4')}
style={{
padding: '12px 24px',
border: 'none',
background: activeTab === 'sm4' ? '#333' : '#1e1e1e',
cursor: 'pointer',
fontSize: '16px',
fontWeight: activeTab === 'sm4' ? 'bold' : 'normal',
color: activeTab === 'sm4' ? '#f59e0b' : '#e0e0e0',
outline: 'none',
transition: 'all 0.3s ease',
borderBottom: activeTab === 'sm4' ? '3px solid #f59e0b' : 'none'
}}
>
SM4
</button>
<button
className={`tab ${activeTab === 'convert' ? 'active' : ''}`}
onClick={() => setActiveTab('convert')}
onClick={() => handleTabChange('convert')}
style={{
padding: '12px 24px',
border: 'none',
background: activeTab === 'convert' ? '#333' : '#1e1e1e',
cursor: 'pointer',
fontSize: '16px',
fontWeight: activeTab === 'convert' ? 'bold' : 'normal',
color: activeTab === 'convert' ? '#f59e0b' : '#e0e0e0',
outline: 'none',
transition: 'all 0.3s ease',
borderBottom: activeTab === 'convert' ? '3px solid #f59e0b' : 'none'
}}
>
</button>
</div>
)}
{/* 移动端下拉选择 */}
{isMobile && (
<div className="mobile-tab-selector" style={{ marginBottom: '20px' }}>
<select
value={mobileTab}
onChange={handleMobileTabChange}
className="mobile-select"
style={{
width: '100%',
padding: '12px',
fontSize: '16px',
border: '1px solid #333',
borderRadius: '4px',
background: '#1e1e1e',
color: '#e0e0e0',
outline: 'none',
appearance: 'none',
cursor: 'pointer'
}}
>
<option value="sm3" style={{ background: '#1e1e1e', color: '#e0e0e0' }}>SM3</option>
<option value="sm4" style={{ background: '#1e1e1e', color: '#e0e0e0' }}>SM4</option>
<option value="convert" style={{ background: '#1e1e1e', color: '#e0e0e0' }}></option>
</select>
</div>
)}
{/* SM3 面板 */}
{activeTab === 'sm3' && (
<div className="panel">
<h2>SM3 </h2>
<div className="panel" style={{ backgroundColor: '#1e1e1e', padding: '20px', borderRadius: '8px', boxShadow: '0 2px 4px rgba(0, 0, 0, 0.3)' }}>
<h2 style={{ color: '#f59e0b', marginBottom: '20px' }}>SM3 </h2>
<div className="form-group">
<label></label>
<div className="form-group" style={{ marginBottom: '15px' }}>
<label style={{ display: 'block', marginBottom: '5px', color: '#e0e0e0' }}></label>
<textarea
value={sm3Message}
onChange={(e) => setSm3Message(e.target.value)}
placeholder="输入要计算的消息"
style={{
width: '100%',
padding: '10px',
border: '1px solid #333',
borderRadius: '4px',
backgroundColor: '#2d2d2d',
color: '#e0e0e0',
fontSize: '14px',
resize: 'vertical',
minHeight: '100px'
}}
/>
</div>
<div className="form-group">
<label>SM3 </label>
<div className="form-group" style={{ marginBottom: '15px' }}>
<label style={{ display: 'block', marginBottom: '5px', color: '#e0e0e0' }}>SM3 </label>
<textarea
value={sm3Result}
readOnly
placeholder="SM3 计算结果将显示在这里"
style={{
width: '100%',
padding: '10px',
border: '1px solid #333',
borderRadius: '4px',
backgroundColor: '#2d2d2d',
color: '#e0e0e0',
fontSize: '14px',
resize: 'vertical',
minHeight: '100px'
}}
/>
</div>
<button onClick={handleCalculateSm3}> SM3</button>
<button
onClick={handleCalculateSm3}
style={{
padding: '10px 20px',
border: 'none',
borderRadius: '4px',
background: '#f59e0b',
color: '#121212',
fontSize: '16px',
fontWeight: 'bold',
cursor: 'pointer',
transition: 'background 0.3s ease'
}}
>
SM3
</button>
<div className="form-group" style={{ marginTop: '1.5rem' }}>
<label>HMAC </label>
<div className="form-group" style={{ marginTop: '1.5rem', marginBottom: '15px' }}>
<label style={{ display: 'block', marginBottom: '5px', color: '#e0e0e0' }}>HMAC </label>
<input
type="text"
value={sm3HmacKey}
onChange={(e) => setSm3HmacKey(e.target.value)}
placeholder="输入 HMAC 密钥 (hex)"
style={{
width: '100%',
padding: '10px',
border: '1px solid #333',
borderRadius: '4px',
backgroundColor: '#2d2d2d',
color: '#e0e0e0',
fontSize: '14px'
}}
/>
</div>
<div className="form-group">
<label>SM3 HMAC </label>
<div className="form-group" style={{ marginBottom: '15px' }}>
<label style={{ display: 'block', marginBottom: '5px', color: '#e0e0e0' }}>SM3 HMAC </label>
<textarea
value={sm3HmacResult}
readOnly
placeholder="SM3 HMAC 计算结果将显示在这里"
style={{
width: '100%',
padding: '10px',
border: '1px solid #333',
borderRadius: '4px',
backgroundColor: '#2d2d2d',
color: '#e0e0e0',
fontSize: '14px',
resize: 'vertical',
minHeight: '100px'
}}
/>
</div>
<button onClick={calculateSm3Hmac}> SM3 HMAC</button>
<button
onClick={calculateSm3Hmac}
style={{
padding: '10px 20px',
border: 'none',
borderRadius: '4px',
background: '#f59e0b',
color: '#121212',
fontSize: '16px',
fontWeight: 'bold',
cursor: 'pointer',
transition: 'background 0.3s ease'
}}
>
SM3 HMAC
</button>
</div>
)}
{/* SM4 面板 */}
{activeTab === 'sm4' && (
<div className="panel">
<h2>SM4 </h2>
<div className="panel" style={{ backgroundColor: '#1e1e1e', padding: '20px', borderRadius: '8px', boxShadow: '0 2px 4px rgba(0, 0, 0, 0.3)' }}>
<h2 style={{ color: '#f59e0b', marginBottom: '20px' }}>SM4 </h2>
<div className="form-group">
<label> (16 hex)</label>
<div className="form-group" style={{ marginBottom: '15px' }}>
<label style={{ display: 'block', marginBottom: '5px', color: '#e0e0e0' }}> (16 hex)</label>
<input
type="text"
value={sm4Key}
onChange={(e) => setSm4Key(e.target.value)}
placeholder="输入 16 字节密钥 (32 位 hex)"
style={{
width: '100%',
padding: '10px',
border: '1px solid #333',
borderRadius: '4px',
backgroundColor: '#2d2d2d',
color: '#e0e0e0',
fontSize: '14px'
}}
/>
</div>
<div className="form-group">
<label>IV (16 hex, CBC/CFB/GCM )</label>
<div className="form-group" style={{ marginBottom: '15px' }}>
<label style={{ display: 'block', marginBottom: '5px', color: '#e0e0e0' }}>IV (16 hex, CBC/CFB/GCM )</label>
<input
type="text"
value={sm4Iv}
onChange={(e) => setSm4Iv(e.target.value)}
placeholder="输入 16 字节 IV (32 位 hex)"
style={{
width: '100%',
padding: '10px',
border: '1px solid #333',
borderRadius: '4px',
backgroundColor: '#2d2d2d',
color: '#e0e0e0',
fontSize: '14px'
}}
/>
</div>
<div className="form-group">
<label></label>
<div className="form-group" style={{ marginBottom: '15px' }}>
<label style={{ display: 'block', marginBottom: '5px', color: '#e0e0e0' }}></label>
<div style={{ display: 'flex', gap: '0.5rem', flexWrap: 'wrap' }}>
{['ecb', 'cbc', 'gcm'].map(mode => (
<button
key={mode}
className={sm4Mode === mode ? 'primary' : ''}
onClick={() => setSm4Mode(mode)}
style={{
padding: '8px 16px',
border: '1px solid #333',
borderRadius: '4px',
background: sm4Mode === mode ? '#f59e0b' : '#2d2d2d',
color: sm4Mode === mode ? '#121212' : '#e0e0e0',
cursor: 'pointer',
fontSize: '14px',
fontWeight: sm4Mode === mode ? 'bold' : 'normal',
transition: 'all 0.3s ease'
}}
>
{mode.toUpperCase()}
</button>
@ -206,14 +400,25 @@ function App() {
</div>
</div>
<div className="form-group">
<label></label>
<div className="form-group" style={{ marginBottom: '15px' }}>
<label style={{ display: 'block', marginBottom: '5px', color: '#e0e0e0' }}></label>
<div style={{ display: 'flex', gap: '0.5rem', flexWrap: 'wrap' }}>
{(['pkcs7', 'none'] as const).map(paddingMode => (
<button
key={paddingMode}
className={sm4PaddingMode === paddingMode ? 'primary' : ''}
onClick={() => setSm4PaddingMode(paddingMode)}
style={{
padding: '8px 16px',
border: '1px solid #333',
borderRadius: '4px',
background: sm4PaddingMode === paddingMode ? '#f59e0b' : '#2d2d2d',
color: sm4PaddingMode === paddingMode ? '#121212' : '#e0e0e0',
cursor: 'pointer',
fontSize: '14px',
fontWeight: sm4PaddingMode === paddingMode ? 'bold' : 'normal',
transition: 'all 0.3s ease'
}}
>
{paddingMode}
</button>
@ -221,73 +426,190 @@ function App() {
</div>
</div>
<div className="form-group">
<label></label>
<div className="form-group" style={{ marginBottom: '15px' }}>
<label style={{ display: 'block', marginBottom: '5px', color: '#e0e0e0' }}></label>
<textarea
value={sm4Message}
onChange={(e) => setSm4Message(e.target.value)}
placeholder="输入要加密的消息"
style={{
width: '100%',
padding: '10px',
border: '1px solid #333',
borderRadius: '4px',
backgroundColor: '#2d2d2d',
color: '#e0e0e0',
fontSize: '14px',
resize: 'vertical',
minHeight: '100px'
}}
/>
</div>
<div className="form-group">
<label></label>
<div className="form-group" style={{ marginBottom: '15px' }}>
<label style={{ display: 'block', marginBottom: '5px', color: '#e0e0e0' }}></label>
<textarea
value={sm4Encrypted}
onChange={(e) => setSm4Encrypted(e.target.value)}
placeholder="输入加密结果 (hex)"
style={{
width: '100%',
padding: '10px',
border: '1px solid #333',
borderRadius: '4px',
backgroundColor: '#2d2d2d',
color: '#e0e0e0',
fontSize: '14px',
resize: 'vertical',
minHeight: '100px'
}}
/>
</div>
<div className="form-group">
<label></label>
<div className="form-group" style={{ marginBottom: '15px' }}>
<label style={{ display: 'block', marginBottom: '5px', color: '#e0e0e0' }}></label>
<textarea
value={sm4Decrypted}
readOnly
placeholder="解密结果将显示在这里"
style={{
width: '100%',
padding: '10px',
border: '1px solid #333',
borderRadius: '4px',
backgroundColor: '#2d2d2d',
color: '#e0e0e0',
fontSize: '14px',
resize: 'vertical',
minHeight: '100px'
}}
/>
</div>
<div className="button-group">
<button onClick={handleEncryptSm4}></button>
<button onClick={handleDecryptSm4}></button>
<div className="button-group" style={{ display: 'flex', gap: '10px' }}>
<button
onClick={handleEncryptSm4}
style={{
padding: '10px 20px',
border: 'none',
borderRadius: '4px',
background: '#f59e0b',
color: '#121212',
fontSize: '16px',
fontWeight: 'bold',
cursor: 'pointer',
transition: 'background 0.3s ease',
flex: 1
}}
>
</button>
<button
onClick={handleDecryptSm4}
style={{
padding: '10px 20px',
border: 'none',
borderRadius: '4px',
background: '#f59e0b',
color: '#121212',
fontSize: '16px',
fontWeight: 'bold',
cursor: 'pointer',
transition: 'background 0.3s ease',
flex: 1
}}
>
</button>
</div>
</div>
)}
{/* 转换工具面板 */}
{activeTab === 'convert' && (
<div className="panel">
<h2>Hex / UTF8 </h2>
<div className="panel" style={{ backgroundColor: '#1e1e1e', padding: '20px', borderRadius: '8px', boxShadow: '0 2px 4px rgba(0, 0, 0, 0.3)' }}>
<h2 style={{ color: '#f59e0b', marginBottom: '20px' }}>Hex / UTF8 </h2>
<div style={{ display: 'flex', gap: '1rem', marginBottom: '1rem' }}>
<div style={{ display: 'flex', gap: '1rem', marginBottom: '1rem', flexDirection: isMobile ? 'column' : 'row' }}>
<div className="form-group" style={{ flex: 1 }}>
<label>UTF8 </label>
<label style={{ display: 'block', marginBottom: '5px', color: '#e0e0e0' }}>UTF8 </label>
<textarea
value={utf8Input}
onChange={(e) => setUtf8Input(e.target.value)}
placeholder="输入 UTF8 字符串"
style={{ height: '200px' }}
style={{
height: '200px',
width: '100%',
padding: '10px',
border: '1px solid #333',
borderRadius: '4px',
backgroundColor: '#2d2d2d',
color: '#e0e0e0',
fontSize: '14px',
resize: 'vertical'
}}
/>
<button onClick={handleUtf8ToHex} style={{ marginTop: '0.5rem' }}>UTF8 Hex</button>
<button
onClick={handleUtf8ToHex}
style={{
marginTop: '0.5rem',
padding: '8px 16px',
border: 'none',
borderRadius: '4px',
background: '#f59e0b',
color: '#121212',
fontSize: '14px',
fontWeight: 'bold',
cursor: 'pointer',
transition: 'background 0.3s ease'
}}
>
UTF8 Hex
</button>
</div>
<div className="form-group" style={{ flex: 1 }}>
<label>Hex </label>
<label style={{ display: 'block', marginBottom: '5px', color: '#e0e0e0' }}>Hex </label>
<textarea
value={hexInput}
onChange={(e) => setHexInput(e.target.value)}
placeholder="输入 hex 字符串"
style={{ height: '200px' }}
style={{
height: '200px',
width: '100%',
padding: '10px',
border: '1px solid #333',
borderRadius: '4px',
backgroundColor: '#2d2d2d',
color: '#e0e0e0',
fontSize: '14px',
resize: 'vertical'
}}
/>
<button onClick={handleHexToUtf8} style={{ marginTop: '0.5rem' }}>UTF8 Hex</button>
<button
onClick={handleHexToUtf8}
style={{
marginTop: '0.5rem',
padding: '8px 16px',
border: 'none',
borderRadius: '4px',
background: '#f59e0b',
color: '#121212',
fontSize: '14px',
fontWeight: 'bold',
cursor: 'pointer',
transition: 'background 0.3s ease'
}}
>
UTF8 Hex
</button>
</div>
</div>
</div>
)}
{/* 页脚 */}
<footer style={{ marginTop: '2rem', padding: '1rem', borderTop: '1px solid #ccc', textAlign: 'center' }}>
<footer style={{ marginTop: '2rem', padding: '1rem', borderTop: '1px solid #333', textAlign: 'center', color: '#e0e0e0' }}>
<p>© 2026 </p>
<p>: {VERSION}</p>
</footer>

View File

@ -1 +1 @@
export const VERSION = "V1.0-20260417022550";
export const VERSION = "V1.0-20260417024927";