${(function(){ const get_random_six_digits = () => { return Math.random().toString().slice(-6) }; const wholesale_enabled = false; const setting_product_image_display = "133.33%"; const product_image = data.image; const secondary_image = data.secondImage; const image_width = product_image.width; let image_height = product_image.height; if(setting_product_image_display == '100%'){ image_height = image_width }else if(setting_product_image_display == '133.33%'){ image_height = image_width * 1.3333; }; const product_image_hover_on = true && !!secondary_image.src; const has_save_label = true && ((+data.compare_at_price) > (+data.price)); const is_single_variant = data.variants.length == 1; const min_price_variant_href = (data.min_price_variant && data.min_price_variant.available) ? data.min_price_variant.withinUrl : data.withinUrl; const retail_price_max = data.retail_price_max || data.compare_at_price_max; const THUMBNAILS_MAX_SIZE = 3; const thumbnails = data.thumbVariants.slice(0, THUMBNAILS_MAX_SIZE); const image_wrap_id = 'image_wrap_' + get_random_six_digits(); const image_carousel_id = 'image_carousel_' + get_random_six_digits(); const thumbnails_selector_id = 'thumbnails_selector_' + get_random_six_digits(); const form_id = 'form_' + get_random_six_digits(); const mixed_wholesale = data.mixed_wholesale; return `
${ data.available ? `${ (+data.compare_at_price > +data.price) ? `Save
` : '' }` : "Sold out" }
Mixed Lot
${data.title}
${ data.price_min != data.price_max ? `from
` : `
` }
+${data.remainInvisibleThumbCount}
` })()}
Free shipping (cash on delivery)
Hassle-free returns. 30-day postage paid returns
Free shipping (cash on delivery)
Hassle-free returns. 30-day postage paid returns
Y&D---you dersver better
${(function() { const productsInfo = data.products || data.product; const product_display = originData?.product_display; const show_atc = product_display ? !!product_display?.show_add_to_cart : true; const show_discount_label = !!product_display?.show_discount_label; const show_sales_progress = !!product_display?.sales_progress?.enabled; const sales_progress_format = product_display?.sales_progress?.format || ''; const limit_purchase = originData.limit_purchase; const productConfig = product_display ? JSON.parse(product_display?.config).color : ''; const sale_progress_bg = productConfig?.sale_bar_background_color || '#F2F2F2'; const sale_progress_bg_start = productConfig?.progress_sale_bar_background_color_start || '#FF9C57'; const sale_progress_bg_end = productConfig?.progress_sale_bar_background_color_end || '#FF4559'; const sale_count_text = productConfig?.sale_bar_atc_color || '#FC5161'; const discount_label_start = productConfig?.discount_sign_background_color_start || '#FF9C57'; const discount_label_end = productConfig?.discount_sign_background_color_end || '#FF4559'; const discount_label_text = productConfig?.discount_sign_color || '#FFFFFF'; //限时促销首页卡片尺寸 const discount_image_size = data.discount_image_size || '100%'; //点击加购按钮需要的参数 let discount_id = data.discount_id; let apply_scenario = data.apply_scenario; if(!productsInfo.length) return ''; return productsInfo.map(product => { let price = product.price || 0; let priceMin = product.price_min || 0; let priceMax = product.price_max || 0; let compareAtPriceMax = product.compare_at_price_max || 0; let compareAtPrice = product.compare_at_price || 0; let title = product.title || ''; let id = product.id || ''; let url = product.url || ''; let type = product.type || ''; let is_sold_out = false; if (product.available == false && product.inventory_policy != 'continue') { is_sold_out = true; } const soldOutLang1 = "Sold out"; const soldOutLang2 = "Sold out"; const discountType = product.discount_type; const noNeedBtn = discountType !== "DT_MIX_MATCH_BUNDLE" && discountType !== "DT_CLASSIC_BUNDLE"; const defaultVariantTitle = product.variants[0]?.title.replace('-', '/'); const flash_sale_info = product?.flash_sale_info; const is_flashsale_sold_out = flash_sale_info?.discount_sales_rate == "100"; const show_product_sold_progress = flash_sale_info?.discount_sales_rate > 0; const off_ratio = flash_sale_info?.off_ratio; price = flash_sale_info?.discount_price || price; discount_id = discount_id || product.discount_id; apply_scenario = apply_scenario || product.apply_scenario; let imageWidth; if (product.image.width) { imageWidth = product.image.width; } else { imageWidth = 300; } let imageHeight; if (product.image.height) { imageHeight= product.image.height; } else { imageHeight = 300; } if (discount_image_size !== 'natural') { imageHeight = (imageWidth * parseFloat(discount_image_size)) / 100; } if (product.published) { return `
-${off_ratio}%
${function(){ if (soldOutLang1){ return `
${soldOutLang1}
` }else{ return `
${soldOutLang2}
` } }()}
${product.title}
Almost sold out
${flash_sale_info?.discount_sales}
${flash_sale_info?.discount_sales_rate}%
sold
Add
${defaultVariantTitle}
` } else { return ``; } }).join(''); })()}
${function(){ let hour = data.d * 24 + data.h; if(hour < 10){ hour = '0' + hour; } return `
End in
${data.dd}
D
${data.hh}
:
${hour}
:
${data.mm}
:
${data.ss}
.
${data.SSS}
` }()}
${function() { const images = data.images || []; const selectedVariant = data.variants.find(v => (v.available && v.is_hit_discount == true)) || data.variants[0]; const selectedIndex = !!selectedVariant ? images.findIndex(img => img.src === (selectedVariant.image && selectedVariant.image.src)) : 0; const initialSlide = selectedIndex === -1 ? 0 : selectedIndex; return `
${images.map((image, index) => `
`).join('')}
${images.map(image => { const imageWidth = image.width || 450; const imageHeight = image.height || 450; return `
` }).join('')}
`; }()}
${function() { const productData = data; const limit_purchase = data.limit_purchase || 0; let product_change_event = ''; let mouse_over_event = ''; let mouse_out_event = ''; const product_options = productData.options.filter(Boolean) || []; for (let opt of product_options) { const nameEscape = opt.name.replace(/\/|\\|\s|\'|\"|`|\<|\>/g, ''); product_change_event = product_change_event + `apps-discount-quick-shop-selected-variant-${opt.id}.rerender(data=event.selectedValues.${opt.name});`; mouse_over_event = mouse_over_event + `@${nameEscape}Mouseover="apps-discount-quick-shop-selected-variant-${opt.id}.rerender(data=event);"`; mouse_out_event = mouse_out_event + `@${nameEscape}Mouseout="apps-discount-quick-shop-selected-variant-${opt.id}.rerender(data=event.selectData.${opt.name});"`; } const selectedVariant = productData.variants.find(v => (v.available && v.is_hit_discount == true)) || productData.variants[0]; const statusLan = ((selectedVariant && !selectedVariant.available) || (!selectedVariant && !productData.available)) ? "Sold out" : "Add to cart"; const status = ( (selectedVariant && !selectedVariant.available) || (!selectedVariant && !data.available)) ? 'soldout' : 'available'; return `
${data.title || data.brief}
Add ${productData.discount_min_purchase_qty} items for discount
Quantity
${function() { const selectedVariant = data.variants.find(v => v.available && v.is_hit_discount == true) || data.variants[0]; const statusLan = ( (selectedVariant && !selectedVariant.available) || (!selectedVariant && !data.available)) ? "Sold out" : "Add to cart"; return `
${statusLan}
Add
`; }()}
`; }()}
${function() { const selectedVariant = data.variant || data.variants[0]; const image = selectedVariant.image || data.product.image; const imageWidth = image?.width || 120; const imageHeight = image?.height || 120; return `
` }()}
${function() { const defaultVariant = data.variants?.find(v => (v.available && v.is_hit_discount == true)) || data.variants?.[0]; const selectedVariant = data.variant || defaultVariant; const isHasRrice = (selectedVariant.price || selectedVariant.price == 0) ? true : false; if(selectedVariant.flash_sale_info && selectedVariant.flash_sale_info.discount_price) { selectedVariant.price = selectedVariant.flash_sale_info.discount_price; } if(data.flash_sale_info && data.flash_sale_info.discount_price) { data.price = data.flash_sale_info.discount_price; } return !!selectedVariant ? `
` : `
-
`; }()}
${function(){ const defaultVariant = data.variants?.find(v => (v.available && v.is_hit_discount == true)) || data.variants?.[0]; const selectedVariant = data.variant || defaultVariant; let show_flashsale_limit_tip = false; let limit_user_product_discount; if(selectedVariant.flash_sale_info && selectedVariant.flash_sale_info?.limit_user_product_type != "LUPT_NO_LIMIT" && selectedVariant.flash_sale_info?.limit_user_product_discount > 0) { show_flashsale_limit_tip = true; limit_user_product_discount = selectedVariant.flash_sale_info?.limit_user_product_discount; } if(data.flash_sale_info && data.flash_sale_info?.limit_user_product_type != "LUPT_NO_LIMIT" && data.flash_sale_info?.limit_user_product_discount > 0) { show_flashsale_limit_tip = true; limit_user_product_discount = data.flash_sale_info?.limit_user_product_discount; } return `
Promo products limited to ${limit_user_product_discount} item per person
` }()}
${function() { const currentProduct = data.product; return (currentProduct.options || []).map((option, index) => { const optionName = option.name || ''; const optionId = option.id || ''; const position = `option${index + 1}`; return `
${optionName}:
${option.values.map((value,idx) => { const selected = data.product.defaultSelectValues?.[optionName] == value ? 'checked' : ''; return `
${value}
`; }).join('')}
`; }).join('') }()}
${function() { const value = (data.originData && data.originData.value) || data.value; const isHasValue = value ? true : false; return `
${value}
` }()}
The activity inventory has been sold out, flash sale discount will not be applied
Continue Shopping
class SpzCustomDiscountAtcAction extends SPZ.BaseElement { constructor(element) { super(element); this.xhr_ = SPZServices.xhrFor(this.win); this.product_title = ""; } isLayoutSupported(layout) { return layout == SPZCore.Layout.LOGIC; } async getProductTitle_ (data){ this.product_title = data.product_title; } handleLoading_ (event) { const { type, action } = event; const loadingElementId = '#apps-discount-whole-loading'; const loadingElement = document.querySelector(loadingElementId); if (loadingElement) { SPZ.whenApiDefined(loadingElement).then((api) => { if (action === 'show') { api.show_(); } else { api.close_(); } }); } } // 渲染加购弹窗内容 async renderQuickShop_ (data) { this.handleLoading_({type: 'whole', action: 'show'}); const apply_scenario = data.apply_scenario; const discount_id = data.discount_id; const product_id = data.product_id; const limit_purchase = data.limit_purchase; this.xhr_.fetchJson(`/api/storefront/promotion/landing_page/product?product_id=${product_id}&discount_id=${discount_id}&apply_scenario=${apply_scenario}`, { method: "get", }).then(async(res)=>{ this.handleLoading_({type: 'whole', action: 'close'}); const $quickShop = await SPZ.whenApiDefined(document.querySelector('#apps-discount-quick-view-render')); // 定义默认渲染的子款式 const selectedVariant = res.product.variants.find((v)=> (v.available && v.is_hit_discount)) || res.product.variants[0]; let selectedValues = {}; selectedVariant.options.length && selectedVariant.options.forEach(item => { selectedValues[item.name] = item.value; }) // 默认选中的 子款式、 options res.product.defaultSelectValues = selectedValues; let data = {...res.product, product:res.product, selectedVariant}; data.need_atc = true; data.limit_purchase = limit_purchase; $quickShop.render(data); // 打开加购弹窗 SPZ.whenApiDefined(document.querySelector(`#apps-discount-quick-view`)).then((api)=>{ api.open(); }); }).catch((err)=>{ this.handleLoading_({type: 'whole', action: 'close'}); }) } // 加入购物车 addToCart_(data) { const apply_scenario = data.apply_scenario; const discount_id = data.discount_id; const product_id = data.product_id; this.xhr_.fetchJson(`/api/storefront/promotion/landing_page/product?product_id=${data.product_id}&discount_id=${discount_id}&apply_scenario=${apply_scenario}`, { method: "get", }).then(async(res)=>{ // 单款式加购 const variant_id = res.product.variants[0]?.id; const $productFormInput = document.querySelector(`#apps-discount-product-form-${data.product_id} input[name='variant_id'`); $productFormInput.value = variant_id; SPZ.whenApiDefined(document.querySelector(`#apps-discount-product-form-${data.product_id}`)).then((api)=>{ api.handleAddToCart_(); }); }).catch((err)=> { this.handleLoading_({type: 'whole', action: 'close'}); }) } // 加购弹窗未参与活动 加购按钮不可点击 handleNotHitDiscount_(data) { const $quickShopBody = document.querySelector('#apps-discount-quick-shop-body'); const $limitTip = document.querySelector('.apps_discount_limit_purchase_tip'); //当前子框式未命中活动 if(data.variant.is_hit_discount == false) { $quickShopBody.setAttribute('variantstatus', 'notHitDiscount'); $limitTip && $limitTip.setAttribute('selectedvariantstatus', 'notHitDiscount'); } else { $quickShopBody.setAttribute('variantstatus', ''); $limitTip && $limitTip.setAttribute('selectedvariantstatus', '') } } setupAction_() { this.registerAction('renderQuickShop', (invocation) => { const data = invocation.args; this.renderQuickShop_(data); }); // 加购 this.registerAction('addToCart', (invocation) => { const data = invocation.args; this.addToCart_(data); }); // 子款式 未参与活动 this.registerAction('handleNotHitDiscount', (invocation) => { const data = invocation.args.data; this.handleNotHitDiscount_(data); }); this.registerAction('getCartCount', (invocation) => { //一些老主题还未用spz重构,需要手动触发一次老方法以更新购物车图标的数量 window.$ && $(document).trigger('dj.common.cart.change'); }); this.registerAction('getProductTitle', (invocation) => { const data = invocation.args; this.getProductTitle_(data); }); this.registerAction('handleButton', (invocation) => { const data = invocation.args; window.location.href = this.product_title; }); }; buildCallback() { this.setupAction_(); }; // 同一页里 flashsale_collection(首页限时促销卡片) 与凑单弹窗容器都渲染了本快速加购栈, // 会产生重复 fixed id——尤其加购弹窗 #apps-discount-quick-view。它“打开”走 querySelector, // “关闭”走声明式动作 apps-discount-quick-view.close(按 id 解析),重复时二者可能命中不同副本, // 导致加购成功后弹窗第一次关不掉、第二次才关。参考 toast 的处理,运行时保证这些单例只保留一份。 mountCallback() { const funcs = document.querySelectorAll('#appDiscountRenderQuickShopFunc'); // 逻辑元件重复:仅保留第一个,其余移除自身,保证按 id 解析到的动作实例唯一。 if (funcs.length > 1 && this.element !== funcs[0]) { this.element.remove(); return; } // 加购弹窗重复:保留第一个,移除多余(移除弹窗即连带移除其内部 render/表单等子节点)。 const modals = document.querySelectorAll('#apps-discount-quick-view'); Array.from(modals).slice(1).forEach((el) => el.remove()); } } SPZ.defineElement('spz-custom-discount-atc-action', SpzCustomDiscountAtcAction);
class SpzCustomDiscountBundle extends SPZ.BaseElement { constructor(element) { super(element); } isLayoutSupported(layout) { return layout == SPZCore.Layout.LOGIC; } mountCallback() { // 同一页可能有多个 block 各自渲染本 snippet,导致逻辑元素 spz-custom-discount-toast(#appsAddCartToastFunc) 重复。 // 仅保留 DOM 中第一个实例,其余重复实例移除自身,保证逻辑元素及其 action 引用(appsAddCartToastFunc)唯一。 const funcs = document.querySelectorAll('#appsAddCartToastFunc'); if (funcs.length > 1 && this.element !== funcs[0]) { this.element.remove(); return; } // 全局折扣 toast 的弹出点分散在多个模板/组件里(含声明式 @atcError),无法逐一在弹出前前置, // 故挂载时幂等地去重并挂到 body;加购 toast 改为弹出前按需去重(见 showAddToCartToast) this.ensureSingleToastInBody_('cart_match_discount_toast_wrap'); } unmountCallback() {} // 同一页面可能有多个 block 各自渲染本 toast snippet(如商详的 discount_automatic + 购物车抽屉里的折扣横幅), // 导致 toast 外层出现重复 id。重复 id 下 getElementById/querySelector 及 SPZ 动作引用都只命中第一个, // 且被关进抽屉的那份会被抽屉的 transform/overflow 裁剪/错位。这里在挂载时幂等去重: // 只保留一份、移除多余的,并把保留的挂到 body(body 是 position:fixed 最安全的落点,避免被任何祖先裁剪)。可反复调用。 ensureSingleToastInBody_(id) { const els = Array.from(document.querySelectorAll('#' + id)); if (!els.length) return; els.slice(1).forEach((el) => el.remove()); const keep = els[0]; if (keep.parentNode !== document.body) { document.body.appendChild(keep); } } // 主题购物车抽屉是否打开 isInCartDrawer_() { return !!document.querySelector('[data-section-type="cart_drawer"] spz-sidebar[open]'); } setupAction_() { this.registerAction('showAddToCartToast', () => { // 抽屉内加购:主题本就不会有加购效果,统一弹插件自己的 toast // 非抽屉:主题有加购代理则沿用主题加购效果,否则插件兜底 const proxyEl = document.getElementById('add-cart-event-proxy'); const inDrawer = this.isInCartDrawer_(); if (!inDrawer && proxyEl) { return; } // 弹出前按需去重并挂到 body(幂等),避免重复 id 命中错对象或被抽屉裁剪/错位 this.ensureSingleToastInBody_('apps_add_cart_toast_wrap'); const toastEl = document.querySelector('#apps-match-drawer-add_to_cart_toast') SPZ.whenApiDefined(toastEl).then((apis) => { apis.showToast("Added successfully"); }); }); } buildCallback() { this.setupAction_(); }; } SPZ.defineElement('spz-custom-discount-toast', SpzCustomDiscountBundle);
${function(){ if(originData.discount_info.discount_id === "0") return; const homePageInfo = originData.home_page_info; const hasBanner = homePageInfo?.banner?.enabled; const bannerText = homePageInfo?.banner?.text; const bannerConfig = JSON.parse(homePageInfo.banner.config); const colorConfig = bannerConfig.color; const banner_bg_start = colorConfig.banner_bg_start; const banner_bg_end = colorConfig.banner_bg_end; const text_color = colorConfig.banner_text; const image_domain = originData.image_domain; const isMobile = originData.isMobile; const bannerImageConfig = bannerConfig.image || {}; const bannerImageUrl = isMobile ? bannerImageConfig.mobile : bannerImageConfig.desktop; const hasBannerImage = !!bannerImageUrl; const bannerImageFullUrl = hasBannerImage ? image_domain + bannerImageUrl : ''; const bannerImageBgSize = bannerImageConfig.image_render === "fill" ? "cover" : "contain"; const countdown_bg = colorConfig.countdown_bg; const countdown_text_color = colorConfig.countdown_text; const is_end_countdown = bannerConfig.countdown.end_opened; const end_format = bannerConfig.countdown.end_format; const is_show_day = end_format.indexOf("DD") != -1; const is_show_millisecond = end_format.indexOf("SSS") != -1; const ends_remaining_seconds = originData.discount_info.ends_remaining_seconds; const promotioUrl = '/' + 'promotions/discount-default/' + originData.discount_info.id; let dom = originData ? `
FLASH SALE
View More
${bannerText}
` : `
`; return dom; }()}
class SpzCustomDiscountFlashsale extends SPZ.BaseElement { constructor(element) { super(element); this.xhr_ = SPZServices.xhrFor(this.win); this.discountInfoApi = "\/api\/storefront\/promotion\/home_page\/campaign?discount_id=" this.product_display = {}; this.model = { loading: false, page: 2, limit: 20, total: 0, //已展示的商品数量 params: { count: 0, has_more: false, sort: { by: "recommend", direction: "asc" } } }; this.discount_id= ""; this.image_size="100%"; this.discount_info = {}; } isLayoutSupported(layout) { return layout == SPZCore.Layout.LOGIC; } async getDiscountList() { const data = await this.xhr_.fetchJson(this.discountInfoApi + this.discount_id, { method: "GET", }).then(res => { this.model.params = { count: res.product_info.count, has_more: res.product_info.has_more, sort: { by: "recommend", direction: "asc" } } if(!res.product_info.product.length) return; this.model.total = res.product_info.product.length; this.product_display = res.home_page_info.product_display; this.discount_info = res.discount_info; res.product_info.product.forEach((product) => { product.url = appDiscountUtils.globalizePath(product.url); }) res.image_domain = this.win.SHOPLAZZA.image_domain; res.isMobile = appDiscountUtils.judgeMobile(); SPZ.whenApiDefined(document.getElementById("appDiscountIndexFlashsale")) .then(apis => { apis.render(res).then(() => { const hiddenArraw = res.home_page_info.banner.enabled ? res.product_info.product.length < 5 : res.product_info.product.length < 6 if(hiddenArraw) { document.querySelectorAll('.app_discount_flashsale_arrow').forEach((item) => { item.style.display="none"; }) } SPZ.whenApiDefined(document.getElementById("flashsaleProductsRender")).then((api) => { res.product_info.product_display = this.product_display; res.product_info.discount_id = this.discount_id; res.product_info.apply_scenario = 1; res.product_info.limit_purchase = this.discount_info.limit_user_product_discount; res.product_info.discount_image_size = this.image_size; api.render(res.product_info,true).then(() => {this.bindEvent_()}); }) }) }) }).catch(err => { console.error(err); }) return data; }; // 获取加载的商品数据,拼接html模板 async loadData(cb) { // 请求数据 this.model.loading = true; //查询活动商品接口 const reqBody = { discount_id: this.discount_id, page: this.model.page, limit: this.model.limit, apply_scenario: 1, sort: this.model.params.sort, sales_channel: { sale_channel_type: "online", sale_channel_id: '1939216' } } this.xhr_.fetchJson(`/api/storefront/promotion/landing_page/product/list`, { method: "post", body: reqBody }).then(async(res)=>{ const count = res.count; this.model.params.has_more = res.has_more; this.model.total = this.model.total + res.products.length; if (count > 0) { this.model.page++; if (res.products && res.products.length > 0) { res.products.forEach((product) => { product.url = appDiscountUtils.globalizePath(product.url); }) res.product_display = this.product_display; res.discount_id = this.discount_id; res.apply_scenario = 1; res.limit_purchase = this.discount_info.limit_user_product_discount; res.discount_image_size = this.image_size; // 获取商品列表渲染模板, dom挂载 const $content = document.querySelector(".app_discount_products_list_wrapper"); this.templates_ = SPZServices.templatesForDoc(); this.templates_.renderTemplate(document.querySelector('#apps-discounts_product_list_template'), res).then((el) => { const childNodes = el.querySelectorAll('.as-render-product-item'); if (childNodes && childNodes.length > 0) { $content.append(...childNodes); } }) // 监听load去掉灰色背景 document.dispatchEvent(new CustomEvent('fire.load.img')); // 触发懒加载 cb && cb(products); window.lazyLoadInstance && window.lazyLoadInstance.update(); } } this.model.loading = false; }).catch((err)=>{ console.error(err); this.model.loading = false; }) }; setupAction_() { this.registerAction('shiftMove', (data) => { const $el = document.querySelector(".app_discount_products_list_wrapper"); const action = data.args.direct === "right"; const scrollwidth = action ? $el.offsetWidth : -$el.offsetWidth; $el.scrollBy({ left: scrollwidth, behavior: 'smooth' }); }); this.registerAction('changeFlashSaleLimitPurchase', (invocation) => { const data = invocation.args.data; this.handleFlashsaleTip_(data); }); }; //切换快速加购弹窗内限时促销限购提示 handleFlashsaleTip_(data) { const flashsaleEl = document.querySelector('#quick-shop-flashsale-tip'); SPZ.whenApiDefined(flashsaleEl).then((api) => { api.render(data); }); } bindEvent_() { // 监听滚动,请求数据 const $el = document.querySelector(".app_discount_products_list_wrapper"); if($el) { $el.addEventListener("scroll", this.win.SPZCore.Types.debounce( this.win, () => { const isRightEnd = $el.scrollLeft + $el.offsetWidth + 10 >= $el.scrollWidth; const isLeftEnd = Math.abs($el.scrollLeft) + $el.offsetWidth + 10 >= $el.scrollWidth; const isRTL = document.documentElement.getAttribute('dir') == 'rtl'; const isEnd = isRTL ? isLeftEnd : isRightEnd; if(isEnd && this.model.params.has_more && !this.model.loading && this.model.total < 100) { this.loadData(); } }, 50 )) }; }; buildCallback() { this.setupAction_(); }; mountCallback() { const $el = document.querySelector("#appDiscountFlashsale") this.discount_id = $el.getAttribute('flashsale-id'); this.image_size = $el.getAttribute('image-size'); if(!this.discount_id) return; this.getDiscountList(); }; } SPZ.defineElement('spz-custom-discount-flashsale', SpzCustomDiscountFlashsale);
Log in
Create an account
${data.data && data.data.count}
Home
Electronics
Camera
Projector
Audio
Save
AED237.00
Save
AED237.00
Y&D GEEK SPACE Solar Security Camera Outdoor Wireless 4G Card Solar Camera
AED555.00
AED792.00
Home Products
Kitchen blender
Air fryer
Save
AED207.00
Save
AED207.00
HOTOR Smoothie Maker Multi-function High-speed Blender
AED485.00
AED692.00
Christmas tree
full lengh mirror
More links
${(function(){ const formatLinks = (links) => { return links.map(link => { link.tag = tags[link.title.toUpperCase()] || {}; link.target_attr = link.target == '_blank' ? 'target="_blank"' : ''; link.href_attr = link.url ? `href="${link.url}"` : ''; if(link.children && link.children.length){ link.children = formatLinks(link.children); } return link; }) }; const tags = "{}"; let linkList = [ { id: 69382893, title: "Home", url: "\/", target: "", levels: 0, product0: { id: (null) }, children: [ ] }, { id: 69382895, title: "Electronics", url: "\/collections\/electronics", target: "", levels: 1, product0: { id: ("ea774d44-67c3-46c2-b11b-76b44ab94f30") }, children: [ { title: "Camera", url: "\/collections\/camera", target: "", levels: 0, children: [ ] }, { title: "Projector", url: "\/collections\/projector", target: "", levels: 0, children: [ ] }, { title: "Audio", url: "\/collections\/audio", target: "", levels: 0, children: [ ] }, ] }, { id: 69382903, title: "Home Products", url: "\/collections\/home-products", target: "", levels: 1, product0: { id: ("19150e43-303e-4578-a1a4-90393ee2c956") }, children: [ { title: "Kitchen blender", url: "\/collections\/kitchen-blender", target: "", levels: 0, children: [ ] }, { title: "Air fryer", url: "\/collections\/air-fryer", target: "", levels: 0, children: [ ] }, ] }, { id: 69382909, title: "Christmas tree", url: "\/collections\/christmas-tree", target: "", levels: 0, product0: { id: (null) }, children: [ ] }, { id: 83763565, title: "full lengh mirror", url: "\/collections\/full-length-mirror", target: "", levels: 0, product0: { id: (null) }, children: [ ] }, ].slice(offset); linkList = formatLinks(linkList); const hasChild = linkList.some(link => !!(link.children && link.children.length || link.product0.id)); return `
${link.title}
${link.tag.label}
${second_link.title}
${second_link.tag.label}
${third_links.title}
${third_links.tag.label}
${link.title}
${link.tag.label}
` })()}
Home
Electronics
Camera
Projector
Audio
Save
AED237.00
Save
AED237.00
Y&D GEEK SPACE Solar Security Camera Outdoor Wireless 4G Card Solar Camera
AED555.00
AED792.00
Home Products
Kitchen blender
Air fryer
Save
AED207.00
Save
AED207.00
HOTOR Smoothie Maker Multi-function High-speed Blender
AED485.00
AED692.00
Christmas tree
full lengh mirror
More links
${(function(){ const formatLinks = (links) => { return links.map(link => { link.tag = tags[link.title.toUpperCase()] || {}; link.target_attr = link.target == '_blank' ? 'target="_blank"' : ''; link.href_attr = link.url ? `href="${link.url}"` : ''; if(link.children && link.children.length){ link.children = formatLinks(link.children); } return link; }) }; const tags = "{}"; let linkList = [ { id: 69382893, title: "Home", url: "\/", target: "", levels: 0, product0: { id: (null) }, children: [ ] }, { id: 69382895, title: "Electronics", url: "\/collections\/electronics", target: "", levels: 1, product0: { id: ("ea774d44-67c3-46c2-b11b-76b44ab94f30") }, children: [ { title: "Camera", url: "\/collections\/camera", target: "", levels: 0, children: [ ] }, { title: "Projector", url: "\/collections\/projector", target: "", levels: 0, children: [ ] }, { title: "Audio", url: "\/collections\/audio", target: "", levels: 0, children: [ ] }, ] }, { id: 69382903, title: "Home Products", url: "\/collections\/home-products", target: "", levels: 1, product0: { id: ("19150e43-303e-4578-a1a4-90393ee2c956") }, children: [ { title: "Kitchen blender", url: "\/collections\/kitchen-blender", target: "", levels: 0, children: [ ] }, { title: "Air fryer", url: "\/collections\/air-fryer", target: "", levels: 0, children: [ ] }, ] }, { id: 69382909, title: "Christmas tree", url: "\/collections\/christmas-tree", target: "", levels: 0, product0: { id: (null) }, children: [ ] }, { id: 83763565, title: "full lengh mirror", url: "\/collections\/full-length-mirror", target: "", levels: 0, product0: { id: (null) }, children: [ ] }, ].slice(offset); linkList = formatLinks(linkList); const hasChild = linkList.some(link => !!(link.children && link.children.length || link.product0.id)); return `
${link.title}
${link.tag.label}
${second_link.title}
${second_link.tag.label}
${third_links.title}
${third_links.tag.label}
${link.title}
${link.tag.label}
` })()}
Y&D---you dersver better
${(function() { const productsInfo = data.products || data.product; const product_display = originData?.product_display; const show_atc = product_display ? !!product_display?.show_add_to_cart : true; const show_discount_label = !!product_display?.show_discount_label; const show_sales_progress = !!product_display?.sales_progress?.enabled; const sales_progress_format = product_display?.sales_progress?.format || ''; const limit_purchase = originData.limit_purchase; const productConfig = product_display ? JSON.parse(product_display?.config).color : ''; const sale_progress_bg = productConfig?.sale_bar_background_color || '#F2F2F2'; const sale_progress_bg_start = productConfig?.progress_sale_bar_background_color_start || '#FF9C57'; const sale_progress_bg_end = productConfig?.progress_sale_bar_background_color_end || '#FF4559'; const sale_count_text = productConfig?.sale_bar_atc_color || '#FC5161'; const discount_label_start = productConfig?.discount_sign_background_color_start || '#FF9C57'; const discount_label_end = productConfig?.discount_sign_background_color_end || '#FF4559'; const discount_label_text = productConfig?.discount_sign_color || '#FFFFFF'; //限时促销首页卡片尺寸 const discount_image_size = data.discount_image_size || '100%'; //点击加购按钮需要的参数 let discount_id = data.discount_id; let apply_scenario = data.apply_scenario; if(!productsInfo.length) return ''; return productsInfo.map(product => { let price = product.price || 0; let priceMin = product.price_min || 0; let priceMax = product.price_max || 0; let compareAtPriceMax = product.compare_at_price_max || 0; let compareAtPrice = product.compare_at_price || 0; let title = product.title || ''; let id = product.id || ''; let url = product.url || ''; let type = product.type || ''; let is_sold_out = false; if (product.available == false && product.inventory_policy != 'continue') { is_sold_out = true; } const soldOutLang1 = "Sold out"; const soldOutLang2 = "Sold out"; const discountType = product.discount_type; const noNeedBtn = discountType !== "DT_MIX_MATCH_BUNDLE" && discountType !== "DT_CLASSIC_BUNDLE"; const defaultVariantTitle = product.variants[0]?.title.replace('-', '/'); const flash_sale_info = product?.flash_sale_info; const is_flashsale_sold_out = flash_sale_info?.discount_sales_rate == "100"; const show_product_sold_progress = flash_sale_info?.discount_sales_rate > 0; const off_ratio = flash_sale_info?.off_ratio; price = flash_sale_info?.discount_price || price; discount_id = discount_id || product.discount_id; apply_scenario = apply_scenario || product.apply_scenario; let imageWidth; if (product.image.width) { imageWidth = product.image.width; } else { imageWidth = 300; } let imageHeight; if (product.image.height) { imageHeight= product.image.height; } else { imageHeight = 300; } if (discount_image_size !== 'natural') { imageHeight = (imageWidth * parseFloat(discount_image_size)) / 100; } if (product.published) { return `
-${off_ratio}%
${function(){ if (soldOutLang1){ return `
${soldOutLang1}
` }else{ return `
${soldOutLang2}
` } }()}
${product.title}
Almost sold out
${flash_sale_info?.discount_sales}
${flash_sale_info?.discount_sales_rate}%
sold
Add
${defaultVariantTitle}
` } else { return ``; } }).join(''); })()}
${function(){ let hour = data.d * 24 + data.h; if(hour < 10){ hour = '0' + hour; } return `
End in
${data.dd}
D
${data.hh}
:
${hour}
:
${data.mm}
:
${data.ss}
.
${data.SSS}
` }()}
${function() { const images = data.images || []; const selectedVariant = data.variants.find(v => (v.available && v.is_hit_discount == true)) || data.variants[0]; const selectedIndex = !!selectedVariant ? images.findIndex(img => img.src === (selectedVariant.image && selectedVariant.image.src)) : 0; const initialSlide = selectedIndex === -1 ? 0 : selectedIndex; return `
${images.map((image, index) => `
`).join('')}
${images.map(image => { const imageWidth = image.width || 450; const imageHeight = image.height || 450; return `
` }).join('')}
`; }()}
${function() { const productData = data; const limit_purchase = data.limit_purchase || 0; let product_change_event = ''; let mouse_over_event = ''; let mouse_out_event = ''; const product_options = productData.options.filter(Boolean) || []; for (let opt of product_options) { const nameEscape = opt.name.replace(/\/|\\|\s|\'|\"|`|\<|\>/g, ''); product_change_event = product_change_event + `apps-discount-quick-shop-selected-variant-${opt.id}.rerender(data=event.selectedValues.${opt.name});`; mouse_over_event = mouse_over_event + `@${nameEscape}Mouseover="apps-discount-quick-shop-selected-variant-${opt.id}.rerender(data=event);"`; mouse_out_event = mouse_out_event + `@${nameEscape}Mouseout="apps-discount-quick-shop-selected-variant-${opt.id}.rerender(data=event.selectData.${opt.name});"`; } const selectedVariant = productData.variants.find(v => (v.available && v.is_hit_discount == true)) || productData.variants[0]; const statusLan = ((selectedVariant && !selectedVariant.available) || (!selectedVariant && !productData.available)) ? "Sold out" : "Add to cart"; const status = ( (selectedVariant && !selectedVariant.available) || (!selectedVariant && !data.available)) ? 'soldout' : 'available'; return `
${data.title || data.brief}
Add ${productData.discount_min_purchase_qty} items for discount
Quantity
${function() { const selectedVariant = data.variants.find(v => v.available && v.is_hit_discount == true) || data.variants[0]; const statusLan = ( (selectedVariant && !selectedVariant.available) || (!selectedVariant && !data.available)) ? "Sold out" : "Add to cart"; return `
${statusLan}
Add
`; }()}
`; }()}
${function() { const selectedVariant = data.variant || data.variants[0]; const image = selectedVariant.image || data.product.image; const imageWidth = image?.width || 120; const imageHeight = image?.height || 120; return `
` }()}
${function() { const defaultVariant = data.variants?.find(v => (v.available && v.is_hit_discount == true)) || data.variants?.[0]; const selectedVariant = data.variant || defaultVariant; const isHasRrice = (selectedVariant.price || selectedVariant.price == 0) ? true : false; if(selectedVariant.flash_sale_info && selectedVariant.flash_sale_info.discount_price) { selectedVariant.price = selectedVariant.flash_sale_info.discount_price; } if(data.flash_sale_info && data.flash_sale_info.discount_price) { data.price = data.flash_sale_info.discount_price; } return !!selectedVariant ? `
` : `
-
`; }()}
${function(){ const defaultVariant = data.variants?.find(v => (v.available && v.is_hit_discount == true)) || data.variants?.[0]; const selectedVariant = data.variant || defaultVariant; let show_flashsale_limit_tip = false; let limit_user_product_discount; if(selectedVariant.flash_sale_info && selectedVariant.flash_sale_info?.limit_user_product_type != "LUPT_NO_LIMIT" && selectedVariant.flash_sale_info?.limit_user_product_discount > 0) { show_flashsale_limit_tip = true; limit_user_product_discount = selectedVariant.flash_sale_info?.limit_user_product_discount; } if(data.flash_sale_info && data.flash_sale_info?.limit_user_product_type != "LUPT_NO_LIMIT" && data.flash_sale_info?.limit_user_product_discount > 0) { show_flashsale_limit_tip = true; limit_user_product_discount = data.flash_sale_info?.limit_user_product_discount; } return `
Promo products limited to ${limit_user_product_discount} item per person
` }()}
${function() { const currentProduct = data.product; return (currentProduct.options || []).map((option, index) => { const optionName = option.name || ''; const optionId = option.id || ''; const position = `option${index + 1}`; return `
${optionName}:
${option.values.map((value,idx) => { const selected = data.product.defaultSelectValues?.[optionName] == value ? 'checked' : ''; return `
${value}
`; }).join('')}
`; }).join('') }()}
${function() { const value = (data.originData && data.originData.value) || data.value; const isHasValue = value ? true : false; return `
${value}
` }()}
The activity inventory has been sold out, flash sale discount will not be applied
Continue Shopping
class SpzCustomDiscountAtcAction extends SPZ.BaseElement { constructor(element) { super(element); this.xhr_ = SPZServices.xhrFor(this.win); this.product_title = ""; } isLayoutSupported(layout) { return layout == SPZCore.Layout.LOGIC; } async getProductTitle_ (data){ this.product_title = data.product_title; } handleLoading_ (event) { const { type, action } = event; const loadingElementId = '#apps-discount-whole-loading'; const loadingElement = document.querySelector(loadingElementId); if (loadingElement) { SPZ.whenApiDefined(loadingElement).then((api) => { if (action === 'show') { api.show_(); } else { api.close_(); } }); } } // 渲染加购弹窗内容 async renderQuickShop_ (data) { this.handleLoading_({type: 'whole', action: 'show'}); const apply_scenario = data.apply_scenario; const discount_id = data.discount_id; const product_id = data.product_id; const limit_purchase = data.limit_purchase; this.xhr_.fetchJson(`/api/storefront/promotion/landing_page/product?product_id=${product_id}&discount_id=${discount_id}&apply_scenario=${apply_scenario}`, { method: "get", }).then(async(res)=>{ this.handleLoading_({type: 'whole', action: 'close'}); const $quickShop = await SPZ.whenApiDefined(document.querySelector('#apps-discount-quick-view-render')); // 定义默认渲染的子款式 const selectedVariant = res.product.variants.find((v)=> (v.available && v.is_hit_discount)) || res.product.variants[0]; let selectedValues = {}; selectedVariant.options.length && selectedVariant.options.forEach(item => { selectedValues[item.name] = item.value; }) // 默认选中的 子款式、 options res.product.defaultSelectValues = selectedValues; let data = {...res.product, product:res.product, selectedVariant}; data.need_atc = true; data.limit_purchase = limit_purchase; $quickShop.render(data); // 打开加购弹窗 SPZ.whenApiDefined(document.querySelector(`#apps-discount-quick-view`)).then((api)=>{ api.open(); }); }).catch((err)=>{ this.handleLoading_({type: 'whole', action: 'close'}); }) } // 加入购物车 addToCart_(data) { const apply_scenario = data.apply_scenario; const discount_id = data.discount_id; const product_id = data.product_id; this.xhr_.fetchJson(`/api/storefront/promotion/landing_page/product?product_id=${data.product_id}&discount_id=${discount_id}&apply_scenario=${apply_scenario}`, { method: "get", }).then(async(res)=>{ // 单款式加购 const variant_id = res.product.variants[0]?.id; const $productFormInput = document.querySelector(`#apps-discount-product-form-${data.product_id} input[name='variant_id'`); $productFormInput.value = variant_id; SPZ.whenApiDefined(document.querySelector(`#apps-discount-product-form-${data.product_id}`)).then((api)=>{ api.handleAddToCart_(); }); }).catch((err)=> { this.handleLoading_({type: 'whole', action: 'close'}); }) } // 加购弹窗未参与活动 加购按钮不可点击 handleNotHitDiscount_(data) { const $quickShopBody = document.querySelector('#apps-discount-quick-shop-body'); const $limitTip = document.querySelector('.apps_discount_limit_purchase_tip'); //当前子框式未命中活动 if(data.variant.is_hit_discount == false) { $quickShopBody.setAttribute('variantstatus', 'notHitDiscount'); $limitTip && $limitTip.setAttribute('selectedvariantstatus', 'notHitDiscount'); } else { $quickShopBody.setAttribute('variantstatus', ''); $limitTip && $limitTip.setAttribute('selectedvariantstatus', '') } } setupAction_() { this.registerAction('renderQuickShop', (invocation) => { const data = invocation.args; this.renderQuickShop_(data); }); // 加购 this.registerAction('addToCart', (invocation) => { const data = invocation.args; this.addToCart_(data); }); // 子款式 未参与活动 this.registerAction('handleNotHitDiscount', (invocation) => { const data = invocation.args.data; this.handleNotHitDiscount_(data); }); this.registerAction('getCartCount', (invocation) => { //一些老主题还未用spz重构,需要手动触发一次老方法以更新购物车图标的数量 window.$ && $(document).trigger('dj.common.cart.change'); }); this.registerAction('getProductTitle', (invocation) => { const data = invocation.args; this.getProductTitle_(data); }); this.registerAction('handleButton', (invocation) => { const data = invocation.args; window.location.href = this.product_title; }); }; buildCallback() { this.setupAction_(); }; // 同一页里 flashsale_collection(首页限时促销卡片) 与凑单弹窗容器都渲染了本快速加购栈, // 会产生重复 fixed id——尤其加购弹窗 #apps-discount-quick-view。它“打开”走 querySelector, // “关闭”走声明式动作 apps-discount-quick-view.close(按 id 解析),重复时二者可能命中不同副本, // 导致加购成功后弹窗第一次关不掉、第二次才关。参考 toast 的处理,运行时保证这些单例只保留一份。 mountCallback() { const funcs = document.querySelectorAll('#appDiscountRenderQuickShopFunc'); // 逻辑元件重复:仅保留第一个,其余移除自身,保证按 id 解析到的动作实例唯一。 if (funcs.length > 1 && this.element !== funcs[0]) { this.element.remove(); return; } // 加购弹窗重复:保留第一个,移除多余(移除弹窗即连带移除其内部 render/表单等子节点)。 const modals = document.querySelectorAll('#apps-discount-quick-view'); Array.from(modals).slice(1).forEach((el) => el.remove()); } } SPZ.defineElement('spz-custom-discount-atc-action', SpzCustomDiscountAtcAction);
class SpzCustomDiscountBundle extends SPZ.BaseElement { constructor(element) { super(element); } isLayoutSupported(layout) { return layout == SPZCore.Layout.LOGIC; } mountCallback() { // 同一页可能有多个 block 各自渲染本 snippet,导致逻辑元素 spz-custom-discount-toast(#appsAddCartToastFunc) 重复。 // 仅保留 DOM 中第一个实例,其余重复实例移除自身,保证逻辑元素及其 action 引用(appsAddCartToastFunc)唯一。 const funcs = document.querySelectorAll('#appsAddCartToastFunc'); if (funcs.length > 1 && this.element !== funcs[0]) { this.element.remove(); return; } // 全局折扣 toast 的弹出点分散在多个模板/组件里(含声明式 @atcError),无法逐一在弹出前前置, // 故挂载时幂等地去重并挂到 body;加购 toast 改为弹出前按需去重(见 showAddToCartToast) this.ensureSingleToastInBody_('cart_match_discount_toast_wrap'); } unmountCallback() {} // 同一页面可能有多个 block 各自渲染本 toast snippet(如商详的 discount_automatic + 购物车抽屉里的折扣横幅), // 导致 toast 外层出现重复 id。重复 id 下 getElementById/querySelector 及 SPZ 动作引用都只命中第一个, // 且被关进抽屉的那份会被抽屉的 transform/overflow 裁剪/错位。这里在挂载时幂等去重: // 只保留一份、移除多余的,并把保留的挂到 body(body 是 position:fixed 最安全的落点,避免被任何祖先裁剪)。可反复调用。 ensureSingleToastInBody_(id) { const els = Array.from(document.querySelectorAll('#' + id)); if (!els.length) return; els.slice(1).forEach((el) => el.remove()); const keep = els[0]; if (keep.parentNode !== document.body) { document.body.appendChild(keep); } } // 主题购物车抽屉是否打开 isInCartDrawer_() { return !!document.querySelector('[data-section-type="cart_drawer"] spz-sidebar[open]'); } setupAction_() { this.registerAction('showAddToCartToast', () => { // 抽屉内加购:主题本就不会有加购效果,统一弹插件自己的 toast // 非抽屉:主题有加购代理则沿用主题加购效果,否则插件兜底 const proxyEl = document.getElementById('add-cart-event-proxy'); const inDrawer = this.isInCartDrawer_(); if (!inDrawer && proxyEl) { return; } // 弹出前按需去重并挂到 body(幂等),避免重复 id 命中错对象或被抽屉裁剪/错位 this.ensureSingleToastInBody_('apps_add_cart_toast_wrap'); const toastEl = document.querySelector('#apps-match-drawer-add_to_cart_toast') SPZ.whenApiDefined(toastEl).then((apis) => { apis.showToast("Added successfully"); }); }); } buildCallback() { this.setupAction_(); }; } SPZ.defineElement('spz-custom-discount-toast', SpzCustomDiscountBundle);
${function(){ if(originData.discount_info.discount_id === "0") return; const homePageInfo = originData.home_page_info; const hasBanner = homePageInfo?.banner?.enabled; const bannerText = homePageInfo?.banner?.text; const bannerConfig = JSON.parse(homePageInfo.banner.config); const colorConfig = bannerConfig.color; const banner_bg_start = colorConfig.banner_bg_start; const banner_bg_end = colorConfig.banner_bg_end; const text_color = colorConfig.banner_text; const image_domain = originData.image_domain; const isMobile = originData.isMobile; const bannerImageConfig = bannerConfig.image || {}; const bannerImageUrl = isMobile ? bannerImageConfig.mobile : bannerImageConfig.desktop; const hasBannerImage = !!bannerImageUrl; const bannerImageFullUrl = hasBannerImage ? image_domain + bannerImageUrl : ''; const bannerImageBgSize = bannerImageConfig.image_render === "fill" ? "cover" : "contain"; const countdown_bg = colorConfig.countdown_bg; const countdown_text_color = colorConfig.countdown_text; const is_end_countdown = bannerConfig.countdown.end_opened; const end_format = bannerConfig.countdown.end_format; const is_show_day = end_format.indexOf("DD") != -1; const is_show_millisecond = end_format.indexOf("SSS") != -1; const ends_remaining_seconds = originData.discount_info.ends_remaining_seconds; const promotioUrl = '/' + 'promotions/discount-default/' + originData.discount_info.id; let dom = originData ? `
FLASH SALE
View More
${bannerText}
` : `
`; return dom; }()}
class SpzCustomDiscountFlashsale extends SPZ.BaseElement { constructor(element) { super(element); this.xhr_ = SPZServices.xhrFor(this.win); this.discountInfoApi = "\/api\/storefront\/promotion\/home_page\/campaign?discount_id=" this.product_display = {}; this.model = { loading: false, page: 2, limit: 20, total: 0, //已展示的商品数量 params: { count: 0, has_more: false, sort: { by: "recommend", direction: "asc" } } }; this.discount_id= ""; this.image_size="100%"; this.discount_info = {}; } isLayoutSupported(layout) { return layout == SPZCore.Layout.LOGIC; } async getDiscountList() { const data = await this.xhr_.fetchJson(this.discountInfoApi + this.discount_id, { method: "GET", }).then(res => { this.model.params = { count: res.product_info.count, has_more: res.product_info.has_more, sort: { by: "recommend", direction: "asc" } } if(!res.product_info.product.length) return; this.model.total = res.product_info.product.length; this.product_display = res.home_page_info.product_display; this.discount_info = res.discount_info; res.product_info.product.forEach((product) => { product.url = appDiscountUtils.globalizePath(product.url); }) res.image_domain = this.win.SHOPLAZZA.image_domain; res.isMobile = appDiscountUtils.judgeMobile(); SPZ.whenApiDefined(document.getElementById("appDiscountIndexFlashsale")) .then(apis => { apis.render(res).then(() => { const hiddenArraw = res.home_page_info.banner.enabled ? res.product_info.product.length < 5 : res.product_info.product.length < 6 if(hiddenArraw) { document.querySelectorAll('.app_discount_flashsale_arrow').forEach((item) => { item.style.display="none"; }) } SPZ.whenApiDefined(document.getElementById("flashsaleProductsRender")).then((api) => { res.product_info.product_display = this.product_display; res.product_info.discount_id = this.discount_id; res.product_info.apply_scenario = 1; res.product_info.limit_purchase = this.discount_info.limit_user_product_discount; res.product_info.discount_image_size = this.image_size; api.render(res.product_info,true).then(() => {this.bindEvent_()}); }) }) }) }).catch(err => { console.error(err); }) return data; }; // 获取加载的商品数据,拼接html模板 async loadData(cb) { // 请求数据 this.model.loading = true; //查询活动商品接口 const reqBody = { discount_id: this.discount_id, page: this.model.page, limit: this.model.limit, apply_scenario: 1, sort: this.model.params.sort, sales_channel: { sale_channel_type: "online", sale_channel_id: '1939216' } } this.xhr_.fetchJson(`/api/storefront/promotion/landing_page/product/list`, { method: "post", body: reqBody }).then(async(res)=>{ const count = res.count; this.model.params.has_more = res.has_more; this.model.total = this.model.total + res.products.length; if (count > 0) { this.model.page++; if (res.products && res.products.length > 0) { res.products.forEach((product) => { product.url = appDiscountUtils.globalizePath(product.url); }) res.product_display = this.product_display; res.discount_id = this.discount_id; res.apply_scenario = 1; res.limit_purchase = this.discount_info.limit_user_product_discount; res.discount_image_size = this.image_size; // 获取商品列表渲染模板, dom挂载 const $content = document.querySelector(".app_discount_products_list_wrapper"); this.templates_ = SPZServices.templatesForDoc(); this.templates_.renderTemplate(document.querySelector('#apps-discounts_product_list_template'), res).then((el) => { const childNodes = el.querySelectorAll('.as-render-product-item'); if (childNodes && childNodes.length > 0) { $content.append(...childNodes); } }) // 监听load去掉灰色背景 document.dispatchEvent(new CustomEvent('fire.load.img')); // 触发懒加载 cb && cb(products); window.lazyLoadInstance && window.lazyLoadInstance.update(); } } this.model.loading = false; }).catch((err)=>{ console.error(err); this.model.loading = false; }) }; setupAction_() { this.registerAction('shiftMove', (data) => { const $el = document.querySelector(".app_discount_products_list_wrapper"); const action = data.args.direct === "right"; const scrollwidth = action ? $el.offsetWidth : -$el.offsetWidth; $el.scrollBy({ left: scrollwidth, behavior: 'smooth' }); }); this.registerAction('changeFlashSaleLimitPurchase', (invocation) => { const data = invocation.args.data; this.handleFlashsaleTip_(data); }); }; //切换快速加购弹窗内限时促销限购提示 handleFlashsaleTip_(data) { const flashsaleEl = document.querySelector('#quick-shop-flashsale-tip'); SPZ.whenApiDefined(flashsaleEl).then((api) => { api.render(data); }); } bindEvent_() { // 监听滚动,请求数据 const $el = document.querySelector(".app_discount_products_list_wrapper"); if($el) { $el.addEventListener("scroll", this.win.SPZCore.Types.debounce( this.win, () => { const isRightEnd = $el.scrollLeft + $el.offsetWidth + 10 >= $el.scrollWidth; const isLeftEnd = Math.abs($el.scrollLeft) + $el.offsetWidth + 10 >= $el.scrollWidth; const isRTL = document.documentElement.getAttribute('dir') == 'rtl'; const isEnd = isRTL ? isLeftEnd : isRightEnd; if(isEnd && this.model.params.has_more && !this.model.loading && this.model.total < 100) { this.loadData(); } }, 50 )) }; }; buildCallback() { this.setupAction_(); }; mountCallback() { const $el = document.querySelector("#appDiscountFlashsale") this.discount_id = $el.getAttribute('flashsale-id'); this.image_size = $el.getAttribute('image-size'); if(!this.discount_id) return; this.getDiscountList(); }; } SPZ.defineElement('spz-custom-discount-flashsale', SpzCustomDiscountFlashsale);
Log in
Create an account
${data.data && data.data.count}
${(function(){ if (data === undefined || typeof data !== 'string' || data == '') return '
'; const keyword = encodeURIComponent(data); return `
View more
Your search for '${data}' did not yield any results.
` })()}
Home
Electronics
Electronics
Camera
Projector
Audio
Home Products
Home Products
Kitchen blender
Air fryer
Christmas tree
full lengh mirror
${(function() { const productsInfo = data.products || data.product; const product_display = originData?.product_display; const show_atc = product_display ? !!product_display?.show_add_to_cart : true; const show_discount_label = !!product_display?.show_discount_label; const show_sales_progress = !!product_display?.sales_progress?.enabled; const sales_progress_format = product_display?.sales_progress?.format || ''; const limit_purchase = originData.limit_purchase; const productConfig = product_display ? JSON.parse(product_display?.config).color : ''; const sale_progress_bg = productConfig?.sale_bar_background_color || '#F2F2F2'; const sale_progress_bg_start = productConfig?.progress_sale_bar_background_color_start || '#FF9C57'; const sale_progress_bg_end = productConfig?.progress_sale_bar_background_color_end || '#FF4559'; const sale_count_text = productConfig?.sale_bar_atc_color || '#FC5161'; const discount_label_start = productConfig?.discount_sign_background_color_start || '#FF9C57'; const discount_label_end = productConfig?.discount_sign_background_color_end || '#FF4559'; const discount_label_text = productConfig?.discount_sign_color || '#FFFFFF'; //限时促销首页卡片尺寸 const discount_image_size = data.discount_image_size || '100%'; //点击加购按钮需要的参数 let discount_id = data.discount_id; let apply_scenario = data.apply_scenario; if(!productsInfo.length) return ''; return productsInfo.map(product => { let price = product.price || 0; let priceMin = product.price_min || 0; let priceMax = product.price_max || 0; let compareAtPriceMax = product.compare_at_price_max || 0; let compareAtPrice = product.compare_at_price || 0; let title = product.title || ''; let id = product.id || ''; let url = product.url || ''; let type = product.type || ''; let is_sold_out = false; if (product.available == false && product.inventory_policy != 'continue') { is_sold_out = true; } const soldOutLang1 = "Sold out"; const soldOutLang2 = "Sold out"; const discountType = product.discount_type; const noNeedBtn = discountType !== "DT_MIX_MATCH_BUNDLE" && discountType !== "DT_CLASSIC_BUNDLE"; const defaultVariantTitle = product.variants[0]?.title.replace('-', '/'); const flash_sale_info = product?.flash_sale_info; const is_flashsale_sold_out = flash_sale_info?.discount_sales_rate == "100"; const show_product_sold_progress = flash_sale_info?.discount_sales_rate > 0; const off_ratio = flash_sale_info?.off_ratio; price = flash_sale_info?.discount_price || price; discount_id = discount_id || product.discount_id; apply_scenario = apply_scenario || product.apply_scenario; let imageWidth; if (product.image.width) { imageWidth = product.image.width; } else { imageWidth = 300; } let imageHeight; if (product.image.height) { imageHeight= product.image.height; } else { imageHeight = 300; } if (discount_image_size !== 'natural') { imageHeight = (imageWidth * parseFloat(discount_image_size)) / 100; } if (product.published) { return `
-${off_ratio}%
${function(){ if (soldOutLang1){ return `
${soldOutLang1}
` }else{ return `
${soldOutLang2}
` } }()}
${product.title}
Almost sold out
${flash_sale_info?.discount_sales}
${flash_sale_info?.discount_sales_rate}%
sold
Add
${defaultVariantTitle}
` } else { return ``; } }).join(''); })()}
${function(){ let hour = data.d * 24 + data.h; if(hour < 10){ hour = '0' + hour; } return `
End in
${data.dd}
D
${data.hh}
:
${hour}
:
${data.mm}
:
${data.ss}
.
${data.SSS}
` }()}
${function() { const images = data.images || []; const selectedVariant = data.variants.find(v => (v.available && v.is_hit_discount == true)) || data.variants[0]; const selectedIndex = !!selectedVariant ? images.findIndex(img => img.src === (selectedVariant.image && selectedVariant.image.src)) : 0; const initialSlide = selectedIndex === -1 ? 0 : selectedIndex; return `
${images.map((image, index) => `
`).join('')}
${images.map(image => { const imageWidth = image.width || 450; const imageHeight = image.height || 450; return `
` }).join('')}
`; }()}
${function() { const productData = data; const limit_purchase = data.limit_purchase || 0; let product_change_event = ''; let mouse_over_event = ''; let mouse_out_event = ''; const product_options = productData.options.filter(Boolean) || []; for (let opt of product_options) { const nameEscape = opt.name.replace(/\/|\\|\s|\'|\"|`|\<|\>/g, ''); product_change_event = product_change_event + `apps-discount-quick-shop-selected-variant-${opt.id}.rerender(data=event.selectedValues.${opt.name});`; mouse_over_event = mouse_over_event + `@${nameEscape}Mouseover="apps-discount-quick-shop-selected-variant-${opt.id}.rerender(data=event);"`; mouse_out_event = mouse_out_event + `@${nameEscape}Mouseout="apps-discount-quick-shop-selected-variant-${opt.id}.rerender(data=event.selectData.${opt.name});"`; } const selectedVariant = productData.variants.find(v => (v.available && v.is_hit_discount == true)) || productData.variants[0]; const statusLan = ((selectedVariant && !selectedVariant.available) || (!selectedVariant && !productData.available)) ? "Sold out" : "Add to cart"; const status = ( (selectedVariant && !selectedVariant.available) || (!selectedVariant && !data.available)) ? 'soldout' : 'available'; return `
${data.title || data.brief}
Add ${productData.discount_min_purchase_qty} items for discount
Quantity
${function() { const selectedVariant = data.variants.find(v => v.available && v.is_hit_discount == true) || data.variants[0]; const statusLan = ( (selectedVariant && !selectedVariant.available) || (!selectedVariant && !data.available)) ? "Sold out" : "Add to cart"; return `
${statusLan}
Add
`; }()}
`; }()}
${function() { const selectedVariant = data.variant || data.variants[0]; const image = selectedVariant.image || data.product.image; const imageWidth = image?.width || 120; const imageHeight = image?.height || 120; return `
` }()}
${function() { const defaultVariant = data.variants?.find(v => (v.available && v.is_hit_discount == true)) || data.variants?.[0]; const selectedVariant = data.variant || defaultVariant; const isHasRrice = (selectedVariant.price || selectedVariant.price == 0) ? true : false; if(selectedVariant.flash_sale_info && selectedVariant.flash_sale_info.discount_price) { selectedVariant.price = selectedVariant.flash_sale_info.discount_price; } if(data.flash_sale_info && data.flash_sale_info.discount_price) { data.price = data.flash_sale_info.discount_price; } return !!selectedVariant ? `
` : `
-
`; }()}
${function(){ const defaultVariant = data.variants?.find(v => (v.available && v.is_hit_discount == true)) || data.variants?.[0]; const selectedVariant = data.variant || defaultVariant; let show_flashsale_limit_tip = false; let limit_user_product_discount; if(selectedVariant.flash_sale_info && selectedVariant.flash_sale_info?.limit_user_product_type != "LUPT_NO_LIMIT" && selectedVariant.flash_sale_info?.limit_user_product_discount > 0) { show_flashsale_limit_tip = true; limit_user_product_discount = selectedVariant.flash_sale_info?.limit_user_product_discount; } if(data.flash_sale_info && data.flash_sale_info?.limit_user_product_type != "LUPT_NO_LIMIT" && data.flash_sale_info?.limit_user_product_discount > 0) { show_flashsale_limit_tip = true; limit_user_product_discount = data.flash_sale_info?.limit_user_product_discount; } return `
Promo products limited to ${limit_user_product_discount} item per person
` }()}
${function() { const currentProduct = data.product; return (currentProduct.options || []).map((option, index) => { const optionName = option.name || ''; const optionId = option.id || ''; const position = `option${index + 1}`; return `
${optionName}:
${option.values.map((value,idx) => { const selected = data.product.defaultSelectValues?.[optionName] == value ? 'checked' : ''; return `
${value}
`; }).join('')}
`; }).join('') }()}
${function() { const value = (data.originData && data.originData.value) || data.value; const isHasValue = value ? true : false; return `
${value}
` }()}
The activity inventory has been sold out, flash sale discount will not be applied
Continue Shopping
class SpzCustomDiscountAtcAction extends SPZ.BaseElement { constructor(element) { super(element); this.xhr_ = SPZServices.xhrFor(this.win); this.product_title = ""; } isLayoutSupported(layout) { return layout == SPZCore.Layout.LOGIC; } async getProductTitle_ (data){ this.product_title = data.product_title; } handleLoading_ (event) { const { type, action } = event; const loadingElementId = '#apps-discount-whole-loading'; const loadingElement = document.querySelector(loadingElementId); if (loadingElement) { SPZ.whenApiDefined(loadingElement).then((api) => { if (action === 'show') { api.show_(); } else { api.close_(); } }); } } // 渲染加购弹窗内容 async renderQuickShop_ (data) { this.handleLoading_({type: 'whole', action: 'show'}); const apply_scenario = data.apply_scenario; const discount_id = data.discount_id; const product_id = data.product_id; const limit_purchase = data.limit_purchase; this.xhr_.fetchJson(`/api/storefront/promotion/landing_page/product?product_id=${product_id}&discount_id=${discount_id}&apply_scenario=${apply_scenario}`, { method: "get", }).then(async(res)=>{ this.handleLoading_({type: 'whole', action: 'close'}); const $quickShop = await SPZ.whenApiDefined(document.querySelector('#apps-discount-quick-view-render')); // 定义默认渲染的子款式 const selectedVariant = res.product.variants.find((v)=> (v.available && v.is_hit_discount)) || res.product.variants[0]; let selectedValues = {}; selectedVariant.options.length && selectedVariant.options.forEach(item => { selectedValues[item.name] = item.value; }) // 默认选中的 子款式、 options res.product.defaultSelectValues = selectedValues; let data = {...res.product, product:res.product, selectedVariant}; data.need_atc = true; data.limit_purchase = limit_purchase; $quickShop.render(data); // 打开加购弹窗 SPZ.whenApiDefined(document.querySelector(`#apps-discount-quick-view`)).then((api)=>{ api.open(); }); }).catch((err)=>{ this.handleLoading_({type: 'whole', action: 'close'}); }) } // 加入购物车 addToCart_(data) { const apply_scenario = data.apply_scenario; const discount_id = data.discount_id; const product_id = data.product_id; this.xhr_.fetchJson(`/api/storefront/promotion/landing_page/product?product_id=${data.product_id}&discount_id=${discount_id}&apply_scenario=${apply_scenario}`, { method: "get", }).then(async(res)=>{ // 单款式加购 const variant_id = res.product.variants[0]?.id; const $productFormInput = document.querySelector(`#apps-discount-product-form-${data.product_id} input[name='variant_id'`); $productFormInput.value = variant_id; SPZ.whenApiDefined(document.querySelector(`#apps-discount-product-form-${data.product_id}`)).then((api)=>{ api.handleAddToCart_(); }); }).catch((err)=> { this.handleLoading_({type: 'whole', action: 'close'}); }) } // 加购弹窗未参与活动 加购按钮不可点击 handleNotHitDiscount_(data) { const $quickShopBody = document.querySelector('#apps-discount-quick-shop-body'); const $limitTip = document.querySelector('.apps_discount_limit_purchase_tip'); //当前子框式未命中活动 if(data.variant.is_hit_discount == false) { $quickShopBody.setAttribute('variantstatus', 'notHitDiscount'); $limitTip && $limitTip.setAttribute('selectedvariantstatus', 'notHitDiscount'); } else { $quickShopBody.setAttribute('variantstatus', ''); $limitTip && $limitTip.setAttribute('selectedvariantstatus', '') } } setupAction_() { this.registerAction('renderQuickShop', (invocation) => { const data = invocation.args; this.renderQuickShop_(data); }); // 加购 this.registerAction('addToCart', (invocation) => { const data = invocation.args; this.addToCart_(data); }); // 子款式 未参与活动 this.registerAction('handleNotHitDiscount', (invocation) => { const data = invocation.args.data; this.handleNotHitDiscount_(data); }); this.registerAction('getCartCount', (invocation) => { //一些老主题还未用spz重构,需要手动触发一次老方法以更新购物车图标的数量 window.$ && $(document).trigger('dj.common.cart.change'); }); this.registerAction('getProductTitle', (invocation) => { const data = invocation.args; this.getProductTitle_(data); }); this.registerAction('handleButton', (invocation) => { const data = invocation.args; window.location.href = this.product_title; }); }; buildCallback() { this.setupAction_(); }; // 同一页里 flashsale_collection(首页限时促销卡片) 与凑单弹窗容器都渲染了本快速加购栈, // 会产生重复 fixed id——尤其加购弹窗 #apps-discount-quick-view。它“打开”走 querySelector, // “关闭”走声明式动作 apps-discount-quick-view.close(按 id 解析),重复时二者可能命中不同副本, // 导致加购成功后弹窗第一次关不掉、第二次才关。参考 toast 的处理,运行时保证这些单例只保留一份。 mountCallback() { const funcs = document.querySelectorAll('#appDiscountRenderQuickShopFunc'); // 逻辑元件重复:仅保留第一个,其余移除自身,保证按 id 解析到的动作实例唯一。 if (funcs.length > 1 && this.element !== funcs[0]) { this.element.remove(); return; } // 加购弹窗重复:保留第一个,移除多余(移除弹窗即连带移除其内部 render/表单等子节点)。 const modals = document.querySelectorAll('#apps-discount-quick-view'); Array.from(modals).slice(1).forEach((el) => el.remove()); } } SPZ.defineElement('spz-custom-discount-atc-action', SpzCustomDiscountAtcAction);
class SpzCustomDiscountBundle extends SPZ.BaseElement { constructor(element) { super(element); } isLayoutSupported(layout) { return layout == SPZCore.Layout.LOGIC; } mountCallback() { // 同一页可能有多个 block 各自渲染本 snippet,导致逻辑元素 spz-custom-discount-toast(#appsAddCartToastFunc) 重复。 // 仅保留 DOM 中第一个实例,其余重复实例移除自身,保证逻辑元素及其 action 引用(appsAddCartToastFunc)唯一。 const funcs = document.querySelectorAll('#appsAddCartToastFunc'); if (funcs.length > 1 && this.element !== funcs[0]) { this.element.remove(); return; } // 全局折扣 toast 的弹出点分散在多个模板/组件里(含声明式 @atcError),无法逐一在弹出前前置, // 故挂载时幂等地去重并挂到 body;加购 toast 改为弹出前按需去重(见 showAddToCartToast) this.ensureSingleToastInBody_('cart_match_discount_toast_wrap'); } unmountCallback() {} // 同一页面可能有多个 block 各自渲染本 toast snippet(如商详的 discount_automatic + 购物车抽屉里的折扣横幅), // 导致 toast 外层出现重复 id。重复 id 下 getElementById/querySelector 及 SPZ 动作引用都只命中第一个, // 且被关进抽屉的那份会被抽屉的 transform/overflow 裁剪/错位。这里在挂载时幂等去重: // 只保留一份、移除多余的,并把保留的挂到 body(body 是 position:fixed 最安全的落点,避免被任何祖先裁剪)。可反复调用。 ensureSingleToastInBody_(id) { const els = Array.from(document.querySelectorAll('#' + id)); if (!els.length) return; els.slice(1).forEach((el) => el.remove()); const keep = els[0]; if (keep.parentNode !== document.body) { document.body.appendChild(keep); } } // 主题购物车抽屉是否打开 isInCartDrawer_() { return !!document.querySelector('[data-section-type="cart_drawer"] spz-sidebar[open]'); } setupAction_() { this.registerAction('showAddToCartToast', () => { // 抽屉内加购:主题本就不会有加购效果,统一弹插件自己的 toast // 非抽屉:主题有加购代理则沿用主题加购效果,否则插件兜底 const proxyEl = document.getElementById('add-cart-event-proxy'); const inDrawer = this.isInCartDrawer_(); if (!inDrawer && proxyEl) { return; } // 弹出前按需去重并挂到 body(幂等),避免重复 id 命中错对象或被抽屉裁剪/错位 this.ensureSingleToastInBody_('apps_add_cart_toast_wrap'); const toastEl = document.querySelector('#apps-match-drawer-add_to_cart_toast') SPZ.whenApiDefined(toastEl).then((apis) => { apis.showToast("Added successfully"); }); }); } buildCallback() { this.setupAction_(); }; } SPZ.defineElement('spz-custom-discount-toast', SpzCustomDiscountBundle);
${function(){ if(originData.discount_info.discount_id === "0") return; const homePageInfo = originData.home_page_info; const hasBanner = homePageInfo?.banner?.enabled; const bannerText = homePageInfo?.banner?.text; const bannerConfig = JSON.parse(homePageInfo.banner.config); const colorConfig = bannerConfig.color; const banner_bg_start = colorConfig.banner_bg_start; const banner_bg_end = colorConfig.banner_bg_end; const text_color = colorConfig.banner_text; const image_domain = originData.image_domain; const isMobile = originData.isMobile; const bannerImageConfig = bannerConfig.image || {}; const bannerImageUrl = isMobile ? bannerImageConfig.mobile : bannerImageConfig.desktop; const hasBannerImage = !!bannerImageUrl; const bannerImageFullUrl = hasBannerImage ? image_domain + bannerImageUrl : ''; const bannerImageBgSize = bannerImageConfig.image_render === "fill" ? "cover" : "contain"; const countdown_bg = colorConfig.countdown_bg; const countdown_text_color = colorConfig.countdown_text; const is_end_countdown = bannerConfig.countdown.end_opened; const end_format = bannerConfig.countdown.end_format; const is_show_day = end_format.indexOf("DD") != -1; const is_show_millisecond = end_format.indexOf("SSS") != -1; const ends_remaining_seconds = originData.discount_info.ends_remaining_seconds; const promotioUrl = '/' + 'promotions/discount-default/' + originData.discount_info.id; let dom = originData ? `
FLASH SALE
View More
${bannerText}
` : `
`; return dom; }()}
class SpzCustomDiscountFlashsale extends SPZ.BaseElement { constructor(element) { super(element); this.xhr_ = SPZServices.xhrFor(this.win); this.discountInfoApi = "\/api\/storefront\/promotion\/home_page\/campaign?discount_id=" this.product_display = {}; this.model = { loading: false, page: 2, limit: 20, total: 0, //已展示的商品数量 params: { count: 0, has_more: false, sort: { by: "recommend", direction: "asc" } } }; this.discount_id= ""; this.image_size="100%"; this.discount_info = {}; } isLayoutSupported(layout) { return layout == SPZCore.Layout.LOGIC; } async getDiscountList() { const data = await this.xhr_.fetchJson(this.discountInfoApi + this.discount_id, { method: "GET", }).then(res => { this.model.params = { count: res.product_info.count, has_more: res.product_info.has_more, sort: { by: "recommend", direction: "asc" } } if(!res.product_info.product.length) return; this.model.total = res.product_info.product.length; this.product_display = res.home_page_info.product_display; this.discount_info = res.discount_info; res.product_info.product.forEach((product) => { product.url = appDiscountUtils.globalizePath(product.url); }) res.image_domain = this.win.SHOPLAZZA.image_domain; res.isMobile = appDiscountUtils.judgeMobile(); SPZ.whenApiDefined(document.getElementById("appDiscountIndexFlashsale")) .then(apis => { apis.render(res).then(() => { const hiddenArraw = res.home_page_info.banner.enabled ? res.product_info.product.length < 5 : res.product_info.product.length < 6 if(hiddenArraw) { document.querySelectorAll('.app_discount_flashsale_arrow').forEach((item) => { item.style.display="none"; }) } SPZ.whenApiDefined(document.getElementById("flashsaleProductsRender")).then((api) => { res.product_info.product_display = this.product_display; res.product_info.discount_id = this.discount_id; res.product_info.apply_scenario = 1; res.product_info.limit_purchase = this.discount_info.limit_user_product_discount; res.product_info.discount_image_size = this.image_size; api.render(res.product_info,true).then(() => {this.bindEvent_()}); }) }) }) }).catch(err => { console.error(err); }) return data; }; // 获取加载的商品数据,拼接html模板 async loadData(cb) { // 请求数据 this.model.loading = true; //查询活动商品接口 const reqBody = { discount_id: this.discount_id, page: this.model.page, limit: this.model.limit, apply_scenario: 1, sort: this.model.params.sort, sales_channel: { sale_channel_type: "online", sale_channel_id: '1939216' } } this.xhr_.fetchJson(`/api/storefront/promotion/landing_page/product/list`, { method: "post", body: reqBody }).then(async(res)=>{ const count = res.count; this.model.params.has_more = res.has_more; this.model.total = this.model.total + res.products.length; if (count > 0) { this.model.page++; if (res.products && res.products.length > 0) { res.products.forEach((product) => { product.url = appDiscountUtils.globalizePath(product.url); }) res.product_display = this.product_display; res.discount_id = this.discount_id; res.apply_scenario = 1; res.limit_purchase = this.discount_info.limit_user_product_discount; res.discount_image_size = this.image_size; // 获取商品列表渲染模板, dom挂载 const $content = document.querySelector(".app_discount_products_list_wrapper"); this.templates_ = SPZServices.templatesForDoc(); this.templates_.renderTemplate(document.querySelector('#apps-discounts_product_list_template'), res).then((el) => { const childNodes = el.querySelectorAll('.as-render-product-item'); if (childNodes && childNodes.length > 0) { $content.append(...childNodes); } }) // 监听load去掉灰色背景 document.dispatchEvent(new CustomEvent('fire.load.img')); // 触发懒加载 cb && cb(products); window.lazyLoadInstance && window.lazyLoadInstance.update(); } } this.model.loading = false; }).catch((err)=>{ console.error(err); this.model.loading = false; }) }; setupAction_() { this.registerAction('shiftMove', (data) => { const $el = document.querySelector(".app_discount_products_list_wrapper"); const action = data.args.direct === "right"; const scrollwidth = action ? $el.offsetWidth : -$el.offsetWidth; $el.scrollBy({ left: scrollwidth, behavior: 'smooth' }); }); this.registerAction('changeFlashSaleLimitPurchase', (invocation) => { const data = invocation.args.data; this.handleFlashsaleTip_(data); }); }; //切换快速加购弹窗内限时促销限购提示 handleFlashsaleTip_(data) { const flashsaleEl = document.querySelector('#quick-shop-flashsale-tip'); SPZ.whenApiDefined(flashsaleEl).then((api) => { api.render(data); }); } bindEvent_() { // 监听滚动,请求数据 const $el = document.querySelector(".app_discount_products_list_wrapper"); if($el) { $el.addEventListener("scroll", this.win.SPZCore.Types.debounce( this.win, () => { const isRightEnd = $el.scrollLeft + $el.offsetWidth + 10 >= $el.scrollWidth; const isLeftEnd = Math.abs($el.scrollLeft) + $el.offsetWidth + 10 >= $el.scrollWidth; const isRTL = document.documentElement.getAttribute('dir') == 'rtl'; const isEnd = isRTL ? isLeftEnd : isRightEnd; if(isEnd && this.model.params.has_more && !this.model.loading && this.model.total < 100) { this.loadData(); } }, 50 )) }; }; buildCallback() { this.setupAction_(); }; mountCallback() { const $el = document.querySelector("#appDiscountFlashsale") this.discount_id = $el.getAttribute('flashsale-id'); this.image_size = $el.getAttribute('image-size'); if(!this.discount_id) return; this.getDiscountList(); }; } SPZ.defineElement('spz-custom-discount-flashsale', SpzCustomDiscountFlashsale);
Log in
Create an account
(function(){ let w = window.innerWidth; function setHeaderCssVar() { const headerEle = document.getElementById('shoplaza-section-header'); if(!headerEle){ return }; document.body.style.setProperty('--window-height', `${window.innerHeight}px`); document.body.style.setProperty('--header-height', `${headerEle.clientHeight}px`); const mdScorllHideEle = headerEle.querySelector('.header__mobile .header__scroll_hide'); if (mdScorllHideEle) { document.body.style.setProperty('--header-scroll-hide-height-md', `${mdScorllHideEle.clientHeight}px`); } const pcScorllHideEle = headerEle.querySelector('.header__desktop .header__scroll_hide'); if (pcScorllHideEle) { document.body.style.setProperty('--header-scroll-hide-height-pc', `${pcScorllHideEle.clientHeight}px`); } } function handlResize() { if(w == window.innerWidth){return}; w = window.innerWidth; setHeaderCssVar(); }; function init(){ setHeaderCssVar(); window.removeEventListener('resize', window._theme_header_listener) window._theme_header_listener = handlResize; window.addEventListener('resize', window._theme_header_listener); } init(); })();
6/35
${data.index + 1}/${data.total}
${Array(data.total).fill(0).map((num, index) => `
`).join('')}
Y&D Hidden Sliding Mirror, Hole Board, Dressing Mirror, Full-Length Mirror, Home Closable Entrance Wall-Mounted Fitting Mirror
AED119.00
${function() { const variantData = data.variant || {"id":"79205091-a692-4265-9bda-ae8afa52aa99","product_id":"48362f35-6d29-4b4b-b47a-22f511015a87","title":"[eco-friendly board] width 30cm, height 120cm, walnut color [optional left and right push and pull]","weight_unit":"kg","inventory_quantity":0,"sku":"","barcode":"","position":1,"option1":"[eco-friendly board] width 30cm, height 120cm, walnut color [optional left and right push and pull]","option2":"","option3":"","note":"","image":{"src":"\/\/img.staticdj.com\/150989bf5560d52ad83add16b360d34e.jpeg","path":"150989bf5560d52ad83add16b360d34e.jpeg","width":800,"height":800,"alt":"","aspect_ratio":1},"wholesale_price":[{"price":119,"min_quantity":1}],"weight":"0","compare_at_price":"0","price":"119","retail_price":"0","available":true,"url":"\/products\/y-d-hidden-sliding-mirror-hole-board-dressing-mirror-full-length-mirror-home-closable-entrance-wall-mounted-fitting-mirror?variant=79205091-a692-4265-9bda-ae8afa52aa99","available_quantity":999999999,"options":[{"name":"Color","value":"[eco-friendly board] width 30cm, height 120cm, walnut color [optional left and right push and pull]"}],"off_ratio":0,"flashsale_info":[],"sales":0}; const saveType = "amount"; const productLabelDiscountOn = true; return `
-
${saveType == 'percentage' ? `
-${variantData.off_ratio}%
` : `
-
` }
`; }()}
Color:
[eco-friendly board] width 30cm, height 120cm, walnut color [optional left and right push and pull]
${function(){ const optName = "Color"; const optionValue = data.originData.selectData ? data.originData.selectData[optName].value : data.originData.value; const optionValueText = optionValue ? (optionValue) : ''; return `
${optionValueText}
`; }()}
[eco-friendly board] width 30cm, height 120cm, walnut color [optional left and right push and pull]
[eco-friendly board] 30cm wide and 120cm high, mysterious black [optional left and right push and pull]
[eco-friendly board] 30cm wide and 120cm high, warm white [optional left and right sliding]
[eco-friendly board] width 40cm, height 120cm, walnut color [optional left and right sliding]
[eco-friendly board] 40cm wide and 120cm high, mysterious black [optional left and right push and pull]
[eco-friendly board] 40cm wide and 120cm high, warm white [optional left and right sliding]
【eco-friendly panels】30cm wide x 150cm high, walnut finish 【left/right sliding】
[eco-friendly board] 30cm wide and 150cm high, mysterious black [optional left and right push and pull]
[eco-friendly board] 30cm wide and 150cm high, warm white [optional left and right sliding]
[eco-friendly board] width 40cm, height 150cm, walnut color [optional left and right sliding]
[eco-friendly board] width 40cm, height 150cm, mysterious black [optional left and right push and pull]
[eco-friendly board] 40cm wide and 150cm high, warm white [optional left and right sliding]
[eco-friendly board] width 50cm, height 150cm, walnut color [optional left and right sliding]
[eco-friendly board] 50cm wide and 150cm high, mysterious black [optional left and right push and pull]
[eco-friendly board] 50cm wide and 150cm high, warm white [optional left and right sliding]
[all solid wood] 30*120 walnut color [self-installation - door-to-door delivery]
[all solid wood] 30*120 warm white [self-installation - door-to-door delivery]
[all solid wood] 30*120 locke gray [self-installation - door-to-door delivery]
[all solid wood] 40*120 walnut color [self-installation - door-to-door delivery]
[all solid wood] 40*120 warm white [self-installation - door delivery]
[all solid wood] 40*120 locke gray [self-installation - door-to-door delivery]
[all solid wood] 30*150 walnut color [self-installation - door delivery]
[all solid wood] 30*150 warm white [self-installation - door delivery]
[all solid wood] 30*150 locke gray [self-installation - door-to-door delivery]
[all solid wood] 40*150 walnut color [self-assembly - door-to-door delivery]
[all solid wood] 40*150 warm white [self-installation - door-to-door delivery]
[all solid wood] 40*150 locke gray [self-installation - door-to-door delivery]
[all solid wood] 50*150 walnut color [self-installation - door-to-door delivery]
[all solid wood] 50*150 warm white [self-installation - door-to-door delivery]
[all solid wood] 50*150 locke gray [self-assembly - door-to-door delivery]
${function(){ const tipText = "Please select a {{ name }}".replace(/\{\{\s+name\s+\}\}/g, data); return `
${tipText}
` }()}
Quantity
Add to cart
AED119.00
${function(){ const wholesale_enabled = false; const qty = data.quantity || 1; const currentSelectVariant = data.variant; const defaultVariant = (data.product && data.product.variants && data.product.variants[0]); const productVariant = {"id":"79205091-a692-4265-9bda-ae8afa52aa99","product_id":"48362f35-6d29-4b4b-b47a-22f511015a87","title":"[eco-friendly board] width 30cm, height 120cm, walnut color [optional left and right push and pull]","weight_unit":"kg","inventory_quantity":0,"sku":"","barcode":"","position":1,"option1":"[eco-friendly board] width 30cm, height 120cm, walnut color [optional left and right push and pull]","option2":"","option3":"","note":"","image":{"src":"\/\/img.staticdj.com\/150989bf5560d52ad83add16b360d34e.jpeg","path":"150989bf5560d52ad83add16b360d34e.jpeg","width":800,"height":800,"alt":"","aspect_ratio":1},"wholesale_price":[{"price":119,"min_quantity":1}],"weight":"0","compare_at_price":"0","price":"119","retail_price":"0","available":true,"url":"\/products\/y-d-hidden-sliding-mirror-hole-board-dressing-mirror-full-length-mirror-home-closable-entrance-wall-mounted-fitting-mirror?variant=79205091-a692-4265-9bda-ae8afa52aa99","available_quantity":999999999,"options":[{"name":"Color","value":"[eco-friendly board] width 30cm, height 120cm, walnut color [optional left and right push and pull]"}],"off_ratio":0,"flashsale_info":[],"sales":0}; const variantData = currentSelectVariant || defaultVariant || productVariant; const wholesale_price = variantData.wholesale_price || []; if(wholesale_enabled && wholesale_price.length > 0) { let wholesaleIndex = wholesale_price.findIndex(item => { return item.min_quantity > qty; }); if(wholesaleIndex < 0){ wholesaleIndex = wholesale_price.length - 1; }else if(wholesaleIndex > 0){ wholesaleIndex = wholesaleIndex - 1; } const wholesalePrice = wholesale_price[wholesaleIndex] || ''; return `
` }else { const price = variantData && variantData.price; return price != undefined ? `
` : '
'; } }()}
Buy now
Product was out of stock.
Product is unavailable.
${function(){ const variantData = data.variant || {"id":"79205091-a692-4265-9bda-ae8afa52aa99","product_id":"48362f35-6d29-4b4b-b47a-22f511015a87","title":"[eco-friendly board] width 30cm, height 120cm, walnut color [optional left and right push and pull]","weight_unit":"kg","inventory_quantity":0,"sku":"","barcode":"","position":1,"option1":"[eco-friendly board] width 30cm, height 120cm, walnut color [optional left and right push and pull]","option2":"","option3":"","note":"","image":{"src":"\/\/img.staticdj.com\/150989bf5560d52ad83add16b360d34e.jpeg","path":"150989bf5560d52ad83add16b360d34e.jpeg","width":800,"height":800,"alt":"","aspect_ratio":1},"wholesale_price":[{"price":119,"min_quantity":1}],"weight":"0","compare_at_price":"0","price":"119","retail_price":"0","available":true,"url":"\/products\/y-d-hidden-sliding-mirror-hole-board-dressing-mirror-full-length-mirror-home-closable-entrance-wall-mounted-fitting-mirror?variant=79205091-a692-4265-9bda-ae8afa52aa99","available_quantity":999999999,"options":[{"name":"Color","value":"[eco-friendly board] width 30cm, height 120cm, walnut color [optional left and right push and pull]"}],"off_ratio":0,"flashsale_info":[],"sales":0}; return `
Sku :
${variantData && variantData.sku}
Weight :
${variantData && variantData.weight}${variantData && variantData.weight_unit}
Barcode :
${variantData && variantData.barcode}
` }()}
Description
${function(){ return `
${data.starNum}
/
${data.starTotal}
`; }()}
${function(){ return `
${data.starNum}
/
${data.starTotal}
`; }()}
Write a Review
${data.title}
How do you like this product?
Score
This field is required.
Your name
This field is required.
Contact Email
This field is required.
Please enter valid email.
Please enter valid email.
Body of Review
0/3000
This field is required.
Pictures/Videos
Submit Comments Anonymously
Submit
${function() { const pc_layout = 'single_column'; const isProductPage = '1' == 1; const product_id = '48362f35-6d29-4b4b-b47a-22f511015a87'; const accent_color = ''; const randomStr = Math.random().toString(36).substring(7); const item = data; const config = data.config; const formatDate = value => { let date = new Date(value * 1000); const day = date.toLocaleString('en-US', { day: '2-digit' }); const month = date.toLocaleString('en-US', { month: 'short' }); const year = date.toLocaleString('en-US', { year: 'numeric' }); return month + '/' + day + '/' + year; }; return `
${item.username}
Verified
More
${item.content}
${data.shop_name} reply:
${item.reply && item.reply.length && item.reply[0].content}
More
${data.product?.title}
${formatDate(item.created_at)}
`; }()}
${function(){ return `
`; }()}
${function() { const randomStr = Math.random().toString(36).substring(7); const list = data.listData; const isPC = data.isPC; const pc_layout = 'single_column'; return `
All(${list.count})
With Photos(${list.image_count})
`; }()}
${function(){ const isPC = data.isPC; const pc_layout = 'single_column'; return `
Write a Review
Customer Reviews
No reviews yet, why don't you leave the first review?
Write a Review
No reviews yet, why don't you leave the first review?
Write a Review
`; }()}
Cart
Your shopping bag is empty
Continue shopping
${item.product_title}
${item.options.map(option => option.value).join('/')}
${propertie.name}/${propertie.isImage ? `
View image
` : propertie.value}
Free gift
Mixed Lot
*${item.quantity}
${item.item_text}
${discount_item.title}
(-
)
Total:
${function() { const textArray = ("Save {{save_amount}}").split(/\{\{\s*save_amount\}\}/); if (textArray.length > 0 && textArray.length < 2) { textArray.push(''); } return textArray.map((text, index) => { if (index == 0) { return `
${text}
`; } return `
${text}
`; }).join(''); }()}
${function() { const textArray = ("Save {{save_amount}}").split(/\{\{\s*save_amount\}\}/); if (textArray.length > 0 && textArray.length < 2) { textArray.push(''); } return textArray.map((text, index) => { if (index == 0) { return `
${text}
`; } return `
${text}
`; }).join(''); }()}
${discount_application.title}:
-
${data.invalid_msg}
Check out
Taxes and shipping calculated at checkout
${data.invalid_msg}
Total:
${function() { const textArray = ("Save {{save_amount}}").split(/\{\{\s*save_amount\}\}/); if (textArray.length > 0 && textArray.length < 2) { textArray.push(''); } return textArray.map((text, index) => { if (index == 0) { return `
${text}
`; } return `
${text}
`; }).join(''); }()}
${function() { const textArray = ("Save {{save_amount}}").split(/\{\{\s*save_amount\}\}/); if (textArray.length > 0 && textArray.length < 2) { textArray.push(''); } return textArray.map((text, index) => { if (index == 0) { return `
${text}
`; } return `
${text}
`; }).join(''); }()}
${function() { const textArray = ("Save {{save_amount}}").split(/\{\{\s*save_amount\}\}/); if (textArray.length > 0 && textArray.length < 2) { textArray.push(''); } return textArray.map((text, index) => { if (index == 0) { return `
${text}
`; } return `
${text}
`; }).join(''); }()}
${discount_application.title}:
-
Check out
${data.invalid_msg}
Check out
Taxes and shipping calculated at checkout
Subtotal:
${discount_application.title}:
-
Total:
Check out
Taxes and shipping calculated at checkout
const summaryStickyRender = document.querySelector('#cart-drawer-summary-sticky-render'); if (summaryStickyRender) { document.body.style.setProperty('--cart-drawer-summary-sticky-height', summaryStickyRender.clientHeight + 'px'); }
View Cart
${function(){ const productData = data.product; let product_change_event = '', mouse_over_event = ' '; mouse_out_event = ''; const product_options = productData.options.filter(Boolean) || []; for (let opt of product_options) { const nameEscape = opt.name.replace(/\/|\\|\s|\'|\"|`|\<|\>/g, '') product_change_event = product_change_event + `quick-shop-selected-variant-${opt.id}.rerender(data=event.selectedValues.${opt.name});`; mouse_out_event = mouse_out_event + `@${nameEscape}Mouseout="quick-shop-selected-variant-${opt.id}.rerender(data=event.selectData.${opt.name}, redo=true);"`; mouse_over_event = mouse_over_event + `@${nameEscape}Mouseover="quick-shop-selected-variant-${opt.id}.rerender(data=event, redo=true);"`; } const selectedVariant = productData.variants.find(v => v.available) || productData.variants[0]; const statusLan = ((selectedVariant && !selectedVariant.available) || (!selectedVariant && !productData.available)) ? "Sold out" : "Add to cart"; return `
${statusLan}
` }()}
${function(){ const currentSelectVariant = data.variant; const defaultVariant = (data.product && data.product.variants && data.product.variants[0]); const variantData = currentSelectVariant || defaultVariant || data; const retail_price = variantData.retail_price || 0; return `
Retail
` }()}
${function(){ const wholesale_enabled = false; const qty = data.quantity || 1; const currentSelectVariant = data.variant; const defaultVariant = (data.product && data.product.variants && data.product.variants[0]); const productVariant = {"id":"79205091-a692-4265-9bda-ae8afa52aa99","product_id":"48362f35-6d29-4b4b-b47a-22f511015a87","title":"[eco-friendly board] width 30cm, height 120cm, walnut color [optional left and right push and pull]","weight_unit":"kg","inventory_quantity":0,"sku":"","barcode":"","position":1,"option1":"[eco-friendly board] width 30cm, height 120cm, walnut color [optional left and right push and pull]","option2":"","option3":"","note":"","image":{"src":"\/\/img.staticdj.com\/150989bf5560d52ad83add16b360d34e.jpeg","path":"150989bf5560d52ad83add16b360d34e.jpeg","width":800,"height":800,"alt":"","aspect_ratio":1},"wholesale_price":[{"price":119,"min_quantity":1}],"weight":"0","compare_at_price":"0","price":"119","retail_price":"0","available":true,"url":"\/products\/y-d-hidden-sliding-mirror-hole-board-dressing-mirror-full-length-mirror-home-closable-entrance-wall-mounted-fitting-mirror?variant=79205091-a692-4265-9bda-ae8afa52aa99","available_quantity":999999999,"options":[{"name":"Color","value":"[eco-friendly board] width 30cm, height 120cm, walnut color [optional left and right push and pull]"}],"off_ratio":0,"flashsale_info":[],"sales":0}; const variantData = currentSelectVariant || defaultVariant || productVariant; const wholesale_price = variantData.wholesale_price || []; if(wholesale_enabled && wholesale_price.length > 0) { let wholesaleIndex = wholesale_price.findIndex(item => { return item.min_quantity > qty; }); if(wholesaleIndex < 0){ wholesaleIndex = wholesale_price.length - 1; }else if(wholesaleIndex > 0){ wholesaleIndex = wholesaleIndex - 1; } const wholesalePrice = wholesale_price[wholesaleIndex] || ''; return `
` }else { const price = variantData && variantData.price; return price != undefined ? `
` : '
'; } }()}
${function() { let variantImageShowed = false; const currentProduct = data.product; return (currentProduct.options || []).map((option, index) => { const optionName = option.name || ''; const optionId = option.id || ''; const position = `option${index + 1}`; let isThumbImage = false; if (currentProduct.need_variant_image && !variantImageShowed) { const variantNames = ["color"] || []; for (let i = 0, len = variantNames.length; i < len; i++) { const name = variantNames[i].toLowerCase(); if (name === optionName.toLowerCase()) { isThumbImage = true; variantImageShowed = true; } } } const variantType = "button"; const thumbStyle = "image_with_text"; return `
${optionName}:
${option.values.map((value, idx) => { const selected = data.selectedValues[optionName] == value ? 'checked' : ''; let thumbImage = null; if (isThumbImage) { const variants = currentProduct.variants; for (let i = 0, len = variants.length; i < len; i++) { const variant = variants[i]; if (variant[position] == value && thumbImage == null) { thumbImage = variant.image; break; } } } return `
${value}
` }).join('')}
${optionName}
${option.values.map(value => { const selected = data.selectedValues[optionName] == value ? 'selected' : ''; return `
${value}
` }).join('')}
` }).join(''); }()}
${data.originData && data.originData.value || data.value}