(function(){ class SPZCustomSubscribeCancel extends SPZ.BaseElement { constructor(element) { super(element); this.action_ = SPZServices.actionServiceForDoc(this.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=>{ const name = 'canceled'; const event = SPZUtils.Event.create(this.win, `spz-custom-subscribe-cancel.${name}`,{}); this.action_.trigger(this.element, name, event); 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; mounting = false; marketActivitieIds = new Set(); constructor(element) { super(element); this.subscribeList = []; this.paymentSettings = null; } isLayoutSupported(layout) { return layout === SPZCore.Layout.CONTAINER; } setMarketActivitieIds(marketActivities) { const set = new Set(); if(marketActivities && marketActivities.length > 0){ marketActivities.forEach(item=> set.add(item.entitled_product_ids?.[0])); this.marketActivitieIds = set; } } buildCallback() { this.registerAction('onRender', (invocation) => { this.fixHandleChange(); this.handleConfirm(); this.setMarketActivitieIds(invocation?.args?.data?.data?.market_activities || []); const data = invocation?.args?.data?.data || {}; this.listData = invocation?.args?.data?.data || []; this.refreshSubscribeList(data); setTimeout(()=>{ this.preloadAbandonImg(); }, 100); }); 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', () => { this.onCloseClick(); }); this.registerAction('onOpen', () => { this.toggleEpisodeSwitchModal(false); const list = document.querySelector('#subscribe_list_render .subscribe_list'); if(list){ list.scrollTo(0,0); if (!this.paymentSettings || !this.mounting) { this.renderECList(); } } }); this.registerAction('storeData', (invocation) => { window.shortSellingType = invocation?.args?.data?.data?.selling_type; }); this.registerAction('startSmartPointer', () => { this.startSmartPointer(); }); this.registerAction('stopSmartPointer', () => { this.stopSmartPointer(); }); } async getPaymentSettings() { try { const res = await fetch("/apps/bs-pay/api/v1/checkout/payment/setting"); const data = await res.json(); return data; } catch (error) { console.error('[getPaymentSettings] error', error); return undefined; } finally { const confirm = document.querySelector('#subscribe_lightbox .confirm'); if(confirm){ confirm.style.pointerEvents = 'auto'; } } } async renderECList(isFirst) { const domSelector = { ...(isFirst ? { paypal: "#payment-ec-paypal-container" } : {}), apple: "#payment-ec-applepay-container", google: "#payment-ec-googlepay-container", } const checked = document.querySelector('#subscribe_lightbox .subscribe_list .item-checked'); const pid = checked?.dataset?.pid; const vid = checked?.dataset?.vid; const price = checked?.dataset?.price; const name = checked?.dataset?.name; const cycleDays = +checked?.dataset?.days; const listItem = this.subscribeList.find(ele=>ele.id === pid); const sellingPlanOptionId = listItem.selling_plan_info.selected_selling_plan_option_id; const lineItem = { variant_id: vid, product_id: pid, product_title: name, price, selling_plan_option_id: sellingPlanOptionId, cycle_days: cycleDays, }; window.shortLineItem = lineItem; this.mounting = true; window.BSPublicJSReady(() => { window.mountBSECPayment(domSelector, this.paymentSettings, lineItem, { onConfirm: () => { this.showLoading(); }, onFinish: () => { this.hideLoading(); }, onError: () => { this.hideLoading(); }, onCancel: () => { this.hideLoading(); }, onInit: (channel) => { this.hideLoading(); } }).then(() => { this.hideLoading(); this.mounting = false; }).catch((err) => { this.hideLoading(); this.mounting = false; }); }); } preloadAbandonImg() { const abandonLogic = document.getElementById('subscribe_ab_discount_logic'); const activities = this.getAbandonActivities(); if (!abandonLogic || !activities) return; SPZ.whenApiDefined(abandonLogic).then((apis) =>{ activities.forEach(activity => { apis.preloadImg(activity); }); }); } async 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; this.paymentSettings = await this.getPaymentSettings(); this.renderECList(true); this.updatePlayerSubscribeData(); } getAbandonActivities() { const marketActivities = this.listData?.market_activities; if (!marketActivities || !Array.isArray(marketActivities)) { return []; } const abandonActivities = []; marketActivities.forEach(marketActivity => { const abandonActivityId = marketActivity?.entitled_product_ids?.[0]; if (abandonActivityId) { const subscribePlan = this.listData.subscribe_plans?.find(ele => ele.id == abandonActivityId); if (!subscribePlan) return; if (!this.listData.line_items) return; const item = this.listData.line_items.find(ele => ele.product_id == abandonActivityId) || {}; const info = this.subscribeList.find(ele => ele.id == abandonActivityId); const config = marketActivity?.config; const priority = marketActivity?.priority; const sellingPlan = this.listData?.selling_plan_info?.[abandonActivityId]; const sellingPlanId = sellingPlan?.selling_plan_options?.[0]?.selling_plan_option_id; const abandonActivity = { ...item, ...info, config, priority, _selling_plan_option_id: sellingPlanId }; abandonActivities.push(abandonActivity); } }); return abandonActivities; } onCloseClick(){ const listBox = document.querySelector('#subscribe_lightbox'); SPZ.whenApiDefined(listBox).then(apis=>{ apis.close(); }) const abandonActivities = this.getAbandonActivities(); const abandonLogic = document.querySelector('#subscribe_ab_discount_logic'); SPZ.whenApiDefined(abandonLogic).then(async (apis)=>{ await apis.startModalSequence(abandonActivities); this.toggleEpisodeSwitchModal(true); }); } 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 || []; if(this.marketActivitieIds.size > 0){ showList = showList.filter(item=>!this.marketActivitieIds.has(item.id)); } showList = showList.filter(item=> +line_items?.find(ele=>ele?.product_id === item?.id)?.final_line_price > 0); let defaultItem = showList?.[0]; if(showList.length > 1){ defaultItem = showList?.[1]; } const checkedItemDOM = document.querySelector('#subscribe_lightbox .item-wrapper.item-checked'); const checkedProductId = checkedItemDOM?.dataset?.pid; const defaultLineItem = line_items.find(ele=>ele.product_id === checkedProductId) || {}; 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']); } trackViewContent(){ let showlist = this.subscribeList.slice(); if(this.marketActivitieIds.size > 0){ showlist = showlist.filter(item=>!this.marketActivitieIds.has(item.id)); } showlist = showlist.filter(ele=>!!ele.final_price); const maxCount = Number("6") || 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']); } formatDate(date) { const year = date.getFullYear(); const month = date.getMonth() + 1; const day = date.getDate(); return `${year}-${month}-${day}`; } pureTrackAddToCart(item) { const currentDate = new Date(); const skitUid = window.csTracker.getSkitUid(); const today = this.formatDate(currentDate); const todayCacheKey = `${today}-${skitUid}`; const cacheKey = `addToCartEventCache`; const cacheData = JSON.parse(localStorage.getItem(cacheKey)) || {}; const todayCache = cacheData[todayCacheKey] || []; if(todayCache.includes(item.id)){ return; } todayCache.push(item.id); cacheData[todayCacheKey] = todayCache; Object.keys(cacheData).forEach(key => { if(!key.startsWith(today)){ delete cacheData[key]; } }); localStorage.setItem(cacheKey, JSON.stringify(cacheData)); 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('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']); } 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 listRender = document.querySelector('#subscribe_list_render'); SPZ.whenApiDefined(listRender).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.renderECList(); // GPay APay 刷新 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; const cycleDays = +checked.dataset.days; 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 }; params['_dj_selling_type'] = window.shortSellingType; params['cycle_days'] = cycleDays; const listItem = this.subscribeList.find(ele => ele.id == pid); if (window.shortSellingType === 'DJ') { params['_selling_plan_dj_option_id'] = listItem.selling_plan_info.selected_selling_plan_option_id; } else { params['_selling_plan_option_id'] = listItem.selling_plan_info.selected_selling_plan_option_id; } params['link'] = location.href; params['entry'] = 'page'; params['short_id'] = ''; params['_sa_track_params'] = window.sa?.trackParams; params['_is_login'] = !!window.C_SETTINGS?.customer?.customer_id; if(location.pathname.includes('/products/')){ params['entry'] = 'product'; params['short_id'] = window.currentVideoPlayer.getCurrentVideoId(); params['short_title'] = null || ''; params['short_variant_id'] = window.currentVideoPlayer?.getCurrentEpisodeId?.() || ''; } const referrer = decodeURIComponent(this.getCookie('latest_referrer') || ''); if(referrer){ const referrerHost = new URL(referrer).hostname; params["_ad_from"] = referrerHost; } 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, selling_type: window.shortSellingType } }) }) .then(response => response.json()) .then(res=>{ if(res && res.check_out_url){ const lightbox = document.querySelector('#subscribe_lightbox'); SPZ.whenApiDefined(lightbox).then((box)=>{ localStorage.setItem('COMMON_NAMESPACE', window.SHOPLAZZA.namespace); localStorage.setItem('BS_PREV_URL', location.href); localStorage.setItem('SHOP_ID', window.C_SETTINGS.shop.shop_id); if(window.fbq){ localStorage.setItem('FBQ_PIXELS', JSON.stringify(window.fbq?.getState?.() || {})); } 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.currency_code, 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']); } this.hideLoading(); const blockOr = this.paymentSettings?.settings?.express_checkout_config?.express_channels?.join(','); const url = blockOr ? `${res.check_out_url}?block_or=${blockOr}&select_payment_method=shoplazzapayment` : `${res.check_out_url}?select_payment_method=shoplazzapayment`; setTimeout(()=>{ location.href = url; }); }); }else{ 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); this.hideLoading(); }) } } updatePlayerSubscribeData() { if (!window.BSPlayerMountReady) return; window.BSPlayerMountReady(() => { if (!window.currentVideoPlayer) return; const marketActivities = this.listData?.market_activities; let filteredList = this.subscribeList; if(marketActivities && marketActivities.length > 0){ const set = new Set(); marketActivities.forEach(item=> set.add(item.entitled_product_ids?.[0])); filteredList = this.subscribeList.filter(item=>!set.has(item.id)); } filteredList = filteredList.filter(item=> !!item.final_price); const maxCount = Number("6") || 4; filteredList = filteredList.slice(0, maxCount); window.currentVideoPlayer.setSubscriptionData(filteredList); }); } toggleEpisodeSwitchModal(status) { if (!window.BSPlayerMountReady) return; window.BSPlayerMountReady(() => { if (!window.currentVideoPlayer) return; if (status) { window.currentVideoPlayer.episodeSwitchModal?.show(); } else { window.currentVideoPlayer.episodeSwitchModal?.hide(); } }); } startSmartPointer() { const fingerWrapper = document.querySelector('#subscribe_lightbox .finger-wrapper'); if(fingerWrapper){ fingerWrapper.style.display = 'block'; } } stopSmartPointer() { const fingerWrapper = document.querySelector('#subscribe_lightbox .finger-wrapper'); if(fingerWrapper){ fingerWrapper.style.display = 'none'; } } } SPZ.defineElement('spz-custom-subscribe-list', SPZCustomSubscribeList); })() (function(){ class SPZCustomTransReportLogic extends SPZ.BaseElement { constructor(element) { super(element); this.transReportList = null this.transReportListScrollInterval = 3000; this.transReportListHeight = 28; this.scrollTime = 200; this.transReportTimer = null; } isLayoutSupported(layout) { return layout === SPZCore.Layout.LOGIC; } buildCallback() { this.registerAction('showTransReport', () => { this.showTransReport(); }); } showTransReport() { // 清除已存在的定时器 this.clearTransReportTimer(); this.transReportList = document.querySelector('.subscribe_trans_report_list'); if (!this.transReportList) { return; } this.transReportList.appendChild(this.generateRandomTransReportItem()); this.transReportTimer = setInterval(() => { this.addNewTransReportItem(); }, this.transReportListScrollInterval); } addNewTransReportItem() { this.transReportList.appendChild(this.generateRandomTransReportItem()); this.animateScroll(); } animateScroll() { const startTime = Date.now(); const animate = () => { const nowTime = Date.now(); const timeDiff = nowTime - startTime; const dis = timeDiff * (this.transReportListHeight / this.scrollTime); this.transReportList.scrollTop = dis; if (dis < this.transReportListHeight) { requestAnimationFrame(animate); } else { this.transReportList.removeChild(this.transReportList.firstChild); } } requestAnimationFrame(animate); } generateRandomTransReportItem() { const div = document.createElement('div'); div.classList.add('subscribe_trans_report_item'); const { time, name, planName } = this.generateRandomTransReport(); div.innerText = `${time} ${name} purchased `; const span = document.createElement('span'); span.classList.add('subscribe_trans_report_plan_name'); span.innerText = planName; div.appendChild(span); return div; } generateRandomTransReport() { const time = this.generateRandomTime(); const username = this.generateRandomUsername(); const name = this.nameDesensitization(username); const planName = this.generateRandomPlanName(); return { time, username, name, planName }; } generateRandomPlanName() { const planDoms = document.querySelectorAll('.subscribe_list .item-wrapper'); if (planDoms && planDoms.length === 0) { return ''; } const randomIndex = Math.floor(Math.random() * planDoms.length); return planDoms[randomIndex].getAttribute('data-name'); } generateRandomTime() { const random = Math.random() * 100; // 生成 0-100 的随机数 let timeText = ''; if (random < 30) { // 30% 的数据:5秒 ~ 59秒前,显示 "Just now" timeText = 'Just now'; } else if (random < 80) { // 50% 的数据:1分钟 ~ 5分钟前,显示 "X mins ago" const minutes = Math.floor(Math.random() * 5) + 1; // 1-5 分钟 timeText = `${minutes} ${minutes === 1 ? 'min' : 'mins'} ago`; } else { // 20% 的数据:6分钟 ~ 15分钟前,显示 "X mins ago" const minutes = Math.floor(Math.random() * 10) + 6; // 6-15 分钟 timeText = `${minutes} mins ago`; } return timeText; } generateRandomUsername() { const names = [ "James", "Mary", "John", "Patricia", "Robert", "Jennifer", "Michael", "Linda", "William", "Elizabeth", "David", "Barbara", "Richard", "Susan", "Joseph", "Jessica", "Thomas", "Sarah", "Charles", "Karen", "Christopher", "Nancy", "Daniel", "Lisa", "Matthew", "Betty", "Anthony", "Margaret", "Mark", "Sandra" ]; const randomIndex = Math.floor(Math.random() * names.length); return names[randomIndex]; } nameDesensitization(name) { if (!name || name.length < 2) { return name + '****'; } return name.substring(0, 2) + '****'; } clearTransReportTimer() { if (this.transReportTimer) { clearInterval(this.transReportTimer); this.transReportTimer = null; } } } SPZ.defineElement('spz-custom-trans-report-logic', SPZCustomTransReportLogic); })() (function(){ class SPZCustomSubscribeSubscript extends SPZ.BaseElement { constructor(element) { super(element); this.payResult = null; } isLayoutSupported(layout) { return layout === SPZCore.Layout.LOGIC; } buildCallback(){ this.registerAction('showsubscript', () => { this.showSubscript(); }); } async showSubscript(){ const listItems = document.querySelectorAll('.subscribe_list .item-wrapper:not(:has(.custom_subscript_item))'); if(listItems.length<=0) return; const productIds = []; listItems.forEach(ele=>{ productIds.push(ele.getAttribute('data-pid')); }); if(productIds.length==0) return; let result = []; try{ const res = await fetch(location.origin+"/apps/best-short/api/v1/subscript", { method:"POST", body: JSON.stringify({ type:'subscription', resource_ids: productIds })}) .then(res=>res.json()); result = res?.data || []; }catch(e){ console.warn('[subscript get error]', e); } result.forEach(ele=>{ const index = productIds.indexOf(ele.id); if(index>=0 && ele.styles?.length>0){ const listItem = listItems[index]; ele.styles.forEach(style=>{ const _item = document.createElement('div'); _item.classList.add('custom_subscript_item'); _item.classList.add('custom_position_'+style.position); _item.classList.add(style.icon); const _span = document.createElement('span'); _span.classList.add('custom_subscript_item_text'); _span.innerHTML = style.content; _item.appendChild(_span); listItem.appendChild(_item.cloneNode(true)); }) } }) } } SPZ.defineElement('spz-custom-subscribe-subscript', SPZCustomSubscribeSubscript); })() (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); })()