(function(){ class SPZCustomSubscribeCancel extends SPZ.BaseElement { constructor(element) { super(element); } isLayoutSupported(layout) { return layout === SPZCore.Layout.LOGIC; } buildCallback(){ this.registerAction('cancel', (invocation) => { this.cancelSubscribe(); }); /* this.registerAction('showviewcount', (invocation) => { this.showViewCount(); }); */ this.registerAction('showretain', (invocation) => { this.showRetain(); }); this.registerAction('showCancel', (invocation) => { const date = invocation?.args?.date || "" this.showCancel(date); }); } showCancel(date){ /* 显示取消订阅弹窗 加入时间 */ const descContent = document.querySelector('#subscribe_cancel_lightbox .desc_content'); if(descContent){ descContent.innerText = `Your subscription will be canceled on the last day of the billing cycle (${date}), and we will no longer charge you any fees. You can choose to renew at any time before that date.` } /* 打开弹窗 */ const cancelBox = document.querySelector('#subscribe_cancel_lightbox_prev'); SPZ.whenApiDefined(cancelBox).then(apis=>{ apis.open(); }) } cancelSubscribe(){ fetch(location.origin+'/apps/best-short/api/v1/customer/subscribe/cancel',{method:'POST'}) .then(res=>res.json()) .then(res=>{ if(res.errors && res.errors[0]){ window.customToast(res.errors[0], 'error') }else{ const confirm = document.querySelector('#subscribe_cancel_lightbox'); SPZ.whenApiDefined(confirm).then(apis=>{ apis.close(); }) } }).catch(err=>console.error('[cancelSubscribe-err]', err)) } formatPlayCount(num) { // 处理非数字类型输入 if (typeof num !== 'number' || isNaN(num)) return '0'; // 处理负数(播放量通常不会为负) if (num < 0) num = 0; if (num >= 1e6) { const value = num / 1e6; return `${value % 1 === 0 ? value : value.toFixed(1).replace(/\.0$/, '')}M`; } if (num >= 1e3) { const value = num / 1e3; return `${value % 1 === 0 ? value : value.toFixed(1).replace(/\.0$/, '')}K`; } return num.toString(); } showRetain(){ let prods = []; prods = prods.map(ele=>({ cover: { src: ele.image.src}, id: ele.id})); fetch(location.origin+'/apps/best-short/api/v1/customer/subscribe/cancel_retain') .then(res=>res.json()) .then(res=>{ if(res && res.skit_infos){ res.skit_infos = res.skit_infos.map(ele=>({...ele, view_count: this.formatPlayCount(Number(ele.view_count) || 0)})) prods = prods.filter(ele=> !res.skit_infos.find(item=>item.skit_id == ele.id)); const cancelList = document.querySelector('#subscribe_cancel_list'); SPZ.whenApiDefined(cancelList).then(apis=>{ const finalList = [...res.skit_infos, ...prods].slice(0,18); apis.render(finalList); }) } }) } /* showViewCount(){ const items = document.querySelectorAll('.like_list .like_item'); if(!items.length) return; const ids = []; items.forEach(ele=> ids.push(ele.dataset.pid)); fetch(location.origin+'/apps/best-short/api/v1/preview/skit/views',{method:'POST',body: JSON.stringify({product_ids: ids})}) .then(res=>res.json()) .then(res=>{ if(res && res.data){ const vals = Object.values(res.data); vals.forEach((ele,index)=>{ const item = items[index]; const count = Number(ele.views); if(count){ const viewCountDom = item.querySelector('.viewcount'); viewCountDom.style = "display: block;" const countDom = item.querySelector('.count'); countDom.innerText = this.formatPlayCount(count); } }) } }).catch(err=>console.error('[showViewCount]', err)); } */ } SPZ.defineElement('spz-custom-subscribe-cancel', SPZCustomSubscribeCancel); })() (function(){ class SPZCustomSubscribeList extends SPZ.BaseElement { trackMode = 1; trackProductId = undefined; constructor(element) { super(element); } isLayoutSupported(layout) { return layout === SPZCore.Layout.CONTAINER; } buildCallback() { this.registerAction('onRender', (invocation) => { this.fixHandleChange(); this.handleConfirm(); const data = invocation?.args?.data?.data || {}; this.listData = invocation?.args?.data?.data || []; this.refreshSubscribeList(data); }); this.registerAction('track', (invocation) => { if ('currentVideoPlayer' in window) { this.trackMode = 2; this.trackProductId = window.currentVideoPlayer.getCurrentVideoId(); } else { this.trackMode = 1; this.trackProductId = undefined; } this.trackViewContent(); setTimeout(()=>{ this.trackImpression(); }, 2000); }); this.registerAction('onCloseClick', (invocation) => { this.onCloseClick(); }); this.registerAction('onOpen', (invocation) => { const list = document.querySelector('#subscribe_list_render .subscribe_list'); if(list){ list.scrollTo(0,0); } }); } refreshSubscribeList(data){ const plans = data.subscribe_plans || []; const info = data.selling_plan_info || {}; const items = data.line_items || []; const mergedPlans = plans.map(plan=>{ let finalPrice = plan.price; const discount = info[plan.id] || {}; const item = items.find(i=>i.product_id === plan.id); finalPrice = item?.final_line_price; return { ...plan, final_price: finalPrice, selling_plan_info: discount } }); this.subscribeList = mergedPlans; } onCloseClick(){ const listBox = document.querySelector('#subscribe_lightbox'); SPZ.whenApiDefined(listBox).then(apis=>{ apis.close(); }) const abandonActivityId = this.listData?.market_activity?.entitled_product_ids?.[0]; let abandonActivity = null; if(abandonActivityId){ const subscribePlan = this.listData.subscribe_plans?.find(ele=>ele.id == abandonActivityId); if(!subscribePlan) return; const item = this.listData.line_items.find(ele=>ele.product_id == abandonActivityId) || {}; const info = this.subscribeList.find(ele=>ele.id == abandonActivityId); const config = this.listData?.market_activity?.config; const sellingPlan = this.listData?.selling_plan_info?.[abandonActivityId]; const sellingPlanId = sellingPlan?.selling_plan_options?.[0]?.selling_plan_option_id; abandonActivity = {...item, ...info, config, _selling_plan_option_id: sellingPlanId}; const abandonBox = document.querySelector('#subscribe_ab_dis_box'); SPZ.whenApiDefined(abandonBox).then(apis=>{ apis.open(); }) const abandonLogic = document.querySelector('#subscribe_ab_discount_logic'); SPZ.whenApiDefined(abandonLogic).then(apis=>{ apis.renderContent(abandonActivity); }) this.pureTrackAddToCart({ id: item.product_id, title: item.product_title, price: item.final_line_price, variant_id: item.variant_id, variant: item.variant_id }); } } trackImpression() { window.csTracker.track('function_expose', { event_name: 'function_expose', event_type: 'popup_expose', event_info: JSON.stringify({ skit_user_id: window.csTracker.getSkitUid(), mode: this.trackMode, product_id: this.trackProductId, }), }, ['sa']); /* 需要排除掉支付挽留,默认第二个 */ let showList = this.listData?.subscribe_plans || []; const line_items = this.listData?.line_items; const abandonActivityId = this.listData?.market_activity?.entitled_product_ids?.[0]; if(abandonActivityId){ showList = showList.filter(item=>item.id != abandonActivityId); } let defaultItem = showList?.[0]; if(showList.length > 1){ let defaultItem = showList?.[1]; } const defaultLineItem = this.listData?.line_items.find(ele=>ele.product_id == defaultItem?.id) || {}; defaultItem = { ...defaultItem, ...defaultLineItem} if(defaultItem){ this.pureTrackAddToCart({ id: defaultItem.id, title: defaultItem.title, price: defaultItem.final_line_price, variant_id: defaultItem.variant_id, }); } window.csTracker.track('function_click', { event_name: 'function_click', event_type: 'click', event_info: JSON.stringify({ skit_user_id: window.csTracker.getSkitUid(), mode: this.trackMode, opt_type: 5, product_id: this.trackProductId, plan_id: defaultItem.id }), }, ['sa']); if(location.pathname.includes('/products/')){ window.sa.track('add_to_cart', { product_id: null, product_title: null, price: null, variant_id: window.currentVideoPlayer.getCurrentEpisodeId(), quantity: 1, sku_quantity: 1, entrance: 'product', currency: window.C_SETTINGS.currency_code, }); const gtagAdsCountry = "shoplaza_" + (window.ADS_COUNTRY || "US") + "_"; const variantId = window.currentVideoPlayer.getCurrentEpisodeId(); const trackId = gtagAdsCountry + variantId; window.csTracker.track('add_to_cart', { currency: window.C_SETTINGS.currency_code, value: null, name: null, user_id: window.csTracker.getClientId(), items: [ { id: trackId, item_id: trackId, item_name: null, item_list_name: 'product', item_brand: "", item_category: "", item_variant: window.currentVideoPlayer.getCurrentEpisode().no.toString(), price: null, quantity: 1, google_business_vertical: 'retail', } ] }, ['ga']); } } trackViewContent(){ let showlist = this.subscribeList.slice(); const abandonActivityId = this.listData?.market_activity?.entitled_product_ids?.[0]; if(abandonActivityId){ showlist = showlist.filter(item=>item.id != abandonActivityId); } showlist = showlist.filter(ele=>!!ele.final_price); const maxCount = Number("4") || 4; showlist = showlist.slice(0,maxCount); showlist.forEach(item=>{ window.csTracker.track('ViewContent', { name: item.title, id: item.variant_id, content_ids: [item.variant_id], content_name: item.title, num_items: 1, currency: window.C_SETTINGS.currency_code, value: item.final_price }, ['fb']); }); /* 套餐曝光 */ const product_ids = showlist.map(item=>item.id); window.csTracker.track('function_expose', { event_name: 'function_expose', event_type: 'expose', event_info: JSON.stringify({ skit_user_id: window.csTracker.getSkitUid(), product_ids, expose_type: 2 }), }, ['sa']); } pureTrackAddToCart(item) { document.dispatchEvent(new CustomEvent('dj.addToCart', { detail: { event_time: new Date().getTime(), product_id: item.id, name: item.title, item_price: item.price, variant_id: item.variant_id, variant: { option1: item.title, }, quantity: '1', number: '1' } })); } /* 上报 initiateCheckRate */ trackOrder(name, pid){ /* window.csTracker.track('initiateCheck', { name: name, id: pid }, ['ga','fb']); */ window.csTracker.track('function_click', { event_name: 'function_click', event_type: 'click', event_info: JSON.stringify({ skit_user_id: window.csTracker.getSkitUid(), opt_type: 1, mode: this.trackMode, product_id: this.trackProductId, }), }, ['sa']); /* if(location.pathname.includes('/products/')){ const name = ""; const id = window.currentVideoPlayer.getCurrentVideoId(); window.csTracker.track('initiateCheck', { name: name, id: id }, ['ga','fb']); } */ } showLoading(){ const loading = document.querySelector('#subscribe_loading'); SPZ.whenApiDefined(loading).then(apis=>{ apis.show_(); }) } hideLoading(){ const loading = document.querySelector('#subscribe_loading'); SPZ.whenApiDefined(loading).then(apis=>{ apis.close_(); }) } mountCallback() { const loading = document.querySelector('#subscribe_list_render'); SPZ.whenApiDefined(loading).then(apis=>{ apis.render(); }) } fixHandleChange(){ const list = document.querySelectorAll('#subscribe_lightbox .subscribe_list .item-wrapper'); list.forEach(item => { item.onclick = () => { const checkedItem = document.querySelector('.subscribe_list .item-checked'); if(item.dataset.pid == checkedItem.dataset.pid){ return; } const list = document.querySelectorAll('#subscribe_lightbox .subscribe_list .item-wrapper'); list.forEach(item=>{ item.classList.remove('item-checked')}) item.classList.add('item-checked'); const listItem = this.subscribeList.find(ele=>ele.id === item.dataset.pid); this.pureTrackAddToCart({ id: listItem.id, title: listItem.title, price: listItem.final_price, variant_id: listItem.variant_id, }); window.csTracker.track('function_click', { event_name: 'function_click', event_type: 'click', event_info: JSON.stringify({ skit_user_id: window.csTracker.getSkitUid(), mode: this.trackMode, opt_type: 5, product_id: this.trackProductId, plan_id: listItem.id }), }, ['sa']); } }) } getCookie(name) { // 创建正则表达式来匹配指定名称的 Cookie const regex = new RegExp('(^|; )' + encodeURIComponent(name) + '=([^;]*)'); const match = document.cookie.match(regex); // 如果找到匹配项,则返回解码后的值,否则返回 null return match ? decodeURIComponent(match[2]) : null; } handleConfirm(){ const skit_uid = this.getCookie('skit-uid'); const confirm = document.querySelector('#subscribe_lightbox .confirm'); confirm.onclick = async()=>{ document.dispatchEvent(new CustomEvent('dj.checkoutSubmit', { detail: {} })); this.showLoading(); const checked = document.querySelector('#subscribe_lightbox .subscribe_list .item-checked'); const pid = checked.dataset.pid; const vid = checked.dataset.vid; const name = checked.dataset.name; let userEmail = ''; let lastName = ''; try{ await fetch(location.origin+'/api/customers/show').then(res=>res.json()).then(res=>{ if(res && res.customer && res.customer.id){ userEmail = res.customer.email; lastName = res.customer.last_name; localStorage.setItem('CUSTOMER_INFO', JSON.stringify(res.customer)); }else{ localStorage.removeItem('CUSTOMER_INFO'); } }) }catch(e){ console.error('[customer-show]', e) } window._local_id_email = userEmail; window._local_last_name = lastName; window._disable_show_agree = true; let params = {_best_short_uid: skit_uid}; const listItem = this.subscribeList.find(ele=>ele.id == pid); params['_selling_plan_option_id'] = listItem.selling_plan_info.selected_selling_plan_option_id; params['link'] = location.href; params['entry'] = '权益中心'; params['short_id'] = ''; if(location.pathname.includes('/products/')){ params['entry'] = '短剧'; params['short_id'] = window.currentVideoPlayer.getCurrentVideoId(); } const referrer = decodeURIComponent(this.getCookie('latest_referrer') || ''); if(referrer){ const referrerHost = new URL(referrer).hostname; params["_ad_from"] = referrerHost; } /* https://feature-v1-3---short-best.dev.myshoplaza.com/apps/best-short-pay/api/v1/checkout/order */ fetch(`${location.origin}/apps/bs-pay/api/v1/checkout/order`, { method: 'POST', headers:{ "Content-Type": "application/json" }, body: JSON.stringify({ line_items: [{quantity:"1", product_id: pid, properties: params, note:"",variant_id:vid }], refer_info: { source :"buy_now", create_identity: btoa(window.C_SETTINGS.shop.shop_id)}, options: { with_uid: true } }) }) .then(response => response.json()) .then(res=>{ if(res && res.check_out_url){ const lightbox = document.querySelector('#subscribe_lightbox'); SPZ.whenApiDefined(lightbox).then((box)=>{ box.close(); this.hideLoading(); localStorage.setItem('COMMON_NAMESPACE', window.SHOPLAZZA.namespace); localStorage.setItem('BS_PREV_URL', location.href); localStorage.setItem('SHOP_ID', window.C_SETTINGS.shop.shop_id); localStorage.setItem('BS_TRACK_PARAMS', JSON.stringify(window.sa.trackParams)); if(window.fbq){ localStorage.setItem('FBQ_PIXELS', JSON.stringify(window.fbq?.getState?.() || {})); } if (location.pathname.includes('/products/')) { const name = ""; const videoId = window.currentVideoPlayer.getCurrentVideoId(); localStorage.setItem('BS_PRODUCT_VIDEO', JSON.stringify({ name, id: videoId })); localStorage.setItem('BS_VIDEO_VARIANT_ID', JSON.stringify(window.currentVideoPlayer?.getCurrentEpisodeId?.())); } else { localStorage.removeItem('BS_PRODUCT_VIDEO'); localStorage.removeItem('BS_VIDEO_VARIANT_ID'); } window.csTracker.track('function_click', { event_name: 'function_click', event_type: 'click', event_info: JSON.stringify({ skit_user_id: window.csTracker.getSkitUid(), mode: this.trackMode, opt_type: 1, product_id: this.trackProductId, plan_id: pid }), }, ['sa']); let orderId = ''; if (res && res.check_out_url) { const match = res.check_out_url.match(/\/order\/(\d+)/); if (match && match[1]) { orderId = `/order/${match[1]}`; } } document.dispatchEvent(new CustomEvent('dj.initiateCheckout', { detail: { id: orderId, checkout_page_type: 'single', order_id: orderId, currency: window.C_SETTINGS.market.market_currency, quantity: '1', line_items: [{ product_id: pid, variant_id: vid, quantity: 1, properties: params, }], prices: { total_price: this.subscribeList.find(item => item.id === pid).final_price, } } })); if(location.pathname.includes('/products/')){ window.sa.track('begin_checkout', { product_id: null, product_title: null, price: null, variant_id: window.currentVideoPlayer.getCurrentEpisodeId(), quantity: 1, sku_quantity: 1, entrance: 'product', currency: window.C_SETTINGS.currency_code, content_ids: null }); const gtagAdsCountry = "shoplaza_" + (window.ADS_COUNTRY || "US") + "_"; const variantId = window.currentVideoPlayer.getCurrentEpisodeId(); const trackId = gtagAdsCountry + variantId; window.csTracker.track('begin_checkout', { name: null, value: null, coupon: "", currency: window.C_SETTINGS.currency_code, user_id: window.csTracker.getClientId(), item_id: trackId, items:{ id: trackId, item_id: trackId, item_name: null, item_brand: "", item_category: "", item_variant: window.currentVideoPlayer.getCurrentEpisode().no.toString(), price: null, quantity:1, google_business_vertical: "retail", } }, ['ga']); } location.href=`${location.origin}${res.check_out_url}`; }); }else{ console.error('[order-error]', res); if(res.message || res.error){ window.customToast(res.message || res.error,'error'); }else{ window.customToast('Order failed','error'); } this.hideLoading(); } }).catch((error)=>{ console.error('[error-fetch]', error); }) /* .finally(()=>{ this.trackOrder(name, pid); }) */ } } } SPZ.defineElement('spz-custom-subscribe-list', SPZCustomSubscribeList); })() (function(){ class SPZCustomSubscribeCheckout extends SPZ.BaseElement { constructor(element) { super(element); } isLayoutSupported(layout) { return layout === SPZCore.Layout.CONTAINER; } buildCallback() { /* console.info('[window]', window); */ this.addIFrameCallback(); } hideLoading(){ const loading = document.querySelector('#subscribe_loading'); SPZ.whenApiDefined(loading).then(apis=>{ apis.close_(); }) } trackPayCount(params){ window.csTracker.track('checkoutStepPayment', params, ['ga','fb']); if(location.pathname.includes('/products/')){ const name = ""; const id = window.currentVideoPlayer.getCurrentVideoId(); window.csTracker.track('checkoutStepPayment', { name: name, id: id }, ['ga','fb']); } } trackPaySuccess(params){ window.csTracker.track('purchase', params, ['ga','fb']); if(location.pathname.includes('/products/')){ const name = ""; const id = window.currentVideoPlayer.getCurrentVideoId(); window.csTracker.track('purchase', { ...params, name: name, id: id }, ['ga','fb']); } } payCallback(val){ if(val.res.state == 'success'){ const checkout = document.querySelector('#subscribe_checkout_lightbox'); SPZ.whenApiDefined(checkout).then(async(apis)=>{ apis.close(); let hasLoggedIn = false; try{ await fetch(location.origin+'/api/customers/show').then(res=>res.json()).then(res=>{ if(res && res.customer && res.customer.id){ hasLoggedIn = true; } }) }catch(e){ console.error('[pay-customers/show]', e); } if(location.pathname.includes('pages/short-me')){ const customer = document.querySelector('#me_customer_info'); SPZ.whenApiDefined(customer).then((apis) => { apis.fresh(); }); } /* 已登录 提示成功,未登录 让注册 */ if(hasLoggedIn){ const okBox = document.querySelector('#subscribe_pay_logged_ok_box'); SPZ.whenApiDefined(okBox).then((apis) => { apis.open(); }); }else{ location.href = '/account/register'; /* const meElement =document.querySelector('#me_account_element'); SPZ.whenApiDefined(meElement).then((apis)=>{ if(val.res.email){ apis.presetEmail(val.res.email); } apis.showType('account_register'); }) const accountBox = document.querySelector('#me_account_lightbox'); SPZ.whenApiDefined(accountBox).then((apis)=>{ apis.open(); }) */ } }); this.trackPaySuccess(val.params) } } addIFrameCallback(){ window.receivedata = (val) => { console.info('[receive]', val); /* Checkout Ready */ if(val && val.type=='READY'){ const lightbox = document.querySelector('#subscribe_lightbox'); SPZ.whenApiDefined(lightbox).then((box)=>{ box.close(); const checkout = document.querySelector('#subscribe_checkout_lightbox'); SPZ.whenApiDefined(checkout).then((apis)=>{ apis.open(); this.hideLoading(); }) }); const loader = document.querySelector('#subscribe_checkout_lightbox .cs_checkout_mask'); loader && (loader.style = 'display: none') } /* 支付结果 */ if(val && val.type=='PAY'){ this.payCallback(val); } /* LOADING */ if(val && val.type=="LOADING"){ const loader = document.querySelector('#subscribe_checkout_lightbox .cs_checkout_mask'); loader && (loader.style = 'display: flex'); } /* 上报 */ if(val && val.type=="PAY_TRACK"){ this.trackPayCount(val.params); } } } } SPZ.defineElement('spz-custom-subscribe-checkout', SPZCustomSubscribeCheckout); })() (function(){ class SPZCustomLoggedPayOk extends SPZ.BaseElement { constructor(element) { super(element); } isLayoutSupported(layout) { return layout === SPZCore.Layout.LOGIC; } buildCallback(){ this.registerAction('onOpen', (invocation) => { const btn = document.querySelector('#subscribe_pay_logged_ok_box .main_btn'); btn && (btn.innerText = '3s close'); let count = 2; let interval = setInterval(()=>{ if(count==0){ clearInterval(interval); const box = document.querySelector('#subscribe_pay_logged_ok_box'); SPZ.whenApiDefined(box).then((apis) => { apis.close(); }); } btn && (btn.innerText = count+'s close'); count--; },1000); }); this.registerAction('reloadstate', (invocation) => { this.reloadstate(); }); } reloadstate(){ location.reload(); } } SPZ.defineElement('spz-custom-logged-pay-ok', SPZCustomLoggedPayOk); })()