Browse Source

ChatSDK测试面板中实现接入代码生成与复制功能

master
wanghanlin 14 hours ago
parent
commit
3e9712f4ea
  1. 139
      src/main/resources/static/sdk/test.html

139
src/main/resources/static/sdk/test.html

@ -80,6 +80,10 @@ body{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Noto Sans S
.code-section .st{color:#059669} /* 字符串 */
.code-section .nu{color:#2563EB} /* 数字 */
.code-section .bl{color:#DC2626} /* 必传高亮 */
.code-tabs{display:flex;gap:4px}
.code-tab{padding:3px 10px;border:1px solid #E5E7EB;border-radius:4px;background:#fff;color:#6B7280;font-size:11px;cursor:pointer;transition:all .15s;font-family:inherit}
.code-tab--active{background:#4F46E5;color:#fff;border-color:#4F46E5}
.code-tab:hover:not(.code-tab--active){background:#F3F4F6}
</style>
</head>
<body>
@ -188,7 +192,13 @@ body{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Noto Sans S
<div class="code-section">
<div class="code-section__header">
<span class="code-section__title">📋 接入代码</span>
<button class="code-section__copy" id="btn-copy" onclick="copyCode()">📋 复制代码</button>
<div style="display:flex;gap:6px;align-items:center">
<div class="code-tabs">
<button class="code-tab code-tab--active" id="tab-snippet" onclick="switchCodeTab('snippet',this)">Script 片段</button>
<button class="code-tab" id="tab-fullpage" onclick="switchCodeTab('fullpage',this)">完整页面</button>
</div>
<button class="code-section__copy" id="btn-copy" onclick="copyCode()">📋 复制代码</button>
</div>
</div>
<div class="code-section__body">
<pre id="code-output"></pre>
@ -284,6 +294,125 @@ body{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Noto Sans S
function assert(c,m){if(!c)throw new Error(m);}
function assertExists(s,m){const el=document.getElementById(s)||document.querySelector(s);assert(!!el,m||s+' 不存在');return el;}
// ==================== 接入代码生成 ====================
// 当前代码展示 Tab:'snippet'(Script 片段)| 'fullpage'(完整 HTML 页面)
let codeTab = 'snippet';
// SDK 可选参数的默认值(与 config.ts parseConfig 严格对齐),用于判断是否需要在生成代码中输出
const SDK_DEFAULTS = {
title: 'AI 智能助手',
width: 380,
position: 'right-bottom',
primaryColor: '#4F46E5',
streaming: true,
locale: 'zh-CN',
showCategorySwitch: false,
};
// 生成 Script 片段代码(纯文本)
function buildCodeSnippet() {
const cfg = getCfg();
const domain = cfg.requestDomain;
// integrateId:纯数字输出为数字字面量,否则输出字符串
const iid = String(cfg.integrateId);
const iidLit = /^\d+$/.test(iid) ? iid : JSON.stringify(iid);
const params = [];
// 必传参数
params.push(' integrateId: ' + iidLit + ', // 必传:客服角色 ID(对应后端 roleId)');
params.push(' requestDomain: ' + JSON.stringify(domain) + ', // 必传:后端 API 域名');
// 可选参数:仅输出与默认值不同的项
if (cfg.userId) params.push(' userId: ' + JSON.stringify(cfg.userId) + ', // 可选:客户账号 ID(对应后端 accountId)');
if (cfg.title !== SDK_DEFAULTS.title) params.push(' title: ' + JSON.stringify(cfg.title) + ', // 弹窗标题');
if (cfg.primaryColor !== SDK_DEFAULTS.primaryColor) params.push(' primaryColor: ' + JSON.stringify(cfg.primaryColor) + ', // 主色调');
if (cfg.position !== SDK_DEFAULTS.position) params.push(' position: ' + JSON.stringify(cfg.position) + ', // 悬浮按钮位置');
if (cfg.width !== SDK_DEFAULTS.width) params.push(' width: ' + cfg.width + ', // 弹窗宽度(px)');
if (cfg.streaming !== SDK_DEFAULTS.streaming) params.push(' streaming: ' + cfg.streaming + ', // 是否启用流式输出');
if (cfg.locale !== SDK_DEFAULTS.locale) params.push(' locale: ' + JSON.stringify(cfg.locale) + ', // 界面语言');
if (cfg.showCategorySwitch !== SDK_DEFAULTS.showCategorySwitch) params.push(' showCategorySwitch: ' + cfg.showCategorySwitch + ', // 是否显示知识库切换');
// debug 强制 false(生产环境推荐),无论面板当前值
params.push(' debug: false // 调试日志,生产环境建议关闭');
const initBlock = 'ChatbotSDK.init({\n' + params.join('\n') + '\n});';
return '<!-- ChatbotSDK 智能客服 -->\n' +
'<script src="' + domain + '/sdk/chatbot-sdk.min.js"><\/script>\n' +
'<script>\n' + initBlock + '\n<\/script>';
}
// 生成完整 HTML 页面代码(纯文本)
function buildFullPage() {
const snippet = buildCodeSnippet();
const indented = snippet.split('\n').map(l => ' ' + l).join('\n');
return '<!DOCTYPE html>\n' +
'<html lang="zh-CN">\n' +
'<head>\n' +
' <meta charset="UTF-8">\n' +
' <meta name="viewport" content="width=device-width, initial-scale=1.0">\n' +
' <title>AI 智能助手</title>\n' +
'</head>\n' +
'<body>\n' + indented + '\n</body>\n' +
'</html>';
}
// 根据当前 Tab 返回纯文本代码
function getCurrentCode() {
return codeTab === 'fullpage' ? buildFullPage() : buildCodeSnippet();
}
// 语法高亮:先转义 HTML,再用单遍正则匹配 HTML 注释 / 字符串 / 行注释 / 数字 / 对象 key
function highlightCode(code) {
const esc = code.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
const re = /(&lt;!--[\s\S]*?--&gt;)|('[^']*'|"[^"]*")|(\/\/[^\n]*)|\b(\d+)\b|\b(integrateId|requestDomain|userId|categoryId|title|primaryColor|position|width|streaming|locale|showCategorySwitch|debug|showClear|showAdminPanel|launcherIcon)(?=\s*:)/g;
return esc.replace(re, (m, htmlCmt, str, cmt, num, key) => {
if (htmlCmt) return '<span class="cm">' + htmlCmt + '</span>';
if (str) return '<span class="st">' + str + '</span>';
if (cmt) return '<span class="cm">' + cmt + '</span>';
if (num) return '<span class="nu">' + num + '</span>';
if (key) return '<span class="kw">' + key + '</span>';
return m;
});
}
// 刷新代码预览区
function generateCode() {
const out = getEl('code-output');
if (out) out.innerHTML = highlightCode(getCurrentCode());
}
// 复制代码到剪贴板(带降级方案)
function fallbackCopy(text, cb) {
const ta = document.createElement('textarea');
ta.value = text; ta.style.position = 'fixed'; ta.style.opacity = '0';
document.body.appendChild(ta); ta.select();
try { document.execCommand('copy'); cb(); } catch (e) { /* 忽略 */ }
document.body.removeChild(ta);
}
window.copyCode = function() {
const code = getCurrentCode();
const btn = getEl('btn-copy');
const done = function() {
if (btn) {
btn.textContent = '✅ 已复制';
btn.classList.add('code-section__copy--ok');
setTimeout(function() {
btn.textContent = '📋 复制代码';
btn.classList.remove('code-section__copy--ok');
}, 1500);
}
};
if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard.writeText(code).then(done).catch(function() { fallbackCopy(code, done); });
} else {
fallbackCopy(code, done);
}
};
// 切换代码 Tab
window.switchCodeTab = function(tab, btn) {
codeTab = tab;
document.querySelectorAll('.code-tab').forEach(function(t) { t.classList.remove('code-tab--active'); });
if (btn) btn.classList.add('code-tab--active');
generateCode();
};
window.doInit=function(){ChatbotSDK.destroy();ChatbotSDK.init(getCfg());const tag=getEl('tag-sdk');if(document.getElementById('csk-launcher')){tag.className='tag tag--pass';tag.textContent='✅ SDK 就绪';}};
window.doDestroy=function(){ChatbotSDK.destroy();const tag=getEl('tag-sdk');tag.className='tag tag--idle';tag.textContent='⭕ SDK 未加载';};
window.doClearHistory=function(){ChatbotSDK.clearHistory();};
@ -379,6 +508,14 @@ body{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Noto Sans S
getEl('cfg-domain').value=window.location.origin;
setEl('footer-time',new Date().toLocaleTimeString());
if(typeof window.ChatbotSDK!=='undefined'){const tag=getEl('tag-sdk');tag.className='tag tag--pass';tag.textContent='✅ SDK 已加载';}
// 监听配置表单变化,实时刷新接入代码
['cfg-iid','cfg-domain','cfg-uid','cfg-title','cfg-color','cfg-pos','cfg-width','cfg-stream','cfg-locale','cfg-cat','cfg-debug'].forEach(function(id){
const el=getEl(id);
if(!el)return;
el.addEventListener('input', generateCode);
el.addEventListener('change', generateCode);
});
generateCode();
fetch(window.location.origin+'/ai/assistant_app/chat/sync?message=test&chatId=__probe__&roleId=1',{signal:AbortSignal.timeout(5000)}).then(r=>{const tag=getEl('tag-api');if(r.ok||r.status<500){tag.className='tag tag--pass';tag.textContent='✅ 后端连通';setEl('footer-info','ChatbotSDK v1.2.0 后端在线 ');}}).catch(()=>{const tag=getEl('tag-api');tag.className='tag tag--fail';tag.textContent='⚠ 后端离线';});
})();
})();

Loading…
Cancel
Save