ysyt-agent-sdk 1.0.15 → 1.0.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -110,7 +110,7 @@ const Zs=e=>(t,s)=>{void 0!==s?s.addInitializer(()=>{customElements.define(e,t)}
110
110
  :host([type='loading']) {
111
111
  background: #595959;
112
112
  }
113
- `}connectedCallback(){super.connectedCallback(),setTimeout(()=>{this.remove()},this.duration+300)}render(){return Ds`<div>${this.content}</div>`}};jt([ei({type:String})],ii.prototype,"type",void 0),jt([ei({type:String})],ii.prototype,"content",void 0),jt([ei({type:Number})],ii.prototype,"duration",void 0),ii=jt([Zs("my-message")],ii);const ri=(e,t,s=3e3)=>{let i=document.querySelector("#message-container");i||(i=document.createElement("div"),i.id="message-container",Object.assign(i.style,{position:"fixed",top:"14px",left:"50%",transform:"translateX(-50%)",zIndex:"9999"}),document.body.appendChild(i));const r=document.createElement("my-message");r.setAttribute("type",e),r.setAttribute("content",t),r.setAttribute("duration",String(s)),r.style.setProperty("--fade-delay",s/1e3+"s"),i.appendChild(r)},ni=(e,t=3e3)=>ri("success",e,t),oi=(e,t=3e3)=>ri("error",e,t),ai=(e,t=3e3)=>ri("warning",e,t),ci="/v1/aicc/bmserver",hi="/v1/aicc/ccs";let di="",li="",gi="";async function ui(e,t){const s=function(){const e=Ft(li,gi);return qt.create({prefixUrl:`${di}/api`,timeout:!1,headers:{Authorization:e},hooks:{afterResponse:[async(e,t,s)=>{const i=await s.clone().json();if(0!==i.code)throw oi(i.msg),new Error(JSON.stringify(i)||"请求失败");return s.json=async()=>i,s}]}})}(),i=e.replace(/^\/+/,"");return s.post(i,{json:t}).json()}const pi={agentInfo:{},isRtcReconnecting:!1,sessionId:"",enableBrowserAlert:!1,autoStateTimer:null};const fi=new class extends Qe{updateRttObject(e){this.setState({rttObject:e})}}({rttObject:{rtt:null,jitter:null,packetsLost:null,packetsReceived:null,packetsSent:null,sendBitrate:null,recvBitrate:null,codec:null}});class mi{constructor(e,t){this.config=e,this.eventCallback=t,this.userAgent=null,this.registerer=null,this.activeSession=null,this.callTimeoutTimer=null,this.incomingInvitation=null,this.reconnectAttempts=0,this.maxReconnectAttempts=5,this.reconnectTimer=null,this.isOffline=!1,this.autoAnswerTimer=null,this.handleMessage=e=>{},this.handleNetworkInfoChange=e=>{0===(e.rttObject?.rtt||0)?this.isOffline||(this.isOffline=!0,this.handleOffline()):this.isOffline&&(this.isOffline=!1,this.handleOnline())},this.handleOffline=()=>{console.warn("[SIPClient] 网络断开,准备销毁 SIP 客户端",(new Date).toLocaleString()),this.destroy()},this.handleOnline=()=>{console.warn("[SIPClient] 网络恢复,准备重新启动 SIP 客户端",(new Date).toLocaleString()),this.reconnect()},fi.subscribe(this.handleNetworkInfoChange)}async start(){const e=Xe.makeURI(`sip:${this.config.user}@${this.config.server}`);if(!e)throw new Error("无效的SIP配置");const t={uri:e,authorizationUsername:this.config.user,authorizationPassword:this.config.password,transportOptions:{server:this.config.webSocket,connectionTimeout:30,keepAliveInterval:0},sessionDescriptionHandlerFactoryOptions:{alwaysAcquireMediaFirst:!0,peerConnectionConfiguration:{iceServers:[]},iceGatheringTimeout:400},logBuiltinEnabled:!1};this.userAgent=new Xe(t),this.setupEventListeners(),await this.userAgent.start(),await this.register()}setupEventListeners(){this.userAgent&&(this.userAgent.transport.stateChange.addListener(e=>{let t;switch(e){case ee.Connecting:t=st.WEB_RTC_CONNECTING;break;case ee.Connected:t=st.WEB_RTC_CONNECTED,this.reconnectAttempts=0,pi.isRtcReconnecting=!1,this.reconnectTimer&&(clearTimeout(this.reconnectTimer),this.reconnectTimer=null);break;case ee.Disconnecting:t=st.WEB_RTC_DISCONNECTING;break;case ee.Disconnected:{t=st.WEB_RTC_DISCONNECTED;const e=dt.get("answerDevice");if(!pi.isRtcReconnecting&&this.reconnectAttempts<this.maxReconnectAttempts&&1===e){this.reconnectAttempts++;const e=1e3*this.reconnectAttempts;console.warn(`SIP WebSocket 断开,第 ${this.reconnectAttempts} 次尝试重连,${e}ms 后重试...`),this.reconnectTimer=setTimeout(()=>{this.reconnect()},e)}else this.reconnectAttempts>=this.maxReconnectAttempts&&console.error("SIP 重连失败:已达到最大重试次数");break}default:t="unknown"}this.eventCallback?.({type:t})}),this.userAgent.transport.stateChange.addListener(e=>{}),this.userAgent.delegate={onInvite:e=>{this.handleIncomingCall(e)}})}async register(){if(this.userAgent){this.registerer=new ne(this.userAgent),this.registerer?.stateChange.addListener(e=>{let t;switch(e){case X.Initial:t="initial";break;case X.Registered:t=st.WEB_RTC_REGISTERED;break;case X.Unregistered:t=st.WEB_RTC_UNREGISTERED;break;case X.Terminated:t=st.WEB_RTC_TERMINATED;break;default:t="unknown"}this.eventCallback?.({type:t})});try{await this.registerer.register()}catch(e){this.eventCallback?.({type:st.WEB_RTC_REGISTER_FAILED,data:e})}}}attachRemoteAudio(e){const t=e.sessionDescriptionHandler;if(t){const e=t.peerConnection;if(!e)return;const s=new MediaStream;e.getReceivers().forEach(e=>{e.track&&"audio"===e.track.kind&&s.addTrack(e.track)});let i=document.getElementById("sip-remote-audio");i||(i=document.createElement("audio"),i.id="sip-remote-audio",i.autoplay=!0,i.style.display="none",document.body.appendChild(i)),i.srcObject=s,i.play().catch(e=>{console.error("音频播放失败,需要用户交互触发",e)})}}handleSessionState(e,t,s){e.stateChange.addListener(t=>{switch(t){case K.Established:clearTimeout(this.callTimeoutTimer),this.activeSession=e,this.attachRemoteAudio(e);break;case K.Terminating:break;case K.Terminated:this.activeSession=null,clearTimeout(this.callTimeoutTimer);case K.Establishing:}})}handleIncomingCall(e){this.incomingInvitation=e,this.handleSessionState(e,!1);const{soft_device_auto_answer:t,auto_answer_time:s}=pi.agentInfo,i=dt.get("direction"),r=1===t;if(i===tt.OUTGOING)this.answerCall();else if(r&&i===tt.INCOMING){const e=Number(s)||0;e>0?this.autoAnswerTimer=setTimeout(()=>{this.answerCall(),this.autoAnswerTimer=null},e):this.answerCall()}}async makeCall(e){if(dt.getState().isCalling)throw new Error("正在呼叫中,请勿重复点击");if(!this.userAgent)throw dt.updateIsCalling(!1),dt.updateDirection(null),new Error("SIP客户端未初始化");dt.updateIsCalling(!0),dt.updateDirection(tt.OUTGOING);const t=Xe.makeURI(`sip:${e}@${this.config.server}`);if(!t)throw new Error("无效的被叫号码");const s=new Z(this.userAgent,t);this.handleSessionState(s,!0,e);try{this.activeSession=s,await s.invite(),this.config.callTimeout&&(this.callTimeoutTimer=setTimeout(()=>{s.state!==K.Established&&(this.hangup(),this.eventCallback?.({type:"error",data:{message:"呼叫超时未接通"}}))},this.config.callTimeout))}catch(e){this.eventCallback?.({type:"error",data:{message:"呼叫失败",detail:e}}),dt.updateIsCalling(!1),dt.updateDirection(null)}}async answerCall(){if(!this.incomingInvitation)throw new Error("无来电可接听");this.autoAnswerTimer&&(clearTimeout(this.autoAnswerTimer),this.autoAnswerTimer=null);try{console.log((new Date).toLocaleString()),await this.incomingInvitation.accept(),console.log((new Date).toLocaleString()),this.activeSession=this.incomingInvitation,this.incomingInvitation=null}catch(e){this.eventCallback?.({type:st.WEB_RTC_ANSWER_FAILED,data:{detail:e}})}}async rejectInCall(){if(this.incomingInvitation)try{await this.incomingInvitation.reject(),this.incomingInvitation=null,dt.updateDirection(null),dt.updateIsCalling(!1),clearTimeout(this.callTimeoutTimer)}catch(e){this.eventCallback?.({type:"error",data:{message:"拒接失败",detail:e}})}}sendDTMF(e){if(!this.activeSession)throw new Error("当前没有活跃的通话");const t=this.activeSession.sessionDescriptionHandler;t&&"function"==typeof t.sendDtmf?(t.sendDtmf(e),this.eventCallback?.({type:st.WEB_RTC_SEND_DTMF,data:{tone:e}})):console.warn("DTMF发送不支持或未初始化")}async hangup(){if(this.activeSession){clearTimeout(this.callTimeoutTimer);const e=this.activeSession;if(!e)return;const t=e.state;try{t===K.Established?await e.bye():t===K.Establishing&&(e instanceof Z?await e.cancel():e instanceof J&&await e.reject()),clearTimeout(this.callTimeoutTimer)}catch(e){console.error("挂断失败",e)}finally{this.activeSession=null}}}async rejectOutCall(){this.activeSession instanceof J&&(await this.activeSession.reject(),this.activeSession=null)}async destroy(){if(clearTimeout(this.callTimeoutTimer),this.activeSession&&await this.hangup(),this.registerer){try{await this.registerer.unregister()}catch(e){console.warn("注销失败",e)}this.registerer=null}this.userAgent&&(await this.userAgent.stop(),this.userAgent=null)}async reconnect(){if(!pi.isRtcReconnecting){pi.isRtcReconnecting=!0;try{await this.destroy(),await this.start(),console.log("重连成功"),this.isOffline=!1}catch(e){console.error("重连失败",e)}finally{pi.isRtcReconnecting=!1}}}async getNetworkStats(){if(this.activeSession){const e=this.activeSession.sessionDescriptionHandler?.peerConnection;if(!e)return null;const t=await e.getStats(),s={};return t.forEach(e=>{"candidate-pair"===e.type&&"succeeded"===e.state&&null!=e.currentRoundTripTime&&(s.rtt=+(1e3*e.currentRoundTripTime).toFixed(2)),"inbound-rtp"===e.type&&"audio"===e.kind&&(s.jitter=+(1e3*e.jitter).toFixed(2),s.packetsLost=e.packetsLost,s.packetsReceived=e.packetsReceived,e.bytesReceived&&e.timestamp&&(s.recvBitrate=+(e.bytesReceived/1024).toFixed(2))),"outbound-rtp"===e.type&&"audio"===e.kind&&(s.packetsSent=e.packetsSent,e.bytesSent&&e.timestamp&&(s.sendBitrate=+(e.bytesSent/1024).toFixed(2))),"codec"===e.type&&e.mimeType&&(s.codec=e.mimeType)}),{...s,rtt:s?.rtt||40}}try{const e=Date.now();await ui(`${ci}/config/ping`,{});const t=Date.now();return{rtt:t-e||1}}catch(e){console.log(e)}}}const vi={statusColor:{[et.IDLE]:"#1D92E9",[et.BUSY]:"#F5212D",[et.OFFLINE]:"#8c8c8c",[et.RINGING]:"#e9b91d"}},wi=["call_number"],yi=[],bi=["hangup"],Ti=["hold","hangup","unhold","mute","unmute","transfer","consult","satisfaction","dtmf"],Si=["consult_transfer"],Ci=["hangup"],Ei=["answer","reject"],Ai=["hangup","consult","transfer","hold","unhold","mute","unmute","satisfaction","dtmf"];let _i=class extends zs{static{this.styles=Yt`
113
+ `}connectedCallback(){super.connectedCallback(),setTimeout(()=>{this.remove()},this.duration+300)}render(){return Ds`<div>${this.content}</div>`}};jt([ei({type:String})],ii.prototype,"type",void 0),jt([ei({type:String})],ii.prototype,"content",void 0),jt([ei({type:Number})],ii.prototype,"duration",void 0),ii=jt([Zs("my-message")],ii);const ri=(e,t,s=3e3)=>{let i=document.querySelector("#message-container");i||(i=document.createElement("div"),i.id="message-container",Object.assign(i.style,{position:"fixed",top:"14px",left:"50%",transform:"translateX(-50%)",zIndex:"9999"}),document.body.appendChild(i));const r=document.createElement("my-message");r.setAttribute("type",e),r.setAttribute("content",t),r.setAttribute("duration",String(s)),r.style.setProperty("--fade-delay",s/1e3+"s"),i.appendChild(r)},ni=(e,t=3e3)=>ri("success",e,t),oi=(e,t=3e3)=>ri("error",e,t),ai=(e,t=3e3)=>ri("warning",e,t),ci="/v1/aicc/bmserver",hi="/v1/aicc/ccs";let di="",li="",gi="";async function ui(e,t){const s=function(){const e=Ft(li,gi);return qt.create({prefixUrl:`${di}/api`,timeout:!1,headers:{Authorization:e},hooks:{afterResponse:[async(e,t,s)=>{const i=await s.clone().json();if(0!==i.code)throw oi(i.msg),new Error(JSON.stringify(i)||"请求失败");return s.json=async()=>i,s}]}})}(),i=e.replace(/^\/+/,"");return s.post(i,{json:t}).json()}const pi={agentInfo:{},isRtcReconnecting:!1,sessionId:"",enableBrowserAlert:!1,autoStateTimer:null};const fi=new class extends Qe{updateRttObject(e){this.setState({rttObject:e})}}({rttObject:{rtt:null,jitter:null,packetsLost:null,packetsReceived:null,packetsSent:null,sendBitrate:null,recvBitrate:null,codec:null}});class mi{constructor(e,t){this.config=e,this.eventCallback=t,this.userAgent=null,this.registerer=null,this.activeSession=null,this.callTimeoutTimer=null,this.incomingInvitation=null,this.reconnectAttempts=0,this.maxReconnectAttempts=5,this.reconnectTimer=null,this.isOffline=!1,this.autoAnswerTimer=null,this.handleMessage=e=>{},this.handleNetworkInfoChange=e=>{const t=e.rttObject?.rtt||0;console.log(t),0===t?this.isOffline||(this.isOffline=!0,this.handleOffline()):this.isOffline&&(this.isOffline=!1,this.handleOnline())},this.handleOffline=()=>{console.warn("[SIPClient] 网络断开,准备销毁 SIP 客户端",(new Date).toLocaleString())},this.handleOnline=()=>{console.warn("[SIPClient] 网络恢复,准备重新启动 SIP 客户端",(new Date).toLocaleString())},fi.subscribe(this.handleNetworkInfoChange)}async start(){const e=Xe.makeURI(`sip:${this.config.user}@${this.config.server}`);if(!e)throw new Error("无效的SIP配置");const t={uri:e,authorizationUsername:this.config.user,authorizationPassword:this.config.password,transportOptions:{server:this.config.webSocket,connectionTimeout:30,keepAliveInterval:0},sessionDescriptionHandlerFactoryOptions:{alwaysAcquireMediaFirst:!0,peerConnectionConfiguration:{iceServers:[]},iceGatheringTimeout:400},logBuiltinEnabled:!1};this.userAgent=new Xe(t),this.setupEventListeners(),await this.userAgent.start(),await this.register()}setupEventListeners(){this.userAgent&&(this.userAgent.transport.stateChange.addListener(e=>{let t;switch(e){case ee.Connecting:t=st.WEB_RTC_CONNECTING;break;case ee.Connected:t=st.WEB_RTC_CONNECTED,this.reconnectAttempts=0,pi.isRtcReconnecting=!1,this.reconnectTimer&&(clearTimeout(this.reconnectTimer),this.reconnectTimer=null);break;case ee.Disconnecting:t=st.WEB_RTC_DISCONNECTING;break;case ee.Disconnected:{t=st.WEB_RTC_DISCONNECTED;const e=dt.get("answerDevice");if(!pi.isRtcReconnecting&&this.reconnectAttempts<this.maxReconnectAttempts&&1===e){this.reconnectAttempts++;const e=1e3*this.reconnectAttempts;console.warn(`SIP WebSocket 断开,第 ${this.reconnectAttempts} 次尝试重连,${e}ms 后重试...`),this.reconnectTimer=setTimeout(()=>{this.reconnect()},e)}else this.reconnectAttempts>=this.maxReconnectAttempts&&console.error("SIP 重连失败:已达到最大重试次数");break}default:t="unknown"}this.eventCallback?.({type:t})}),this.userAgent.transport.stateChange.addListener(e=>{}),this.userAgent.delegate={onInvite:e=>{this.handleIncomingCall(e)}})}async register(){if(this.userAgent){this.registerer=new ne(this.userAgent),this.registerer?.stateChange.addListener(e=>{let t;switch(e){case X.Initial:t="initial";break;case X.Registered:t=st.WEB_RTC_REGISTERED;break;case X.Unregistered:t=st.WEB_RTC_UNREGISTERED;break;case X.Terminated:t=st.WEB_RTC_TERMINATED;break;default:t="unknown"}this.eventCallback?.({type:t})});try{await this.registerer.register()}catch(e){this.eventCallback?.({type:st.WEB_RTC_REGISTER_FAILED,data:e})}}}attachRemoteAudio(e){const t=e.sessionDescriptionHandler;if(t){const e=t.peerConnection;if(!e)return;const s=new MediaStream;e.getReceivers().forEach(e=>{e.track&&"audio"===e.track.kind&&s.addTrack(e.track)});let i=document.getElementById("sip-remote-audio");i||(i=document.createElement("audio"),i.id="sip-remote-audio",i.autoplay=!0,i.style.display="none",document.body.appendChild(i)),i.srcObject=s,i.play().catch(e=>{console.error("音频播放失败,需要用户交互触发",e)})}}handleSessionState(e,t,s){e.stateChange.addListener(t=>{switch(t){case K.Established:clearTimeout(this.callTimeoutTimer),this.activeSession=e,this.attachRemoteAudio(e);break;case K.Terminating:break;case K.Terminated:this.activeSession=null,clearTimeout(this.callTimeoutTimer);case K.Establishing:}})}handleIncomingCall(e){this.incomingInvitation=e,this.handleSessionState(e,!1);const{soft_device_auto_answer:t,auto_answer_time:s}=pi.agentInfo,i=dt.get("direction"),r=1===t;if(i===tt.OUTGOING)this.answerCall();else if(r&&i===tt.INCOMING){const e=Number(s)||0;e>0?this.autoAnswerTimer=setTimeout(()=>{this.answerCall(),this.autoAnswerTimer=null},e):this.answerCall()}}async makeCall(e){if(dt.getState().isCalling)throw new Error("正在呼叫中,请勿重复点击");if(!this.userAgent)throw dt.updateIsCalling(!1),dt.updateDirection(null),new Error("SIP客户端未初始化");dt.updateIsCalling(!0),dt.updateDirection(tt.OUTGOING);const t=Xe.makeURI(`sip:${e}@${this.config.server}`);if(!t)throw new Error("无效的被叫号码");const s=new Z(this.userAgent,t);this.handleSessionState(s,!0,e);try{this.activeSession=s,await s.invite(),this.config.callTimeout&&(this.callTimeoutTimer=setTimeout(()=>{s.state!==K.Established&&(this.hangup(),this.eventCallback?.({type:"error",data:{message:"呼叫超时未接通"}}))},this.config.callTimeout))}catch(e){this.eventCallback?.({type:"error",data:{message:"呼叫失败",detail:e}}),dt.updateIsCalling(!1),dt.updateDirection(null)}}async answerCall(){if(!this.incomingInvitation)throw new Error("无来电可接听");this.autoAnswerTimer&&(clearTimeout(this.autoAnswerTimer),this.autoAnswerTimer=null);try{console.log((new Date).toLocaleString()),await this.incomingInvitation.accept(),console.log((new Date).toLocaleString()),this.activeSession=this.incomingInvitation,this.incomingInvitation=null}catch(e){this.eventCallback?.({type:st.WEB_RTC_ANSWER_FAILED,data:{detail:e}})}}async rejectInCall(){if(this.incomingInvitation)try{await this.incomingInvitation.reject(),this.incomingInvitation=null,dt.updateDirection(null),dt.updateIsCalling(!1),clearTimeout(this.callTimeoutTimer)}catch(e){this.eventCallback?.({type:"error",data:{message:"拒接失败",detail:e}})}}sendDTMF(e){if(!this.activeSession)throw new Error("当前没有活跃的通话");const t=this.activeSession.sessionDescriptionHandler;t&&"function"==typeof t.sendDtmf?(t.sendDtmf(e),this.eventCallback?.({type:st.WEB_RTC_SEND_DTMF,data:{tone:e}})):console.warn("DTMF发送不支持或未初始化")}async hangup(){if(this.activeSession){clearTimeout(this.callTimeoutTimer);const e=this.activeSession;if(!e)return;const t=e.state;try{t===K.Established?await e.bye():t===K.Establishing&&(e instanceof Z?await e.cancel():e instanceof J&&await e.reject()),clearTimeout(this.callTimeoutTimer)}catch(e){console.error("挂断失败",e)}finally{this.activeSession=null}}}async rejectOutCall(){this.activeSession instanceof J&&(await this.activeSession.reject(),this.activeSession=null)}async destroy(){if(clearTimeout(this.callTimeoutTimer),this.activeSession&&await this.hangup(),this.registerer){try{await this.registerer.unregister()}catch(e){console.warn("注销失败",e)}this.registerer=null}this.userAgent&&(await this.userAgent.stop(),this.userAgent=null)}async reconnect(){if(!pi.isRtcReconnecting){pi.isRtcReconnecting=!0;try{await this.destroy(),await this.start(),console.log("重连成功"),this.isOffline=!1}catch(e){console.error("重连失败",e)}finally{pi.isRtcReconnecting=!1}}}async getNetworkStats(){if(this.activeSession){const e=this.activeSession.sessionDescriptionHandler?.peerConnection;if(!e)return null;const t=await e.getStats(),s={};return t.forEach(e=>{"candidate-pair"===e.type&&"succeeded"===e.state&&null!=e.currentRoundTripTime&&(s.rtt=+(1e3*e.currentRoundTripTime).toFixed(2)),"inbound-rtp"===e.type&&"audio"===e.kind&&(s.jitter=+(1e3*e.jitter).toFixed(2),s.packetsLost=e.packetsLost,s.packetsReceived=e.packetsReceived,e.bytesReceived&&e.timestamp&&(s.recvBitrate=+(e.bytesReceived/1024).toFixed(2))),"outbound-rtp"===e.type&&"audio"===e.kind&&(s.packetsSent=e.packetsSent,e.bytesSent&&e.timestamp&&(s.sendBitrate=+(e.bytesSent/1024).toFixed(2))),"codec"===e.type&&e.mimeType&&(s.codec=e.mimeType)}),{...s,rtt:s?.rtt||40}}try{const e=Date.now();await ui(`${ci}/config/ping`,{});const t=Date.now();return{rtt:t-e||1}}catch(e){console.log(e)}}}const vi={statusColor:{[et.IDLE]:"#1D92E9",[et.BUSY]:"#F5212D",[et.OFFLINE]:"#8c8c8c",[et.RINGING]:"#e9b91d"}},wi=["call_number"],yi=[],bi=["hangup"],Ti=["hold","hangup","unhold","mute","unmute","transfer","consult","satisfaction","dtmf"],Si=["consult_transfer"],Ci=["hangup"],Ei=["answer","reject"],Ai=["hangup","consult","transfer","hold","unhold","mute","unmute","satisfaction","dtmf"];let _i=class extends zs{static{this.styles=Yt`
114
114
  .timer-text {
115
115
  width: 70px;
116
116
  font-size: 14px;
@@ -658,16 +658,16 @@ const Zs=e=>(t,s)=>{void 0!==s?s.addInitializer(()=>{customElements.define(e,t)}
658
658
  </div>`}
659
659
  </div>
660
660
  </my-modal-wrapper>
661
- `;Ws(i,this.modalRoot)}})}catch(e){oi(e)}}getActionConfigs(){const{show_satisfaction:e}=pi.agentInfo,t=dt.get("isHold"),s=dt.get("isMuted"),i=dt.get("actionConfigs").filter(i=>(0!==e||"satisfaction"!==i)&&(!(!t&&"unhold"===i)&&((!t||"hold"!==i)&&((!s||"mute"!==i)&&!(!s&&"unmute"===i)))));return[{render:this.renderCallPopover,type:"call_number"},{render:this.renderAnswer,type:"answer"},{render:this.renderReject,type:"reject"},{render:this.renderHangup,type:"hangup"},{render:this.renderDialer,type:"dtmf"},{render:this.renderUnhold,type:"unhold"},{render:this.renderHold,type:"hold"},{render:this.renderMute,type:"mute"},{render:this.renderUnmute,type:"unmute"},{render:this.renderSatisfaction,type:"satisfaction"},{render:this.renderConsult,type:"consult"},{render:this.renderTransfer,type:"transfer"},{render:this.renderConsultTransfer,type:"consult_transfer"}].filter(({type:e})=>i.includes(e))}async render(){const{displayText:e,answerDevice:t}=dt.getState(),{default_device:s,answer_devices:i,show_satisfaction:r}=pi.agentInfo,n=(i||"").split(","),o=this.getActionConfigs(),a={...vi},{statusColor:c}=a,h=document.querySelector("head");if(h){const e=Ds`
661
+ `;Ws(i,this.modalRoot)}})}catch(e){oi(e)}}getActionConfigs(){const{show_satisfaction:e}=pi.agentInfo,t=dt.get("isHold"),s=dt.get("isMuted"),i=dt.get("actionConfigs").filter(i=>(0!==e||"satisfaction"!==i)&&(!(!t&&"unhold"===i)&&((!t||"hold"!==i)&&((!s||"mute"!==i)&&!(!s&&"unmute"===i)))));return[{render:this.renderCallPopover,type:"call_number"},{render:this.renderAnswer,type:"answer"},{render:this.renderReject,type:"reject"},{render:this.renderHangup,type:"hangup"},{render:this.renderDialer,type:"dtmf"},{render:this.renderUnhold,type:"unhold"},{render:this.renderHold,type:"hold"},{render:this.renderMute,type:"mute"},{render:this.renderUnmute,type:"unmute"},{render:this.renderSatisfaction,type:"satisfaction"},{render:this.renderConsult,type:"consult"},{render:this.renderTransfer,type:"transfer"},{render:this.renderConsultTransfer,type:"consult_transfer"}].filter(({type:e})=>i.includes(e))}async render(){const{displayText:e}=dt.getState(),{default_device:t,answer_devices:s,show_satisfaction:i}=pi.agentInfo,r=(s||"").split(","),n=this.getActionConfigs(),o={...vi},{statusColor:a}=o,c=document.querySelector("head");if(c){const e=Ds`
662
662
  <style>
663
663
  .ysyt-phone-body {
664
- background: ${c[this.statusParams.state]};
664
+ background: ${a[this.statusParams.state]};
665
665
  }
666
666
  .ysyt-action-body {
667
- border-bottom: 1px solid ${c[this.statusParams.state]};
667
+ border-bottom: 1px solid ${a[this.statusParams.state]};
668
668
  }
669
669
  </style>
670
- `;Ws(e,h)}const d=Ds`
670
+ `;Ws(e,c)}const h=Ds`
671
671
  <i class="ysyt icon-shang select-icon" style="${this.isOpenSelect?"display: block;":"display: none;"}"></i>
672
672
  <div
673
673
  class="ysyt-select"
@@ -684,30 +684,30 @@ const Zs=e=>(t,s)=>{void 0!==s?s.addInitializer(()=>{customElements.define(e,t)}
684
684
  `)}
