chore: sync local changes (2026-03-12)
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -1,212 +1,212 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>多功能哈希工具 - Hash Toolkit</title>
|
||||
<link rel="stylesheet" href="css/style.css">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<!-- Header Section -->
|
||||
<header class="header">
|
||||
<div class="header-content">
|
||||
<div class="logo">
|
||||
<i class="fas fa-fingerprint"></i>
|
||||
<h1>Hash Toolkit</h1>
|
||||
</div>
|
||||
<p class="subtitle">多功能哈希、编码与压缩工具</p>
|
||||
</div>
|
||||
<div class="header-decoration">
|
||||
<div class="floating-shapes">
|
||||
<div class="shape shape-1"></div>
|
||||
<div class="shape shape-2"></div>
|
||||
<div class="shape shape-3"></div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<!-- Main Content -->
|
||||
<main class="main-content">
|
||||
<!-- Input Section -->
|
||||
<section class="input-section">
|
||||
<div class="input-card">
|
||||
<div class="card-header">
|
||||
<i class="fas fa-edit"></i>
|
||||
<h2>输入内容</h2>
|
||||
</div>
|
||||
<div class="input-wrapper">
|
||||
<textarea
|
||||
id="inputText"
|
||||
placeholder="请输入要处理的文本内容...\n支持中文、英文、特殊字符等"
|
||||
rows="6"
|
||||
></textarea>
|
||||
<div class="input-actions">
|
||||
<button id="clearBtn" class="btn btn-secondary">
|
||||
<i class="fas fa-trash"></i>
|
||||
清空
|
||||
</button>
|
||||
<button id="processBtn" class="btn btn-primary">
|
||||
<i class="fas fa-cogs"></i>
|
||||
开始处理
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Results Section -->
|
||||
<section class="results-section" id="resultsSection">
|
||||
<div class="results-grid">
|
||||
<!-- Hash Results -->
|
||||
<div class="result-card hash-card">
|
||||
<div class="card-header">
|
||||
<i class="fas fa-hashtag"></i>
|
||||
<h3>哈希算法</h3>
|
||||
</div>
|
||||
<div class="result-items">
|
||||
<div class="result-item">
|
||||
<label>MD5</label>
|
||||
<div class="result-value" id="md5Result">
|
||||
<span class="placeholder">等待处理...</span>
|
||||
<button class="copy-btn" data-target="md5Result">
|
||||
<i class="fas fa-copy"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="result-item">
|
||||
<label>SHA1</label>
|
||||
<div class="result-value" id="sha1Result">
|
||||
<span class="placeholder">等待处理...</span>
|
||||
<button class="copy-btn" data-target="sha1Result">
|
||||
<i class="fas fa-copy"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="result-item">
|
||||
<label>SHA256</label>
|
||||
<div class="result-value" id="sha256Result">
|
||||
<span class="placeholder">等待处理...</span>
|
||||
<button class="copy-btn" data-target="sha256Result">
|
||||
<i class="fas fa-copy"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="result-item">
|
||||
<label>SHA512</label>
|
||||
<div class="result-value" id="sha512Result">
|
||||
<span class="placeholder">等待处理...</span>
|
||||
<button class="copy-btn" data-target="sha512Result">
|
||||
<i class="fas fa-copy"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Encoding Results -->
|
||||
<div class="result-card encoding-card">
|
||||
<div class="card-header">
|
||||
<i class="fas fa-code"></i>
|
||||
<h3>编码转换</h3>
|
||||
</div>
|
||||
<div class="result-items">
|
||||
<div class="result-item">
|
||||
<label>Base64 编码</label>
|
||||
<div class="result-value" id="base64EncodeResult">
|
||||
<span class="placeholder">等待处理...</span>
|
||||
<button class="copy-btn" data-target="base64EncodeResult">
|
||||
<i class="fas fa-copy"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="result-item">
|
||||
<label>Base64 解码</label>
|
||||
<div class="result-value" id="base64DecodeResult">
|
||||
<span class="placeholder">等待处理...</span>
|
||||
<button class="copy-btn" data-target="base64DecodeResult">
|
||||
<i class="fas fa-copy"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="result-item">
|
||||
<label>URL 编码</label>
|
||||
<div class="result-value" id="urlEncodeResult">
|
||||
<span class="placeholder">等待处理...</span>
|
||||
<button class="copy-btn" data-target="urlEncodeResult">
|
||||
<i class="fas fa-copy"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="result-item">
|
||||
<label>URL 解码</label>
|
||||
<div class="result-value" id="urlDecodeResult">
|
||||
<span class="placeholder">等待处理...</span>
|
||||
<button class="copy-btn" data-target="urlDecodeResult">
|
||||
<i class="fas fa-copy"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Compression Results -->
|
||||
<div class="result-card compression-card">
|
||||
<div class="card-header">
|
||||
<i class="fas fa-compress-alt"></i>
|
||||
<h3>压缩算法</h3>
|
||||
</div>
|
||||
<div class="result-items">
|
||||
<div class="result-item">
|
||||
<label>Gzip 压缩</label>
|
||||
<div class="result-value" id="gzipCompressResult">
|
||||
<span class="placeholder">等待处理...</span>
|
||||
<button class="copy-btn" data-target="gzipCompressResult">
|
||||
<i class="fas fa-copy"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="result-item">
|
||||
<label>Deflate 压缩</label>
|
||||
<div class="result-value" id="deflateCompressResult">
|
||||
<span class="placeholder">等待处理...</span>
|
||||
<button class="copy-btn" data-target="deflateCompressResult">
|
||||
<i class="fas fa-copy"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="result-item">
|
||||
<label>Brotli 压缩</label>
|
||||
<div class="result-value" id="brotliCompressResult">
|
||||
<span class="placeholder">等待处理...</span>
|
||||
<button class="copy-btn" data-target="brotliCompressResult">
|
||||
<i class="fas fa-copy"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<!-- Loading Overlay -->
|
||||
<div class="loading-overlay" id="loadingOverlay">
|
||||
<div class="loading-spinner">
|
||||
<div class="spinner"></div>
|
||||
<p>正在处理中...</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Toast Notification -->
|
||||
<div class="toast" id="toast">
|
||||
<i class="fas fa-check-circle"></i>
|
||||
<span id="toastMessage">复制成功!</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="js/script.js"></script>
|
||||
</body>
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>多功能哈希工具 - Hash Toolkit</title>
|
||||
<link rel="stylesheet" href="css/style.css">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<!-- Header Section -->
|
||||
<header class="header">
|
||||
<div class="header-content">
|
||||
<div class="logo">
|
||||
<i class="fas fa-fingerprint"></i>
|
||||
<h1>Hash Toolkit</h1>
|
||||
</div>
|
||||
<p class="subtitle">多功能哈希、编码与压缩工具</p>
|
||||
</div>
|
||||
<div class="header-decoration">
|
||||
<div class="floating-shapes">
|
||||
<div class="shape shape-1"></div>
|
||||
<div class="shape shape-2"></div>
|
||||
<div class="shape shape-3"></div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<!-- Main Content -->
|
||||
<main class="main-content">
|
||||
<!-- Input Section -->
|
||||
<section class="input-section">
|
||||
<div class="input-card">
|
||||
<div class="card-header">
|
||||
<i class="fas fa-edit"></i>
|
||||
<h2>输入内容</h2>
|
||||
</div>
|
||||
<div class="input-wrapper">
|
||||
<textarea
|
||||
id="inputText"
|
||||
placeholder="请输入要处理的文本内容...\n支持中文、英文、特殊字符等"
|
||||
rows="6"
|
||||
></textarea>
|
||||
<div class="input-actions">
|
||||
<button id="clearBtn" class="btn btn-secondary">
|
||||
<i class="fas fa-trash"></i>
|
||||
清空
|
||||
</button>
|
||||
<button id="processBtn" class="btn btn-primary">
|
||||
<i class="fas fa-cogs"></i>
|
||||
开始处理
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Results Section -->
|
||||
<section class="results-section" id="resultsSection">
|
||||
<div class="results-grid">
|
||||
<!-- Hash Results -->
|
||||
<div class="result-card hash-card">
|
||||
<div class="card-header">
|
||||
<i class="fas fa-hashtag"></i>
|
||||
<h3>哈希算法</h3>
|
||||
</div>
|
||||
<div class="result-items">
|
||||
<div class="result-item">
|
||||
<label>MD5</label>
|
||||
<div class="result-value" id="md5Result">
|
||||
<span class="placeholder">等待处理...</span>
|
||||
<button class="copy-btn" data-target="md5Result">
|
||||
<i class="fas fa-copy"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="result-item">
|
||||
<label>SHA1</label>
|
||||
<div class="result-value" id="sha1Result">
|
||||
<span class="placeholder">等待处理...</span>
|
||||
<button class="copy-btn" data-target="sha1Result">
|
||||
<i class="fas fa-copy"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="result-item">
|
||||
<label>SHA256</label>
|
||||
<div class="result-value" id="sha256Result">
|
||||
<span class="placeholder">等待处理...</span>
|
||||
<button class="copy-btn" data-target="sha256Result">
|
||||
<i class="fas fa-copy"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="result-item">
|
||||
<label>SHA512</label>
|
||||
<div class="result-value" id="sha512Result">
|
||||
<span class="placeholder">等待处理...</span>
|
||||
<button class="copy-btn" data-target="sha512Result">
|
||||
<i class="fas fa-copy"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Encoding Results -->
|
||||
<div class="result-card encoding-card">
|
||||
<div class="card-header">
|
||||
<i class="fas fa-code"></i>
|
||||
<h3>编码转换</h3>
|
||||
</div>
|
||||
<div class="result-items">
|
||||
<div class="result-item">
|
||||
<label>Base64 编码</label>
|
||||
<div class="result-value" id="base64EncodeResult">
|
||||
<span class="placeholder">等待处理...</span>
|
||||
<button class="copy-btn" data-target="base64EncodeResult">
|
||||
<i class="fas fa-copy"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="result-item">
|
||||
<label>Base64 解码</label>
|
||||
<div class="result-value" id="base64DecodeResult">
|
||||
<span class="placeholder">等待处理...</span>
|
||||
<button class="copy-btn" data-target="base64DecodeResult">
|
||||
<i class="fas fa-copy"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="result-item">
|
||||
<label>URL 编码</label>
|
||||
<div class="result-value" id="urlEncodeResult">
|
||||
<span class="placeholder">等待处理...</span>
|
||||
<button class="copy-btn" data-target="urlEncodeResult">
|
||||
<i class="fas fa-copy"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="result-item">
|
||||
<label>URL 解码</label>
|
||||
<div class="result-value" id="urlDecodeResult">
|
||||
<span class="placeholder">等待处理...</span>
|
||||
<button class="copy-btn" data-target="urlDecodeResult">
|
||||
<i class="fas fa-copy"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Compression Results -->
|
||||
<div class="result-card compression-card">
|
||||
<div class="card-header">
|
||||
<i class="fas fa-compress-alt"></i>
|
||||
<h3>压缩算法</h3>
|
||||
</div>
|
||||
<div class="result-items">
|
||||
<div class="result-item">
|
||||
<label>Gzip 压缩</label>
|
||||
<div class="result-value" id="gzipCompressResult">
|
||||
<span class="placeholder">等待处理...</span>
|
||||
<button class="copy-btn" data-target="gzipCompressResult">
|
||||
<i class="fas fa-copy"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="result-item">
|
||||
<label>Deflate 压缩</label>
|
||||
<div class="result-value" id="deflateCompressResult">
|
||||
<span class="placeholder">等待处理...</span>
|
||||
<button class="copy-btn" data-target="deflateCompressResult">
|
||||
<i class="fas fa-copy"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="result-item">
|
||||
<label>Brotli 压缩</label>
|
||||
<div class="result-value" id="brotliCompressResult">
|
||||
<span class="placeholder">等待处理...</span>
|
||||
<button class="copy-btn" data-target="brotliCompressResult">
|
||||
<i class="fas fa-copy"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<!-- Loading Overlay -->
|
||||
<div class="loading-overlay" id="loadingOverlay">
|
||||
<div class="loading-spinner">
|
||||
<div class="spinner"></div>
|
||||
<p>正在处理中...</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Toast Notification -->
|
||||
<div class="toast" id="toast">
|
||||
<i class="fas fa-check-circle"></i>
|
||||
<span id="toastMessage">复制成功!</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="js/script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,394 +1,394 @@
|
||||
// API配置
|
||||
const API_BASE_URL = 'https://60s.api.shumengya.top/v2/hash';
|
||||
|
||||
// DOM元素
|
||||
const elements = {
|
||||
inputText: document.getElementById('inputText'),
|
||||
processBtn: document.getElementById('processBtn'),
|
||||
clearBtn: document.getElementById('clearBtn'),
|
||||
resultsSection: document.getElementById('resultsSection'),
|
||||
loadingOverlay: document.getElementById('loadingOverlay'),
|
||||
toast: document.getElementById('toast'),
|
||||
toastMessage: document.getElementById('toastMessage')
|
||||
};
|
||||
|
||||
// 结果元素映射
|
||||
const resultElements = {
|
||||
md5: document.getElementById('md5Result'),
|
||||
sha1: document.getElementById('sha1Result'),
|
||||
sha256: document.getElementById('sha256Result'),
|
||||
sha512: document.getElementById('sha512Result'),
|
||||
base64Encode: document.getElementById('base64EncodeResult'),
|
||||
base64Decode: document.getElementById('base64DecodeResult'),
|
||||
urlEncode: document.getElementById('urlEncodeResult'),
|
||||
urlDecode: document.getElementById('urlDecodeResult'),
|
||||
gzipCompress: document.getElementById('gzipCompressResult'),
|
||||
deflateCompress: document.getElementById('deflateCompressResult'),
|
||||
brotliCompress: document.getElementById('brotliCompressResult')
|
||||
};
|
||||
|
||||
// 初始化
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
initializeEventListeners();
|
||||
addInputAnimation();
|
||||
});
|
||||
|
||||
// 事件监听器初始化
|
||||
function initializeEventListeners() {
|
||||
// 处理按钮点击
|
||||
elements.processBtn.addEventListener('click', handleProcess);
|
||||
|
||||
// 清空按钮点击
|
||||
elements.clearBtn.addEventListener('click', handleClear);
|
||||
|
||||
// 输入框回车键
|
||||
elements.inputText.addEventListener('keydown', function(e) {
|
||||
if (e.ctrlKey && e.key === 'Enter') {
|
||||
handleProcess();
|
||||
}
|
||||
});
|
||||
|
||||
// 复制按钮事件委托
|
||||
document.addEventListener('click', function(e) {
|
||||
if (e.target.closest('.copy-btn')) {
|
||||
const copyBtn = e.target.closest('.copy-btn');
|
||||
const targetId = copyBtn.getAttribute('data-target');
|
||||
const targetElement = document.getElementById(targetId);
|
||||
const textContent = targetElement.textContent.trim();
|
||||
|
||||
if (textContent && textContent !== '等待处理...' && textContent !== '处理失败') {
|
||||
copyToClipboard(textContent);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 输入框实时验证
|
||||
elements.inputText.addEventListener('input', function() {
|
||||
const hasContent = this.value.trim().length > 0;
|
||||
elements.processBtn.disabled = !hasContent;
|
||||
|
||||
if (hasContent) {
|
||||
elements.processBtn.classList.remove('disabled');
|
||||
} else {
|
||||
elements.processBtn.classList.add('disabled');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 添加输入动画效果
|
||||
function addInputAnimation() {
|
||||
elements.inputText.addEventListener('focus', function() {
|
||||
this.parentElement.classList.add('focused');
|
||||
});
|
||||
|
||||
elements.inputText.addEventListener('blur', function() {
|
||||
this.parentElement.classList.remove('focused');
|
||||
});
|
||||
}
|
||||
|
||||
// 处理主要功能
|
||||
async function handleProcess() {
|
||||
const inputValue = elements.inputText.value.trim();
|
||||
|
||||
if (!inputValue) {
|
||||
showToast('请输入要处理的内容', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
// 显示加载状态
|
||||
showLoading(true);
|
||||
resetResults();
|
||||
|
||||
try {
|
||||
// 调用API
|
||||
const response = await fetch(`${API_BASE_URL}?content=${encodeURIComponent(inputValue)}`);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (data.code === 200 && data.data) {
|
||||
displayResults(data.data);
|
||||
showResultsSection();
|
||||
showToast('处理完成!', 'success');
|
||||
} else {
|
||||
throw new Error(data.message || '处理失败');
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('处理错误:', error);
|
||||
showToast(`处理失败: ${error.message}`, 'error');
|
||||
displayError();
|
||||
} finally {
|
||||
showLoading(false);
|
||||
}
|
||||
}
|
||||
|
||||
// 显示结果
|
||||
function displayResults(data) {
|
||||
try {
|
||||
// 哈希结果
|
||||
updateResultElement('md5', data.md5 || '不可用');
|
||||
|
||||
// SHA系列
|
||||
if (data.sha) {
|
||||
updateResultElement('sha1', data.sha.sha1 || '不可用');
|
||||
updateResultElement('sha256', data.sha.sha256 || '不可用');
|
||||
updateResultElement('sha512', data.sha.sha512 || '不可用');
|
||||
}
|
||||
|
||||
// Base64编码
|
||||
if (data.base64) {
|
||||
updateResultElement('base64Encode', data.base64.encoded || '不可用');
|
||||
// BASE64解码:只有当输入本身是BASE64格式时才显示解码结果
|
||||
let base64DecodeResult = data.base64.decoded;
|
||||
if (!base64DecodeResult) {
|
||||
// 检查输入是否为有效的BASE64格式
|
||||
const inputValue = elements.inputText.value.trim();
|
||||
const base64Regex = /^[A-Za-z0-9+/]*={0,2}$/;
|
||||
if (base64Regex.test(inputValue) && inputValue.length % 4 === 0) {
|
||||
try {
|
||||
base64DecodeResult = atob(inputValue);
|
||||
} catch (e) {
|
||||
base64DecodeResult = '解码失败';
|
||||
}
|
||||
} else {
|
||||
base64DecodeResult = '输入非BASE64格式';
|
||||
}
|
||||
}
|
||||
updateResultElement('base64Decode', base64DecodeResult || '不可用');
|
||||
}
|
||||
|
||||
// URL编码
|
||||
if (data.url) {
|
||||
updateResultElement('urlEncode', data.url.encoded || '不可用');
|
||||
updateResultElement('urlDecode', data.url.decoded || '不可用');
|
||||
}
|
||||
|
||||
// 压缩结果(仅显示压缩,不显示解压)
|
||||
if (data.gzip) {
|
||||
updateResultElement('gzipCompress', data.gzip.encoded || '不可用');
|
||||
}
|
||||
|
||||
if (data.deflate) {
|
||||
updateResultElement('deflateCompress', data.deflate.encoded || '不可用');
|
||||
}
|
||||
|
||||
if (data.brotli) {
|
||||
updateResultElement('brotliCompress', data.brotli.encoded || '不可用');
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('显示结果时出错:', error);
|
||||
showToast('显示结果时出错', 'error');
|
||||
}
|
||||
}
|
||||
|
||||
// 更新单个结果元素
|
||||
function updateResultElement(key, value) {
|
||||
const element = resultElements[key];
|
||||
if (element) {
|
||||
const textSpan = element.querySelector('span') || element;
|
||||
textSpan.textContent = value;
|
||||
textSpan.classList.remove('placeholder');
|
||||
|
||||
// 添加动画效果
|
||||
element.classList.add('slide-in');
|
||||
setTimeout(() => {
|
||||
element.classList.remove('slide-in');
|
||||
}, 300);
|
||||
}
|
||||
}
|
||||
|
||||
// 重置结果
|
||||
function resetResults() {
|
||||
Object.values(resultElements).forEach(element => {
|
||||
if (element) {
|
||||
const textSpan = element.querySelector('span') || element;
|
||||
textSpan.textContent = '等待处理...';
|
||||
textSpan.classList.add('placeholder');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 显示错误状态
|
||||
function displayError() {
|
||||
Object.values(resultElements).forEach(element => {
|
||||
if (element) {
|
||||
const textSpan = element.querySelector('span') || element;
|
||||
textSpan.textContent = '处理失败';
|
||||
textSpan.classList.add('placeholder');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 显示结果区域
|
||||
function showResultsSection() {
|
||||
elements.resultsSection.classList.add('show');
|
||||
|
||||
// 平滑滚动到结果区域
|
||||
setTimeout(() => {
|
||||
elements.resultsSection.scrollIntoView({
|
||||
behavior: 'smooth',
|
||||
block: 'start'
|
||||
});
|
||||
}, 100);
|
||||
}
|
||||
|
||||
// 清空功能
|
||||
function handleClear() {
|
||||
elements.inputText.value = '';
|
||||
elements.inputText.focus();
|
||||
elements.resultsSection.classList.remove('show');
|
||||
resetResults();
|
||||
elements.processBtn.disabled = true;
|
||||
elements.processBtn.classList.add('disabled');
|
||||
|
||||
showToast('内容已清空', 'info');
|
||||
}
|
||||
|
||||
// 复制到剪贴板
|
||||
async function copyToClipboard(text) {
|
||||
try {
|
||||
if (navigator.clipboard && window.isSecureContext) {
|
||||
await navigator.clipboard.writeText(text);
|
||||
} else {
|
||||
// 降级方案
|
||||
const textArea = document.createElement('textarea');
|
||||
textArea.value = text;
|
||||
textArea.style.position = 'fixed';
|
||||
textArea.style.left = '-999999px';
|
||||
textArea.style.top = '-999999px';
|
||||
document.body.appendChild(textArea);
|
||||
textArea.focus();
|
||||
textArea.select();
|
||||
document.execCommand('copy');
|
||||
textArea.remove();
|
||||
}
|
||||
|
||||
showToast('复制成功!', 'success');
|
||||
} catch (error) {
|
||||
console.error('复制失败:', error);
|
||||
showToast('复制失败,请手动复制', 'error');
|
||||
}
|
||||
}
|
||||
|
||||
// 显示/隐藏加载状态
|
||||
function showLoading(show) {
|
||||
if (show) {
|
||||
elements.loadingOverlay.classList.add('show');
|
||||
elements.processBtn.disabled = true;
|
||||
elements.processBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> 处理中...';
|
||||
} else {
|
||||
elements.loadingOverlay.classList.remove('show');
|
||||
elements.processBtn.disabled = false;
|
||||
elements.processBtn.innerHTML = '<i class="fas fa-cogs"></i> 开始处理';
|
||||
}
|
||||
}
|
||||
|
||||
// 显示提示消息
|
||||
function showToast(message, type = 'success') {
|
||||
elements.toastMessage.textContent = message;
|
||||
|
||||
// 设置图标和样式
|
||||
const icon = elements.toast.querySelector('i');
|
||||
icon.className = getToastIcon(type);
|
||||
|
||||
elements.toast.className = `toast ${type}`;
|
||||
elements.toast.classList.add('show');
|
||||
|
||||
// 自动隐藏
|
||||
setTimeout(() => {
|
||||
elements.toast.classList.remove('show');
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
// 获取提示图标
|
||||
function getToastIcon(type) {
|
||||
const icons = {
|
||||
success: 'fas fa-check-circle',
|
||||
error: 'fas fa-exclamation-circle',
|
||||
info: 'fas fa-info-circle',
|
||||
warning: 'fas fa-exclamation-triangle'
|
||||
};
|
||||
return icons[type] || icons.success;
|
||||
}
|
||||
|
||||
// 工具函数:防抖
|
||||
function debounce(func, wait) {
|
||||
let timeout;
|
||||
return function executedFunction(...args) {
|
||||
const later = () => {
|
||||
clearTimeout(timeout);
|
||||
func(...args);
|
||||
};
|
||||
clearTimeout(timeout);
|
||||
timeout = setTimeout(later, wait);
|
||||
};
|
||||
}
|
||||
|
||||
// 工具函数:节流
|
||||
function throttle(func, limit) {
|
||||
let inThrottle;
|
||||
return function() {
|
||||
const args = arguments;
|
||||
const context = this;
|
||||
if (!inThrottle) {
|
||||
func.apply(context, args);
|
||||
inThrottle = true;
|
||||
setTimeout(() => inThrottle = false, limit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 添加键盘快捷键支持
|
||||
document.addEventListener('keydown', function(e) {
|
||||
// Ctrl+Enter 处理
|
||||
if (e.ctrlKey && e.key === 'Enter') {
|
||||
e.preventDefault();
|
||||
if (!elements.processBtn.disabled) {
|
||||
handleProcess();
|
||||
}
|
||||
}
|
||||
|
||||
// Escape 清空
|
||||
if (e.key === 'Escape') {
|
||||
handleClear();
|
||||
}
|
||||
});
|
||||
|
||||
// 页面可见性变化处理
|
||||
document.addEventListener('visibilitychange', function() {
|
||||
if (document.hidden) {
|
||||
// 页面隐藏时的处理
|
||||
console.log('页面已隐藏');
|
||||
} else {
|
||||
// 页面显示时的处理
|
||||
console.log('页面已显示');
|
||||
}
|
||||
});
|
||||
|
||||
// 错误处理
|
||||
window.addEventListener('error', function(e) {
|
||||
console.error('全局错误:', e.error);
|
||||
showToast('发生未知错误,请刷新页面重试', 'error');
|
||||
});
|
||||
|
||||
// 未处理的Promise拒绝
|
||||
window.addEventListener('unhandledrejection', function(e) {
|
||||
console.error('未处理的Promise拒绝:', e.reason);
|
||||
showToast('网络请求失败,请检查网络连接', 'error');
|
||||
});
|
||||
|
||||
// 导出函数供测试使用
|
||||
if (typeof module !== 'undefined' && module.exports) {
|
||||
module.exports = {
|
||||
handleProcess,
|
||||
copyToClipboard,
|
||||
showToast,
|
||||
debounce,
|
||||
throttle
|
||||
};
|
||||
// API配置
|
||||
const API_BASE_URL = 'https://60s.api.shumengya.top/v2/hash';
|
||||
|
||||
// DOM元素
|
||||
const elements = {
|
||||
inputText: document.getElementById('inputText'),
|
||||
processBtn: document.getElementById('processBtn'),
|
||||
clearBtn: document.getElementById('clearBtn'),
|
||||
resultsSection: document.getElementById('resultsSection'),
|
||||
loadingOverlay: document.getElementById('loadingOverlay'),
|
||||
toast: document.getElementById('toast'),
|
||||
toastMessage: document.getElementById('toastMessage')
|
||||
};
|
||||
|
||||
// 结果元素映射
|
||||
const resultElements = {
|
||||
md5: document.getElementById('md5Result'),
|
||||
sha1: document.getElementById('sha1Result'),
|
||||
sha256: document.getElementById('sha256Result'),
|
||||
sha512: document.getElementById('sha512Result'),
|
||||
base64Encode: document.getElementById('base64EncodeResult'),
|
||||
base64Decode: document.getElementById('base64DecodeResult'),
|
||||
urlEncode: document.getElementById('urlEncodeResult'),
|
||||
urlDecode: document.getElementById('urlDecodeResult'),
|
||||
gzipCompress: document.getElementById('gzipCompressResult'),
|
||||
deflateCompress: document.getElementById('deflateCompressResult'),
|
||||
brotliCompress: document.getElementById('brotliCompressResult')
|
||||
};
|
||||
|
||||
// 初始化
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
initializeEventListeners();
|
||||
addInputAnimation();
|
||||
});
|
||||
|
||||
// 事件监听器初始化
|
||||
function initializeEventListeners() {
|
||||
// 处理按钮点击
|
||||
elements.processBtn.addEventListener('click', handleProcess);
|
||||
|
||||
// 清空按钮点击
|
||||
elements.clearBtn.addEventListener('click', handleClear);
|
||||
|
||||
// 输入框回车键
|
||||
elements.inputText.addEventListener('keydown', function(e) {
|
||||
if (e.ctrlKey && e.key === 'Enter') {
|
||||
handleProcess();
|
||||
}
|
||||
});
|
||||
|
||||
// 复制按钮事件委托
|
||||
document.addEventListener('click', function(e) {
|
||||
if (e.target.closest('.copy-btn')) {
|
||||
const copyBtn = e.target.closest('.copy-btn');
|
||||
const targetId = copyBtn.getAttribute('data-target');
|
||||
const targetElement = document.getElementById(targetId);
|
||||
const textContent = targetElement.textContent.trim();
|
||||
|
||||
if (textContent && textContent !== '等待处理...' && textContent !== '处理失败') {
|
||||
copyToClipboard(textContent);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 输入框实时验证
|
||||
elements.inputText.addEventListener('input', function() {
|
||||
const hasContent = this.value.trim().length > 0;
|
||||
elements.processBtn.disabled = !hasContent;
|
||||
|
||||
if (hasContent) {
|
||||
elements.processBtn.classList.remove('disabled');
|
||||
} else {
|
||||
elements.processBtn.classList.add('disabled');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 添加输入动画效果
|
||||
function addInputAnimation() {
|
||||
elements.inputText.addEventListener('focus', function() {
|
||||
this.parentElement.classList.add('focused');
|
||||
});
|
||||
|
||||
elements.inputText.addEventListener('blur', function() {
|
||||
this.parentElement.classList.remove('focused');
|
||||
});
|
||||
}
|
||||
|
||||
// 处理主要功能
|
||||
async function handleProcess() {
|
||||
const inputValue = elements.inputText.value.trim();
|
||||
|
||||
if (!inputValue) {
|
||||
showToast('请输入要处理的内容', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
// 显示加载状态
|
||||
showLoading(true);
|
||||
resetResults();
|
||||
|
||||
try {
|
||||
// 调用API
|
||||
const response = await fetch(`${API_BASE_URL}?content=${encodeURIComponent(inputValue)}`);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (data.code === 200 && data.data) {
|
||||
displayResults(data.data);
|
||||
showResultsSection();
|
||||
showToast('处理完成!', 'success');
|
||||
} else {
|
||||
throw new Error(data.message || '处理失败');
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('处理错误:', error);
|
||||
showToast(`处理失败: ${error.message}`, 'error');
|
||||
displayError();
|
||||
} finally {
|
||||
showLoading(false);
|
||||
}
|
||||
}
|
||||
|
||||
// 显示结果
|
||||
function displayResults(data) {
|
||||
try {
|
||||
// 哈希结果
|
||||
updateResultElement('md5', data.md5 || '不可用');
|
||||
|
||||
// SHA系列
|
||||
if (data.sha) {
|
||||
updateResultElement('sha1', data.sha.sha1 || '不可用');
|
||||
updateResultElement('sha256', data.sha.sha256 || '不可用');
|
||||
updateResultElement('sha512', data.sha.sha512 || '不可用');
|
||||
}
|
||||
|
||||
// Base64编码
|
||||
if (data.base64) {
|
||||
updateResultElement('base64Encode', data.base64.encoded || '不可用');
|
||||
// BASE64解码:只有当输入本身是BASE64格式时才显示解码结果
|
||||
let base64DecodeResult = data.base64.decoded;
|
||||
if (!base64DecodeResult) {
|
||||
// 检查输入是否为有效的BASE64格式
|
||||
const inputValue = elements.inputText.value.trim();
|
||||
const base64Regex = /^[A-Za-z0-9+/]*={0,2}$/;
|
||||
if (base64Regex.test(inputValue) && inputValue.length % 4 === 0) {
|
||||
try {
|
||||
base64DecodeResult = atob(inputValue);
|
||||
} catch (e) {
|
||||
base64DecodeResult = '解码失败';
|
||||
}
|
||||
} else {
|
||||
base64DecodeResult = '输入非BASE64格式';
|
||||
}
|
||||
}
|
||||
updateResultElement('base64Decode', base64DecodeResult || '不可用');
|
||||
}
|
||||
|
||||
// URL编码
|
||||
if (data.url) {
|
||||
updateResultElement('urlEncode', data.url.encoded || '不可用');
|
||||
updateResultElement('urlDecode', data.url.decoded || '不可用');
|
||||
}
|
||||
|
||||
// 压缩结果(仅显示压缩,不显示解压)
|
||||
if (data.gzip) {
|
||||
updateResultElement('gzipCompress', data.gzip.encoded || '不可用');
|
||||
}
|
||||
|
||||
if (data.deflate) {
|
||||
updateResultElement('deflateCompress', data.deflate.encoded || '不可用');
|
||||
}
|
||||
|
||||
if (data.brotli) {
|
||||
updateResultElement('brotliCompress', data.brotli.encoded || '不可用');
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('显示结果时出错:', error);
|
||||
showToast('显示结果时出错', 'error');
|
||||
}
|
||||
}
|
||||
|
||||
// 更新单个结果元素
|
||||
function updateResultElement(key, value) {
|
||||
const element = resultElements[key];
|
||||
if (element) {
|
||||
const textSpan = element.querySelector('span') || element;
|
||||
textSpan.textContent = value;
|
||||
textSpan.classList.remove('placeholder');
|
||||
|
||||
// 添加动画效果
|
||||
element.classList.add('slide-in');
|
||||
setTimeout(() => {
|
||||
element.classList.remove('slide-in');
|
||||
}, 300);
|
||||
}
|
||||
}
|
||||
|
||||
// 重置结果
|
||||
function resetResults() {
|
||||
Object.values(resultElements).forEach(element => {
|
||||
if (element) {
|
||||
const textSpan = element.querySelector('span') || element;
|
||||
textSpan.textContent = '等待处理...';
|
||||
textSpan.classList.add('placeholder');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 显示错误状态
|
||||
function displayError() {
|
||||
Object.values(resultElements).forEach(element => {
|
||||
if (element) {
|
||||
const textSpan = element.querySelector('span') || element;
|
||||
textSpan.textContent = '处理失败';
|
||||
textSpan.classList.add('placeholder');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 显示结果区域
|
||||
function showResultsSection() {
|
||||
elements.resultsSection.classList.add('show');
|
||||
|
||||
// 平滑滚动到结果区域
|
||||
setTimeout(() => {
|
||||
elements.resultsSection.scrollIntoView({
|
||||
behavior: 'smooth',
|
||||
block: 'start'
|
||||
});
|
||||
}, 100);
|
||||
}
|
||||
|
||||
// 清空功能
|
||||
function handleClear() {
|
||||
elements.inputText.value = '';
|
||||
elements.inputText.focus();
|
||||
elements.resultsSection.classList.remove('show');
|
||||
resetResults();
|
||||
elements.processBtn.disabled = true;
|
||||
elements.processBtn.classList.add('disabled');
|
||||
|
||||
showToast('内容已清空', 'info');
|
||||
}
|
||||
|
||||
// 复制到剪贴板
|
||||
async function copyToClipboard(text) {
|
||||
try {
|
||||
if (navigator.clipboard && window.isSecureContext) {
|
||||
await navigator.clipboard.writeText(text);
|
||||
} else {
|
||||
// 降级方案
|
||||
const textArea = document.createElement('textarea');
|
||||
textArea.value = text;
|
||||
textArea.style.position = 'fixed';
|
||||
textArea.style.left = '-999999px';
|
||||
textArea.style.top = '-999999px';
|
||||
document.body.appendChild(textArea);
|
||||
textArea.focus();
|
||||
textArea.select();
|
||||
document.execCommand('copy');
|
||||
textArea.remove();
|
||||
}
|
||||
|
||||
showToast('复制成功!', 'success');
|
||||
} catch (error) {
|
||||
console.error('复制失败:', error);
|
||||
showToast('复制失败,请手动复制', 'error');
|
||||
}
|
||||
}
|
||||
|
||||
// 显示/隐藏加载状态
|
||||
function showLoading(show) {
|
||||
if (show) {
|
||||
elements.loadingOverlay.classList.add('show');
|
||||
elements.processBtn.disabled = true;
|
||||
elements.processBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> 处理中...';
|
||||
} else {
|
||||
elements.loadingOverlay.classList.remove('show');
|
||||
elements.processBtn.disabled = false;
|
||||
elements.processBtn.innerHTML = '<i class="fas fa-cogs"></i> 开始处理';
|
||||
}
|
||||
}
|
||||
|
||||
// 显示提示消息
|
||||
function showToast(message, type = 'success') {
|
||||
elements.toastMessage.textContent = message;
|
||||
|
||||
// 设置图标和样式
|
||||
const icon = elements.toast.querySelector('i');
|
||||
icon.className = getToastIcon(type);
|
||||
|
||||
elements.toast.className = `toast ${type}`;
|
||||
elements.toast.classList.add('show');
|
||||
|
||||
// 自动隐藏
|
||||
setTimeout(() => {
|
||||
elements.toast.classList.remove('show');
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
// 获取提示图标
|
||||
function getToastIcon(type) {
|
||||
const icons = {
|
||||
success: 'fas fa-check-circle',
|
||||
error: 'fas fa-exclamation-circle',
|
||||
info: 'fas fa-info-circle',
|
||||
warning: 'fas fa-exclamation-triangle'
|
||||
};
|
||||
return icons[type] || icons.success;
|
||||
}
|
||||
|
||||
// 工具函数:防抖
|
||||
function debounce(func, wait) {
|
||||
let timeout;
|
||||
return function executedFunction(...args) {
|
||||
const later = () => {
|
||||
clearTimeout(timeout);
|
||||
func(...args);
|
||||
};
|
||||
clearTimeout(timeout);
|
||||
timeout = setTimeout(later, wait);
|
||||
};
|
||||
}
|
||||
|
||||
// 工具函数:节流
|
||||
function throttle(func, limit) {
|
||||
let inThrottle;
|
||||
return function() {
|
||||
const args = arguments;
|
||||
const context = this;
|
||||
if (!inThrottle) {
|
||||
func.apply(context, args);
|
||||
inThrottle = true;
|
||||
setTimeout(() => inThrottle = false, limit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 添加键盘快捷键支持
|
||||
document.addEventListener('keydown', function(e) {
|
||||
// Ctrl+Enter 处理
|
||||
if (e.ctrlKey && e.key === 'Enter') {
|
||||
e.preventDefault();
|
||||
if (!elements.processBtn.disabled) {
|
||||
handleProcess();
|
||||
}
|
||||
}
|
||||
|
||||
// Escape 清空
|
||||
if (e.key === 'Escape') {
|
||||
handleClear();
|
||||
}
|
||||
});
|
||||
|
||||
// 页面可见性变化处理
|
||||
document.addEventListener('visibilitychange', function() {
|
||||
if (document.hidden) {
|
||||
// 页面隐藏时的处理
|
||||
console.log('页面已隐藏');
|
||||
} else {
|
||||
// 页面显示时的处理
|
||||
console.log('页面已显示');
|
||||
}
|
||||
});
|
||||
|
||||
// 错误处理
|
||||
window.addEventListener('error', function(e) {
|
||||
console.error('全局错误:', e.error);
|
||||
showToast('发生未知错误,请刷新页面重试', 'error');
|
||||
});
|
||||
|
||||
// 未处理的Promise拒绝
|
||||
window.addEventListener('unhandledrejection', function(e) {
|
||||
console.error('未处理的Promise拒绝:', e.reason);
|
||||
showToast('网络请求失败,请检查网络连接', 'error');
|
||||
});
|
||||
|
||||
// 导出函数供测试使用
|
||||
if (typeof module !== 'undefined' && module.exports) {
|
||||
module.exports = {
|
||||
handleProcess,
|
||||
copyToClipboard,
|
||||
showToast,
|
||||
debounce,
|
||||
throttle
|
||||
};
|
||||
}
|
||||
@@ -1,3 +1,3 @@
|
||||
[
|
||||
"https://60s.api.shumengya.top"
|
||||
]
|
||||
[
|
||||
"https://60s.api.shumengya.top"
|
||||
]
|
||||
|
||||
@@ -1,35 +1,35 @@
|
||||
{
|
||||
"code": 200,
|
||||
"message": "获取成功。数据来自官方/权威源头,以确保稳定与实时。开源地址 https://github.com/vikiboss/60s,反馈群 595941841",
|
||||
"data": {
|
||||
"source": "hello",
|
||||
"md5": "5d41402abc4b2a76b9719d911017c592",
|
||||
"sha": {
|
||||
"sha1": "aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d",
|
||||
"sha256": "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824",
|
||||
"sha512": "9b71d224bd62f3785d96d46ad3ea3d73319bfbc2890caadae2dff72519673ca72323c3d99ba5c11d7c7acc6e14b8c5da0c4663475c2e5c3adef46f73bcdec043"
|
||||
},
|
||||
"base64": {
|
||||
"encoded": "aGVsbG8=",
|
||||
"decoded": ""
|
||||
},
|
||||
"url": {
|
||||
"encoded": "hello",
|
||||
"decoded": "hello"
|
||||
},
|
||||
"gzip": {
|
||||
"encoded": "1f8b0800000000000003cb48cdc9c9070086a6103605000000",
|
||||
"decoded": ""
|
||||
},
|
||||
"deflate": {
|
||||
"encoded": "789ccb48cdc9c90700062c0215",
|
||||
"decoded": ""
|
||||
},
|
||||
"brotli": {
|
||||
"encoded": "0b028068656c6c6f03",
|
||||
"decoded": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
"code": 200,
|
||||
"message": "获取成功。数据来自官方/权威源头,以确保稳定与实时。开源地址 https://github.com/vikiboss/60s,反馈群 595941841",
|
||||
"data": {
|
||||
"source": "hello",
|
||||
"md5": "5d41402abc4b2a76b9719d911017c592",
|
||||
"sha": {
|
||||
"sha1": "aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d",
|
||||
"sha256": "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824",
|
||||
"sha512": "9b71d224bd62f3785d96d46ad3ea3d73319bfbc2890caadae2dff72519673ca72323c3d99ba5c11d7c7acc6e14b8c5da0c4663475c2e5c3adef46f73bcdec043"
|
||||
},
|
||||
"base64": {
|
||||
"encoded": "aGVsbG8=",
|
||||
"decoded": ""
|
||||
},
|
||||
"url": {
|
||||
"encoded": "hello",
|
||||
"decoded": "hello"
|
||||
},
|
||||
"gzip": {
|
||||
"encoded": "1f8b0800000000000003cb48cdc9c9070086a6103605000000",
|
||||
"decoded": ""
|
||||
},
|
||||
"deflate": {
|
||||
"encoded": "789ccb48cdc9c90700062c0215",
|
||||
"decoded": ""
|
||||
},
|
||||
"brotli": {
|
||||
"encoded": "0b028068656c6c6f03",
|
||||
"decoded": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
注意:实际API返回的字段名是 encoded/decoded,不是 encode/decode
|
||||
Reference in New Issue
Block a user