PasswordStrengthIndicator.tsx 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. import React, { useEffect, useState } from 'react';
  2. import { passwordApi, PasswordStrengthLevel } from '../services/passwordApi';
  3. import { Shield, ShieldAlert, ShieldCheck } from 'lucide-react';
  4. interface PasswordStrengthIndicatorProps {
  5. password: string;
  6. onStrengthChange?: (meetsRequirements: boolean) => void;
  7. }
  8. const PasswordStrengthIndicator: React.FC<PasswordStrengthIndicatorProps> = ({
  9. password,
  10. onStrengthChange
  11. }) => {
  12. const [strength, setStrength] = useState<PasswordStrengthLevel>('weak');
  13. const [score, setScore] = useState<number>(0);
  14. const [suggestions, setSuggestions] = useState<string[]>([]);
  15. const [meetsRequirements, setMeetsRequirements] = useState<boolean>(false);
  16. const [isChecking, setIsChecking] = useState<boolean>(false);
  17. useEffect(() => {
  18. const checkStrength = async () => {
  19. if (!password) {
  20. setStrength('weak');
  21. setScore(0);
  22. setSuggestions([]);
  23. setMeetsRequirements(false);
  24. onStrengthChange?.(false);
  25. return;
  26. }
  27. setIsChecking(true);
  28. try {
  29. const result = await passwordApi.checkPasswordStrength(password);
  30. setStrength(result.strength);
  31. setScore(result.score);
  32. setSuggestions(result.suggestions);
  33. setMeetsRequirements(result.meets_requirements);
  34. onStrengthChange?.(result.meets_requirements);
  35. } catch (error) {
  36. console.error('密码强度检测失败:', error);
  37. } finally {
  38. setIsChecking(false);
  39. }
  40. };
  41. // 防抖处理
  42. const timer = setTimeout(checkStrength, 300);
  43. return () => clearTimeout(timer);
  44. }, [password, onStrengthChange]);
  45. if (!password) {
  46. return null;
  47. }
  48. // 强度配置
  49. const strengthConfig = {
  50. weak: {
  51. label: '弱',
  52. color: 'text-red-600',
  53. bgColor: 'bg-red-100',
  54. borderColor: 'border-red-300',
  55. barColor: 'bg-red-500',
  56. icon: ShieldAlert,
  57. width: '33%'
  58. },
  59. medium: {
  60. label: '中',
  61. color: 'text-yellow-600',
  62. bgColor: 'bg-yellow-100',
  63. borderColor: 'border-yellow-300',
  64. barColor: 'bg-yellow-500',
  65. icon: Shield,
  66. width: '66%'
  67. },
  68. strong: {
  69. label: '强',
  70. color: 'text-green-600',
  71. bgColor: 'bg-green-100',
  72. borderColor: 'border-green-300',
  73. barColor: 'bg-green-500',
  74. icon: ShieldCheck,
  75. width: '100%'
  76. }
  77. };
  78. const config = strengthConfig[strength];
  79. const Icon = config.icon;
  80. return (
  81. <div className="space-y-2">
  82. {/* 强度指示器 */}
  83. <div className="flex items-center gap-2">
  84. <div className="flex-1">
  85. <div className="h-2 bg-gray-200 rounded-full overflow-hidden">
  86. <div
  87. className={`h-full ${config.barColor} transition-all duration-300`}
  88. style={{ width: config.width }}
  89. />
  90. </div>
  91. </div>
  92. <div className={`flex items-center gap-1 ${config.color}`}>
  93. <Icon className="w-4 h-4" />
  94. <span className="text-sm font-bold">{config.label}</span>
  95. </div>
  96. </div>
  97. {/* 建议提示 */}
  98. {suggestions.length > 0 && (
  99. <div className={`text-xs ${config.color} space-y-1`}>
  100. {suggestions.map((suggestion, index) => (
  101. <div key={index} className="flex items-start gap-1">
  102. <span>•</span>
  103. <span>{suggestion}</span>
  104. </div>
  105. ))}
  106. </div>
  107. )}
  108. {/* 强度说明 */}
  109. {!isChecking && (
  110. <div className="text-xs text-gray-500">
  111. {strength === 'weak' && '密码强度较弱,建议添加大写字母、数字和特殊符号'}
  112. {strength === 'medium' && '密码强度中等,添加更多字符类型可提高安全性'}
  113. {strength === 'strong' && '密码强度很好,符合安全要求'}
  114. </div>
  115. )}
  116. </div>
  117. );
  118. };
  119. export default PasswordStrengthIndicator;