685
685
  </div>
686
686
  </div>
687
- `,l=Ds`
687
+ `,d=Ds`
688
688
  <div id="ysyt-body">
689
689
  <div id="ysyt-devices-body">
690
690
  <my-select
691
691
  width="100px"
692
- value="${String(s)}"
692
+ value="${String(t)}"
693
693
  placeholder=""
694
694
  @change=${e=>this.onChangeDevices(Number(e.detail.value))}
695
695
  >
696
- ${n.includes("1")?Ds`
696
+ ${r.includes("1")?Ds`
697
697
  <select-option value="1">
698
698
  <div style="display: flex; align-items: center; gap: 8px;">
699
699
  <img src="${"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAC0AAAAtCAYAAAA6GuKaAAAAAXNSR0IArs4c6QAAAjhJREFUaEPtmM1WwjAQhWeAF0I34kZ5MuDJqBtxo7wQEE9CkzNNk8yktIl4YKOHRvPl9s5PBuEOP3iHzPCALvXWxEq/HBfvGmp2AfPz8/m0LQXp78NCa1gEtQF1hbUfVLirBZ6EXh3neweL0CjAnVZaodpoeIW4/lqemtKKB6E76rawFM48V2oPCM1heV7/CWircMoCr9+LrVa8hk16SufArH7mqoZNboKuZZMetLXG4enMZhatsl1fMij/F7RUuZwYGCvLRJWWQDtPA4DUTmOARwORg6bApdNeD1qaEWy6Kw2s31QwQxigRLWr4eNO3xPyGJfGLDRnoTH8G/of8d5DqX0MijvUVLCuwwxtwPmae14FWm/K+bZW3xENRKtUCsweqkZ7muwvODBJCzuFVdimiAu6GvmaheZKdY3KyELToIz5Nxe8d1lGaPCCH9KLsgia9s2xsk3BU8HprzOeb2/60pZADC0Bp2tMagqMGULBawJ+pt6k8FnQUhu4rNOmDg1vBG3BYorSv0upngXd8XdESZvi9AHpjMSlPmbs4I8vQiOKbOgccP8Alxk00uFOqkYMgh4CPqTIxFrkwdAlwCeBdj0KmflJ0xanfKphu0lpunEnY2QWi+BFJDG9Gg3a2cXLtznBZ+G5tnhUaH9TqqDUNvSNxcYSk0B34Iny5vvWOnaNfhP6d5PTydrU/XNS6F6h8Q8QMnNgHu4vKwLtb2qrJf3eKi4pPlWguXTHPX9AcwqN9fwulf4FD/s5TOGFiLYAAAAASUVORK5CYII="}" width="16" alt="" /><span style="font-size: 14px">软电话</span>
700
700
  </div>
701
701
  </select-option>
702
702
  `:""}
703
- ${n.includes("2")?Ds`
703
+ ${r.includes("2")?Ds`
704
704
  <select-option value="2">
705
705
  <div style="display: flex; align-items: center; gap: 8px;">
706
706
  <img src="${"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAC0AAAAtCAYAAAA6GuKaAAAAAXNSR0IArs4c6QAAAWtJREFUaEPtWdFNAzEMdW6Ewgo3BzBOYYi2Q0DHKcxxK0BHaNA7cIVEVD0n8Uck31dVOfbLyzvn9JxkwCcNiFmqQd8fl8eWDX9u5/fa9WbQm9dlnyZ5yFmaQF8BZzmcX+a9ZQMm0HfH5QSwKcnKUr7Ih6XYv9gkO/yHfF/b+YnNRYMGw4IiFczcAlOTlwf9tmQUPz/P9BqWOZwgYlm2aQAbgO7Msm5KZccSQoFGp7hkOUF7SeTAMsjGZZEd3hUX0CyI2jgX0GC6uWMUdqQt1AX0kJoO0H9k4to9gulgutCS9HIJeYQ8Qh7cV0j0aeUpukdBMSGPkMeNRhLyCHmEPIibdujLJcyawgm7+R7T9GPz9nx8bTHSgNQpAev2u1wuYBWuKWt+q+fMxruBtnjIVqN8tZEN3jdl9a5MjzgJAHA9RvzWuUvrC6kzHHYKsNa2Fr0ybl1Ysnh/rWPX6VYHnF1SmJnuUrUxyZCgvwFf6/M9kuThSwAAAABJRU5ErkJggg=="}" width="16" alt="" /><span style="font-size: 14px">手机模式</span>
707
707
  </div>
708
708
  </select-option>
709
709
  `:""}
710
- ${n.includes("3")?Ds`
710
+ ${r.includes("3")?Ds`
711
711
  <select-option value="3">
712
712
  <div style="display: flex; align-items: center; gap: 8px;">
713
713
  <img src="${"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAC0AAAAtCAYAAAA6GuKaAAAAAXNSR0IArs4c6QAAAq5JREFUaEPtmWFywiAQhcEr6Als79F6LdsZdab1WsZ7tJ7AXiF0lmYzC9mFDUGrM/qrmrB8PB7LQq25w4+9Q2bzgL7WrD2UvhmlF8/vr865jXXueD7tt1PAIBZtf/76aPA7PKPf4Xf6Pn2WtMdiud46YzZ9R9Y2P9+fqxLw+dPbwTgXQNvZbIUw8+XaGRJ/0LcxkDV2IJwIHTSytuk7LADnAGDgCOFns20P8NvPae+ZuEFiGxaadtIHpqqPBPcqEsh4plLQg/6tbVhoqZNYfY1VKBC1AwUfBf03+PDDBQg6KFCcTjUoB/Hoos7ag9gT2g+hESphgbGKUygUAKcds4TK0x1TEbTvqEBxaANtMSOhXZJKg4edO5rZrMFMUwxdCk4zgyZ70BkhsxR5WmEPyeOphUbboBXqQTM5M7eZ4ELjVPHKdikviEM3kkSeVilNO5GUE5Xudqx4kANoZpHDO8Hi7GZcD41bbmYT4Tah3KzUeM7viEqL5GxRA5CLIdYe/a5IiprBtHczorFRzQHI0AqL9DvdyFpk6gDkKo9YRMoKuS1/KpzUXl1PSxbIVXCXAM+eEft0JVjgPzJIFjooLYU8rAWvdXTLQsc1hmgTcpzi1kDNo5sKmhY58LdYY0RnSqydnbUv9Lg25ejm+9culKAm1tbaUfAaR7dR0HGxTk/O3MC9HUDh7mOt3QVXBgX1uFia5pQvKf6lmKWx1PaQKruc4pcQoQg6ziipxZmDHsRSlATF0AOPJ+41aoNPgu7BndtgGpPqlLHgqTiToREm3jxK4TWVYzVozuddTvWXhjeptJhdME/DzRK5u4gHEd9CpQZaVekYRLothTQZvEuugDW2uih04Hdafwhe0R7brgIdWAf+G9C2weV6yjbc+K4OrVmQuXce0DmFaj2/S6V/Ae/pt8oTAp/jAAAAAElFTkSuQmCC"}" width="16" alt="" /><span style="font-size: 14px">SIP话机</span>
@@ -727,14 +727,14 @@ const Zs=e=>(t,s)=>{void 0!==s?s.addInitializer(()=>{customElements.define(e,t)}
727
727
  <span>${t}</span>
728
728
  `:void 0)(this.statusParams)}
729
729
  <i class="ysyt icon-xia"></i>
730
- ${d}
730
+ ${h}
731
731
  `}
732
732
  </div>
733
733
  <timer-component id="my-timer"></timer-component>
734
734
  </div>
735
- <div class="ysyt-action-body">${o.map(e=>e.render())}</div>
735
+ <div class="ysyt-action-body">${n.map(e=>e.render())}</div>
736
736
  </div>
737
- `;Ws(l,this.container)}async renderRtt(e){const{outCallIsAnswer:t}=dt.getState(),s=e?.rtt||500,i=Ds`
737
+ `;Ws(d,this.container)}async renderRtt(e){const{outCallIsAnswer:t}=dt.getState(),s=e?.rtt||500,i=Ds`
738
738
  <my-popover triggerType="hover">
739
739
  <div slot="trigger" id="wifi-body">
740
740
  ${s>=250?Ds`<img src="${"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAC0AAAAtCAYAAAA6GuKaAAAAAXNSR0IArs4c6QAAAlVJREFUaEPtmGFuwyAMhU2PtU1qOVmbk5FKW4+1TCawkcQYG2i3aM2fqirBn83zc1IDO7zMDpnhCf2oU+teaefcKYW31o69k6mGTuDOAWoBmwGNCVwBYKxNSAUdQDWQkiIPuMhae5EsxjUi6ARWUk1pbGrdIIFnoZWwqXbx+NPrqJAQLmXhSWghLELGo1U1m3MuSiFKLXc6JPwGOmyY28yD1jYQRSZIYAP+DV2obnfYdQIF+EV8Dx2AHVGJu8Mq4X3VDSMHUSe3WAV3L8eF0BNxs9XoNpwU2mF0CdwSv6fDxIeRWFrkyYEjNMoi+q9YDkKHyRUT41wlCRBxhqhptCDRWC24S41aRDIMcT2jaCKGZsXESr6aQmM1NRNUBK8Z46mE1tWMumX9W+DHxUkYA7eMcbH+maFCnVxx3xI05SzFTTXCZnok62BZ6MxmYt11AM/G4qCxidIpqfJuDXSm0fWVTgz+pBk0E7wFx/gMn4fRwLv4KTC+EXExxZbHVW6ClwuAOQJMjMWZEWC6GriJ31ByMZug56pOZx6WDD20wFdDT/DqKmDTDKrBq6BnOVDTESXgZ5Z/owGIus5Jx4wGPqy2aWuhV/6NsGbgGm6Wkk9iMVAM3NQM6huwKj+V1jfX6pSqJFIFrT1Oaj1WXmOF6R6/Bt2S+N2gWypZSqg7NOEsVbrlwLtC560QuoL3hqYeZWfnrrC2u4zxdNPgw9R/J2HZwda6xRr+f1d6OXQ2B/t3NU2D1z1fPMw9thrHBpS/AJT8Of7eVdPSoK3rntCtFZTev8tKfwHUBxjzil9I5gAAAABJRU5ErkJggg=="}" alt="" />`:""}
@@ -774,4 +774,4 @@ const Zs=e=>(t,s)=>{void 0!==s?s.addInitializer(()=>{customElements.define(e,t)}
774
774
  `:""}
775
775
  </div>
776
776
  </my-popover>
777
- `;Ws(i,this.rttHTML)}}const Pi=new class{constructor(){this.events={}}on(e,t){this.events[e]=this.events[e]||[],this.events[e].push(t)}off(e,t){this.events[e]=(this.events[e]||[]).filter(e=>e!==t)}emit(e,...t){(this.events[e]||[]).forEach(e=>e(...t))}};class Oi{static requestPermission(){"Notification"in window&&"default"===Notification.permission&&Notification.requestPermission()}static async requestMediaPermissions(){try{const e=await navigator.mediaDevices.enumerateDevices();if(e.some(e=>"audioinput"===e.kind&&""!==e.label))return console.log("已授权麦克风权限,无需再次获取"),null;const t=await navigator.mediaDevices.getUserMedia({audio:!0});return console.log("获取音频权限成功"),t}catch(e){return console.warn("获取音频权限失败:",e),null}}static show(e,t,s){if("Notification"in window&&"granted"===Notification.permission){const i=new Notification(e,{body:t,tag:"xy-global-notification",renotify:!0});i.onclick=()=>{window.focus(),i.close(),s?.()},setTimeout(()=>i.close(),5e3)}}static async checkMediaPermissions(){try{return(await navigator.mediaDevices.enumerateDevices()).some(e=>"audioinput"===e.kind&&""!==e.label)}catch(e){return console.warn("无法检查设备权限:",e),!1}}}let qi=null;class Li{constructor(e){this.url=e,this.ws=null,this.heartbeatWorker=null,this.reconnectDelay=3e3,this.manualClose=!1,this.apiClient=new Ni,this.initWebSocket()}static getInstance(e){if(!qi){if(!e)throw new Error("WebSocket 尚未初始化");qi=new Li(e)}return qi}stateIdleChange(){const{state:e}=pi.stateObject;e!==et.IDLE&&this.apiClient.changeState({data:{state:et.IDLE,state_name:"空闲"}})}putAgentState(){pi.sessionId="";const{post_call_process_time:e}=pi.agentInfo,t=e||0;pi.autoStateTimer&&(clearTimeout(pi.autoStateTimer),pi.autoStateTimer=null),t>0?pi.autoStateTimer=setTimeout(()=>{pi.autoStateTimer=null,this.stateIdleChange()},t):this.stateIdleChange()}initWebSocket(){this.ws=new WebSocket(this.url),this.ws.onopen=()=>{this.sendMessage({type:0}),this.startHeartbeat()},this.ws.onmessage=e=>{const t=JSON.parse(e.data),{type:s,data:i,code:r,msg:n}=t;if(0!==s&&console.warn(s),s===rt.OUT_CALL&&0!==r&&(ct.emit(it.OUT_FAILED,n),this.stateIdleChange()),s===rt.AGENT_STATE){const{state:e,state_name:t}=i;pi.stateObject={state:e,state_name:t},ct.emit(it.AGENT_STATE,{state:e,state_name:t})}s===rt.OUT_CALL_INCOMING_CALL&&(ct.emit(it.OUT_INCOMING_CALL,i),pi.sessionId=i.session_id,dt.updateActionConfigs(bi)),s===rt.OUT_CALL_END&&(0===i.device_type||1===i.device_type?(this.putAgentState(),dt.reset(),ct.emit(it.OUT_HANGUP,i)):2===i.device_type&&(dt.get("direction")===tt.CONSULT?(dt.reset(),ct.emit(it.OUR_SIDE_CONSULT_HANGUP,i),this.putAgentState()):dt.get("isCalling")&&(dt.updateDisplayText(ot.CALLING),ct.emit(it.OTHER_SIDE_CONSULT_HANGUP,i),dt.updateActionConfigs(Ti)))),s===rt.OUT_CALL_RINGING&&(ct.emit(it.OUT_RINGING,i),dt.updateDisplayText(ot.RINGING)),s===rt.OUT_CALL_ANSWER&&(ct.emit(it.OUT_OFF_ANSWER,i),dt.updateOutCallIsAnswer(!0),dt.updateDisplayText(ot.CALLING),dt.updateActionConfigs(Ti)),s===rt.CONSULT_RINGING&&(ct.emit(it.CONSULT_RINGING,i),dt.updateDisplayText(ot.AGENT_RINGING),dt.updateActionConfigs([])),s===rt.CONSULT_ANSWER&&(ct.emit(it.CONSULT_OFF_HOOK,i),dt.updateConsultIsAnswer(!0),dt.updateDisplayText(ot.CONSULTING),dt.updateActionConfigs(Si)),s===rt.CONSULT_FAIL&&(ct.emit(it.CONSULT_FAILED),dt.updateDisplayText(ot.CALLING),dt.updateActionConfigs(Ti)),s===rt.CONSULT_CALL_IN&&(ct.emit(it.CONSULT_INCOMING,i),dt.updateIsCalling(!0),dt.updateDirection(tt.CONSULT),dt.updateDisplayText(ot.CONSULT_CALL_IN),dt.updateActionConfigs(Ei),pi.enableBrowserAlert&&Oi.show("📞 咨询来电",`坐席 [${i.agent_name}] 正在咨询...`,()=>{ct.emit(nt.NOTIFICATION_CLICK,{agent_mane:i.agent_name})})),s===rt.CONSULT_CALL_IN_SUCCESS&&(pi.sessionId=i.session_id,ct.emit(it.CONSULT_CALL_IN_SUCCESS,i),dt.updateConsultIsAnswer(!0),dt.updateDisplayText(ot.CALLING),dt.updateActionConfigs(Ci)),s===rt.MUTE&&(0===r?(dt.updateIsMuted(!0),ct.emit(it.MUTE_SUCCESS)):ct.emit(it.MUTE_FAILED,n)),s===rt.UNMUTE&&(0===r?(dt.updateIsMuted(!1),ct.emit(it.UNMUTE_SUCCESS)):ct.emit(it.UNMUTE_FAILED,n)),s===rt.CONSULT_TRANSFER&&(0===r?ct.emit(it.CONSULT_TRANSFER_SUCCESS):ct.emit(it.CONSULT_TRANSFER_FAILED,n)),s===rt.CONSULT_TRANSFER_FAILED&&ct.emit(it.CONSULT_TRANSFER_FAILED,i.status),s===rt.CONSULT_TRANSFER_OFF_HOOK&&(dt.updateDirection(tt.INCOMING),dt.updateDisplayText(ot.CALLING),ct.emit(it.CONSULT_TRANSFER_OFF_HOOK),dt.updateActionConfigs(Ai),dt.updateIncomingIsAnswer(!0),dt.updateConsultIsAnswer(!1)),s===rt.INCOMING_CALL&&(pi.sessionId=i.session_id,dt.updateIsCalling(!0),dt.updateDirection(tt.INCOMING),dt.updateDisplayText(ot.INCOMING_CALL),ct.emit(it.INCOMING_CALL,{customer_phone:i.customer_phone}),dt.updateActionConfigs(Ei),pi.enableBrowserAlert&&Oi.show("📞 客户来电",`客户 [${i.customer_phone}] 正在呼入...`,()=>{ct.emit(nt.NOTIFICATION_CLICK,{customer_phone:i.customer_phone})})),s===rt.INCOMING_CALL_OFF_HOOK&&(dt.updateIncomingIsAnswer(!0),ct.emit(it.INCOMING_CALL_OFF_HOOK),dt.updateActionConfigs(Ai),dt.updateDisplayText(ot.CALLING)),s===rt.INCOMING_CALL_END&&(ct.emit(it.INCOMING_CALL_END),dt.reset(),dt.updateActionConfigs(wi),this.putAgentState()),0!==s&&Pi.emit("ws-message",t)},this.ws.onclose=()=>{this.stopHeartbeat(),this.manualClose||setTimeout(()=>this.initWebSocket(),this.reconnectDelay)},this.ws.onerror=()=>{this.ws?.close()}}startHeartbeat(){const e=new Blob(["\n let timer;\n self.onmessage = function (e) {\n if (e.data === 'start') {\n timer = setInterval(() => {\n self.postMessage('heartbeat');\n }, 14000);\n } else if (e.data === 'stop') {\n clearInterval(timer);\n }\n };\n "],{type:"application/javascript"}),t=URL.createObjectURL(e);this.heartbeatWorker=new Worker(t),this.heartbeatWorker.onmessage=()=>{this.sendMessage({type:0})},this.heartbeatWorker.postMessage("start")}stopHeartbeat(){this.heartbeatWorker&&(this.heartbeatWorker.postMessage("stop"),this.heartbeatWorker.terminate(),this.heartbeatWorker=null)}sendMessage(e){this.ws?.readyState===WebSocket.OPEN?this.ws.send(JSON.stringify(e)):console.warn("WebSocket 未连接,消息未发送")}close(){this.manualClose=!0,this.stopHeartbeat(),this.ws?.close()}static __internalClose(){qi&&(qi.close(),qi=null)}static __internalSend(e){if(!qi)throw new Error("WebSocket 尚未初始化");qi.sendMessage(e)}}module.exports=class{#e=null;#t=new Ni;#s=null;#i=!1;#r;constructor(){clearInterval(this.#s),this.#s=setInterval(async()=>{const e=await this.#n();fi.updateRttObject(e)},2e3),Oi.requestMediaPermissions(),window.addEventListener("beforeunload",()=>{this.destroy()}),this.#r=dt.subscribeKey("answerDevice",e=>{1===e&&this.initWebRtc()})}async initWebRtc(){const e=pi.agentInfo.sip_account_list.find(e=>1===e.device_type);if(e){const t=e.sip_register_addr;this.#e=new mi({server:t.split(":")[0],user:e.sip_account,password:e.sip_password,webSocket:`wss://${t}`,callTimeout:3e4},this.#o),await this.#e.start()}}async init({actionNodeParams:e,url:t,appKey:s,appSecret:i,agentNo:r,enableBrowserAlert:n}){try{const{viewHtmlElement:o,rttHTML:a}=e;di=t||"https://aicc-api.yescloudy.com",li=s,gi=i;const c=Ft(s,i);await this.#t._agentLogin(r);const{agent_no:h,current_answer_device:d,init_state:l}=pi.agentInfo;l===et.IDLE?(dt.updateActionConfigs(wi),pi.stateObject={state:l,state_name:"空闲"}):l===et.BUSY&&(dt.updateActionConfigs(yi),pi.stateObject={state:l,state_name:"忙碌"}),Li.getInstance(`ws://112.90.183.54:8719/api/v1/ws/call/${h}?Authorization=${c}`),dt.updateAnswerDevice(d),1===d&&await this.initWebRtc(),e&&o&&(this.#i=!0,new Hi({container:o,rttHTML:a,statusParams:{state:et.IDLE,statusName:"空闲"}},this)),pi.enableBrowserAlert=n,n&&Oi.requestPermission()}catch(e){this.#i&&oi("初始化失败"),console.log(e)}}#o=e=>{const{type:t,data:s}=e;ct.emit(t,s)};#a=e=>{};on(e,t){return ct.on(e,t),this}off(e,t){ct.off(e,t)}offAll(){ct.clearAllListeners()}#c(){if(!this.#e)throw new Error("请先初始化SDK");const e=dt.get("isCalling"),t=pi.sessionId;if(!e)throw new Error("当前没有通话");if(!t)throw new Error("sessionId不存在")}#h(){const e=dt.get("isHold"),{sessionId:t}=pi;if(t){if(e)throw new Error("当前已处于保持状态");Li.__internalSend({type:rt.CALL_HOLD,data:{session_id:t}}),dt.updateDisplayText(ot.HOLD),dt.updateIsHold(!0)}}#d(){const{isHold:e}=dt.getState(),{sessionId:t}=pi;if(t){if(!e)throw new Error("当前未处于保持状态");Li.__internalSend({type:rt.CALL_UNHOLD,data:{session_id:t}}),dt.updateDisplayText(""),dt.updateIsHold(!1)}}#l(e){if(!this.#e)throw new Error("请先初始化SDK");const{isCalling:t}=dt.getState();if(!t)throw new Error("当前没有通话");this.#e.sendDTMF(e)}#g(){if(1!==dt.get("answerDevice"))throw new Error("当前设备不支持此功能");if(!this.#e)throw new Error("请先初始化SDK");const{isCalling:e,direction:t,outCallIsAnswer:s}=dt.getState();if(!e)throw new Error("当前没有通话");s||(t===tt.INCOMING?this.#u():t===tt.OUTGOING&&this.#p())}async#f(e){if(!this.#e)throw new Error("请先初始化SDK");const{isCalling:t,outCallIsAnswer:s,consultIsAnswer:i,incomingIsAnswer:r}=dt.getState(),n=pi.sessionId;if(i)throw new Error("当前正在咨询");if(!(t||s||r))throw new Error("当前没有通话");if(!n)throw new Error("sessionId不存在");Li.__internalSend({type:rt.CONSULT_REQUEST,data:{session_id:n,consultation_agent_no:e}})}async#m(){if(1!==dt.get("answerDevice"))throw new Error("当前设备不支持此功能");if(!this.#e)throw new Error("请先初始化SDK");await this.#e.answerCall()}async#u(){if(!this.#e)throw new Error("请先初始化SDK");const{isCalling:e}=dt.getState();if(!e)throw new Error("当前没有通话");await this.#e.rejectInCall()}async#v(e){if(!this.#e)throw new Error("请先初始化SDK");if(dt.getState().isCalling)throw new Error("正在呼叫中,请勿重复点击");dt.updateIsCalling(!0),dt.updateDirection(tt.OUTGOING),Li.__internalSend({type:rt.OUT_CALL,data:{customer_phone:e}})}async#p(){const{isCalling:e}=dt.getState();if(!this.#e)throw new Error("请先初始化SDK");if(!e)throw new Error("当前没有通话");await this.#e.rejectOutCall()}async#w(){if(!this.#e)throw new Error("请先初始化SDK");if(!dt.get("isCalling"))throw new Error("当前没有通话");await this.#e.hangup()}#y(){this.#c();const e=dt.get("actionConfigs"),t=dt.get("isMuted"),s=pi.sessionId;if(t)throw new Error("当前未处于静音状态");if(!e.includes("mute"))throw new Error("当前状态请勿调用静音");Li.__internalSend({type:rt.MUTE,data:{session_id:s}})}#b(){this.#c();const e=dt.get("actionConfigs"),t=dt.get("isMuted"),s=pi.sessionId;if(!t)throw new Error("当前未处于未静音状态");if(!e.includes("unmute"))throw new Error("当前状态请勿调用静音");Li.__internalSend({type:rt.UNMUTE,data:{session_id:s}})}#T(){this.#c();const e=dt.get("consultIsAnswer"),t=pi.sessionId;if(!dt.get("actionConfigs").includes("consult_transfer"))throw new Error("当前状态请勿调用咨询转移");if(!e)throw new Error("当前未处于咨询中");Li.__internalSend({type:rt.CONSULT_TRANSFER,data:{session_id:t}})}async destroyRtc(){await(this.#e?.destroy())}destroy(){this.destroyRtc(),Pi.off("ws-message",this.#a),Li.__internalClose(),this.offAll(),this.#r?.()}async#n(){return this.#e?this.#e.getNetworkStats():{}}get call_api(){return this.#i?{answerCall:this.#m.bind(this),makeCall:this.#v.bind(this),cancelCall:this.#g.bind(this),hangup:this.#w.bind(this),sendDTMF:this.#l.bind(this),holdCall:this.#h.bind(this),unholdCall:this.#d.bind(this),consultCall:async e=>{try{await this.#f(e)}catch(e){throw console.warn(e),e}},consultTransfer:this.#T.bind(this),mute:this.#y.bind(this),unmute:this.#b.bind(this)}:{}}get agent_api(){return this.#i?{changeDevice:this.#t.changeDevice.bind(this.#t),changeState:this.#t.changeState.bind(this.#t),getIdleAgentList:e=>this.#t.getIdleAgentList(e),getAgentState:e=>this.#t.getAgentState(e)}:{}}};
777
+ `;Ws(i,this.rttHTML)}}const Pi=new class{constructor(){this.events={}}on(e,t){this.events[e]=this.events[e]||[],this.events[e].push(t)}off(e,t){this.events[e]=(this.events[e]||[]).filter(e=>e!==t)}emit(e,...t){(this.events[e]||[]).forEach(e=>e(...t))}};class Oi{static requestPermission(){"Notification"in window&&"default"===Notification.permission&&Notification.requestPermission()}static async requestMediaPermissions(){try{const e=await navigator.mediaDevices.enumerateDevices();if(e.some(e=>"audioinput"===e.kind&&""!==e.label))return console.log("已授权麦克风权限,无需再次获取"),null;const t=await navigator.mediaDevices.getUserMedia({audio:!0});return console.log("获取音频权限成功"),t}catch(e){return console.warn("获取音频权限失败:",e),null}}static show(e,t,s){if("Notification"in window&&"granted"===Notification.permission){const i=new Notification(e,{body:t,tag:"xy-global-notification",renotify:!0});i.onclick=()=>{window.focus(),i.close(),s?.()},setTimeout(()=>i.close(),5e3)}}static async checkMediaPermissions(){try{return(await navigator.mediaDevices.enumerateDevices()).some(e=>"audioinput"===e.kind&&""!==e.label)}catch(e){return console.warn("无法检查设备权限:",e),!1}}}let qi=null;class Li{constructor(e){this.url=e,this.ws=null,this.heartbeatWorker=null,this.reconnectDelay=3e3,this.manualClose=!1,this.apiClient=new Ni,this.initWebSocket()}static getInstance(e){if(!qi){if(!e)throw new Error("WebSocket 尚未初始化");qi=new Li(e)}return qi}stateIdleChange(){const{state:e}=pi.stateObject;e!==et.IDLE&&this.apiClient.changeState({data:{state:et.IDLE,state_name:"空闲"}})}putAgentState(){pi.sessionId="";const{post_call_process_time:e}=pi.agentInfo,t=e||0;pi.autoStateTimer&&(clearTimeout(pi.autoStateTimer),pi.autoStateTimer=null),t>0?pi.autoStateTimer=setTimeout(()=>{pi.autoStateTimer=null,this.stateIdleChange()},t):this.stateIdleChange()}initWebSocket(){this.ws=new WebSocket(this.url),this.ws.onopen=()=>{this.sendMessage({type:0}),this.startHeartbeat()},this.ws.onmessage=e=>{const t=JSON.parse(e.data),{type:s,data:i,code:r,msg:n}=t;if(0!==s&&console.warn(s),s===rt.OUT_CALL&&0!==r&&(ct.emit(it.OUT_FAILED,n),this.stateIdleChange()),s===rt.AGENT_STATE){const{state:e,state_name:t}=i;pi.stateObject={state:e,state_name:t},ct.emit(it.AGENT_STATE,{state:e,state_name:t})}s===rt.OUT_CALL_INCOMING_CALL&&(ct.emit(it.OUT_INCOMING_CALL,i),pi.sessionId=i.session_id,dt.updateActionConfigs(bi)),s===rt.OUT_CALL_END&&(0===i.device_type||1===i.device_type?(this.putAgentState(),dt.reset(),ct.emit(it.OUT_HANGUP,i)):2===i.device_type&&(dt.get("direction")===tt.CONSULT?(dt.reset(),ct.emit(it.OUR_SIDE_CONSULT_HANGUP,i),this.putAgentState()):dt.get("isCalling")&&(dt.updateDisplayText(ot.CALLING),ct.emit(it.OTHER_SIDE_CONSULT_HANGUP,i),dt.updateActionConfigs(Ti)))),s===rt.OUT_CALL_RINGING&&(ct.emit(it.OUT_RINGING,i),dt.updateDisplayText(ot.RINGING)),s===rt.OUT_CALL_ANSWER&&(ct.emit(it.OUT_OFF_ANSWER,i),dt.updateOutCallIsAnswer(!0),dt.updateDisplayText(ot.CALLING),dt.updateActionConfigs(Ti)),s===rt.CONSULT_RINGING&&(ct.emit(it.CONSULT_RINGING,i),dt.updateDisplayText(ot.AGENT_RINGING),dt.updateActionConfigs([])),s===rt.CONSULT_ANSWER&&(ct.emit(it.CONSULT_OFF_HOOK,i),dt.updateConsultIsAnswer(!0),dt.updateDisplayText(ot.CONSULTING),dt.updateActionConfigs(Si)),s===rt.CONSULT_FAIL&&(ct.emit(it.CONSULT_FAILED),dt.updateDisplayText(ot.CALLING),dt.updateActionConfigs(Ti)),s===rt.CONSULT_CALL_IN&&(ct.emit(it.CONSULT_INCOMING,i),dt.updateIsCalling(!0),dt.updateDirection(tt.CONSULT),dt.updateDisplayText(ot.CONSULT_CALL_IN),dt.updateActionConfigs(Ei),pi.enableBrowserAlert&&Oi.show("📞 咨询来电",`坐席 [${i.agent_name}] 正在咨询...`,()=>{ct.emit(nt.NOTIFICATION_CLICK,{agent_mane:i.agent_name})})),s===rt.CONSULT_CALL_IN_SUCCESS&&(pi.sessionId=i.session_id,ct.emit(it.CONSULT_CALL_IN_SUCCESS,i),dt.updateConsultIsAnswer(!0),dt.updateDisplayText(ot.CALLING),dt.updateActionConfigs(Ci)),s===rt.MUTE&&(0===r?(dt.updateIsMuted(!0),ct.emit(it.MUTE_SUCCESS)):ct.emit(it.MUTE_FAILED,n)),s===rt.UNMUTE&&(0===r?(dt.updateIsMuted(!1),ct.emit(it.UNMUTE_SUCCESS)):ct.emit(it.UNMUTE_FAILED,n)),s===rt.CONSULT_TRANSFER&&(0===r?ct.emit(it.CONSULT_TRANSFER_SUCCESS):ct.emit(it.CONSULT_TRANSFER_FAILED,n)),s===rt.CONSULT_TRANSFER_FAILED&&ct.emit(it.CONSULT_TRANSFER_FAILED,i.status),s===rt.CONSULT_TRANSFER_OFF_HOOK&&(dt.updateDirection(tt.INCOMING),dt.updateDisplayText(ot.CALLING),ct.emit(it.CONSULT_TRANSFER_OFF_HOOK),dt.updateActionConfigs(Ai),dt.updateIncomingIsAnswer(!0),dt.updateConsultIsAnswer(!1)),s===rt.INCOMING_CALL&&(pi.sessionId=i.session_id,dt.updateIsCalling(!0),dt.updateDirection(tt.INCOMING),dt.updateDisplayText(ot.INCOMING_CALL),ct.emit(it.INCOMING_CALL,{customer_phone:i.customer_phone}),dt.updateActionConfigs(Ei),pi.enableBrowserAlert&&Oi.show("📞 客户来电",`客户 [${i.customer_phone}] 正在呼入...`,()=>{ct.emit(nt.NOTIFICATION_CLICK,{customer_phone:i.customer_phone})})),s===rt.INCOMING_CALL_OFF_HOOK&&(dt.updateIncomingIsAnswer(!0),ct.emit(it.INCOMING_CALL_OFF_HOOK),dt.updateActionConfigs(Ai),dt.updateDisplayText(ot.CALLING)),s===rt.INCOMING_CALL_END&&(ct.emit(it.INCOMING_CALL_END),dt.reset(),dt.updateActionConfigs(wi),this.putAgentState()),0!==s&&Pi.emit("ws-message",t)},this.ws.onclose=()=>{this.stopHeartbeat(),this.manualClose||setTimeout(()=>this.initWebSocket(),this.reconnectDelay)},this.ws.onerror=()=>{this.ws?.close()}}startHeartbeat(){const e=new Blob(["\n let timer;\n self.onmessage = function (e) {\n if (e.data === 'start') {\n timer = setInterval(() => {\n self.postMessage('heartbeat');\n }, 14000);\n } else if (e.data === 'stop') {\n clearInterval(timer);\n }\n };\n "],{type:"application/javascript"}),t=URL.createObjectURL(e);this.heartbeatWorker=new Worker(t),this.heartbeatWorker.onmessage=()=>{this.sendMessage({type:0})},this.heartbeatWorker.postMessage("start")}stopHeartbeat(){this.heartbeatWorker&&(this.heartbeatWorker.postMessage("stop"),this.heartbeatWorker.terminate(),this.heartbeatWorker=null)}sendMessage(e){this.ws?.readyState===WebSocket.OPEN?this.ws.send(JSON.stringify(e)):console.warn("WebSocket 未连接,消息未发送")}close(){this.manualClose=!0,this.stopHeartbeat(),this.ws?.close()}static __internalClose(){qi&&(qi.close(),qi=null)}static __internalSend(e){if(!qi)throw new Error("WebSocket 尚未初始化");qi.sendMessage(e)}}module.exports=class{#e=null;#t=new Ni;#s=null;#i=!1;#r;constructor(){clearInterval(this.#s),this.#s=setInterval(async()=>{const e=await this.#n();fi.updateRttObject(e)},2e3),Oi.requestMediaPermissions(),window.addEventListener("beforeunload",()=>{this.destroy()}),this.#r=dt.subscribeKey("answerDevice",e=>{1===e&&this.initWebRtc()})}async initWebRtc(){const e=pi.agentInfo.sip_account_list.find(e=>1===e.device_type);if(e){const t=e.sip_register_addr;this.#e=new mi({server:t.split(":")[0],user:e.sip_account,password:e.sip_password,webSocket:`wss://${t}`,callTimeout:3e4},this.#o),await this.#e.start()}}async init({actionNodeParams:e,url:t,appKey:s,appSecret:i,agentNo:r,enableBrowserAlert:n}){try{const{viewHtmlElement:o,rttHTML:a}=e;di=t||"https://aicc-api.yescloudy.com",li=s,gi=i;const c=Ft(s,i);await this.#t._agentLogin(r);const{agent_no:h,current_answer_device:d,init_state:l}=pi.agentInfo;l===et.IDLE?(dt.updateActionConfigs(wi),pi.stateObject={state:l,state_name:"空闲"}):l===et.BUSY&&(dt.updateActionConfigs(yi),pi.stateObject={state:l,state_name:"忙碌"}),Li.getInstance(`ws://112.90.183.54:8719/api/v1/ws/call/${h}?Authorization=${c}`),dt.updateAnswerDevice(d),1===d&&await this.initWebRtc(),e&&o&&(this.#i=!0,new Hi({container:o,rttHTML:a,statusParams:{state:et.IDLE,statusName:"空闲"}},this)),pi.enableBrowserAlert=n,n&&Oi.requestPermission()}catch(e){this.#i&&oi("初始化失败"),console.log(e)}}#o=e=>{const{type:t,data:s}=e;ct.emit(t,s)};#a=e=>{};on(e,t){return ct.on(e,t),this}off(e,t){ct.off(e,t)}offAll(){ct.clearAllListeners()}#c(){if(!this.#e)throw new Error("请先初始化SDK");const e=dt.get("isCalling"),t=pi.sessionId;if(!e)throw new Error("当前没有通话");if(!t)throw new Error("sessionId不存在")}#h(){const e=dt.get("isHold"),{sessionId:t}=pi;if(t){if(e)throw new Error("当前已处于保持状态");Li.__internalSend({type:rt.CALL_HOLD,data:{session_id:t}}),dt.updateDisplayText(ot.HOLD),dt.updateIsHold(!0)}}#d(){const{isHold:e}=dt.getState(),{sessionId:t}=pi;if(t){if(!e)throw new Error("当前未处于保持状态");Li.__internalSend({type:rt.CALL_UNHOLD,data:{session_id:t}}),dt.updateDisplayText(""),dt.updateIsHold(!1)}}#l(e){if(!this.#e)throw new Error("请先初始化SDK");const{isCalling:t}=dt.getState();if(!t)throw new Error("当前没有通话");this.#e.sendDTMF(e)}#g(){if(1!==dt.get("answerDevice"))throw new Error("当前设备不支持此功能");if(!this.#e)throw new Error("请先初始化SDK");const{isCalling:e,direction:t,outCallIsAnswer:s}=dt.getState();if(!e)throw new Error("当前没有通话");s||(t===tt.INCOMING?this.#u():t===tt.OUTGOING&&this.#p())}async#f(e){if(!this.#e)throw new Error("请先初始化SDK");const{isCalling:t,outCallIsAnswer:s,consultIsAnswer:i,incomingIsAnswer:r}=dt.getState(),n=pi.sessionId;if(i)throw new Error("当前正在咨询");if(!(t||s||r))throw new Error("当前没有通话");if(!n)throw new Error("sessionId不存在");Li.__internalSend({type:rt.CONSULT_REQUEST,data:{session_id:n,consultation_agent_no:e}})}async#m(){if(1!==dt.get("answerDevice"))throw new Error("当前设备不支持此功能");if(!this.#e)throw new Error("请先初始化SDK");await this.#e.answerCall()}async#u(){if(!this.#e)throw new Error("请先初始化SDK");const{isCalling:e}=dt.getState();if(!e)throw new Error("当前没有通话");await this.#e.rejectInCall()}async#v(e){if(!this.#e)throw new Error("请先初始化SDK");if(dt.getState().isCalling)throw new Error("正在呼叫中,请勿重复点击");dt.updateIsCalling(!0),dt.updateDirection(tt.OUTGOING),Li.__internalSend({type:rt.OUT_CALL,data:{customer_phone:e}})}async#p(){const{isCalling:e}=dt.getState();if(!this.#e)throw new Error("请先初始化SDK");if(!e)throw new Error("当前没有通话");await this.#e.rejectOutCall()}async#w(){if(!this.#e)throw new Error("请先初始化SDK");if(!dt.get("isCalling"))throw new Error("当前没有通话");await this.#e.hangup()}#y(){this.#c();const e=dt.get("actionConfigs"),t=dt.get("isMuted"),s=pi.sessionId;if(t)throw new Error("当前未处于静音状态");if(!e.includes("mute"))throw new Error("当前状态请勿调用静音");Li.__internalSend({type:rt.MUTE,data:{session_id:s}})}#b(){this.#c();const e=dt.get("actionConfigs"),t=dt.get("isMuted"),s=pi.sessionId;if(!t)throw new Error("当前未处于未静音状态");if(!e.includes("unmute"))throw new Error("当前状态请勿调用静音");Li.__internalSend({type:rt.UNMUTE,data:{session_id:s}})}#T(){this.#c();const e=dt.get("consultIsAnswer"),t=pi.sessionId;if(!dt.get("actionConfigs").includes("consult_transfer"))throw new Error("当前状态请勿调用咨询转移");if(!e)throw new Error("当前未处于咨询中");Li.__internalSend({type:rt.CONSULT_TRANSFER,data:{session_id:t}})}async destroyRtc(){await(this.#e?.destroy())}destroy(){this.destroyRtc(),clearInterval(this.#s),Pi.off("ws-message",this.#a),Li.__internalClose(),this.offAll(),this.#r?.()}async#n(){return this.#e?this.#e.getNetworkStats():{}}get call_api(){return this.#i?{answerCall:this.#m.bind(this),makeCall:this.#v.bind(this),cancelCall:this.#g.bind(this),hangup:this.#w.bind(this),sendDTMF:this.#l.bind(this),holdCall:this.#h.bind(this),unholdCall:this.#d.bind(this),consultCall:async e=>{try{await this.#f(e)}catch(e){throw console.warn(e),e}},consultTransfer:this.#T.bind(this),mute:this.#y.bind(this),unmute:this.#b.bind(this)}:{}}get agent_api(){return this.#i?{changeDevice:this.#t.changeDevice.bind(this.#t),changeState:this.#t.changeState.bind(this.#t),getIdleAgentList:e=>this.#t.getIdleAgentList(e),getAgentState:e=>this.#t.getAgentState(e)}:{}}};
@@ -110,7 +110,7 @@ const Xs=e=>(t,s)=>{void 0!==s?s.addInitializer(()=>{customElements.define(e,t)}
110
110
  :host([type='loading']) {
111
111
  background: #595959;
112
112
  }
113
- `}connectedCallback(){super.connectedCallback(),setTimeout(()=>{this.remove()},this.duration+300)}render(){return xs`<div>${this.content}</div>`}};Bt([ti({type:String})],ri.prototype,"type",void 0),Bt([ti({type:String})],ri.prototype,"content",void 0),Bt([ti({type:Number})],ri.prototype,"duration",void 0),ri=Bt([Xs("my-message")],ri);const ni=(e,t,s=3e3)=>{let i=document.querySelector("#message-container");i||(i=document.createElement("div"),i.id="message-container",Object.assign(i.style,{position:"fixed",top:"14px",left:"50%",transform:"translateX(-50%)",zIndex:"9999"}),document.body.appendChild(i));const r=document.createElement("my-message");r.setAttribute("type",e),r.setAttribute("content",t),r.setAttribute("duration",String(s)),r.style.setProperty("--fade-delay",s/1e3+"s"),i.appendChild(r)},oi=(e,t=3e3)=>ni("success",e,t),ai=(e,t=3e3)=>ni("error",e,t),ci=(e,t=3e3)=>ni("warning",e,t),hi="/v1/aicc/bmserver",di="/v1/aicc/ccs";let li="",gi="",ui="";async function pi(e,t){const s=function(){const e=jt(gi,ui);return Lt.create({prefixUrl:`${li}/api`,timeout:!1,headers:{Authorization:e},hooks:{afterResponse:[async(e,t,s)=>{const i=await s.clone().json();if(0!==i.code)throw ai(i.msg),new Error(JSON.stringify(i)||"请求失败");return s.json=async()=>i,s}]}})}(),i=e.replace(/^\/+/,"");return s.post(i,{json:t}).json()}const fi={agentInfo:{},isRtcReconnecting:!1,sessionId:"",enableBrowserAlert:!1,autoStateTimer:null};const mi=new class extends Qe{updateRttObject(e){this.setState({rttObject:e})}}({rttObject:{rtt:null,jitter:null,packetsLost:null,packetsReceived:null,packetsSent:null,sendBitrate:null,recvBitrate:null,codec:null}});class vi{constructor(e,t){this.config=e,this.eventCallback=t,this.userAgent=null,this.registerer=null,this.activeSession=null,this.callTimeoutTimer=null,this.incomingInvitation=null,this.reconnectAttempts=0,this.maxReconnectAttempts=5,this.reconnectTimer=null,this.isOffline=!1,this.autoAnswerTimer=null,this.handleMessage=e=>{},this.handleNetworkInfoChange=e=>{0===(e.rttObject?.rtt||0)?this.isOffline||(this.isOffline=!0,this.handleOffline()):this.isOffline&&(this.isOffline=!1,this.handleOnline())},this.handleOffline=()=>{console.warn("[SIPClient] 网络断开,准备销毁 SIP 客户端",(new Date).toLocaleString()),this.destroy()},this.handleOnline=()=>{console.warn("[SIPClient] 网络恢复,准备重新启动 SIP 客户端",(new Date).toLocaleString()),this.reconnect()},mi.subscribe(this.handleNetworkInfoChange)}async start(){const e=Xe.makeURI(`sip:${this.config.user}@${this.config.server}`);if(!e)throw new Error("无效的SIP配置");const t={uri:e,authorizationUsername:this.config.user,authorizationPassword:this.config.password,transportOptions:{server:this.config.webSocket,connectionTimeout:30,keepAliveInterval:0},sessionDescriptionHandlerFactoryOptions:{alwaysAcquireMediaFirst:!0,peerConnectionConfiguration:{iceServers:[]},iceGatheringTimeout:400},logBuiltinEnabled:!1};this.userAgent=new Xe(t),this.setupEventListeners(),await this.userAgent.start(),await this.register()}setupEventListeners(){this.userAgent&&(this.userAgent.transport.stateChange.addListener(e=>{let t;switch(e){case ee.Connecting:t=st.WEB_RTC_CONNECTING;break;case ee.Connected:t=st.WEB_RTC_CONNECTED,this.reconnectAttempts=0,fi.isRtcReconnecting=!1,this.reconnectTimer&&(clearTimeout(this.reconnectTimer),this.reconnectTimer=null);break;case ee.Disconnecting:t=st.WEB_RTC_DISCONNECTING;break;case ee.Disconnected:{t=st.WEB_RTC_DISCONNECTED;const e=dt.get("answerDevice");if(!fi.isRtcReconnecting&&this.reconnectAttempts<this.maxReconnectAttempts&&1===e){this.reconnectAttempts++;const e=1e3*this.reconnectAttempts;console.warn(`SIP WebSocket 断开,第 ${this.reconnectAttempts} 次尝试重连,${e}ms 后重试...`),this.reconnectTimer=setTimeout(()=>{this.reconnect()},e)}else this.reconnectAttempts>=this.maxReconnectAttempts&&console.error("SIP 重连失败:已达到最大重试次数");break}default:t="unknown"}this.eventCallback?.({type:t})}),this.userAgent.transport.stateChange.addListener(e=>{}),this.userAgent.delegate={onInvite:e=>{this.handleIncomingCall(e)}})}async register(){if(this.userAgent){this.registerer=new ne(this.userAgent),this.registerer?.stateChange.addListener(e=>{let t;switch(e){case X.Initial:t="initial";break;case X.Registered:t=st.WEB_RTC_REGISTERED;break;case X.Unregistered:t=st.WEB_RTC_UNREGISTERED;break;case X.Terminated:t=st.WEB_RTC_TERMINATED;break;default:t="unknown"}this.eventCallback?.({type:t})});try{await this.registerer.register()}catch(e){this.eventCallback?.({type:st.WEB_RTC_REGISTER_FAILED,data:e})}}}attachRemoteAudio(e){const t=e.sessionDescriptionHandler;if(t){const e=t.peerConnection;if(!e)return;const s=new MediaStream;e.getReceivers().forEach(e=>{e.track&&"audio"===e.track.kind&&s.addTrack(e.track)});let i=document.getElementById("sip-remote-audio");i||(i=document.createElement("audio"),i.id="sip-remote-audio",i.autoplay=!0,i.style.display="none",document.body.appendChild(i)),i.srcObject=s,i.play().catch(e=>{console.error("音频播放失败,需要用户交互触发",e)})}}handleSessionState(e,t,s){e.stateChange.addListener(t=>{switch(t){case K.Established:clearTimeout(this.callTimeoutTimer),this.activeSession=e,this.attachRemoteAudio(e);break;case K.Terminating:break;case K.Terminated:this.activeSession=null,clearTimeout(this.callTimeoutTimer);case K.Establishing:}})}handleIncomingCall(e){this.incomingInvitation=e,this.handleSessionState(e,!1);const{soft_device_auto_answer:t,auto_answer_time:s}=fi.agentInfo,i=dt.get("direction"),r=1===t;if(i===tt.OUTGOING)this.answerCall();else if(r&&i===tt.INCOMING){const e=Number(s)||0;e>0?this.autoAnswerTimer=setTimeout(()=>{this.answerCall(),this.autoAnswerTimer=null},e):this.answerCall()}}async makeCall(e){if(dt.getState().isCalling)throw new Error("正在呼叫中,请勿重复点击");if(!this.userAgent)throw dt.updateIsCalling(!1),dt.updateDirection(null),new Error("SIP客户端未初始化");dt.updateIsCalling(!0),dt.updateDirection(tt.OUTGOING);const t=Xe.makeURI(`sip:${e}@${this.config.server}`);if(!t)throw new Error("无效的被叫号码");const s=new Z(this.userAgent,t);this.handleSessionState(s,!0,e);try{this.activeSession=s,await s.invite(),this.config.callTimeout&&(this.callTimeoutTimer=setTimeout(()=>{s.state!==K.Established&&(this.hangup(),this.eventCallback?.({type:"error",data:{message:"呼叫超时未接通"}}))},this.config.callTimeout))}catch(e){this.eventCallback?.({type:"error",data:{message:"呼叫失败",detail:e}}),dt.updateIsCalling(!1),dt.updateDirection(null)}}async answerCall(){if(!this.incomingInvitation)throw new Error("无来电可接听");this.autoAnswerTimer&&(clearTimeout(this.autoAnswerTimer),this.autoAnswerTimer=null);try{console.log((new Date).toLocaleString()),await this.incomingInvitation.accept(),console.log((new Date).toLocaleString()),this.activeSession=this.incomingInvitation,this.incomingInvitation=null}catch(e){this.eventCallback?.({type:st.WEB_RTC_ANSWER_FAILED,data:{detail:e}})}}async rejectInCall(){if(this.incomingInvitation)try{await this.incomingInvitation.reject(),this.incomingInvitation=null,dt.updateDirection(null),dt.updateIsCalling(!1),clearTimeout(this.callTimeoutTimer)}catch(e){this.eventCallback?.({type:"error",data:{message:"拒接失败",detail:e}})}}sendDTMF(e){if(!this.activeSession)throw new Error("当前没有活跃的通话");const t=this.activeSession.sessionDescriptionHandler;t&&"function"==typeof t.sendDtmf?(t.sendDtmf(e),this.eventCallback?.({type:st.WEB_RTC_SEND_DTMF,data:{tone:e}})):console.warn("DTMF发送不支持或未初始化")}async hangup(){if(this.activeSession){clearTimeout(this.callTimeoutTimer);const e=this.activeSession;if(!e)return;const t=e.state;try{t===K.Established?await e.bye():t===K.Establishing&&(e instanceof Z?await e.cancel():e instanceof J&&await e.reject()),clearTimeout(this.callTimeoutTimer)}catch(e){console.error("挂断失败",e)}finally{this.activeSession=null}}}async rejectOutCall(){this.activeSession instanceof J&&(await this.activeSession.reject(),this.activeSession=null)}async destroy(){if(clearTimeout(this.callTimeoutTimer),this.activeSession&&await this.hangup(),this.registerer){try{await this.registerer.unregister()}catch(e){console.warn("注销失败",e)}this.registerer=null}this.userAgent&&(await this.userAgent.stop(),this.userAgent=null)}async reconnect(){if(!fi.isRtcReconnecting){fi.isRtcReconnecting=!0;try{await this.destroy(),await this.start(),console.log("重连成功"),this.isOffline=!1}catch(e){console.error("重连失败",e)}finally{fi.isRtcReconnecting=!1}}}async getNetworkStats(){if(this.activeSession){const e=this.activeSession.sessionDescriptionHandler?.peerConnection;if(!e)return null;const t=await e.getStats(),s={};return t.forEach(e=>{"candidate-pair"===e.type&&"succeeded"===e.state&&null!=e.currentRoundTripTime&&(s.rtt=+(1e3*e.currentRoundTripTime).toFixed(2)),"inbound-rtp"===e.type&&"audio"===e.kind&&(s.jitter=+(1e3*e.jitter).toFixed(2),s.packetsLost=e.packetsLost,s.packetsReceived=e.packetsReceived,e.bytesReceived&&e.timestamp&&(s.recvBitrate=+(e.bytesReceived/1024).toFixed(2))),"outbound-rtp"===e.type&&"audio"===e.kind&&(s.packetsSent=e.packetsSent,e.bytesSent&&e.timestamp&&(s.sendBitrate=+(e.bytesSent/1024).toFixed(2))),"codec"===e.type&&e.mimeType&&(s.codec=e.mimeType)}),{...s,rtt:s?.rtt||40}}try{const e=Date.now();await pi(`${hi}/config/ping`,{});const t=Date.now();return{rtt:t-e||1}}catch(e){console.log(e)}}}const wi={statusColor:{[et.IDLE]:"#1D92E9",[et.BUSY]:"#F5212D",[et.OFFLINE]:"#8c8c8c",[et.RINGING]:"#e9b91d"}},yi=["call_number"],bi=[],Ti=["hangup"],Si=["hold","hangup","unhold","mute","unmute","transfer","consult","satisfaction","dtmf"],Ci=["consult_transfer"],Ei=["hangup"],Ai=["answer","reject"],_i=["hangup","consult","transfer","hold","unhold","mute","unmute","satisfaction","dtmf"];let Ii=class extends Js{static{this.styles=zt`
113
+ `}connectedCallback(){super.connectedCallback(),setTimeout(()=>{this.remove()},this.duration+300)}render(){return xs`<div>${this.content}</div>`}};Bt([ti({type:String})],ri.prototype,"type",void 0),Bt([ti({type:String})],ri.prototype,"content",void 0),Bt([ti({type:Number})],ri.prototype,"duration",void 0),ri=Bt([Xs("my-message")],ri);const ni=(e,t,s=3e3)=>{let i=document.querySelector("#message-container");i||(i=document.createElement("div"),i.id="message-container",Object.assign(i.style,{position:"fixed",top:"14px",left:"50%",transform:"translateX(-50%)",zIndex:"9999"}),document.body.appendChild(i));const r=document.createElement("my-message");r.setAttribute("type",e),r.setAttribute("content",t),r.setAttribute("duration",String(s)),r.style.setProperty("--fade-delay",s/1e3+"s"),i.appendChild(r)},oi=(e,t=3e3)=>ni("success",e,t),ai=(e,t=3e3)=>ni("error",e,t),ci=(e,t=3e3)=>ni("warning",e,t),hi="/v1/aicc/bmserver",di="/v1/aicc/ccs";let li="",gi="",ui="";async function pi(e,t){const s=function(){const e=jt(gi,ui);return Lt.create({prefixUrl:`${li}/api`,timeout:!1,headers:{Authorization:e},hooks:{afterResponse:[async(e,t,s)=>{const i=await s.clone().json();if(0!==i.code)throw ai(i.msg),new Error(JSON.stringify(i)||"请求失败");return s.json=async()=>i,s}]}})}(),i=e.replace(/^\/+/,"");return s.post(i,{json:t}).json()}const fi={agentInfo:{},isRtcReconnecting:!1,sessionId:"",enableBrowserAlert:!1,autoStateTimer:null};const mi=new class extends Qe{updateRttObject(e){this.setState({rttObject:e})}}({rttObject:{rtt:null,jitter:null,packetsLost:null,packetsReceived:null,packetsSent:null,sendBitrate:null,recvBitrate:null,codec:null}});class vi{constructor(e,t){this.config=e,this.eventCallback=t,this.userAgent=null,this.registerer=null,this.activeSession=null,this.callTimeoutTimer=null,this.incomingInvitation=null,this.reconnectAttempts=0,this.maxReconnectAttempts=5,this.reconnectTimer=null,this.isOffline=!1,this.autoAnswerTimer=null,this.handleMessage=e=>{},this.handleNetworkInfoChange=e=>{const t=e.rttObject?.rtt||0;console.log(t),0===t?this.isOffline||(this.isOffline=!0,this.handleOffline()):this.isOffline&&(this.isOffline=!1,this.handleOnline())},this.handleOffline=()=>{console.warn("[SIPClient] 网络断开,准备销毁 SIP 客户端",(new Date).toLocaleString())},this.handleOnline=()=>{console.warn("[SIPClient] 网络恢复,准备重新启动 SIP 客户端",(new Date).toLocaleString())},mi.subscribe(this.handleNetworkInfoChange)}async start(){const e=Xe.makeURI(`sip:${this.config.user}@${this.config.server}`);if(!e)throw new Error("无效的SIP配置");const t={uri:e,authorizationUsername:this.config.user,authorizationPassword:this.config.password,transportOptions:{server:this.config.webSocket,connectionTimeout:30,keepAliveInterval:0},sessionDescriptionHandlerFactoryOptions:{alwaysAcquireMediaFirst:!0,peerConnectionConfiguration:{iceServers:[]},iceGatheringTimeout:400},logBuiltinEnabled:!1};this.userAgent=new Xe(t),this.setupEventListeners(),await this.userAgent.start(),await this.register()}setupEventListeners(){this.userAgent&&(this.userAgent.transport.stateChange.addListener(e=>{let t;switch(e){case ee.Connecting:t=st.WEB_RTC_CONNECTING;break;case ee.Connected:t=st.WEB_RTC_CONNECTED,this.reconnectAttempts=0,fi.isRtcReconnecting=!1,this.reconnectTimer&&(clearTimeout(this.reconnectTimer),this.reconnectTimer=null);break;case ee.Disconnecting:t=st.WEB_RTC_DISCONNECTING;break;case ee.Disconnected:{t=st.WEB_RTC_DISCONNECTED;const e=dt.get("answerDevice");if(!fi.isRtcReconnecting&&this.reconnectAttempts<this.maxReconnectAttempts&&1===e){this.reconnectAttempts++;const e=1e3*this.reconnectAttempts;console.warn(`SIP WebSocket 断开,第 ${this.reconnectAttempts} 次尝试重连,${e}ms 后重试...`),this.reconnectTimer=setTimeout(()=>{this.reconnect()},e)}else this.reconnectAttempts>=this.maxReconnectAttempts&&console.error("SIP 重连失败:已达到最大重试次数");break}default:t="unknown"}this.eventCallback?.({type:t})}),this.userAgent.transport.stateChange.addListener(e=>{}),this.userAgent.delegate={onInvite:e=>{this.handleIncomingCall(e)}})}async register(){if(this.userAgent){this.registerer=new ne(this.userAgent),this.registerer?.stateChange.addListener(e=>{let t;switch(e){case X.Initial:t="initial";break;case X.Registered:t=st.WEB_RTC_REGISTERED;break;case X.Unregistered:t=st.WEB_RTC_UNREGISTERED;break;case X.Terminated:t=st.WEB_RTC_TERMINATED;break;default:t="unknown"}this.eventCallback?.({type:t})});try{await this.registerer.register()}catch(e){this.eventCallback?.({type:st.WEB_RTC_REGISTER_FAILED,data:e})}}}attachRemoteAudio(e){const t=e.sessionDescriptionHandler;if(t){const e=t.peerConnection;if(!e)return;const s=new MediaStream;e.getReceivers().forEach(e=>{e.track&&"audio"===e.track.kind&&s.addTrack(e.track)});let i=document.getElementById("sip-remote-audio");i||(i=document.createElement("audio"),i.id="sip-remote-audio",i.autoplay=!0,i.style.display="none",document.body.appendChild(i)),i.srcObject=s,i.play().catch(e=>{console.error("音频播放失败,需要用户交互触发",e)})}}handleSessionState(e,t,s){e.stateChange.addListener(t=>{switch(t){case K.Established:clearTimeout(this.callTimeoutTimer),this.activeSession=e,this.attachRemoteAudio(e);break;case K.Terminating:break;case K.Terminated:this.activeSession=null,clearTimeout(this.callTimeoutTimer);case K.Establishing:}})}handleIncomingCall(e){this.incomingInvitation=e,this.handleSessionState(e,!1);const{soft_device_auto_answer:t,auto_answer_time:s}=fi.agentInfo,i=dt.get("direction"),r=1===t;if(i===tt.OUTGOING)this.answerCall();else if(r&&i===tt.INCOMING){const e=Number(s)||0;e>0?this.autoAnswerTimer=setTimeout(()=>{this.answerCall(),this.autoAnswerTimer=null},e):this.answerCall()}}async makeCall(e){if(dt.getState().isCalling)throw new Error("正在呼叫中,请勿重复点击");if(!this.userAgent)throw dt.updateIsCalling(!1),dt.updateDirection(null),new Error("SIP客户端未初始化");dt.updateIsCalling(!0),dt.updateDirection(tt.OUTGOING);const t=Xe.makeURI(`sip:${e}@${this.config.server}`);if(!t)throw new Error("无效的被叫号码");const s=new Z(this.userAgent,t);this.handleSessionState(s,!0,e);try{this.activeSession=s,await s.invite(),this.config.callTimeout&&(this.callTimeoutTimer=setTimeout(()=>{s.state!==K.Established&&(this.hangup(),this.eventCallback?.({type:"error",data:{message:"呼叫超时未接通"}}))},this.config.callTimeout))}catch(e){this.eventCallback?.({type:"error",data:{message:"呼叫失败",detail:e}}),dt.updateIsCalling(!1),dt.updateDirection(null)}}async answerCall(){if(!this.incomingInvitation)throw new Error("无来电可接听");this.autoAnswerTimer&&(clearTimeout(this.autoAnswerTimer),this.autoAnswerTimer=null);try{console.log((new Date).toLocaleString()),await this.incomingInvitation.accept(),console.log((new Date).toLocaleString()),this.activeSession=this.incomingInvitation,this.incomingInvitation=null}catch(e){this.eventCallback?.({type:st.WEB_RTC_ANSWER_FAILED,data:{detail:e}})}}async rejectInCall(){if(this.incomingInvitation)try{await this.incomingInvitation.reject(),this.incomingInvitation=null,dt.updateDirection(null),dt.updateIsCalling(!1),clearTimeout(this.callTimeoutTimer)}catch(e){this.eventCallback?.({type:"error",data:{message:"拒接失败",detail:e}})}}sendDTMF(e){if(!this.activeSession)throw new Error("当前没有活跃的通话");const t=this.activeSession.sessionDescriptionHandler;t&&"function"==typeof t.sendDtmf?(t.sendDtmf(e),this.eventCallback?.({type:st.WEB_RTC_SEND_DTMF,data:{tone:e}})):console.warn("DTMF发送不支持或未初始化")}async hangup(){if(this.activeSession){clearTimeout(this.callTimeoutTimer);const e=this.activeSession;if(!e)return;const t=e.state;try{t===K.Established?await e.bye():t===K.Establishing&&(e instanceof Z?await e.cancel():e instanceof J&&await e.reject()),clearTimeout(this.callTimeoutTimer)}catch(e){console.error("挂断失败",e)}finally{this.activeSession=null}}}async rejectOutCall(){this.activeSession instanceof J&&(await this.activeSession.reject(),this.activeSession=null)}async destroy(){if(clearTimeout(this.callTimeoutTimer),this.activeSession&&await this.hangup(),this.registerer){try{await this.registerer.unregister()}catch(e){console.warn("注销失败",e)}this.registerer=null}this.userAgent&&(await this.userAgent.stop(),this.userAgent=null)}async reconnect(){if(!fi.isRtcReconnecting){fi.isRtcReconnecting=!0;try{await this.destroy(),await this.start(),console.log("重连成功"),this.isOffline=!1}catch(e){console.error("重连失败",e)}finally{fi.isRtcReconnecting=!1}}}async getNetworkStats(){if(this.activeSession){const e=this.activeSession.sessionDescriptionHandler?.peerConnection;if(!e)return null;const t=await e.getStats(),s={};return t.forEach(e=>{"candidate-pair"===e.type&&"succeeded"===e.state&&null!=e.currentRoundTripTime&&(s.rtt=+(1e3*e.currentRoundTripTime).toFixed(2)),"inbound-rtp"===e.type&&"audio"===e.kind&&(s.jitter=+(1e3*e.jitter).toFixed(2),s.packetsLost=e.packetsLost,s.packetsReceived=e.packetsReceived,e.bytesReceived&&e.timestamp&&(s.recvBitrate=+(e.bytesReceived/1024).toFixed(2))),"outbound-rtp"===e.type&&"audio"===e.kind&&(s.packetsSent=e.packetsSent,e.bytesSent&&e.timestamp&&(s.sendBitrate=+(e.bytesSent/1024).toFixed(2))),"codec"===e.type&&e.mimeType&&(s.codec=e.mimeType)}),{...s,rtt:s?.rtt||40}}try{const e=Date.now();await pi(`${hi}/config/ping`,{});const t=Date.now();return{rtt:t-e||1}}catch(e){console.log(e)}}}const wi={statusColor:{[et.IDLE]:"#1D92E9",[et.BUSY]:"#F5212D",[et.OFFLINE]:"#8c8c8c",[et.RINGING]:"#e9b91d"}},yi=["call_number"],bi=[],Ti=["hangup"],Si=["hold","hangup","unhold","mute","unmute","transfer","consult","satisfaction","dtmf"],Ci=["consult_transfer"],Ei=["hangup"],Ai=["answer","reject"],_i=["hangup","consult","transfer","hold","unhold","mute","unmute","satisfaction","dtmf"];let Ii=class extends Js{static{this.styles=zt`
114
114
  .timer-text {
115
115
  width: 70px;
116
116
  font-size: 14px;
@@ -658,16 +658,16 @@ const Xs=e=>(t,s)=>{void 0!==s?s.addInitializer(()=>{customElements.define(e,t)}
658
658
  </div>`}
659
659
  </div>
660
660
  </my-modal-wrapper>
661
- `;Ys(i,this.modalRoot)}})}catch(e){ai(e)}}getActionConfigs(){const{show_satisfaction:e}=fi.agentInfo,t=dt.get("isHold"),s=dt.get("isMuted"),i=dt.get("actionConfigs").filter(i=>(0!==e||"satisfaction"!==i)&&(!(!t&&"unhold"===i)&&((!t||"hold"!==i)&&((!s||"mute"!==i)&&!(!s&&"unmute"===i)))));return[{render:this.renderCallPopover,type:"call_number"},{render:this.renderAnswer,type:"answer"},{render:this.renderReject,type:"reject"},{render:this.renderHangup,type:"hangup"},{render:this.renderDialer,type:"dtmf"},{render:this.renderUnhold,type:"unhold"},{render:this.renderHold,type:"hold"},{render:this.renderMute,type:"mute"},{render:this.renderUnmute,type:"unmute"},{render:this.renderSatisfaction,type:"satisfaction"},{render:this.renderConsult,type:"consult"},{render:this.renderTransfer,type:"transfer"},{render:this.renderConsultTransfer,type:"consult_transfer"}].filter(({type:e})=>i.includes(e))}async render(){const{displayText:e,answerDevice:t}=dt.getState(),{default_device:s,answer_devices:i,show_satisfaction:r}=fi.agentInfo,n=(i||"").split(","),o=this.getActionConfigs(),a={...wi},{statusColor:c}=a,h=document.querySelector("head");if(h){const e=xs`
661
+ `;Ys(i,this.modalRoot)}})}catch(e){ai(e)}}getActionConfigs(){const{show_satisfaction:e}=fi.agentInfo,t=dt.get("isHold"),s=dt.get("isMuted"),i=dt.get("actionConfigs").filter(i=>(0!==e||"satisfaction"!==i)&&(!(!t&&"unhold"===i)&&((!t||"hold"!==i)&&((!s||"mute"!==i)&&!(!s&&"unmute"===i)))));return[{render:this.renderCallPopover,type:"call_number"},{render:this.renderAnswer,type:"answer"},{render:this.renderReject,type:"reject"},{render:this.renderHangup,type:"hangup"},{render:this.renderDialer,type:"dtmf"},{render:this.renderUnhold,type:"unhold"},{render:this.renderHold,type:"hold"},{render:this.renderMute,type:"mute"},{render:this.renderUnmute,type:"unmute"},{render:this.renderSatisfaction,type:"satisfaction"},{render:this.renderConsult,type:"consult"},{render:this.renderTransfer,type:"transfer"},{render:this.renderConsultTransfer,type:"consult_transfer"}].filter(({type:e})=>i.includes(e))}async render(){const{displayText:e}=dt.getState(),{default_device:t,answer_devices:s,show_satisfaction:i}=fi.agentInfo,r=(s||"").split(","),n=this.getActionConfigs(),o={...wi},{statusColor:a}=o,c=document.querySelector("head");if(c){const e=xs`
662
662
  <style>
663
663
  .ysyt-phone-body {
664
- background: ${c[this.statusParams.state]};
664
+ background: ${a[this.statusParams.state]};
665
665
  }
666
666
  .ysyt-action-body {
667
- border-bottom: 1px solid ${c[this.statusParams.state]};
667
+ border-bottom: 1px solid ${a[this.statusParams.state]};
668
668
  }
669
669
  </style>
670
- `;Ys(e,h)}const d=xs`
670
+ `;Ys(e,c)}const h=xs`
671
671
  <i class="ysyt icon-shang select-icon" style="${this.isOpenSelect?"display: block;":"display: none;"}"></i>
672
672
  <div
673
673
  class="ysyt-select"
@@ -684,30 +684,30 @@ const Xs=e=>(t,s)=>{void 0!==s?s.addInitializer(()=>{customElements.define(e,t)}
684
684
  `)}
