Files
wechatAiclaw/public/swagger.html
2026-03-11 11:36:05 +08:00

244 lines
8.3 KiB
HTML

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<title>API 文档 (Swagger) - Wechat 智能托管</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="https://unpkg.com/swagger-ui-dist@5/swagger-ui.css" />
<style>
:root {
--bg: #f8f9fa;
--card: #ffffff;
--border: #e5e7eb;
--accent: #22c55e;
--text: #111827;
--muted: #6b7280;
}
* { box-sizing: border-box; }
body {
margin: 0;
min-height: 100vh;
background: var(--bg);
font-family: system-ui, -apple-system, sans-serif;
color: var(--text);
}
.swagger-config {
max-width: 1200px;
margin: 0 auto;
padding: 16px 24px;
border-bottom: 1px solid var(--border);
background: rgba(30, 41, 59, 0.6);
}
.config-grid {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 16px 24px;
}
.config-item {
display: flex;
align-items: center;
gap: 8px;
}
.config-item label {
font-size: 13px;
color: var(--muted);
white-space: nowrap;
}
.config-item input[type="text"] {
width: 280px;
padding: 8px 12px;
border: 1px solid var(--border);
border-radius: 8px;
background: rgba(15, 23, 42, 0.9);
color: var(--text);
font-size: 13px;
}
.config-item input[type="radio"] {
margin-right: 4px;
}
.config-item .radio-group {
display: flex;
gap: 12px;
}
.config-item .radio-group label {
display: flex;
align-items: center;
cursor: pointer;
}
.copy-base-wrap {
display: flex;
align-items: center;
gap: 8px;
}
.copy-base-wrap input[type="checkbox"] {
width: 18px;
height: 18px;
cursor: pointer;
}
.base-url-hint {
font-size: 12px;
color: var(--muted);
}
#swagger-ui {
max-width: 1200px;
margin: 0 auto;
padding: 20px 24px 40px;
background: #ffffff;
box-shadow: 0 10px 25px rgba(15, 23, 42, 0.12);
}
.btn-copy {
padding: 4px 10px;
margin-left: 8px;
font-size: 12px;
border-radius: 6px;
border: 1px solid var(--accent);
background: rgba(34, 197, 94, 0.15);
color: var(--accent);
cursor: pointer;
}
.btn-copy:hover { background: rgba(34, 197, 94, 0.25); }
</style>
</head>
<body>
<div id="swagger-ui"></div>
<script src="https://unpkg.com/swagger-ui-dist@5/swagger-ui-bundle.js"></script>
<script>
(function () {
var baseUrlInput = document.getElementById('base-url');
var keyInput = document.getElementById('key-param');
var openapiUrlEl = document.getElementById('openapi-url');
var copyBaseCheck = document.getElementById('copy-base-url');
function getOpenApiUrl() {
var base = (baseUrlInput && baseUrlInput.value.trim()) || '';
return base.replace(/\/$/, '') + '/openapi.json';
}
function applyBaseUrl() {
var url = getOpenApiUrl();
if (openapiUrlEl) openapiUrlEl.textContent = url;
return url;
}
baseUrlInput && baseUrlInput.addEventListener('change', applyBaseUrl);
baseUrlInput && baseUrlInput.addEventListener('input', applyBaseUrl);
var apiUrl = applyBaseUrl();
window.xxcaibi = {
BASE_URL: (baseUrlInput && baseUrlInput.value.trim()) || '',
copy: true,
KEY: ''
};
copyBaseCheck && copyBaseCheck.addEventListener('change', function () {
window.xxcaibi.copy = copyBaseCheck.checked;
});
keyInput && keyInput.addEventListener('input', function () {
window.xxcaibi.KEY = keyInput.value.trim();
});
function copyText(text) {
if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard.writeText(text).catch(function () {
fallbackCopy(text);
});
} else {
fallbackCopy(text);
}
}
function fallbackCopy(text) {
var ta = document.createElement('textarea');
ta.value = text;
document.body.appendChild(ta);
ta.select();
try { document.execCommand('copy'); } catch (e) {}
document.body.removeChild(ta);
}
window.ui = SwaggerUIBundle({
url: apiUrl,
dom_id: '#swagger-ui',
deepLinking: true,
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIBundle.SwaggerUIStandalonePreset
],
layout: 'BaseLayout',
docExpansion: 'none',
onComplete: function () {
applyBaseUrl();
var config = window.ui.specSelectors.specJson();
if (config && config.toJS) {
var spec = config.toJS();
window.xxcaibi.BASE_URL = (baseUrlInput && baseUrlInput.value.trim()) || (spec.servers && spec.servers[0] && spec.servers[0].url) || '';
}
function addCopyButtons() {
document.querySelectorAll('.opblock-summary-path').forEach(function (pathEl) {
if (pathEl.getAttribute('data-copy-done')) return;
var pathSpan = pathEl.querySelector('[data-path]');
var path = pathSpan ? pathSpan.getAttribute('data-path') : (pathEl.textContent || '').trim().replace(/\s+/g, '');
if (!path) return;
var parent = pathEl.closest('.opblock-summary');
var methodEl = parent ? parent.querySelector('.opblock-summary-method') : null;
var method = methodEl ? methodEl.textContent.trim() : '';
var btn = document.createElement('button');
btn.type = 'button';
btn.className = 'btn-copy';
btn.textContent = '复制';
btn.addEventListener('click', function (e) {
e.preventDefault();
e.stopPropagation();
var base = (window.xxcaibi && window.xxcaibi.copy && window.xxcaibi.BASE_URL) ? window.xxcaibi.BASE_URL.replace(/\/$/, '') : '';
var text = base ? base + path : method + ' ' + path;
copyText(text);
btn.textContent = '已复制';
setTimeout(function () { btn.textContent = '复制'; }, 600);
});
pathEl.appendChild(btn);
pathEl.setAttribute('data-copy-done', '1');
});
}
addCopyButtons();
var observer = new MutationObserver(function () { addCopyButtons(); });
var swaggerEl = document.getElementById('swagger-ui');
if (swaggerEl) observer.observe(swaggerEl, { childList: true, subtree: true });
}
});
document.querySelectorAll('input[name="doc-expansion"]').forEach(function (radio) {
radio.addEventListener('change', function () {
if (window.ui && window.ui.getConfigs) {
var c = window.ui.getConfigs();
c.docExpansion = this.value;
window.ui.configsActions && window.ui.configsActions.toggle && window.ui.configsActions.toggle();
}
});
});
keyInput && keyInput.addEventListener('change', function () {
var key = keyInput.value.trim();
if (!window.ui || !window.ui.specActions) return;
try {
var spec = window.ui.specSelectors.specJson().toJS();
var paths = spec.paths || {};
Object.keys(paths).forEach(function (pathKey) {
Object.keys(paths[pathKey]).forEach(function (method) {
var op = paths[pathKey][method];
if (op.parameters && Array.isArray(op.parameters)) {
op.parameters.forEach(function (p) {
if (p.name === 'key' && p.in === 'query') p.default = key;
});
}
});
});
window.ui.specActions.updateSpec(JSON.stringify(spec));
} catch (e) {}
});
})();
</script>
</body>
</html>