123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136 |
- import { ref, computed } from 'vue';
-
- /**
- * 生成随机字符串
- * @param length 字符串长度
- * @returns 随机字符串
- */
- function generateRandomString(length: number): string {
- const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
- let result = '';
- for (let i = 0; i < length; i++) {
- result += characters.charAt(Math.floor(Math.random() * characters.length));
- }
- return result;
- }
-
- /**
- * 为验证码文本生成扭曲的 SVG
- * @param text 验证码文本
- * @returns SVG 字符串
- */
- function generateCaptchaSvg(text: string): string {
- const width = 150;
- const height = 50;
- const fontSize = 30;
- const letters = text.split('');
-
- // 应用于整个 SVG 的滤镜,增加噪点和轻微扭曲
- const filter = `
- <filter id="captchaNoise">
- <feTurbulence baseFrequency="0.7 0.8" numOctaves="3" seed="${Math.random() * 100}" stitchTiles="stitch" type="fractalNoise" result="turbulence"/>
- <feDisplacementMap in="SourceGraphic" in2="turbulence" scale="3" xChannelSelector="R" yChannelSelector="G" result="displacement"/>
- <feGaussianBlur in="displacement" stdDeviation="0.5" />
- </filter>
- `;
-
- // 为每个字母生成 <text> 元素,并应用随机变换
- const textElements = letters.map((char, index) => {
- const x = (width / text.length) * (index + 0.5);
- const y = height / 2 + fontSize / 3; // 基线调整
- const rotate = Math.random() * 30 - 15; // -15 到 15 度旋转
- const skewX = Math.random() * 10 - 5; // 轻微倾斜
- const fill = `hsl(${Math.random() * 360}, 70%, 70%)`; // 随机 HSL 颜色
-
- return `<text
- x="${x}"
- y="${y}"
- font-size="${fontSize}"
- font-family="Arial, sans-serif"
- font-weight="bold"
- text-anchor="middle"
- fill="${fill}"
- transform="rotate(${rotate} ${x} ${y}) skewX(${skewX})"
- style="letter-spacing: 1px;"
- >${char}</text>`;
- }).join('');
-
- // 添加几条干扰线
- let lines = '';
- for (let i = 0; i < 3; i++) {
- lines += `<line
- x1="${Math.random() * width * 0.8}"
- y1="${Math.random() * height}"
- x2="${Math.random() * width * 0.8 + width * 0.2}"
- y2="${Math.random() * height}"
- stroke="rgba(180, 180, 200, 0.3)"
- stroke-width="2"
- />`;
- }
-
- return `
- <svg
- xmlns="http://www.w3.org/2000/svg"
- width="${width}"
- height="${height}"
- viewBox="0 0 ${width} ${height}"
- style="background-color: rgba(55, 65, 81, 0.3); border-radius: 6px; border: 1px solid rgba(107, 114, 128, 0.5);"
- >
- <defs>
- ${filter}
- </defs>
- <g style="filter: url(#captchaNoise);">
- ${textElements}
- ${lines}
- </g>
- </svg>
- `;
- }
-
-
- export function useCaptcha(length: number = 5) {
- const captchaText = ref('');
- const userInput = ref('');
- const captchaSvg = ref('');
- const error = ref('');
-
- /**
- * 生成新的验证码
- */
- const generateCaptcha = () => {
- const newText = generateRandomString(length);
- captchaText.value = newText;
- captchaSvg.value = generateCaptchaSvg(newText);
- userInput.value = ''; // 清空用户输入
- error.value = ''; // 清除错误
- };
-
- /**
- * 验证用户输入
- * @returns 是否验证通过
- */
- const validateCaptcha = (): boolean => {
- if (!userInput.value) {
- error.value = '请输入验证码';
- return false;
- }
- if (userInput.value.toLowerCase() !== captchaText.value.toLowerCase()) {
- error.value = '验证码错误';
- generateCaptcha(); // 错误后自动刷新
- return false;
- }
- error.value = '';
- return true;
- };
-
- // 初始化生成第一个验证码
- generateCaptcha();
-
- return {
- userInput,
- captchaSvg,
- error,
- generateCaptcha,
- validateCaptcha,
- };
- }
|