685
685
  </div>
686
686
  </div>
687
- `,l=xs`
687
+ `,d=xs`
688
688
  <div id="ysyt-body">
689
689
  <div id="ysyt-devices-body">
690
690
  <my-select
691
691
  width="100px"
692
- value="${String(s)}"
692
+ value="${String(t)}"
693
693
  placeholder=""
694
694
  @change=${e=>this.onChangeDevices(Number(e.detail.value))}
695
695
  >
696
- ${n.includes("1")?xs`
696
+ ${r.includes("1")?xs`
697
697
  <select-option value="1">
698
698
  <div style="display: flex; align-items: center; gap: 8px;">
699
699
  <img src="${"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAC0AAAAtCAYAAAA6GuKaAAAAAXNSR0IArs4c6QAAAjhJREFUaEPtmM1WwjAQhWeAF0I34kZ5MuDJqBtxo7wQEE9CkzNNk8yktIl4YKOHRvPl9s5PBuEOP3iHzPCALvXWxEq/HBfvGmp2AfPz8/m0LQXp78NCa1gEtQF1hbUfVLirBZ6EXh3neweL0CjAnVZaodpoeIW4/lqemtKKB6E76rawFM48V2oPCM1heV7/CWircMoCr9+LrVa8hk16SufArH7mqoZNboKuZZMetLXG4enMZhatsl1fMij/F7RUuZwYGCvLRJWWQDtPA4DUTmOARwORg6bApdNeD1qaEWy6Kw2s31QwQxigRLWr4eNO3xPyGJfGLDRnoTH8G/of8d5DqX0MijvUVLCuwwxtwPmae14FWm/K+bZW3xENRKtUCsweqkZ7muwvODBJCzuFVdimiAu6GvmaheZKdY3KyELToIz5Nxe8d1lGaPCCH9KLsgia9s2xsk3BU8HprzOeb2/60pZADC0Bp2tMagqMGULBawJ+pt6k8FnQUhu4rNOmDg1vBG3BYorSv0upngXd8XdESZvi9AHpjMSlPmbs4I8vQiOKbOgccP8Alxk00uFOqkYMgh4CPqTIxFrkwdAlwCeBdj0KmflJ0xanfKphu0lpunEnY2QWi+BFJDG9Gg3a2cXLtznBZ+G5tnhUaH9TqqDUNvSNxcYSk0B34Iny5vvWOnaNfhP6d5PTydrU/XNS6F6h8Q8QMnNgHu4vKwLtb2qrJf3eKi4pPlWguXTHPX9AcwqN9fwulf4FD/s5TOGFiLYAAAAASUVORK5CYII="}" width="16" alt="" /><span style="font-size: 14px">软电话</span>
700
700
  </div>
701
701
  </select-option>
702
702
  `:""}
703
- ${n.includes("2")?xs`
703
+ ${r.includes("2")?xs`
704
704
  <select-option value="2">
705
705
  <div style="display: flex; align-items: center; gap: 8px;">
706
706
  <img src="${"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAC0AAAAtCAYAAAA6GuKaAAAAAXNSR0IArs4c6QAAAWtJREFUaEPtWdFNAzEMdW6Ewgo3BzBOYYi2Q0DHKcxxK0BHaNA7cIVEVD0n8Uck31dVOfbLyzvn9JxkwCcNiFmqQd8fl8eWDX9u5/fa9WbQm9dlnyZ5yFmaQF8BZzmcX+a9ZQMm0HfH5QSwKcnKUr7Ih6XYv9gkO/yHfF/b+YnNRYMGw4IiFczcAlOTlwf9tmQUPz/P9BqWOZwgYlm2aQAbgO7Msm5KZccSQoFGp7hkOUF7SeTAMsjGZZEd3hUX0CyI2jgX0GC6uWMUdqQt1AX0kJoO0H9k4to9gulgutCS9HIJeYQ8Qh7cV0j0aeUpukdBMSGPkMeNRhLyCHmEPIibdujLJcyawgm7+R7T9GPz9nx8bTHSgNQpAev2u1wuYBWuKWt+q+fMxruBtnjIVqN8tZEN3jdl9a5MjzgJAHA9RvzWuUvrC6kzHHYKsNa2Fr0ybl1Ysnh/rWPX6VYHnF1SmJnuUrUxyZCgvwFf6/M9kuThSwAAAABJRU5ErkJggg=="}" width="16" alt="" /><span style="font-size: 14px">手机模式</span>
707
707
  </div>
708
708
  </select-option>
709
709
  `:""}
710
- ${n.includes("3")?xs`
710
+ ${r.includes("3")?xs`
711
711
  <select-option value="3">
712
712
  <div style="display: flex; align-items: center; gap: 8px;">
713
713
  <img src="${"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAC0AAAAtCAYAAAA6GuKaAAAAAXNSR0IArs4c6QAAAq5JREFUaEPtmWFywiAQhcEr6Als79F6LdsZdab1WsZ7tJ7AXiF0lmYzC9mFDUGrM/qrmrB8PB7LQq25w4+9Q2bzgL7WrD2UvhmlF8/vr865jXXueD7tt1PAIBZtf/76aPA7PKPf4Xf6Pn2WtMdiud46YzZ9R9Y2P9+fqxLw+dPbwTgXQNvZbIUw8+XaGRJ/0LcxkDV2IJwIHTSytuk7LADnAGDgCOFns20P8NvPae+ZuEFiGxaadtIHpqqPBPcqEsh4plLQg/6tbVhoqZNYfY1VKBC1AwUfBf03+PDDBQg6KFCcTjUoB/Hoos7ag9gT2g+hESphgbGKUygUAKcds4TK0x1TEbTvqEBxaANtMSOhXZJKg4edO5rZrMFMUwxdCk4zgyZ70BkhsxR5WmEPyeOphUbboBXqQTM5M7eZ4ELjVPHKdikviEM3kkSeVilNO5GUE5Xudqx4kANoZpHDO8Hi7GZcD41bbmYT4Tah3KzUeM7viEqL5GxRA5CLIdYe/a5IiprBtHczorFRzQHI0AqL9DvdyFpk6gDkKo9YRMoKuS1/KpzUXl1PSxbIVXCXAM+eEft0JVjgPzJIFjooLYU8rAWvdXTLQsc1hmgTcpzi1kDNo5sKmhY58LdYY0RnSqydnbUv9Lg25ejm+9culKAm1tbaUfAaR7dR0HGxTk/O3MC9HUDh7mOt3QVXBgX1uFia5pQvKf6lmKWx1PaQKruc4pcQoQg6ziipxZmDHsRSlATF0AOPJ+41aoNPgu7BndtgGpPqlLHgqTiToREm3jxK4TWVYzVozuddTvWXhjeptJhdME/DzRK5u4gHEd9CpQZaVekYRLothTQZvEuugDW2uih04Hdafwhe0R7brgIdWAf+G9C2weV6yjbc+K4OrVmQuXce0DmFaj2/S6V/Ae/pt8oTAp/jAAAAAElFTkSuQmCC"}" width="16" alt="" /><span style="font-size: 14px">SIP话机</span>
@@ -727,14 +727,14 @@ const Xs=e=>(t,s)=>{void 0!==s?s.addInitializer(()=>{customElements.define(e,t)}
727
727
  <span>${t}</span>
728
728
  `:void 0)(this.statusParams)}
729
729
  <i class="ysyt icon-xia"></i>
730
- ${d}
730
+ ${h}
731
731
  `}
732
732
  </div>
733
733
  <timer-component id="my-timer"></timer-component>
734
734
  </div>
735
- <div class="ysyt-action-body">${o.map(e=>e.render())}</div>
735
+ <div class="ysyt-action-body">${n.map(e=>e.render())}</div>
736
736
  </div>
737
- `;Ys(l,this.container)}async renderRtt(e){const{outCallIsAnswer:t}=dt.getState(),s=e?.rtt||500,i=xs`
737
+ `;Ys(d,this.container)}async renderRtt(e){const{outCallIsAnswer:t}=dt.getState(),s=e?.rtt||500,i=xs`
738
738
  <my-popover triggerType="hover">
739
739
  <div slot="trigger" id="wifi-body">
740
740
  ${s>=250?xs`<img src="${"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAC0AAAAtCAYAAAA6GuKaAAAAAXNSR0IArs4c6QAAAlVJREFUaEPtmGFuwyAMhU2PtU1qOVmbk5FKW4+1TCawkcQYG2i3aM2fqirBn83zc1IDO7zMDpnhCf2oU+teaefcKYW31o69k6mGTuDOAWoBmwGNCVwBYKxNSAUdQDWQkiIPuMhae5EsxjUi6ARWUk1pbGrdIIFnoZWwqXbx+NPrqJAQLmXhSWghLELGo1U1m3MuSiFKLXc6JPwGOmyY28yD1jYQRSZIYAP+DV2obnfYdQIF+EV8Dx2AHVGJu8Mq4X3VDSMHUSe3WAV3L8eF0BNxs9XoNpwU2mF0CdwSv6fDxIeRWFrkyYEjNMoi+q9YDkKHyRUT41wlCRBxhqhptCDRWC24S41aRDIMcT2jaCKGZsXESr6aQmM1NRNUBK8Z46mE1tWMumX9W+DHxUkYA7eMcbH+maFCnVxx3xI05SzFTTXCZnok62BZ6MxmYt11AM/G4qCxidIpqfJuDXSm0fWVTgz+pBk0E7wFx/gMn4fRwLv4KTC+EXExxZbHVW6ClwuAOQJMjMWZEWC6GriJ31ByMZug56pOZx6WDD20wFdDT/DqKmDTDKrBq6BnOVDTESXgZ5Z/owGIus5Jx4wGPqy2aWuhV/6NsGbgGm6Wkk9iMVAM3NQM6huwKj+V1jfX6pSqJFIFrT1Oaj1WXmOF6R6/Bt2S+N2gWypZSqg7NOEsVbrlwLtC560QuoL3hqYeZWfnrrC2u4zxdNPgw9R/J2HZwda6xRr+f1d6OXQ2B/t3NU2D1z1fPMw9thrHBpS/AJT8Of7eVdPSoK3rntCtFZTev8tKfwHUBxjzil9I5gAAAABJRU5ErkJggg=="}" alt="" />`:""}
@@ -774,4 +774,4 @@ const Xs=e=>(t,s)=>{void 0!==s?s.addInitializer(()=>{customElements.define(e,t)}
774
774
  `:""}
775
775
  </div>
776
776
  </my-popover>
777
- `;Ys(i,this.rttHTML)}}const Oi=new class{constructor(){this.events={}}on(e,t){this.events[e]=this.events[e]||[],this.events[e].push(t)}off(e,t){this.events[e]=(this.events[e]||[]).filter(e=>e!==t)}emit(e,...t){(this.events[e]||[]).forEach(e=>e(...t))}};class qi{static requestPermission(){"Notification"in window&&"default"===Notification.permission&&Notification.requestPermission()}static async requestMediaPermissions(){try{const e=await navigator.mediaDevices.enumerateDevices();if(e.some(e=>"audioinput"===e.kind&&""!==e.label))return console.log("已授权麦克风权限,无需再次获取"),null;const t=await navigator.mediaDevices.getUserMedia({audio:!0});return console.log("获取音频权限成功"),t}catch(e){return console.warn("获取音频权限失败:",e),null}}static show(e,t,s){if("Notification"in window&&"granted"===Notification.permission){const i=new Notification(e,{body:t,tag:"xy-global-notification",renotify:!0});i.onclick=()=>{window.focus(),i.close(),s?.()},setTimeout(()=>i.close(),5e3)}}static async checkMediaPermissions(){try{return(await navigator.mediaDevices.enumerateDevices()).some(e=>"audioinput"===e.kind&&""!==e.label)}catch(e){return console.warn("无法检查设备权限:",e),!1}}}let Li=null;class Ui{constructor(e){this.url=e,this.ws=null,this.heartbeatWorker=null,this.reconnectDelay=3e3,this.manualClose=!1,this.apiClient=new Hi,this.initWebSocket()}static getInstance(e){if(!Li){if(!e)throw new Error("WebSocket 尚未初始化");Li=new Ui(e)}return Li}stateIdleChange(){const{state:e}=fi.stateObject;e!==et.IDLE&&this.apiClient.changeState({data:{state:et.IDLE,state_name:"空闲"}})}putAgentState(){fi.sessionId="";const{post_call_process_time:e}=fi.agentInfo,t=e||0;fi.autoStateTimer&&(clearTimeout(fi.autoStateTimer),fi.autoStateTimer=null),t>0?fi.autoStateTimer=setTimeout(()=>{fi.autoStateTimer=null,this.stateIdleChange()},t):this.stateIdleChange()}initWebSocket(){this.ws=new WebSocket(this.url),this.ws.onopen=()=>{this.sendMessage({type:0}),this.startHeartbeat()},this.ws.onmessage=e=>{const t=JSON.parse(e.data),{type:s,data:i,code:r,msg:n}=t;if(0!==s&&console.warn(s),s===rt.OUT_CALL&&0!==r&&(ct.emit(it.OUT_FAILED,n),this.stateIdleChange()),s===rt.AGENT_STATE){const{state:e,state_name:t}=i;fi.stateObject={state:e,state_name:t},ct.emit(it.AGENT_STATE,{state:e,state_name:t})}s===rt.OUT_CALL_INCOMING_CALL&&(ct.emit(it.OUT_INCOMING_CALL,i),fi.sessionId=i.session_id,dt.updateActionConfigs(Ti)),s===rt.OUT_CALL_END&&(0===i.device_type||1===i.device_type?(this.putAgentState(),dt.reset(),ct.emit(it.OUT_HANGUP,i)):2===i.device_type&&(dt.get("direction")===tt.CONSULT?(dt.reset(),ct.emit(it.OUR_SIDE_CONSULT_HANGUP,i),this.putAgentState()):dt.get("isCalling")&&(dt.updateDisplayText(ot.CALLING),ct.emit(it.OTHER_SIDE_CONSULT_HANGUP,i),dt.updateActionConfigs(Si)))),s===rt.OUT_CALL_RINGING&&(ct.emit(it.OUT_RINGING,i),dt.updateDisplayText(ot.RINGING)),s===rt.OUT_CALL_ANSWER&&(ct.emit(it.OUT_OFF_ANSWER,i),dt.updateOutCallIsAnswer(!0),dt.updateDisplayText(ot.CALLING),dt.updateActionConfigs(Si)),s===rt.CONSULT_RINGING&&(ct.emit(it.CONSULT_RINGING,i),dt.updateDisplayText(ot.AGENT_RINGING),dt.updateActionConfigs([])),s===rt.CONSULT_ANSWER&&(ct.emit(it.CONSULT_OFF_HOOK,i),dt.updateConsultIsAnswer(!0),dt.updateDisplayText(ot.CONSULTING),dt.updateActionConfigs(Ci)),s===rt.CONSULT_FAIL&&(ct.emit(it.CONSULT_FAILED),dt.updateDisplayText(ot.CALLING),dt.updateActionConfigs(Si)),s===rt.CONSULT_CALL_IN&&(ct.emit(it.CONSULT_INCOMING,i),dt.updateIsCalling(!0),dt.updateDirection(tt.CONSULT),dt.updateDisplayText(ot.CONSULT_CALL_IN),dt.updateActionConfigs(Ai),fi.enableBrowserAlert&&qi.show("📞 咨询来电",`坐席 [${i.agent_name}] 正在咨询...`,()=>{ct.emit(nt.NOTIFICATION_CLICK,{agent_mane:i.agent_name})})),s===rt.CONSULT_CALL_IN_SUCCESS&&(fi.sessionId=i.session_id,ct.emit(it.CONSULT_CALL_IN_SUCCESS,i),dt.updateConsultIsAnswer(!0),dt.updateDisplayText(ot.CALLING),dt.updateActionConfigs(Ei)),s===rt.MUTE&&(0===r?(dt.updateIsMuted(!0),ct.emit(it.MUTE_SUCCESS)):ct.emit(it.MUTE_FAILED,n)),s===rt.UNMUTE&&(0===r?(dt.updateIsMuted(!1),ct.emit(it.UNMUTE_SUCCESS)):ct.emit(it.UNMUTE_FAILED,n)),s===rt.CONSULT_TRANSFER&&(0===r?ct.emit(it.CONSULT_TRANSFER_SUCCESS):ct.emit(it.CONSULT_TRANSFER_FAILED,n)),s===rt.CONSULT_TRANSFER_FAILED&&ct.emit(it.CONSULT_TRANSFER_FAILED,i.status),s===rt.CONSULT_TRANSFER_OFF_HOOK&&(dt.updateDirection(tt.INCOMING),dt.updateDisplayText(ot.CALLING),ct.emit(it.CONSULT_TRANSFER_OFF_HOOK),dt.updateActionConfigs(_i),dt.updateIncomingIsAnswer(!0),dt.updateConsultIsAnswer(!1)),s===rt.INCOMING_CALL&&(fi.sessionId=i.session_id,dt.updateIsCalling(!0),dt.updateDirection(tt.INCOMING),dt.updateDisplayText(ot.INCOMING_CALL),ct.emit(it.INCOMING_CALL,{customer_phone:i.customer_phone}),dt.updateActionConfigs(Ai),fi.enableBrowserAlert&&qi.show("📞 客户来电",`客户 [${i.customer_phone}] 正在呼入...`,()=>{ct.emit(nt.NOTIFICATION_CLICK,{customer_phone:i.customer_phone})})),s===rt.INCOMING_CALL_OFF_HOOK&&(dt.updateIncomingIsAnswer(!0),ct.emit(it.INCOMING_CALL_OFF_HOOK),dt.updateActionConfigs(_i),dt.updateDisplayText(ot.CALLING)),s===rt.INCOMING_CALL_END&&(ct.emit(it.INCOMING_CALL_END),dt.reset(),dt.updateActionConfigs(yi),this.putAgentState()),0!==s&&Oi.emit("ws-message",t)},this.ws.onclose=()=>{this.stopHeartbeat(),this.manualClose||setTimeout(()=>this.initWebSocket(),this.reconnectDelay)},this.ws.onerror=()=>{this.ws?.close()}}startHeartbeat(){const e=new Blob(["\n let timer;\n self.onmessage = function (e) {\n if (e.data === 'start') {\n timer = setInterval(() => {\n self.postMessage('heartbeat');\n }, 14000);\n } else if (e.data === 'stop') {\n clearInterval(timer);\n }\n };\n "],{type:"application/javascript"}),t=URL.createObjectURL(e);this.heartbeatWorker=new Worker(t),this.heartbeatWorker.onmessage=()=>{this.sendMessage({type:0})},this.heartbeatWorker.postMessage("start")}stopHeartbeat(){this.heartbeatWorker&&(this.heartbeatWorker.postMessage("stop"),this.heartbeatWorker.terminate(),this.heartbeatWorker=null)}sendMessage(e){this.ws?.readyState===WebSocket.OPEN?this.ws.send(JSON.stringify(e)):console.warn("WebSocket 未连接,消息未发送")}close(){this.manualClose=!0,this.stopHeartbeat(),this.ws?.close()}static __internalClose(){Li&&(Li.close(),Li=null)}static __internalSend(e){if(!Li)throw new Error("WebSocket 尚未初始化");Li.sendMessage(e)}}class Mi{#e=null;#t=new Hi;#s=null;#i=!1;#r;constructor(){clearInterval(this.#s),this.#s=setInterval(async()=>{const e=await this.#n();mi.updateRttObject(e)},2e3),qi.requestMediaPermissions(),window.addEventListener("beforeunload",()=>{this.destroy()}),this.#r=dt.subscribeKey("answerDevice",e=>{1===e&&this.initWebRtc()})}async initWebRtc(){const e=fi.agentInfo.sip_account_list.find(e=>1===e.device_type);if(e){const t=e.sip_register_addr;this.#e=new vi({server:t.split(":")[0],user:e.sip_account,password:e.sip_password,webSocket:`wss://${t}`,callTimeout:3e4},this.#o),await this.#e.start()}}async init({actionNodeParams:e,url:t,appKey:s,appSecret:i,agentNo:r,enableBrowserAlert:n}){try{const{viewHtmlElement:o,rttHTML:a}=e;li=t||"https://aicc-api.yescloudy.com",gi=s,ui=i;const c=jt(s,i);await this.#t._agentLogin(r);const{agent_no:h,current_answer_device:d,init_state:l}=fi.agentInfo;l===et.IDLE?(dt.updateActionConfigs(yi),fi.stateObject={state:l,state_name:"空闲"}):l===et.BUSY&&(dt.updateActionConfigs(bi),fi.stateObject={state:l,state_name:"忙碌"}),Ui.getInstance(`ws://112.90.183.54:8719/api/v1/ws/call/${h}?Authorization=${c}`),dt.updateAnswerDevice(d),1===d&&await this.initWebRtc(),e&&o&&(this.#i=!0,new Pi({container:o,rttHTML:a,statusParams:{state:et.IDLE,statusName:"空闲"}},this)),fi.enableBrowserAlert=n,n&&qi.requestPermission()}catch(e){this.#i&&ai("初始化失败"),console.log(e)}}#o=e=>{const{type:t,data:s}=e;ct.emit(t,s)};#a=e=>{};on(e,t){return ct.on(e,t),this}off(e,t){ct.off(e,t)}offAll(){ct.clearAllListeners()}#c(){if(!this.#e)throw new Error("请先初始化SDK");const e=dt.get("isCalling"),t=fi.sessionId;if(!e)throw new Error("当前没有通话");if(!t)throw new Error("sessionId不存在")}#h(){const e=dt.get("isHold"),{sessionId:t}=fi;if(t){if(e)throw new Error("当前已处于保持状态");Ui.__internalSend({type:rt.CALL_HOLD,data:{session_id:t}}),dt.updateDisplayText(ot.HOLD),dt.updateIsHold(!0)}}#d(){const{isHold:e}=dt.getState(),{sessionId:t}=fi;if(t){if(!e)throw new Error("当前未处于保持状态");Ui.__internalSend({type:rt.CALL_UNHOLD,data:{session_id:t}}),dt.updateDisplayText(""),dt.updateIsHold(!1)}}#l(e){if(!this.#e)throw new Error("请先初始化SDK");const{isCalling:t}=dt.getState();if(!t)throw new Error("当前没有通话");this.#e.sendDTMF(e)}#g(){if(1!==dt.get("answerDevice"))throw new Error("当前设备不支持此功能");if(!this.#e)throw new Error("请先初始化SDK");const{isCalling:e,direction:t,outCallIsAnswer:s}=dt.getState();if(!e)throw new Error("当前没有通话");s||(t===tt.INCOMING?this.#u():t===tt.OUTGOING&&this.#p())}async#f(e){if(!this.#e)throw new Error("请先初始化SDK");const{isCalling:t,outCallIsAnswer:s,consultIsAnswer:i,incomingIsAnswer:r}=dt.getState(),n=fi.sessionId;if(i)throw new Error("当前正在咨询");if(!(t||s||r))throw new Error("当前没有通话");if(!n)throw new Error("sessionId不存在");Ui.__internalSend({type:rt.CONSULT_REQUEST,data:{session_id:n,consultation_agent_no:e}})}async#m(){if(1!==dt.get("answerDevice"))throw new Error("当前设备不支持此功能");if(!this.#e)throw new Error("请先初始化SDK");await this.#e.answerCall()}async#u(){if(!this.#e)throw new Error("请先初始化SDK");const{isCalling:e}=dt.getState();if(!e)throw new Error("当前没有通话");await this.#e.rejectInCall()}async#v(e){if(!this.#e)throw new Error("请先初始化SDK");if(dt.getState().isCalling)throw new Error("正在呼叫中,请勿重复点击");dt.updateIsCalling(!0),dt.updateDirection(tt.OUTGOING),Ui.__internalSend({type:rt.OUT_CALL,data:{customer_phone:e}})}async#p(){const{isCalling:e}=dt.getState();if(!this.#e)throw new Error("请先初始化SDK");if(!e)throw new Error("当前没有通话");await this.#e.rejectOutCall()}async#w(){if(!this.#e)throw new Error("请先初始化SDK");if(!dt.get("isCalling"))throw new Error("当前没有通话");await this.#e.hangup()}#y(){this.#c();const e=dt.get("actionConfigs"),t=dt.get("isMuted"),s=fi.sessionId;if(t)throw new Error("当前未处于静音状态");if(!e.includes("mute"))throw new Error("当前状态请勿调用静音");Ui.__internalSend({type:rt.MUTE,data:{session_id:s}})}#b(){this.#c();const e=dt.get("actionConfigs"),t=dt.get("isMuted"),s=fi.sessionId;if(!t)throw new Error("当前未处于未静音状态");if(!e.includes("unmute"))throw new Error("当前状态请勿调用静音");Ui.__internalSend({type:rt.UNMUTE,data:{session_id:s}})}#T(){this.#c();const e=dt.get("consultIsAnswer"),t=fi.sessionId;if(!dt.get("actionConfigs").includes("consult_transfer"))throw new Error("当前状态请勿调用咨询转移");if(!e)throw new Error("当前未处于咨询中");Ui.__internalSend({type:rt.CONSULT_TRANSFER,data:{session_id:t}})}async destroyRtc(){await(this.#e?.destroy())}destroy(){this.destroyRtc(),Oi.off("ws-message",this.#a),Ui.__internalClose(),this.offAll(),this.#r?.()}async#n(){return this.#e?this.#e.getNetworkStats():{}}get call_api(){return this.#i?{answerCall:this.#m.bind(this),makeCall:this.#v.bind(this),cancelCall:this.#g.bind(this),hangup:this.#w.bind(this),sendDTMF:this.#l.bind(this),holdCall:this.#h.bind(this),unholdCall:this.#d.bind(this),consultCall:async e=>{try{await this.#f(e)}catch(e){throw console.warn(e),e}},consultTransfer:this.#T.bind(this),mute:this.#y.bind(this),unmute:this.#b.bind(this)}:{}}get agent_api(){return this.#i?{changeDevice:this.#t.changeDevice.bind(this.#t),changeState:this.#t.changeState.bind(this.#t),getIdleAgentList:e=>this.#t.getIdleAgentList(e),getAgentState:e=>this.#t.getAgentState(e)}:{}}}export{Mi as default};
777
+ `;Ys(i,this.rttHTML)}}const Oi=new class{constructor(){this.events={}}on(e,t){this.events[e]=this.events[e]||[],this.events[e].push(t)}off(e,t){this.events[e]=(this.events[e]||[]).filter(e=>e!==t)}emit(e,...t){(this.events[e]||[]).forEach(e=>e(...t))}};class qi{static requestPermission(){"Notification"in window&&"default"===Notification.permission&&Notification.requestPermission()}static async requestMediaPermissions(){try{const e=await navigator.mediaDevices.enumerateDevices();if(e.some(e=>"audioinput"===e.kind&&""!==e.label))return console.log("已授权麦克风权限,无需再次获取"),null;const t=await navigator.mediaDevices.getUserMedia({audio:!0});return console.log("获取音频权限成功"),t}catch(e){return console.warn("获取音频权限失败:",e),null}}static show(e,t,s){if("Notification"in window&&"granted"===Notification.permission){const i=new Notification(e,{body:t,tag:"xy-global-notification",renotify:!0});i.onclick=()=>{window.focus(),i.close(),s?.()},setTimeout(()=>i.close(),5e3)}}static async checkMediaPermissions(){try{return(await navigator.mediaDevices.enumerateDevices()).some(e=>"audioinput"===e.kind&&""!==e.label)}catch(e){return console.warn("无法检查设备权限:",e),!1}}}let Li=null;class Ui{constructor(e){this.url=e,this.ws=null,this.heartbeatWorker=null,this.reconnectDelay=3e3,this.manualClose=!1,this.apiClient=new Hi,this.initWebSocket()}static getInstance(e){if(!Li){if(!e)throw new Error("WebSocket 尚未初始化");Li=new Ui(e)}return Li}stateIdleChange(){const{state:e}=fi.stateObject;e!==et.IDLE&&this.apiClient.changeState({data:{state:et.IDLE,state_name:"空闲"}})}putAgentState(){fi.sessionId="";const{post_call_process_time:e}=fi.agentInfo,t=e||0;fi.autoStateTimer&&(clearTimeout(fi.autoStateTimer),fi.autoStateTimer=null),t>0?fi.autoStateTimer=setTimeout(()=>{fi.autoStateTimer=null,this.stateIdleChange()},t):this.stateIdleChange()}initWebSocket(){this.ws=new WebSocket(this.url),this.ws.onopen=()=>{this.sendMessage({type:0}),this.startHeartbeat()},this.ws.onmessage=e=>{const t=JSON.parse(e.data),{type:s,data:i,code:r,msg:n}=t;if(0!==s&&console.warn(s),s===rt.OUT_CALL&&0!==r&&(ct.emit(it.OUT_FAILED,n),this.stateIdleChange()),s===rt.AGENT_STATE){const{state:e,state_name:t}=i;fi.stateObject={state:e,state_name:t},ct.emit(it.AGENT_STATE,{state:e,state_name:t})}s===rt.OUT_CALL_INCOMING_CALL&&(ct.emit(it.OUT_INCOMING_CALL,i),fi.sessionId=i.session_id,dt.updateActionConfigs(Ti)),s===rt.OUT_CALL_END&&(0===i.device_type||1===i.device_type?(this.putAgentState(),dt.reset(),ct.emit(it.OUT_HANGUP,i)):2===i.device_type&&(dt.get("direction")===tt.CONSULT?(dt.reset(),ct.emit(it.OUR_SIDE_CONSULT_HANGUP,i),this.putAgentState()):dt.get("isCalling")&&(dt.updateDisplayText(ot.CALLING),ct.emit(it.OTHER_SIDE_CONSULT_HANGUP,i),dt.updateActionConfigs(Si)))),s===rt.OUT_CALL_RINGING&&(ct.emit(it.OUT_RINGING,i),dt.updateDisplayText(ot.RINGING)),s===rt.OUT_CALL_ANSWER&&(ct.emit(it.OUT_OFF_ANSWER,i),dt.updateOutCallIsAnswer(!0),dt.updateDisplayText(ot.CALLING),dt.updateActionConfigs(Si)),s===rt.CONSULT_RINGING&&(ct.emit(it.CONSULT_RINGING,i),dt.updateDisplayText(ot.AGENT_RINGING),dt.updateActionConfigs([])),s===rt.CONSULT_ANSWER&&(ct.emit(it.CONSULT_OFF_HOOK,i),dt.updateConsultIsAnswer(!0),dt.updateDisplayText(ot.CONSULTING),dt.updateActionConfigs(Ci)),s===rt.CONSULT_FAIL&&(ct.emit(it.CONSULT_FAILED),dt.updateDisplayText(ot.CALLING),dt.updateActionConfigs(Si)),s===rt.CONSULT_CALL_IN&&(ct.emit(it.CONSULT_INCOMING,i),dt.updateIsCalling(!0),dt.updateDirection(tt.CONSULT),dt.updateDisplayText(ot.CONSULT_CALL_IN),dt.updateActionConfigs(Ai),fi.enableBrowserAlert&&qi.show("📞 咨询来电",`坐席 [${i.agent_name}] 正在咨询...`,()=>{ct.emit(nt.NOTIFICATION_CLICK,{agent_mane:i.agent_name})})),s===rt.CONSULT_CALL_IN_SUCCESS&&(fi.sessionId=i.session_id,ct.emit(it.CONSULT_CALL_IN_SUCCESS,i),dt.updateConsultIsAnswer(!0),dt.updateDisplayText(ot.CALLING),dt.updateActionConfigs(Ei)),s===rt.MUTE&&(0===r?(dt.updateIsMuted(!0),ct.emit(it.MUTE_SUCCESS)):ct.emit(it.MUTE_FAILED,n)),s===rt.UNMUTE&&(0===r?(dt.updateIsMuted(!1),ct.emit(it.UNMUTE_SUCCESS)):ct.emit(it.UNMUTE_FAILED,n)),s===rt.CONSULT_TRANSFER&&(0===r?ct.emit(it.CONSULT_TRANSFER_SUCCESS):ct.emit(it.CONSULT_TRANSFER_FAILED,n)),s===rt.CONSULT_TRANSFER_FAILED&&ct.emit(it.CONSULT_TRANSFER_FAILED,i.status),s===rt.CONSULT_TRANSFER_OFF_HOOK&&(dt.updateDirection(tt.INCOMING),dt.updateDisplayText(ot.CALLING),ct.emit(it.CONSULT_TRANSFER_OFF_HOOK),dt.updateActionConfigs(_i),dt.updateIncomingIsAnswer(!0),dt.updateConsultIsAnswer(!1)),s===rt.INCOMING_CALL&&(fi.sessionId=i.session_id,dt.updateIsCalling(!0),dt.updateDirection(tt.INCOMING),dt.updateDisplayText(ot.INCOMING_CALL),ct.emit(it.INCOMING_CALL,{customer_phone:i.customer_phone}),dt.updateActionConfigs(Ai),fi.enableBrowserAlert&&qi.show("📞 客户来电",`客户 [${i.customer_phone}] 正在呼入...`,()=>{ct.emit(nt.NOTIFICATION_CLICK,{customer_phone:i.customer_phone})})),s===rt.INCOMING_CALL_OFF_HOOK&&(dt.updateIncomingIsAnswer(!0),ct.emit(it.INCOMING_CALL_OFF_HOOK),dt.updateActionConfigs(_i),dt.updateDisplayText(ot.CALLING)),s===rt.INCOMING_CALL_END&&(ct.emit(it.INCOMING_CALL_END),dt.reset(),dt.updateActionConfigs(yi),this.putAgentState()),0!==s&&Oi.emit("ws-message",t)},this.ws.onclose=()=>{this.stopHeartbeat(),this.manualClose||setTimeout(()=>this.initWebSocket(),this.reconnectDelay)},this.ws.onerror=()=>{this.ws?.close()}}startHeartbeat(){const e=new Blob(["\n let timer;\n self.onmessage = function (e) {\n if (e.data === 'start') {\n timer = setInterval(() => {\n self.postMessage('heartbeat');\n }, 14000);\n } else if (e.data === 'stop') {\n clearInterval(timer);\n }\n };\n "],{type:"application/javascript"}),t=URL.createObjectURL(e);this.heartbeatWorker=new Worker(t),this.heartbeatWorker.onmessage=()=>{this.sendMessage({type:0})},this.heartbeatWorker.postMessage("start")}stopHeartbeat(){this.heartbeatWorker&&(this.heartbeatWorker.postMessage("stop"),this.heartbeatWorker.terminate(),this.heartbeatWorker=null)}sendMessage(e){this.ws?.readyState===WebSocket.OPEN?this.ws.send(JSON.stringify(e)):console.warn("WebSocket 未连接,消息未发送")}close(){this.manualClose=!0,this.stopHeartbeat(),this.ws?.close()}static __internalClose(){Li&&(Li.close(),Li=null)}static __internalSend(e){if(!Li)throw new Error("WebSocket 尚未初始化");Li.sendMessage(e)}}class Mi{#e=null;#t=new Hi;#s=null;#i=!1;#r;constructor(){clearInterval(this.#s),this.#s=setInterval(async()=>{const e=await this.#n();mi.updateRttObject(e)},2e3),qi.requestMediaPermissions(),window.addEventListener("beforeunload",()=>{this.destroy()}),this.#r=dt.subscribeKey("answerDevice",e=>{1===e&&this.initWebRtc()})}async initWebRtc(){const e=fi.agentInfo.sip_account_list.find(e=>1===e.device_type);if(e){const t=e.sip_register_addr;this.#e=new vi({server:t.split(":")[0],user:e.sip_account,password:e.sip_password,webSocket:`wss://${t}`,callTimeout:3e4},this.#o),await this.#e.start()}}async init({actionNodeParams:e,url:t,appKey:s,appSecret:i,agentNo:r,enableBrowserAlert:n}){try{const{viewHtmlElement:o,rttHTML:a}=e;li=t||"https://aicc-api.yescloudy.com",gi=s,ui=i;const c=jt(s,i);await this.#t._agentLogin(r);const{agent_no:h,current_answer_device:d,init_state:l}=fi.agentInfo;l===et.IDLE?(dt.updateActionConfigs(yi),fi.stateObject={state:l,state_name:"空闲"}):l===et.BUSY&&(dt.updateActionConfigs(bi),fi.stateObject={state:l,state_name:"忙碌"}),Ui.getInstance(`ws://112.90.183.54:8719/api/v1/ws/call/${h}?Authorization=${c}`),dt.updateAnswerDevice(d),1===d&&await this.initWebRtc(),e&&o&&(this.#i=!0,new Pi({container:o,rttHTML:a,statusParams:{state:et.IDLE,statusName:"空闲"}},this)),fi.enableBrowserAlert=n,n&&qi.requestPermission()}catch(e){this.#i&&ai("初始化失败"),console.log(e)}}#o=e=>{const{type:t,data:s}=e;ct.emit(t,s)};#a=e=>{};on(e,t){return ct.on(e,t),this}off(e,t){ct.off(e,t)}offAll(){ct.clearAllListeners()}#c(){if(!this.#e)throw new Error("请先初始化SDK");const e=dt.get("isCalling"),t=fi.sessionId;if(!e)throw new Error("当前没有通话");if(!t)throw new Error("sessionId不存在")}#h(){const e=dt.get("isHold"),{sessionId:t}=fi;if(t){if(e)throw new Error("当前已处于保持状态");Ui.__internalSend({type:rt.CALL_HOLD,data:{session_id:t}}),dt.updateDisplayText(ot.HOLD),dt.updateIsHold(!0)}}#d(){const{isHold:e}=dt.getState(),{sessionId:t}=fi;if(t){if(!e)throw new Error("当前未处于保持状态");Ui.__internalSend({type:rt.CALL_UNHOLD,data:{session_id:t}}),dt.updateDisplayText(""),dt.updateIsHold(!1)}}#l(e){if(!this.#e)throw new Error("请先初始化SDK");const{isCalling:t}=dt.getState();if(!t)throw new Error("当前没有通话");this.#e.sendDTMF(e)}#g(){if(1!==dt.get("answerDevice"))throw new Error("当前设备不支持此功能");if(!this.#e)throw new Error("请先初始化SDK");const{isCalling:e,direction:t,outCallIsAnswer:s}=dt.getState();if(!e)throw new Error("当前没有通话");s||(t===tt.INCOMING?this.#u():t===tt.OUTGOING&&this.#p())}async#f(e){if(!this.#e)throw new Error("请先初始化SDK");const{isCalling:t,outCallIsAnswer:s,consultIsAnswer:i,incomingIsAnswer:r}=dt.getState(),n=fi.sessionId;if(i)throw new Error("当前正在咨询");if(!(t||s||r))throw new Error("当前没有通话");if(!n)throw new Error("sessionId不存在");Ui.__internalSend({type:rt.CONSULT_REQUEST,data:{session_id:n,consultation_agent_no:e}})}async#m(){if(1!==dt.get("answerDevice"))throw new Error("当前设备不支持此功能");if(!this.#e)throw new Error("请先初始化SDK");await this.#e.answerCall()}async#u(){if(!this.#e)throw new Error("请先初始化SDK");const{isCalling:e}=dt.getState();if(!e)throw new Error("当前没有通话");await this.#e.rejectInCall()}async#v(e){if(!this.#e)throw new Error("请先初始化SDK");if(dt.getState().isCalling)throw new Error("正在呼叫中,请勿重复点击");dt.updateIsCalling(!0),dt.updateDirection(tt.OUTGOING),Ui.__internalSend({type:rt.OUT_CALL,data:{customer_phone:e}})}async#p(){const{isCalling:e}=dt.getState();if(!this.#e)throw new Error("请先初始化SDK");if(!e)throw new Error("当前没有通话");await this.#e.rejectOutCall()}async#w(){if(!this.#e)throw new Error("请先初始化SDK");if(!dt.get("isCalling"))throw new Error("当前没有通话");await this.#e.hangup()}#y(){this.#c();const e=dt.get("actionConfigs"),t=dt.get("isMuted"),s=fi.sessionId;if(t)throw new Error("当前未处于静音状态");if(!e.includes("mute"))throw new Error("当前状态请勿调用静音");Ui.__internalSend({type:rt.MUTE,data:{session_id:s}})}#b(){this.#c();const e=dt.get("actionConfigs"),t=dt.get("isMuted"),s=fi.sessionId;if(!t)throw new Error("当前未处于未静音状态");if(!e.includes("unmute"))throw new Error("当前状态请勿调用静音");Ui.__internalSend({type:rt.UNMUTE,data:{session_id:s}})}#T(){this.#c();const e=dt.get("consultIsAnswer"),t=fi.sessionId;if(!dt.get("actionConfigs").includes("consult_transfer"))throw new Error("当前状态请勿调用咨询转移");if(!e)throw new Error("当前未处于咨询中");Ui.__internalSend({type:rt.CONSULT_TRANSFER,data:{session_id:t}})}async destroyRtc(){await(this.#e?.destroy())}destroy(){this.destroyRtc(),clearInterval(this.#s),Oi.off("ws-message",this.#a),Ui.__internalClose(),this.offAll(),this.#r?.()}async#n(){return this.#e?this.#e.getNetworkStats():{}}get call_api(){return this.#i?{answerCall:this.#m.bind(this),makeCall:this.#v.bind(this),cancelCall:this.#g.bind(this),hangup:this.#w.bind(this),sendDTMF:this.#l.bind(this),holdCall:this.#h.bind(this),unholdCall:this.#d.bind(this),consultCall:async e=>{try{await this.#f(e)}catch(e){throw console.warn(e),e}},consultTransfer:this.#T.bind(this),mute:this.#y.bind(this),unmute:this.#b.bind(this)}:{}}get agent_api(){return this.#i?{changeDevice:this.#t.changeDevice.bind(this.#t),changeState:this.#t.changeState.bind(this.#t),getIdleAgentList:e=>this.#t.getIdleAgentList(e),getAgentState:e=>this.#t.getAgentState(e)}:{}}}export{Mi as default};
@@ -110,7 +110,7 @@ const Zs=e=>(t,s)=>{void 0!==s?s.addInitializer(()=>{customElements.define(e,t)}
110
110
  :host([type='loading']) {
111
111
  background: #595959;
112
112
  }
113
- `}connectedCallback(){super.connectedCallback(),setTimeout(()=>{this.remove()},this.duration+300)}render(){return Ds`<div>${this.content}</div>`}};jt([ei({type:String})],ii.prototype,"type",void 0),jt([ei({type:String})],ii.prototype,"content",void 0),jt([ei({type:Number})],ii.prototype,"duration",void 0),ii=jt([Zs("my-message")],ii);const ri=(e,t,s=3e3)=>{let i=document.querySelector("#message-container");i||(i=document.createElement("div"),i.id="message-container",Object.assign(i.style,{position:"fixed",top:"14px",left:"50%",transform:"translateX(-50%)",zIndex:"9999"}),document.body.appendChild(i));const r=document.createElement("my-message");r.setAttribute("type",e),r.setAttribute("content",t),r.setAttribute("duration",String(s)),r.style.setProperty("--fade-delay",s/1e3+"s"),i.appendChild(r)},ni=(e,t=3e3)=>ri("success",e,t),oi=(e,t=3e3)=>ri("error",e,t),ai=(e,t=3e3)=>ri("warning",e,t),ci="/v1/aicc/bmserver",hi="/v1/aicc/ccs";let di="",li="",gi="";async function ui(e,t){const s=function(){const e=Ft(li,gi);return qt.create({prefixUrl:`${di}/api`,timeout:!1,headers:{Authorization:e},hooks:{afterResponse:[async(e,t,s)=>{const i=await s.clone().json();if(0!==i.code)throw oi(i.msg),new Error(JSON.stringify(i)||"请求失败");return s.json=async()=>i,s}]}})}(),i=e.replace(/^\/+/,"");return s.post(i,{json:t}).json()}const pi={agentInfo:{},isRtcReconnecting:!1,sessionId:"",enableBrowserAlert:!1,autoStateTimer:null};const fi=new class extends Qe{updateRttObject(e){this.setState({rttObject:e})}}({rttObject:{rtt:null,jitter:null,packetsLost:null,packetsReceived:null,packetsSent:null,sendBitrate:null,recvBitrate:null,codec:null}});class mi{constructor(e,t){this.config=e,this.eventCallback=t,this.userAgent=null,this.registerer=null,this.activeSession=null,this.callTimeoutTimer=null,this.incomingInvitation=null,this.reconnectAttempts=0,this.maxReconnectAttempts=5,this.reconnectTimer=null,this.isOffline=!1,this.autoAnswerTimer=null,this.handleMessage=e=>{},this.handleNetworkInfoChange=e=>{0===(e.rttObject?.rtt||0)?this.isOffline||(this.isOffline=!0,this.handleOffline()):this.isOffline&&(this.isOffline=!1,this.handleOnline())},this.handleOffline=()=>{console.warn("[SIPClient] 网络断开,准备销毁 SIP 客户端",(new Date).toLocaleString()),this.destroy()},this.handleOnline=()=>{console.warn("[SIPClient] 网络恢复,准备重新启动 SIP 客户端",(new Date).toLocaleString()),this.reconnect()},fi.subscribe(this.handleNetworkInfoChange)}async start(){const e=Xe.makeURI(`sip:${this.config.user}@${this.config.server}`);if(!e)throw new Error("无效的SIP配置");const t={uri:e,authorizationUsername:this.config.user,authorizationPassword:this.config.password,transportOptions:{server:this.config.webSocket,connectionTimeout:30,keepAliveInterval:0},sessionDescriptionHandlerFactoryOptions:{alwaysAcquireMediaFirst:!0,peerConnectionConfiguration:{iceServers:[]},iceGatheringTimeout:400},logBuiltinEnabled:!1};this.userAgent=new Xe(t),this.setupEventListeners(),await this.userAgent.start(),await this.register()}setupEventListeners(){this.userAgent&&(this.userAgent.transport.stateChange.addListener(e=>{let t;switch(e){case ee.Connecting:t=st.WEB_RTC_CONNECTING;break;case ee.Connected:t=st.WEB_RTC_CONNECTED,this.reconnectAttempts=0,pi.isRtcReconnecting=!1,this.reconnectTimer&&(clearTimeout(this.reconnectTimer),this.reconnectTimer=null);break;case ee.Disconnecting:t=st.WEB_RTC_DISCONNECTING;break;case ee.Disconnected:{t=st.WEB_RTC_DISCONNECTED;const e=dt.get("answerDevice");if(!pi.isRtcReconnecting&&this.reconnectAttempts<this.maxReconnectAttempts&&1===e){this.reconnectAttempts++;const e=1e3*this.reconnectAttempts;console.warn(`SIP WebSocket 断开,第 ${this.reconnectAttempts} 次尝试重连,${e}ms 后重试...`),this.reconnectTimer=setTimeout(()=>{this.reconnect()},e)}else this.reconnectAttempts>=this.maxReconnectAttempts&&console.error("SIP 重连失败:已达到最大重试次数");break}default:t="unknown"}this.eventCallback?.({type:t})}),this.userAgent.transport.stateChange.addListener(e=>{}),this.userAgent.delegate={onInvite:e=>{this.handleIncomingCall(e)}})}async register(){if(this.userAgent){this.registerer=new ne(this.userAgent),this.registerer?.stateChange.addListener(e=>{let t;switch(e){case X.Initial:t="initial";break;case X.Registered:t=st.WEB_RTC_REGISTERED;break;case X.Unregistered:t=st.WEB_RTC_UNREGISTERED;break;case X.Terminated:t=st.WEB_RTC_TERMINATED;break;default:t="unknown"}this.eventCallback?.({type:t})});try{await this.registerer.register()}catch(e){this.eventCallback?.({type:st.WEB_RTC_REGISTER_FAILED,data:e})}}}attachRemoteAudio(e){const t=e.sessionDescriptionHandler;if(t){const e=t.peerConnection;if(!e)return;const s=new MediaStream;e.getReceivers().forEach(e=>{e.track&&"audio"===e.track.kind&&s.addTrack(e.track)});let i=document.getElementById("sip-remote-audio");i||(i=document.createElement("audio"),i.id="sip-remote-audio",i.autoplay=!0,i.style.display="none",document.body.appendChild(i)),i.srcObject=s,i.play().catch(e=>{console.error("音频播放失败,需要用户交互触发",e)})}}handleSessionState(e,t,s){e.stateChange.addListener(t=>{switch(t){case K.Established:clearTimeout(this.callTimeoutTimer),this.activeSession=e,this.attachRemoteAudio(e);break;case K.Terminating:break;case K.Terminated:this.activeSession=null,clearTimeout(this.callTimeoutTimer);case K.Establishing:}})}handleIncomingCall(e){this.incomingInvitation=e,this.handleSessionState(e,!1);const{soft_device_auto_answer:t,auto_answer_time:s}=pi.agentInfo,i=dt.get("direction"),r=1===t;if(i===tt.OUTGOING)this.answerCall();else if(r&&i===tt.INCOMING){const e=Number(s)||0;e>0?this.autoAnswerTimer=setTimeout(()=>{this.answerCall(),this.autoAnswerTimer=null},e):this.answerCall()}}async makeCall(e){if(dt.getState().isCalling)throw new Error("正在呼叫中,请勿重复点击");if(!this.userAgent)throw dt.updateIsCalling(!1),dt.updateDirection(null),new Error("SIP客户端未初始化");dt.updateIsCalling(!0),dt.updateDirection(tt.OUTGOING);const t=Xe.makeURI(`sip:${e}@${this.config.server}`);if(!t)throw new Error("无效的被叫号码");const s=new Z(this.userAgent,t);this.handleSessionState(s,!0,e);try{this.activeSession=s,await s.invite(),this.config.callTimeout&&(this.callTimeoutTimer=setTimeout(()=>{s.state!==K.Established&&(this.hangup(),this.eventCallback?.({type:"error",data:{message:"呼叫超时未接通"}}))},this.config.callTimeout))}catch(e){this.eventCallback?.({type:"error",data:{message:"呼叫失败",detail:e}}),dt.updateIsCalling(!1),dt.updateDirection(null)}}async answerCall(){if(!this.incomingInvitation)throw new Error("无来电可接听");this.autoAnswerTimer&&(clearTimeout(this.autoAnswerTimer),this.autoAnswerTimer=null);try{console.log((new Date).toLocaleString()),await this.incomingInvitation.accept(),console.log((new Date).toLocaleString()),this.activeSession=this.incomingInvitation,this.incomingInvitation=null}catch(e){this.eventCallback?.({type:st.WEB_RTC_ANSWER_FAILED,data:{detail:e}})}}async rejectInCall(){if(this.incomingInvitation)try{await this.incomingInvitation.reject(),this.incomingInvitation=null,dt.updateDirection(null),dt.updateIsCalling(!1),clearTimeout(this.callTimeoutTimer)}catch(e){this.eventCallback?.({type:"error",data:{message:"拒接失败",detail:e}})}}sendDTMF(e){if(!this.activeSession)throw new Error("当前没有活跃的通话");const t=this.activeSession.sessionDescriptionHandler;t&&"function"==typeof t.sendDtmf?(t.sendDtmf(e),this.eventCallback?.({type:st.WEB_RTC_SEND_DTMF,data:{tone:e}})):console.warn("DTMF发送不支持或未初始化")}async hangup(){if(this.activeSession){clearTimeout(this.callTimeoutTimer);const e=this.activeSession;if(!e)return;const t=e.state;try{t===K.Established?await e.bye():t===K.Establishing&&(e instanceof Z?await e.cancel():e instanceof J&&await e.reject()),clearTimeout(this.callTimeoutTimer)}catch(e){console.error("挂断失败",e)}finally{this.activeSession=null}}}async rejectOutCall(){this.activeSession instanceof J&&(await this.activeSession.reject(),this.activeSession=null)}async destroy(){if(clearTimeout(this.callTimeoutTimer),this.activeSession&&await this.hangup(),this.registerer){try{await this.registerer.unregister()}catch(e){console.warn("注销失败",e)}this.registerer=null}this.userAgent&&(await this.userAgent.stop(),this.userAgent=null)}async reconnect(){if(!pi.isRtcReconnecting){pi.isRtcReconnecting=!0;try{await this.destroy(),await this.start(),console.log("重连成功"),this.isOffline=!1}catch(e){console.error("重连失败",e)}finally{pi.isRtcReconnecting=!1}}}async getNetworkStats(){if(this.activeSession){const e=this.activeSession.sessionDescriptionHandler?.peerConnection;if(!e)return null;const t=await e.getStats(),s={};return t.forEach(e=>{"candidate-pair"===e.type&&"succeeded"===e.state&&null!=e.currentRoundTripTime&&(s.rtt=+(1e3*e.currentRoundTripTime).toFixed(2)),"inbound-rtp"===e.type&&"audio"===e.kind&&(s.jitter=+(1e3*e.jitter).toFixed(2),s.packetsLost=e.packetsLost,s.packetsReceived=e.packetsReceived,e.bytesReceived&&e.timestamp&&(s.recvBitrate=+(e.bytesReceived/1024).toFixed(2))),"outbound-rtp"===e.type&&"audio"===e.kind&&(s.packetsSent=e.packetsSent,e.bytesSent&&e.timestamp&&(s.sendBitrate=+(e.bytesSent/1024).toFixed(2))),"codec"===e.type&&e.mimeType&&(s.codec=e.mimeType)}),{...s,rtt:s?.rtt||40}}try{const e=Date.now();await ui(`${ci}/config/ping`,{});const t=Date.now();return{rtt:t-e||1}}catch(e){console.log(e)}}}const vi={statusColor:{[et.IDLE]:"#1D92E9",[et.BUSY]:"#F5212D",[et.OFFLINE]:"#8c8c8c",[et.RINGING]:"#e9b91d"}},wi=["call_number"],yi=[],bi=["hangup"],Ti=["hold","hangup","unhold","mute","unmute","transfer","consult","satisfaction","dtmf"],Si=["consult_transfer"],Ci=["hangup"],Ei=["answer","reject"],Ai=["hangup","consult","transfer","hold","unhold","mute","unmute","satisfaction","dtmf"];let _i=class extends zs{static{this.styles=Yt`
113
+ `}connectedCallback(){super.connectedCallback(),setTimeout(()=>{this.remove()},this.duration+300)}render(){return Ds`<div>${this.content}</div>`}};jt([ei({type:String})],ii.prototype,"type",void 0),jt([ei({type:String})],ii.prototype,"content",void 0),jt([ei({type:Number})],ii.prototype,"duration",void 0),ii=jt([Zs("my-message")],ii);const ri=(e,t,s=3e3)=>{let i=document.querySelector("#message-container");i||(i=document.createElement("div"),i.id="message-container",Object.assign(i.style,{position:"fixed",top:"14px",left:"50%",transform:"translateX(-50%)",zIndex:"9999"}),document.body.appendChild(i));const r=document.createElement("my-message");r.setAttribute("type",e),r.setAttribute("content",t),r.setAttribute("duration",String(s)),r.style.setProperty("--fade-delay",s/1e3+"s"),i.appendChild(r)},ni=(e,t=3e3)=>ri("success",e,t),oi=(e,t=3e3)=>ri("error",e,t),ai=(e,t=3e3)=>ri("warning",e,t),ci="/v1/aicc/bmserver",hi="/v1/aicc/ccs";let di="",li="",gi="";async function ui(e,t){const s=function(){const e=Ft(li,gi);return qt.create({prefixUrl:`${di}/api`,timeout:!1,headers:{Authorization:e},hooks:{afterResponse:[async(e,t,s)=>{const i=await s.clone().json();if(0!==i.code)throw oi(i.msg),new Error(JSON.stringify(i)||"请求失败");return s.json=async()=>i,s}]}})}(),i=e.replace(/^\/+/,"");return s.post(i,{json:t}).json()}const pi={agentInfo:{},isRtcReconnecting:!1,sessionId:"",enableBrowserAlert:!1,autoStateTimer:null};const fi=new class extends Qe{updateRttObject(e){this.setState({rttObject:e})}}({rttObject:{rtt:null,jitter:null,packetsLost:null,packetsReceived:null,packetsSent:null,sendBitrate:null,recvBitrate:null,codec:null}});class mi{constructor(e,t){this.config=e,this.eventCallback=t,this.userAgent=null,this.registerer=null,this.activeSession=null,this.callTimeoutTimer=null,this.incomingInvitation=null,this.reconnectAttempts=0,this.maxReconnectAttempts=5,this.reconnectTimer=null,this.isOffline=!1,this.autoAnswerTimer=null,this.handleMessage=e=>{},this.handleNetworkInfoChange=e=>{const t=e.rttObject?.rtt||0;console.log(t),0===t?this.isOffline||(this.isOffline=!0,this.handleOffline()):this.isOffline&&(this.isOffline=!1,this.handleOnline())},this.handleOffline=()=>{console.warn("[SIPClient] 网络断开,准备销毁 SIP 客户端",(new Date).toLocaleString())},this.handleOnline=()=>{console.warn("[SIPClient] 网络恢复,准备重新启动 SIP 客户端",(new Date).toLocaleString())},fi.subscribe(this.handleNetworkInfoChange)}async start(){const e=Xe.makeURI(`sip:${this.config.user}@${this.config.server}`);if(!e)throw new Error("无效的SIP配置");const t={uri:e,authorizationUsername:this.config.user,authorizationPassword:this.config.password,transportOptions:{server:this.config.webSocket,connectionTimeout:30,keepAliveInterval:0},sessionDescriptionHandlerFactoryOptions:{alwaysAcquireMediaFirst:!0,peerConnectionConfiguration:{iceServers:[]},iceGatheringTimeout:400},logBuiltinEnabled:!1};this.userAgent=new Xe(t),this.setupEventListeners(),await this.userAgent.start(),await this.register()}setupEventListeners(){this.userAgent&&(this.userAgent.transport.stateChange.addListener(e=>{let t;switch(e){case ee.Connecting:t=st.WEB_RTC_CONNECTING;break;case ee.Connected:t=st.WEB_RTC_CONNECTED,this.reconnectAttempts=0,pi.isRtcReconnecting=!1,this.reconnectTimer&&(clearTimeout(this.reconnectTimer),this.reconnectTimer=null);break;case ee.Disconnecting:t=st.WEB_RTC_DISCONNECTING;break;case ee.Disconnected:{t=st.WEB_RTC_DISCONNECTED;const e=dt.get("answerDevice");if(!pi.isRtcReconnecting&&this.reconnectAttempts<this.maxReconnectAttempts&&1===e){this.reconnectAttempts++;const e=1e3*this.reconnectAttempts;console.warn(`SIP WebSocket 断开,第 ${this.reconnectAttempts} 次尝试重连,${e}ms 后重试...`),this.reconnectTimer=setTimeout(()=>{this.reconnect()},e)}else this.reconnectAttempts>=this.maxReconnectAttempts&&console.error("SIP 重连失败:已达到最大重试次数");break}default:t="unknown"}this.eventCallback?.({type:t})}),this.userAgent.transport.stateChange.addListener(e=>{}),this.userAgent.delegate={onInvite:e=>{this.handleIncomingCall(e)}})}async register(){if(this.userAgent){this.registerer=new ne(this.userAgent),this.registerer?.stateChange.addListener(e=>{let t;switch(e){case X.Initial:t="initial";break;case X.Registered:t=st.WEB_RTC_REGISTERED;break;case X.Unregistered:t=st.WEB_RTC_UNREGISTERED;break;case X.Terminated:t=st.WEB_RTC_TERMINATED;break;default:t="unknown"}this.eventCallback?.({type:t})});try{await this.registerer.register()}catch(e){this.eventCallback?.({type:st.WEB_RTC_REGISTER_FAILED,data:e})}}}attachRemoteAudio(e){const t=e.sessionDescriptionHandler;if(t){const e=t.peerConnection;if(!e)return;const s=new MediaStream;e.getReceivers().forEach(e=>{e.track&&"audio"===e.track.kind&&s.addTrack(e.track)});let i=document.getElementById("sip-remote-audio");i||(i=document.createElement("audio"),i.id="sip-remote-audio",i.autoplay=!0,i.style.display="none",document.body.appendChild(i)),i.srcObject=s,i.play().catch(e=>{console.error("音频播放失败,需要用户交互触发",e)})}}handleSessionState(e,t,s){e.stateChange.addListener(t=>{switch(t){case K.Established:clearTimeout(this.callTimeoutTimer),this.activeSession=e,this.attachRemoteAudio(e);break;case K.Terminating:break;case K.Terminated:this.activeSession=null,clearTimeout(this.callTimeoutTimer);case K.Establishing:}})}handleIncomingCall(e){this.incomingInvitation=e,this.handleSessionState(e,!1);const{soft_device_auto_answer:t,auto_answer_time:s}=pi.agentInfo,i=dt.get("direction"),r=1===t;if(i===tt.OUTGOING)this.answerCall();else if(r&&i===tt.INCOMING){const e=Number(s)||0;e>0?this.autoAnswerTimer=setTimeout(()=>{this.answerCall(),this.autoAnswerTimer=null},e):this.answerCall()}}async makeCall(e){if(dt.getState().isCalling)throw new Error("正在呼叫中,请勿重复点击");if(!this.userAgent)throw dt.updateIsCalling(!1),dt.updateDirection(null),new Error("SIP客户端未初始化");dt.updateIsCalling(!0),dt.updateDirection(tt.OUTGOING);const t=Xe.makeURI(`sip:${e}@${this.config.server}`);if(!t)throw new Error("无效的被叫号码");const s=new Z(this.userAgent,t);this.handleSessionState(s,!0,e);try{this.activeSession=s,await s.invite(),this.config.callTimeout&&(this.callTimeoutTimer=setTimeout(()=>{s.state!==K.Established&&(this.hangup(),this.eventCallback?.({type:"error",data:{message:"呼叫超时未接通"}}))},this.config.callTimeout))}catch(e){this.eventCallback?.({type:"error",data:{message:"呼叫失败",detail:e}}),dt.updateIsCalling(!1),dt.updateDirection(null)}}async answerCall(){if(!this.incomingInvitation)throw new Error("无来电可接听");this.autoAnswerTimer&&(clearTimeout(this.autoAnswerTimer),this.autoAnswerTimer=null);try{console.log((new Date).toLocaleString()),await this.incomingInvitation.accept(),console.log((new Date).toLocaleString()),this.activeSession=this.incomingInvitation,this.incomingInvitation=null}catch(e){this.eventCallback?.({type:st.WEB_RTC_ANSWER_FAILED,data:{detail:e}})}}async rejectInCall(){if(this.incomingInvitation)try{await this.incomingInvitation.reject(),this.incomingInvitation=null,dt.updateDirection(null),dt.updateIsCalling(!1),clearTimeout(this.callTimeoutTimer)}catch(e){this.eventCallback?.({type:"error",data:{message:"拒接失败",detail:e}})}}sendDTMF(e){if(!this.activeSession)throw new Error("当前没有活跃的通话");const t=this.activeSession.sessionDescriptionHandler;t&&"function"==typeof t.sendDtmf?(t.sendDtmf(e),this.eventCallback?.({type:st.WEB_RTC_SEND_DTMF,data:{tone:e}})):console.warn("DTMF发送不支持或未初始化")}async hangup(){if(this.activeSession){clearTimeout(this.callTimeoutTimer);const e=this.activeSession;if(!e)return;const t=e.state;try{t===K.Established?await e.bye():t===K.Establishing&&(e instanceof Z?await e.cancel():e instanceof J&&await e.reject()),clearTimeout(this.callTimeoutTimer)}catch(e){console.error("挂断失败",e)}finally{this.activeSession=null}}}async rejectOutCall(){this.activeSession instanceof J&&(await this.activeSession.reject(),this.activeSession=null)}async destroy(){if(clearTimeout(this.callTimeoutTimer),this.activeSession&&await this.hangup(),this.registerer){try{await this.registerer.unregister()}catch(e){console.warn("注销失败",e)}this.registerer=null}this.userAgent&&(await this.userAgent.stop(),this.userAgent=null)}async reconnect(){if(!pi.isRtcReconnecting){pi.isRtcReconnecting=!0;try{await this.destroy(),await this.start(),console.log("重连成功"),this.isOffline=!1}catch(e){console.error("重连失败",e)}finally{pi.isRtcReconnecting=!1}}}async getNetworkStats(){if(this.activeSession){const e=this.activeSession.sessionDescriptionHandler?.peerConnection;if(!e)return null;const t=await e.getStats(),s={};return t.forEach(e=>{"candidate-pair"===e.type&&"succeeded"===e.state&&null!=e.currentRoundTripTime&&(s.rtt=+(1e3*e.currentRoundTripTime).toFixed(2)),"inbound-rtp"===e.type&&"audio"===e.kind&&(s.jitter=+(1e3*e.jitter).toFixed(2),s.packetsLost=e.packetsLost,s.packetsReceived=e.packetsReceived,e.bytesReceived&&e.timestamp&&(s.recvBitrate=+(e.bytesReceived/1024).toFixed(2))),"outbound-rtp"===e.type&&"audio"===e.kind&&(s.packetsSent=e.packetsSent,e.bytesSent&&e.timestamp&&(s.sendBitrate=+(e.bytesSent/1024).toFixed(2))),"codec"===e.type&&e.mimeType&&(s.codec=e.mimeType)}),{...s,rtt:s?.rtt||40}}try{const e=Date.now();await ui(`${ci}/config/ping`,{});const t=Date.now();return{rtt:t-e||1}}catch(e){console.log(e)}}}const vi={statusColor:{[et.IDLE]:"#1D92E9",[et.BUSY]:"#F5212D",[et.OFFLINE]:"#8c8c8c",[et.RINGING]:"#e9b91d"}},wi=["call_number"],yi=[],bi=["hangup"],Ti=["hold","hangup","unhold","mute","unmute","transfer","consult","satisfaction","dtmf"],Si=["consult_transfer"],Ci=["hangup"],Ei=["answer","reject"],Ai=["hangup","consult","transfer","hold","unhold","mute","unmute","satisfaction","dtmf"];let _i=class extends zs{static{this.styles=Yt`
114
114
  .timer-text {
115
115
  width: 70px;
116
116
  font-size: 14px;
@@ -658,16 +658,16 @@ const Zs=e=>(t,s)=>{void 0!==s?s.addInitializer(()=>{customElements.define(e,t)}
658
658
  </div>`}
659
659
  </div>
660
660
  </my-modal-wrapper>
661
- `;Ws(i,this.modalRoot)}})}catch(e){oi(e)}}getActionConfigs(){const{show_satisfaction:e}=pi.agentInfo,t=dt.get("isHold"),s=dt.get("isMuted"),i=dt.get("actionConfigs").filter(i=>(0!==e||"satisfaction"!==i)&&(!(!t&&"unhold"===i)&&((!t||"hold"!==i)&&((!s||"mute"!==i)&&!(!s&&"unmute"===i)))));return[{render:this.renderCallPopover,type:"call_number"},{render:this.renderAnswer,type:"answer"},{render:this.renderReject,type:"reject"},{render:this.renderHangup,type:"hangup"},{render:this.renderDialer,type:"dtmf"},{render:this.renderUnhold,type:"unhold"},{render:this.renderHold,type:"hold"},{render:this.renderMute,type:"mute"},{render:this.renderUnmute,type:"unmute"},{render:this.renderSatisfaction,type:"satisfaction"},{render:this.renderConsult,type:"consult"},{render:this.renderTransfer,type:"transfer"},{render:this.renderConsultTransfer,type:"consult_transfer"}].filter(({type:e})=>i.includes(e))}async render(){const{displayText:e,answerDevice:t}=dt.getState(),{default_device:s,answer_devices:i,show_satisfaction:r}=pi.agentInfo,n=(i||"").split(","),o=this.getActionConfigs(),a={...vi},{statusColor:c}=a,h=document.querySelector("head");if(h){const e=Ds`
661
+ `;Ws(i,this.modalRoot)}})}catch(e){oi(e)}}getActionConfigs(){const{show_satisfaction:e}=pi.agentInfo,t=dt.get("isHold"),s=dt.get("isMuted"),i=dt.get("actionConfigs").filter(i=>(0!==e||"satisfaction"!==i)&&(!(!t&&"unhold"===i)&&((!t||"hold"!==i)&&((!s||"mute"!==i)&&!(!s&&"unmute"===i)))));return[{render:this.renderCallPopover,type:"call_number"},{render:this.renderAnswer,type:"answer"},{render:this.renderReject,type:"reject"},{render:this.renderHangup,type:"hangup"},{render:this.renderDialer,type:"dtmf"},{render:this.renderUnhold,type:"unhold"},{render:this.renderHold,type:"hold"},{render:this.renderMute,type:"mute"},{render:this.renderUnmute,type:"unmute"},{render:this.renderSatisfaction,type:"satisfaction"},{render:this.renderConsult,type:"consult"},{render:this.renderTransfer,type:"transfer"},{render:this.renderConsultTransfer,type:"consult_transfer"}].filter(({type:e})=>i.includes(e))}async render(){const{displayText:e}=dt.getState(),{default_device:t,answer_devices:s,show_satisfaction:i}=pi.agentInfo,r=(s||"").split(","),n=this.getActionConfigs(),o={...vi},{statusColor:a}=o,c=document.querySelector("head");if(c){const e=Ds`
662
662
  <style>
663
663
  .ysyt-phone-body {
664
- background: ${c[this.statusParams.state]};
664
+ background: ${a[this.statusParams.state]};
665
665
  }
666
666
  .ysyt-action-body {
667
- border-bottom: 1px solid ${c[this.statusParams.state]};
667
+ border-bottom: 1px solid ${a[this.statusParams.state]};
668
668
  }
669
669
  </style>
670
- `;Ws(e,h)}const d=Ds`
670
+ `;Ws(e,c)}const h=Ds`
671
671
  <i class="ysyt icon-shang select-icon" style="${this.isOpenSelect?"display: block;":"display: none;"}"></i>
672
672
  <div
673
673
  class="ysyt-select"
@@ -684,30 +684,30 @@ const Zs=e=>(t,s)=>{void 0!==s?s.addInitializer(()=>{customElements.define(e,t)}
684
684
  `)}
