新增快手平台和对应的接口
This commit is contained in:
355
controller/debug/admin_controller.go
Normal file
355
controller/debug/admin_controller.go
Normal file
@@ -0,0 +1,355 @@
|
||||
package debug
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/net/ghttp"
|
||||
)
|
||||
|
||||
var DebugController = new(debugCtrl)
|
||||
|
||||
type debugCtrl struct{}
|
||||
|
||||
// DebugPage 调试页面
|
||||
func (c *debugCtrl) DebugPage(r *ghttp.Request) {
|
||||
r.Response.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||
r.Response.Write(adminHTML)
|
||||
r.Exit()
|
||||
}
|
||||
|
||||
var adminHTML = `<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>数据引擎管理后台</title>
|
||||
<style>
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; background: #f0f2f5; color: #333; }
|
||||
.header { background: #001529; color: #fff; padding: 14px 24px; display: flex; align-items: center; gap: 12px; }
|
||||
.header h1 { font-size: 18px; font-weight: 600; }
|
||||
.container { max-width: 1400px; margin: 0 auto; padding: 20px; }
|
||||
.tabs { display: flex; gap: 0; margin-bottom: 20px; background: #fff; border-radius: 8px; overflow: hidden; box-shadow: 0 1px 4px rgba(0,0,0,0.06); }
|
||||
.tab { padding: 12px 28px; cursor: pointer; font-size: 14px; color: #666; border-bottom: 2px solid transparent; transition: all .2s; }
|
||||
.tab:hover { color: #1890ff; }
|
||||
.tab.active { color: #1890ff; border-bottom-color: #1890ff; font-weight: 600; }
|
||||
.panel { display: none; }
|
||||
.panel.active { display: block; }
|
||||
.toolbar { display: flex; justify-content: space-between; align-items: center; margin-bottom: 16px; }
|
||||
.toolbar h2 { font-size: 16px; color: #1a1a2e; }
|
||||
.btn { display: inline-flex; align-items: center; gap: 4px; padding: 8px 16px; border: none; border-radius: 6px; font-size: 13px; cursor: pointer; transition: all .2s; }
|
||||
.btn-primary { background: #1890ff; color: #fff; }
|
||||
.btn-primary:hover { background: #40a9ff; }
|
||||
.btn-danger { background: #ff4d4f; color: #fff; }
|
||||
.btn-danger:hover { background: #ff7875; }
|
||||
.btn-sm { padding: 4px 10px; font-size: 12px; }
|
||||
.btn-outline { background: #fff; border: 1px solid #d9d9d9; color: #333; }
|
||||
.btn-outline:hover { border-color: #1890ff; color: #1890ff; }
|
||||
.btn-success { background: #52c41a; color: #fff; }
|
||||
.btn-success:hover { background: #73d13d; }
|
||||
table { width: 100%; background: #fff; border-radius: 8px; overflow: hidden; box-shadow: 0 1px 4px rgba(0,0,0,0.06); border-collapse: collapse; }
|
||||
th { background: #fafafa; padding: 12px 16px; text-align: left; font-size: 13px; color: #666; font-weight: 600; border-bottom: 1px solid #f0f0f0; }
|
||||
td { padding: 12px 16px; font-size: 13px; border-bottom: 1px solid #f0f0f0; }
|
||||
tr:hover td { background: #fafafa; }
|
||||
.badge { display: inline-block; padding: 2px 8px; border-radius: 10px; font-size: 11px; font-weight: 500; }
|
||||
.badge.active { background: #f6ffed; color: #52c41a; border: 1px solid #b7eb8f; }
|
||||
.badge.inactive { background: #fff2f0; color: #ff4d4f; border: 1px solid #ffccc7; }
|
||||
.actions { display: flex; gap: 6px; }
|
||||
.modal-overlay { display: none; position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0,0,0,0.45); z-index: 1000; }
|
||||
.modal-overlay.open { display: block; }
|
||||
.modal { display: none; position: fixed; top: 50%; left: 50%; transform: translate(-50%,-50%); background: #fff; border-radius: 8px; width: 600px; max-width: 90%; max-height: 85vh; overflow-y: auto; z-index: 1001; box-shadow: 0 4px 24px rgba(0,0,0,0.15); }
|
||||
.modal.open { display: block; }
|
||||
.modal-header { padding: 16px 20px; border-bottom: 1px solid #f0f0f0; display: flex; justify-content: space-between; align-items: center; }
|
||||
.modal-header h3 { font-size: 16px; }
|
||||
.modal-close { background: none; border: none; font-size: 20px; cursor: pointer; color: #999; }
|
||||
.modal-body { padding: 20px; }
|
||||
.modal-footer { padding: 12px 20px; border-top: 1px solid #f0f0f0; display: flex; justify-content: flex-end; gap: 8px; }
|
||||
.form-group { margin-bottom: 14px; }
|
||||
.form-group label { display: block; font-size: 13px; color: #666; margin-bottom: 4px; font-weight: 500; }
|
||||
.form-group input, .form-group select, .form-group textarea { width: 100%; padding: 8px 12px; border: 1px solid #d9d9d9; border-radius: 6px; font-size: 13px; outline: none; transition: border .2s; }
|
||||
.form-group input:focus, .form-group select:focus { border-color: #1890ff; box-shadow: 0 0 0 2px rgba(24,144,255,0.1); }
|
||||
.form-group textarea { font-family: "Fira Code", "Consolas", monospace; font-size: 12px; min-height: 80px; resize: vertical; }
|
||||
.form-row { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
|
||||
.loading { text-align: center; padding: 40px; color: #999; }
|
||||
.empty { text-align: center; padding: 32px; color: #999; font-size: 14px; }
|
||||
.interfaces-section { margin-top: 8px; }
|
||||
.sub-table { background: #fafafa; border-radius: 6px; overflow: hidden; margin-bottom: 8px; box-shadow: none; }
|
||||
.sub-table th { background: #f0f0f0; font-size: 12px; padding: 8px 12px; }
|
||||
.sub-table td { padding: 8px 12px; font-size: 12px; }
|
||||
.json-preview { max-width: 200px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; cursor: pointer; color: #1890ff; }
|
||||
.json-preview:hover { text-decoration: underline; }
|
||||
.platform-row { cursor: pointer; }
|
||||
.platform-row td:first-child { position: relative; }
|
||||
.expand-icon { margin-right: 8px; font-size: 10px; color: #999; transition: transform .2s; display: inline-block; }
|
||||
.expand-icon.open { transform: rotate(90deg); }
|
||||
.interface-detail { display: none; }
|
||||
.interface-detail.open { display: table-row; }
|
||||
.interface-detail td { padding: 0; }
|
||||
.interface-detail-inner { padding: 12px 16px 12px 44px; background: #fafafa; }
|
||||
.toast { position: fixed; top: 20px; right: 20px; padding: 12px 20px; border-radius: 6px; color: #fff; font-size: 13px; z-index: 2000; animation: slideIn .3s; }
|
||||
.toast.success { background: #52c41a; }
|
||||
.toast.error { background: #ff4d4f; }
|
||||
@keyframes slideIn { from { transform: translateX(100%); opacity: 0; } to { transform: translateX(0); opacity: 1; } }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="header"><h1>📊 数据引擎管理后台</h1></div>
|
||||
<div class="container">
|
||||
<div class="tabs">
|
||||
<div class="tab active" onclick="switchTab('platforms')">平台管理</div>
|
||||
<div class="tab" onclick="switchTab('interfaces')">接口管理</div>
|
||||
</div>
|
||||
|
||||
<div id="platforms-panel" class="panel active">
|
||||
<div class="toolbar"><h2>平台列表</h2><button class="btn btn-primary" onclick="openPlatformModal()">+ 新建平台</button></div>
|
||||
<div id="platform-loading" class="loading">加载中...</div>
|
||||
<div id="platform-list"></div>
|
||||
</div>
|
||||
|
||||
<div id="interfaces-panel" class="panel">
|
||||
<div class="toolbar"><h2>接口列表</h2><button class="btn btn-primary" onclick="openInterfaceModal()">+ 新建接口</button></div>
|
||||
<div id="interface-loading" class="loading">加载中...</div>
|
||||
<div id="interface-list"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal-overlay" id="modalOverlay" onclick="closeModal()"></div>
|
||||
<div class="modal" id="modal">
|
||||
<div class="modal-header"><h3 id="modalTitle"></h3><button class="modal-close" onclick="closeModal()">×</button></div>
|
||||
<div class="modal-body" id="modalBody"></div>
|
||||
<div class="modal-footer" id="modalFooter"></div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const BASE = '';
|
||||
|
||||
function toast(msg, type) {
|
||||
const t = document.createElement('div');
|
||||
t.className = 'toast ' + type;
|
||||
t.textContent = msg;
|
||||
document.body.appendChild(t);
|
||||
setTimeout(() => t.remove(), 2500);
|
||||
}
|
||||
|
||||
async function api(method, url, body) {
|
||||
const opt = { method, headers: {} };
|
||||
if (body) { opt.headers['Content-Type'] = 'application/json'; opt.body = JSON.stringify(body); }
|
||||
const resp = await fetch(BASE + url, opt);
|
||||
if (!resp.ok) { const t = await resp.text(); throw new Error(t || resp.statusText); }
|
||||
const json = await resp.json();
|
||||
// 解包 GoFrame 标准响应: {"code":0,"message":"success","data":{...}}
|
||||
if (json.code !== undefined && json.data !== undefined) {
|
||||
if (json.code !== 0) { throw new Error(json.message || '请求失败'); }
|
||||
return json.data;
|
||||
}
|
||||
return json;
|
||||
}
|
||||
|
||||
const P = { platform: '/datasource/platform/controller', iface: '/api/interface/controller' };
|
||||
|
||||
function switchTab(name) {
|
||||
document.querySelectorAll('.tab').forEach(t => t.classList.remove('active'));
|
||||
document.querySelectorAll('.panel').forEach(p => p.classList.remove('active'));
|
||||
document.querySelector('.tab[onclick*="' + name + '"]').classList.add('active');
|
||||
document.getElementById(name + '-panel').classList.add('active');
|
||||
if (name === 'platforms') loadPlatforms();
|
||||
else loadInterfaces();
|
||||
}
|
||||
|
||||
// ========== 平台管理 ==========
|
||||
async function loadPlatforms() {
|
||||
document.getElementById('platform-loading').style.display = 'block';
|
||||
try {
|
||||
const data = await api('GET', P.platform + '/listDatasourcePlatforms?page=1&pageSize=100');
|
||||
document.getElementById('platform-loading').style.display = 'none';
|
||||
if (!data.list || data.list.length === 0) {
|
||||
document.getElementById('platform-list').innerHTML = '<div class="empty">暂无平台,点击"新建平台"添加</div>';
|
||||
return;
|
||||
}
|
||||
let html = '<table><thead><tr><th style="width:30px"></th><th>编码</th><th>名称</th><th>API地址</th><th>认证</th><th>状态</th><th>操作</th></tr></thead><tbody>';
|
||||
for (const p of data.list) {
|
||||
const sc = p.status === 'ACTIVE' ? 'active' : 'inactive';
|
||||
html += '<tr class="platform-row" onclick="togglePlatform(' + p.id + ')">' +
|
||||
'<td><span class="expand-icon" id="expand-' + p.id + '">▶</span></td>' +
|
||||
'<td><strong>' + esc(p.platformCode) + '</strong></td>' +
|
||||
'<td>' + esc(p.platformName) + '</td>' +
|
||||
'<td style="font-size:12px;color:#666">' + esc(p.apiBaseUrl || '-') + '</td>' +
|
||||
'<td>' + esc(p.authType || '-') + '</td>' +
|
||||
'<td><span class="badge ' + sc + '">' + p.status + '</span></td>' +
|
||||
'<td class="actions" onclick="event.stopPropagation()">' +
|
||||
'<button class="btn btn-sm btn-outline" onclick="openPlatformModal(' + p.id + ')">编辑</button>' +
|
||||
'<button class="btn btn-sm btn-danger" onclick="deletePlatform(' + p.id + ')">删除</button></td></tr>' +
|
||||
'<tr class="interface-detail" id="ifaces-' + p.id + '"><td colspan="7"><div class="interface-detail-inner" id="ifaces-content-' + p.id + '">点击展开...</div></td></tr>';
|
||||
}
|
||||
html += '</tbody></table>';
|
||||
document.getElementById('platform-list').innerHTML = html;
|
||||
} catch (e) { document.getElementById('platform-loading').style.display = 'none'; toast(e.message, 'error'); }
|
||||
}
|
||||
|
||||
async function togglePlatform(id) {
|
||||
const row = document.getElementById('ifaces-' + id);
|
||||
const icon = document.getElementById('expand-' + id);
|
||||
row.classList.toggle('open');
|
||||
icon.classList.toggle('open');
|
||||
if (row.classList.contains('open') && document.getElementById('ifaces-content-' + id).textContent === '点击展开...') {
|
||||
try {
|
||||
const data = await api('GET', P.iface + '/listApiInterfaces?platformId=' + id + '&page=1&pageSize=100');
|
||||
const content = document.getElementById('ifaces-content-' + id);
|
||||
if (!data.list || data.list.length === 0) { content.innerHTML = '<div class="empty" style="padding:8px">暂无接口</div>'; return; }
|
||||
let h = '<table class="sub-table"><thead><tr><th>编码</th><th>名称</th><th>URL</th><th>方法</th><th>状态</th><th>请求配置</th><th>响应配置</th><th>操作</th></tr></thead><tbody>';
|
||||
for (const fi of data.list) {
|
||||
h += '<tr><td>' + esc(fi.code) + '</td><td>' + esc(fi.name) + '</td><td style="font-size:11px">' + esc(fi.url) + '</td>' +
|
||||
'<td><span class="badge ' + (fi.method === 'GET' ? 'active' : '') + '">' + fi.method + '</span></td>' +
|
||||
'<td><span class="badge ' + (fi.status === 'active' ? 'active' : 'inactive') + '">' + fi.status + '</span></td>' +
|
||||
'<td class="json-preview" title="' + esc(JSON.stringify(fi.requestConfig||{})) + '">' + esc(JSON.stringify(fi.requestConfig||{}).substring(0,25)) + '</td>' +
|
||||
'<td class="json-preview" title="' + esc(JSON.stringify(fi.responseConfig||{})) + '">' + esc(JSON.stringify(fi.responseConfig||{}).substring(0,25)) + '</td>' +
|
||||
'<td class="actions"><button class="btn btn-sm btn-outline" onclick="event.stopPropagation();openInterfaceModal(' + fi.id + ')">编辑</button>' +
|
||||
'<button class="btn btn-sm btn-danger" onclick="event.stopPropagation();deleteInterface(' + fi.id + ')">删</button></td></tr>';
|
||||
}
|
||||
h += '</tbody></table>';
|
||||
content.innerHTML = h;
|
||||
} catch (e) { document.getElementById('ifaces-content-' + id).textContent = '加载失败'; }
|
||||
}
|
||||
}
|
||||
|
||||
async function deletePlatform(id) {
|
||||
if (!confirm('确定删除此平台?')) return;
|
||||
try { await api('DELETE', P.platform + '/deleteDatasourcePlatform?id=' + id); toast('删除成功', 'success'); loadPlatforms(); }
|
||||
catch (e) { toast(e.message, 'error'); }
|
||||
}
|
||||
|
||||
// ========== 接口管理 ==========
|
||||
async function loadInterfaces() {
|
||||
document.getElementById('interface-loading').style.display = 'block';
|
||||
try {
|
||||
const data = await api('GET', P.iface + '/listApiInterfaces?page=1&pageSize=100');
|
||||
document.getElementById('interface-loading').style.display = 'none';
|
||||
if (!data.list || data.list.length === 0) {
|
||||
document.getElementById('interface-list').innerHTML = '<div class="empty">暂无接口,点击"新建接口"添加</div>';
|
||||
return;
|
||||
}
|
||||
let html = '<table><thead><tr><th>编码</th><th>名称</th><th>URL</th><th>方法</th><th>状态</th><th>平台</th><th>请求配置</th><th>响应配置</th><th>操作</th></tr></thead><tbody>';
|
||||
for (const fi of data.list) {
|
||||
html += '<tr><td><strong>' + esc(fi.code) + '</strong></td><td>' + esc(fi.name) + '</td>' +
|
||||
'<td style="font-size:12px;color:#666">' + esc(fi.url) + '</td>' +
|
||||
'<td><span class="badge ' + (fi.method === 'GET' ? 'active' : '') + '">' + fi.method + '</span></td>' +
|
||||
'<td><span class="badge ' + (fi.status === 'active' ? 'active' : 'inactive') + '">' + fi.status + '</span></td>' +
|
||||
'<td>' + esc(fi.platformName || '-') + '</td>' +
|
||||
'<td class="json-preview" title="' + esc(JSON.stringify(fi.requestConfig||{})) + '">' + esc(JSON.stringify(fi.requestConfig||{}).substring(0,30)) + '</td>' +
|
||||
'<td class="json-preview" title="' + esc(JSON.stringify(fi.responseConfig||{})) + '">' + esc(JSON.stringify(fi.responseConfig||{}).substring(0,30)) + '</td>' +
|
||||
'<td class="actions"><button class="btn btn-sm btn-outline" onclick="openInterfaceModal(' + fi.id + ')">编辑</button>' +
|
||||
'<button class="btn btn-sm btn-danger" onclick="deleteInterface(' + fi.id + ')">删除</button></td></tr>';
|
||||
}
|
||||
html += '</tbody></table>';
|
||||
document.getElementById('interface-list').innerHTML = html;
|
||||
} catch (e) { document.getElementById('interface-loading').style.display = 'none'; toast(e.message, 'error'); }
|
||||
}
|
||||
|
||||
async function deleteInterface(id) {
|
||||
if (!confirm('确定删除此接口?')) return;
|
||||
try { await api('DELETE', P.iface + '/deleteApiInterface?id=' + id); toast('删除成功', 'success'); loadInterfaces(); loadPlatforms(); }
|
||||
catch (e) { toast(e.message, 'error'); }
|
||||
}
|
||||
|
||||
// ========== 平台表单 ==========
|
||||
async function openPlatformModal(id) {
|
||||
const title = document.getElementById('modalTitle');
|
||||
const body = document.getElementById('modalBody');
|
||||
const footer = document.getElementById('modalFooter');
|
||||
if (id) {
|
||||
const data = await api('GET', P.platform + '/getDatasourcePlatform?id=' + id);
|
||||
title.textContent = '编辑平台';
|
||||
body.innerHTML = pfHTML(data);
|
||||
footer.innerHTML = '<button class="btn btn-outline" onclick="closeModal()">取消</button><button class="btn btn-primary" onclick="saveP(' + id + ')">保存</button>';
|
||||
} else {
|
||||
title.textContent = '新建平台';
|
||||
body.innerHTML = pfHTML(null);
|
||||
footer.innerHTML = '<button class="btn btn-outline" onclick="closeModal()">取消</button><button class="btn btn-primary" onclick="saveP(0)">创建</button>';
|
||||
}
|
||||
document.getElementById('modalOverlay').classList.add('open');
|
||||
document.getElementById('modal').classList.add('open');
|
||||
}
|
||||
function pfHTML(d) {
|
||||
d = d || {};
|
||||
const authCfg = d.authConfig ? JSON.stringify(d.authConfig, null, 2) : '{}';
|
||||
return '<div class="form-row"><div class="form-group"><label>编码 *</label><input id="f-pcode" value="' + esc(d.platformCode||'') + '"></div>' +
|
||||
'<div class="form-group"><label>名称 *</label><input id="f-pname" value="' + esc(d.platformName||'') + '"></div></div>' +
|
||||
'<div class="form-group"><label>API地址</label><input id="f-apiurl" value="' + esc(d.apiBaseUrl||'') + '"></div>' +
|
||||
'<div class="form-row"><div class="form-group"><label>认证类型 *</label><select id="f-auth"><option value="OAUTH2"' + (d.authType==='OAUTH2'?' selected':'') + '>OAuth2</option><option value="TOKEN"' + (d.authType==='TOKEN'?' selected':'') + '>Token</option><option value="API_KEY"' + (d.authType==='API_KEY'?' selected':'') + '>API Key</option><option value="SIGN"' + (d.authType==='SIGN'?' selected':'') + '>签名</option></select></div>' +
|
||||
'<div class="form-group"><label>状态</label><select id="f-ps"><option value="ACTIVE"' + ((d.status||'ACTIVE')==='ACTIVE'?' selected':'') + '>启用</option><option value="INACTIVE"' + (d.status==='INACTIVE'?' selected':'') + '>停用</option></select></div></div>' +
|
||||
'<div class="form-group"><label>Token / access_token</label><input id="f-tk" value="' + esc(d.token||'') + '"></div>' +
|
||||
'<div class="form-row"><div class="form-group"><label>Client ID</label><input id="f-cid" value="' + esc(d.clientId||'') + '"></div>' +
|
||||
'<div class="form-group"><label>Client Secret</label><input id="f-cs" value="' + esc(d.clientSecret||'') + '"></div></div>' +
|
||||
'<div class="form-group"><label>认证配置 JSON</label><textarea id="f-ac" rows="4">' + esc(authCfg) + '</textarea></div>' +
|
||||
'<div class="form-row"><div class="form-group"><label>限流/分钟</label><input id="f-rpm" type="number" value="' + (d.rateLimitPerMinute||60) + '"></div>' +
|
||||
'<div class="form-group"><label>超时(ms)</label><input id="f-to" type="number" value="' + (d.requestTimeoutMs||30000) + '"></div></div>';
|
||||
}
|
||||
async function saveP(id) {
|
||||
const now = Date.now().toString();
|
||||
const body = {
|
||||
platformCode: v('f-pcode'), platformName: v('f-pname'), apiBaseUrl: v('f-apiurl'),
|
||||
authType: v('f-auth'), status: v('f-ps'), token: v('f-tk'),
|
||||
clientId: v('f-cid'), clientSecret: v('f-cs'),
|
||||
rateLimitPerMinute: parseInt(v('f-rpm'))||60, requestTimeoutMs: parseInt(v('f-to'))||30000,
|
||||
createdBy: 'admin', createdAt: now, updatedBy: 'admin', updatedAt: now, version: '0',
|
||||
};
|
||||
try { body.authConfig = JSON.parse(v('f-ac')); } catch(e) { toast('auth_config JSON 格式错误', 'error'); return; }
|
||||
try {
|
||||
if (id) { await api('PUT', P.platform + '/updateDatasourcePlatform', { ...body, id }); toast('更新成功', 'success'); }
|
||||
else { await api('POST', P.platform + '/createDatasourcePlatform', body); toast('创建成功', 'success'); }
|
||||
closeModal(); loadPlatforms();
|
||||
} catch(e) { toast(e.message, 'error'); }
|
||||
}
|
||||
|
||||
// ========== 接口表单 ==========
|
||||
async function openInterfaceModal(id) {
|
||||
const pl = await api('GET', P.platform + '/listDatasourcePlatforms?page=1&pageSize=100');
|
||||
const opts = (pl.list||[]).map(p => '<option value="' + p.id + '">' + esc(p.platformName) + '</option>').join('');
|
||||
const title = document.getElementById('modalTitle');
|
||||
const body = document.getElementById('modalBody');
|
||||
const footer = document.getElementById('modalFooter');
|
||||
if (id) {
|
||||
const data = await api('GET', P.iface + '/getApiInterface?id=' + id);
|
||||
title.textContent = '编辑接口';
|
||||
body.innerHTML = iFormHTML(data, opts);
|
||||
footer.innerHTML = '<button class="btn btn-outline" onclick="closeModal()">取消</button><button class="btn btn-primary" onclick="saveI(' + id + ')">保存</button>';
|
||||
} else {
|
||||
title.textContent = '新建接口';
|
||||
body.innerHTML = iFormHTML(null, opts);
|
||||
footer.innerHTML = '<button class="btn btn-outline" onclick="closeModal()">取消</button><button class="btn btn-primary" onclick="saveI(0)">创建</button>';
|
||||
}
|
||||
document.getElementById('modalOverlay').classList.add('open');
|
||||
document.getElementById('modal').classList.add('open');
|
||||
}
|
||||
function iFormHTML(d, opts) {
|
||||
d = d || {};
|
||||
const sel = opts.replace('value="' + (d.platformId||'') + '"', 'value="' + (d.platformId||'') + '" selected');
|
||||
return '<div class="form-group"><label>所属平台</label><select id="f-pid">' + sel + '</select></div>' +
|
||||
'<div class="form-row"><div class="form-group"><label>编码 *</label><input id="f-ic" value="' + esc(d.code||'') + '"></div>' +
|
||||
'<div class="form-group"><label>名称 *</label><input id="f-in" value="' + esc(d.name||'') + '"></div></div>' +
|
||||
'<div class="form-row"><div class="form-group"><label>URL *</label><input id="f-iu" value="' + esc(d.url||'') + '"></div>' +
|
||||
'<div class="form-group"><label>方法 *</label><select id="f-im"><option value="GET"' + ((d.method||'GET')==='GET'?' selected':'') + '>GET</option><option value="POST"' + (d.method==='POST'?' selected':'') + '>POST</option></select></div></div>' +
|
||||
'<div class="form-group"><label>请求配置 JSON</label><textarea id="f-rqc" rows="6">' + esc(d.requestConfig ? JSON.stringify(d.requestConfig, null, 2) : '{}') + '</textarea></div>' +
|
||||
'<div class="form-group"><label>响应配置 JSON</label><textarea id="f-rsc" rows="4">' + esc(d.responseConfig ? JSON.stringify(d.responseConfig, null, 2) : '{}') + '</textarea></div>' +
|
||||
'<div class="form-group"><label>表结构定义 JSON</label><textarea id="f-td" rows="6">' + esc(d.tableDefinition ? JSON.stringify(d.tableDefinition, null, 2) : '{}') + '</textarea></div>';
|
||||
}
|
||||
async function saveI(id) {
|
||||
let rqc, rsc, td;
|
||||
try { rqc = JSON.parse(v('f-rqc')); } catch(e) { toast('请求配置 JSON 错误', 'error'); return; }
|
||||
try { rsc = JSON.parse(v('f-rsc')); } catch(e) { toast('响应配置 JSON 错误', 'error'); return; }
|
||||
try { td = JSON.parse(v('f-td')); } catch(e) { toast('表结构定义 JSON 错误', 'error'); return; }
|
||||
const body = { platformId: parseInt(v('f-pid')), code: v('f-ic'), name: v('f-in'), url: v('f-iu'),
|
||||
method: v('f-im'), requestConfig: rqc, responseConfig: rsc, tableDefinition: td };
|
||||
try {
|
||||
if (id) { await api('PUT', P.iface + '/updateApiInterface', { ...body, id }); toast('更新成功', 'success'); }
|
||||
else { await api('POST', P.iface + '/createApiInterface', body); toast('创建成功', 'success'); }
|
||||
closeModal(); loadInterfaces(); loadPlatforms();
|
||||
} catch(e) { toast(e.message, 'error'); }
|
||||
}
|
||||
|
||||
function closeModal() { document.getElementById('modalOverlay').classList.remove('open'); document.getElementById('modal').classList.remove('open'); }
|
||||
function v(id) { return document.getElementById(id).value; }
|
||||
function esc(s) { if (!s && s!==0) return ''; const d = document.createElement('div'); d.textContent = s; return d.innerHTML; }
|
||||
|
||||
loadPlatforms();
|
||||
</script>
|
||||
</body>
|
||||
</html>`
|
||||
Reference in New Issue
Block a user