Diamond Bridal Set 5/8 ct tw Round-cut 10K White Gold
              
            
        
          
           
  
    
    
  
 people are viewing this right now
   
            
        
          
          
              
              
            
        
          
          
              
              
              
            
        
          
          
              
                
  
  
  
    ${function() {
      const variantData = data.variant || {"id":"e149e82c-3d07-4ff8-a730-5eedd7833a08","product_id":"bd64ad24-40c4-4b36-8a47-97bb380a6b15","title":"6","weight_unit":"lb","inventory_quantity":9994,"sku":"Rings_093_6","barcode":"","position":1,"option1":"6","option2":"","option3":"","note":"","image":null,"wholesale_price":[{"price":36.99,"min_quantity":1}],"weight":"0","compare_at_price":"0","price":"36.99","retail_price":"0","available":true,"url":"\/products\/diamond-bridal-set-5-8-ct-tw-round-cut-10k-white-gold?variant=e149e82c-3d07-4ff8-a730-5eedd7833a08","available_quantity":9994,"options":[{"name":"size","value":"6"}],"off_ratio":0,"flashsale_info":[],"sales":35};
      const saveType = "amount";
      const productLabelDiscountOn = true;
      return `
        
          
            
             - 
            
          
          
            
            
            
              ${saveType == 'percentage'
                ? `-${variantData.off_ratio}%`
                : `-`
              }
            
            
           
         
      `;
    }()}
  
              
              
            
        
          
          
              
              
   
  
  
  
  
  
  
    
    
    
    
  
  
    
      
      
      
        
      
      
      
      
        
      
      
        
          ${function(){
            const tipText = "Please select a {{ name }}".replace(/\{\{\s+name\s+\}\}/g, data);
            return `${tipText}
`
          }()}
        
      
    
  
            
        
          
          
              
                
              
          
        
          
          
              
            
        
          
          
              
  
  
    
      
    
  
  
    
      
    
    
      
    
    
    
      Product was out of stock.
    
    
      Product is unavailable.
    
   
            
        
          
          
              
                
  
  /** @private {string} */
  class SpzCustomAnchorScroll extends SPZ.BaseElement {
    static deferredMount() {
      return false;
    }
    constructor(element) {
      super(element);
      /** @private {Element} */
      this.scrollableContainer_ = null;
    }
    isLayoutSupported(layout) {
      return layout == SPZCore.Layout.LOGIC;
    }
    buildCallback() {
      this.viewport_ = this.getViewport();
      this.initActions_();
    }
    setTarget(containerId, targetId) {
      this.containerId = '#' + containerId;
      this.targetId = '#' + targetId;
    }
    scrollToTarget() {
      const container = document.querySelector(this.containerId);
      const target = container.querySelector(this.targetId);
      const {scrollTop} = container;
      const eleOffsetTop = this.getOffsetTop_(target, container);
      this.viewport_
        .interpolateScrollIntoView_(
          container,
          scrollTop,
          scrollTop + eleOffsetTop
        );
    }
    initActions_() {
      this.registerAction(
        'scrollToTarget',
        (invocation) => this.scrollToTarget(invocation?.caller)
      );
      this.registerAction(
        'setTarget',
        (invocation) => this.setTarget(invocation?.args?.containerId, invocation?.args?.targetId)
      );
    }
    /**
    * @param {Element} element
    * @param {Element} container
    * @return {number}
    * @private
    */
    getOffsetTop_(element, container) {
      if (!element./*OK*/ getClientRects().length) {
        return 0;
      }
      const rect = element./*OK*/ getBoundingClientRect();
      if (rect.width || rect.height) {
        return rect.top - container./*OK*/ getBoundingClientRect().top;
      }
      return rect.top;
    }
  }
  SPZ.defineElement('spz-custom-anchor-scroll', SpzCustomAnchorScroll);
  const STRENGTHEN_TRUST_URL = "/api/strengthen_trust/settings";
  class SpzCustomStrengthenTrust extends SPZ.BaseElement {
    constructor(element) {
      super(element);
      this.renderElement_ = null;
    }
    isLayoutSupported(layout) {
      return layout == SPZCore.Layout.CONTAINER;
    }
    buildCallback() {
      this.xhr_ = SPZServices.xhrFor(this.win);
      const renderId = this.element.getAttribute('render-id');
      SPZCore.Dom.waitForChild(
        document.body,
        () => !!document.getElementById(renderId),
        () => {
          this.renderElement_ = SPZCore.Dom.scopedQuerySelector(
            document.body,
            `#${renderId}`
          );
          if (this.renderElement_) {
            this.render_();
          }
          this.registerAction('track', (invocation) => {
            this.track_(invocation.args);
          });
        }
      );
    }
    render_() {
      this.fetchData_().then((data) => {
        if (!data) {
          return;
        }
        SPZ.whenApiDefined(this.renderElement_).then((apis) => {
          apis?.render(data);
          document.querySelector('#strengthen-trust-render-1539149753700').addEventListener('click',(event)=>{
            if(event.target.nodeName == 'A'){
              this.track_({type: 'trust_content_click'});
            }
          })
        });
      });
    }
    track_(data = {}) {
      const track = window.sa && window.sa.track;
      if (!track) {
        return;
      }
      track('trust_enhancement_event', data);
    }
    parseJSON_(string) {
      let result = {};
      try {
        result = JSON.parse(string);
      } catch (e) {}
      return result;
    }
    fetchData_() {
      return this.xhr_
        .fetchJson(STRENGTHEN_TRUST_URL)
        .then((responseData) => {
          if (!responseData || !responseData.data) {
            return null;
          }
          const data = responseData.data;
          const moduleSettings = (data.module_settings || []).reduce((result, moduleSetting) => {
            return result.concat(Object.assign(moduleSetting, {
              logos: (moduleSetting.logos || []).map((item) => {
                return moduleSetting.logos_type == 'custom' ? this.parseJSON_(item) : item;
              })
            }));
          }, []);
          return Object.assign(data, {
            module_settings: moduleSettings,
            isEditor: window.self !== window.top,
          });
        });
    }
  }
  SPZ.defineElement('spz-custom-strengthen-trust', SpzCustomStrengthenTrust);
  
    
      
        
          ${data.module_title}
        
        
          
          
            To display this card to customers, you need to go to "Booster & Store Conversion" to turn on the trust enhancement feature.
          
         
        
          
            
            
  
    
    
      ${item.content.replaceAll("{store_name}","lovesjewelry")}
    
    
      
    
    
      
    
   
 
          
        
       
      
  
    
    
      To display this card to customers, you need to go to "Booster & Store Conversion" to turn on the trust enhancement feature.
    
   
  
    
    
    
    
  
 
     
  
              
          
        
          
           
  
  
  
    
      
        
        
          This stunning bridal set for her features a princess-cut diamond at the center of the engagement ring, framed in twinkling round diamonds Additional round diamonds are channel-set into the 10K white gold band of the engagement ring and the matching wedding band The bridal set has a total diamond weight of 5/8 carat
         
      
    
  
 
            
        
          
          
              
                
  
  
  
    
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
    const TAG = 'spz-custom-revue-util';
    const DEFAULT_DELAY_TIME = 100;
    class SpzCustomRevueUtil extends SPZ.BaseElement {
      constructor(element) {
        super(element);
        this.templates_ = SPZServices.templatesForDoc();
      }
      buildCallback = () => {
        this.action_ = SPZServices.actionServiceForDoc(this.element);
        this.templates_ = SPZServices.templatesForDoc(this.element);
        this.xhr_ = SPZServices.xhrFor(this.win);
      }
      static deferredMount() {
        return false;
      }
      mountCallback() {
      }
      debounceRender(el, thisEl, containerStr) {
        return this.smoothRender_(el, thisEl, containerStr).then(() => this.attemptToFit_(thisEl));
      }
  
      smoothRender_(newEl, thisEl, containerStr) {
        const that = this;
        that.appendAsUnvisibleContainer_(newEl, thisEl);
        const components = newEl.querySelectorAll('[layout]');
        return Promise.race([
          Promise.all(
            Array.prototype.map.call(components, (e) =>
              SPZ.whenDefined(e).then(() => e.whenBuilt())
            )
          ),
          SPZServices.timerFor(that.win).promise(DEFAULT_DELAY_TIME),
        ]).then(() => {
          return containerStr !== 'form_' ? thisEl.mutateElement(() => that.quickReplace(thisEl, newEl)) : thisEl.mutateElement(() => that.quickReplaceForm(thisEl, newEl));
        });
      }
      quickReplace(thisEl, newEl) {
        thisEl.container_ && this.toggleVisible_(thisEl.container_);
        this.toggleVisible_(newEl, true);
        thisEl.container_ && SPZCore.Dom.removeElement(thisEl.container_);
        thisEl.container_ = newEl;
      };
      quickReplaceForm(thisEl, newEl) {
        thisEl.form_ && this.toggleVisible_(thisEl.form_);
        this.toggleVisible_(newEl, true);
        const children = thisEl.form_.querySelector('*:not(template)');
        children && SPZCore.Dom.removeElement(children);
        this.toggleVisible_(thisEl.form_, true);
        thisEl.form_.appendChild(newEl);
      };
  
      appendAsUnvisibleContainer_(el, thisEl) {
        this.toggleVisible_(el);
        thisEl.element.appendChild(el);
      }
  
      attemptToFit_(thisEl) {
        const fitFunc = () => {
          thisEl.mutateElement(this.setElementHeight_.bind(thisEl));
        };
        const container = thisEl.container_ || thisEl.form_;
        if (container) {
          const children = container.querySelectorAll('*:not(template)');
          const spzChildren = Array.prototype.filter
            .call(children, SPZUtils.isSpzElement)
            .filter((e) => !(e.isMount && e.isMount()));
          spzChildren
            .map((e) => SPZ.whenDefined(e).then(() => e.whenMounted()))
            .forEach((p) => p.then(() => fitFunc()));
        }
        return fitFunc();
      }
  
      setElementHeight_() {
        const targetHeight = (this.container_ || this.form_)?./*OK*/ scrollHeight;
        const height = this.element./*OK*/ offsetHeight;
        if (height !== targetHeight) {
          SPZCore.Dom.setStyles(this.element, {
            height: `${targetHeight}px`,
          });
        }
      }
  
      toggleVisible_(el, visible = false) {
        if (!visible) {
          el.classList.add('i-spzhtml-layout-fill');
          SPZCore.Dom.setStyles(el, {
            'z-index': -100000,
            'opacity': 0,
          });
        } else {
          el.classList.remove('i-spzhtml-layout-fill');
          SPZCore.Dom.setStyles(el, {
            'z-index': 'auto',
            'opacity': 1,
          });
        }
      }
  
      setMinWidth_() {
        const targetWidth = this.container_?./*OK*/ scrollWidth;
        const width = this.element./*OK*/ offsetWidth;
        if (width !== targetWidth) {
          SPZCore.Dom.setStyles(this.element, {
            'min-width': `${targetWidth}px`,
          });
        }
      }
      triggerEvent_ = (name, data) => {
        const event = SPZUtils.Event.create(this.win, `${TAG}.${name}`, data || {});
        this.action_.trigger(this.element, name, event);
      }
      isLayoutSupported(layout) {
        return layout == SPZCore.Layout.CONTAINER;
      }
    }
    SPZ.defineElement(TAG, SpzCustomRevueUtil);
  const TAG = 'spz-custom-revue-render';
  class SPZCustomRevueRender extends SPZ.BaseElement {
    constructor(element) {
      super(element);
    }
    static deferredMount() {
      return false;
    }
    buildCallback = () => {
      this.action_ = SPZServices.actionServiceForDoc(this.element);
      this.templates_ = SPZServices.templatesForDoc(this.element);
      this.xhr_ = SPZServices.xhrFor(this.win);
    }
    mountCallback = () => {}
    render = (data) => {
      return this.templates_
      .findAndRenderTemplate(this.element, data, null)
      .then((el) => {
        if (this.element.children.length > 0) {
          this.element.children[0].style.display = 'none';
        }
        this.element.appendChild(el);
        // const utilsEl = document.getElementById('spz_custom_revue_util');
        // utilsEl && SPZ.whenApiDefined(utilsEl).then((api) => {
        //   api.debounceRender(el, this);
        // });
      });
    }
    triggerEvent_(name, data) {
      const event = SPZUtils.Event.create(this.win, `${ TAG }.${ name }`, data || {});
      this.action_.trigger(this.element, name, event);
    }
    isLayoutSupported(layout) {
      return layout == SPZCore.Layout.CONTAINER;
    }
  }
  SPZ.defineElement(TAG, SPZCustomRevueRender)
  ${function(){
    
    return `
      
        
          ${data.starNum}/${data.starTotal}
        
       
    `;
  }()}
  ${function(){
    return `
      
        
        ${data.showStarText === 'true' ? `
          
            
              
                ${data.starNum}/${data.starTotal}
              
             
          
        ` : ''}
      
 
    `;
  }()}
    const TAG = 'spz-custom-revue-star';
    class SPZCustomRevueStar extends SPZ.BaseElement {
      constructor(element) {
        super(element);
      }
      static deferredMount() {
        return false;
      }
      buildCallback = () => {
        this.action_ = SPZServices.actionServiceForDoc(this.element);
        this.templates_ = SPZServices.templatesForDoc(this.element);
        this.xhr_ = SPZServices.xhrFor(this.win);
        this.starNum = this.element.getAttribute('starNum');
        this.starTotal = this.element.getAttribute('starTotal');
        this.showStarText = this.element.getAttribute('showStarText');
        this.starColor = this.element.getAttribute('color');
        this.interact = this.element.getAttribute('interact');
        this.starSize = this.element.getAttribute('starSize') || 14;
      }
      mountCallback = () => {
        this.doRender_({
          starTotal: this.starTotal,
          totalArray: Array.from({ length: Number(this.starTotal) }, (v, k) => k + 1),
          starNum: this.starNum,
          showStarText: this.showStarText,
          starColor: this.starColor,
          starSize: this.starSize
        }).then(() => {
          if (this.interact) {
            this.addEventListeners_();
          }
        });
      }
      addEventListeners_ = () => {
        
        const stars = document.querySelectorAll('.revue-star__star');
        
        stars.forEach(star => {
          star.addEventListener('click', event => {
            const starEl = star.closest('.revue-star__star');
            const starIndex = Number(starEl.dataset.index);
            let isHalf = event.offsetX < star.offsetWidth / 2;
            // rtl
            if (document.documentElement.getAttribute('dir') === 'rtl') {
              isHalf = event.offsetX > star.offsetWidth / 2;
            }
            const starValue = isHalf ? starIndex - 0.5 : starIndex;
            this.starClickHandler_({ value: starValue });
          });
        });
      }
      renderStar = () => {
        
        const isRtl = document.documentElement.getAttribute('dir') === 'rtl';
        const stars = this.element.querySelectorAll('.revue-star__star');
        stars.forEach((star, i) => {
          const starIndex = i + 1;
          const starEl = star.querySelector('svg:nth-child(2)');
          const isHalf = this.starNum % 1 > 0 && Math.ceil(this.starNum) === starIndex;
          const isSolid = starIndex <= Math.ceil(this.starNum);
          starEl.style.display = isSolid ? 'block' : 'none';
          if (isHalf) {
            if (isRtl) {
              // RTL布局下,如果是半星,显示星星的右半边
              starEl.style.clipPath = `polygon(50% 0, 100% 0, 100% 100%, 50% 100%)`;
            } else {
              // LTR布局下,如果是半星,显示星星的左半边
              starEl.style.clipPath = `polygon(0 0, 50% 0, 50% 100%, 0 100%)`;
            }
          } else {
            starEl.style.clipPath = `polygon(0 0, 100% 0, 100% 100%, 0 100%)`
          }
        });
        const showCountEle = this.element.querySelector('#revue-star-show-count');
        showCountEle && SPZ.whenApiDefined(showCountEle).then((api) => {
          api.render({ starNum: this.starNum, starTotal: this.starTotal });
        });
      }
      doRender_ = (data) => {
        return this.templates_
        .findAndRenderTemplate(this.element, { starSize: this.starSize, ...data }, null)
        .then((el) => {
          const children = this.element.querySelector('*:not(template)');
          children && SPZCore.Dom.removeElement(children);
          this.element.appendChild(el);
        })
        .then(() => {
          this.starNum = data.starNum;
          this.renderStar();
        });
      }
      starClickHandler_ = (event) => {
        this.starNum = event.value;
        this.renderStar();
        this.triggerEvent_('change', { value: event.value });
      }
      triggerEvent_(name, data) {
        const event = SPZUtils.Event.create(this.win, `${ TAG }.${ name }`, data || {});
        this.action_.trigger(this.element, name, event);
      }
      isLayoutSupported(layout) {
        return layout == SPZCore.Layout.CONTAINER;
      }
    }
    SPZ.defineElement(TAG, SPZCustomRevueStar)
 
 
  ${function() {
    const isPercentage = data.show_percentage === 'true' && data.total <= data.show_percentage_num;
    return `
      
      
        ${!isPercentage ? `${data.count}` : `${data.count / data.total * 100}%`}
      
     
    `
  }()}
    const TAG = 'spz-custom-revue-progress';
    class SPZCustomRevueProgress extends SPZ.BaseElement {
      constructor(element) {
        super(element);
      }
      static deferredMount() {
        return false;
      }
      buildCallback = () => {
        this.action_ = SPZServices.actionServiceForDoc(this.element);
        this.templates_ = SPZServices.templatesForDoc(this.element);
        this.xhr_ = SPZServices.xhrFor(this.win);
        this.isPC = window.innerWidth > (window.breakpoint || 960);
        this.height = '6px';
        this.color = this.element.getAttribute('color') || '#000000';
        this.show_percentage = 'false';
        this.show_percentage_num = 100;
        this.count = this.element.getAttribute('count');
        this.total = this.element.getAttribute('total');
      }
      mountCallback = () => {
        this.doRender_({
          count: Number(this.count),
          total: Number(this.total),
          height: this.height,
          color: this.color,
          show_percentage: this.show_percentage,
          show_percentage_num: this.show_percentage_num
        }).then(() => {
        });
      }
      doRender_ = (data) => {
        return this.templates_
        .findAndRenderTemplate(this.element, data, null)
        .then((el) => {
          const children = this.element.querySelector('*:not(template)');
          children && SPZCore.Dom.removeElement(children);
          this.element.appendChild(el);
        });
      }
      triggerEvent_(name, data) {
        const event = SPZUtils.Event.create(this.win, `${ TAG }.${ name }`, data || {});
        this.action_.trigger(this.element, name, event);
      }
      isLayoutSupported(layout) {
        return layout == SPZCore.Layout.CONTAINER;
      }
    }
    SPZ.defineElement(TAG, SPZCustomRevueProgress)
  ${function() {
    return `
      
        
        
          ${data.count > 99 ? '99+' : data.count < 1 ? '' : data.count}
        
       
    `;
  }()}
    const TAG = 'spz-custom-revue-like';
    class SPZCustomRevueLike extends SPZ.BaseElement {
      constructor(element) {
        super(element);
      }
      static deferredMount() {
        return false;
      }
      buildCallback = () => {
        this.action_ = SPZServices.actionServiceForDoc(this.element);
        this.templates_ = SPZServices.templatesForDoc(this.element);
        this.xhr_ = SPZServices.xhrFor(this.win);
        this.grayColor = this.element.getAttribute('gray_color') || "#BDBDBD";
        this.likedColor = this.element.getAttribute('like_color') || "#FFCB44";
        this.color = this.grayColor;
        this.count = this.element.getAttribute('count');
        this.revueId = this.element.getAttribute('revue-id');
        this.location = this.element.getAttribute('location');
      }
      mountCallback = () => {
        const likes = sessionStorage.getItem('likes') ? JSON.parse(sessionStorage.getItem('likes')) : [];
        const like = likes.find(item => item.id === this.revueId);
        if (like) {
          this.color = like.like_status === 1 ? this.likedColor : this.grayColor;
        }
        // 如果location是modal,则找到相同revue-id的list的元素,拿到其count,存在list count变了,但是modal的count没变的情况
        if (this.location === 'modal') {
          const listElement = document.querySelector(`spz-custom-revue-like[revue-id="${this.revueId}"] .revue-like-count`);
          if (listElement) {
            this.count = listElement.getAttribute('data-real-count');
          }
        }
        this.doRender_({
          color: this.color,
          count: this.count
        }).then(() => {
          this.addEventListeners_();
          if(this.location === 'list') { // modal数量变更,list同步变更
            document.addEventListener('like-clicked', (e) => {
              if (e.detail.location !== this.location && e.detail.id === this.revueId) {
                this.color = e.detail.like_status === 1 ? this.likedColor : this.grayColor;
                this.count = e.detail.count;
                this.element.querySelector('.revue-like__icon').querySelector('svg').setAttribute('fill', this.color);
                this.element.querySelector('.revue-like__icon').querySelector('svg').querySelector('path').setAttribute('fill', this.color);
                this.element.querySelector('.revue-like-count').innerText = this.count > 99 ? '99+' : this.count < 1 ? '' : this.count;
                this.element.querySelector('.revue-like-count').setAttribute('data-real-count', this.count);
                if(this.count > 0){
                  this.element.querySelector('.revue-like-count').classList.remove('hidden');
                }else{
                  this.element.querySelector('.revue-like-count').classList.add('hidden');
                }
              }
            });
          }
        });
      }
      addEventListeners_ = () => {
        const icon = this.element.querySelector('.revue-like__icon');
        icon.addEventListener('click', (e) => {
          e.stopPropagation();
          const likeStatus = this.color === this.likedColor ? 0 : 1;
          this.color = this.color === this.likedColor ? this.grayColor : this.likedColor;
          this.count = likeStatus === 1 ? parseInt(this.count) + 1 : parseInt(this.count) - 1;
          icon.querySelector('svg').setAttribute('fill', this.color);
          icon.querySelector('svg').querySelector('path').setAttribute('fill', this.color);
          this.element.querySelector('.revue-like-count').innerText = this.count > 99 ? '99+' : this.count < 1 ? '' : this.count;
          this.element.querySelector('.revue-like-count').setAttribute('data-real-count', this.count);
          if(this.count > 0){
            this.element.querySelector('.revue-like-count').classList.remove('hidden');
          }else{
            this.element.querySelector('.revue-like-count').classList.add('hidden');
          }
          this.postLike(likeStatus);
          if (this.location === 'modal') {
            const clickedEvent = new CustomEvent('like-clicked', {
              detail: {
                id: this.revueId,
                like_status: likeStatus,
                count: this.count,
                location: this.location
              }
            });
            document.dispatchEvent(clickedEvent);
          }
        });
      }
      setLikeToStorage = (likeToStore) => {
        if (typeof (Storage) !== 'function') return;
        const likesInStore = sessionStorage.getItem('likes') ? JSON.parse(sessionStorage.getItem('likes')) : [];
        const reviewIndex = likesInStore.findIndex(item => item.id === likeToStore.id);
        if (reviewIndex !== -1) {
          likesInStore[reviewIndex].like_status = likeToStore.like_status;
          likesInStore[reviewIndex].count = likeToStore.count;
        } else {
          likesInStore.push(likeToStore);
        }
        sessionStorage.setItem('likes', JSON.stringify(likesInStore));
      }
      doRender_ = (data) => {
        return this.templates_
        .findAndRenderTemplate(this.element, data, null)
        .then((el) => {
          const children = this.element.querySelector('*:not(template)');
          children && SPZCore.Dom.removeElement(children);
          this.element.appendChild(el);
        });
      }
      postLike = (likeStatus) => {
        fetch('/api/comment/like', {
          method: 'POST',
          headers: {
            'Accept': 'application/json',
            'Content-Type': 'application/json'
          },
          body: JSON.stringify({
            id: this.revueId,
            status: likeStatus
          })
        }).then((res) => {
          if (res.status === 200) {
            this.setLikeToStorage({
              id: this.revueId,
              like_status: likeStatus,
              count: this.count
            });
          }
        });
      }
      triggerEvent_(name, data) {
        const event = SPZUtils.Event.create(this.win, `${ TAG }.${ name }`, data || {});
        this.action_.trigger(this.element, name, event);
      }
      isLayoutSupported(layout) {
        return layout == SPZCore.Layout.CONTAINER;
      }
    }
    SPZ.defineElement(TAG, SPZCustomRevueLike)
  ${function() {
    return `
    
      
        
        ${function() {
          if(data.imgCover) {
            if(media.videosrc) {
              let src = '';
              if (media.videosrc) {
                src = media.videosrc + '.' + media.ext;
              }
              const videoDom = `
                
              `;
              
              if(!isPC){
                 return `
                  
                    ${videoDom}
                  
                 `
              }
              return `
                
                  ${videoDom}
                
              `
            } else if(media.mp4 || media.hls) {
              const videoDom = `
                
              `;
              if(!isPC){
                 return `
                  
                    ${videoDom}
                  
                 `
              }
              return `
                
                  ${videoDom}
                
              `
            } else {
              if(!isPC){
                return `
                  
                `
              }else{
                return `
                  
                `
              }
            }
          } else {
            if (media.videosrc) {
              let src = '';
              if (media.videosrc) {
                src = media.videosrc + '.' + media.ext;
              }
              return `
                
                `
            } else if(media.mp4 || media.hls) {
              return `
                
              `
            } else {
              return `
              
              `
            }
          }
        }()}
        
 
     
    `;
  }()}
    const TAG = 'spz-custom-revue-media';
    class SPZCustomRevueMedia extends SPZ.BaseElement {
      constructor(element) {
        super(element);
      }
      static deferredMount() {
        return false;
      }
      buildCallback = () => {
        this.action_ = SPZServices.actionServiceForDoc(this.element);
        this.templates_ = SPZServices.templatesForDoc(this.element);
        this.xhr_ = SPZServices.xhrFor(this.win);
        this.imgCover = this.element.getAttribute('img-cover') ?? false;
        this.pc_layout = this.element.getAttribute('pc-layout') ?? '';
        // data-images 格式为 xxxx.png?width=1&height=1,xxxx.png?width=1&height=1
        const images = this.element.getAttribute('data-images').split(',') || [];
        const parsedImages = images.map(image => {
          return this.mediaParse_(image);
        });
        this.images = parsedImages;
        this.isPC = window.innerWidth > 960;
      }
      mountCallback = () => {
        this.doRender_({
          images: this.images,
          isPC: this.isPC,
          imgCover: this.imgCover,
          pc_layout: this.pc_layout
        }).then(() => {
          this.addEventListeners_();
        });
      }
      addEventListeners_ = () => {
        const images = this.element.querySelectorAll('.revue-image-item');
        images.forEach((image, index) => {
          image.addEventListener('click', () => {
            const carousel = document.querySelector('#revue-image-carousel-render');
            carousel && SPZ.whenApiDefined(carousel).then((api) => {
              
              const width = this.isPC ? 460 : window.innerWidth * 0.9;
              const height = this.isPC ? 630 : 500;
              api.render({ images: this.images, index: index, width: width, height: height });
            });
          });
        });
      }
      doRender_ = (data) => {
        return this.templates_
        .findAndRenderTemplate(this.element, data, null)
        .then((el) => {
          const children = this.element.querySelector('*:not(template)');
          children && SPZCore.Dom.removeElement(children);
          this.element.appendChild(el);
        });
      }
      mediaParse_ = function (url) {
        var result = {};
        try {
          url.replace(/[?&]+([^=&]+)=([^&]*)/gi, function (str, key, value) {
            try {
              result[key] = decodeURIComponent(value);
            } catch (e) {
              result[key] = value;
            }
          });
          result.preview_image = url.split('?')[0];
        } catch (e) {};
        return result;
      }
      triggerEvent_(name, data) {
        const event = SPZUtils.Event.create(this.win, `${ TAG }.${ name }`, data || {});
        this.action_.trigger(this.element, name, event);
      }
      isLayoutSupported(layout) {
        return layout == SPZCore.Layout.CONTAINER;
      }
    }
    SPZ.defineElement(TAG, SPZCustomRevueMedia)
 
  ${function() {
    return `
    
    `
  }()}
  ${function() {
    return `
    
      
        
        
          Most liked
        
        
          Highest ratings
        
        
          Lowest ratings
        
       
    
    `
  }()}
  ${function() {
    return `
      
        
          
          
            Most liked
          
          
            Highest ratings
          
          
            Lowest ratings
          
         
      
    `
  }()}
    const TAG = 'spz-custom-revue-sort';
    class SPZCustomRevueSort extends SPZ.BaseElement {
      constructor(element) {
        super(element);
      }
      static deferredMount() {
        return false;
      }
      triggerEvent_(name, data) {
        const event = SPZUtils.Event.create(this.win, `${ TAG }.${ name }`, data || {});
        this.action_.trigger(this.element, name, event);
      }
      isLayoutSupported(layout) {
        return layout == SPZCore.Layout.CONTAINER;
      }
      buildCallback = () => {
        this.action_ = SPZServices.actionServiceForDoc(this.element);
        this.templates_ = SPZServices.templatesForDoc(this.element);
        this.xhr_ = SPZServices.xhrFor(this.win);
        this.isPC = window.innerWidth > 960;
        this.width = this.isPC ? `${this.element.getAttribute('width') || 150}px` : '100%';
        this.randomStr = Math.random().toString(36).substr(2);
        this.sectionId =  this.element.getAttribute('section-id') || '1539149753700';
        this.prefix = this.element.getAttribute('prefix');
      }
      mountCallback = () => {
        const data = {
          width: this.width,
          randomStr: this.randomStr
        };
        this.doRender_(data).then(() => {
          let revueSortListRender = this.isPC ? this.element.querySelector(`#${this.prefix}-revue-sort-list-render-${this.sectionId}`) : this.element.querySelector(`#${this.prefix}-revue-sort-dropdown-render-${this.sectionId}`);
          revueSortListRender && SPZ.whenApiDefined(revueSortListRender).then((api) => {
            api.render(data).then(() => {
              if (this.isPC) {
                this.addEventListenersForPC_();
              } else {
                this.addEventListenersForMobile_();
              }
            });
          });
        });
      }
      doRender_ = (data) => {
        return this.templates_
        .findAndRenderTemplate(this.element, data, null)
        .then((el) => {
          const children = this.element.querySelector('*:not(template)');
          children && SPZCore.Dom.removeElement(children);
          this.element.appendChild(el);
        });
      }
      addEventListenersForPC_ = () => {
        const revueSelectList = this.element.querySelector('.revue_select_list');
        const revueSelectItem = this.element.querySelectorAll('.revue_select_item');
        const revueSelectSortIcon = this.element.querySelector(`#${this.prefix}-revue_select_sort_icon-${this.sectionId}`);
        
        revueSelectItem.forEach(item => {
          item.addEventListener('click', () => {
            const sort = item.getAttribute('data-sort');
            const direction = item.getAttribute('data-direction');
            
            
            this.triggerEvent_('sort', { sort, direction });
            this.element.querySelector('.revue_select_label').innerText = item.innerText;
            revueSelectList.classList.remove('revue_select_list_active');
            
            const revueChecked = this.element.querySelector(`#${this.prefix}-revue_checked`);
            revueChecked && SPZCore.Dom.removeElement(revueChecked);
            const revueCheckedClone = revueChecked.cloneNode(true);
            item.appendChild(revueCheckedClone);
            const pcDropdownEle = document.querySelector(`#${this.prefix}-revue-sort-pc-dropdown-${this.sectionId}`);
            if (!revueSelectSortIcon.classList.contains('up_icon')) {
              return;
            }
            revueSelectSortIcon.classList.remove('up_icon');
            SPZ.whenApiDefined(pcDropdownEle).then((api) => {
              api.close();
            });
          });
        });
       
        window.addEventListener('scroll', (e) => {
          if (!revueSelectSortIcon || !revueSelectSortIcon.classList.contains('up_icon')) {
            return;
          }
          revueSelectSortIcon.classList.remove('up_icon');
          SPZ.whenApiDefined(pcDropdownEle).then((api) => {
            api.close();
          });
        });
      }
      addEventListenersForMobile_ = () => {
        const revueSortDropdownRender = document.querySelector(`#${this.prefix}-revue-sort-dropdown-render-${this.sectionId}`);
        revueSortDropdownRender && SPZ.whenApiDefined(revueSortDropdownRender).then(async (api) => {
          await api.render();
          const revueSortDropdownItem = document.querySelectorAll(`#${this.prefix}-revue-sort-dropdown-${this.sectionId} .revue_sort_dropdown_item`);
          revueSortDropdownItem.forEach(item => {
            item.addEventListener('click', () => {
              const sort = item.getAttribute('data-sort');
              const direction = item.getAttribute('data-direction');
              revueSortDropdownItem.forEach((_item)=>{_item.classList.remove('selected')})
              item.classList.add('selected');
              // 抛出事件
              this.triggerEvent_('sort', { sort, direction });
              // 移除revue_checked元素,复制一个新的到当前选中的元素 
              const revueChecked = document.querySelector(`#${this.prefix}-revue-sort-dropdown-${this.sectionId} #${this.prefix}-revue_checked`);
              revueChecked && SPZCore.Dom.removeElement(revueChecked);
              const revueCheckedClone = revueChecked.cloneNode(true);
              item.appendChild(revueCheckedClone);
              
              const mDropdownEle = document.querySelector(`#${this.prefix}-revue-sort-dropdown-${this.sectionId}`);
              SPZ.whenApiDefined(mDropdownEle).then((api) => {
                api.close();
              }); 
            });
          });
        })
      }
    }
    SPZ.defineElement(TAG, SPZCustomRevueSort)
  ${function() {
    return `
    
    `
  }()}
  ${function() {
    const list = data.listData;
    return `
      
        
          
          
          With Photos(${list.image_count})
          
         
      
    `
  }()}
  ${function() {
    const list = data.listData;
    return `
      
        
          
          
            With Photos(${list.image_count})
          
         
      
    `
  }()}
    const TAG = 'spz-custom-revue-type';
    class SPZCustomRevueType extends SPZ.BaseElement {
      constructor(element) {
        super(element);
      }
      static deferredMount() {
        return false;
      }
      triggerEvent_(name, data) {
        const event = SPZUtils.Event.create(this.win, `${ TAG }.${ name }`, data || {});
        this.action_.trigger(this.element, name, event);
      }
      isLayoutSupported(layout) {
        return layout == SPZCore.Layout.CONTAINER;
      }
      buildCallback = () => {
        this.action_ = SPZServices.actionServiceForDoc(this.element);
        this.templates_ = SPZServices.templatesForDoc(this.element);
        this.xhr_ = SPZServices.xhrFor(this.win);
        this.isPC = window.innerWidth > 960;
        this.width = this.isPC ? `${this.element.getAttribute('width') || 150}px` : '100%';
        this.randomStr = Math.random().toString(36).substr(2);
        this.sectionId =  this.element.getAttribute('section-id') || '1539149753700';
        this.prefix = this.element.getAttribute('prefix');
      }
      mountCallback = () => {
      }
      render = (data) => {
        const renderData = {
          ...data,
          width: this.width,
          randomStr: this.randomStr
        };
        return this.templates_
        .findAndRenderTemplate(this.element, renderData, null)
        .then((el) => {
          const children = this.element.querySelector('*:not(template)');
          children && SPZCore.Dom.removeElement(children);
          this.element.appendChild(el);
        }).then(() => {
          let revueTypeListRender = this.isPC ? this.element.querySelector(`#${this.prefix}-revue-type-list-render-${this.sectionId}`) : this.element.querySelector(`#${this.prefix}-revue-type-dropdown-render-${this.sectionId}`);
          revueTypeListRender && SPZ.whenApiDefined(revueTypeListRender).then((api) => {
            api.render(renderData).then(() => {
              if (this.isPC) {
                this.addEventListenersForPC_();
              } else {
                this.addEventListenersForMobile_();
              }
            });
          });
        });
      }
      addEventListenersForPC_ = () => {
        const revueSelectList = this.element.querySelector('.revue_select_list');
        const revueSelectItem = this.element.querySelectorAll('.revue_select_item');
        const revueSelectTypeIcon = this.element.querySelector(`#${this.prefix}-revue_select_type_icon-${this.sectionId}`);
       
        revueSelectItem.forEach(item => {
          item.addEventListener('click', () => {
            const type = item.getAttribute('data-type');
            const direction = item.getAttribute('data-direction');
            
            this.triggerEvent_('type', { type, direction });
            this.element.querySelector('.revue_select_label').innerText = item.innerText;
            revueSelectList.classList.remove('revue_select_list_active');
            
            const revueChecked = this.element.querySelector(`#${this.prefix}-revue_checked`);
            revueChecked && SPZCore.Dom.removeElement(revueChecked);
            const revueCheckedClone = revueChecked.cloneNode(true);
            item.appendChild(revueCheckedClone);
            if (!revueSelectTypeIcon.classList.contains('up_icon')) {
              return;
            }
            const pcDropdownEle = this.element.querySelector(`#${this.prefix}-revue-type-pc-dropdown-${this.sectionId}`);
            revueSelectTypeIcon.classList.remove('up_icon');
            SPZ.whenApiDefined(pcDropdownEle).then((api) => {
              api.close();
            });
          });
        });
      
        window.addEventListener('scroll', (e) => {
          if (!revueSelectTypeIcon.classList.contains('up_icon')) {
            return;
          }
          revueSelectTypeIcon.classList.remove('up_icon');
          SPZ.whenApiDefined(pcDropdownEle).then((api) => {
            api.close();
          });
        });
      }
      addEventListenersForMobile_ = () => {
        const revueTypeDropdownItem = this.element.querySelectorAll(`#${this.prefix}-revue-type-dropdown-${this.sectionId} .revue_type_dropdown_item`);
        revueTypeDropdownItem.forEach(item => {
          item.addEventListener('click', () => {
            const type = item.getAttribute('data-type');
            const direction = item.getAttribute('data-direction');
            revueTypeDropdownItem.forEach((_item)=>{_item.classList.remove('selected')})
            item.classList.add('selected');
            // 抛出事件
            this.triggerEvent_('type', { type, direction });
            // 移除revue_checked元素,复制一个新的到当前选中的元素 
            const revueChecked = this.element.querySelector(`#${this.prefix}-revue-type-dropdown-${this.sectionId} #${this.prefix}-revue_checked`);
            revueChecked && SPZCore.Dom.removeElement(revueChecked);
            const revueCheckedClone = revueChecked.cloneNode(true);
            item.appendChild(revueCheckedClone);
            const mDropdownEle = this.element.querySelector(`#${this.prefix}-revue-type-dropdown-${this.sectionId}`);
            SPZ.whenApiDefined(mDropdownEle).then((api) => {
              api.close();
            });
          });
        });
      }
    }
    SPZ.defineElement(TAG, SPZCustomRevueType)
 
    const TAG = 'spz-custom-revue-pagination';
    class SPZCustomRevuePagination extends SPZ.BaseElement {
      constructor(element) {
        super(element);
      }
      static deferredMount() {
        return false;
      }
      buildCallback = () => {
        this.action_ = SPZServices.actionServiceForDoc(this.element);
        this.templates_ = SPZServices.templatesForDoc(this.element);
        this.xhr_ = SPZServices.xhrFor(this.win);
        this.isPC = window.innerWidth > (window.breakpoint || 960);
        this.numItems = this.numItems();
        this.pageSize = this.pageSize();
      }
      mountCallback = () => {
        this.doRender_({
          numPages: this.numPages(),
          pageNum: this.currentPageNumber(),
          useCallback: true
        }).then(() => {
        });
      }
      currentPageNumber() {
        let pageNum = this.element.getAttribute('page-num');
        if (pageNum) return parseInt(pageNum);
      }
      numPages() {
        return Math.ceil(this.numItems / this.pageSize);
      }
      numItems() {
        return parseInt(this.element.getAttribute('num-items'));
      }
      pageSize() {
        return parseInt(this.element.getAttribute('page-size')) || 10;
      }
      doRender_ = (data) => {
        return this.templates_
        .findAndRenderTemplate(this.element, data, null)
        .then((el) => {
          const children = this.element.querySelector('*:not(template)');
          children && SPZCore.Dom.removeElement(children);
          this.element.appendChild(el);
        });
      }
      triggerEvent_(name, data) {
        const event = SPZUtils.Event.create(this.win, `${ TAG }.${ name }`, data || {});
        this.action_.trigger(this.element, name, event);
      }
      isLayoutSupported(layout) {
        return layout == SPZCore.Layout.CONTAINER;
      }
    }
    SPZ.defineElement(TAG, SPZCustomRevuePagination)
    const TAG = 'spz-custom-revue-product';
    
    class SpzCustomRevueProduct extends SPZ.BaseElement {
      constructor(element) {
        super(element);
      }
      static deferredMount() {
        return false;
      }
      triggerEvent_(name, data) {
        const event = SPZUtils.Event.create(this.win, `${ TAG }.${ name }`, data || {});
        this.action_.trigger(this.element, name, event);
      }
      isLayoutSupported(layout) {
        return layout == SPZCore.Layout.CONTAINER;
      }
      buildCallback = () => {
        this.section_id = this.element.getAttribute('section-id');
        this.action_ = SPZServices.actionServiceForDoc(this.element);
        this.templates_ = SPZServices.templatesForDoc(this.element);
        this.xhr_ = SPZServices.xhrFor(this.win);
        this.setupAction_();
        const url = new URL(window.location.href);
        this.isPC = window.innerWidth > (window.breakpoint || 960);
        this.nodata = false;
        this.firstRender = true;
        this.commentConfig = {};
        this.commentSummary = {};
        this.commentList = {};
        this.panelId = 'all';
        this.sort = 'created_at';
        this.direction = 'desc';
        this.pageNum = 1;
        this.pageSize = +window.reviewProductSettings[this.section_id].page_limit;
        this.pc_layout = window.reviewProductSettings[this.section_id].pc_layout;
        this.star_least = +window.reviewProductSettings[this.section_id].star_least;
        this.only_media = window.reviewProductSettings[this.section_id].only_media;
        this.product_id = window.SHOPLAZZA.meta.page.resource_id;
        this.isProductPage = '1' == 1;
        this.isCollectionPage = '1' == 2;
        this.isCartPage = '1' == 13;
        this.review_insufficient = window.reviewProductSettings[this.section_id].review_insufficient; // 评论不足类型
        this.mini_quantity = window.reviewProductSettings[this.section_id].mini_quantity; // 评论少于一定数量
        this.actions = window.reviewProductSettings[this.section_id].actions; // 评论处理方式
        this.only_media = window.reviewProductSettings[this.section_id].only_media; // 只显示有图片的评论
        this.only_featured = window.reviewProductSettings[this.section_id].only_featured ?? false; // 只显示精选评论
        this.display_product_link = window.reviewProductSettings[this.section_id].display_product_link ?? false; // 是否显示商品链接
        this.m_loading_type = window.reviewProductSettings[this.section_id].m_loading_type; // 移动端加载方式
        this.m_modal_page_limit = window.reviewProductSettings[this.section_id].m_modal_page_limit; // 移动端弹窗加载限制
        this.hide_review_section = window.reviewProductSettings[this.section_id].hide_review_section; // 无数据是否隐藏评论组件
        this.accent_color = window.reviewProductSettings[this.section_id].accent_color; // 主题色
      }
      mountCallback = () => {
        this.templates_
          .findAndRenderTemplate(this.element, { isPC: this.isPC }, null)
          .then((el) => {
            this.element.appendChild(el);
            this.renderPage();
          })
      }
      
      fetchCommentConfig_ = async () => {
        const response = await fetch('/api/comment-config');
        return response.json();
      }
      
      fetchCommentSummary_ = async(data) => {
        const response = await fetch(`/api/v1/comments/summary`, {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json',
          },
          body: JSON.stringify(data)
        });
        return response.json();
      }
      
      fetchCommentList_ = async(data) => {
        // const response = await fetch(`/api/comment/list?show_product=1&star_least=${data.star_least}&onlyimg=${data.onlyimg}&limit=${data.limit}&offset=${data.offset}&sort_by=${data.sort_by || 'created_at'}&product_id=${data.productId}&status=1&sort_direction=${data.sort_direction || 'desc'}&show_reply=${data.show_reply}`);
        const response = await fetch('/api/v1/comments', {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json',
          },
          body: JSON.stringify(data)
        });
        return response.json();
      }
      
      fetchThemeConfig_ = async(themeId) => {
        const response = await fetch(`/api/comment/theme-config?theme_id=${themeId}`);
        return response.json();
      }
      getCommentConfig = () => {
        return this.fetchCommentConfig_()
      }
      getCommentSummary = (data = {}) => {
        const fetchData = {
          star_least: this.star_least,
          product_ids: this.isProductPage ? 'bd64ad24-40c4-4b36-8a47-97bb380a6b15' :  this.isCartPage ? '' : '',
          collection_id: this.isCollectionPage ? 'c9bd444e-d7cc-4ea5-8ea5-104043965e9c' :  '',
          filter_type: this.isProductPage ? 'product' : this.isCollectionPage ? 'collection' : 'store',
          fill_min_threshold: this.review_insufficient === 'less_than' ? this.mini_quantity : undefined,
          fill_strategy: this.actions === 'all_product' ? 'store' : '',
          only_media: this.only_media ? this.only_media : this.panelId !== 'all',
          only_featured: this.only_featured,
          ...data,
        }
        return this.fetchCommentSummary_(fetchData)
      }
      getCommentList = (data = {}) => {
        const fetchData = {
          show_product: true,
          filter_type: (this.isProductPage || this.isCartPage)
           ? 'product' 
           : this.isCollectionPage ? 'collection' : 'store',
          star_least: this.star_least,
          show_reply: true,
          limit: this.pageSize,
          offset: (this.pageNum - 1) * this.pageSize,
          only_media: this.only_media ? this.only_media : this.panelId !== 'all',
          sort_by: this.sort,
          sort_direction: this.direction,
          product_ids: this.isProductPage ? 'bd64ad24-40c4-4b36-8a47-97bb380a6b15' :  this.isCartPage ? '' : '',
          collection_id: this.isCollectionPage ? 'c9bd444e-d7cc-4ea5-8ea5-104043965e9c' :  '',
          only_featured: this.only_featured,
          fill_strategy: this.actions === 'all_product' ? 'store' : '',
          fill_min_threshold: this.review_insufficient === 'less_than' ? this.mini_quantity : undefined,
          ...data,
        }
        return this.fetchCommentList_(fetchData)
      }
      getPageData = () => {
        return Promise.all([
          this.getCommentConfig(),
          this.getCommentSummary(),
          this.getCommentList()
        ])
      }
      renderPage = async () => {
        const [commentConfigRes, commentSummaryRes, commentListRes] = await this.getPageData();
        let commentConfigData = commentConfigRes.data || {};
        let commentSummaryData = commentSummaryRes.data || {};
        let commentListData = commentListRes.data || [];
        this.commentConfig = commentConfigData;
        this.commentSummary = commentSummaryData;
        this.commentList = commentListData;
        this.accent_color = this.accent_color || this.commentConfig.star_color;
        let lessThanCount = 1;
        // 评论不足逻辑
        if(this.actions === "hide") { // 不展示评论组件
          if(this.review_insufficient === 'less_than') {
            lessThanCount = this.mini_quantity; // 无评论或少于一定数量
          }
        } else if(this.actions === "all_product") {
          lessThanCount = 1;
        }
        if(commentListData.count < lessThanCount) {
          // 是否隐藏评论组件
          if(this.hide_review_section) {
            this.renderNoData();
            return null;
          } else {
            this.renderRevueEmpty();
          }
          this.nodata = true;
        }
        window.addEventListener('resize', SPZCore.Types.throttle(window, this.onResize, 300));
        this.renderPageData([this.commentConfig, this.commentSummary, this.commentList]);
      }
      onResize = () => {
          if(this.nodata) {
            return;
          }
          // 判断是否需要重新渲染
          if((this.isPC && window.innerWidth > (window.breakpoint || 960)) || (!this.isPC && window.innerWidth < (window.breakpoint || 960))) {
            return;
          }
          this.isPC = window.innerWidth > (window.breakpoint || 960);
          this.panelId = 'all';
          this.sort = 'created_at';
          this.direction = 'desc';
          this.pageNum = 1;
          
          this.templates_
            .findAndRenderTemplate(this.element, { isPC: this.isPC }, null)
            .then((el) => {
              const children = this.element.querySelector('*:not(template)');
              children && SPZCore.Dom.removeElement(children);
              this.element.appendChild(el);
              this.renderPageData([this.commentConfig, this.commentSummary, this.commentList]);
            })
        }
      renderPageData = (data) => {
        const [commentConfigData, commentSummaryData, commentListData] = data;
        // 渲染头部
        this.renderHeader_({
          starData: commentSummaryData,
          listData: commentListData,
          comment_avg_star: commentSummaryData.comment_avg_star,
          comment_count: commentSummaryData.comment_count,
        });
        // 有评论逻辑
        this.renderStarCounts(commentSummaryData);
        
        if(this.isPC && this.pc_layout === 'single_column') {
          this.renderCommentTab({ 
            listData: commentListData, 
            isPC: this.isPC,
          }, `revue-tab-${this.section_id}`);
        } else {
          this.renderList_({ 
            listData: commentListData, 
            config: this.commentConfig,
            shop_name: window.SHOPLAZZA.shop.shop_name,
            isPC: this.isPC,
            star_color: this.accent_color,
          });
        }
      }
      renderNoData = () => {
        const sectionEle = document.querySelector(`#revue-product-compo`);
        if (sectionEle) {
          sectionEle.setAttribute('hidden', 'true');
        }
        if(window.top === window.self) { // c端不渲染 
          return;
        }
        // b端渲染
        const noDataPlaceholder = document.querySelector(`#revue_no_data_placeholder_${this.section_id}`);
        if(noDataPlaceholder) {
          SPZ.whenApiDefined(noDataPlaceholder).then(async (api) => {
            await api.render();
          });
        }
      }
      renderRevueEmpty = (section) => {
        const emptyEle = document.querySelector(`#revue_empty-${this.section_id}`);
        const writeReviewBtn = document.querySelector(`#revue_write_review_btn_single`);
        if (emptyEle) {
          emptyEle.classList.remove('hidden');
        }
        if (writeReviewBtn) {
          writeReviewBtn.classList.remove('hidden');
        }
        const skeletonEle = document.querySelector('#revue_skeleton');
        if (skeletonEle) {
          skeletonEle.classList.add('hidden');
        }
      }
      renderHeader_ = (data) => {
        const headerEle = document.querySelector(`#app-review-revue-header-${this.section_id}`);
        if (headerEle) {
          SPZ.whenApiDefined(headerEle).then(async (api) => {
            api.render({
              ...data,
              star_color: this.accent_color,
              isPC: this.isPC,
            });
          });
        }
      }
      
      renderStarCounts = (data, eleId = `revue-summary-${this.section_id}`) => {
        const ndata = {
          ...this.commentSummary,
          star_color: this.accent_color,
          isPC: this.isPC,
          ...data,
        }
        const summaryEle = document.querySelector(`#${eleId}`);
        if (summaryEle) {
          SPZ.whenApiDefined(summaryEle).then((api) => {
            api.render({
              ...ndata,
            });
          });
        }
      }
      
      renderCommentTab = (data, eleId) => {
        const elementId = eleId || `revue-tab-${this.section_id}`;
        const ndata = { listData: this.commentList, isPC: this.isPC, ...data }
        const tabEle = document.querySelector(`#${elementId}`);
        let listId;
        if (tabEle) {
          SPZ.whenApiDefined(tabEle).then(async (api) => {
            await api.render({
              ...ndata,
              // suffix: "list",
            });
            if(eleId) {
              listId = `revue-comment-list-${this.section_id}_tab`;
            }
            this.renderList_({
              ...ndata,
              // suffix: "list",
            }, listId);
          });
        }
      }
      
      renderList_ = (data, eleId) => {
        const listEle = document.querySelector(`#revue-comment-list`);
        if (listEle && !eleId) {
          SPZ.whenApiDefined(listEle).then(async (api) => {
            await api.render({
              ...data,
              // suffix: "list",
              pageSize: this.pageSize,
              hasmore: data.listData.has_more,
            })
            
            let nlist = data.listData.list.map(item => {
              return {
                ...item,
                config: this.commentConfig,
                star_color: this.accent_color,
                shop_name: window.SHOPLAZZA.shop.shop_name,
                current_panel: this.panelId,
                pageNum: this.pageNum,
                suffix: data.suffix,
                show_link: this.display_product_link,
              }
            })
            let hasmore = data.listData.has_more;
            if(!this.isPC && this.m_loading_type === 'modal') {
              nlist = nlist.slice(0, this.m_modal_page_limit);
              hasmore = true;
            }
            api.renderList({
              ...data,
              list: nlist,
              count: this.panelId === 'all' ? data.listData.count : data.listData.image_count,
              // suffix: "list",
              hasmore: hasmore,
              pageSize: this.pageSize
            })
          })
          return;
        }
        const viewallListEle = document.querySelector(`#${eleId}`);
        if (viewallListEle) {
          SPZ.whenApiDefined(viewallListEle).then(async (api) => {
            await api.render({
              ...data,
              pageSize: this.pageSize,
              hasmore: data.listData.has_more,
            });
            let nlist = data.listData.list.map(item => {
              return {
                ...item,
                config: this.commentConfig,
                star_color: this.accent_color,
                shop_name: window.SHOPLAZZA.shop.shop_name,
                current_panel: this.panelId,
                pageNum: this.pageNum,
                suffix: data.suffix,
                show_link: this.display_product_link,
              }
            })
            api.renderList({
              ...data,
              list: nlist,
              count: this.panelId === 'all' ? data.listData.count : data.listData.image_count,
              hasmore: data.listData.has_more,
              pageSize: this.pageSize,
            })
          });
        }
      }
      renderCommentList = (data, eleId = 'revue-comment-list', renderType = 'list', redo = false) => {
        const listEle = document.querySelector(`#${eleId}`);
        if (listEle) {
          SPZ.whenApiDefined(listEle).then((api) => {
            let nlist = data.listData.list.map(item => {
              return {
                ...item,
                config: this.commentConfig,
                star_color: this.accent_color,
                shop_name: window.SHOPLAZZA.shop.shop_name,  
                current_panel: this.panelId,
                pageNum: this.pageNum,
                hasmore: data.listData.has_more,
                show_link: this.display_product_link,
                // suffix: data.suffix,
              }
            })
            if(!this.isPC && this.m_loading_type === 'modal' && renderType === 'list') {
              nlist = nlist.slice(0, this.m_modal_page_limit);
            }
            api.renderList({
              count: this.panelId === 'all' ? data.listData.count : data.listData.image_count,
              list: nlist,
              // suffix: "list",
              hasmore: data.listData.has_more,
              pageSize: this.pageSize
           }, redo);
          });
          return;
        }
      }
      renderByScrollPagination = async (eleId, renderType) => {
        this.pageNum = this.pageNum + 1;
        const params = {}
        const res = await this.getCommentList(params);
        this.renderCommentList({ 
          listData: res.data, 
        }, eleId, renderType, false);
      }
      setupAction_ = () => {
        this.registerAction('renderTabChangeList', async (invocation) => {
          // 兼容 ljs-tab 首次加载会触发 tabchange 事件
          if(this.firstRender) {
            this.firstRender = false;
            return;
          }
          const panelId = invocation.args.data.panelId;
          const { eleId, renderType } = invocation.args;
          this.panelId = panelId;
          this.pageNum = 1;
          this.modalHasMore = true;
          const params = {
            // only_media: panelId !== 'all',
          } 
          const res = await this.getCommentList(params);
          this.renderCommentList({ 
            listData: res.data, 
          }, eleId, renderType, true);
        });
        this.registerAction('renderTypeChangeList', async (invocation) => {
          const { type } = invocation.args.data;
          const { eleId, renderType } = invocation.args;
          this.panelId = type;
          this.pageNum = 1;
          this.modalHasMore = true;
          const params = {
            // only_media: type !== 'all',
          }
          const res = await this.getCommentList(params);
          this.renderCommentList({ 
            listData: res.data, 
          }, eleId, renderType, true);
        });
        this.registerAction('renderSortedList', async(invocation) => {
          const { sort, direction } = invocation.args.data;
          const eleId = invocation.args.eleId;
          const renderType = invocation.args.renderType;
          this.sort = sort;
          this.direction = direction;
          this.pageNum = 1;
          this.modalHasMore = true;
          const params = {
            sort_by: sort,
            sort_direction: direction,
          }
          const res = await this.getCommentList(params);
          this.renderCommentList({ 
            listData: res.data, 
          }, eleId, renderType, true);
        });
        this.registerAction('renderByPagination', async(invocation) => {
          const { pageNum, eleId, renderType } = invocation.args;
          this.pageNum = pageNum;
          const params = {}
          const res = await this.getCommentList(params);
          this.renderCommentList({ 
            listData: res.data, 
          }, `revue-comment-list-${this.section_id}_tab`, 'tab', true);
          
          const tabsEle = document.querySelector('#revue-product-compo');
          if (tabsEle) {
            tabsEle.scrollIntoView({ behavior: 'smooth' });
          }
        });
        this.registerAction('renderByViewMore', async(invocation) => {
          const { eleId, renderType } = invocation.args;
          this.pageNum = this.pageNum + 1;
          const params = {}
          const res = await this.getCommentList(params);
          this.renderCommentList({ 
            listData: res.data, 
          }, eleId, renderType, false);
        });
        this.registerAction('refresh', async(invocation) => {
          this.panelId = 'all';
          this.sort = 'created_at';
          this.direction = 'desc';
          this.pageNum = 1;
          this.templates_
            .findAndRenderTemplate(this.element, { isPC: this.isPC }, null)
            .then((el) => {
              const children = this.element.querySelector('*:not(template)');
              children && SPZCore.Dom.removeElement(children);
              this.element.appendChild(el);
              this.renderPage();
            });
          const productEle = document.querySelector(`#revue-viewall-modal-comp`);
          if (productEle) {
            SPZ.whenApiDefined(productEle).then(async (api) => {
              api.refresh();
            });
          }
        });
      }
    }
    SPZ.defineElement(TAG, SpzCustomRevueProduct)
    
  
  (function() {
    const TAG = 'spz-custom-new-revue';
    class SpzCustomNewRevue extends SPZ.BaseElement {
      constructor(element) {
        super(element);
        this.config_ = null;
        this.loading_ = false;
        this.accent_color = this.element.getAttribute('accent-color');
        this.sectionId = this.element.getAttribute('section-id');
        this.prefix = this.element.getAttribute('prefix');
      }
      buildCallback() {
        this.action_ = SPZServices.actionServiceForDoc(this.element);
        this.xhr_ = SPZServices.xhrFor(this.win);
        this.form_ = SPZCore.Dom.scopedQuerySelector(
          this.element,
          'form'
        );
        this.hasShowLengthInputs_ = SPZCore.Dom.scopedQuerySelectorAll(
          this.form_,
          '[showlength]'
        );
        [...this.hasShowLengthInputs_].forEach(item => {
          const countRecordDom = SPZCore.Dom.scopedQuerySelector(
            this.form_,
            `#${item.id} ~ div[type="count-record"]`
          );
          if (!countRecordDom) {
            console.error(`Cannot find count record DOM element for input ${item.id}`);
            return;
          }
          item.addEventListener('input', (e) => {
            countRecordDom.innerText = `${e.target.value.length}/3000`;
          });
        });
        this.setupAction_();
        this.getRevueConfigData_();
      }
      setupAction_() {
        this.registerAction('submitForm', async(invocation) => {
          if (this.loading_) {
            return;
          }
          this.loading_ = true;
          const formData = Object.entries(invocation.args.data).reduce((acc, [key, value]) => {
            if (key === 'star' || key === 'type') {
              acc[key] = Number(value[0]);
            } else {
              acc[key] = value[0];
            }
            return acc;
          }, {});
          try {
            const data = await fetch('/api/comment', {
              method: "post",
              headers: {
                "Content-Type": "application/json"
              },
              body: JSON.stringify(formData)
            }).then(res => res.json());
            if (data.state === 0) {
              this.triggerEvent_('submitSuccess', {
                panelId: 'with_photo',
                message: ''
              });
              return;
            }
            throw new Error(data.msg);
          } catch(e) {
            e = await e;
            this.triggerEvent_('submitError', {data: e.message});
          } finally {
            this.loading_ = false;
          }
        });
        this.registerAction('renderFormStar', async(invocation) => {
          this.triggerEvent_('rerenderFormStar', { star_color: this.starColor_ });
        })
      }
      mountCallback() {
      }
      getRevueConfigData_ = () => {
        fetch('/api/comment-config')
          .then(res => res.json())
          .then(data => {
            this.config_ = data.data;
            // anonymous_permission 是否支持匿名
            if (!this.config_.anonymous_permission) {
              const anonymousInput = this.form_.querySelector(`#${this.prefix}-revue-anonymous-${this.sectionId}`);
              anonymousInput.value = 'false';
              anonymousInput.parentNode.classList.add('hidden', 'anonymous-permission-hidden');
            }
            this.starColor_ = this.config_.star_color;
            if(this.accent_color && this.accent_color != 'null'){
              this.starColor_ = this.accent_color;
            }
            // render star
            // star_color 星星颜色
            const starEl = this.form_.querySelector(`#${this.prefix}-revue_write_modal_star-${this.sectionId}`);
            if (starEl) {
              SPZ.whenApiDefined(starEl).then((api) => {
                api.render({ star_color: this.starColor_ });
              });
            }
          });
      }
      triggerEvent_(name, data) {
        const event = SPZUtils.Event.create(this.win, `${ TAG }.${ name }`, data || {});
        this.action_.trigger(this.element, name, event);
      }
      isLayoutSupported = (layout) => {
        return layout == SPZCore.Layout.CONTAINER;
      }
    }
    SPZ.defineElement(TAG, SpzCustomNewRevue);
  })()
  (function() {
    const TAG = 'spz-custom-revue-product-info-script';
    class SpzCustomRevueProductInfoScript extends SPZ.BaseElement {
      constructor(element) {
        super(element);
        /** @private {!Element} */
        this.product_id = null;
      }
      async buildCallback() {
        this.action_ = SPZServices.actionServiceForDoc(this.element);
        this.product_id = this.getProductId_();
        this.triggerEvent_('init', { product_id: this.product_id });
        try {
          const data = await this.getProductInfo_();
          if (data?.data?.product) {
            this.triggerEvent_('finish', data.data.product);
          }
        } catch (error) {
          console.error('Failed to fetch product info:', error);
          // Handle the error appropriately
        }
      }
      getProductId_ = () => {
        return window.SHOPLAZZA.meta.page.resource_id;
      }
      async getProductInfo_() {
        if (!this.product_id) {
          console.error('Product ID is undefined or null');
          return null;
        }
        try {
          const response = await fetch(`/api/products/${this.product_id}`);
          if (!response.ok) {
            throw new Error(`HTTP error! status: ${response.status}`);
          }
          return await response.json();
        } catch (error) {
          console.error('Error fetching product info:', error);
          throw error; // Rethrow to be caught by the caller
        }
      }
      triggerEvent_(name, data) {
        const event = SPZUtils.Event.create(this.win, `${ TAG }.${ name }`, data || {});
        this.action_.trigger(this.element, name, event);
      }
      isLayoutSupported = (layout) => {
        return layout == SPZCore.Layout.LOGIC;
      }
    }
    SPZ.defineElement(TAG, SpzCustomRevueProductInfoScript);
  })()
  ${function(){
    
    return `
      
        
          ${data.starNum}/${data.starTotal}
        
       
    `;
  }()}
  ${function(){
    return `
      
        
        ${data.showStarText === 'true' ? `
          
            
              
                ${data.starNum}/${data.starTotal}
              
             
          
        ` : ''}
      
 
    `;
  }()}
    const TAG = 'spz-custom-revue-star';
    class SPZCustomRevueStar extends SPZ.BaseElement {
      constructor(element) {
        super(element);
      }
      static deferredMount() {
        return false;
      }
      buildCallback = () => {
        this.action_ = SPZServices.actionServiceForDoc(this.element);
        this.templates_ = SPZServices.templatesForDoc(this.element);
        this.xhr_ = SPZServices.xhrFor(this.win);
        this.starNum = this.element.getAttribute('starNum');
        this.starTotal = this.element.getAttribute('starTotal');
        this.showStarText = this.element.getAttribute('showStarText');
        this.starColor = this.element.getAttribute('color');
        this.interact = this.element.getAttribute('interact');
        this.starSize = this.element.getAttribute('starSize') || 14;
      }
      mountCallback = () => {
        this.doRender_({
          starTotal: this.starTotal,
          totalArray: Array.from({ length: Number(this.starTotal) }, (v, k) => k + 1),
          starNum: this.starNum,
          showStarText: this.showStarText,
          starColor: this.starColor,
          starSize: this.starSize
        }).then(() => {
          if (this.interact) {
            this.addEventListeners_();
          }
        });
      }
      addEventListeners_ = () => {
        
        const stars = document.querySelectorAll('.revue-star__star');
        
        stars.forEach(star => {
          star.addEventListener('click', event => {
            const starEl = star.closest('.revue-star__star');
            const starIndex = Number(starEl.dataset.index);
            let isHalf = event.offsetX < star.offsetWidth / 2;
            // rtl
            if (document.documentElement.getAttribute('dir') === 'rtl') {
              isHalf = event.offsetX > star.offsetWidth / 2;
            }
            const starValue = isHalf ? starIndex - 0.5 : starIndex;
            this.starClickHandler_({ value: starValue });
          });
        });
      }
      renderStar = () => {
        
        const isRtl = document.documentElement.getAttribute('dir') === 'rtl';
        const stars = this.element.querySelectorAll('.revue-star__star');
        stars.forEach((star, i) => {
          const starIndex = i + 1;
          const starEl = star.querySelector('svg:nth-child(2)');
          const isHalf = this.starNum % 1 > 0 && Math.ceil(this.starNum) === starIndex;
          const isSolid = starIndex <= Math.ceil(this.starNum);
          starEl.style.display = isSolid ? 'block' : 'none';
          if (isHalf) {
            if (isRtl) {
              // RTL布局下,如果是半星,显示星星的右半边
              starEl.style.clipPath = `polygon(50% 0, 100% 0, 100% 100%, 50% 100%)`;
            } else {
              // LTR布局下,如果是半星,显示星星的左半边
              starEl.style.clipPath = `polygon(0 0, 50% 0, 50% 100%, 0 100%)`;
            }
          } else {
            starEl.style.clipPath = `polygon(0 0, 100% 0, 100% 100%, 0 100%)`
          }
        });
        const showCountEle = this.element.querySelector('#revue-star-show-count');
        showCountEle && SPZ.whenApiDefined(showCountEle).then((api) => {
          api.render({ starNum: this.starNum, starTotal: this.starTotal });
        });
      }
      doRender_ = (data) => {
        return this.templates_
        .findAndRenderTemplate(this.element, { starSize: this.starSize, ...data }, null)
        .then((el) => {
          const children = this.element.querySelector('*:not(template)');
          children && SPZCore.Dom.removeElement(children);
          this.element.appendChild(el);
        })
        .then(() => {
          this.starNum = data.starNum;
          this.renderStar();
        });
      }
      starClickHandler_ = (event) => {
        this.starNum = event.value;
        this.renderStar();
        this.triggerEvent_('change', { value: event.value });
      }
      triggerEvent_(name, data) {
        const event = SPZUtils.Event.create(this.win, `${ TAG }.${ name }`, data || {});
        this.action_.trigger(this.element, name, event);
      }
      isLayoutSupported(layout) {
        return layout == SPZCore.Layout.CONTAINER;
      }
    }
    SPZ.defineElement(TAG, SPZCustomRevueStar)
  (function() {
    const TAG = 'spz-custom-new-revue-files-show';
    class SpzCustomNewRevueFilesShow extends SPZ.BaseElement {
      constructor(element) {
        super(element);
        /** @private {!Element} */
        this.files_ = []
      }
      buildCallback() {
        this.action_ = SPZServices.actionServiceForDoc(this.element);
        this.templates_ = SPZServices.templatesForDoc(this.element);
        this.setupAction_();
        this.element.setAttribute('nums', this.files_.length);
      }
      mountCallback() {
 
      }
      
      setupAction_() {
        this.registerAction('upload', async(invocation) => {
          const uploadFileList = invocation.args?.data || [];
          uploadFileList.forEach(file => {
            if(this.files_.some(item => item.url === file.url)) return
            this.files_.push(file);
          })
          this.doRender_();
        });
        this.registerAction('delete', async(invocation) => {
          this.files_ = this.files_.filter((_, index) => index !== invocation.args.index);
          this.doRender_();
          this.triggerEvent_('delete', { count: this.files_.length, files: this.files_  });
        });
        this.registerAction('preview', async(invocation) => {
          let previewFileData = this.files_[invocation.args.index];
          if (previewFileData.type === 'video') {
            previewFileData = {...this.parseVideoSrc_(previewFileData.url), ...previewFileData};
          }
          this.triggerEvent_('preview', previewFileData);
        });
        this.registerAction('clear', async(invocation) => {
          this.files_ = [];
          this.doRender_();
        });
      
      }
      triggerEvent_(name, data) {
        const event = SPZUtils.Event.create(this.win, `${ TAG }.${ name }`, data || {});
        this.action_.trigger(this.element, name, event);
      }
      parseVideoSrc_(src) {
        const url = new URL(src);
        const params = new URLSearchParams(url.search);
        return {
          videoUrl: url.origin + url.pathname,
          mediaType: params.get('media_type'),
          vID: params.get('vID'),
          mp4: params.get('mp4'),
          hls: params.get('hls')
        };
      }
      doRender_ = () => {
        this.triggerEvent_('setInputValue', {
          data: this.files_
            .map(file => {
              const url = file.type === 'video' ? file.poster : file.url;
              return `${url}?width=${file.width}&height=${file.height}`;
            })
            .join(',')
        });
        this.element.setAttribute('nums', this.files_.length);
        return this.templates_
        .findAndRenderTemplate(this.element, {
          files: this.files_
        })
        .then((el) => {
          const children = this.element.querySelector('*:not(template)');
          children && SPZCore.Dom.removeElement(children);
          this.element.appendChild(el);
        })
      }
      
      isLayoutSupported = (layout) => {
        return layout == SPZCore.Layout.CONTAINER;
      }
    }
    SPZ.defineElement(TAG, SpzCustomNewRevueFilesShow);
  })()
  
    
      
        
        
          
            
            
            
            
              
                
              
            
            
  
    
  
  
    
      ${function() {
          if (!data) {
            return '';
          }
          const {url, type, height, width, poster, mp4} = data;
          if (type === 'image') {
            return `
              
            `
          }
          if (type === 'video') {
            return `
                
            ` 
          }
          return ``
        }()}
    
  
 
           
        
       
    
  
  
  const TAG = 'spz-custom-revue-header';
  class SPZCustomRevueHeader extends SPZ.BaseElement {
    constructor(element) {
      super(element);
      this.showCount = this.element.getAttribute('show-count');
    }
    static deferredMount() {
      return false;
    }
    
    isLayoutSupported(layout) {
      return layout == SPZCore.Layout.CONTAINER;
    }
    buildCallback() {
      this.action_ = SPZServices.actionServiceForDoc(this.element);
      this.templates_ = SPZServices.templatesForDoc(this.element);
      this.xhr_ = SPZServices.xhrFor(this.win);
      this.showCount = this.element.getAttribute('show-count');
      this.showSummary = this.element.getAttribute('show-summary');
      this.showWriteReview = this.element.getAttribute('show-write-review');
      this.showType = this.element.getAttribute('show-type') ;
      this.showSort = this.element.getAttribute('show-sort') ;
      this.sectionId = this.element.getAttribute('section-id');
      this.viewall = this.element.getAttribute('viewall') ?? false;
      this.prefix = this.element.getAttribute('prefix');
    }
    mountCallback() {
      
    }
    triggerEvent_(name, data) {
      const event = SPZUtils.Event.create(this.win, `${ TAG }.${ name }`, data || {});
      this.action_.trigger(this.element, name, event);
    }
    render(data) {
      const ndata = {
        ...data,
        showCount: this.showCount,
        showSummary: this.showSummary,
        showWriteReview: this.showWriteReview,
        showType: this.showType,
        showSort: this.showSort,
      }
      if(this.viewall == 'review'){
        ndata.viewall = false
      }
      return this.templates_
        .findAndRenderTemplate(this.element, ndata, null, true)
        .then(({el}) => {
          const children = this.element.querySelector('*:not(template)');
          children && SPZCore.Dom.removeElement(children);
          this.element.appendChild(el);
        }).then(() => {
          if(data && Object.keys(data).length > 0) {
            this.updateRender(data);
            this.setupSummaryContainerEffects_(data);
          }
        });
    }
   
    updateRender(data) {
      this.renderStarCounts_(data);
      this.renderTypeSelect(data);
      this.renderSortSelect(data);
    }
    renderStarCounts_(data) {
      const renderData = {
        ...data.starData,
        star_color: data.star_color,
        isPC: data.isPC,
      }
      const summaryEle = data.isPC ? this.element.querySelector(`#${this.prefix}-revue-summary-${this.sectionId}_header_pc`) : this.element.querySelector(`#${this.prefix}-revue-summary-${this.sectionId}_header`);
      if(summaryEle) {
        SPZ.whenApiDefined(summaryEle).then((api) => {
          api.render(renderData);
        });
      }
    }
    renderTypeSelect(data) {
      const typeSelect = this.element.querySelector(`#${this.prefix}-revue-header-type-${this.sectionId}`);
      if(typeSelect) {
        SPZ.whenApiDefined(typeSelect).then((api) => {
          api.render(data);
          api.registerAction('headerType_', (invocation) => {
            this.triggerEvent_('headerType', invocation.args.data);
          });
        });
      }
    }
    renderSortSelect(data) {
      const suffix = data.suffix || this.sectionId;
      const sortSelect = this.element.querySelector(`#${this.prefix}-revue-header-sort-${suffix}`);
      if(sortSelect) {
        SPZ.whenApiDefined(sortSelect).then((api) => {
          api.registerAction('headerSort_', (invocation) => {
            this.triggerEvent_('headerSort', invocation.args.data);
          });
        });
      }
    }
    setupSummaryContainerEffects_(data) {
      if(data.isPC) {
        this.setupSummaryContainerHover_();
      } else {
        this.setupSummaryContainerTap_();
      }
    }
    setupSummaryContainerHover_() {
      const summaryContainer = this.element.querySelector(`#revue-header-summary-container-${this.sectionId}`);
      const summaryEle = this.element.querySelector(`#${this.prefix}-revue-summary-${this.sectionId}_header_pc`);
      if (!summaryContainer || !summaryEle) return;
      let isHovering = false;
      // 鼠标移入容器时显示summary
      SPZUtils.Event.listen(summaryContainer, 'mouseenter', () => {
        isHovering = true;
        summaryEle.removeAttribute('hidden');
        const selectIcon = summaryContainer.querySelector(`#revue-header-summary-icon-${this.sectionId}`);
        if(selectIcon) {
          selectIcon.classList.add('up-icon');
        }
      });
      // 鼠标移入summary时也保持显示
      SPZUtils.Event.listen(summaryEle, 'mouseenter', () => {
        isHovering = true;
      });
      
      // 鼠标移出容器时,检查是否还在summary上
      SPZUtils.Event.listen(summaryContainer, 'mouseleave', () => {
        isHovering = false;
        setTimeout(() => {
          if (!isHovering) {
            summaryEle.setAttribute('hidden', 'true');
            const selectIcon = summaryContainer.querySelector(`#revue-header-summary-icon-${this.sectionId}`);
            if(selectIcon) {
              selectIcon.classList.remove('up-icon');
            }
          }
        }, 50);
      });
      // 鼠标移出summary时,检查是否还在容器上
      SPZUtils.Event.listen(summaryEle, 'mouseleave', () => {
        isHovering = false;
        setTimeout(() => {
          if (!isHovering) {
            summaryEle.setAttribute('hidden', 'true');
            const selectIcon = summaryEle.querySelector(`#revue-header-summary-icon-${this.sectionId}`);
            if(selectIcon) {
              selectIcon.classList.remove('up-icon');
            }
          }
        }, 50);
      });
    }
    setupSummaryContainerTap_() {
      const selectIcon = this.element.querySelector(`#revue-header-summary-icon-${this.sectionId}`);
      const summaryEle = this.element.querySelector(`#${this.prefix}-revue-summary-${this.sectionId}_header`);
      if(!summaryEle) return;
      let isTapped = false; // 是否显示summary
      SPZ.whenApiDefined(summaryEle).then((api) => {
        api.registerAction('display', () => {
          if(isTapped) {
            isTapped = false;
            summaryEle.removeAttribute('hidden');
            selectIcon.classList.add('up-icon');
          } else {
            isTapped = true;
            summaryEle.setAttribute('hidden', 'true');
            selectIcon.classList.remove('up-icon');
          }
        });
      });
    }
  }
  SPZ.defineElement(TAG, SPZCustomRevueHeader);
 
  
 ${function() {
    const pc_layout = 'single_column';
    const isProductPage = '1' == 1;
    const product_id = 'bd64ad24-40c4-4b36-8a47-97bb380a6b15';
    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 `
      
        
        
        
        
        
        
        
        
        
          
            ${formatDate(item.created_at)}
           
         
       
    `;
  }()}
  ${function() {
    const isPC = data.isPC; 
    const pc_layout = data.pc_layout;
    const is_pagination = isPC && pc_layout == 'single_column';
    const column_type = (isPC && pc_layout == 'double_column') ? 2 : 1;
    const is_view_more = data.hasmore && ((isPC && pc_layout == 'double_column') || (!isPC && data.m_loading_type === 'curr_page'));
    const is_view_all = (data.viewall ?? true) && !isPC && data.m_loading_type === 'modal';
    const is_write_review = (data.write_review ?? true) && !isPC;
    const scroll_loading = data.scroll_loading ?? false;
    const is_reach_bottom = (isPC && pc_layout == 'double_column') || !isPC;
    return `
      
         
        
        
          
           
            Wow you reached the bottom
          
          View all
          Write a Review
          
         
       
    `; 
  }()}
  const TAG = 'spz-custom-revue-list';
  class SPZCustomRevueList extends SPZ.BaseElement {
    constructor(element) {
      super(element);
    }
    static deferredMount() {
      return false;
    }
    triggerEvent_(name, data) {
      const event = SPZUtils.Event.create(this.win, `${ TAG }.${ name }`, data || {});
      this.action_.trigger(this.element, name, event);
    }
    isLayoutSupported(layout) {
      return layout == SPZCore.Layout.CONTAINER;
    }
    buildCallback = () => {
      this.element_id = this.element.getAttribute('id');
      this.section_id = this.element.getAttribute('section-id');
      this.suffix = this.element.getAttribute('suffix');
      this.action_ = SPZServices.actionServiceForDoc(this.element);
      this.templates_ = SPZServices.templatesForDoc(this.element);
      this.xhr_ = SPZServices.xhrFor(this.win);
      this.isPC = window.innerWidth > (window.breakpoint || 960);
    }
    mountCallback = () => {
      // this.render({});
      this.setAction()
    }
    render = (data) => {
      const ndata = {
        ...data,
        pc_layout: window.reviewProductSettings[this.section_id].pc_layout,
        m_loading_type: window.reviewProductSettings[this.section_id].m_loading_type,
        container_id: this.element_id,
        suffix: this.suffix,
        isProductPage: this.isProductPage,
      }
      return this.templates_
        .findAndRenderTemplate(this.element, ndata, null)
        .then((el) => {
          const children = this.element.querySelector('*:not(template)');
          children && SPZCore.Dom.removeElement(children);
          this.element.appendChild(el);
      }).then(() => {
        this.triggerEvent_('finish', {});
        this.setupIntersectionObserver();
      });
    }
    renderList = (data, redo = false) => {
      const listEle = document.querySelector(`#revue-list-${this.suffix}`);
      const viewMoreEle = document.querySelector(`#revue-list-view-more`);
      const loadingEle = document.querySelector(`#revue-list-scroll-loading`);
      const viewMoreModal = document.querySelector(`#revue-viewall-modal-comp`);
      const reachBottomEle = document.querySelector(`#revue-list-reach-bottom-${this.suffix}`);
      if(viewMoreModal) {
        SPZ.whenApiDefined(viewMoreModal).then((api) => {
          api.setMarkScrollTop()
        })
      }
     
      if (listEle) {
        SPZ.whenApiDefined(listEle).then((api) => {
          api.listRender(data, redo);
        });
      }
      if(viewMoreEle) {
        if(data.hasmore) {
          viewMoreEle.removeAttribute('hidden');
        } else {
          viewMoreEle.setAttribute('hidden', true);
        }
      } 
      if (loadingEle) {
        if(data.hasmore) {
          loadingEle.removeAttribute('hidden');
        } else {
          loadingEle.setAttribute('hidden', true);
        }
      } 
      if (reachBottomEle) {
        if(data.hasmore) {
          reachBottomEle.setAttribute('hidden', true);
        } else {
          reachBottomEle.removeAttribute('hidden');
        }
      }
    }
    setupIntersectionObserver = () => {
      // 创建 Intersection Observer 实例
      const observer = new IntersectionObserver((entries) => {
        entries.forEach(entry => {
          if (entry.isIntersecting) {
            const viewallModal = document.querySelector(`#revue-viewall-modal-comp`);
            if (viewallModal) {
              SPZ.whenApiDefined(viewallModal).then((api) => {
                api.loadMore();
              });
            }
          }
        });
      }, {
        threshold: 0.1 // 当目标元素 10% 进入视区时触发
      });
      const loadingElement = document.querySelector('.revue-list-scroll-loading');
      if (loadingElement) {
        observer.observe(loadingElement);
      }
    }
    
    setAction = () => {
      this.registerAction('checkOverFlow', () => {
        // 检查普通评论
        this.element.querySelectorAll('.revue_text_line_4').forEach(elem => {
          if (elem.scrollHeight > elem.clientHeight + 10) {
            elem.classList.add('overflow-text');
          } else {
            elem.classList.remove('overflow-text');
          }
        });
        
        // 检查回复内容
        this.element.querySelectorAll('.revue_reply').forEach(elem => {
          const contentElem = elem.querySelector('.revue_reply_content');
          if (contentElem.scrollHeight > contentElem.clientHeight + 10) {
            elem.classList.add('overflow-text');
          } else {
            elem.classList.remove('overflow-text');
          }
        });
      });
    }
  }
  SPZ.defineElement(TAG, SPZCustomRevueList);
  ${function(){
    const starOrder = ['one_star', 'two_star', 'three_star', 'four_star', 'five_star'];
    function sortStarRatings(ratings) {
      const sortedRatingsArr = [];
      starOrder.map((star,index) => {
        sortedRatingsArr.push(index+1);
        return star;
      });
      return sortedRatingsArr;
    };
    const star_levels = sortStarRatings(data.star_detail).reverse();
    return `
    
      
        
          ${data.comment_avg_star}
          
            
            
            Total reviews: ${data.comment_count > 999 ? '999+' : data.comment_count}
           
         
        
        
       
     
    `;
  }()}
  ${function() {
    return `
       
        
      
    `
  }()}
  const TAG = 'spz-custom-revue-viewall-modal';
  class SPZCustomRevueViewallModal extends SPZ.BaseElement {
    constructor(element) {
      super(element);
    }
    triggerEvent_(name, data) {
      const event = SPZUtils.Event.create(this.win, `${ TAG }.${ name }`, data || {});
      this.action_.trigger(this.element, name, event);
    }
    isLayoutSupported(layout) {
      return layout == SPZCore.Layout.CONTAINER;
    }
    buildCallback = () => {
      this.section_id = this.element.getAttribute('section-id');
      this.action_ = SPZServices.actionServiceForDoc(this.element);
      this.templates_ = SPZServices.templatesForDoc(this.element);
      this.firstRender = true;
      this.markScrollTop = 0;
      this.scrollTop = 0;
    }
    mountCallback = () => {
      this.doRender_();
      this.setupAction_();
    }
    doRender_() {
      this.templates_
        .findAndRenderTemplate(this.element, {})
        .then((el) => {
          const children = this.element.querySelector('*:not(template)');
          children && SPZCore.Dom.removeElement(children);
          this.element.appendChild(el);
        }).then(() => {
          const viewallModalContentEle = document.querySelector(`#revue-viewall-modal-content-${this.section_id}`);
          viewallModalContentEle.addEventListener('scroll', () => {
            this.scrollTop = viewallModalContentEle.scrollTop;
          });
        })
    } 
    setupAction_() {
      this.registerAction('renderTab', async (invocation) => {
        if(this.firstRender) {
          this.firstRender = false;
          const productEle = document.querySelector(`#revue-product-compo`);
          const summaryEle = document.querySelector(`#revue-summary-${this.section_id}_viewall`);
          if (productEle) {
            SPZ.whenApiDefined(productEle).then(async (api) => {
              api.renderStarCounts({}, `revue-summary-${this.section_id}_viewall`);
              api.renderCommentTab({
                viewall: false,
                write_review: false,
                scroll_loading: true
              }, `revue-tab-${this.section_id}_viewall`);
            });
          }
        }
      });
      this.registerAction('scrollToLast', async (invocation) => {
        const viewallModalContentEle = document.querySelector(`#revue-viewall-modal-content-${this.section_id}`);
        if(viewallModalContentEle) {
          requestAnimationFrame(() => {
            viewallModalContentEle.scrollTop = this.markScrollTop;
          });
        }
      });
    }
    setMarkScrollTop() {
      this.markScrollTop = this.scrollTop;
    }
    refresh() {
      this.firstRender = true;  
      this.scrollTop = 0;
      const productEle = document.querySelector(`#revue-viewall-modal-${this.section_id}`);
      if (productEle) {
        SPZ.whenApiDefined(productEle).then(async (api) => {
          api.close();
        });
      }
    }
    loadMore() {
      const productEle = document.querySelector(`#revue-product-compo`);
      if (productEle) {
        SPZ.whenApiDefined(productEle).then(async (api) => {
          await api.renderByScrollPagination(`revue-comment-list-${this.section_id}_tab`, 'tab');
        });
      }
    }
  }
  SPZ.defineElement(TAG, SPZCustomRevueViewallModal);
    
  
  let section_id = '1539149753700';
  window.reviewProductSettings = {};
  const default_settings = {
    "star_least": "5",
    "only_featured": false,
    "only_media": false,
    "review_insufficient": "no_reviews",
    "mini_quantity": 5,
    "actions": "hide",
    "pc_layout": "single_column",
    "m_loading_type": "modal",
    "m_modal_page_limit": "3",
    "page_limit": 10,
    "display_product_link": false,
    "hide_review_section": true,
    "title": "Reviews",
    "title_color": "rgba(51, 51, 51, 1)",
    "primary_color": "rgba(48, 53, 77, 1)",
    "section_bg_color": "rgba(255, 255, 255, 1)",
    "background_color_new": "rgba(255, 255, 255, 1)"
  };
  
  const user_settings = {
    "description_text": "Here are what our customers say.",
    "star_least": "1",
    "only_featured": false,
    "only_media": false,
    "review_insufficient": null,
    "mini_quantity": 5,
    "actions": null,
    "pc_layout": "single_column",
    "m_loading_type": null,
    "m_modal_page_limit": null,
    "comment_page_limit": 20,
    "page_limit": 10,
    "display_product_link": false,
    "hide_review_section": true,
    "title": "Customer Reviews",
    "accent_color": null,
    "title_color": "rgba(51, 51, 51, 1)",
    "text_color": "rgba(48, 53, 77, 1)",
    "section_bg_color": null,
    "background_color_new": null
  };
  window.reviewProductSettings[section_id] = Object.assign({}, default_settings, user_settings, {
    page_limit: user_settings.comment_page_limit || user_settings.page_limit || default_settings.page_limit
  });
  ${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(){
    return `
                   ${function(){               if (media.videosrc) {                 let src = '';                 if (media.videosrc) {                   src = media.videosrc + '.' + media.ext;                 }                 return `                                      `               } else if(media.mp4 || media.hls) {                 return `                                      `               } else {                 return `                                      `               }             }()}           
        
        
          
          
          
          
          
            
              No reviews yet, why don't you leave the first review?
            
            
              Write a Review
            
           
         
        
       
    `;
  }()}
  
  
  
  
    
      ${function(){
        return `
        
          
            
              No reviews available. The product reviews component has been hidden
            
            Product Detail Reviews
           
         
      `
      }()}