685
685
  </div>
686
686
  </div>
687
- `,l=Ds`
687
+ `,d=Ds`
688
688
  <div id="ysyt-body">
689
689
  <div id="ysyt-devices-body">
690
690
  <my-select
691
691
  width="100px"
692
- value="${String(s)}"
692
+ value="${String(t)}"
693
693
  placeholder=""
694
694
  @change=${e=>this.onChangeDevices(Number(e.detail.value))}
695
695
  >
696
- ${n.includes("1")?Ds`
696
+ ${r.includes("1")?Ds`
697
697
  <select-option value="1">
698
698
  <div style="display: flex; align-items: center; gap: 8px;">
699
699
  <img src="${"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAC0AAAAtCAYAAAA6GuKaAAAAAXNSR0IArs4c6QAAAjhJREFUaEPtmM1WwjAQhWeAF0I34kZ5MuDJqBtxo7wQEE9CkzNNk8yktIl4YKOHRvPl9s5PBuEOP3iHzPCALvXWxEq/HBfvGmp2AfPz8/m0LQXp78NCa1gEtQF1hbUfVLirBZ6EXh3neweL0CjAnVZaodpoeIW4/lqemtKKB6E76rawFM48V2oPCM1heV7/CWircMoCr9+LrVa8hk16SufArH7mqoZNboKuZZMetLXG4enMZhatsl1fMij/F7RUuZwYGCvLRJWWQDtPA4DUTmOARwORg6bApdNeD1qaEWy6Kw2s31QwQxigRLWr4eNO3xPyGJfGLDRnoTH8G/of8d5DqX0MijvUVLCuwwxtwPmae14FWm/K+bZW3xENRKtUCsweqkZ7muwvODBJCzuFVdimiAu6GvmaheZKdY3KyELToIz5Nxe8d1lGaPCCH9KLsgia9s2xsk3BU8HprzOeb2/60pZADC0Bp2tMagqMGULBawJ+pt6k8FnQUhu4rNOmDg1vBG3BYorSv0upngXd8XdESZvi9AHpjMSlPmbs4I8vQiOKbOgccP8Alxk00uFOqkYMgh4CPqTIxFrkwdAlwCeBdj0KmflJ0xanfKphu0lpunEnY2QWi+BFJDG9Gg3a2cXLtznBZ+G5tnhUaH9TqqDUNvSNxcYSk0B34Iny5vvWOnaNfhP6d5PTydrU/XNS6F6h8Q8QMnNgHu4vKwLtb2qrJf3eKi4pPlWguXTHPX9AcwqN9fwulf4FD/s5TOGFiLYAAAAASUVORK5CYII="}" width="16" alt="" /><span style="font-size: 14px">软电话</span>
700
700
  </div>
701
701
  </select-option>
702
702
  `:""}
703
- ${n.includes("2")?Ds`
703
+ ${r.includes("2")?Ds`
704
704
  <select-option value="2">
705
705
  <div style="display: flex; align-items: center; gap: 8px;">
706
706
  <img src="${"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAC0AAAAtCAYAAAA6GuKaAAAAAXNSR0IArs4c6QAAAWtJREFUaEPtWdFNAzEMdW6Ewgo3BzBOYYi2Q0DHKcxxK0BHaNA7cIVEVD0n8Uck31dVOfbLyzvn9JxkwCcNiFmqQd8fl8eWDX9u5/fa9WbQm9dlnyZ5yFmaQF8BZzmcX+a9ZQMm0HfH5QSwKcnKUr7Ih6XYv9gkO/yHfF/b+YnNRYMGw4IiFczcAlOTlwf9tmQUPz/P9BqWOZwgYlm2aQAbgO7Msm5KZccSQoFGp7hkOUF7SeTAMsjGZZEd3hUX0CyI2jgX0GC6uWMUdqQt1AX0kJoO0H9k4to9gulgutCS9HIJeYQ8Qh7cV0j0aeUpukdBMSGPkMeNRhLyCHmEPIibdujLJcyawgm7+R7T9GPz9nx8bTHSgNQpAev2u1wuYBWuKWt+q+fMxruBtnjIVqN8tZEN3jdl9a5MjzgJAHA9RvzWuUvrC6kzHHYKsNa2Fr0ybl1Ysnh/rWPX6VYHnF1SmJnuUrUxyZCgvwFf6/M9kuThSwAAAABJRU5ErkJggg=="}" width="16" alt="" /><span style="font-size: 14px">手机模式</span>
707
707
  </div>
708
708
  </select-option>
709
709
  `:""}
710
- ${n.includes("3")?Ds`
710
+ ${r.includes("3")?Ds`
711
711
  <select-option value="3">
712
712
  <div style="display: flex; align-items: center; gap: 8px;">
713
713
  <img src="${"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAC0AAAAtCAYAAAA6GuKaAAAAAXNSR0IArs4c6QAAAq5JREFUaEPtmWFywiAQhcEr6Als79F6LdsZdab1WsZ7tJ7AXiF0lmYzC9mFDUGrM/qrmrB8PB7LQq25w4+9Q2bzgL7WrD2UvhmlF8/vr865jXXueD7tt1PAIBZtf/76aPA7PKPf4Xf6Pn2WtMdiud46YzZ9R9Y2P9+fqxLw+dPbwTgXQNvZbIUw8+XaGRJ/0LcxkDV2IJwIHTSytuk7LADnAGDgCOFns20P8NvPae+ZuEFiGxaadtIHpqqPBPcqEsh4plLQg/6tbVhoqZNYfY1VKBC1AwUfBf03+PDDBQg6KFCcTjUoB/Hoos7ag9gT2g+hESphgbGKUygUAKcds4TK0x1TEbTvqEBxaANtMSOhXZJKg4edO5rZrMFMUwxdCk4zgyZ70BkhsxR5WmEPyeOphUbboBXqQTM5M7eZ4ELjVPHKdikviEM3kkSeVilNO5GUE5Xudqx4kANoZpHDO8Hi7GZcD41bbmYT4Tah3KzUeM7viEqL5GxRA5CLIdYe/a5IiprBtHczorFRzQHI0AqL9DvdyFpk6gDkKo9YRMoKuS1/KpzUXl1PSxbIVXCXAM+eEft0JVjgPzJIFjooLYU8rAWvdXTLQsc1hmgTcpzi1kDNo5sKmhY58LdYY0RnSqydnbUv9Lg25ejm+9culKAm1tbaUfAaR7dR0HGxTk/O3MC9HUDh7mOt3QVXBgX1uFia5pQvKf6lmKWx1PaQKruc4pcQoQg6ziipxZmDHsRSlATF0AOPJ+41aoNPgu7BndtgGpPqlLHgqTiToREm3jxK4TWVYzVozuddTvWXhjeptJhdME/DzRK5u4gHEd9CpQZaVekYRLothTQZvEuugDW2uih04Hdafwhe0R7brgIdWAf+G9C2weV6yjbc+K4OrVmQuXce0DmFaj2/S6V/Ae/pt8oTAp/jAAAAAElFTkSuQmCC"}" width="16" alt="" /><span style="font-size: 14px">SIP话机</span>
@@ -727,14 +727,14 @@ const Zs=e=>(t,s)=>{void 0!==s?s.addInitializer(()=>{customElements.define(e,t)}
727
727
  <span>${t}</span>
728
728
  `:void 0)(this.statusParams)}
729
729
  <i class="ysyt icon-xia"></i>
730
- ${d}
730
+ ${h}
731
731
  `}
732
732
  </div>
733
733
  <timer-component id="my-timer"></timer-component>
734
734
  </div>
735
- <div class="ysyt-action-body">${o.map(e=>e.render())}</div>
735
+ <div class="ysyt-action-body">${n.map(e=>e.render())}</div>
736
736
  </div>
737
- `;Ws(l,this.container)}async renderRtt(e){const{outCallIsAnswer:t}=dt.getState(),s=e?.rtt||500,i=Ds`
737
+ `;Ws(d,this.container)}async renderRtt(e){const{outCallIsAnswer:t}=dt.getState(),s=e?.rtt||500,i=Ds`
738
738
  <my-popover triggerType="hover">
739
739
  <div slot="trigger" id="wifi-body">
740
740
  ${s>=250?Ds`<img src="${"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAC0AAAAtCAYAAAA6GuKaAAAAAXNSR0IArs4c6QAAAlVJREFUaEPtmGFuwyAMhU2PtU1qOVmbk5FKW4+1TCawkcQYG2i3aM2fqirBn83zc1IDO7zMDpnhCf2oU+teaefcKYW31o69k6mGTuDOAWoBmwGNCVwBYKxNSAUdQDWQkiIPuMhae5EsxjUi6ARWUk1pbGrdIIFnoZWwqXbx+NPrqJAQLmXhSWghLELGo1U1m3MuSiFKLXc6JPwGOmyY28yD1jYQRSZIYAP+DV2obnfYdQIF+EV8Dx2AHVGJu8Mq4X3VDSMHUSe3WAV3L8eF0BNxs9XoNpwU2mF0CdwSv6fDxIeRWFrkyYEjNMoi+q9YDkKHyRUT41wlCRBxhqhptCDRWC24S41aRDIMcT2jaCKGZsXESr6aQmM1NRNUBK8Z46mE1tWMumX9W+DHxUkYA7eMcbH+maFCnVxx3xI05SzFTTXCZnok62BZ6MxmYt11AM/G4qCxidIpqfJuDXSm0fWVTgz+pBk0E7wFx/gMn4fRwLv4KTC+EXExxZbHVW6ClwuAOQJMjMWZEWC6GriJ31ByMZug56pOZx6WDD20wFdDT/DqKmDTDKrBq6BnOVDTESXgZ5Z/owGIus5Jx4wGPqy2aWuhV/6NsGbgGm6Wkk9iMVAM3NQM6huwKj+V1jfX6pSqJFIFrT1Oaj1WXmOF6R6/Bt2S+N2gWypZSqg7NOEsVbrlwLtC560QuoL3hqYeZWfnrrC2u4zxdNPgw9R/J2HZwda6xRr+f1d6OXQ2B/t3NU2D1z1fPMw9thrHBpS/AJT8Of7eVdPSoK3rntCtFZTev8tKfwHUBxjzil9I5gAAAABJRU5ErkJggg=="}" alt="" />`:""}
@@ -774,4 +774,4 @@ const Zs=e=>(t,s)=>{void 0!==s?s.addInitializer(()=>{customElements.define(e,t)}
774
774
  `:""}
775
775
  </div>
776
776
  </my-popover>
777
- `;Ws(i,this.rttHTML)}}const Pi=new class{constructor(){this.events={}}on(e,t){this.events[e]=this.events[e]||[],this.events[e].push(t)}off(e,t){this.events[e]=(this.events[e]||[]).filter(e=>e!==t)}emit(e,...t){(this.events[e]||[]).forEach(e=>e(...t))}};class Oi{static requestPermission(){"Notification"in window&&"default"===Notification.permission&&Notification.requestPermission()}static async requestMediaPermissions(){try{const e=await navigator.mediaDevices.enumerateDevices();if(e.some(e=>"audioinput"===e.kind&&""!==e.label))return console.log("已授权麦克风权限,无需再次获取"),null;const t=await navigator.mediaDevices.getUserMedia({audio:!0});return console.log("获取音频权限成功"),t}catch(e){return console.warn("获取音频权限失败:",e),null}}static show(e,t,s){if("Notification"in window&&"granted"===Notification.permission){const i=new Notification(e,{body:t,tag:"xy-global-notification",renotify:!0});i.onclick=()=>{window.focus(),i.close(),s?.()},setTimeout(()=>i.close(),5e3)}}static async checkMediaPermissions(){try{return(await navigator.mediaDevices.enumerateDevices()).some(e=>"audioinput"===e.kind&&""!==e.label)}catch(e){return console.warn("无法检查设备权限:",e),!1}}}let qi=null;class Li{constructor(e){this.url=e,this.ws=null,this.heartbeatWorker=null,this.reconnectDelay=3e3,this.manualClose=!1,this.apiClient=new Ni,this.initWebSocket()}static getInstance(e){if(!qi){if(!e)throw new Error("WebSocket 尚未初始化");qi=new Li(e)}return qi}stateIdleChange(){const{state:e}=pi.stateObject;e!==et.IDLE&&this.apiClient.changeState({data:{state:et.IDLE,state_name:"空闲"}})}putAgentState(){pi.sessionId="";const{post_call_process_time:e}=pi.agentInfo,t=e||0;pi.autoStateTimer&&(clearTimeout(pi.autoStateTimer),pi.autoStateTimer=null),t>0?pi.autoStateTimer=setTimeout(()=>{pi.autoStateTimer=null,this.stateIdleChange()},t):this.stateIdleChange()}initWebSocket(){this.ws=new WebSocket(this.url),this.ws.onopen=()=>{this.sendMessage({type:0}),this.startHeartbeat()},this.ws.onmessage=e=>{const t=JSON.parse(e.data),{type:s,data:i,code:r,msg:n}=t;if(0!==s&&console.warn(s),s===rt.OUT_CALL&&0!==r&&(ct.emit(it.OUT_FAILED,n),this.stateIdleChange()),s===rt.AGENT_STATE){const{state:e,state_name:t}=i;pi.stateObject={state:e,state_name:t},ct.emit(it.AGENT_STATE,{state:e,state_name:t})}s===rt.OUT_CALL_INCOMING_CALL&&(ct.emit(it.OUT_INCOMING_CALL,i),pi.sessionId=i.session_id,dt.updateActionConfigs(bi)),s===rt.OUT_CALL_END&&(0===i.device_type||1===i.device_type?(this.putAgentState(),dt.reset(),ct.emit(it.OUT_HANGUP,i)):2===i.device_type&&(dt.get("direction")===tt.CONSULT?(dt.reset(),ct.emit(it.OUR_SIDE_CONSULT_HANGUP,i),this.putAgentState()):dt.get("isCalling")&&(dt.updateDisplayText(ot.CALLING),ct.emit(it.OTHER_SIDE_CONSULT_HANGUP,i),dt.updateActionConfigs(Ti)))),s===rt.OUT_CALL_RINGING&&(ct.emit(it.OUT_RINGING,i),dt.updateDisplayText(ot.RINGING)),s===rt.OUT_CALL_ANSWER&&(ct.emit(it.OUT_OFF_ANSWER,i),dt.updateOutCallIsAnswer(!0),dt.updateDisplayText(ot.CALLING),dt.updateActionConfigs(Ti)),s===rt.CONSULT_RINGING&&(ct.emit(it.CONSULT_RINGING,i),dt.updateDisplayText(ot.AGENT_RINGING),dt.updateActionConfigs([])),s===rt.CONSULT_ANSWER&&(ct.emit(it.CONSULT_OFF_HOOK,i),dt.updateConsultIsAnswer(!0),dt.updateDisplayText(ot.CONSULTING),dt.updateActionConfigs(Si)),s===rt.CONSULT_FAIL&&(ct.emit(it.CONSULT_FAILED),dt.updateDisplayText(ot.CALLING),dt.updateActionConfigs(Ti)),s===rt.CONSULT_CALL_IN&&(ct.emit(it.CONSULT_INCOMING,i),dt.updateIsCalling(!0),dt.updateDirection(tt.CONSULT),dt.updateDisplayText(ot.CONSULT_CALL_IN),dt.updateActionConfigs(Ei),pi.enableBrowserAlert&&Oi.show("📞 咨询来电",`坐席 [${i.agent_name}] 正在咨询...`,()=>{ct.emit(nt.NOTIFICATION_CLICK,{agent_mane:i.agent_name})})),s===rt.CONSULT_CALL_IN_SUCCESS&&(pi.sessionId=i.session_id,ct.emit(it.CONSULT_CALL_IN_SUCCESS,i),dt.updateConsultIsAnswer(!0),dt.updateDisplayText(ot.CALLING),dt.updateActionConfigs(Ci)),s===rt.MUTE&&(0===r?(dt.updateIsMuted(!0),ct.emit(it.MUTE_SUCCESS)):ct.emit(it.MUTE_FAILED,n)),s===rt.UNMUTE&&(0===r?(dt.updateIsMuted(!1),ct.emit(it.UNMUTE_SUCCESS)):ct.emit(it.UNMUTE_FAILED,n)),s===rt.CONSULT_TRANSFER&&(0===r?ct.emit(it.CONSULT_TRANSFER_SUCCESS):ct.emit(it.CONSULT_TRANSFER_FAILED,n)),s===rt.CONSULT_TRANSFER_FAILED&&ct.emit(it.CONSULT_TRANSFER_FAILED,i.status),s===rt.CONSULT_TRANSFER_OFF_HOOK&&(dt.updateDirection(tt.INCOMING),dt.updateDisplayText(ot.CALLING),ct.emit(it.CONSULT_TRANSFER_OFF_HOOK),dt.updateActionConfigs(Ai),dt.updateIncomingIsAnswer(!0),dt.updateConsultIsAnswer(!1)),s===rt.INCOMING_CALL&&(pi.sessionId=i.session_id,dt.updateIsCalling(!0),dt.updateDirection(tt.INCOMING),dt.updateDisplayText(ot.INCOMING_CALL),ct.emit(it.INCOMING_CALL,{customer_phone:i.customer_phone}),dt.updateActionConfigs(Ei),pi.enableBrowserAlert&&Oi.show("📞 客户来电",`客户 [${i.customer_phone}] 正在呼入...`,()=>{ct.emit(nt.NOTIFICATION_CLICK,{customer_phone:i.customer_phone})})),s===rt.INCOMING_CALL_OFF_HOOK&&(dt.updateIncomingIsAnswer(!0),ct.emit(it.INCOMING_CALL_OFF_HOOK),dt.updateActionConfigs(Ai),dt.updateDisplayText(ot.CALLING)),s===rt.INCOMING_CALL_END&&(ct.emit(it.INCOMING_CALL_END),dt.reset(),dt.updateActionConfigs(wi),this.putAgentState()),0!==s&&Pi.emit("ws-message",t)},this.ws.onclose=()=>{this.stopHeartbeat(),this.manualClose||setTimeout(()=>this.initWebSocket(),this.reconnectDelay)},this.ws.onerror=()=>{this.ws?.close()}}startHeartbeat(){const e=new Blob(["\n let timer;\n self.onmessage = function (e) {\n if (e.data === 'start') {\n timer = setInterval(() => {\n self.postMessage('heartbeat');\n }, 14000);\n } else if (e.data === 'stop') {\n clearInterval(timer);\n }\n };\n "],{type:"application/javascript"}),t=URL.createObjectURL(e);this.heartbeatWorker=new Worker(t),this.heartbeatWorker.onmessage=()=>{this.sendMessage({type:0})},this.heartbeatWorker.postMessage("start")}stopHeartbeat(){this.heartbeatWorker&&(this.heartbeatWorker.postMessage("stop"),this.heartbeatWorker.terminate(),this.heartbeatWorker=null)}sendMessage(e){this.ws?.readyState===WebSocket.OPEN?this.ws.send(JSON.stringify(e)):console.warn("WebSocket 未连接,消息未发送")}close(){this.manualClose=!0,this.stopHeartbeat(),this.ws?.close()}static __internalClose(){qi&&(qi.close(),qi=null)}static __internalSend(e){if(!qi)throw new Error("WebSocket 尚未初始化");qi.sendMessage(e)}}return class{#e=null;#t=new Ni;#s=null;#i=!1;#r;constructor(){clearInterval(this.#s),this.#s=setInterval(async()=>{const e=await this.#n();fi.updateRttObject(e)},2e3),Oi.requestMediaPermissions(),window.addEventListener("beforeunload",()=>{this.destroy()}),this.#r=dt.subscribeKey("answerDevice",e=>{1===e&&this.initWebRtc()})}async initWebRtc(){const e=pi.agentInfo.sip_account_list.find(e=>1===e.device_type);if(e){const t=e.sip_register_addr;this.#e=new mi({server:t.split(":")[0],user:e.sip_account,password:e.sip_password,webSocket:`wss://${t}`,callTimeout:3e4},this.#o),await this.#e.start()}}async init({actionNodeParams:e,url:t,appKey:s,appSecret:i,agentNo:r,enableBrowserAlert:n}){try{const{viewHtmlElement:o,rttHTML:a}=e;di=t||"https://aicc-api.yescloudy.com",li=s,gi=i;const c=Ft(s,i);await this.#t._agentLogin(r);const{agent_no:h,current_answer_device:d,init_state:l}=pi.agentInfo;l===et.IDLE?(dt.updateActionConfigs(wi),pi.stateObject={state:l,state_name:"空闲"}):l===et.BUSY&&(dt.updateActionConfigs(yi),pi.stateObject={state:l,state_name:"忙碌"}),Li.getInstance(`ws://112.90.183.54:8719/api/v1/ws/call/${h}?Authorization=${c}`),dt.updateAnswerDevice(d),1===d&&await this.initWebRtc(),e&&o&&(this.#i=!0,new Hi({container:o,rttHTML:a,statusParams:{state:et.IDLE,statusName:"空闲"}},this)),pi.enableBrowserAlert=n,n&&Oi.requestPermission()}catch(e){this.#i&&oi("初始化失败"),console.log(e)}}#o=e=>{const{type:t,data:s}=e;ct.emit(t,s)};#a=e=>{};on(e,t){return ct.on(e,t),this}off(e,t){ct.off(e,t)}offAll(){ct.clearAllListeners()}#c(){if(!this.#e)throw new Error("请先初始化SDK");const e=dt.get("isCalling"),t=pi.sessionId;if(!e)throw new Error("当前没有通话");if(!t)throw new Error("sessionId不存在")}#h(){const e=dt.get("isHold"),{sessionId:t}=pi;if(t){if(e)throw new Error("当前已处于保持状态");Li.__internalSend({type:rt.CALL_HOLD,data:{session_id:t}}),dt.updateDisplayText(ot.HOLD),dt.updateIsHold(!0)}}#d(){const{isHold:e}=dt.getState(),{sessionId:t}=pi;if(t){if(!e)throw new Error("当前未处于保持状态");Li.__internalSend({type:rt.CALL_UNHOLD,data:{session_id:t}}),dt.updateDisplayText(""),dt.updateIsHold(!1)}}#l(e){if(!this.#e)throw new Error("请先初始化SDK");const{isCalling:t}=dt.getState();if(!t)throw new Error("当前没有通话");this.#e.sendDTMF(e)}#g(){if(1!==dt.get("answerDevice"))throw new Error("当前设备不支持此功能");if(!this.#e)throw new Error("请先初始化SDK");const{isCalling:e,direction:t,outCallIsAnswer:s}=dt.getState();if(!e)throw new Error("当前没有通话");s||(t===tt.INCOMING?this.#u():t===tt.OUTGOING&&this.#p())}async#f(e){if(!this.#e)throw new Error("请先初始化SDK");const{isCalling:t,outCallIsAnswer:s,consultIsAnswer:i,incomingIsAnswer:r}=dt.getState(),n=pi.sessionId;if(i)throw new Error("当前正在咨询");if(!(t||s||r))throw new Error("当前没有通话");if(!n)throw new Error("sessionId不存在");Li.__internalSend({type:rt.CONSULT_REQUEST,data:{session_id:n,consultation_agent_no:e}})}async#m(){if(1!==dt.get("answerDevice"))throw new Error("当前设备不支持此功能");if(!this.#e)throw new Error("请先初始化SDK");await this.#e.answerCall()}async#u(){if(!this.#e)throw new Error("请先初始化SDK");const{isCalling:e}=dt.getState();if(!e)throw new Error("当前没有通话");await this.#e.rejectInCall()}async#v(e){if(!this.#e)throw new Error("请先初始化SDK");if(dt.getState().isCalling)throw new Error("正在呼叫中,请勿重复点击");dt.updateIsCalling(!0),dt.updateDirection(tt.OUTGOING),Li.__internalSend({type:rt.OUT_CALL,data:{customer_phone:e}})}async#p(){const{isCalling:e}=dt.getState();if(!this.#e)throw new Error("请先初始化SDK");if(!e)throw new Error("当前没有通话");await this.#e.rejectOutCall()}async#w(){if(!this.#e)throw new Error("请先初始化SDK");if(!dt.get("isCalling"))throw new Error("当前没有通话");await this.#e.hangup()}#y(){this.#c();const e=dt.get("actionConfigs"),t=dt.get("isMuted"),s=pi.sessionId;if(t)throw new Error("当前未处于静音状态");if(!e.includes("mute"))throw new Error("当前状态请勿调用静音");Li.__internalSend({type:rt.MUTE,data:{session_id:s}})}#b(){this.#c();const e=dt.get("actionConfigs"),t=dt.get("isMuted"),s=pi.sessionId;if(!t)throw new Error("当前未处于未静音状态");if(!e.includes("unmute"))throw new Error("当前状态请勿调用静音");Li.__internalSend({type:rt.UNMUTE,data:{session_id:s}})}#T(){this.#c();const e=dt.get("consultIsAnswer"),t=pi.sessionId;if(!dt.get("actionConfigs").includes("consult_transfer"))throw new Error("当前状态请勿调用咨询转移");if(!e)throw new Error("当前未处于咨询中");Li.__internalSend({type:rt.CONSULT_TRANSFER,data:{session_id:t}})}async destroyRtc(){await(this.#e?.destroy())}destroy(){this.destroyRtc(),Pi.off("ws-message",this.#a),Li.__internalClose(),this.offAll(),this.#r?.()}async#n(){return this.#e?this.#e.getNetworkStats():{}}get call_api(){return this.#i?{answerCall:this.#m.bind(this),makeCall:this.#v.bind(this),cancelCall:this.#g.bind(this),hangup:this.#w.bind(this),sendDTMF:this.#l.bind(this),holdCall:this.#h.bind(this),unholdCall:this.#d.bind(this),consultCall:async e=>{try{await this.#f(e)}catch(e){throw console.warn(e),e}},consultTransfer:this.#T.bind(this),mute:this.#y.bind(this),unmute:this.#b.bind(this)}:{}}get agent_api(){return this.#i?{changeDevice:this.#t.changeDevice.bind(this.#t),changeState:this.#t.changeState.bind(this.#t),getIdleAgentList:e=>this.#t.getIdleAgentList(e),getAgentState:e=>this.#t.getAgentState(e)}:{}}}});
777
+ `;Ws(i,this.rttHTML)}}const Pi=new class{constructor(){this.events={}}on(e,t){this.events[e]=this.events[e]||[],this.events[e].push(t)}off(e,t){this.events[e]=(this.events[e]||[]).filter(e=>e!==t)}emit(e,...t){(this.events[e]||[]).forEach(e=>e(...t))}};class Oi{static requestPermission(){"Notification"in window&&"default"===Notification.permission&&Notification.requestPermission()}static async requestMediaPermissions(){try{const e=await navigator.mediaDevices.enumerateDevices();if(e.some(e=>"audioinput"===e.kind&&""!==e.label))return console.log("已授权麦克风权限,无需再次获取"),null;const t=await navigator.mediaDevices.getUserMedia({audio:!0});return console.log("获取音频权限成功"),t}catch(e){return console.warn("获取音频权限失败:",e),null}}static show(e,t,s){if("Notification"in window&&"granted"===Notification.permission){const i=new Notification(e,{body:t,tag:"xy-global-notification",renotify:!0});i.onclick=()=>{window.focus(),i.close(),s?.()},setTimeout(()=>i.close(),5e3)}}static async checkMediaPermissions(){try{return(await navigator.mediaDevices.enumerateDevices()).some(e=>"audioinput"===e.kind&&""!==e.label)}catch(e){return console.warn("无法检查设备权限:",e),!1}}}let qi=null;class Li{constructor(e){this.url=e,this.ws=null,this.heartbeatWorker=null,this.reconnectDelay=3e3,this.manualClose=!1,this.apiClient=new Ni,this.initWebSocket()}static getInstance(e){if(!qi){if(!e)throw new Error("WebSocket 尚未初始化");qi=new Li(e)}return qi}stateIdleChange(){const{state:e}=pi.stateObject;e!==et.IDLE&&this.apiClient.changeState({data:{state:et.IDLE,state_name:"空闲"}})}putAgentState(){pi.sessionId="";const{post_call_process_time:e}=pi.agentInfo,t=e||0;pi.autoStateTimer&&(clearTimeout(pi.autoStateTimer),pi.autoStateTimer=null),t>0?pi.autoStateTimer=setTimeout(()=>{pi.autoStateTimer=null,this.stateIdleChange()},t):this.stateIdleChange()}initWebSocket(){this.ws=new WebSocket(this.url),this.ws.onopen=()=>{this.sendMessage({type:0}),this.startHeartbeat()},this.ws.onmessage=e=>{const t=JSON.parse(e.data),{type:s,data:i,code:r,msg:n}=t;if(0!==s&&console.warn(s),s===rt.OUT_CALL&&0!==r&&(ct.emit(it.OUT_FAILED,n),this.stateIdleChange()),s===rt.AGENT_STATE){const{state:e,state_name:t}=i;pi.stateObject={state:e,state_name:t},ct.emit(it.AGENT_STATE,{state:e,state_name:t})}s===rt.OUT_CALL_INCOMING_CALL&&(ct.emit(it.OUT_INCOMING_CALL,i),pi.sessionId=i.session_id,dt.updateActionConfigs(bi)),s===rt.OUT_CALL_END&&(0===i.device_type||1===i.device_type?(this.putAgentState(),dt.reset(),ct.emit(it.OUT_HANGUP,i)):2===i.device_type&&(dt.get("direction")===tt.CONSULT?(dt.reset(),ct.emit(it.OUR_SIDE_CONSULT_HANGUP,i),this.putAgentState()):dt.get("isCalling")&&(dt.updateDisplayText(ot.CALLING),ct.emit(it.OTHER_SIDE_CONSULT_HANGUP,i),dt.updateActionConfigs(Ti)))),s===rt.OUT_CALL_RINGING&&(ct.emit(it.OUT_RINGING,i),dt.updateDisplayText(ot.RINGING)),s===rt.OUT_CALL_ANSWER&&(ct.emit(it.OUT_OFF_ANSWER,i),dt.updateOutCallIsAnswer(!0),dt.updateDisplayText(ot.CALLING),dt.updateActionConfigs(Ti)),s===rt.CONSULT_RINGING&&(ct.emit(it.CONSULT_RINGING,i),dt.updateDisplayText(ot.AGENT_RINGING),dt.updateActionConfigs([])),s===rt.CONSULT_ANSWER&&(ct.emit(it.CONSULT_OFF_HOOK,i),dt.updateConsultIsAnswer(!0),dt.updateDisplayText(ot.CONSULTING),dt.updateActionConfigs(Si)),s===rt.CONSULT_FAIL&&(ct.emit(it.CONSULT_FAILED),dt.updateDisplayText(ot.CALLING),dt.updateActionConfigs(Ti)),s===rt.CONSULT_CALL_IN&&(ct.emit(it.CONSULT_INCOMING,i),dt.updateIsCalling(!0),dt.updateDirection(tt.CONSULT),dt.updateDisplayText(ot.CONSULT_CALL_IN),dt.updateActionConfigs(Ei),pi.enableBrowserAlert&&Oi.show("📞 咨询来电",`坐席 [${i.agent_name}] 正在咨询...`,()=>{ct.emit(nt.NOTIFICATION_CLICK,{agent_mane:i.agent_name})})),s===rt.CONSULT_CALL_IN_SUCCESS&&(pi.sessionId=i.session_id,ct.emit(it.CONSULT_CALL_IN_SUCCESS,i),dt.updateConsultIsAnswer(!0),dt.updateDisplayText(ot.CALLING),dt.updateActionConfigs(Ci)),s===rt.MUTE&&(0===r?(dt.updateIsMuted(!0),ct.emit(it.MUTE_SUCCESS)):ct.emit(it.MUTE_FAILED,n)),s===rt.UNMUTE&&(0===r?(dt.updateIsMuted(!1),ct.emit(it.UNMUTE_SUCCESS)):ct.emit(it.UNMUTE_FAILED,n)),s===rt.CONSULT_TRANSFER&&(0===r?ct.emit(it.CONSULT_TRANSFER_SUCCESS):ct.emit(it.CONSULT_TRANSFER_FAILED,n)),s===rt.CONSULT_TRANSFER_FAILED&&ct.emit(it.CONSULT_TRANSFER_FAILED,i.status),s===rt.CONSULT_TRANSFER_OFF_HOOK&&(dt.updateDirection(tt.INCOMING),dt.updateDisplayText(ot.CALLING),ct.emit(it.CONSULT_TRANSFER_OFF_HOOK),dt.updateActionConfigs(Ai),dt.updateIncomingIsAnswer(!0),dt.updateConsultIsAnswer(!1)),s===rt.INCOMING_CALL&&(pi.sessionId=i.session_id,dt.updateIsCalling(!0),dt.updateDirection(tt.INCOMING),dt.updateDisplayText(ot.INCOMING_CALL),ct.emit(it.INCOMING_CALL,{customer_phone:i.customer_phone}),dt.updateActionConfigs(Ei),pi.enableBrowserAlert&&Oi.show("📞 客户来电",`客户 [${i.customer_phone}] 正在呼入...`,()=>{ct.emit(nt.NOTIFICATION_CLICK,{customer_phone:i.customer_phone})})),s===rt.INCOMING_CALL_OFF_HOOK&&(dt.updateIncomingIsAnswer(!0),ct.emit(it.INCOMING_CALL_OFF_HOOK),dt.updateActionConfigs(Ai),dt.updateDisplayText(ot.CALLING)),s===rt.INCOMING_CALL_END&&(ct.emit(it.INCOMING_CALL_END),dt.reset(),dt.updateActionConfigs(wi),this.putAgentState()),0!==s&&Pi.emit("ws-message",t)},this.ws.onclose=()=>{this.stopHeartbeat(),this.manualClose||setTimeout(()=>this.initWebSocket(),this.reconnectDelay)},this.ws.onerror=()=>{this.ws?.close()}}startHeartbeat(){const e=new Blob(["\n let timer;\n self.onmessage = function (e) {\n if (e.data === 'start') {\n timer = setInterval(() => {\n self.postMessage('heartbeat');\n }, 14000);\n } else if (e.data === 'stop') {\n clearInterval(timer);\n }\n };\n "],{type:"application/javascript"}),t=URL.createObjectURL(e);this.heartbeatWorker=new Worker(t),this.heartbeatWorker.onmessage=()=>{this.sendMessage({type:0})},this.heartbeatWorker.postMessage("start")}stopHeartbeat(){this.heartbeatWorker&&(this.heartbeatWorker.postMessage("stop"),this.heartbeatWorker.terminate(),this.heartbeatWorker=null)}sendMessage(e){this.ws?.readyState===WebSocket.OPEN?this.ws.send(JSON.stringify(e)):console.warn("WebSocket 未连接,消息未发送")}close(){this.manualClose=!0,this.stopHeartbeat(),this.ws?.close()}static __internalClose(){qi&&(qi.close(),qi=null)}static __internalSend(e){if(!qi)throw new Error("WebSocket 尚未初始化");qi.sendMessage(e)}}return class{#e=null;#t=new Ni;#s=null;#i=!1;#r;constructor(){clearInterval(this.#s),this.#s=setInterval(async()=>{const e=await this.#n();fi.updateRttObject(e)},2e3),Oi.requestMediaPermissions(),window.addEventListener("beforeunload",()=>{this.destroy()}),this.#r=dt.subscribeKey("answerDevice",e=>{1===e&&this.initWebRtc()})}async initWebRtc(){const e=pi.agentInfo.sip_account_list.find(e=>1===e.device_type);if(e){const t=e.sip_register_addr;this.#e=new mi({server:t.split(":")[0],user:e.sip_account,password:e.sip_password,webSocket:`wss://${t}`,callTimeout:3e4},this.#o),await this.#e.start()}}async init({actionNodeParams:e,url:t,appKey:s,appSecret:i,agentNo:r,enableBrowserAlert:n}){try{const{viewHtmlElement:o,rttHTML:a}=e;di=t||"https://aicc-api.yescloudy.com",li=s,gi=i;const c=Ft(s,i);await this.#t._agentLogin(r);const{agent_no:h,current_answer_device:d,init_state:l}=pi.agentInfo;l===et.IDLE?(dt.updateActionConfigs(wi),pi.stateObject={state:l,state_name:"空闲"}):l===et.BUSY&&(dt.updateActionConfigs(yi),pi.stateObject={state:l,state_name:"忙碌"}),Li.getInstance(`ws://112.90.183.54:8719/api/v1/ws/call/${h}?Authorization=${c}`),dt.updateAnswerDevice(d),1===d&&await this.initWebRtc(),e&&o&&(this.#i=!0,new Hi({container:o,rttHTML:a,statusParams:{state:et.IDLE,statusName:"空闲"}},this)),pi.enableBrowserAlert=n,n&&Oi.requestPermission()}catch(e){this.#i&&oi("初始化失败"),console.log(e)}}#o=e=>{const{type:t,data:s}=e;ct.emit(t,s)};#a=e=>{};on(e,t){return ct.on(e,t),this}off(e,t){ct.off(e,t)}offAll(){ct.clearAllListeners()}#c(){if(!this.#e)throw new Error("请先初始化SDK");const e=dt.get("isCalling"),t=pi.sessionId;if(!e)throw new Error("当前没有通话");if(!t)throw new Error("sessionId不存在")}#h(){const e=dt.get("isHold"),{sessionId:t}=pi;if(t){if(e)throw new Error("当前已处于保持状态");Li.__internalSend({type:rt.CALL_HOLD,data:{session_id:t}}),dt.updateDisplayText(ot.HOLD),dt.updateIsHold(!0)}}#d(){const{isHold:e}=dt.getState(),{sessionId:t}=pi;if(t){if(!e)throw new Error("当前未处于保持状态");Li.__internalSend({type:rt.CALL_UNHOLD,data:{session_id:t}}),dt.updateDisplayText(""),dt.updateIsHold(!1)}}#l(e){if(!this.#e)throw new Error("请先初始化SDK");const{isCalling:t}=dt.getState();if(!t)throw new Error("当前没有通话");this.#e.sendDTMF(e)}#g(){if(1!==dt.get("answerDevice"))throw new Error("当前设备不支持此功能");if(!this.#e)throw new Error("请先初始化SDK");const{isCalling:e,direction:t,outCallIsAnswer:s}=dt.getState();if(!e)throw new Error("当前没有通话");s||(t===tt.INCOMING?this.#u():t===tt.OUTGOING&&this.#p())}async#f(e){if(!this.#e)throw new Error("请先初始化SDK");const{isCalling:t,outCallIsAnswer:s,consultIsAnswer:i,incomingIsAnswer:r}=dt.getState(),n=pi.sessionId;if(i)throw new Error("当前正在咨询");if(!(t||s||r))throw new Error("当前没有通话");if(!n)throw new Error("sessionId不存在");Li.__internalSend({type:rt.CONSULT_REQUEST,data:{session_id:n,consultation_agent_no:e}})}async#m(){if(1!==dt.get("answerDevice"))throw new Error("当前设备不支持此功能");if(!this.#e)throw new Error("请先初始化SDK");await this.#e.answerCall()}async#u(){if(!this.#e)throw new Error("请先初始化SDK");const{isCalling:e}=dt.getState();if(!e)throw new Error("当前没有通话");await this.#e.rejectInCall()}async#v(e){if(!this.#e)throw new Error("请先初始化SDK");if(dt.getState().isCalling)throw new Error("正在呼叫中,请勿重复点击");dt.updateIsCalling(!0),dt.updateDirection(tt.OUTGOING),Li.__internalSend({type:rt.OUT_CALL,data:{customer_phone:e}})}async#p(){const{isCalling:e}=dt.getState();if(!this.#e)throw new Error("请先初始化SDK");if(!e)throw new Error("当前没有通话");await this.#e.rejectOutCall()}async#w(){if(!this.#e)throw new Error("请先初始化SDK");if(!dt.get("isCalling"))throw new Error("当前没有通话");await this.#e.hangup()}#y(){this.#c();const e=dt.get("actionConfigs"),t=dt.get("isMuted"),s=pi.sessionId;if(t)throw new Error("当前未处于静音状态");if(!e.includes("mute"))throw new Error("当前状态请勿调用静音");Li.__internalSend({type:rt.MUTE,data:{session_id:s}})}#b(){this.#c();const e=dt.get("actionConfigs"),t=dt.get("isMuted"),s=pi.sessionId;if(!t)throw new Error("当前未处于未静音状态");if(!e.includes("unmute"))throw new Error("当前状态请勿调用静音");Li.__internalSend({type:rt.UNMUTE,data:{session_id:s}})}#T(){this.#c();const e=dt.get("consultIsAnswer"),t=pi.sessionId;if(!dt.get("actionConfigs").includes("consult_transfer"))throw new Error("当前状态请勿调用咨询转移");if(!e)throw new Error("当前未处于咨询中");Li.__internalSend({type:rt.CONSULT_TRANSFER,data:{session_id:t}})}async destroyRtc(){await(this.#e?.destroy())}destroy(){this.destroyRtc(),clearInterval(this.#s),Pi.off("ws-message",this.#a),Li.__internalClose(),this.offAll(),this.#r?.()}async#n(){return this.#e?this.#e.getNetworkStats():{}}get call_api(){return this.#i?{answerCall:this.#m.bind(this),makeCall:this.#v.bind(this),cancelCall:this.#g.bind(this),hangup:this.#w.bind(this),sendDTMF:this.#l.bind(this),holdCall:this.#h.bind(this),unholdCall:this.#d.bind(this),consultCall:async e=>{try{await this.#f(e)}catch(e){throw console.warn(e),e}},consultTransfer:this.#T.bind(this),mute:this.#y.bind(this),unmute:this.#b.bind(this)}:{}}get agent_api(){return this.#i?{changeDevice:this.#t.changeDevice.bind(this.#t),changeState:this.#t.changeState.bind(this.#t),getIdleAgentList:e=>this.#t.getIdleAgentList(e),getAgentState:e=>this.#t.getAgentState(e)}:{}}}});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ysyt-agent-sdk",
3
- "version": "1.0.15",
3
+ "version": "1.0.17",
4
4
  "main": "dist/ysyt-agent-sdk.cjs.js",
5
5
  "module": "dist/ysyt-agent-sdk.esm.js",
6
6
  "types": "dist/index.d.ts",