(function() {
const script = document.currentScript;
const src = script.src;
const queryString = src.substring(src.indexOf('?') + 1);
const urlParams = new URLSearchParams(queryString);
const uuidUrl = urlParams.get('uuid');
const isCn = src.includes('saasflow.cn')
const capsuleStyleStr = `
@media screen and (max-width: 769px) {
.sfchat-capsule {
/* keep floating button visible on mobile */
}
.sflow-chat-plugin {
width: 80% !important;
left: 10% !important;
margin-left: 0 !important;
height: 70vh !important;
}
.sflow-chat-plugin-content{
z-index: 999;
}
.sflow-chat-plugin-iframe{
overflow: visible !important;
}
}
.chatai-animated {
border: 2px solid #5D7EFF !important;
border-radius: 50% !important;
animation: pulse-scale 2s infinite !important;
box-sizing: border-box !important;
overflow: hidden !important;
}
@keyframes pulse-scale {
0% {
transform: translate(-50%, -50%) scale(0.8);
}
100% {
transform: translate(-50%, -50%) scale(1);
}
}
.sfchat-capsule {
position: fixed;
width: 70px;
background: #3E69FF;
border-radius: 50px;
top: 40%;
right: 10px;
z-index: 999;
display: flex;
flex-direction: column;
align-items: center;
padding: 0px 0;
box-shadow: 0px 0px 10px 0px rgba(0, 0, 0, 0.06);
}
.sfchat-capsule.useAvatar-capsule{
width: 200px;
height: 200px;
background: transparent !important;
}
.sfchat-capsule.useAvatar-capsule.large{
width: 200px;
height: 200px;
}
.sfchat-capsule.useAvatar-capsule.medium{
width: 100px;
height: 100px;
}
.sfchat-capsule.useAvatar-capsule.small{
width: 50px;
height: auto;
}
.use-avatar-box{
width: 100%;
height: 100%;
position: relative;
cursor: pointer;
}
.use-avatar-box.small{
width: 36px;
height: 36px;
border-radius: 50%;
position: relative;
overflow: hidden;
}
.use-avatar-box.medium{
width: 100px;
height: 100px;
border-radius: 20px;
position: relative;
overflow: hidden;
}
.use-avatar-box.large{
width: 180px;
height: 180px;
border-radius: 10px;
position: relative;
overflow: hidden;
}
.sfchat-capsule.useAvatar-capsule .use-avatar-box .video-avatar{
object-fit: cover;
}
.useAvatar-capsule .avatar-float-content{
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
.useAvatar-capsule .avatar-float-content-box{
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
justify-content: flex-end;
align-items: center;
cursor: pointer;
padding-bottom: 30px;
box-sizing: border-box;
}
.use-avatar-box.medium .avatar-float-content-box{
padding-bottom: 20px;
}
.use-avatar-box.medium .avatar-float-content-box .img-icon{
width: 20px;
height: 20px;
}
.use-avatar-box.medium .avatar-float-content-box .avatar-float-content-word{
font-size: 12px;
}
.use-avatar-box.small .avatar-float-content-box{
padding-bottom: 10px;
}
.useAvatar-capsule .img-icon{
width: 28px;
height: 28px;
margin-bottom: 5px;
}
.useAvatar-capsule .avatar-float-content-word{
color: white;
font-size: 12px;
font-weight: 500;
text-align: center;
}
.sfchat-capsule .phone,
.sfchat-capsule .email,
.sfchat-capsule .chatAi,
.sfchat-capsule .wx_qrcode_dom {
width: 50px;
display: flex;
height: 33%;
justify-content: center;
align-items: center;
position: relative;
cursor: pointer;
height: 50px;
}
.chat-widget-item {
height: 75px;
width: 100%;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
padding: 0px 0;
border-bottom: 1px solid #eee;
box-sizing: content-box;
}
.chat-widget-item:last-child {
border: none;
padding-bottom: 6px;
}
.chat-widget-item-content {
position: relative;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
}
.chat-widget-item a {
text-decoration: none;
color: inherit;
}
.chat-widget-item-content-box{
}
.chat-widget-item-content .chatai-widget-item-word{
// position: absolute;
font-size: 12px;
bottom: -26px;
white-space: nowrap;
color: #aaa;
left: 53%;
// transform: translateX(-50%);
color: #436ff6;
margin-top: 6px;
}
.sfchat-capsule .chatAi {
cursor: pointer;
background: #436ff6;
position: relative;
border-radius: 50%;
}
.sfchat-capsule .chatAi:before {
content: "";
display: block;
position: absolute;
top: 50%;
left: 50%;
width: 130%;
height: 130%;
-webkit-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
-webkit-animation: scale2 1s linear infinite alternate;
animation: pulse-scale 1s linear infinite alternate;
background-color: #436ff6;
border-radius: 50%;
opacity: 0.4;
}
.sfchat-capsule .chatAi .chatAi-content{
position: relative;
display: flex;
align-items: center;
justify-content: center;
}
.sfchat-capsule .chatAi .chatAi-content img{
height: 30px;
width: 30px;
}
.sfchat-capsule .chat-widget-item .email img,
.sfchat-capsule .chat-widget-item .phone img{
height: 26px;
width: 26px !important;
}
.sfchat-capsule .chatAi .chatAi-content .chatai-zx-word{
position: absolute;
font-size: 12px;
bottom: -40px;
white-space: nowrap;
color: #aaa;
left: 50%;
transform: translateX(-50%);
color: #436ff6;
}
.sfchat-capsule .chatAi .customicon{
width: 34px;
height: 34px;
border-radius: 50%;
}
.sfchat-capsule hr {
height: 1px;
width: 20px;
color: #698AFF;
margin: 0 16px;
}
.sfchat-capsule .email img ,
.sfchat-capsule .phone img {
width: 1.35rem;
}
.sfchat-capsule img {
width: 1.75rem;
position: relative;
left: 1px;
}
.sfchat-capsule .text {
display: none;
position: absolute;
right: 80px;
height: 50px;
background: #FFFFFF;
box-shadow: 0px 5px 20px 0px rgba(122, 132, 165, 0.3);
border-radius: 10px;
padding: 0 10px;
font-size: 14px;
z-index: 9999;
color: #698AFF !important;
}
.sfchat-capsule .text p{
color: #698AFF !important;
}
.sfchat-email-menu {
position: absolute;
right: 80px;
top: -6px;
background: #ffffff;
border: 1px solid rgba(62, 105, 255, 0.2);
box-shadow: 0 8px 20px rgba(122, 132, 165, 0.25);
border-radius: 8px;
padding: 6px;
z-index: 10000;
min-width: 160px;
}
.sfchat-email-menu button {
display: block;
width: 100%;
border: none;
background: #ffffff;
color: #3E69FF;
font-size: 13px;
padding: 6px 8px;
text-align: left;
cursor: pointer;
}
.sfchat-email-menu button:hover {
background: rgba(62, 105, 255, 0.08);
}
.sfchat-capsule .wx-qrcode-text{
padding: 10px 10px !important;
}
.sfchat-capsule .chatAi .text {
width: 120px;
height: 60px;
}
.sfchat-capsule .chatAi .text .chatai-text-words{
display: flex;
flex-direction: column;
justify-content: center;
align-items: flex-start;
height: 60px;
}
.sfchat-capsule .chatAi .text .chatai-text-word1{
font-weight: 500;
color: #436ff6;
line-height: 16px;
font-size: 16px;
}
.sfchat-capsule .chatAi .text .chatai-text-word2{
font-size: 12px;
line-height: 12px;
margin-top: 8px;
color: #999;
white-space: nowrap;
}
.sfchat-capsule .email .text {
width: 170px;
}
.sfchat-capsule .phone .text {
width: 140px;
}
.sfchat-capsule p {
position: relative;
width: 100%;
height: 100%;
text-align: center;
display: flex;
justify-content: center;
align-items: center;
margin: 0;
}
/* .sfchat-capsule .wechat .text{
width: 320px;
height: 320px;
text-align: center;
}
*/
.sfchat-capsule span {
position: absolute;
display: inline-block;
border: 1px dashed transparent;
border-top: 7px solid transparent;
border-bottom: 7px solid transparent;
border-left: 12px solid #fff;
top: 36%;
right: -12px;
}
.chatai-sf-list-container {
position: absolute;
display: none;
top: -75px;
left: -360px;
transition: 1.3s;
opacity: 0;
}
.chatai-sf-list-aiimg {
position: absolute;
right: -40px;
top: 46px;
width: 30px;
height: 30px;
cursor: pointer;
top: 50%;
transform: translateY(-100%);
}
.chatai-sf-list-aiimg img {
width: 30px;
}
.chatai-sf-list {
position: relative;
height: 230px;
overflow: hidden;
width: 300px;
padding: 0;
margin: 0;
pointer-events: none;
}
.chatai-sf-list li {
position: absolute;
right: 0;
padding: 0 10px;
opacity: 0;
transition: opacity 1s, top 1s;
background-color: white;
height: 50px;
display: flex;
align-items: center;
box-shadow: 0 0 20px #eee;
border-radius: 10px 20px 0px 10px;
text-align: left;
margin: 0;
color: black;
white-space: pre-wrap;
width: max-content;
}
.chatai-sf-list li.li-hide {
opacity: 0 !important;
}
.chatai-sf-list li:nth-child(-n+2) {
opacity: 1;
}
.chatai-sf-list li:nth-child(1) {
top: 0;
}
.chatai-sf-list li:nth-child(2) {
top: 70px;
}
.chatai-sf-list li:nth-child(3) {
top: 140px;
}
.chatai-sf-list li:nth-child(4) {
top: 210px;
}
.chatai-sf-list.fade-out {
opacity: 0;
}
.chatai-sf-list.fade-in {
opacity: 1;
}
.chatAi-red-dot {
position: absolute;
top: -3px;
right: -3px;
width: 1.1rem;
height: 1.1rem;
background: #ff3b30;
border-radius: 50%;
z-index: 10;
box-shadow: 0 0 2px #fff;
border: 2px solid #fff;
pointer-events: none;
color: white;
font-size: 12px;
display: flex;
justify-content: center;
align-items: center;
}
`
const capsuleStyle = document.createElement("style")
capsuleStyle.innerHTML = capsuleStyleStr
document.head.appendChild(capsuleStyle)
const chatLayerStyleStr = `
.sflow-chat-shade {
top: 0;
left: 0;
width: 100%;
height: 100%;
display: none;
z-index: 19891014;
background-color: rgb(0, 0, 0);
opacity: 0.3;
}
.sflow-chat-plugin,
.sflow-chat-shade {
position: fixed;
pointer-events: auto;
}
.sflow-chat-plugin.sflow-chat-small{
width: 46vh;
height: 77.5vh;
left: auto;
right: 1.5%;
top: auto;
bottom: 5%;
}
.sflow-chat-plugin.sflow-chat-small .sflow-chat-plugin-min{
display: none;
}
.sflow-chat-plugin-max{
display: none !important;
}
.sflow-chat-plugin-iframe {
overflow-y: auto;
-webkit-overflow-scrolling: touch;
}
.sflow-chat-plugin {
bottom: 2%;
right: 5%;
margin: 0;
padding: 0;
background-color: #fff;
-webkit-background-clip: content;
border-radius: 12px;
box-shadow: 1px 1px 50px rgba(0, 0, 0, .3);
position: fixed;
margin-left: -35%;
margin-top: 20px;
overflow: hidden;
display: none;
transition: 0.09s;
z-index: 19891015000;
width: 360px;
height: 607px;
}
.sflow-chat-plugin-move {
display: none;
position: fixed;
*position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
/* cursor: move; */
opacity: 0;
filter: alpha(opacity=0);
background-color: #fff;
z-index: 2147483647;
}
.sflow-chat-plugin-title {
padding: 0 80px 0 20px;
height: 50px;
line-height: 50px;
border-bottom: 1px solid #f0f0f0;
font-size: 14px;
color: #333;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
border-radius: 2px 2px 0 0;
}
.sflow-chat-plugin-lan-sf .sflow-chat-plugin-title {
background-color: #285cd1;
color: white;
}
.sflow-chat-plugin-title {
display:flex;
align-items:center;
}
.sflow-chat-plugin-title img{
width: 30px;
height: 30px;
}
.sflow-chat-plugin-content {
position: relative;
width: 100%;
height: calc(100% - 50px);
}
.sflow-chat-plugin-content iframe {
width: 100%;
height: 100%;
}
.sflow-chat-plugin-setwin {
position: absolute;
right: 15px;
*right: 0;
top: 16px;
font-size: 0;
line-height: initial;
}
.sflow-chat-plugin-resize {
position: absolute;
width: 15px;
height: 15px;
right: 0;
bottom: 0;
cursor: se-resize;
}
.sflow-chat-plugin-setwin span {
position: relative;
width: 16px;
height: 16px;
line-height: 18px;
margin-left: 10px;
text-align: center;
font-size: 16px;
cursor: pointer;
color: #000;
_overflow: hidden;
}
.sflow-chat-plugin-btn a,
.sflow-chat-plugin-setwin span {
display: inline-block;
*display: inline;
*zoom: 1;
vertical-align: top;
}
.sflow-chat-plugin-setwin span {
position: relative;
width: 16px;
height: 16px;
line-height: 18px;
margin-left: 10px;
text-align: center;
font-size: 16px;
cursor: pointer;
color: #000;
_overflow: hidden;
}
.sflow-chat-plugin-btn a,
.sflow-chat-plugin-setwin span {
display: inline-block;
*display: inline;
*zoom: 1;
vertical-align: top;
}
.sflow-chat-plugin-setwin span {
position: relative;
width: 16px;
height: 16px;
line-height: 18px;
margin-left: 10px;
text-align: center;
font-size: 16px;
cursor: pointer;
color: #000;
_overflow: hidden;
}
.sflow-chat-plugin-setwin .sflow-chat-plugin-close {
cursor: pointer;
}
`
const chatLayerStyle = document.createElement("style")
chatLayerStyle.innerHTML = chatLayerStyleStr
document.head.appendChild(chatLayerStyle)
class chatLayer {
shade = null;
layer = null;
maxScreen = false
settingInfo = {}
chatSettingInfo = {}
isWhite = false
chatBubbleShow = true
chatBubbleTimer = null
chatBots = []
layoutMode = 'big'
language = "zh"
pendingShow = false
pendingShowForce = false
chatEndStartTimerInfo = {}
constructor() {
this.settingInfo.uuid = uuidUrl
}
createShade() {
const shadeDom = document.createElement("div")
shadeDom.id = "sflow-chat-shade1"
shadeDom.className = "sflow-chat-shade"
this.shade = shadeDom
document.body.appendChild(shadeDom)
}
createLayerIframe() {
const layerDom = document.createElement("div")
layerDom.id = "sflow-chat-plugin1"
layerDom.className = "sflow-chat-plugin sflow-chat-plugin-iframe sflow-chat-plugin-lan-sf"
this.layoutMode = this.chatSettingInfo.chatAIwidgetStyleSize || 'big'
if (this.chatSettingInfo.chatAIwidgetStyleSize && this.chatSettingInfo.chatAIwidgetStyleSize === 'small') {
layerDom.className = "sflow-chat-plugin sflow-chat-plugin-iframe sflow-chat-plugin-lan-sf sflow-chat-small"
}
let chatUrl = "https://chatbot.easiiodev.ai"
// let chatUrl = "http://localhost:1002"
// if (isCn) {
// chatUrl = "https://chat.saasflow.cn"
// } else {
// chatUrl = "https://chat.sflow.io"
// }
const isWhite = this.chatSettingInfo.chatAiTitleColor === '#FFFFFF'
const resolvedAvatarUrl = this.resolveAssetUrl(this.chatSettingInfo.chatAiAvatarUrl, chatUrl)
const avatarUrl = resolvedAvatarUrl || `${chatUrl}/img/default-robot-avatar.svg`
this.isWhite = isWhite
let toolIcons = [
`${chatUrl}/img/ai_chat_icons/minimize.svg`,
`${chatUrl}/img/ai_chat_icons/maximize.svg`,
`${chatUrl}/img/ai_chat_icons/close.svg`
]
if (isWhite) {
toolIcons = [
`${chatUrl}/img/ai_chat_icons/minimize_dark.svg`,
`${chatUrl}/img/ai_chat_icons/maximize_dark.svg`,
`${chatUrl}/img/ai_chat_icons/close_dark.svg`
]
}
layerDom.innerHTML = `
${this.chatSettingInfo.chatAiName || "AI Chatbot"}
`
this.layer = layerDom
document.body.appendChild(layerDom)
if (this.shade) {
this.shade.style.display = 'none'
}
}
createCapsule() {
const capsule = document.createElement("div")
let isChatNeedHr = true
if (this.chatSettingInfo.enableChatAiEmail == 0 && this.chatSettingInfo.enableChatAiPhone == 0) {
isChatNeedHr = false
}
let isEmailNeedHr = true
if (this.chatSettingInfo.enableChatAiDisplay == 0 && this.chatSettingInfo.enableChatAiPhone == 0) {
isEmailNeedHr = false
}
const isCustomicon = [
'techwithsoul.live',
'mikejohns.ceo',
'digitalmindstate.com',
'techthisout.shop',
'www.techthisout.ai'
].includes(window.location.hostname)
// Define chatUrl for this function
let chatUrl = "https://chatbot.easiiodev.ai"
// default icon
const resolvedCapsuleAvatarUrl = this.resolveAssetUrl(this.chatSettingInfo.chatAiAvatarUrl, chatUrl)
let chatAiIconUrl = resolvedCapsuleAvatarUrl || `${chatUrl}/img/default-robot-avatar.svg`
if (isCustomicon && resolvedCapsuleAvatarUrl) {
chatAiIconUrl = resolvedCapsuleAvatarUrl
}
let chatDomStr = `
`
let emailDomStr = `
`
let phoneDomStr = `
`
let weixinDomStr = `
`
if (!this.chatSettingInfo.enableChatAiDisplay) chatDomStr = ''
if (!this.chatSettingInfo.enableChatAiEmail) emailDomStr = ''
if (!this.chatSettingInfo.enableChatAiPhone) phoneDomStr = ''
if (!this.chatSettingInfo.chatAiContactWxQrcode) weixinDomStr = ''
let chatAiPosition = {
top: "40%",
right: "10px"
}
if (this.chatSettingInfo.chatAiFloatToolPosition) {
switch (this.chatSettingInfo.chatAiFloatToolPosition) {
case 'top-left':
chatAiPosition = {
top: "5%",
right: "none"
}
break;
case 'center-left':
chatAiPosition = {
top: "40%",
right: "none"
}
break;
case 'bottom-left':
chatAiPosition = {
top: "70%",
right: "none"
}
break;
case 'top-right':
chatAiPosition = {
top: "5%",
right: "30px"
}
break;
case 'center-right':
break;
case 'bottom-right':
chatAiPosition = {
top: "60%",
right: "30px"
}
break;
case 'top-center':
chatAiPosition = {
top: "5%",
right: "calc(50% - 25px)"
}
break;
case 'center-center':
chatAiPosition = {
top: "48%",
right: "calc(50% - 25px)"
}
break;
case 'bottom-center':
chatAiPosition = {
top: "90%",
right: "calc(50% - 25px)"
}
break;
case 'custom':
try {
const chatAiFloatToolPosition = JSON.parse(this.chatSettingInfo.chatAiFloatToolPositionCustom)
console.log('chatAiFloatToolPosition', chatAiFloatToolPosition)
chatAiPosition = {
top: chatAiFloatToolPosition.y,
right: `calc(100vw - ${chatAiFloatToolPosition.x} - 50px)`,
}
} catch (error) {
console.log('err', error)
}
break;
default:
break;
}
}
let useAvatarAsFloatingTool = 0
let iconSize = "small"
let chatIconSetting = {}
try {
chatIconSetting = JSON.parse(this.chatSettingInfo.chatIconSetting)
useAvatarAsFloatingTool = chatIconSetting.useAvatarAsFloatingTool || 0
iconSize = chatIconSetting.iconSize || "small"
} catch (error) {
}
// let sfchatCapsuleContentStr = `
// ${this.settingInfo.uuid ? chatDomStr : ''}
let sfchatCapsuleContentStr = `
${this.settingInfo.uuid ? chatDomStr : ''}
${this.settingInfo.phone ? phoneDomStr : ''}
${this.settingInfo.email ? emailDomStr : ''}
${this.settingInfo.email ? weixinDomStr : ''}
`
if (useAvatarAsFloatingTool === 1) {
const isVideoType = this.checkIsVideo(this.chatSettingInfo.chatAiAvatarUrl)
const floatingAvatarUrl = resolvedCapsuleAvatarUrl || `${chatUrl}/img/default-robot-avatar.svg`
const that = this
function navToChatFloatPage() {
if (chatIconSetting.open == 1 && chatIconSetting.floatingLink) {
window.open(chatIconSetting.floatingLink, '_blank')
return
}
that.open()
}
window.navToChatFloatPage = navToChatFloatPage
sfchatCapsuleContentStr = `
${isVideoType ? `
` :
`

`
}
${chatIconSetting.open ? `
${chatIconSetting.floatingIcon ? `

` : ''
}
${chatIconSetting.floatingText ? `
${chatIconSetting.floatingText}
` : ''
}
` : ''
}
`
}
// this.chatSettingInfo.chatAiTitleColor = "#ffffff";
// capsule.innerHTML = `
//
// ${sfchatCapsuleContentStr}
//
// `
capsule.innerHTML = `
${sfchatCapsuleContentStr}
`
document.body.appendChild(capsule)
let email = document.querySelector(".sfchat-capsule .email")
if (email) {
let email_text = document.querySelector(".sfchat-capsule .email .text")
const showEmailMenu = () => {
const existingMenu = document.querySelector(".sfchat-email-menu")
if (existingMenu) {
existingMenu.remove()
}
const menu = document.createElement("div")
menu.className = "sfchat-email-menu"
const copyBtn = document.createElement("button")
copyBtn.textContent = this.language === 'en' ? "Copy email" : "复制邮箱"
copyBtn.addEventListener("click", () => {
if (navigator.clipboard && email && email.href) {
navigator.clipboard.writeText(email.href.replace(/^mailto:/, ''))
}
menu.remove()
})
const openBtn = document.createElement("button")
openBtn.textContent = this.language === 'en' ? "Open email" : "打开邮箱"
openBtn.addEventListener("click", () => {
if (email && email.href) {
window.location.href = email.href
}
menu.remove()
})
menu.appendChild(copyBtn)
menu.appendChild(openBtn)
email.appendChild(menu)
const handleOutside = (event) => {
if (!menu.contains(event.target) && !email.contains(event.target)) {
menu.remove()
document.removeEventListener("click", handleOutside)
}
}
setTimeout(() => {
document.addEventListener("click", handleOutside)
}, 0)
}
email.addEventListener('mouseover', function () {
email_text.style.display = 'block'
})
email.addEventListener('mouseout', function () {
email_text.style.display = 'none'
})
email.addEventListener('click', function (event) {
event.preventDefault()
showEmailMenu()
})
}
let phone = document.querySelector(".sfchat-capsule .phone")
if (phone) {
let phone_text = document.querySelector(".sfchat-capsule .phone .text")
phone.addEventListener('mouseover', function () {
phone_text.style.display = 'block'
})
phone.addEventListener('mouseout', function () {
phone_text.style.display = 'none'
})
}
let chatAi = document.querySelector(".sfchat-capsule .chatAi")
if (chatAi) {
let chatAi_text = document.querySelector(".sfchat-capsule .chatAi .text")
chatAi.addEventListener('mouseover', function () {
chatAi_text.style.display = 'block'
})
chatAi.addEventListener('mouseout', function () {
chatAi_text.style.display = 'none'
})
chatAi.onclick = () => {
this.open()
}
}
let weixin = document.querySelector(".sfchat-capsule .wx_qrcode_dom")
if (weixin) {
let weixin_text = document.querySelector(".sfchat-capsule .wx_qrcode_dom .wx-qrcode-text")
weixin.addEventListener('mouseover', function () {
weixin_text.style.display = 'block'
})
weixin.addEventListener('mouseout', function () {
weixin_text.style.display = 'none'
})
}
if (this.chatSettingInfo.enableChatAiWidgetAnimation === 1) {
// this.createChatBubble()
}
}
checkIsVideo(url) {
const videoType = [
"mov",
"mp4",
"avi",
"flv",
"3gp",
"webm",
"rmvb",
"wmv",
"asf",
"asx",
"vob",
"dat",
"mkv",
];
return videoType.includes(
url.split(".")[url.split(".").length - 1].toLowerCase()
);
}
resolveAssetUrl(url, chatUrl) {
if (!url) return url
if (url.startsWith("/")) return `${chatUrl}${url}`
return url
}
async createChatBubble() {
this.chatBubbleShow = true
let sfbots = []
if (this.chatBots.length) {
sfbots = [...this.chatBots].filter(item => {
return !this.checkIsVideo(item.icon || '')
})
} else {
const baseChatUrl = "https://chatbot.easiiodev.ai"
sfbots = [{
icon: this.resolveAssetUrl(this.chatSettingInfo.chatAiAvatarUrl, baseChatUrl) || `${baseChatUrl}/img/default-robot-avatar.svg`
}]
try {
const { data: { getSfbotCharactersBySfbotId: botCharacters } } = await getSfbotCharactersBySfbotId(this.chatSettingInfo.id)
if (botCharacters.length) {
sfbots = sfbots.concat(botCharacters).filter(item => {
return item.title !== 'ChatAI default'
})
}
} catch (error) {
}
sfbots = sfbots.filter(item => {
return !this.checkIsVideo(item.icon || '')
})
this.chatBots = [...sfbots]
}
//
let chatAiWidgetAnimationGreetingStr = this.chatSettingInfo.chatAiWidgetAnimationGreeting
let chatAiWidgetAnimationGreeting = []
try {
chatAiWidgetAnimationGreeting = JSON.parse(chatAiWidgetAnimationGreetingStr)
} catch (error) {
}
if (!chatAiWidgetAnimationGreeting.length) return
console.log('chatAiWidgetAnimationGreeting', chatAiWidgetAnimationGreeting)
let chatAiWidgetAnimationGreetings = ''
let chatAiWidgetAnimationGreetingStyleStr = ''
let liHeightTop = 0
chatAiWidgetAnimationGreeting.forEach((item, index) => {
// 几行文本
const line = (item.content || '').split('\n').length
if (item.link && item.link.includes('http')) {
chatAiWidgetAnimationGreetings += `${item.content}`
} else {
chatAiWidgetAnimationGreetings += `${item.content}`
}
let beishu = Math.ceil(line / 2)
let liHtight = beishu * 50
chatAiWidgetAnimationGreetingStyleStr += `
.chatai-sf-list li:nth-child(${index + 1}) {
top: ${liHeightTop}px;
}
.chatai-sf-list li.li_${index} {
height: ${liHtight}px;
}
`
liHeightTop += (liHtight + 20)
})
// 若不需要显示动画的图标
if (this.chatSettingInfo.enableChatAiWidgetAnimationIconShow == 0) {
chatAiWidgetAnimationGreetingStyleStr += `
.chatai-sf-list-container{
left: -330px;
}
`
}
const animationStyle = document.createElement("style")
animationStyle.innerHTML = chatAiWidgetAnimationGreetingStyleStr
document.head.appendChild(animationStyle)
const enableChatAiWidgetAnimationIconShow = this.chatSettingInfo.enableChatAiWidgetAnimationIconShow
// Hi, I'm ChatAI
// I can give you quick answers to \n popular questions.
// Do you need my help?
const chatBubbleStr = `
${chatAiWidgetAnimationGreetings}
${enableChatAiWidgetAnimationIconShow == 0 ? '' :
``
}
`
let that = this
let curMoveFrequency = 1
// 显示次数
const chatAiWidgetAnimationGreetingShowTimes = this.chatSettingInfo.chatAiWidgetAnimationGreetingShowTimes || 0
let currentChatAiWidgetAnimationGreetingShowTimes = 0
const bubbleMove = () => {
this.chatEndStartTimerInfo.show = setTimeout(function () {
var list = document.querySelector('.chatai-sf-list');
var firstItem = list.querySelector('.chatai-sf-list li:first-child');
var fourthItem = list.querySelector(`.chatai-sf-list li:nth-child(${chatAiWidgetAnimationGreeting.length})`);
firstItem.classList.add('fade-out');
fourthItem.classList.add('fade-in');
that.chatEndStartTimerInfo.startshow = setTimeout(function () {
list.removeChild(firstItem);
list.insertBefore(firstItem, fourthItem.nextSibling);
// 重新计算li的top值
var listItems = list.querySelectorAll('li');
let liHeightTop = 0
for (let index = 0; index < listItems.length; index++) {
const listItem = listItems[index];
listItem.style.top = liHeightTop + 'px'
const liHtight = Number(listItem.offsetHeight)
liHeightTop += (liHtight + 20)
}
firstItem.classList.remove('fade-out');
fourthItem.classList.remove('fade-in');
curMoveFrequency++
if (curMoveFrequency % chatAiWidgetAnimationGreeting.length === chatAiWidgetAnimationGreeting.length - 1) {
currentChatAiWidgetAnimationGreetingShowTimes++
if (chatAiWidgetAnimationGreetingShowTimes && currentChatAiWidgetAnimationGreetingShowTimes >= chatAiWidgetAnimationGreetingShowTimes) {
that.closeChatBubble()
} else {
that.chatEndStartTimerInfo.startshowsleep = setTimeout(() => {
bubbleMove()
}, 1000 * 7);
}
} else {
bubbleMove()
}
}, 1000);
}, 1000);
}
const chataiSfListContainerDom = document.createElement('div')
chataiSfListContainerDom.className = 'chatai-sf-list-container'
if (!this.chatSettingInfo.enableChatAiEmail && !this.chatSettingInfo.enableChatAiPhone) {
chataiSfListContainerDom.style.top = '-70px'
}
chataiSfListContainerDom.innerHTML = chatBubbleStr
const sfchatCapsule = document.querySelector('.sfchat-capsule')
sfchatCapsule.appendChild(chataiSfListContainerDom)
const chatAiImgDom = document.querySelector('.chatai-sf-list-aiimg')
if (chatAiImgDom) {
chatAiImgDom.onclick = () => {
this.open()
}
this.create30SliceImg()
}
setTimeout(() => {
if (this.chatBubbleShow) {
this.chatBubbleShow = false
chataiSfListContainerDom.style.display = 'inline-block'
setTimeout(() => {
chataiSfListContainerDom.style.opacity = 1
bubbleMove()
}, 500);
}
}, 1000 * 20);
}
create30SliceImg() {
// 创建每30s更换头像的定时器
if (this.chatBots.length > 1) {
let currBotImgIndex = 0
this.chatBubbleTimer = setInterval(() => {
currBotImgIndex++
const chatAIImg = document.querySelector('.chatai-sf-list-aiimg img')
chatAIImg.src = this.chatBots[currBotImgIndex % this.chatBots.length].icon
}, 1000 * 30);
}
}
closeChatBubble() {
this.chatBubbleShow = false
const chataiSfListContainerDom = document.querySelector('.chatai-sf-list-container')
if (chataiSfListContainerDom) {
chataiSfListContainerDom.style.opacity = 0
setTimeout(() => {
chataiSfListContainerDom.style.display = 'none'
chataiSfListContainerDom.remove()
}, 1200);
}
clearInterval(this.chatBubbleTimer)
clearTimeout(this.chatEndStartTimerInfo.show)
clearTimeout(this.chatEndStartTimerInfo.startshow)
clearTimeout(this.chatEndStartTimerInfo.startshowsleep)
this.chatEndStartTimerInfo.show = setTimeout(() => {
// this.createChatBubble()
}, 1000 * 40);
}
init() {
if (this.layer) return
this.createShade()
this.createLayerIframe()
this.screenEventInit()
}
screenEventInit() {
const minBtn = document.querySelector(".sflow-chat-plugin-min")
const maxBtn = document.querySelector(".sflow-chat-plugin-max")
const closeBtn = document.querySelector(".sflow-chat-plugin-close")
minBtn.onclick = this.min.bind(this)
maxBtn.onclick = this.max.bind(this)
closeBtn.onclick = this.close.bind(this)
}
min() {
this.shade.style.display = 'none'
this.layer.style.display = 'none'
// Show the floating capsule when minimized
const existingCapsule = document.querySelector('.sfchat-capsule')
if (!existingCapsule) {
this.createCapsule()
} else {
existingCapsule.style.display = 'flex'
}
}
max() {
this.maxScreen = !this.maxScreen
let maxMinIcons = [
"/icons/favicon-32x32.png",
"/icons/favicon-16x16.png"
]
if (this.isWhite) {
maxMinIcons = [
"/icons/favicon-96x96.png",
"/icons/favicon-32x32.png"
]
}
if (this.maxScreen) {
if (this.layoutMode === 'small') {
this.layer.style.width = '70vw'
this.layer.style.height = '83vh'
document.querySelector(".sflow-chat-plugin-max img").src = maxMinIcons[0]
} else {
this.layer.style.width = '100vw'
this.layer.style.height = '100vh'
document.querySelector(".sflow-chat-plugin-max img").src = maxMinIcons[0]
this.layer.style.marginLeft = "0px"
this.layer.style.marginTop = "0px"
this.layer.style.left = "0px"
}
} else {
if (this.layoutMode === 'small') {
this.layer.style.width = '58vh'
this.layer.style.height = '83vh'
document.querySelector(".sflow-chat-plugin-max img").src = maxMinIcons[1]
} else {
this.layer.style.width = '70vw'
this.layer.style.height = '650px'
document.querySelector(".sflow-chat-plugin-max img").src = maxMinIcons[1]
this.layer.style.marginLeft = "-35%"
this.layer.style.marginTop = "20px"
this.layer.style.left = "50%"
}
}
}
close() {
this.min()
return
this.layer.remove()
this.shade.remove()
this.layer = null
this.shade = null
this.maxScreen = false
}
open() {
this.closeChatBubble()
this.init()
// this.shade.style.display = "block"
this.layer.style.opacity = "0"
this.layer.style.display = "block"
this.fadeIn(this.layer)
// Hide the floating capsule when chat window is opened
const existingCapsule = document.querySelector('.sfchat-capsule')
if (existingCapsule) {
existingCapsule.style.display = 'none'
}
}
async set({ uuid, email, phone, language }) {
this.settingInfo.uuid = uuid
if (language)
this.language = language
this.settingInfo.email = email
this.settingInfo.phone = phone
const result = await getChatInfo(uuid)
const isExist = document.querySelector('.sfchat-capsule')
if (isExist) return
if (result && result.data && result.data.getOrgSfbotFromUuid) {
// 匹配是否在忽略目录
try {
if (result.data.getOrgSfbotFromUuid.floatToolIgnoresPages) {
const floatToolIgnoresPages = JSON.parse(result.data.getOrgSfbotFromUuid.floatToolIgnoresPages)
if (Array.isArray(floatToolIgnoresPages) && floatToolIgnoresPages.length) {
const findPage = floatToolIgnoresPages.find(item => {
if (item.title.includes(window.location.pathname)) {
return true
}
})
if (findPage) {
return
}
}
}
} catch (error) {
}
this.chatSettingInfo = result.data.getOrgSfbotFromUuid
if (!language && this.chatSettingInfo.language) {
const sfbotLang = this.chatSettingInfo.language.toLowerCase()
if (sfbotLang === 'en' || sfbotLang === 'en-us')
this.language = 'en'
else if (sfbotLang === 'zh' || sfbotLang === 'zh-cn')
this.language = 'zh'
}
// 判断浏览器是不是手机
if (/Mobi|Android|iPhone/i.test(navigator.userAgent)) {
try {
let chatIconSetting = JSON.parse(this.chatSettingInfo.chatIconSetting)
if (chatIconSetting.iconSize === 'large') {
this.chatSettingInfo = {
...this.chatSettingInfo,
chatIconSetting: '{}'
}
}
} catch (error) {
}
}
this.settingInfo.email = this.chatSettingInfo.contactEmail || this.settingInfo.email
this.settingInfo.phone = this.chatSettingInfo.contactPhone || this.settingInfo.phone
}
if (this.pendingShow) {
const allowAutoPopup = Number(this.chatSettingInfo.chatAiComponentsAutoPupop) === 1
if (this.pendingShowForce || allowAutoPopup) {
this.open()
}
this.pendingShow = false
this.pendingShowForce = false
}
if (!this.chatSettingInfo.enableChatAiFloatTool) return
this.createCapsule()
// 自动弹出逻辑(移动端不自动弹出,仅保留悬浮按钮)
if (this.chatSettingInfo.chatAiComponentsAutoPupop == 1) {
const isMobileDevice = (/Mobi|Android|iPhone|iPad|iPod/i.test(navigator.userAgent)) ||
(window.matchMedia && window.matchMedia('(max-width: 769px)').matches)
if (!isMobileDevice) {
let pupopTime = Number(this.chatSettingInfo.chatAiComponentsAutoPupopTime) || 3;
setTimeout(() => {
if (this.layer) {
return
}
this.show();
}, pupopTime * 1000);
}
}
}
fadeOut(element) {
var speed = speed || 30;
var num = 10;
var st = setInterval(() => {
num--;
element.style.opacity = num / 10;
if (num <= 0) {
clearInterval(st);
}
}, speed);
}
fadeIn(element, speed) {
var speed = speed || 20;
var num = 0;
var st = setInterval(() => {
num++;
element.style.opacity = num / 10;
if (num >= 10) {
clearInterval(st);
}
}, speed);
}
show(force) {
const hasSettingInfo = this.chatSettingInfo && this.chatSettingInfo.id
if (!hasSettingInfo) {
this.pendingShow = true
this.pendingShowForce = !!force
return
}
if (!force && Number(this.chatSettingInfo.chatAiComponentsAutoPupop) !== 1) {
return
}
this.open()
}
}
const getSfApiUrl = () => {
return "https://chatbot.easiiodev.ai"
}
const getChatInfo = (uuid) => {
return new Promise((resolve, reject) => {
fetch(`${getSfApiUrl()}/graphql`, {
method: 'POST',
body: JSON.stringify({
query: `
query getOrgSfbotFromUuid($uuid: String!) {
getOrgSfbotFromUuid(uuid: $uuid){
id
contactPhone
contactEmail
chatAiName
chatAiAvatarUrl
chatAiTitleColor
enableChatAiFloatTool
enableChatAiDisplay
enableChatAiEmail
enableChatAiPhone
enableChatAiWidgetAnimation
enableShopping
chatAiWidgetAnimationGreeting
chatAiFloatToolPosition
chatAiFloatToolPositionCustom
enableChatAiWidgetAnimationIconShow
chatAiWidgetAnimationGreetingShowTimes
chatIconSetting
floatToolIgnoresPages
chatAIwidgetStyleSize
chatAiComponentsAutoPupop
chatAiComponentsAutoPupopTime
chatAiContactWxQrcode
chatAiContactQrcodeLabel
language
}
}
`,
variables: {
uuid: uuid,
},
}),
headers: {
'Content-Type': 'application/json',
},
}).then(res => res.json()).then((res) => {
if (res.errors && res.errors.length) {
resolve(null)
} else {
resolve(res)
}
}).catch((err) => {
resolve(null)
})
})
}
const getSfbotCharactersBySfbotId = (sfbotId) => {
return new Promise((resolve, reject) => {
fetch(`${getSfApiUrl()}/graphql`, {
method: 'POST',
body: JSON.stringify({
query: `
query getSfbotCharactersBySfbotId($sfbotId: Int!) {
getSfbotCharactersBySfbotId(sfbotId: $sfbotId){
id
icon
title
}
}
`,
variables: {
sfbotId: sfbotId,
},
}),
headers: {
'Content-Type': 'application/json',
},
}).then(res => res.json()).then((res) => {
if (res.errors && res.errors.length) {
resolve(null)
} else {
resolve(res)
}
}).catch((err) => {
resolve(null)
})
})
}
const chatlayer = new chatLayer()
window.chatlayer = chatlayer
}())