'use client'; import React, { useState, useEffect } from 'react'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faExchangeAlt, faCopy, faCheck, faSyncAlt, faEraser } from '@fortawesome/free-solid-svg-icons'; import ToolHeader from '@/components/ToolHeader'; import BackToTop from '@/components/BackToTop'; import tools from '@/config/tools'; import { useLanguage } from '@/context/LanguageContext'; // 添加CSS变量样式 const styles = { card: "card p-6", container: "min-h-screen flex flex-col max-w-[1440px] mx-auto p-4 md:p-6", typeBtnActive: "px-4 py-2 rounded-md transition-all bg-gradient-to-r from-[rgb(var(--color-primary))] to-[rgb(var(--color-primary-hover))] text-white shadow-sm shadow-[rgba(var(--color-primary),0.3)]", typeBtnInactive: "px-4 py-2 rounded-md transition-all btn-secondary", toggleContainer: "flex items-center bg-block-strong rounded-md p-1", toggleBtnActive: "px-4 py-2 rounded-md transition-all bg-block text-primary shadow-sm", toggleBtnInactive: "px-4 py-2 rounded-md transition-all text-tertiary", description: "text-sm text-tertiary", textArea: "w-full h-48 p-3 bg-block border border-purple-glow rounded-lg text-primary focus:border-purple focus:outline-none focus:ring-1 focus:ring-purple resize-y font-mono", errorMsg: "py-2 px-3 bg-red-900/20 border border-red-700/30 text-error rounded-md", flexRow: "flex flex-col sm:flex-row gap-4 justify-between items-center", copyBtn: "flex items-center gap-1 px-3 py-1 text-sm rounded-md bg-block-strong hover:bg-block-hover text-secondary transition-colors", swapBtn: "bg-purple-glow/10 text-purple p-2 rounded-full hover:bg-purple-glow/20 transition-colors" }; export default function EncodingConverter() { const { t } = useLanguage(); // 从工具配置中获取当前工具图标 const toolIcon = tools.find(tool => tool.code === 'encoding_converter')?.icon || faExchangeAlt; // 编码类型选项 const encodingTypes = [ { id: 'base64', name: 'Base64', description: t('tools.encoding_converter.base64_desc') }, { id: 'url', name: 'URL', description: t('tools.encoding_converter.url_desc') }, { id: 'unicode', name: 'Unicode', description: t('tools.encoding_converter.unicode_desc') }, { id: 'html', name: 'HTML', description: t('tools.encoding_converter.html_desc') } ]; // 状态管理 const [inputText, setInputText] = useState(''); const [outputText, setOutputText] = useState(''); const [encodingType, setEncodingType] = useState('base64'); const [operation, setOperation] = useState('encode'); // 'encode' 或 'decode' const [error, setError] = useState(''); const [copied, setCopied] = useState(false); // 当输入文本、编码类型或操作变化时,自动执行转换 useEffect(() => { if (inputText.trim() === '') { setOutputText(''); setError(''); return; } try { const result = processConversion(inputText, encodingType, operation); setOutputText(result); setError(''); } catch (err) { if (err instanceof Error) { setError(err.message); } else { setError(t('tools.encoding_converter.general_error')); } setOutputText(''); } }, [inputText, encodingType, operation, t]); // 执行编码或解码操作 const processConversion = (text: string, type: string, op: string): string => { if (text.trim() === '') return ''; try { if (type === 'base64') { return op === 'encode' ? btoa(encodeURIComponent(text).replace(/%([0-9A-F]{2})/g, (_, p1) => String.fromCharCode(parseInt(p1, 16)))) : decodeURIComponent(Array.from(atob(text.replace(/\s/g, ''))) .map(c => '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2)) .join('')); } else if (type === 'url') { return op === 'encode' ? encodeURIComponent(text) : decodeURIComponent(text); } else if (type === 'unicode') { if (op === 'encode') { return Array.from(text) .map(char => '\\u' + char.charCodeAt(0).toString(16).padStart(4, '0')) .join(''); } else { return text.replace(/\\u([0-9a-fA-F]{4})/g, (_, hex) => String.fromCharCode(parseInt(hex, 16)) ); } } else if (type === 'html') { if (op === 'encode') { const el = document.createElement('div'); el.textContent = text; return el.innerHTML; } else { const el = document.createElement('div'); el.innerHTML = text; return el.textContent || ''; } } throw new Error(t('tools.encoding_converter.unsupported_type')); } catch (err) { if (type === 'base64' && op === 'decode') { throw new Error(t('tools.encoding_converter.invalid_base64')); } else if (type === 'url' && op === 'decode') { throw new Error(t('tools.encoding_converter.invalid_url')); } else if (type === 'unicode' && op === 'decode') { throw new Error(t('tools.encoding_converter.invalid_unicode')); } else if (type === 'html' && op === 'decode') { throw new Error(t('tools.encoding_converter.invalid_html')); } throw err; } }; // 复制输出内容到剪贴板 const copyToClipboard = () => { if (!outputText) return; navigator.clipboard.writeText(outputText) .then(() => { setCopied(true); setTimeout(() => setCopied(false), 2000); }) .catch(err => { console.error(t('tools.encoding_converter.copy_failed'), err); setError(t('tools.encoding_converter.clipboard_error')); }); }; // 清空输入和输出 const clearAll = () => { setInputText(''); setOutputText(''); setError(''); }; // 切换操作类型(编码/解码) const _toggleOperation = () => { // 添加动画过渡效果 const container = document.getElementById('converter-container'); if (container) { container.classList.add('animate-pulse'); setTimeout(() => { container.classList.remove('animate-pulse'); }, 300); } // 交换输入和输出文本 const newOperation = operation === 'encode' ? 'decode' : 'encode'; // 使用输出文本替换输入文本 setInputText(outputText); setOperation(newOperation); setError(''); }; // 加载示例文本 const loadExample = () => { const examples = { base64: { encode: t('tools.encoding_converter.example_text'), decode: '5L2g5aW977yM5LiW55WM77yB' }, url: { encode: 'https://jisuxiang.com?query=' + t('tools.encoding_converter.hello') + '&lang=zh-CN', decode: 'https%3A%2F%2Fjisuxiang.com%3Fquery%3D%E4%BD%A0%E5%A5%BD%26lang%3Dzh-CN' }, unicode: { encode: t('tools.encoding_converter.example_text'), decode: '\\u4f60\\u597d\\uff0c\\u4e16\\u754c\\uff01' }, html: { encode: '
{encodingType === 'base64' && ( "Base64是一种基于64个可打印字符来表示二进制数据的表示方法,常用于在HTTP环境下传输二进制数据,如图片或其他媒体文件。" )} {encodingType === 'url' && ( "URL编码将字符转换为可在URL中安全传输的格式,例如将空格转换为%20,中文和特殊字符也会被转换为%后跟十六进制值。" )} {encodingType === 'unicode' && ( "Unicode编码使用\\u前缀后跟四位十六进制数字表示字符,可以表示几乎所有语言的字符,如中文、日文等。" )} {encodingType === 'html' && ( "HTML编码将特殊字符(如<、>、&等)转换为HTML实体,以防止它们被浏览器解释为HTML标签或特殊结构。" )}