添加更多的API接口功能

This commit is contained in:
2025-09-08 22:08:09 +08:00
parent 227ccf9c29
commit 6889ca37e5
31 changed files with 8796 additions and 9 deletions

View File

@@ -0,0 +1,878 @@
/* 基础样式重置 */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', sans-serif;
line-height: 1.6;
color: #2c3e50;
min-height: 100vh;
overflow-x: hidden;
}
/* 容器布局 */
.container {
max-width: 1200px;
margin: 0 auto;
padding: 20px;
min-height: 100vh;
display: flex;
flex-direction: column;
}
/* 头部样式 */
.header {
text-align: center;
margin-bottom: 40px;
padding: 40px 20px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border-radius: 20px;
box-shadow: 0 10px 30px rgba(102, 126, 234, 0.3);
color: white;
}
.header h1 {
font-size: 2.8rem;
font-weight: 700;
margin-bottom: 15px;
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
}
.subtitle {
font-size: 1.2rem;
opacity: 0.9;
font-weight: 400;
}
/* 主内容区域 */
.main-content {
flex: 1;
display: flex;
flex-direction: column;
gap: 30px;
}
/* 输入容器 */
.input-container {
background: #ffffff;
border-radius: 20px;
padding: 40px;
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.1);
border: 1px solid #e8ecf4;
}
.input-group {
margin-bottom: 30px;
}
.input-label {
display: block;
font-size: 1.1rem;
font-weight: 600;
color: #2c3e50;
margin-bottom: 15px;
}
.password-input-wrapper {
position: relative;
margin-bottom: 15px;
}
.password-input {
width: 100%;
padding: 18px 60px 18px 20px;
border: 2px solid #e8ecf4;
border-radius: 12px;
font-size: 1.1rem;
font-family: 'Courier New', monospace;
background: #f8fafc;
transition: all 0.3s ease;
letter-spacing: 1px;
}
.password-input:focus {
outline: none;
border-color: #667eea;
background: #ffffff;
box-shadow: 0 0 0 4px rgba(102, 126, 234, 0.1);
}
.password-input::placeholder {
color: #94a3b8;
letter-spacing: normal;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
}
.toggle-visibility {
position: absolute;
right: 15px;
top: 50%;
transform: translateY(-50%);
background: none;
border: none;
cursor: pointer;
padding: 8px;
border-radius: 6px;
color: #64748b;
transition: all 0.3s ease;
}
.toggle-visibility:hover {
background: #f1f5f9;
color: #475569;
}
.input-hint {
display: flex;
align-items: center;
gap: 8px;
color: #64748b;
font-size: 0.9rem;
}
.hint-icon {
font-size: 1rem;
}
/* 检测按钮 */
.check-btn {
width: 100%;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border: none;
padding: 18px 32px;
border-radius: 12px;
font-size: 1.1rem;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
box-shadow: 0 4px 20px rgba(102, 126, 234, 0.3);
display: flex;
align-items: center;
justify-content: center;
gap: 10px;
position: relative;
overflow: hidden;
}
.check-btn:hover {
transform: translateY(-2px);
box-shadow: 0 6px 25px rgba(102, 126, 234, 0.4);
}
.check-btn:active {
transform: translateY(0);
}
.check-btn:disabled {
opacity: 0.7;
cursor: not-allowed;
transform: none;
}
.btn-icon {
font-size: 1.2rem;
}
/* 结果容器 */
.result-container {
background: #ffffff;
border-radius: 20px;
padding: 40px;
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.1);
border: 1px solid #e8ecf4;
animation: slideIn 0.5s ease-out;
}
@keyframes slideIn {
from {
opacity: 0;
transform: translateY(30px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* 强度概览 */
.strength-overview {
margin-bottom: 40px;
padding: 30px;
background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);
border-radius: 16px;
border: 1px solid #e2e8f0;
}
.strength-score {
display: flex;
align-items: center;
gap: 30px;
margin-bottom: 25px;
}
.score-circle {
width: 120px;
height: 120px;
border-radius: 50%;
background: conic-gradient(from 0deg, #e2e8f0 0deg, #e2e8f0 360deg);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
position: relative;
transition: all 0.5s ease;
}
.score-circle::before {
content: '';
position: absolute;
width: 90px;
height: 90px;
background: white;
border-radius: 50%;
z-index: 1;
}
.score-value {
font-size: 2.5rem;
font-weight: 700;
color: #2c3e50;
z-index: 2;
position: relative;
}
.score-label {
font-size: 0.9rem;
color: #64748b;
z-index: 2;
position: relative;
}
.strength-info {
flex: 1;
}
.strength-level {
font-size: 2rem;
font-weight: 700;
margin-bottom: 8px;
color: #2c3e50;
}
.strength-description {
font-size: 1.1rem;
color: #64748b;
line-height: 1.5;
}
.strength-bar {
margin-top: 20px;
}
.bar-background {
width: 100%;
height: 12px;
background: #e2e8f0;
border-radius: 6px;
overflow: hidden;
margin-bottom: 10px;
}
.bar-fill {
height: 100%;
background: linear-gradient(90deg, #ef4444, #f97316, #eab308, #22c55e);
border-radius: 6px;
width: 0%;
transition: width 0.8s ease;
}
.bar-labels {
display: flex;
justify-content: space-between;
font-size: 0.85rem;
color: #64748b;
}
/* 详细信息网格 */
.details-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 25px;
margin-bottom: 30px;
}
.detail-card {
background: #f8fafc;
border-radius: 16px;
padding: 25px;
border: 1px solid #e2e8f0;
transition: all 0.3s ease;
}
.detail-card:hover {
transform: translateY(-2px);
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.1);
}
.card-header {
display: flex;
align-items: center;
gap: 12px;
margin-bottom: 20px;
}
.card-icon {
font-size: 1.5rem;
}
.card-header h3 {
font-size: 1.3rem;
font-weight: 600;
color: #2c3e50;
}
.card-content {
display: flex;
flex-direction: column;
gap: 15px;
}
.info-row {
display: flex;
justify-content: space-between;
align-items: center;
padding: 12px 0;
border-bottom: 1px solid #e2e8f0;
}
.info-row:last-child {
border-bottom: none;
}
.info-label {
font-weight: 500;
color: #64748b;
}
.info-value {
font-weight: 600;
color: #2c3e50;
}
/* 字符类型分析 */
.character-types {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 12px;
margin-bottom: 20px;
}
.char-type {
display: flex;
align-items: center;
gap: 8px;
padding: 10px 12px;
background: white;
border-radius: 8px;
border: 1px solid #e2e8f0;
font-size: 0.9rem;
}
.char-type.has-type {
background: #dcfce7;
border-color: #bbf7d0;
color: #166534;
}
.char-type.has-type .type-icon {
color: #22c55e;
}
.type-icon {
font-size: 1rem;
}
.character-issues {
display: flex;
flex-direction: column;
gap: 8px;
}
.issue-item {
display: flex;
align-items: center;
gap: 8px;
padding: 8px 12px;
background: #fef2f2;
border: 1px solid #fecaca;
border-radius: 8px;
color: #dc2626;
font-size: 0.9rem;
}
.issue-item.hidden {
display: none;
}
.issue-icon {
font-size: 1rem;
}
/* 建议和提示区域 */
.recommendations-section {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));
gap: 25px;
}
.recommendations-card,
.security-tips-card {
background: #f8fafc;
border-radius: 16px;
padding: 25px;
border: 1px solid #e2e8f0;
}
.recommendations-list {
list-style: none;
display: flex;
flex-direction: column;
gap: 12px;
}
.recommendations-list li {
display: flex;
align-items: flex-start;
gap: 10px;
padding: 12px 16px;
background: white;
border-radius: 10px;
border: 1px solid #e2e8f0;
color: #2c3e50;
line-height: 1.5;
}
.recommendations-list li::before {
content: '💡';
font-size: 1rem;
margin-top: 2px;
flex-shrink: 0;
}
.tips-container {
display: flex;
flex-direction: column;
gap: 12px;
}
.tip-item {
display: flex;
align-items: flex-start;
gap: 12px;
padding: 12px 16px;
background: white;
border-radius: 10px;
border: 1px solid #e2e8f0;
color: #2c3e50;
line-height: 1.5;
}
.tip-icon {
font-size: 1rem;
margin-top: 2px;
flex-shrink: 0;
}
/* 错误容器 */
.error-container {
background: #ffffff;
border-radius: 20px;
padding: 50px 40px;
text-align: center;
box-shadow: 0 10px 40px rgba(239, 68, 68, 0.1);
border: 1px solid #fecaca;
}
.error-icon {
font-size: 4rem;
margin-bottom: 20px;
}
.error-container h3 {
color: #dc2626;
margin-bottom: 15px;
font-size: 1.5rem;
font-weight: 600;
}
.error-container p {
color: #64748b;
margin-bottom: 25px;
font-size: 1.1rem;
}
.retry-btn {
background: #dc2626;
color: white;
border: none;
padding: 14px 28px;
border-radius: 10px;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
font-size: 1rem;
}
.retry-btn:hover {
background: #b91c1c;
transform: translateY(-1px);
}
/* 页脚 */
.footer {
text-align: center;
padding: 40px 20px;
color: #64748b;
margin-top: 40px;
}
.footer p {
margin-bottom: 8px;
font-size: 1rem;
}
.footer-note {
font-size: 0.9rem;
opacity: 0.8;
}
/* 提示框 */
.toast {
position: fixed;
top: 20px;
right: 20px;
background: #22c55e;
color: white;
padding: 16px 24px;
border-radius: 10px;
box-shadow: 0 4px 20px rgba(34, 197, 94, 0.3);
z-index: 1000;
animation: toastSlide 0.3s ease-out;
font-weight: 500;
}
@keyframes toastSlide {
from {
transform: translateX(100%);
opacity: 0;
}
to {
transform: translateX(0);
opacity: 1;
}
}
/* 强度等级颜色 */
.strength-weak {
color: #dc2626 !important;
}
.strength-medium {
color: #f59e0b !important;
}
.strength-strong {
color: #059669 !important;
}
.strength-very-strong {
color: #047857 !important;
}
/* 分数圆圈颜色 */
.score-weak {
background: conic-gradient(from 0deg, #dc2626 0deg, #dc2626 var(--score-deg), #e2e8f0 var(--score-deg), #e2e8f0 360deg) !important;
}
.score-medium {
background: conic-gradient(from 0deg, #f59e0b 0deg, #f59e0b var(--score-deg), #e2e8f0 var(--score-deg), #e2e8f0 360deg) !important;
}
.score-strong {
background: conic-gradient(from 0deg, #059669 0deg, #059669 var(--score-deg), #e2e8f0 var(--score-deg), #e2e8f0 360deg) !important;
}
.score-very-strong {
background: conic-gradient(from 0deg, #047857 0deg, #047857 var(--score-deg), #e2e8f0 var(--score-deg), #e2e8f0 360deg) !important;
}
/* 平板端适配 (768px - 1024px) */
@media (min-width: 768px) and (max-width: 1024px) {
.container {
max-width: 900px;
padding: 25px;
}
.header h1 {
font-size: 2.4rem;
}
.input-container,
.result-container {
padding: 30px;
}
.details-grid {
grid-template-columns: 1fr;
}
.recommendations-section {
grid-template-columns: 1fr;
}
.strength-score {
flex-direction: column;
text-align: center;
gap: 20px;
}
}
/* 手机端适配 (最大767px) */
@media (max-width: 767px) {
.container {
padding: 15px;
max-width: 100%;
}
.header {
padding: 25px 15px;
margin-bottom: 25px;
}
.header h1 {
font-size: 2rem;
}
.subtitle {
font-size: 1rem;
}
.input-container,
.result-container {
padding: 25px;
border-radius: 15px;
}
.main-content {
gap: 20px;
}
.password-input {
padding: 16px 50px 16px 16px;
font-size: 1rem;
}
.check-btn {
padding: 16px 28px;
font-size: 1rem;
}
.strength-overview {
padding: 20px;
margin-bottom: 25px;
}
.strength-score {
flex-direction: column;
text-align: center;
gap: 20px;
}
.score-circle {
width: 100px;
height: 100px;
}
.score-circle::before {
width: 75px;
height: 75px;
}
.score-value {
font-size: 2rem;
}
.strength-level {
font-size: 1.6rem;
}
.details-grid {
grid-template-columns: 1fr;
gap: 20px;
}
.detail-card {
padding: 20px;
}
.character-types {
grid-template-columns: 1fr;
}
.recommendations-section {
grid-template-columns: 1fr;
gap: 20px;
}
.recommendations-card,
.security-tips-card {
padding: 20px;
}
.toast {
right: 15px;
left: 15px;
top: 15px;
text-align: center;
}
}
/* 小屏手机适配 (最大480px) */
@media (max-width: 480px) {
.container {
padding: 10px;
}
.header {
padding: 20px 10px;
margin-bottom: 20px;
}
.header h1 {
font-size: 1.8rem;
}
.input-container,
.result-container {
padding: 20px;
}
.password-input {
padding: 14px 45px 14px 14px;
font-size: 0.95rem;
}
.check-btn {
padding: 14px 24px;
}
.detail-card {
padding: 15px;
}
.card-header h3 {
font-size: 1.1rem;
}
}
/* 触摸设备优化 */
@media (hover: none) and (pointer: coarse) {
.check-btn,
.retry-btn,
.toggle-visibility {
min-height: 44px;
}
.toggle-visibility {
padding: 12px;
}
}
/* 高对比度模式支持 */
@media (prefers-contrast: high) {
.input-container,
.result-container,
.detail-card {
border: 2px solid #2c3e50;
}
.password-input {
border: 2px solid #2c3e50;
}
}
/* 减少动画模式支持 */
@media (prefers-reduced-motion: reduce) {
* {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}
/* 深色模式支持 */
@media (prefers-color-scheme: dark) {
body {
background: #0f172a;
color: #e2e8f0;
}
.input-container,
.result-container,
.detail-card,
.recommendations-card,
.security-tips-card {
background: #1e293b;
border-color: #334155;
}
.password-input {
background: #334155;
border-color: #475569;
color: #e2e8f0;
}
.password-input:focus {
background: #1e293b;
border-color: #667eea;
}
.strength-overview {
background: #1e293b;
border-color: #334155;
}
.char-type,
.recommendations-list li,
.tip-item {
background: #334155;
border-color: #475569;
color: #e2e8f0;
}
}
/* 打印样式 */
@media print {
.header {
background: none !important;
color: black !important;
box-shadow: none !important;
}
.check-btn,
.retry-btn,
.toggle-visibility,
.toast {
display: none !important;
}
.input-container,
.result-container {
box-shadow: none !important;
border: 1px solid #ccc !important;
}
}

View File

@@ -0,0 +1,218 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="在线密码强度检测工具,实时分析密码安全性,提供专业的密码安全建议">
<meta name="keywords" content="密码强度检测,密码安全,密码分析,在线工具">
<title>🔒 密码强度检测器</title>
<link rel="preconnect" href="https://60s.api.shumengya.top">
<link rel="dns-prefetch" href="https://60s.api.shumengya.top">
<link rel="stylesheet" href="css/style.css">
<link rel="stylesheet" href="css/background.css">
</head>
<body>
<div class="container">
<header class="header">
<h1>🔒 密码强度检测器</h1>
<p class="subtitle">实时分析密码安全性,保护您的数字生活</p>
</header>
<main class="main-content">
<!-- 密码输入区域 -->
<div class="input-container">
<div class="input-group">
<label for="passwordInput" class="input-label">请输入要检测的密码</label>
<div class="password-input-wrapper">
<input
type="password"
id="passwordInput"
class="password-input"
placeholder="输入您的密码进行安全性检测..."
autocomplete="new-password"
spellcheck="false"
>
<button type="button" class="toggle-visibility" id="toggleVisibility" title="显示/隐藏密码">
<svg class="eye-icon" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"></path>
<circle cx="12" cy="12" r="3"></circle>
</svg>
<svg class="eye-off-icon" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="display: none;">
<path d="M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24"></path>
<line x1="1" y1="1" x2="23" y2="23"></line>
</svg>
</button>
</div>
<div class="input-hint">
<span class="hint-icon">💡</span>
<span class="hint-text">输入密码后将实时显示安全性分析结果</span>
</div>
</div>
<button type="button" class="check-btn" id="checkBtn">
<span class="btn-icon">🔍</span>
<span class="btn-text">检测密码强度</span>
<span class="btn-loading" style="display: none;">检测中...</span>
</button>
</div>
<!-- 结果显示区域 -->
<div class="result-container" id="resultContainer" style="display: none;">
<!-- 密码强度概览 -->
<div class="strength-overview">
<div class="strength-score">
<div class="score-circle" id="scoreCircle">
<div class="score-value" id="scoreValue">0</div>
<div class="score-label"></div>
</div>
<div class="strength-info">
<div class="strength-level" id="strengthLevel">未知</div>
<div class="strength-description" id="strengthDescription">请输入密码进行检测</div>
</div>
</div>
<div class="strength-bar">
<div class="bar-background">
<div class="bar-fill" id="strengthBar"></div>
</div>
<div class="bar-labels">
<span></span>
<span>中等</span>
<span></span>
<span>非常强</span>
</div>
</div>
</div>
<!-- 详细信息 -->
<div class="details-grid">
<div class="detail-card">
<div class="card-header">
<span class="card-icon">📏</span>
<h3>基本信息</h3>
</div>
<div class="card-content">
<div class="info-row">
<span class="info-label">密码长度:</span>
<span class="info-value" id="passwordLength">-</span>
</div>
<div class="info-row">
<span class="info-label">熵值:</span>
<span class="info-value" id="entropyValue">-</span>
</div>
<div class="info-row">
<span class="info-label">破解时间:</span>
<span class="info-value" id="crackTime">-</span>
</div>
<div class="info-row">
<span class="info-label">字符种类:</span>
<span class="info-value" id="characterVariety">-</span>
</div>
</div>
</div>
<div class="detail-card">
<div class="card-header">
<span class="card-icon">🔤</span>
<h3>字符分析</h3>
</div>
<div class="card-content">
<div class="character-types" id="characterTypes">
<div class="char-type" id="hasLowercase">
<span class="type-icon"></span>
<span class="type-text">小写字母</span>
</div>
<div class="char-type" id="hasUppercase">
<span class="type-icon"></span>
<span class="type-text">大写字母</span>
</div>
<div class="char-type" id="hasNumbers">
<span class="type-icon"></span>
<span class="type-text">数字</span>
</div>
<div class="char-type" id="hasSymbols">
<span class="type-icon"></span>
<span class="type-text">特殊符号</span>
</div>
</div>
<div class="character-issues" id="characterIssues">
<div class="issue-item" id="hasRepeated">
<span class="issue-icon">⚠️</span>
<span class="issue-text">包含重复字符</span>
</div>
<div class="issue-item" id="hasSequential">
<span class="issue-icon">⚠️</span>
<span class="issue-text">包含连续字符</span>
</div>
</div>
</div>
</div>
</div>
<!-- 建议和提示 -->
<div class="recommendations-section">
<div class="recommendations-card">
<div class="card-header">
<span class="card-icon">💡</span>
<h3>改进建议</h3>
</div>
<div class="card-content">
<ul class="recommendations-list" id="recommendationsList">
<li>请输入密码进行分析</li>
</ul>
</div>
</div>
<div class="security-tips-card">
<div class="card-header">
<span class="card-icon">🛡️</span>
<h3>安全提示</h3>
</div>
<div class="card-content">
<div class="tips-container" id="securityTips">
<div class="tip-item">
<span class="tip-icon">🔐</span>
<span class="tip-text">使用密码管理器生成和存储复杂密码</span>
</div>
<div class="tip-item">
<span class="tip-icon">🔄</span>
<span class="tip-text">为不同账户使用不同的密码</span>
</div>
<div class="tip-item">
<span class="tip-icon"></span>
<span class="tip-text">定期更换重要账户的密码</span>
</div>
<div class="tip-item">
<span class="tip-icon">🔒</span>
<span class="tip-text">启用双因素认证2FA增强安全性</span>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- 错误显示区域 -->
<div class="error-container" id="errorContainer" style="display: none;">
<div class="error-icon">⚠️</div>
<h3>检测失败</h3>
<p id="errorMessage">请检查网络连接后重试</p>
<button class="retry-btn" id="retryBtn">重新检测</button>
</div>
</main>
<footer class="footer">
<p>🔒 保护您的数字安全,从强密码开始</p>
<p class="footer-note">本工具不会存储您的密码信息</p>
</footer>
</div>
<!-- 提示框 -->
<div class="toast" id="toast" style="display: none;">
<span id="toastMessage">操作成功</span>
</div>
<script src="js/script.js"></script>
</body>
</html>

View File

@@ -0,0 +1,516 @@
/**
* 密码强度检测器
* 提供密码强度分析和安全建议
*/
class PasswordStrengthChecker {
constructor() {
this.apiUrl = 'https://60s.api.shumengya.top/v2/password/check';
this.isChecking = false;
this.currentPassword = '';
this.init();
}
/**
* 初始化应用
*/
init() {
this.bindEvents();
this.setupFormValidation();
this.hideResultContainer();
this.hideErrorContainer();
console.log('密码强度检测器初始化完成');
}
/**
* 绑定事件监听器
*/
bindEvents() {
// 密码输入框事件
const passwordInput = document.getElementById('passwordInput');
if (passwordInput) {
passwordInput.addEventListener('input', this.handlePasswordInput.bind(this));
passwordInput.addEventListener('keypress', this.handleKeyPress.bind(this));
}
// 显示/隐藏密码按钮
const toggleBtn = document.getElementById('toggleVisibility');
if (toggleBtn) {
toggleBtn.addEventListener('click', this.togglePasswordVisibility.bind(this));
}
// 检测按钮
const checkBtn = document.getElementById('checkBtn');
if (checkBtn) {
checkBtn.addEventListener('click', this.handleCheckPassword.bind(this));
}
// 重试按钮
const retryBtn = document.getElementById('retryBtn');
if (retryBtn) {
retryBtn.addEventListener('click', this.handleRetry.bind(this));
}
}
/**
* 设置表单验证
*/
setupFormValidation() {
const form = document.querySelector('.input-container');
if (form) {
form.addEventListener('submit', (e) => {
e.preventDefault();
this.handleCheckPassword();
});
}
}
/**
* 处理密码输入
*/
handlePasswordInput(event) {
const password = event.target.value;
this.currentPassword = password;
// 更新按钮状态
this.updateCheckButtonState();
// 如果密码为空,隐藏结果
if (!password.trim()) {
this.hideResultContainer();
this.hideErrorContainer();
}
}
/**
* 处理键盘事件
*/
handleKeyPress(event) {
if (event.key === 'Enter' && !this.isChecking) {
event.preventDefault();
this.handleCheckPassword();
}
}
/**
* 切换密码可见性
*/
togglePasswordVisibility() {
const passwordInput = document.getElementById('passwordInput');
const toggleBtn = document.getElementById('toggleVisibility');
if (passwordInput && toggleBtn) {
const isPassword = passwordInput.type === 'password';
passwordInput.type = isPassword ? 'text' : 'password';
toggleBtn.innerHTML = isPassword ? '🙈' : '👁️';
toggleBtn.title = isPassword ? '隐藏密码' : '显示密码';
}
}
/**
* 更新检测按钮状态
*/
updateCheckButtonState() {
const checkBtn = document.getElementById('checkBtn');
const hasPassword = this.currentPassword.trim().length > 0;
if (checkBtn) {
checkBtn.disabled = !hasPassword || this.isChecking;
if (this.isChecking) {
checkBtn.innerHTML = '<span class="btn-icon">⏳</span>检测中...';
} else if (hasPassword) {
checkBtn.innerHTML = '<span class="btn-icon">🔍</span>检测密码强度';
} else {
checkBtn.innerHTML = '<span class="btn-icon">🔍</span>请输入密码';
}
}
}
/**
* 处理密码检测
*/
async handleCheckPassword() {
const password = this.currentPassword.trim();
if (!password) {
this.showToast('请输入要检测的密码', 'error');
return;
}
if (this.isChecking) {
return;
}
try {
this.setLoadingState(true);
this.hideErrorContainer();
const result = await this.checkPasswordStrength(password);
if (result.code === 200 && result.data) {
this.displayResults(result.data);
this.showResultContainer();
this.showToast('密码强度检测完成', 'success');
} else {
throw new Error(result.message || '检测失败');
}
} catch (error) {
console.error('密码检测错误:', error);
this.showError(error.message || '检测服务暂时不可用,请稍后重试');
} finally {
this.setLoadingState(false);
}
}
/**
* 调用API检测密码强度
*/
async checkPasswordStrength(password) {
const url = new URL(this.apiUrl);
url.searchParams.append('password', password);
url.searchParams.append('encoding', 'utf-8');
const response = await fetch(url.toString(), {
method: 'GET',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
return await response.json();
}
/**
* 显示检测结果
*/
displayResults(data) {
this.updateStrengthOverview(data);
this.updateDetailedInfo(data);
this.updateRecommendations(data);
}
/**
* 更新强度概览
*/
updateStrengthOverview(data) {
// 更新分数圆圈
const scoreCircle = document.getElementById('scoreCircle');
const scoreValue = document.getElementById('scoreValue');
const strengthLevel = document.getElementById('strengthLevel');
const strengthDescription = document.getElementById('strengthDescription');
const barFill = document.getElementById('strengthBar');
if (scoreValue) {
scoreValue.textContent = data.score || 0;
}
if (strengthLevel) {
strengthLevel.textContent = this.getStrengthText(data.strength);
const strengthClass = this.getStrengthClass(data.strength);
strengthLevel.className = `strength-level strength-${strengthClass}`;
}
if (strengthDescription) {
strengthDescription.textContent = this.getStrengthDescription(data.strength);
}
// 更新分数圆圈
if (scoreCircle) {
const percentage = (data.score / 100) * 360;
scoreCircle.style.setProperty('--score-deg', `${percentage}deg`);
// 将中文强度转换为CSS类名
const strengthClass = this.getStrengthClass(data.strength);
scoreCircle.className = `score-circle score-${strengthClass}`;
}
// 更新强度条
if (barFill) {
setTimeout(() => {
barFill.style.width = `${data.score}%`;
}, 100);
}
}
/**
* 更新详细信息
*/
updateDetailedInfo(data) {
// 基本信息
this.updateElement('passwordLength', data.length || 0);
this.updateElement('entropyValue', data.entropy ? data.entropy.toFixed(2) : '0.00');
this.updateElement('crackTime', data.time_to_crack || '未知');
// 字符类型分析
this.updateCharacterAnalysis(data.character_analysis || {});
}
/**
* 更新字符类型分析
*/
updateCharacterAnalysis(analysis) {
const types = {
'has_lowercase': { element: 'hasLowercase', label: '小写字母', icon: '🔤' },
'has_uppercase': { element: 'hasUppercase', label: '大写字母', icon: '🔠' },
'has_numbers': { element: 'hasNumbers', label: '数字', icon: '🔢' },
'has_symbols': { element: 'hasSymbols', label: '特殊符号', icon: '🔣' }
};
Object.keys(types).forEach(key => {
const element = document.getElementById(types[key].element);
if (element) {
const hasType = analysis[key] || false;
element.className = `char-type ${hasType ? 'has-type' : ''}`;
element.innerHTML = `
<span class="type-icon">${hasType ? '✅' : '❌'}</span>
<span>${types[key].label}</span>
`;
}
});
// 更新字符种类数量
this.updateElement('characterVariety', analysis.character_variety || 0);
// 更新问题提示
this.updateCharacterIssues(analysis);
}
/**
* 更新字符问题提示
*/
updateCharacterIssues(analysis) {
const issues = [
{ id: 'hasRepeated', condition: analysis.has_repeated, text: '包含重复字符' },
{ id: 'hasSequential', condition: analysis.has_sequential, text: '包含连续字符' }
];
issues.forEach(issue => {
const element = document.getElementById(issue.id);
if (element) {
if (issue.condition) {
element.style.display = 'flex';
element.innerHTML = `
<span class="issue-icon">⚠️</span>
<span class="issue-text">${issue.text}</span>
`;
} else {
element.style.display = 'none';
}
}
});
}
/**
* 更新建议和提示
*/
updateRecommendations(data) {
// 更新建议列表
const recommendationsList = document.getElementById('recommendationsList');
if (recommendationsList && data.recommendations) {
recommendationsList.innerHTML = '';
data.recommendations.forEach(recommendation => {
const li = document.createElement('li');
li.textContent = recommendation;
recommendationsList.appendChild(li);
});
}
// 更新安全提示
const tipsContainer = document.getElementById('securityTips');
if (tipsContainer && data.security_tips) {
tipsContainer.innerHTML = '';
data.security_tips.forEach((tip, index) => {
const tipElement = document.createElement('div');
tipElement.className = 'tip-item';
tipElement.innerHTML = `
<span class="tip-icon">${this.getTipIcon(index)}</span>
<span class="tip-text">${tip}</span>
`;
tipsContainer.appendChild(tipElement);
});
}
}
/**
* 获取提示图标
*/
getTipIcon(index) {
const icons = ['🛡️', '🔐', '⚡', '🎯', '💡', '🔄'];
return icons[index % icons.length];
}
/**
* 获取强度文本
*/
getStrengthText(strength) {
// API直接返回中文强度无需映射
return strength || '未知';
}
/**
* 获取强度CSS类名
*/
getStrengthClass(strength) {
const classMap = {
'弱': 'weak',
'中等': 'medium',
'强': 'strong',
'非常强': 'very-strong'
};
return classMap[strength] || 'unknown';
}
/**
* 获取强度描述
*/
getStrengthDescription(strength) {
const descriptions = {
'弱': '密码强度较弱,建议增加复杂度',
'中等': '密码强度中等,可以进一步优化',
'强': '密码强度良好,安全性较高',
'非常强': '密码强度非常好,安全性很高'
};
return descriptions[strength] || '无法评估密码强度';
}
/**
* 设置加载状态
*/
setLoadingState(loading) {
this.isChecking = loading;
this.updateCheckButtonState();
const passwordInput = document.getElementById('passwordInput');
if (passwordInput) {
passwordInput.disabled = loading;
}
}
/**
* 显示结果容器
*/
showResultContainer() {
const container = document.getElementById('resultContainer');
if (container) {
container.style.display = 'block';
container.scrollIntoView({ behavior: 'smooth', block: 'start' });
}
}
/**
* 隐藏结果容器
*/
hideResultContainer() {
const container = document.getElementById('resultContainer');
if (container) {
container.style.display = 'none';
}
}
/**
* 显示错误
*/
showError(message) {
const errorContainer = document.getElementById('errorContainer');
const errorMessage = document.getElementById('errorMessage');
if (errorContainer && errorMessage) {
errorMessage.textContent = message;
errorContainer.style.display = 'block';
this.hideResultContainer();
errorContainer.scrollIntoView({ behavior: 'smooth', block: 'start' });
}
}
/**
* 隐藏错误容器
*/
hideErrorContainer() {
const container = document.getElementById('errorContainer');
if (container) {
container.style.display = 'none';
}
}
/**
* 处理重试
*/
handleRetry() {
this.hideErrorContainer();
const passwordInput = document.getElementById('passwordInput');
if (passwordInput) {
passwordInput.focus();
}
}
/**
* 更新元素内容
*/
updateElement(id, content) {
const element = document.getElementById(id);
if (element) {
element.textContent = content;
}
}
/**
* 显示提示消息
*/
showToast(message, type = 'success') {
const toast = document.getElementById('toast');
const toastMessage = document.getElementById('toastMessage');
if (toast && toastMessage) {
toastMessage.textContent = message;
toast.className = `toast toast-${type}`;
toast.style.display = 'block';
// 3秒后自动隐藏
setTimeout(() => {
toast.style.display = 'none';
}, 3000);
}
}
}
// 页面加载完成后初始化
document.addEventListener('DOMContentLoaded', () => {
try {
window.passwordChecker = new PasswordStrengthChecker();
console.log('密码强度检测器已启动');
} catch (error) {
console.error('初始化失败:', error);
}
});
// 页面可见性变化处理
document.addEventListener('visibilitychange', () => {
if (document.visibilityState === 'visible' && window.passwordChecker) {
console.log('页面重新激活');
}
});
// 全局错误处理
window.addEventListener('error', (event) => {
console.error('全局错误:', event.error);
if (window.passwordChecker) {
window.passwordChecker.showToast('发生了意外错误,请刷新页面重试', 'error');
}
});
// 网络状态监听
window.addEventListener('online', () => {
if (window.passwordChecker) {
window.passwordChecker.showToast('网络连接已恢复', 'success');
}
});
window.addEventListener('offline', () => {
if (window.passwordChecker) {
window.passwordChecker.showToast('网络连接已断开', 'error');
}
});

View File

@@ -0,0 +1,37 @@
{
"code": 200,
"message": "获取成功。数据来自官方/权威源头,以确保稳定与实时。开源地址 https://github.com/vikiboss/60s反馈群 595941841",
"data": {
"password": "adasdasdasdadasd",
"length": 16,
"score": 68,
"strength": "中等",
"entropy": 75.21,
"time_to_crack": "数百万年",
"character_analysis": {
"has_lowercase": true,
"has_uppercase": false,
"has_numbers": false,
"has_symbols": false,
"has_repeated": false,
"has_sequential": true,
"character_variety": 26
},
"recommendations": [
"建议包含大写字母",
"建议包含数字",
"建议包含特殊符号",
"避免使用连续序列字符"
],
"security_tips": [
"使用密码管理器生成和存储复杂密码",
"为不同账户使用不同的密码",
"定期更换重要账户的密码",
"启用双因素认证2FA增强安全性",
"避免在公共场合输入密码",
"不要将密码保存在浏览器中(除非使用可信的密码管理器)",
"避免使用个人信息作为密码",
"长密码比复杂密码更安全"
]
}
}