(function(){
if (window.__SUBAI_KF_LOADED__) return;
window.__SUBAI_KF_LOADED__ = true;
var script = document.currentScript || (function(){var s=document.getElementsByTagName('script');return s[s.length-1];})();
var src = script && script.src ? new URL(script.src, window.location.href) : null;
var server = window.KF_SERVER || (src ? src.origin : window.location.origin);
var apiKey = window.KF_API_KEY || (script && script.getAttribute('data-api-key')) || '';
var bizId = window.KF_BIZ_ID || (script && script.getAttribute('data-biz-id')) || '';
var sessionId = 'kf_' + Date.now().toString(36) + '_' + Math.random().toString(36).slice(2,8);
var state = {open:false, sending:false, name:'', phone:'', avatarUrl:'', position:'bottom-right'};
function cssEscape(v){ return String(v == null ? '' : v); }
function make(tag, cls){ var node=document.createElement(tag); if(cls) node.className=cls; return node; }
function setText(node, text){ node.textContent = text == null ? '' : String(text); }
function now(){ return new Date().toLocaleTimeString('zh-CN',{hour:'2-digit',minute:'2-digit'}); }
var host = document.createElement('div');
host.id = 'subai-kf-root';
document.body.appendChild(host);
var root = host.attachShadow ? host.attachShadow({mode:'open'}) : host;
root.innerHTML = ''+
''+
'';
var bubble = root.querySelector('.bubble');
var panel = root.querySelector('.panel');
var messages = root.querySelector('.messages');
var input = root.querySelector('textarea');
var sendBtn = root.querySelector('.send');
var quick = root.querySelector('.quick');
var nameInput = root.querySelector('.name');
var phoneInput = root.querySelector('.phone');
var referrerInput = root.querySelector('.referrer');
function applyPosition(pos){
state.position = pos || 'bottom-right';
var left = state.position === 'bottom-left';
bubble.classList.toggle('left', left);
panel.classList.toggle('left', left);
}
function addMessage(role, text, meta){
var row = make('div','msg '+role);
if(role === 'bot'){
var avatar = make('div','avatar');
if(state.avatarUrl){ var im=document.createElement('img'); im.src=state.avatarUrl; im.alt=''; avatar.appendChild(im); } else avatar.textContent='AI';
row.appendChild(avatar);
}
var body = make('div','bubbleText'); setText(body,text);
var stamp = make('span','time'); stamp.textContent = now() + (meta ? ' · '+meta : ''); body.appendChild(stamp);
if(role === 'bot' && meta === '需要登录'){
var actions = make('div','actions'); actions.innerHTML='登录注册'; body.appendChild(actions);
}
row.appendChild(body); messages.appendChild(row); messages.scrollTop = messages.scrollHeight;
}
function setBranding(b){
if(!b || b.error) return;
root.host.style.setProperty('--p', b.primary_color || '#6366f1');
root.host.style.setProperty('--a', b.accent_color || '#8b5cf6');
root.querySelector('.title strong').textContent = b.name || 'AI 客服';
state.avatarUrl = b.avatar_url || b.logo_url || '';
var logo = root.querySelector('.logo'); logo.innerHTML='';
if(b.logo_url){ var img=document.createElement('img'); img.src=b.logo_url; img.alt=''; logo.appendChild(img); bubble.innerHTML=''; var bimg=document.createElement('img'); bimg.src=b.logo_url; bimg.alt=''; bubble.appendChild(bimg); }
else { logo.textContent=(b.name || 'AI').slice(0,2); bubble.innerHTML='AI'; }
applyPosition(b.widget_position || 'bottom-right');
messages.innerHTML=''; addMessage('bot', b.welcome_msg || '您好!有什么可以帮您的?');
}
function openPanel(force){ state.open = force == null ? !state.open : !!force; panel.classList.toggle('open', state.open); if(state.open) setTimeout(function(){input.focus();}, 30); }
async function loadBranding(){
messages.innerHTML=''; addMessage('bot','您好!有什么可以帮您的?'); applyPosition(window.KF_POSITION || 'bottom-right');
if(!apiKey) return;
try{ var r=await fetch(server+'/api/branding?api_key='+encodeURIComponent(apiKey)); if(r.ok) setBranding(await r.json()); }catch(e){}
}
async function send(text){
var q = (text || input.value).trim(); if(!q || state.sending) return;
input.value=''; addMessage('user', q); var typing=make('div','typing'); typing.textContent='AI 正在输入...'; messages.appendChild(typing); messages.scrollTop=messages.scrollHeight;
state.sending=true; sendBtn.disabled=true;
try{
var body = {message:q, session_id:sessionId, api_key:apiKey};
if(bizId) body.biz_id=bizId; if(nameInput.value.trim()) body.name=nameInput.value.trim(); if(phoneInput.value.trim()) body.phone=phoneInput.value.trim(); if(referrerInput.value.trim()) body.referrer_code=referrerInput.value.trim();
var headers = {'Content-Type':'application/json'}; if(apiKey) headers['X-API-Key']=apiKey;
var r = await fetch(server+'/api/chatbot', {method:'POST', headers:headers, body:JSON.stringify(body)});
var data = await r.json(); typing.remove();
if(!r.ok || data.error) addMessage('bot', data.message || data.error || '服务暂时不可用,请稍后再试。','错误');
else addMessage('bot', data.reply || '已收到,我们会尽快回复您。', data.source === 'login_required' ? '需要登录' : '');
}catch(e){ typing.remove(); addMessage('bot','网络连接失败,请稍后重试。','错误'); }
state.sending=false; sendBtn.disabled=false; input.focus();
}
bubble.addEventListener('click', function(){ openPanel(); });
root.querySelector('.close').addEventListener('click', function(){ openPanel(false); });
root.querySelector('.input').addEventListener('submit', function(e){ e.preventDefault(); send(); });
input.addEventListener('input', function(){ this.style.height='auto'; this.style.height=Math.min(this.scrollHeight,90)+'px'; });
input.addEventListener('keydown', function(e){ if(e.key === 'Enter' && !e.shiftKey){ e.preventDefault(); send(); }});
quick.addEventListener('click', function(e){ if(e.target.dataset.q) send(e.target.dataset.q); });
phoneInput.addEventListener('change', function(){ if(this.value.trim() || nameInput.value.trim()) quick.style.display='flex'; });
nameInput.addEventListener('change', function(){ if(this.value.trim() || phoneInput.value.trim()) quick.style.display='flex'; });
// 自动预填推荐码
var savedRef = localStorage.getItem('subai_referrer');
if(savedRef && referrerInput) referrerInput.value = savedRef;
window.KF_OPEN = function(){ openPanel(true); };
window.KF_CLOSE = function(){ openPanel(false); };
window.KF_SEND = send;
loadBranding();
})();