1/** 2 * @kuaidi100/customer-service-sdk v1.0.1 3 * 客æç³»ç»éæ SDK - æ¯ææ¬æµ®çªãiframe åµå ¥ãè·¨åéä¿¡ãæ ·å¼é离 4 * 5 * @author Your Company 6 * @license MIT 7 * @repository git+https://github.com/your-company/customer-service-sdk.git 8 * 9 * Build Date: 2026-04-09T03:29:59.423Z 10 * Copyright (c) 2026 Your Company 11 */!function(){"use strict";!function(t,e){const i="kuaidics";class CustomerService{constructor(t){this.config={code:"",link:"",selector:"",targetSelector:"",position:"absolute",panel:{css:{right:"20px",bottom:"20px",width:"400px",height:"600px",zIndex:9999}},autoShow:!1,isolateHistory:!0,sandbox:"allow-same-origin allow-scripts allow-forms allow-popups allow-modals allow-popups-to-escape-sandbox allow-downloads",...t},this.isInitialized=!1,this.isVisible=!1,this.shadowRoot=null,this.container=null,this.iframe=null,this.panel=null,this.historyStack=[],this.currentHistoryIndex=-1,this.lastIframeUrl="",this.init()}init(){this.isInitialized?console.warn("[CustomerService] SDK already initialized"):this.config.code&&this.config.link?("loading"===e.readyState?e.addEventListener("DOMContentLoaded",()=>this.setup()):this.setup(),this.isInitialized=!0):console.error("[CustomerService] Missing required config: code or link")}setup(){this.createContainer(),this.createPanel(),this.createIframe(),this.bindEvents(),this.setupMessageListener(),this.config.autoShow&&this.show(),console.log("[CustomerService] SDK initialized successfully")}createContainer(){if(this.config.targetSelector&&(this.container=e.querySelector(this.config.targetSelector),this.container||console.warn(`[CustomerService] Target selector "${this.config.targetSelector}" not found, creating default container`)),this.container||(this.container=e.createElement("div"),this.container.id=`cs-container-${this.config.code}`,e.body.appendChild(this.container)),this.container.shadowRoot)this.shadowRoot=this.container.shadowRoot;else try{this.shadowRoot=this.container.attachShadow({mode:"open"})}catch(t){console.warn("[CustomerService] Shadow DOM not supported, using regular DOM"),this.shadowRoot=this.container}this.injectStyles()}injectStyles(){const t=e.createElement("style");t.textContent="\n :host {\n all: initial;\n }\n\n * {\n box-sizing: border-box;\n margin: 0;\n padding: 0;\n }\n\n .cs-panel {\n position: fixed;\n background: #ffffff;\n box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);\n border-radius: 12px;\n overflow: hidden;\n transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n opacity: 0;\n transform: scale(0.9) translateY(20px);\n pointer-events: none;\n z-index: 9999;\n }\n\n .cs-panel.visible {\n opacity: 1;\n transform: scale(1) translateY(0);\n pointer-events: all;\n }\n\n .cs-panel-header {\n background: #F3F5FA;\n color: #ffffff;\n padding: 16px 20px;\n display: flex;\n justify-content: space-between;\n align-items: center;\n user-select: none;\n cursor: move;\n }\n\n .cs-panel-title {\n font-size: 16px;\n font-weight: 600;\n margin: 0;\n color: #000;\n }\n\n .cs-panel-controls {\n display: flex;\n gap: 8px;\n }\n\n .cs-btn {\n width: 28px;\n height: 28px;\n border: none;\n background: transparent;\n color: #000;\n border-radius: 6px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: all 0.2s;\n font-size: 16px;\n line-height: 1;\n font-weight: 600;\n }\n\n .cs-btn:hover {\n background: rgba(255, 255, 255, 0.3);\n transform: scale(1.1);\n }\n\n .cs-btn:active {\n transform: scale(0.95);\n }\n\n .cs-panel-body {\n width: 100%;\n height: calc(100% - 56px);\n position: relative;\n }\n\n .cs-iframe {\n width: 100%;\n height: 100%;\n border: none;\n display: block;\n }\n\n .cs-loading {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n text-align: center;\n color: #666;\n }\n\n .cs-spinner {\n width: 40px;\n height: 40px;\n border: 4px solid #f3f3f3;
11\n border-top: 4px solid #667eea;\n border-radius: 50%;\n animation: spin 1s linear infinite;\n margin: 0 auto 12px;\n }\n\n @keyframes spin {\n 0% { transform: rotate(0deg); }\n 100% { transform: rotate(360deg); }\n }\n\n /* æå°åç¶æ */\n .cs-panel.minimized {\n width: 60px !important;\n height: 60px !important;\n border-radius: 50%;\n overflow: hidden;\n }\n\n .cs-panel.minimized .cs-panel-header {\n padding: 0;\n width: 100%;\n height: 100%;\n justify-content: center;\n border-radius: 50%;\n cursor: pointer;\n }\n\n .cs-panel.minimized .cs-panel-title,\n .cs-panel.minimized .cs-btn-minimize,\n .cs-panel.minimized .cs-btn-close,\n .cs-panel.minimized .cs-panel-body {\n display: none;\n }\n\n .cs-panel.minimized .cs-btn-maximize {\n display: flex !important;\n width: 100%;\n height: 100%;\n border-radius: 50%;\n background: transparent;\n font-size: 24px;\n }\n\n .cs-btn-maximize {\n display: none;\n }\n ",this.shadowRoot.appendChild(t)}createPanel(){const t=e.createElement("div");t.className="cs-panel",Object.entries(this.config.panel.css).forEac
11h(([e,i])=>{t.style[e]=i});const i=e.createElement("div");i.className="cs-panel-header",i.innerHTML='\n \n <h3 class="cs-panel-title">æå®</h3>\n <div class="cs-panel-controls">\n <button class="cs-btn cs-btn-back" title="è¿å" style="opacity: 0;"><</button>\n <button class="cs-btn cs-btn-minimize" title="æå°å">â</button>\n </div>\n \n ';const n=e.createElement("div");n.className="cs-panel-body",n.innerHTML='\n <div class="cs-loading">\n <div class="cs-spinner"></div>\n <div>å è½½ä¸...</div>\n </div>\n ',t.appendChild(i),t.appendChild(n),this.shadowRoot.appendChild(t),this.panel=t,this.panelHeader=i,this.panelBody=n,this.makeDraggable(i,t)}createIframe(){const t=e.createElement("iframe");t.className="cs-iframe",t.src=this.buildIframeUrl(),t.setAttribute("allowfullscreen","true"),t.setAttribute("allow","camera; microphone; clipboard-write"),this.config.isolateHistory&&(t.setAttribute("sandbox",this.config.sandbox),console.log("[CustomerService] History isolation enabled")),t.onload=()=>{const t=this.panelBody.querySelector(".cs-loading");t&&(t.style.display="none"),this.sendMessageToIframe({type:"sdk:ready",code:this.config.code}),this.startMonitoringIframeUrl()},this.panelBody.appendChild(t),this.iframe=t}buildIframeUrl(){const t=new URL(this.config.link);return t.searchParams.set("code",this.config.code),t.searchParams.set("sdk_version","1.0.0"),t.toString()}bindEvents(){if(this.config.selector){const t=e.querySelector(this.config.selector);t&&(this.triggerButton=t,t.addEventListener("click",t=>{t.preventDefault(),this.toggle()}))}const i=this.shadowRoot.querySelector(".cs-btn-back"),n=this.shadowRoot.querySelector(".cs-btn-forward"),s=this.shadowRoot.querySelector(".cs-btn-minimize"),o=this.shadowRoot.querySelector(".cs-btn-maximize"),a=this.shadowRoot.querySelector(".cs-btn-close");i&&i.addEventListener("click",()=>this.goBack()),n&&n.addEventListener("click",()=>this.goForward()),s&&s.addEventListener("click",()=>this.hide()),o&&o.addEventListener("click",()=>this.maximize()),a&&a.addEventListener("click",()=>this.hide()),this.triggerButton&&(this.repositionHandler=()=>{this.isVisible&&!this.panel.classList.contains("minimized")&&this.positionPanelRelativeToButton()},t.addEventListener("resize",this.repositionHandler),t.addEventListener("scroll",this.repositionHandler,!0))}setupMessageListener(){t.addEventListener("message",t=>{try{const e=new URL(this.config.link).origin;if(t.origin!==e)return}catch(t){return}const{type:e,data:i}=t.data;switch(e){case"iframe:ready":console.log("[CustomerService] Iframe is ready");break;case"iframe:close":this.hide();break;case"iframe:minimize":this.minimize();break;case"iframe:resize":this.resize(i.width,i.height);break;case"iframe:notification":this.handleNotification(i);break;case"iframe:historyState":this.updateHistoryState(i.canGoBack,i.canGoForward);break;default:console.log("[CustomerService] Unknown message type:",e)}})}sendMessageToIframe(e){const i=t?.location.href||"";if(e.parentPage=i,this.iframe&&this.iframe.contentWindow){const t=new URL(this.config.link).origin;this.iframe.contentWindow.postMessage(e,t)}}show(){this.triggerButton&&this.positionPanelRelativeToButton(),this.panel.classList.add("visible"),this.panel.classList.remove("minimized"),this.isVisible=!0,this.sendMessageToIframe({type:"sdk:show"})}positionPanelRelativeToButton(){if(!this.triggerButton)return;const e=this.triggerButton.getBoundingClientRect(),i=this.config.panel.css;
11if("fixed"===this.config.position)return this.panel.style.left=i.left||"auto",this.panel.style.top=i.top||"auto",this.panel.style.right=i.right||"auto",void(this.panel.style.bottom=i.bottom||"auto");const n=t=>"number"==typeof t?t:parseFloat(t)||0;let s,o;const a=n(i.width)||400,r=n(i.height)||600;if(void 0!==i.right){const t=n(i.right);s=e.right-t-e.width-a}else if(void 0!==i.left){const t=n(i.left);s=e.left+t+e.width}else s=e.right+20;if(void 0!==i.top){const t=n(i.top);o=e.top+t}else if(void 0!==i.bottom){const t=n(i.bottom);o=e.bottom+t}else o=e.top;const c=t.innerWidth,l=t.innerHeight;s+a>c&&(s=c-a-20),s<20&&(s=20),o+r>l&&(o=l-r-20),o<20&&(o=20),this.panel.style.left=s+"px",this.panel.style.top=o+"px",this.panel.style.right="auto",this.panel.style.bottom="auto"}hide(){this.panel.classList.remove("visible"),this.isVisible=!1,this.sendMessageToIframe({type:"sdk:hide"})}toggle(){this.isVisible?this.hide():this.show()}minimize(){this.panel.classList.add("minimized"),this.sendMessageToIframe({type:"sdk:minimize"})}maximize(){this.panel.classList.remove("minimized"),this.sendMessageToIframe({type:"sdk:maximize"})}resize(t,e){t&&(this.panel.style.width=t+"px"),e&&(this.panel.style.height=e+"px")}handleNotification(t){console.log("[CustomerService] Notification:",t)}startMonitoringIframeUrl(){this.urlMonitorTimer=setInterval(()=>{try{const t=this.iframe.contentWindow.location.href;t!==this.lastIframeUrl&&""!==this.lastIframeUrl&&(console.log("[CustomerService] Iframe URL changed:",t),this.handleIframeNavigation(t)),this.lastIframeUrl=t}catch(t){}},500);try{this.lastIframeUrl=this.iframe.contentWindow.location.href,this.pushHistory(this.lastIframeUrl)}catch(t){this.lastIframeUrl=this.config.link,this.pushHistory(this.lastIframeUrl)}}stopMonitoringIframeUrl(){this.urlMonitorTimer&&(clearInterval(this.urlMonitorTimer),this.urlMonitorTimer=null)}handleIframeNavigation(t){this.isNavigatingHistory||(this.historyStack=this.historyStack.slice(0,this.currentHistoryIndex+1),this.pushHistory(t)),this.isNavigatingHistory=!1,this.updateNavigationButtons()}pushHistory(t){this.historyStack.push(t),this.currentHistoryIndex=this.historyStack.length-1,this.updateNavigationButtons(),console.log("[CustomerService] History pushed:",{url:t,index:this.currentHistoryIndex,stackLength:this.historyStack.length})}goBack(){if(this.canGoBack()){this.isNavigatingHistory=!0,this.currentHistoryIndex--;const t=this.historyStack[this.currentHistoryIndex];this.iframe.src=t,this.lastIframeUrl=t,this.sendMessageToIframe({type:"sdk:goBack"}),this.updateNavigationButtons(),console.log("[CustomerService] Go back to:",t)}}goForward(){if(this.canGoForward()){this.isNavigatingHistory=!0,this.currentHistoryIndex++;const t=this.historyStack[this.currentHistoryIndex];this.iframe.src=t,this.lastIframeUrl=t,this.sendMessageToIframe({type:"sdk:goForward"}),this.updateNavigationButtons(),console.log("[CustomerService] Go forward to:",t)}}canGoBack(){return this.currentHistoryIndex>0}canGoForward(){return this.currentHistoryIndex<this.historyStack.length-1}updateNavigationButtons(){const t=this.shadowRoot.querySelector(".cs-btn-back"),e=this.shadowRoot.querySelector(".cs-btn-forward");t&&(t.style.opacity=this.canGoBack()?"1":"0"),e&&(e.style.display=this.canGoForward()?"flex":"none"),console.log("[CustomerService] Navigation buttons updated:",{canGoBack:this.canGoBack(),canGoForward:this.canGoForward(),currentIndex:this.currentHistoryIndex,stackLength:this.historyStack.length})}updateHistoryState(t,e){const i=this.shadowRoot.querySelector(".cs-btn-back"),n=this.shadowRoot.querySelector(".cs-btn-forward");i&&(i.style.display=t?"flex":"none"),n&&(n.style.display=e?"flex":"none"),console.log("[CustomerService] History state updated from iframe:",{canGoBack:t,canGoForward:e})}makeDraggable(t,i){let n,s,o,a,r=!1;t.addEventListener("mousedown",t=>{i.classList.contains("minimized")||(r=!0,o=t.clientX-i.offsetLeft,a=t.clientY-i.offsetTop,i.style.cursor="grabbing")}),e.addEventListener("mousemove",t=>{r&&(t.preventDefault(),n=t.clientX-o,s=t.clientY-a,i.style.left=n+"px",i.style.top=s+"px",i.style.right="auto",i.style.bottom="auto")}),e.addEventListener("mouseup",()=>{r&&(r=!1,i.style.cursor="default")})}destroy(){this.stopMonitoringIframeUrl(),this.repositionHandler&&(t.removeEventListener("resize",this.repositionHandler),t.removeEventListener("scroll",this.repositionHandler,!0)),this.container&&this.container.parentNode&&this.container.parentNode.removeChild(this.container),this.isInitialized=!1,console.log("[CustomerService] SDK destroyed")}}const n=new class{constructor(){this.instances={},this.queue=[]}execute(t){const e=t.code||"default";return this.instances[e]||(this.instances[e]=new CustomerService(t)),this.instances[e]}getInstance(t="default"){return this.instances[t]}
11destroyInstance(t="default"){this.instances[t]&&(this.instances[t].destroy(),delete this.instances[t])}destroyAll(){Object.keys(this.instances).forEach(t=>{this.destroyInstance(t)})}};t[i]&&t[i].d&&t[i].d.forEach(t=>{n.execute(t[0])}),t[i]=function(t){return n.execute(t)},t[i].getInstance=t=>n.getInstance(t),t[i].destroy=t=>n.destroyInstance(t),t[i].destroyAll=()=>n.destroyAll(),console.log("[CustomerServiceSDK] SDK loaded successfully")}(window,document)}(); 12//# sourceMappingURL=customer-service-sdk.min.js.map
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.